Enable Policy Debugging Feature (#118)

* debug refactor

* temp

* connect to cloud

* temp

* fix bugs

* connect to cloud update

* temp change

* Use bearer token

* Refactor code

* temp change

* comment code

* UpdateOne

* Change dogfood endpoint

* Fix more issues

* temp changes

* Neat code

* Fix lint error
This commit is contained in:
RupengLiu 2020-09-10 12:56:26 -07:00 коммит произвёл GitHub
Родитель 552cd501bd
Коммит d6d6304d3e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
22 изменённых файлов: 2231 добавлений и 251 удалений

18
.vscode/launch.json поставляемый
Просмотреть файл

@ -90,6 +90,20 @@
"NODE_DEBUG": "",
"ENABLE_LONG_RUNNING_TESTS": ""
}
}
]
},
{
"type": "node",
"request": "launch",
"name": "Server",
"cwd": "${workspaceFolder}",
"program": "${workspaceFolder}/resources/debug/debugAdapter.js",
"args": [ "--server=4711" ]
},
],
"compounds": [
{
"name": "Extension + Server",
"configurations": [ "Launch Extension (no build)", "Server" ]
}
]
}

532
package-lock.json сгенерированный
Просмотреть файл

@ -5,29 +5,35 @@
"requires": true,
"dependencies": {
"@babel/code-frame": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
"integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
"integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
"dev": true,
"requires": {
"@babel/highlight": "^7.0.0"
"@babel/highlight": "^7.8.3"
}
},
"@babel/helper-validator-identifier": {
"version": "7.9.0",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz",
"integrity": "sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw==",
"dev": true
},
"@babel/highlight": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
"integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
"version": "7.9.0",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz",
"integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.9.0",
"chalk": "^2.0.0",
"esutils": "^2.0.2",
"js-tokens": "^4.0.0"
}
},
"@types/bluebird": {
"version": "3.5.27",
"resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.27.tgz",
"integrity": "sha512-6BmYWSBea18+tSjjSC3QIyV93ZKAeNWGM7R6aYt1ryTZXrlHF+QLV0G2yV0viEGVyRkyQsWfMoJ0k/YghBX5sQ==",
"version": "3.5.30",
"resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.30.tgz",
"integrity": "sha512-8LhzvcjIoqoi1TghEkRMkbbmM+jhHnBokPGkJWjclMK+Ks0MxEBow3/p2/iFTZ+OIbJHQDSfpgdZEb+af3gfVw==",
"dev": true
},
"@types/caseless": {
@ -42,15 +48,6 @@
"integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==",
"dev": true
},
"@types/form-data": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz",
"integrity": "sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/fs-extra": {
"version": "4.0.9",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-4.0.9.tgz",
@ -105,32 +102,54 @@
"dev": true
},
"@types/node": {
"version": "10.17.17",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.17.tgz",
"integrity": "sha512-gpNnRnZP3VWzzj5k3qrpRC6Rk3H/uclhAVo1aIvwzK5p5cOrs9yEyQ8H/HBsBY0u5rrWxXEiVPQ0dEB6pkjE8Q=="
"version": "8.10.62",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.62.tgz",
"integrity": "sha512-76fupxOYVxk36kb7O/6KtrAPZ9jnSK3+qisAX4tQMEuGNdlvl7ycwatlHqjoE6jHfVtXFM3pCrCixZOidc5cuw=="
},
"@types/request": {
"version": "2.48.1",
"resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.1.tgz",
"integrity": "sha512-ZgEZ1TiD+KGA9LiAAPPJL68Id2UWfeSO62ijSXZjFJArVV+2pKcsVHmrcu+1oiE3q6eDGiFiSolRc4JHoerBBg==",
"version": "2.48.4",
"resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.4.tgz",
"integrity": "sha512-W1t1MTKYR8PxICH+A4HgEIPuAC3sbljoEVfyZbeFJJDbr30guDspJri2XOaM2E+Un7ZjrihaDi7cf6fPa2tbgw==",
"dev": true,
"requires": {
"@types/caseless": "*",
"@types/form-data": "*",
"@types/node": "*",
"@types/tough-cookie": "*"
"@types/tough-cookie": "*",
"form-data": "^2.5.0"
},
"dependencies": {
"form-data": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
"integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
"dev": true,
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
}
}
},
"@types/request-promise": {
"version": "4.1.44",
"resolved": "https://registry.npmjs.org/@types/request-promise/-/request-promise-4.1.44.tgz",
"integrity": "sha512-RId7eFsUKxfal1LirDDIcOp9u3MM3NXFDBcC3sqIMcmu7f4U6DsCEMD8RbLZtnPrQlN5Jc79di/WPsIEDO4keg==",
"version": "4.1.46",
"resolved": "https://registry.npmjs.org/@types/request-promise/-/request-promise-4.1.46.tgz",
"integrity": "sha512-3Thpj2Va5m0ji3spaCk8YKrjkZyZc6RqUVOphA0n/Xet66AW/AiOAs5vfXhQIL5NmkaO7Jnun7Nl9NEjJ2zBaw==",
"dev": true,
"requires": {
"@types/bluebird": "*",
"@types/request": "*"
}
},
"@types/request-promise-native": {
"version": "1.0.17",
"resolved": "https://registry.npmjs.org/@types/request-promise-native/-/request-promise-native-1.0.17.tgz",
"integrity": "sha512-05/d0WbmuwjtGMYEdHIBZ0tqMJJQ2AD9LG2F6rKNBGX1SSFR27XveajH//2N/XYtual8T9Axwl+4v7oBtPUZqg==",
"dev": true,
"requires": {
"@types/request": "*"
}
},
"@types/swagger-parser": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@types/swagger-parser/-/swagger-parser-4.0.3.tgz",
@ -147,9 +166,9 @@
"dev": true
},
"@types/tough-cookie": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.5.tgz",
"integrity": "sha512-SCcK7mvGi3+ZNz833RRjFIxrn4gI1PPR3NtuIS+6vMkvmsGjosqTJwRt5bAEFLRz+wtJMWv8+uOnZf2hi2QXTg==",
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.6.tgz",
"integrity": "sha512-wHNBMnkoEBiRAd3s8KTKwIuO9biFtTf0LehITzBhSco+HQI0xkXZbLOD55SW3Aqw3oUkHstkm5SPv58yaAdFPQ==",
"dev": true
},
"@types/undertaker": {
@ -187,10 +206,19 @@
"@types/vinyl": "*"
}
},
"@types/ws": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-6.0.4.tgz",
"integrity": "sha512-PpPrX7SZW9re6+Ha8ojZG4Se8AZXgf0GK6zmfqEuCsY49LFDNXO3SByp44X3dFEqtB73lkCDAdUazhAjVPiNwg==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/xml": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@types/xml/-/xml-1.0.3.tgz",
"integrity": "sha512-qeqQIjDfSLjmWR0noFQmcPKCtqn0L68MchoEi1Zj33unPfC83Op3j2mBH2g4hAgOaWUobv/O86w7LObo6p4sDQ==",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@types/xml/-/xml-1.0.4.tgz",
"integrity": "sha512-l9RTwMnKc7WTHpARC9A1CoeF40U5xi6ZOQePDvkeTr6RZpzck/Y54i9YCYe2fgrWZiOxfJ4wnBbDd3g/7HYtug==",
"requires": {
"@types/node": "*"
}
@ -906,6 +934,11 @@
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
"dev": true
},
"await-notify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/await-notify/-/await-notify-1.0.1.tgz",
"integrity": "sha1-C0gTOyLlJBgeEVV2ZRhfKi885Hw="
},
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
@ -1347,9 +1380,9 @@
"dev": true
},
"cacache": {
"version": "11.3.3",
"resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz",
"integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==",
"version": "12.0.3",
"resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz",
"integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==",
"dev": true,
"requires": {
"bluebird": "^3.5.5",
@ -1357,6 +1390,7 @@
"figgy-pudding": "^3.5.1",
"glob": "^7.1.4",
"graceful-fs": "^4.1.15",
"infer-owner": "^1.0.3",
"lru-cache": "^5.1.1",
"mississippi": "^3.0.0",
"mkdirp": "^0.5.1",
@ -1461,9 +1495,9 @@
}
},
"chownr": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
"dev": true
},
"chrome-trace-event": {
@ -2175,9 +2209,9 @@
"optional": true
},
"cyclist": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz",
"integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
"integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
"dev": true
},
"d": {
@ -2758,12 +2792,6 @@
"integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
"dev": true
},
"esutils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
"dev": true
},
"events": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz",
@ -3283,9 +3311,9 @@
},
"dependencies": {
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@ -3347,9 +3375,9 @@
},
"dependencies": {
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@ -4623,6 +4651,12 @@
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
"dev": true
},
"infer-owner": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
"integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==",
"dev": true
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@ -5052,9 +5086,9 @@
}
},
"kind-of": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"dev": true
},
"last-run": {
@ -5137,9 +5171,9 @@
}
},
"linkify-it": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.1.0.tgz",
"integrity": "sha512-4REs8/062kV2DSHxNfq5183zrqXMl7WP0WzABH9IeJI+NLm429FgE1PDecltYfnOoFDFlZGh2T8PfZn0r+GTRg==",
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
"integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
"dev": true,
"requires": {
"uc.micro": "^1.0.1"
@ -5706,7 +5740,6 @@
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"requires": {
"minimist": "0.0.8"
},
@ -5714,8 +5747,7 @@
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
}
}
},
@ -5776,9 +5808,9 @@
}
},
"mocha-junit-reporter": {
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/mocha-junit-reporter/-/mocha-junit-reporter-1.23.0.tgz",
"integrity": "sha512-pmpnEO4iDTmLfrT2RKqPsc5relG4crnDSGmXPuGogdda27A7kLujDNJV4EbTbXlVBCZXggN9rQYPEWMkOv4AAA==",
"version": "1.23.3",
"resolved": "https://registry.npmjs.org/mocha-junit-reporter/-/mocha-junit-reporter-1.23.3.tgz",
"integrity": "sha512-ed8LqbRj1RxZfjt/oC9t12sfrWsjZ3gNnbhV1nuj9R/Jb5/P3Xb4duv2eCfCDMYH+fEu0mqca7m4wsiVjsxsvA==",
"dev": true,
"requires": {
"debug": "^2.2.0",
@ -6420,20 +6452,20 @@
"dev": true
},
"parallel-transform": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz",
"integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz",
"integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==",
"dev": true,
"requires": {
"cyclist": "~0.2.2",
"cyclist": "^1.0.1",
"inherits": "^2.0.3",
"readable-stream": "^2.1.5"
},
"dependencies": {
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
@ -7013,9 +7045,9 @@
}
},
"request": {
"version": "2.88.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
"version": "2.88.2",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
"requires": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
@ -7024,7 +7056,7 @@
"extend": "~3.0.2",
"forever-agent": "~0.6.1",
"form-data": "~2.3.2",
"har-validator": "~5.1.0",
"har-validator": "~5.1.3",
"http-signature": "~1.2.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
@ -7034,9 +7066,20 @@
"performance-now": "^2.1.0",
"qs": "~6.5.2",
"safe-buffer": "^5.1.2",
"tough-cookie": "~2.4.3",
"tough-cookie": "~2.5.0",
"tunnel-agent": "^0.6.0",
"uuid": "^3.3.2"
},
"dependencies": {
"tough-cookie": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
"requires": {
"psl": "^1.1.28",
"punycode": "^2.1.1"
}
}
}
},
"request-progress": {
@ -7049,22 +7092,54 @@
}
},
"request-promise": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.4.tgz",
"integrity": "sha512-8wgMrvE546PzbR5WbYxUQogUnUDfM0S7QIFZMID+J73vdFARkFy+HElj4T+MWYhpXwlLp0EQ8Zoj8xUA0he4Vg==",
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.5.tgz",
"integrity": "sha512-ZgnepCykFdmpq86fKGwqntyTiUrHycALuGggpyCZwMvGaZWgxW6yagT0FHkgo5LzYvOaCNvxYwWYIjevSH1EDg==",
"requires": {
"bluebird": "^3.5.0",
"request-promise-core": "1.1.2",
"request-promise-core": "1.1.3",
"stealthy-require": "^1.1.1",
"tough-cookie": "^2.3.3"
}
},
"request-promise-core": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz",
"integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==",
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz",
"integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==",
"requires": {
"lodash": "^4.17.11"
"lodash": "^4.17.15"
},
"dependencies": {
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
}
}
},
"request-promise-native": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz",
"integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==",
"requires": {
"request-promise-core": "1.1.3",
"stealthy-require": "^1.1.1",
"tough-cookie": "^2.3.3"
},
"dependencies": {
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
"request-promise-core": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz",
"integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==",
"requires": {
"lodash": "^4.17.15"
}
}
}
},
"require-directory": {
@ -7233,9 +7308,9 @@
}
},
"serialize-javascript": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.7.0.tgz",
"integrity": "sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA==",
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
"integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==",
"dev": true
},
"set-blocking": {
@ -7932,14 +8007,14 @@
}
},
"terser": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-4.0.0.tgz",
"integrity": "sha512-dOapGTU0hETFl1tCo4t56FN+2jffoKyER9qBGoUFyZ6y7WLoKT0bF+lAYi6B6YsILcGF3q1C2FBh8QcKSCgkgA==",
"version": "4.6.6",
"resolved": "https://registry.npmjs.org/terser/-/terser-4.6.6.tgz",
"integrity": "sha512-4lYPyeNmstjIIESr/ysHg2vUPRGf2tzF9z2yYwnowXVuVzLEamPN1Gfrz7f8I9uEPuHcbFlW4PLIAsJoxXyJ1g==",
"dev": true,
"requires": {
"commander": "^2.19.0",
"commander": "^2.20.0",
"source-map": "~0.6.1",
"source-map-support": "~0.5.10"
"source-map-support": "~0.5.12"
},
"dependencies": {
"source-map": {
@ -7951,20 +8026,19 @@
}
},
"terser-webpack-plugin": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.3.0.tgz",
"integrity": "sha512-W2YWmxPjjkUcOWa4pBEv4OP4er1aeQJlSo2UhtCFQCuRXEHjOFscO8VyWHj9JLlA0RzQb8Y2/Ta78XZvT54uGg==",
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz",
"integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==",
"dev": true,
"requires": {
"cacache": "^11.3.2",
"find-cache-dir": "^2.0.0",
"cacache": "^12.0.2",
"find-cache-dir": "^2.1.0",
"is-wsl": "^1.1.0",
"loader-utils": "^1.2.3",
"schema-utils": "^1.0.0",
"serialize-javascript": "^1.7.0",
"serialize-javascript": "^2.1.2",
"source-map": "^0.6.1",
"terser": "^4.0.0",
"webpack-sources": "^1.3.0",
"terser": "^4.1.2",
"webpack-sources": "^1.4.0",
"worker-farm": "^1.7.0"
},
"dependencies": {
@ -7973,6 +8047,16 @@
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"webpack-sources": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
"integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
"dev": true,
"requires": {
"source-list-map": "^2.0.0",
"source-map": "~0.6.1"
}
}
}
},
@ -8190,16 +8274,16 @@
"dev": true
},
"tslint": {
"version": "5.18.0",
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.18.0.tgz",
"integrity": "sha512-Q3kXkuDEijQ37nXZZLKErssQVnwCV/+23gFEMROi8IlbaBG6tXqLPQJ5Wjcyt/yHPKBC+hD5SzuGaMora+ZS6w==",
"version": "5.20.1",
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz",
"integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
"builtin-modules": "^1.1.1",
"chalk": "^2.3.0",
"commander": "^2.12.1",
"diff": "^3.2.0",
"diff": "^4.0.1",
"glob": "^7.1.1",
"js-yaml": "^3.13.1",
"minimatch": "^3.0.4",
@ -8208,6 +8292,14 @@
"semver": "^5.3.0",
"tslib": "^1.8.0",
"tsutils": "^2.29.0"
},
"dependencies": {
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true
}
}
},
"tslint-microsoft-contrib": {
@ -8297,9 +8389,9 @@
"dev": true
},
"typescript": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.2.tgz",
"integrity": "sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA==",
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
"dev": true
},
"uc.micro": {
@ -8668,9 +8760,9 @@
"dev": true
},
"vsce": {
"version": "1.64.0",
"resolved": "https://registry.npmjs.org/vsce/-/vsce-1.64.0.tgz",
"integrity": "sha512-t3R7QTe2nAXQZs2kD+nA8GjdlX8pAQlnzxaNTG2976i5cyQ8r+ZsMNa/f9PDt7bhjcQM+u/fL+LkNuw+hwoy2A==",
"version": "1.74.0",
"resolved": "https://registry.npmjs.org/vsce/-/vsce-1.74.0.tgz",
"integrity": "sha512-8zWM9bZBNn9my40kkxAxdY4nhb9ADfazXsyDgx1thbRaLPbmPTlmqQ55vCAyWYFEi6XbJv8w599vzVUqsU1gHg==",
"dev": true,
"requires": {
"azure-devops-node-api": "^7.2.0",
@ -8680,7 +8772,7 @@
"denodeify": "^1.2.1",
"didyoumean": "^1.2.1",
"glob": "^7.0.6",
"lodash": "^4.17.10",
"lodash": "^4.17.15",
"markdown-it": "^8.3.1",
"mime": "^1.3.4",
"minimatch": "^3.0.3",
@ -8693,111 +8785,29 @@
"url-join": "^1.1.0",
"yauzl": "^2.3.1",
"yazl": "^2.2.2"
},
"dependencies": {
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
}
}
},
"vscode": {
"version": "1.1.34",
"resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.34.tgz",
"integrity": "sha512-GuT3tCT2N5Qp26VG4C+iGmWMgg/MuqtY5G5TSOT3U/X6pgjM9LFulJEeqpyf6gdzpI4VyU3ZN/lWPo54UFPuQg==",
"version": "1.1.36",
"resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.36.tgz",
"integrity": "sha512-cGFh9jmGLcTapCpPCKvn8aG/j9zVQ+0x5hzYJq5h5YyUXVGa1iamOaB2M2PZXoumQPES4qeAP1FwkI0b6tL4bQ==",
"dev": true,
"requires": {
"glob": "^7.1.2",
"mocha": "^4.0.1",
"mocha": "^5.2.0",
"request": "^2.88.0",
"semver": "^5.4.1",
"source-map-support": "^0.5.0",
"url-parse": "^1.4.4",
"vscode-test": "^0.4.1"
},
"dependencies": {
"browser-stdout": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz",
"integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=",
"dev": true
},
"commander": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
"dev": true
},
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
},
"diff": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz",
"integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==",
"dev": true
},
"growl": {
"version": "1.10.3",
"resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz",
"integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==",
"dev": true
},
"has-flag": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
"integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
"dev": true
},
"he": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
"integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
"dev": true
},
"mocha": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-4.1.0.tgz",
"integrity": "sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA==",
"dev": true,
"requires": {
"browser-stdout": "1.3.0",
"commander": "2.11.0",
"debug": "3.1.0",
"diff": "3.3.1",
"escape-string-regexp": "1.0.5",
"glob": "7.1.2",
"growl": "1.10.3",
"he": "1.1.1",
"mkdirp": "0.5.1",
"supports-color": "4.4.0"
},
"dependencies": {
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
}
}
},
"supports-color": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
"integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
"dev": true,
"requires": {
"has-flag": "^2.0.0"
}
}
}
},
"vscode-azureextensiondev": {
@ -8843,6 +8853,52 @@
"ajv-keywords": "^3.1.0"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"terser-webpack-plugin": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz",
"integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==",
"dev": true,
"requires": {
"cacache": "^12.0.2",
"find-cache-dir": "^2.1.0",
"is-wsl": "^1.1.0",
"schema-utils": "^1.0.0",
"serialize-javascript": "^2.1.2",
"source-map": "^0.6.1",
"terser": "^4.1.2",
"webpack-sources": "^1.4.0",
"worker-farm": "^1.7.0"
},
"dependencies": {
"schema-utils": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
"integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
"dev": true,
"requires": {
"ajv": "^6.1.0",
"ajv-errors": "^1.0.0",
"ajv-keywords": "^3.1.0"
}
},
"webpack-sources": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
"integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
"dev": true,
"requires": {
"source-list-map": "^2.0.0",
"source-map": "~0.6.1"
}
}
}
},
"webpack": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.28.1.tgz",
@ -8912,6 +8968,29 @@
}
}
},
"vscode-debugadapter": {
"version": "1.39.1",
"resolved": "https://registry.npmjs.org/vscode-debugadapter/-/vscode-debugadapter-1.39.1.tgz",
"integrity": "sha512-+WYpOcY0PiAEBILf6nIwbNVF8ig8gugWTKWhQ7Ds1884JXpVL336pG0xH66Nc1Z1W/KSzuXarm1gtccdwl6PKw==",
"requires": {
"mkdirp": "^0.5.1",
"vscode-debugprotocol": "1.39.0"
}
},
"vscode-debugadapter-testsupport": {
"version": "1.40.2",
"resolved": "https://registry.npmjs.org/vscode-debugadapter-testsupport/-/vscode-debugadapter-testsupport-1.40.2.tgz",
"integrity": "sha512-HN1KoQUtFwCfPz2r1XaOtw3aUPpkgDPPRpLSGjCbOGRYhUJKlnLEwSaq4djVvZsfav6Zfd9QaBoaBNy03eBTvg==",
"dev": true,
"requires": {
"vscode-debugprotocol": "1.39.0"
}
},
"vscode-debugprotocol": {
"version": "1.39.0",
"resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.39.0.tgz",
"integrity": "sha512-Wkvgtuz90vjtQBcvw9Z+BYa4dA6W+sHwHMpqvJVNmwWSuT3JZdl0XDhZNLqtMXkVF4okxtAe0MmbupPSt+gnAQ=="
},
"vscode-extension-telemetry": {
"version": "0.0.18",
"resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.18.tgz",
@ -8935,9 +9014,9 @@
}
},
"vscode-nls": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-4.1.1.tgz",
"integrity": "sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A=="
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-4.1.2.tgz",
"integrity": "sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw=="
},
"vscode-test": {
"version": "0.4.3",
@ -9189,9 +9268,9 @@
}
},
"webpack-cli": {
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.5.tgz",
"integrity": "sha512-w0j/s42c5UhchwTmV/45MLQnTVwRoaUTu9fM5LuyOd/8lFoCNCELDogFoecx5NzRUndO0yD/gF2b02XKMnmAWQ==",
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.11.tgz",
"integrity": "sha512-dXlfuml7xvAFwYUPsrtQAA9e4DOe58gnzSxhgrO/ZM/gyXTBowrsYeubyN4mqGhYdpXMFNyQ6emjJS9M7OBd4g==",
"dev": true,
"requires": {
"chalk": "2.4.2",
@ -9375,9 +9454,9 @@
}
},
"yargs-parser": {
"version": "13.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
"integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
"version": "13.1.2",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
"integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
"dev": true,
"requires": {
"camelcase": "^5.0.0",
@ -9449,6 +9528,11 @@
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
"ws": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz",
"integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ=="
},
"xml": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
@ -9478,9 +9562,9 @@
"dev": true
},
"yallist": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true
},
"yargs": {

Просмотреть файл

@ -33,6 +33,7 @@
"onCommand:azureApiManagement.selectSubscriptions",
"onView:azureApiManagementExplorer",
"onLanguage:policy",
"onLanguage:apim-policy",
"onCommand:azureApiManagement.createService",
"onCommand:azureApiManagement.deleteService",
"onCommand:azureApiManagement.copySubscriptionKey",
@ -67,10 +68,50 @@
"onCommand:azureApiManagement.importWebAppToApi",
"onCommand:azureApiManagement.copyDockerRunCommand",
"onCommand:azureApiManagement.generateKubernetesDeployment",
"onCommand:azureApiManagement.generateNewGatewayToken"
"onCommand:azureApiManagement.generateNewGatewayToken",
"onCommand:azureApiManagement.debugPolicy"
],
"main": "main",
"contributes": {
"breakpoints": [
{
"language": "apim-policy"
}
],
"languages": [
{
"id": "apim-policy",
"mimetypes": [
"application/vnd.ms-azure-apim.policy.raw+xml"
]
}
],
"debuggers": [
{
"type": "apim-policy",
"label": "Attach to APIM",
"runtime": "node",
"configurationAttributes": {
"launch": {
"properties": {
"stopOnEntry": {
"type": "boolean",
"description": "Automatically stop after launch.",
"default": true
}
}
}
},
"initialConfigurations": [
{
"type": "apim-policy",
"request": "launch",
"name": "Attach to APIM",
"stopOnEntry": true
}
]
}
],
"jsonValidation": [
{
"fileMatch": "/*-api-arm.json",
@ -274,6 +315,11 @@
"title": "%azureApiManagement.importWebAppToApi%",
"category": "Azure API Management"
},
{
"command": "azureApiManagement.debugPolicy",
"title": "%azureApiManagement.debugPolicy%",
"category": "Azure API Management"
},
{
"command": "azureApiManagement.copyDockerRunCommand",
"title": "%azureApiManagement.copyDockerRunCommand%",
@ -443,6 +489,11 @@
"when": "view == azureApiManagementExplorer && viewItem == azureApiManagementApiOperation",
"group": "1@1"
},
{
"command": "azureApiManagement.debugPolicy",
"when": "view == azureApiManagementExplorer && viewItem == azureApiManagementApiOperation",
"group": "2@1"
},
{
"command": "azureApiManagement.createNamedValue",
"when": "view == azureApiManagementExplorer && viewItem == azureApiManagementNamedValues",
@ -542,38 +593,46 @@
"devDependencies": {
"@types/fs-extra": "^4.0.3",
"@types/gulp": "^4.0.6",
"@types/node": "^10.0.0",
"@types/request": "^2.47.0",
"@types/request-promise": "^4.1.43",
"@types/swagger-parser": "^4.0.3",
"@types/mocha": "^5.2.6",
"tslint": "^5.7.0",
"typescript": "^3.3.1",
"ts-node": "^7.0.1",
"tslint-microsoft-contrib": "5.0.1",
"vscode-extension-telemetry": "^0.0.18",
"@types/node": "^8.10.59",
"@types/request": "^2.48.4",
"@types/request-promise": "^4.1.46",
"@types/request-promise-native": "^1.0.17",
"@types/swagger-parser": "^4.0.3",
"@types/ws": "^6.0.4",
"gulp": "^4.0.0",
"vsce": "^1.59.0",
"vscode": "^1.1.33",
"vscode-azureextensiondev": "0.1.8",
"webpack": "4.29.6",
"webpack-cli": "^3.3.0",
"mocha": "^5.2.0",
"mocha-junit-reporter": "^1.18.0",
"mocha-multi-reporters": "^1.1.7"
"mocha-junit-reporter": "^1.23.3",
"mocha-multi-reporters": "^1.1.7",
"ts-node": "^7.0.1",
"tslint": "^5.20.1",
"tslint-microsoft-contrib": "5.0.1",
"typescript": "^3.8.3",
"vsce": "^1.74.0",
"vscode": "^1.1.36",
"vscode-azureextensiondev": "0.1.8",
"vscode-debugadapter-testsupport": "1.40.2",
"vscode-extension-telemetry": "^0.0.18",
"webpack": "4.29.6",
"webpack-cli": "^3.3.11"
},
"dependencies": {
"@types/xml": "^1.0.3",
"@types/xml": "^1.0.4",
"await-notify": "1.0.1",
"azure-arm-apimanagement": "^6.0.0",
"azure-arm-resource": "^3.0.0-preview",
"azure-arm-website": "5.7.0",
"fs-extra": "^4.0.2",
"opn": "^5.3.0",
"request": "^2.83.0",
"request-promise": "^4.2.2",
"request": "^2.88.2",
"request-promise": "^4.2.5",
"request-promise-native": "^1.0.8",
"swagger-parser": "^6.0.5",
"vscode-azureextensionui": "^0.23.3",
"vscode-nls": "^4.1.0"
"vscode-debugadapter": "^1.39.1",
"vscode-debugprotocol": "^1.39.0",
"vscode-nls": "^4.1.2",
"ws": "^7.2.3"
},
"extensionDependencies": [
"ms-vscode.azure-account",

Просмотреть файл

@ -37,5 +37,6 @@
"azureApiManagement.importWebAppToApi": "Import Azure App Service",
"azureApiManagement.copyDockerRunCommand": "Copy Docker Run Command",
"azureApiManagement.generateKubernetesDeployment": "Generate Kubernetes Deployment File",
"azureApiManagement.generateNewGatewayToken": "Generate New Gateway Token"
"azureApiManagement.generateNewGatewayToken": "Generate New Gateway Token",
"azureApiManagement.debugPolicy": "Start Policy Debugging"
}

Просмотреть файл

@ -61,6 +61,11 @@ export class ApimService {
return res.value;
}
public async getSubscriptionMasterkey(): Promise<string> {
const masterKeyUrl = `${this.baseUrl}/subscriptions/master?api-version=${this.apiVersion}`;
return await requestUtil(masterKeyUrl, this.credentials, 'GET');
}
private genSiteUrl(endPointUrl: string, subscriptionId: string, resourceGroup: string, serviceName: string): string {
return `${endPointUrl}/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.ApiManagement/service/${serviceName}`;
}

Просмотреть файл

@ -30,3 +30,15 @@ export interface IGatewayTokenList {
primary: string;
secondary: string;
}
export interface IMasterSubscription {
id : string;
name : string;
properties: ISubscriptionProperty;
}
export interface ISubscriptionProperty {
displayName: string;
primaryKey: string;
secondaryKey: string;
}

Просмотреть файл

@ -0,0 +1,68 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { ApiOperationTreeItem } from '../../explorer/ApiOperationTreeItem';
import { IOperationTreeRoot } from '../../explorer/IOperationTreeRoot';
import { ext } from "../../extensionVariables";
import { nameUtil } from '../../utils/nameUtil';
export async function debugPolicy(node?: ApiOperationTreeItem): Promise<void> {
if (!node) {
node = <ApiOperationTreeItem>await ext.tree.showTreeItemPicker(ApiOperationTreeItem.contextValue);
}
const operationData = await node.getOperationDebugInfo();
const debugConfig: vscode.DebugConfiguration = {
type: "apim-policy",
request: "launch",
name: "Attach to APIM",
stopOnEntry: true,
// tslint:disable-next-line: no-non-null-assertion
gatewayAddress: getDebugGatewayAddressUrl(node!.root.serviceName),
managementAddress: getManagementUrl(node.root),
subscriptionId: node.root.subscriptionId,
operationData: operationData,
fileName: `${nameUtil(node.root)}.http`
};
// const debugConfig3: vscode.DebugConfiguration = {
// type: "apim-policy",
// request: "launch",
// name: "Attach to APIM",
// stopOnEntry: true,
// gatewayAddress: 'wss://proxy.apim.net/debug-0123456789abcdef',
// managementAddress: 'https://management.apim.net/subscriptions/x/resourceGroups/x/providers/microsoft.apimanagement/service/x',
// managementAuth: '',
// operationData: getLocalDebugOperationData2(),
// fileName: `${nameUtil(node.root)}.http`
// };
if (!vscode.debug.activeDebugSession) {
await vscode.debug.startDebugging(undefined, debugConfig);
// await vscode.debug.startDebugging(undefined, debugConfig3);
vscode.debug.onDidTerminateDebugSession(_ => {
const editors = vscode.window.visibleTextEditors;
editors.forEach(editor => {
editor.hide();
});
}, vscode.debug.activeDebugSession);
}
}
function getManagementUrl(root: IOperationTreeRoot): string {
return `${root.environment.resourceManagerEndpointUrl}/subscriptions/${root.subscriptionId}/resourceGroups/${root.resourceGroupName}/providers/microsoft.apimanagement/service/${root.serviceName}`;
}
function getDebugGatewayAddressUrl(serviceName: string): string {
return `wss://${serviceName}.azure-api.net/debug-0123456789abcdef`;
}
// function getLocalDebugOperationData2(): string {
// return `
// GET https://proxy.apim.net/echo/resource
// Ocp-Apim-Subscription-Key:
// Ocp-Apim-Debug:`;
// }

Просмотреть файл

@ -155,7 +155,7 @@ export function createXmlPolicyForSwaggerOperations(backendId: string): string {
export async function setAppBackendEntity(node: ApisTreeItem | ApiTreeItem, backendId: string, appName: string, appPath: string, appResourceGroup: string, webAppName: string, BackendCredentials?: BackendCredentialsContract): Promise<void> {
const nbackend: BackendContract = {
description: `${appName}`,
resourceId: getWebAppResourceId(node.root.environment.managementEndpointUrl, node.root.subscriptionId, appResourceGroup, webAppName),
resourceId: getWebAppResourceId(node.root.environment.resourceManagerEndpointUrl, node.root.subscriptionId, appResourceGroup, webAppName),
url: appPath,
id: backendId,
name: backendId,

Просмотреть файл

@ -14,13 +14,28 @@ export async function testOperation(node?: ApiOperationTreeItem): Promise<void>
if (!node) {
node = <ApiOperationTreeItem>await ext.tree.showTreeItemPicker(ApiOperationTreeItem.contextValue);
}
// tslint:disable-next-line: no-non-null-assertion
await createOperationTestFile(node!, OperationRunMode.test);
}
export async function createOperationTestFile(node: ApiOperationTreeItem, mode: OperationRunMode): Promise<vscode.TextEditor> {
// using https://github.com/Huachao/vscode-restclient
const fileName = `${nameUtil(node.root)}.http`;
const localFilePath: string = await createTemporaryFile(fileName);
const data: string = await node.getOperationTestInfo();
let data: string;
if (mode === OperationRunMode.debug) {
data = await node.getOperationDebugInfo();
} else {
data = await node.getOperationTestInfo();
}
const document: vscode.TextDocument = await vscode.workspace.openTextDocument(localFilePath);
const textEditor: vscode.TextEditor = await vscode.window.showTextDocument(document);
await writeToEditor(textEditor, data);
await textEditor.document.save();
return textEditor;
}
export enum OperationRunMode {
debug = "debug",
test = "test"
}

515
src/debugger/apimDebug.ts Normal file
Просмотреть файл

@ -0,0 +1,515 @@
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
import { ServiceClientCredentials } from "ms-rest";
import * as request from 'request-promise-native';
import * as vscode from 'vscode';
import { Breakpoint, Handles, InitializedEvent, Logger, logger, LoggingDebugSession, OutputEvent, Scope, StackFrame, StoppedEvent, TerminatedEvent, Thread, ThreadEvent, Variable } from 'vscode-debugadapter';
import { DebugProtocol } from 'vscode-debugprotocol';
import { createTemporaryFile } from "../utils/fsUtil";
import { getBearerToken } from '../utils/requestUtil';
import { writeToEditor } from '../utils/vscodeUtils';
import { DebuggerConnection, RequestContract } from './debuggerConnection';
import { PolicySource } from './policySource';
import { UiRequest } from './uiRequest';
import { UiThread } from './uiThread';
// tslint:disable: no-unsafe-any
// tslint:disable: indent
// tslint:disable: export-name
// tslint:disable: strict-boolean-expressions
// tslint:disable: typedef
// tslint:disable: no-non-null-assertion
// tslint:disable: no-for-in
// tslint:disable: forin
// tslint:disable: no-var-requires
const { Subject } = require('await-notify');
interface ILaunchRequestArguments extends DebugProtocol.LaunchRequestArguments {
gatewayAddress: string;
managementAddress: string;
managementAuth: string;
subscriptionId: string;
operationData: string;
fileName: string;
stopOnEntry?: boolean;
}
export class ApimDebugSession extends LoggingDebugSession {
private availablePolicies: string[];
private runtime: DebuggerConnection;
private configurationDone = new Subject();
private requests: UiRequest[] = [];
private policySource: PolicySource;
private variablesHandles = new Handles<string>();
public constructor() {
super();
this.setDebuggerLinesStartAt1(false);
this.setDebuggerColumnsStartAt1(false);
this.runtime = new DebuggerConnection();
this.runtime.on('stopOnEntry', (requestId, threadId, operationId, apiId, productId) => this.onStop('entry', requestId, threadId, operationId, apiId, productId));
this.runtime.on('stopOnStep', (requestId, threadId, operationId, apiId, productId) => this.onStop('step', requestId, threadId, operationId, apiId, productId));
this.runtime.on('stopOnBreakpoint', (requestId, threadId, operationId, apiId, productId) => this.onStop('breakpoint', requestId, threadId, operationId, apiId, productId));
this.runtime.on('stopOnException', (requestId, threadId, operationId, apiId, productId, message) => this.onStop('exception', requestId, threadId, operationId, apiId, productId, message));
this.runtime.on('threadExited', (requestId, threadId) => this.onThreadExited(requestId, threadId));
this.runtime.on('end', message => {
this.requests = [];
if (message) {
this.sendEvent(new OutputEvent(message, 'stderr'));
}
this.sendEvent(new TerminatedEvent());
});
}
protected initializeRequest(response: DebugProtocol.InitializeResponse, _args: DebugProtocol.InitializeRequestArguments): void {
response.body = response.body || {};
response.body.supportsConfigurationDoneRequest = true;
response.body.supportsRestartRequest = false;
response.body.supportsRestartFrame = false;
this.sendResponse(response);
}
protected configurationDoneRequest(response: DebugProtocol.ConfigurationDoneResponse, args: DebugProtocol.ConfigurationDoneArguments): void {
super.configurationDoneRequest(response, args);
this.configurationDone.notify();
}
protected async launchRequest(response: DebugProtocol.LaunchResponse, args: ILaunchRequestArguments): Promise<void> {
logger.setup(Logger.LogLevel.Verbose, false);
let masterKey;
if (args.managementAuth) {
this.policySource = new PolicySource(args.managementAddress, undefined, args.managementAuth);
masterKey = await this.getMasterSubscriptionKey(args.managementAddress, undefined, args.managementAuth);
this.availablePolicies = await this.getAvailablePolicies(args.managementAddress, undefined, args.managementAuth);
} else {
const credential = await this.getAccountCredentials(args.subscriptionId);
this.policySource = new PolicySource(args.managementAddress, credential);
masterKey = await this.getMasterSubscriptionKey(args.managementAddress, credential);
this.availablePolicies = await this.getAvailablePolicies(args.managementAddress, credential);
}
await this.runtime.attach(args.gatewayAddress, masterKey, !!args.stopOnEntry);
this.sendEvent(new InitializedEvent());
await this.configurationDone.wait(1000);
this.sendResponse(response);
this.updateRequests(await this.runtime.getRequests(), true);
await this.createTestOperationFile(args.operationData, args.fileName);
}
protected async threadsRequest(response: DebugProtocol.ThreadsResponse) {
if (this.runtime.isConnected()) {
this.updateRequests(await this.runtime.getRequests(), true);
}
const threads: Thread[] = [];
for (const nRequest of this.requests) {
for (const thread of nRequest.threads) {
threads.push(new Thread(thread.uiId, `${nRequest.id} (${thread.id})`));
}
}
response.body = {
threads: threads
};
this.sendResponse(response);
}
protected async terminateThreadsRequest(response: DebugProtocol.TerminateThreadsResponse, args: DebugProtocol.TerminateThreadsArguments, _request?: DebugProtocol.Request) {
const requests = args.threadIds!.map(id => this.findThreadByUiId(id));
if (requests.length) {
await this.runtime.terminateRequests(requests.map(r => r![0].id).filter((value, index, self) => self.indexOf(value) === index));
}
this.sendResponse(response);
}
protected async stackTraceRequest(response: DebugProtocol.StackTraceResponse, args: DebugProtocol.StackTraceArguments) {
let stack: StackFrame[] = [];
if (this.runtime.isConnected()) {
const nRequest = this.findThreadByUiId(args.threadId);
if (nRequest) {
const requestStack = await this.runtime.getStackTrace(nRequest[0].id, nRequest[1].id);
stack = await nRequest[1].getStackFrames(requestStack);
for (const item of <DebugProtocol.StackFrame[]>stack) {
if (item.line) {
item.line = this.convertDebuggerLineToClient(item.line);
}
if (item.column) {
item.column = this.convertDebuggerColumnToClient(item.column);
}
if (item.endLine) {
item.endLine = this.convertDebuggerLineToClient(item.endLine);
}
if (item.endColumn) {
item.endColumn = this.convertDebuggerColumnToClient(item.endColumn) + 1;
}
}
}
}
response.body = {
stackFrames: stack,
totalFrames: stack.length
};
this.sendResponse(response);
}
protected async sourceRequest(response: DebugProtocol.SourceResponse, args: DebugProtocol.SourceArguments) {
const policy = this.policySource.getPolicyBySourceReference(args.sourceReference);
if (policy !== null && policy.xml !== null) {
response.body = {
content: policy && policy.xml,
mimeType: 'application/vnd.ms-azure-apim.policy.raw+xml'
};
this.sendResponse(response);
}
}
protected async continueRequest(response: DebugProtocol.ContinueResponse, args: DebugProtocol.ContinueArguments) {
const nRequest = this.findThreadByUiId(args.threadId);
if (nRequest && this.runtime.isConnected()) {
await this.runtime.continue(nRequest[0].id, nRequest[1].id);
}
response.body = {
allThreadsContinued: false
};
this.sendResponse(response);
}
protected async nextRequest(response: DebugProtocol.NextResponse, args: DebugProtocol.NextArguments) {
const nRequest = this.findThreadByUiId(args.threadId);
if (nRequest && this.runtime.isConnected()) {
await this.runtime.stepOver(nRequest[0].id, nRequest[1].id);
}
this.sendResponse(response);
}
protected async stepInRequest(response: DebugProtocol.StepInResponse, args: DebugProtocol.StepInArguments) {
const nRequest = this.findThreadByUiId(args.threadId);
if (nRequest && this.runtime.isConnected()) {
await this.runtime.stepIn(nRequest[0].id, nRequest[1].id);
}
this.sendResponse(response);
}
protected async stepOutRequest(response: DebugProtocol.StepOutResponse, args: DebugProtocol.StepOutArguments) {
const nRequest = this.findThreadByUiId(args.threadId);
if (nRequest && this.runtime.isConnected()) {
await this.runtime.stepOut(nRequest[0].id, nRequest[1].id);
}
this.sendResponse(response);
}
protected async pauseRequest(response: DebugProtocol.PauseResponse, args: DebugProtocol.PauseArguments) {
const nRequest = this.findThreadByUiId(args.threadId);
if (nRequest && this.runtime.isConnected()) {
await this.runtime.pause(nRequest[0].id, nRequest[1].id);
}
this.sendResponse(response);
}
protected scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments) {
let scopes: Scope[] = [];
const nRequest = this.findThreadByStackFrameId(args.frameId);
if (nRequest) {
scopes = [new Scope("Request", this.variablesHandles.create(`${nRequest[0].id}|${nRequest[1].id}`), true)];
}
response.body = {
scopes: scopes || []
};
this.sendResponse(response);
}
protected async variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments) {
let variables: Variable[] = [];
if (this.runtime.isConnected()) {
const variableScope = this.variablesHandles.get(args.variablesReference);
const scopeParts = variableScope.split('|');
if (scopeParts.length >= 2) {
const vars = await this.runtime.getVariables(scopeParts[0], +scopeParts[1], scopeParts.slice(2).join('.'));
variables = vars.map(v => {
const variable = new Variable(v.name, v.value || "", v.nestedCount ? this.variablesHandles.create(`${variableScope}|${v.name}`) : 0);
(<DebugProtocol.Variable>variable).type = v.type;
(<DebugProtocol.Variable>variable).namedVariables = v.nestedCount;
(<DebugProtocol.Variable>variable).presentationHint = {
kind: 'property',
visibility: 'public'
};
return variable;
});
}
}
response.body = {
variables: variables || []
};
this.sendResponse(response);
}
protected async setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments) {
const breakpoints = await this.setBreakpoints(args);
const nBreakpoints: Breakpoint[] = (breakpoints.length !== 0) ? breakpoints : (args.breakpoints) ? args.breakpoints.map(_b => new Breakpoint(false)) : [];
response.body = {
breakpoints: nBreakpoints
};
this.sendResponse(response);
}
private async createTestOperationFile(operationData: string, fileName: string) {
const localFilePath: string = await createTemporaryFile(fileName);
const document: vscode.TextDocument = await vscode.workspace.openTextDocument(localFilePath);
const textEditor: vscode.TextEditor = await vscode.window.showTextDocument(document);
await writeToEditor(textEditor, operationData);
await textEditor.document.save();
}
private async setBreakpoints(args: DebugProtocol.SetBreakpointsArguments): Promise<Breakpoint[]> {
let breakpoints: Breakpoint[] = [];
const breakpointsToSet: {
path: string,
scopeId: string
}[] = [];
let policy = this.policySource.getPolicyBySourceReference(args.source.sourceReference);
if (!policy && args.source.name) {
policy = this.policySource.getPolicy(args.source.name) || await this.policySource.fetchPolicy(args.source.name);
}
if (args.breakpoints && args.breakpoints.length) {
// set breakpoints if has policy otherwise check if it's initialization
if (policy && policy !== null) {
breakpoints = args.breakpoints.map(b => {
let position = {
line: -1,
column: -1,
endLine: -1,
endColumn: -1
};
let path: string | null = null;
const breakpointLine = this.convertClientLineToDebugger(b.line);
const breakpointColumn = b.column && this.convertClientColumnToDebugger(b.column);
for (const key in policy!.map) {
const mapEntry = policy!.map[key];
if (mapEntry.line === breakpointLine
&& (!breakpointColumn || breakpointColumn >= mapEntry.column && breakpointColumn <= mapEntry.endColumn)
&& (position.line === -1 || mapEntry.column < position.column)) {
path = key;
position = mapEntry;
}
}
if (position.line === -1) {
return new Breakpoint(false);
}
if (path === null) {
throw new Error("Path is null");
}
let policyName = path.substring(path.lastIndexOf('/') + 1);
if (policyName.indexOf('[') !== -1) {
policyName = policyName.substring(0, policyName.lastIndexOf('['));
}
if (this.availablePolicies.indexOf(policyName) === -1) {
return new Breakpoint(false);
}
breakpointsToSet.push({
path: path.substr(path.indexOf('/') + 1), //Remove 'policies/' prefix
scopeId: policy!.scopeId
});
const breakpoint = new Breakpoint(true, this.convertDebuggerLineToClient(position.line), this.convertDebuggerColumnToClient(position.column), policy!.source);
(<DebugProtocol.Breakpoint>breakpoint).endLine = this.convertDebuggerLineToClient(position.endLine);
(<DebugProtocol.Breakpoint>breakpoint).endColumn = this.convertDebuggerColumnToClient(position.endColumn);
return breakpoint;
});
}
}
await this.runtime.setBreakpoints(breakpointsToSet, policy!.scopeId);
return breakpoints;
}
private onThreadExited(requestId: string, threadId: number) {
const nRequest = this.requests.find(r => r.id === requestId);
const thread = nRequest && nRequest.findThreadById(threadId);
if (thread) {
this.sendEvent(new ThreadEvent('exited', thread.uiId));
}
}
private onStop(event: string, requestId: string, threadId: number, operationId: string, apiId: string, productId: string, exceptionText?: string) {
this.updateRequests([
{
id: requestId,
threads: [threadId],
operationId: operationId,
apiId: apiId,
productId: productId
}
], false);
const nRequest = this.requests.find(r => r.id === requestId);
const thread = nRequest && nRequest.findThreadById(threadId);
if (thread) {
this.sendEvent(new StoppedEvent(event, thread.uiId, exceptionText));
}
}
private async getAccountCredentials(subscriptionId: string): Promise<ServiceClientCredentials> {
const azureAccountExtension = vscode.extensions.getExtension('ms-vscode.azure-account');
const azureAccount = azureAccountExtension!.exports;
await azureAccount.waitForFilters();
if (azureAccount.status !== 'LoggedIn') {
throw new Error("ERROR!");
}
const creds = azureAccount.filters.filter(filter => filter.subscription.subscriptionId === subscriptionId).map(filter => filter.session.credentials);
return creds[0];
}
private async getMasterSubscriptionKey(managementAddress: string, credential?: ServiceClientCredentials, managementAuth?: string) {
const resourceUrl = `${managementAddress}/subscriptions/master?api-version=2019-01-01`;
const authToken = managementAuth ? managementAuth : await getBearerToken(resourceUrl, "GET", credential!);
const subscription: IApimSubscription = await request.get(resourceUrl, {
headers: {
Authorization: authToken
},
strictSSL: false,
json: true
}).on('error', _e => {
this.sendEvent(new TerminatedEvent());
}).on('response', e => {
if (e.statusCode !== 200) {
this.sendEvent(new OutputEvent(`Error fetching master subscription: ${e.statusCode} ${e.statusMessage}`, 'stderr'));
this.sendEvent(new TerminatedEvent());
}
});
return subscription.properties.primaryKey;
}
private async getAvailablePolicies(managementAddress: string, credential?: ServiceClientCredentials, managementAuth?: string) {
const resourceUrl = `${managementAddress}/policysnippets?api-version=2019-01-01`;
const authToken = managementAuth ? managementAuth : await getBearerToken(resourceUrl, "GET", credential!);
const snippets: IPolicySnippet[] = await request.get(resourceUrl, {
headers: {
Authorization: authToken
},
strictSSL: false,
json: true
}).on('error', _e => {
this.sendEvent(new TerminatedEvent());
}).on('response', e => {
if (e.statusCode !== 200) {
this.sendEvent(new OutputEvent(`Error fetching policy definitions: ${e.statusCode} ${e.statusMessage}`, 'stderr'));
this.sendEvent(new TerminatedEvent());
}
});
return snippets.map(s => s.content.substring(1, /[\s>/]/.exec(s.content)!.index));
}
private findThreadByUiId(id: number): [UiRequest, UiThread] | null {
for (const uiRequest of this.requests) {
const uiThread = uiRequest.findThreadByUiId(id);
if (uiThread) {
return [uiRequest, uiThread];
}
}
return null;
}
private findThreadByStackFrameId(id: number): [UiRequest, UiThread] | null {
for (const uiRequest of this.requests) {
const uiThread = uiRequest.findThreadByStackFrameId(id);
if (uiThread) {
return [uiRequest, uiThread];
}
}
return null;
}
private updateRequests(gatewayRequests: RequestContract[], clean: boolean) {
if (clean) {
let requestIndex = 0;
while (requestIndex < this.requests.length) {
const uiRequest = this.requests[requestIndex];
const gatewayRequest = gatewayRequests.find(r => r.id === uiRequest.id);
if (!gatewayRequest) {
for (const thread of uiRequest.threads) {
this.sendEvent(new ThreadEvent('exited', thread.uiId));
}
this.requests.splice(requestIndex, 1);
continue;
}
let threadIndex = 0;
while (threadIndex < uiRequest.threads.length) {
const uiThread = uiRequest.threads[threadIndex];
if (gatewayRequest.threads.indexOf(uiThread.id) < 0) {
this.sendEvent(new ThreadEvent('exited', uiThread.uiId));
uiRequest.threads.splice(threadIndex, 1);
continue;
}
threadIndex++;
}
if (!uiRequest.threads.length) {
this.requests.splice(requestIndex, 1);
continue;
}
requestIndex++;
}
}
for (const gatewayRequest of gatewayRequests) {
let uiRequest = this.requests.find(r => r.id === gatewayRequest.id);
if (!uiRequest) {
this.requests.push(uiRequest = new UiRequest(gatewayRequest.id, gatewayRequest.operationId, gatewayRequest.apiId, gatewayRequest.productId));
}
for (const gatewayThread of gatewayRequest.threads) {
let uiThread = uiRequest.threads.find(t => t.id === gatewayThread);
if (!uiThread) {
uiThread = uiRequest.addNewThread(gatewayThread, this.policySource);
this.sendEvent(new ThreadEvent('started', uiThread.uiId));
}
}
}
}
}
interface IApimSubscription {
properties: {
primaryKey: string;
secondaryKey: string;
};
}
interface IPolicySnippet {
content: string;
}

Просмотреть файл

@ -0,0 +1,7 @@
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
import { ApimDebugSession } from './apimDebug';
ApimDebugSession.run(ApimDebugSession);

Просмотреть файл

@ -0,0 +1,219 @@
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
import { EventEmitter } from 'events';
import * as WebSocket from "ws";
// tslint:disable: no-unsafe-any
// tslint:disable: indent
// tslint:disable: export-name
// tslint:disable: strict-boolean-expressions
// tslint:disable: typedef
// tslint:disable: no-non-null-assertion
// tslint:disable: no-any
// tslint:disable: no-reserved-keywords
// tslint:disable: interface-name
export interface MockBreakpoint {
id: number;
line: number;
verified: boolean;
}
export class DebuggerConnection extends EventEmitter {
private connection: WebSocket | null;
private responseAwaiters: {
[key: string]: ((value: any) => void)[]
} = {};
constructor() {
super();
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
}
public isConnected() {
return this.connection != null;
}
public async attach(address: string, key: string, stopOnEntry: boolean) {
let connection: WebSocket;
return new Promise((resolve, reject) => {
connection = new WebSocket(`${address}?key=${key}`)
.on('error', e => {
if (this.connection == null || this.connection === connection) {
this.connection = null;
this.sendEvent('end', `Can't connect to gateway: ${e.message}.`);
}
reject();
})
.on('open', () => {
this.connection = connection;
this.sendCommand('attach', {
break: stopOnEntry
});
resolve();
})
.on('message', e => {
this.parseResponse(e.toString());
});
});
}
public async getRequests() {
return this.waitForResponse<RequestContract[]>(() => this.sendCommand('getRequests'), 'requests');
}
public async getStackTrace(requestId: string, threadId: number) {
return this.waitForResponse<StackFrameContract[]>(() => this.sendCommand('getStackTrace', {
requestId: requestId,
threadId: threadId
}), 'stackTrace');
}
public async getVariables(requestId: string, threadId: number, path?: string) {
return this.waitForResponse<VariableContract[]>(() => this.sendCommand('getVariables', {
requestId: requestId,
threadId: threadId,
path: path
}), 'variables');
}
public async setBreakpoints(breakpoints: { path: string, scopeId: string}[], scopeId: string) {
this.sendCommand('setBreakpoints', {
scopeId: scopeId,
breakpoints: breakpoints
});
}
public async stepOver(requestId: string, threadId: number) {
this.sendCommand('stepOver', {
requestId: requestId,
threadId: threadId
});
}
public async stepIn(requestId: string, threadId: number) {
this.sendCommand('stepIn', {
requestId: requestId,
threadId: threadId
});
}
public async stepOut(requestId: string, threadId: number) {
this.sendCommand('stepOut', {
requestId: requestId,
threadId: threadId
});
}
public async continue(requestId: string, threadId: number) {
this.sendCommand('continue', {
requestId: requestId,
threadId: threadId
});
}
public async pause(requestId: string, threadId: number) {
this.sendCommand('pause', {
requestId: requestId,
threadId: threadId
});
}
public async terminateRequests(requests: string[]) {
this.sendCommand('terminateRequests', {
requests: requests
});
}
private sendCommand(name: string, args?: any) {
if (this.connection == null) {
return;
}
this.connection.send(JSON.stringify({
name: name,
arguments: args
}));
}
private parseResponse(data: string) {
try {
// tslint:disable-next-line: no-banned-terms
const event: { name: string, arguments: any } = JSON.parse(data.trim());
// tslint:disable-next-line: switch-default
switch (event.name) {
case 'stopOnEntry':
this.sendEvent(event.name, event.arguments.requestId, event.arguments.threadId, event.arguments.operationId, event.arguments.apiId, event.arguments.productId);
break;
case 'stopOnStep':
this.sendEvent(event.name, event.arguments.requestId, event.arguments.threadId, event.arguments.operationId, event.arguments.apiId, event.arguments.productId);
break;
case 'stopOnException':
this.sendEvent(event.name, event.arguments.requestId, event.arguments.threadId, event.arguments.operationId, event.arguments.apiId, event.arguments.productId, event.arguments.message);
break;
case 'stopOnBreakpoint':
this.sendEvent(event.name, event.arguments.requestId, event.arguments.threadId, event.arguments.operationId, event.arguments.apiId, event.arguments.productId);
break;
case 'threadExited':
this.sendEvent(event.name, event.arguments.requestId, event.arguments.threadId, event.arguments.operationId, event.arguments.apiId, event.arguments.productId);
break;
}
const awaiters = this.responseAwaiters[event.name];
if (awaiters) {
for (const awaiter of awaiters) {
awaiter(event.arguments);
}
delete this.responseAwaiters[event.name];
}
} catch {
return;
}
}
private async waitForResponse<T>(sendCommand: () => void, name: string) {
return new Promise<T>(resolve => {
(this.responseAwaiters[name] || (this.responseAwaiters[name] = [])).push(resolve);
sendCommand();
});
}
private sendEvent(event: string, ...args: any[]) {
setImmediate(_ => {
this.emit(event, ...args);
});
}
}
export interface RequestContract {
id: string;
threads: number[];
operationId: string;
apiId: string;
productId: string;
}
export interface StackFrameContract {
scopeId: string;
index: number;
name: string;
section: string;
}
export enum StackFrameScopeContract {
operation = '/operations',
api = '/apis',
product = '/products',
tenant = '/tenant'
}
export interface VariableContract {
name: string;
type: string;
value: any;
nestedCount: any;
}

66
src/debugger/extension.ts Normal file
Просмотреть файл

@ -0,0 +1,66 @@
'use strict';
import * as Net from 'net';
import * as vscode from 'vscode';
import { CancellationToken, DebugConfiguration, ProviderResult, WorkspaceFolder } from 'vscode';
import { ApimDebugSession } from './apimDebug';
// tslint:disable: no-unsafe-any
// tslint:disable: indent
// tslint:disable: export-name
// tslint:disable: strict-boolean-expressions
// tslint:disable: typedef
// tslint:disable: no-non-null-assertion
// tslint:disable: no-any
// tslint:disable: no-empty
export function activate(context: vscode.ExtensionContext) {
const provider = new ApimPolicyConfigurationProvider();
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('apim-policy', provider));
const factory = new ApimPolicyDebugAdapterDescriptorFactory();
context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory('apim-policy', factory));
context.subscriptions.push(factory);
}
export function deactivate() {}
class ApimPolicyConfigurationProvider implements vscode.DebugConfigurationProvider {
public resolveDebugConfiguration(_folder: WorkspaceFolder | undefined, config: DebugConfiguration, _token?: CancellationToken): ProviderResult<DebugConfiguration> {
if (!config.type && !config.request && !config.name) {
const editor = vscode.window.activeTextEditor;
if (editor && editor.document.languageId === 'apim-policy') {
config.type = 'apim-policy';
config.name = 'Debug open APIM policy';
config.request = 'launch';
config.stopOnEntry = true;
}
}
return config;
}
}
class ApimPolicyDebugAdapterDescriptorFactory implements vscode.DebugAdapterDescriptorFactory {
private server?: Net.Server;
public createDebugAdapterDescriptor(_session: vscode.DebugSession, _executable: vscode.DebugAdapterExecutable | undefined): vscode.ProviderResult<vscode.DebugAdapterDescriptor> {
if (!this.server) {
// start listening on a random port
this.server = Net.createServer(socket => {
const session = new ApimDebugSession();
session.setRunAsServer(true);
session.start(<NodeJS.ReadableStream>socket, socket);
}).listen(0);
}
// make VS Code connect to debug server
return new vscode.DebugAdapterServer(this.server.address().port);
}
public dispose() {
if (this.server) {
this.server.close();
}
}
}

Просмотреть файл

@ -0,0 +1,405 @@
// tslint:disable: no-unsafe-any
// tslint:disable: indent
// tslint:disable: export-name
// tslint:disable: strict-boolean-expressions
// tslint:disable: typedef
// tslint:disable: no-non-null-assertion
// tslint:disable: no-for-in
// tslint:disable: forin
// tslint:disable: no-any
// tslint:disable: no-reserved-keywords
// tslint:disable: interface-name
// tslint:disable: no-empty
// tslint:disable: prefer-template
export class PolicyMapper {
public static WhiteSpaceCharacters = " \r\n\t";
public static NameCharacters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-:";
private index: number;
private xml: string;
private map: PolicyMap;
private count: {
[key: string]: number
};
private stack: string[];
private line: number;
private column: number;
private capturedLocation: {
line: number,
column: number,
index: number;
};
public mapPolicy(xml: string) {
this.index = 0;
this.xml = xml;
this.count = {};
this.map = {};
this.stack = [];
this.line = 0;
this.column = 0;
while (this.index < this.xml.length && (this.xmlComment() || this.element())) { }
return this.map;
}
// tslint:disable: cyclomatic-complexity
// tslint:disable: max-func-body-length
private element() {
this.captureLocation();
let nameStart = -1;
let name: string | null = null;
let start: [number, number] | null = null;
let end: [number, number] | null = null;
let selfClosing = false;
let closing = false;
while (this.index < this.xml.length) {
const char = this.xml[this.index];
if (char === '<') {
if (!start) {
start = [this.line, this.column];
}
} else if (char === '/') {
if (!name) {
if (nameStart > 0 && !name) {
name = this.xml.substring(nameStart, this.index);
const curkey = this.stack.length === 0 ? `${name}[1]` : this.stack.join('/') + `/${name}[1]`;
//const curkey = this.stack.reduce((a, b) => `${a}/${b}`) + `${name}[1]`;
if (this.count[curkey]) {
this.stack.push(name + `[${this.count[curkey] + 1}]`);
this.count[curkey]++;
} else {
this.stack.push(name + `[1]`);
this.count[curkey] = 1;
}
} else {
break;
}
}
if (!end) {
selfClosing = true;
} else {
closing = true;
}
} else if (char === '>') {
if (nameStart > 0 && !name) {
name = this.xml.substring(nameStart, this.index);
const curkey = this.stack.length === 0 ? `${name}[1]` : this.stack.join('/') + `/${name}[1]`;
if (this.count[curkey]) {
this.stack.push(name + `[${this.count[curkey] + 1}]`);
this.count[curkey]++;
} else {
this.stack.push(name + `[1]`);
this.count[curkey] = 1;
}
}
if (!end && start !== null) {
end = [this.line, this.column];
this.addElementToMap(start, end);
}
this.advance();
if (closing || selfClosing) {
this.stack.pop();
return true;
}
if (this.elementValue()) {
continue;
}
} else if (char === '<') {
if (end) {
closing = true;
} else {
break;
}
} else if (PolicyMapper.WhiteSpaceCharacters.indexOf(char) >= 0) {
if (nameStart >= 0 && !name) {
name = this.xml.substring(nameStart, this.index);
const curkey = this.stack.length === 0 ? `${name}[1]` : this.stack.join('/') + `/${name}[1]`;
if (this.count[curkey]) {
this.stack.push(name + `[${this.count[curkey] + 1}]`);
this.count[curkey]++;
} else {
this.stack.push(name + `[1]`);
this.count[curkey] = 1;
}
}
if (name && !end && this.attributes()) {
continue;
}
} else if (PolicyMapper.NameCharacters.indexOf(char) >= 0) {
if (start && nameStart < 0) {
nameStart = this.index;
} else if (name && !closing) {
break;
}
} else {
break;
}
this.advance();
}
this.backtrack();
return false;
}
private xmlComment() {
this.captureLocation();
let openCount = 0;
let closeCount = 0;
while (this.index < this.xml.length) {
const char = this.xml[this.index];
if (char === '<') {
if (openCount === 0) {
openCount++;
}
} else if (char === '!') {
if (openCount === 1) {
openCount++;
} else {
openCount = 0;
}
} else if (char === '-') {
if (openCount === 2 || openCount === 3) {
openCount++;
} else if (openCount === 4) {
if (closeCount < 2) {
closeCount++;
} else {
closeCount = 0;
}
} else {
break;
}
} else if (char === '>') {
if (closeCount === 2) {
this.advance();
return true;
}
} else if (PolicyMapper.WhiteSpaceCharacters.indexOf(char) >= 0) {
if (openCount > 0 && openCount < 4) {
break;
}
closeCount = 0;
} else {
if (openCount < 4) {
break;
}
closeCount = 0;
}
this.advance();
}
this.backtrack();
return false;
}
private attributes() {
let flag = false;
while (this.attribute()) {
flag = true;
}
return flag;
}
private attribute() {
this.captureLocation();
let nameStart = -1;
let name: string | null = null;
let hasValue = false;
while (this.index < this.xml.length) {
const char = this.xml[this.index];
if (char === '=') {
if (nameStart >= 0 && !name) {
name = this.xml.substring(nameStart, this.index);
}
if (!name) {
break;
}
} else if (char === '"') {
if (!name) {
break;
}
if (hasValue) {
this.advance();
return true;
}
this.advance();
if (this.expression()) {
hasValue = true;
}
if (this.simpleValue('"', true)) {
hasValue = true;
continue;
} else {
break;
}
} else if (PolicyMapper.WhiteSpaceCharacters.indexOf(char) >= 0) {
if (hasValue) {
return true;
}
if (nameStart >= 0) {
name = this.xml.substring(nameStart, this.index);
}
} else if (PolicyMapper.NameCharacters.indexOf(char) >= 0) {
if (nameStart < 0) {
nameStart = this.index;
}
} else {
break;
}
this.advance();
}
this.backtrack();
return false;
}
private expression() {
this.captureLocation();
let at = false;
let openingBracket: string | null = null;
let closingBracket: string | null = null;
let bracketDepth = -1;
while (this.index < this.xml.length) {
const char = this.xml[this.index];
if (char === '@') {
if (at) {
break;
}
at = true;
} else if (char === '{' || char === '(') {
if (!at) {
break;
}
if (!openingBracket) {
openingBracket = char;
closingBracket = char === '{' ? '}' : ')';
bracketDepth = 0;
} else if (openingBracket === char) {
bracketDepth++;
}
} else if (char === '}' || char === ')') {
if (!openingBracket) {
break;
}
if (closingBracket === char && --bracketDepth <= 0) {
this.advance();
return true;
}
} else if (bracketDepth >= 0) {
// Just advance.
} else if (PolicyMapper.WhiteSpaceCharacters.indexOf(char) >= 0) {
// Just advance.
} else {
break;
}
this.advance();
}
this.backtrack();
return false;
}
private simpleValue(terminator: string, allowEmpty: boolean) {
this.captureLocation();
let empty = true;
while (this.index < this.xml.length) {
const char = this.xml[this.index];
if (char === terminator) {
if (empty && !allowEmpty) {
break;
}
return true;
} else if (PolicyMapper.WhiteSpaceCharacters.indexOf(char) < 0) {
empty = false;
}
this.advance();
}
this.backtrack();
return false;
}
private elementValue() {
let flag = false;
while (this.expression() || this.xmlComment() || this.element() || this.simpleValue('<', false)) {
flag = true;
}
return flag;
}
private advance() {
if (this.xml[this.index] === '\n') {
this.line++;
this.column = 0;
} else {
this.column++;
}
this.index++;
}
private addElementToMap(start: [number, number], end: [number, number]) {
const key = this.stack.reduce((a, b) => `${a}/${b}`);
this.map[key] = {
line: start[0],
endLine: end[0],
column: start[1],
endColumn: end[1]
};
}
private captureLocation() {
this.capturedLocation = {
line: this.line,
column: this.column,
index: this.index
};
}
private backtrack() {
this.line = this.capturedLocation.line;
this.column = this.capturedLocation.column;
this.index = this.capturedLocation.index;
}
}
export interface PolicyMap {
[path: string]: PolicyLocation;
}
export interface PolicyLocation {
line: number;
endLine: number;
column: number;
endColumn: number;
}

Просмотреть файл

@ -0,0 +1,161 @@
import { ServiceClientCredentials } from 'ms-rest';
import * as path from 'path';
import * as request from 'request-promise-native';
import { Source } from 'vscode-debugadapter';
import { getBearerToken } from '../utils/requestUtil';
import { StackFrameScopeContract } from './debuggerConnection';
import { PolicyLocation, PolicyMap, PolicyMapper } from './policyMapper';
// tslint:disable: no-unsafe-any
// tslint:disable: indent
// tslint:disable: export-name
// tslint:disable: strict-boolean-expressions
// tslint:disable: no-non-null-assertion
// tslint:disable: no-for-in
// tslint:disable: forin
// tslint:disable: no-shadowed-variable
// tslint:disable: interface-name
export class PolicySource {
private static NextSourceReference : number = 1;
private managementAddress: string;
private credential: ServiceClientCredentials | undefined;
private auth: string | undefined;
private policies: { [key: string]: Policy } = {};
constructor(managementAddress: string, credential?: ServiceClientCredentials, auth?: string) {
this.managementAddress = managementAddress;
this.credential = credential;
this.auth = auth;
if (!credential && !auth) {
throw new Error("Missing credentials!");
}
}
public getPolicyLocation(scopeId: string, path: string): PolicyLocation | null {
const policy = this.policies[this.normalizeScopeId(scopeId)];
if (!policy) {
return null;
}
if (Object.keys(policy.map).includes(path)) {
return policy.map[path];
}
const paths = path.split("/");
const mapKeys = Object.keys(policy.map).map(s => s.split("/")).filter(s => s.length === paths.length);
for (const curKey of mapKeys) {
let isEqual = true;
// tslint:disable-next-line: prefer-for-of
for (let idx = 0; idx < paths.length; idx++) {
if (paths[idx] === curKey[idx]) {
continue;
} else {
isEqual = false;
}
}
if (isEqual === true) {
return policy.map[curKey.join("/")];
}
}
return null;
}
public async fetchPolicies(scopes: string[]): Promise<void> {
const policiesToRequest = scopes.map(s => this.normalizeScopeId(s)).filter(s => !this.policies[s]);
if (policiesToRequest.length) {
// Batching goes here
await Promise.all(policiesToRequest.map(s => this.fetchPolicy(s).catch(_e => null)));
}
}
public getPolicyBySourceReference(id: number | undefined): Policy | null {
for (const scope in this.policies) {
const policy = this.policies[scope];
if (policy && policy.source && policy.source.sourceReference === id) {
return policy;
}
}
return null;
}
public getPolicy(scopeId: string): Policy {
return this.policies[this.normalizeScopeId(scopeId)];
}
public async fetchPolicy(scopeId: string): Promise<Policy | null> {
scopeId = this.normalizeScopeId(scopeId);
const policyUrl = this.getPolicyUrl(scopeId);
if (!policyUrl) {
return null;
}
let authToken;
if (this.auth) {
authToken = this.auth;
} else {
authToken = await getBearerToken(policyUrl, "GET", this.credential!);
}
const policyContract: PolicyContract = await request.get(policyUrl, {
headers: {
Authorization: authToken
},
strictSSL: false,
json: true
}).on('error', _e => {
//const a = 5;
}).on('response', _e => {
//const a = 5;
});
const policy = this.policies[scopeId] || (this.policies[scopeId] = {
scopeId: scopeId,
xml: null,
source: new Source(scopeId, path.normalize(scopeId), PolicySource.NextSourceReference++),
map: {}
});
policy.xml = policyContract.properties.value;
this.mapPolicy(policy);
return policy;
}
private normalizeScopeId(scopeId: string): string {
return scopeId.replace(/\\/g, '/');
}
private mapPolicy(policy: Policy): void {
if (!policy || !policy.xml) {
return;
}
policy.map = new PolicyMapper().mapPolicy(policy.xml);
}
private getPolicyUrl(scopeId: string): string {
if (scopeId === StackFrameScopeContract.tenant) {
return `${this.managementAddress}/policies/policy?api-version=2019-01-01&format=xml-raw`;
} else {
return `${this.managementAddress}/${scopeId}/policies/policy?api-version=2019-01-01&format=xml-raw`;
}
}
}
interface PolicyContract {
properties: {
format: string,
value: string
};
}
interface Policy {
scopeId: string;
xml: string | null;
source: Source;
map: PolicyMap;
}

59
src/debugger/uiRequest.ts Normal file
Просмотреть файл

@ -0,0 +1,59 @@
import { PolicySource } from "./policySource";
import { UiThread } from "./uiThread";
// tslint:disable: indent
// tslint:disable: export-name
export class UiRequest {
public id: string;
public threads: UiThread[];
private operationId: string;
private apiId: string;
private productId: string;
constructor(id: string, operationId: string, apiId: string, productId: string) {
this.id = id;
this.threads = [];
this.operationId = operationId;
this.apiId = apiId;
this.productId = productId;
}
public addNewThread(gatewayThread: number, policySource: PolicySource): UiThread {
let thread: UiThread;
this.threads.push(thread = new UiThread(gatewayThread, this.operationId, this.apiId, this.productId, policySource));
return thread;
}
public findThreadByStackFrameId(id: number): UiThread | null {
for (const thread of this.threads) {
if (thread.containsStackFrame(id)) {
return thread;
}
}
return null;
}
public findThreadById(id: number): UiThread | null {
for (const thread of this.threads) {
if (thread.id === id) {
return thread;
}
}
return null;
}
public findThreadByUiId(uiId: number): UiThread | null {
for (const thread of this.threads) {
if (thread.uiId === uiId) {
return thread;
}
}
return null;
}
}

191
src/debugger/uiThread.ts Normal file
Просмотреть файл

@ -0,0 +1,191 @@
import { StackFrame } from 'vscode-debugadapter';
import { DebugProtocol } from 'vscode-debugprotocol';
import { StackFrameContract, StackFrameScopeContract } from './debuggerConnection';
import { PolicySource } from './policySource';
// tslint:disable: indent
// tslint:disable: export-name
// tslint:disable: strict-boolean-expressions
// tslint:disable: no-non-null-assertion
// tslint:disable: no-for-in
// tslint:disable: forin
// tslint:disable: interface-name
interface PendingSource {
scopeId: string;
stackFrames: StackFrame[];
}
export class UiThread {
private static NextThreadId: number = 1;
private static NextStackFrameId: number = 1;
public id: number;
public uiId: number;
private operationId: string;
private apiId: string;
private productId: string;
private stackFrames: {
[key: string]: StackFrame
} = {};
private policySource: PolicySource;
constructor(id: number, operationId: string, apiId: string, productId: string, policySource: PolicySource) {
this.id = id;
this.uiId = UiThread.NextThreadId++;
this.operationId = operationId;
this.apiId = apiId;
this.productId = productId;
this.policySource = policySource;
}
private static addPendingSource(pendingSources: PendingSource[], frame: StackFrameContract, stackFrame: StackFrame): void {
let pendingSource = pendingSources.find(s => s.scopeId === frame.scopeId);
if (!pendingSource) {
pendingSources.push(pendingSource = {
scopeId: frame.scopeId,
stackFrames: []
});
}
pendingSource.stackFrames.push(stackFrame);
}
public containsStackFrame(id: number): boolean {
for (const key in this.stackFrames) {
if (this.stackFrames[key].id === id) {
return true;
}
}
return false;
}
// tslint:disable-next-line: cyclomatic-complexity
public async getStackFrames(frames: StackFrameContract[]): Promise<StackFrame[]> {
if (!frames.length) {
return [];
}
// Create UI stack frames
const stack: {
key: string,
frame: StackFrameContract,
isVirtual?: boolean,
stackFrame: StackFrame
}[] = [];
const allFrames = this.addVirtualStack(frames);
const pendingSources: PendingSource[] = [];
let prevFrame: StackFrameContract | null = null;
let path: string[] = [];
for (const frame of allFrames.reverse()) {
if (!path.length || prevFrame && (prevFrame.scopeId !== frame.scopeId)) {
// tslint:disable-next-line: prefer-template
path = ['policies[1]', frame.section + "[1]"];
}
prevFrame = frame;
if (!frame.name.endsWith(']')) {
path.push(`${frame.name}[${frame.index || 1}]`);
} else {
path.push(`${frame.name}`);
}
const stackFrameKey = path.join('/');
stack.push({
key: stackFrameKey,
frame: frame,
isVirtual: frame.isVirtual,
stackFrame: this.getStackFrame(frame, stackFrameKey, pendingSources)
});
}
// Fetch any sources if necessary
if (pendingSources.length > 0) {
await this.policySource.fetchPolicies(pendingSources.map(p => p.scopeId));
}
// Assign source line numbers as per scope, name, and index
for (const item of stack) {
const frame = item.frame;
const stackFrame = <DebugProtocol.StackFrame>item.stackFrame;
if (!stackFrame.source) {
const policy = this.policySource.getPolicy(frame.scopeId);
stackFrame.source = policy && policy.source;
}
const location = this.policySource.getPolicyLocation(frame.scopeId, item.key);
if (location) {
stackFrame.line = location.line;
stackFrame.column = location.column;
stackFrame.endLine = location.endLine;
stackFrame.endColumn = location.endColumn;
}
}
// Remove any 'virtual' UI stack frames if no policy present
for (let index = 0; index < stack.length;) {
if (stack[index].isVirtual && (!stack[index].stackFrame.source || !stack[index].stackFrame.line && !stack[index].stackFrame.column)) {
stack.splice(index, 1);
} else {
index++;
}
}
return stack.map(s => s.stackFrame).reverse();
}
private addVirtualStack(frames: StackFrameContract[]): (StackFrameContract & { isVirtual?: true })[] {
const allFrames: (StackFrameContract & { isVirtual?: true })[] = [...frames];
let lastFrame = allFrames[frames.length - 1];
if (lastFrame.scopeId === StackFrameScopeContract.tenant && this.productId) {
allFrames.push(lastFrame = {
scopeId: `/products/${this.productId}`,
name: 'base',
section: lastFrame.section,
index: 0,
isVirtual: true
});
}
if ((lastFrame.scopeId === StackFrameScopeContract.tenant || lastFrame.scopeId.startsWith(StackFrameScopeContract.product)) && this.apiId) {
allFrames.push(lastFrame = {
scopeId: `/apis/${this.apiId}`,
name: 'base',
section: lastFrame.section,
index: 0,
isVirtual: true
});
}
if (lastFrame.scopeId.startsWith(StackFrameScopeContract.api) && !lastFrame.scopeId.includes('/operations/') && this.apiId && this.operationId) {
allFrames.push(lastFrame = {
scopeId: `/apis/${this.apiId}/operations/${this.operationId}`,
name: 'base',
section: lastFrame.section,
index: 0,
isVirtual: true
});
}
return allFrames;
}
private getStackFrame(frame: StackFrameContract, path: string, pendingSources: PendingSource[]): StackFrame {
const frameKey = `${frame.scopeId}/${path}`;
let stackFrame = this.stackFrames[frameKey];
if (!stackFrame) {
this.stackFrames[frameKey] = stackFrame = new StackFrame(UiThread.NextStackFrameId++, frame.name);
const policy = this.policySource.getPolicy(frame.scopeId);
stackFrame.source = policy && policy.source;
if (!stackFrame.source) {
UiThread.addPendingSource(pendingSources, frame, stackFrame);
}
}
return stackFrame;
}
}

Просмотреть файл

@ -80,6 +80,10 @@ export class ApiOperationTreeItem extends AzureParentTreeItem<IOperationTreeRoot
return await new OperationConsole().buildRequestInfo(this.root);
}
public async getOperationDebugInfo(): Promise<string> {
return await new OperationConsole().buildDebugRequestInfo(this.root);
}
private createRoot(subRoot: ISubscriptionRoot): IOperationTreeRoot {
return Object.assign({}, <IApiTreeRoot>subRoot, {
opName : nonNullProp(this.operationContract, 'name')

Просмотреть файл

@ -12,6 +12,7 @@ import { addApiToGateway } from './commands/addApiToGateway';
import { addApiToProduct } from './commands/addApiToProduct';
import { copySubscriptionKey } from './commands/copySubscriptionKey';
import { createService } from './commands/createService';
import { debugPolicy } from './commands/debugPolicies/debugPolicy';
import { deleteNode } from './commands/deleteNode';
import { copyDockerRunCommand, generateKubernetesDeployment } from './commands/deployGateway';
import { extractAPI, extractService } from './commands/extract';
@ -26,6 +27,7 @@ import { openWorkingFolder } from './commands/openWorkingFolder';
import { setupWorkingFolder } from './commands/setupWorkingFolder';
import { testOperation } from './commands/testOperation';
import { doubleClickDebounceDelay } from './constants';
import { activate } from './debugger/extension';
import { ApiManagementProvider } from './explorer/ApiManagementProvider';
import { ApiOperationTreeItem } from './explorer/ApiOperationTreeItem';
import { ApiPolicyTreeItem } from './explorer/ApiPolicyTreeItem';
@ -99,11 +101,14 @@ export function activateInternal(context: vscode.ExtensionContext) {
registerCommand('azureApiManagement.copyDockerRunCommand', async (node: GatewayTreeItem) => await copyDockerRunCommand(node));
registerCommand('azureApiManagement.generateKubernetesDeployment', async (node: GatewayTreeItem) => await generateKubernetesDeployment(node));
registerCommand('azureApiManagement.generateNewGatewayToken', async (node: GatewayTreeItem) => await generateNewGatewayToken(node));
registerCommand('azureApiManagement.debugPolicy', async (node: ApiOperationTreeItem) => await debugPolicy(node));
registerCommand('azureApiManagement.openExtensionWorkspaceFolder', openWorkingFolder);
registerCommand('azureApiManagement.initializeExtensionWorkspaceFolder', setupWorkingFolder);
registerEditors(context);
activate(context); // activeta debug context
}
function registerEditors(context: vscode.ExtensionContext) : void {

Просмотреть файл

@ -4,6 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import { ApiContract, ApiRevisionContract } from "azure-arm-apimanagement/lib/models";
import { ApimService } from "../azure/apim/ApimService";
import { IMasterSubscription } from "../azure/apim/contracts";
import { IOperationTreeRoot } from "../explorer/IOperationTreeRoot";
import { nonNullOrEmptyValue, nonNullProp } from "../utils/nonNull";
import { ConsoleOperation } from "./ConsoleOperation";
@ -45,6 +47,77 @@ export class OperationConsole {
return requestSummary;
}
public async buildDebugRequestInfo(root: IOperationTreeRoot): Promise<string> {
const results = await Promise.all([
root.client.apiManagementService.get(root.resourceGroupName, root.serviceName),
root.client.api.get(root.resourceGroupName, root.serviceName, root.apiName),
root.client.apiOperation.get(root.resourceGroupName, root.serviceName, root.apiName, root.opName),
root.client.apiRevision.listByService(root.resourceGroupName, root.serviceName, root.apiName)]);
const service = results[0];
const api = results[1];
const operation = results[2];
const hostName = nonNullProp(service, "gatewayUrl").split("/")[2];
const consoleOperation = new ConsoleOperation(hostName, operation);
let revision: ApiRevisionContract | undefined;
if (api.apiRevision) {
const revisions = results[3];
revision = revisions.find((r) => r.apiRevision === api.apiRevision);
}
const url = `${this.getRequestUrl(consoleOperation, api, revision)}`;
const method = consoleOperation.method;
let requestSummary = `${method} ${url} HTTP/1.1\n`;
const headers = this.getDebugHeaders();
const apimService = new ApimService(root.credentials, root.environment.resourceManagerEndpointUrl, root.subscriptionId, root.resourceGroupName, root.serviceName);
const masterSubscriptionObj = await apimService.getSubscriptionMasterkey();
const masterSubscription = <IMasterSubscription>JSON.parse(masterSubscriptionObj);
headers.forEach(header => {
requestSummary += `${header}: ${masterSubscription.properties.primaryKey}\n`;
});
requestSummary += "Ocp-Apim-Trace: true\n";
if (consoleOperation.request.body) {
requestSummary += `\n\n${consoleOperation.request.body}`;
}
return requestSummary;
}
// public async buildDebugRequestInfo(root: IOperationTreeRoot): Promise<string> {
// const operation = await root.client.apiOperation.get(root.resourceGroupName, root.serviceName, root.apiName, root.opName);
// const url = getAPIHostUrl(root.serviceName);
// const method = operation.method;
// let body: string | undefined;
// if (operation.request && operation.request.representations && operation.request.representations.length > 0) {
// if (operation.request.representations[0].sample) {
// body = operation.request.representations[0].sample;
// }
// }
// let requestSummary = `${method} ${url} HTTP/1.1\n`;
// const headers = this.getDebugHeaders();
// const apimService = new ApimService(root.credentials, root.environment.resourceManagerEndpointUrl, root.subscriptionId, root.resourceGroupName, root.serviceName);
// const masterSubscriptionObj = await apimService.getSubscriptionMasterkey();
// const masterSubscription = <IMasterSubscription>JSON.parse(masterSubscriptionObj);
// headers.forEach(header => {
// requestSummary += `${header}: ${masterSubscription.properties.primaryKey}\n`;
// });
// if (body) {
// requestSummary += `\n\n${body}`;
// }
// return requestSummary;
// }
private getDebugHeaders(): string[] {
return ["Ocp-Apim-Subscription-Key", "Ocp-Apim-Debug"];
}
private getRequestUrl(consoleOperation: ConsoleOperation, api: ApiContract, revision: ApiRevisionContract | undefined): string {
const protocol = nonNullProp(api, "protocols").indexOf("https") !== -1 ? "https" : "http";
let urlTemplate = this.requestUrl(consoleOperation, api, revision);

Просмотреть файл

@ -39,3 +39,20 @@ export async function requestUtil<T>(url: string, credentials?: ServiceClientCre
export async function sendRequest<T>(httpReq: nRequest): Promise<T> {
return await <Thenable<T>>request(httpReq).promise();
}
export async function getBearerToken(url: string, method: HttpMethods, credentials: ServiceClientCredentials): Promise<string> {
const requestOptions: WebResource = new WebResource();
requestOptions.headers = {
['User-Agent']: appendExtensionUserAgent()
};
requestOptions.url = url;
requestOptions.method = method;
try {
await signRequest(requestOptions, credentials);
} catch (err) {
throw err;
}
const headers = requestOptions.headers;
// tslint:disable-next-line: no-string-literal
return headers['authorization'];
}

Просмотреть файл

@ -71,7 +71,7 @@
},
"linterOptions": {
"exclude": [
"src/test/**" // Enable back when tests are ready.
"src/test/**"
]
}
}