From e9df0c0e6c90206cc46200782ec7488f2864440e Mon Sep 17 00:00:00 2001 From: Brian Leighty Date: Wed, 24 Apr 2024 11:34:45 -0400 Subject: [PATCH] Add on device brightscript repl (#564) * Add on device brightscript repl * switch repl manifest version to 1.0.0 * Verify code is valid before sending to device, add better hinting at need to return a value --------- Co-authored-by: Brian Leighty Co-authored-by: Bronley Plumb --- package-lock.json | 243 +++++++++--------- package.json | 8 +- src/managers/WebviewViewProviderManager.ts | 4 + src/viewProviders/BaseRdbViewProvider.ts | 10 +- src/viewProviders/BaseWebviewViewProvider.ts | 27 +- .../RokuAppOverlaysViewViewProvider.ts | 2 +- .../RokuAutomationViewViewProvider.ts | 24 +- .../RokuDeviceViewViewProvider.ts | 30 +-- .../RokuFileSystemViewViewProvider.ts | 2 +- src/viewProviders/RokuReplViewProvider.ts | 184 +++++++++++++ .../SceneGraphInspectorViewProvider.ts | 2 +- src/viewProviders/ViewProviderCommand.ts | 5 +- src/viewProviders/ViewProviderId.ts | 3 +- webviews/src/ExtensionIntermediary.ts | 2 +- webviews/src/main.ts | 4 +- .../RokuDeviceView/RokuDeviceView.svelte | 2 +- .../views/RokuReplView/RokuReplView.svelte | 134 ++++++++++ 17 files changed, 509 insertions(+), 177 deletions(-) create mode 100644 src/viewProviders/RokuReplViewProvider.ts create mode 100644 webviews/src/views/RokuReplView/RokuReplView.svelte diff --git a/package-lock.json b/package-lock.json index f078347e..fbfe1183 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "glob": "^7.1.3", "hex-rgb": "^5.0.0", "iconv-lite": "0.4.24", + "jszip": "^3.10.1", "just-throttle": "^4.0.1", "net": "^1.0.2", "node-cache": "^4.2.0", @@ -35,7 +36,7 @@ "pretty-bytes": "^5.6.0", "roku-debug": "^0.21.7", "roku-deploy": "^3.12.0", - "roku-test-automation": "^2.0.4", + "roku-test-automation": "^2.0.6", "semver": "^7.1.3", "source-map": "^0.7.3", "thenby": "^1.3.4", @@ -1223,9 +1224,9 @@ "dev": true }, "node_modules/@suitest/types": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@suitest/types/-/types-4.6.0.tgz", - "integrity": "sha512-42NRmZNZ+D+ELcnbT4oRYnq5bAtsl1OhDTfuIp5x8uVh33GcipmbZLKDxBlwVTGCTbIH9xXRN9dS2o4gfzLoGw==" + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@suitest/types/-/types-4.10.0.tgz", + "integrity": "sha512-HY06eniGdHvbkMHWoflpL75+DNm8gh1lXgX2eTdSsY/NqeH6HntZhi8MlMn9oTFHghEuvs3dJVZcuv5+6kJv7A==" }, "node_modules/@tsconfig/node10": { "version": "1.0.9", @@ -1261,9 +1262,9 @@ } }, "node_modules/@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -1297,17 +1298,17 @@ "dev": true }, "node_modules/@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dependencies": { "@types/node": "*" } }, "node_modules/@types/express": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", - "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -1316,9 +1317,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.34", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz", - "integrity": "sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w==", + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", + "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -1345,10 +1346,15 @@ "@types/node": "*" } }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==" + }, "node_modules/@types/http-proxy": { - "version": "1.17.11", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz", - "integrity": "sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==", + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", "dependencies": { "@types/node": "*" } @@ -1366,9 +1372,9 @@ "dev": true }, "node_modules/@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" }, "node_modules/@types/minimatch": { "version": "5.1.2", @@ -1407,14 +1413,14 @@ } }, "node_modules/@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==" }, "node_modules/@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" }, "node_modules/@types/request": { "version": "2.48.12", @@ -1440,21 +1446,22 @@ "dev": true }, "node_modules/@types/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", - "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "node_modules/@types/serve-static": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", - "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dependencies": { - "@types/mime": "*", - "@types/node": "*" + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" } }, "node_modules/@types/sinon": { @@ -2406,12 +2413,12 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -2419,7 +2426,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -3271,9 +3278,9 @@ "dev": true }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } @@ -4600,16 +4607,16 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -5765,9 +5772,9 @@ } }, "node_modules/http-network-proxy/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "engines": { "node": ">= 10.0.0" } @@ -8468,9 +8475,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -8995,9 +9002,9 @@ } }, "node_modules/roku-test-automation": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/roku-test-automation/-/roku-test-automation-2.0.4.tgz", - "integrity": "sha512-WhyBDQp10Y5ETr9up90HRmBsjWRfr6scbHMhHEGE1WfA3WkcZglc/6FZ9L3MWMr+jDOc693u4wvue3cWNhPyYw==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/roku-test-automation/-/roku-test-automation-2.0.6.tgz", + "integrity": "sha512-xp8KSruRM/uTKD6lOo7FU2cvgDaY9EhZ1qYXiM5nr94q5mJGe7sVbKP3dFjADEkWsO56q9KWdNJT1UWhnwY38A==", "dependencies": { "@suitest/types": "^4.6.0", "ajv": "^6.12.6", @@ -12013,9 +12020,9 @@ "dev": true }, "@suitest/types": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@suitest/types/-/types-4.6.0.tgz", - "integrity": "sha512-42NRmZNZ+D+ELcnbT4oRYnq5bAtsl1OhDTfuIp5x8uVh33GcipmbZLKDxBlwVTGCTbIH9xXRN9dS2o4gfzLoGw==" + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@suitest/types/-/types-4.10.0.tgz", + "integrity": "sha512-HY06eniGdHvbkMHWoflpL75+DNm8gh1lXgX2eTdSsY/NqeH6HntZhi8MlMn9oTFHghEuvs3dJVZcuv5+6kJv7A==" }, "@tsconfig/node10": { "version": "1.0.9", @@ -12051,9 +12058,9 @@ } }, "@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "requires": { "@types/connect": "*", "@types/node": "*" @@ -12086,17 +12093,17 @@ "dev": true }, "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "requires": { "@types/node": "*" } }, "@types/express": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", - "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "requires": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -12105,9 +12112,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.34", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz", - "integrity": "sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w==", + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", + "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", "requires": { "@types/node": "*", "@types/qs": "*", @@ -12134,10 +12141,15 @@ "@types/node": "*" } }, + "@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==" + }, "@types/http-proxy": { - "version": "1.17.11", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz", - "integrity": "sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==", + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", "requires": { "@types/node": "*" } @@ -12155,9 +12167,9 @@ "dev": true }, "@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" }, "@types/minimatch": { "version": "5.1.2", @@ -12196,14 +12208,14 @@ } }, "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==" }, "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" }, "@types/request": { "version": "2.48.12", @@ -12229,21 +12241,22 @@ "dev": true }, "@types/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", - "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", "requires": { "@types/mime": "^1", "@types/node": "*" } }, "@types/serve-static": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", - "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "requires": { - "@types/mime": "*", - "@types/node": "*" + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" } }, "@types/sinon": { @@ -12950,12 +12963,12 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, "body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "requires": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -12963,7 +12976,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -13620,9 +13633,9 @@ "dev": true }, "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" }, "cookie-signature": { "version": "1.0.6", @@ -14631,16 +14644,16 @@ "optional": true }, "express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -15511,9 +15524,9 @@ "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==" }, "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==" } } }, @@ -17566,9 +17579,9 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "requires": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -17980,9 +17993,9 @@ } }, "roku-test-automation": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/roku-test-automation/-/roku-test-automation-2.0.4.tgz", - "integrity": "sha512-WhyBDQp10Y5ETr9up90HRmBsjWRfr6scbHMhHEGE1WfA3WkcZglc/6FZ9L3MWMr+jDOc693u4wvue3cWNhPyYw==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/roku-test-automation/-/roku-test-automation-2.0.6.tgz", + "integrity": "sha512-xp8KSruRM/uTKD6lOo7FU2cvgDaY9EhZ1qYXiM5nr94q5mJGe7sVbKP3dFjADEkWsO56q9KWdNJT1UWhnwY38A==", "requires": { "@suitest/types": "^4.6.0", "ajv": "^6.12.6", diff --git a/package.json b/package.json index 4d71b54a..d706954b 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "glob": "^7.1.3", "hex-rgb": "^5.0.0", "iconv-lite": "0.4.24", + "jszip": "^3.10.1", "just-throttle": "^4.0.1", "net": "^1.0.2", "node-cache": "^4.2.0", @@ -77,7 +78,7 @@ "pretty-bytes": "^5.6.0", "roku-debug": "^0.21.7", "roku-deploy": "^3.12.0", - "roku-test-automation": "^2.0.4", + "roku-test-automation": "^2.0.6", "semver": "^7.1.3", "source-map": "^0.7.3", "thenby": "^1.3.4", @@ -241,6 +242,11 @@ "id": "rokuAutomationView", "name": "Roku Automation", "type": "webview" + }, + { + "id": "rokuReplView", + "name": "Roku REPL", + "type": "webview" } ] }, diff --git a/src/managers/WebviewViewProviderManager.ts b/src/managers/WebviewViewProviderManager.ts index ab9d8506..5be61cfd 100644 --- a/src/managers/WebviewViewProviderManager.ts +++ b/src/managers/WebviewViewProviderManager.ts @@ -10,6 +10,7 @@ import { RokuAppOverlaysViewViewProvider } from '../viewProviders/RokuAppOverlay import { RokuRegistryViewProvider } from '../viewProviders/RokuRegistryViewProvider'; import { SceneGraphInspectorViewProvider } from '../viewProviders/SceneGraphInspectorViewProvider'; import { RokuAutomationViewViewProvider } from '../viewProviders/RokuAutomationViewViewProvider'; +import { RokuReplViewProvider } from '../viewProviders/RokuReplViewProvider'; export class WebviewViewProviderManager { constructor( @@ -51,6 +52,9 @@ export class WebviewViewProviderManager { }, { constructor: SceneGraphInspectorViewProvider, provider: undefined as SceneGraphInspectorViewProvider + }, { + constructor: RokuReplViewProvider, + provider: undefined as RokuReplViewProvider }]; public getWebviewViewProviders() { diff --git a/src/viewProviders/BaseRdbViewProvider.ts b/src/viewProviders/BaseRdbViewProvider.ts index 61505697..b668110f 100644 --- a/src/viewProviders/BaseRdbViewProvider.ts +++ b/src/viewProviders/BaseRdbViewProvider.ts @@ -35,10 +35,7 @@ export abstract class BaseRdbViewProvider extends BaseWebviewViewProvider { this.addMessageCommandCallback(command, async (message) => { const { command, context } = message; const response = await this.dependencies.rtaManager.sendOdcRequest(this.id, command, context); - this.postOrQueueMessage({ - ...message, - response: response - }); + this.postOrQueueMessage(this.createResponseMessage(message, response)); return true; }); } @@ -53,10 +50,7 @@ export abstract class BaseRdbViewProvider extends BaseWebviewViewProvider { this.addMessageCommandCallback(ViewProviderCommand.getStoredNodeReferences, (message) => { const response = this.dependencies.rtaManager.getStoredNodeReferences(); - this.postOrQueueMessage({ - ...message, - response: response - }); + this.postOrQueueMessage(this.createResponseMessage(message, response)); return Promise.resolve(true); }); } diff --git a/src/viewProviders/BaseWebviewViewProvider.ts b/src/viewProviders/BaseWebviewViewProvider.ts index af48f363..a5dd90c5 100644 --- a/src/viewProviders/BaseWebviewViewProvider.ts +++ b/src/viewProviders/BaseWebviewViewProvider.ts @@ -76,6 +76,16 @@ export abstract class BaseWebviewViewProvider implements vscode.WebviewViewProvi return message; } + public createResponseMessage(incomingMessage, response = undefined, error = undefined) { + const message = { + ...incomingMessage, + response: response, + error: error + }; + + return message; + } + public postOrQueueMessage(message) { if (this.viewReady) { this.postMessage(message); @@ -122,16 +132,11 @@ export abstract class BaseWebviewViewProvider implements vscode.WebviewViewProvi } else if (command === ViewProviderCommand.updateWorkspaceState) { const context = message.context; await this.extensionContext.workspaceState.update(context.key, context.value); - this.postOrQueueMessage({ - ...message - }); + this.postOrQueueMessage(this.createResponseMessage(message)); } else if (command === ViewProviderCommand.getWorkspaceState) { const context = message.context; const response = await this.extensionContext.workspaceState.get(context.key, context.defaultValue); - this.postOrQueueMessage({ - ...message, - response: response - }); + this.postOrQueueMessage(this.createResponseMessage(message, response)); } else { const callback = this.messageCommandCallbacks[command]; if (!callback || !await callback(message)) { @@ -150,8 +155,8 @@ export abstract class BaseWebviewViewProvider implements vscode.WebviewViewProvi }); } - protected registerCommandWithWebViewNotifier(context: vscode.ExtensionContext, command: string, callback: (() => any) | undefined = undefined) { - this.registerCommand(context, command, async () => { + protected registerCommandWithWebViewNotifier(command: string, callback: (() => any) | undefined = undefined) { + this.registerCommand(command, async () => { if (callback) { await callback(); } @@ -163,8 +168,8 @@ export abstract class BaseWebviewViewProvider implements vscode.WebviewViewProvi }); } - protected registerCommand(context: vscode.ExtensionContext, command: string, callback: (...args: any[]) => any) { - context.subscriptions.push(vscode.commands.registerCommand(command, callback)); + protected registerCommand(command: string, callback: (...args: any[]) => any) { + this.extensionContext.subscriptions.push(vscode.commands.registerCommand(command, callback)); } protected onViewReady() { } diff --git a/src/viewProviders/RokuAppOverlaysViewViewProvider.ts b/src/viewProviders/RokuAppOverlaysViewViewProvider.ts index fd177949..8144a6f0 100644 --- a/src/viewProviders/RokuAppOverlaysViewViewProvider.ts +++ b/src/viewProviders/RokuAppOverlaysViewViewProvider.ts @@ -14,7 +14,7 @@ export class RokuAppOverlaysViewViewProvider extends BaseRdbViewProvider { const subscriptions = context.subscriptions; - this.registerCommandWithWebViewNotifier(context, VscodeCommand.rokuAppOverlaysViewRemoveAllOverlays); + this.registerCommandWithWebViewNotifier(VscodeCommand.rokuAppOverlaysViewRemoveAllOverlays); subscriptions.push(vscode.commands.registerCommand(VscodeCommand.rokuAppOverlaysViewAddNewOverlay, async () => { const options: vscode.OpenDialogOptions = { diff --git a/src/viewProviders/RokuAutomationViewViewProvider.ts b/src/viewProviders/RokuAutomationViewViewProvider.ts index 2c6f31bd..de0fa885 100644 --- a/src/viewProviders/RokuAutomationViewViewProvider.ts +++ b/src/viewProviders/RokuAutomationViewViewProvider.ts @@ -16,8 +16,6 @@ export class RokuAutomationViewViewProvider extends BaseRdbViewProvider { constructor(context: vscode.ExtensionContext, dependencies) { super(context, dependencies); - this.context = context; - this.addMessageCommandCallback(ViewProviderCommand.storeRokuAutomationConfigs, async (message) => { this.rokuAutomationConfigs = message.context.configs; // Make sure to use JSON.stringify or weird stuff happens @@ -43,9 +41,7 @@ export class RokuAutomationViewViewProvider extends BaseRdbViewProvider { } }); - const subscriptions = context.subscriptions; - - subscriptions.push(vscode.commands.registerCommand(VscodeCommand.rokuAutomationViewStartRecording, async () => { + this.registerCommand(VscodeCommand.rokuAutomationViewStartRecording, async () => { if (this.currentRunningStep === -1) { // Only allow recording when we aren't currently running await this.setIsRecording(true); @@ -54,22 +50,22 @@ export class RokuAutomationViewViewProvider extends BaseRdbViewProvider { // We reset the current step to update the timestamp of the first sleep this.updateCurrentRunningStep(-1); } - })); + }); - subscriptions.push(vscode.commands.registerCommand(VscodeCommand.rokuAutomationViewStopRecording, async () => { + this.registerCommand(VscodeCommand.rokuAutomationViewStopRecording, async () => { if (this.isRecording) { await this.setIsRecording(false); await vscode.commands.executeCommand(VscodeCommand.disableRemoteControlMode); } - })); + }); - subscriptions.push(vscode.commands.registerCommand(VscodeCommand.rokuAutomationViewEnableAutorunOnDeploy, async () => { + this.registerCommand(VscodeCommand.rokuAutomationViewEnableAutorunOnDeploy, async () => { await this.setAutorunOnDeploy(true); - })); + }); - subscriptions.push(vscode.commands.registerCommand(VscodeCommand.rokuAutomationViewDisableAutorunOnDeploy, async () => { + this.registerCommand(VscodeCommand.rokuAutomationViewDisableAutorunOnDeploy, async () => { await this.setAutorunOnDeploy(false); - })); + }); let autorunOnDeploy: boolean = this.extensionContext.workspaceState.get(WorkspaceStateKey.rokuAutomationAutorunOnDeploy); // Default to true if not set @@ -87,11 +83,9 @@ export class RokuAutomationViewViewProvider extends BaseRdbViewProvider { private async setAutorunOnDeploy(autorunOnDeploy: boolean) { this.rokuAutomationAutorunOnDeploy = autorunOnDeploy; await vscodeContextManager.set('brightscript.rokuAutomationView.autorunOnDeploy', autorunOnDeploy); - await this.context.workspaceState.update(WorkspaceStateKey.rokuAutomationAutorunOnDeploy, autorunOnDeploy); + await this.extensionContext.workspaceState.update(WorkspaceStateKey.rokuAutomationAutorunOnDeploy, autorunOnDeploy); } - private context: vscode.ExtensionContext; - private isRecording = false; private rokuAutomationConfigs: { name: string; diff --git a/src/viewProviders/RokuDeviceViewViewProvider.ts b/src/viewProviders/RokuDeviceViewViewProvider.ts index fc75dfca..ab493853 100644 --- a/src/viewProviders/RokuDeviceViewViewProvider.ts +++ b/src/viewProviders/RokuDeviceViewViewProvider.ts @@ -14,12 +14,12 @@ export class RokuDeviceViewViewProvider extends BaseRdbViewProvider { constructor(context: vscode.ExtensionContext, dependencies) { super(context, dependencies); - this.registerCommandWithWebViewNotifier(context, VscodeCommand.rokuDeviceViewEnableNodeInspector); - this.registerCommandWithWebViewNotifier(context, VscodeCommand.rokuDeviceViewDisableNodeInspector); - this.registerCommandWithWebViewNotifier(context, VscodeCommand.rokuDeviceViewRefreshScreenshot); - this.registerCommandWithWebViewNotifier(context, VscodeCommand.rokuDeviceViewPauseScreenshotCapture); - this.registerCommandWithWebViewNotifier(context, VscodeCommand.rokuDeviceViewResumeScreenshotCapture); - this.registerCommandWithWebViewNotifier(context, VscodeCommand.rokuDeviceViewCopyScreenshot, () => { + this.registerCommandWithWebViewNotifier(VscodeCommand.rokuDeviceViewEnableNodeInspector); + this.registerCommandWithWebViewNotifier(VscodeCommand.rokuDeviceViewDisableNodeInspector); + this.registerCommandWithWebViewNotifier(VscodeCommand.rokuDeviceViewRefreshScreenshot); + this.registerCommandWithWebViewNotifier(VscodeCommand.rokuDeviceViewPauseScreenshotCapture); + this.registerCommandWithWebViewNotifier(VscodeCommand.rokuDeviceViewResumeScreenshotCapture); + this.registerCommandWithWebViewNotifier(VscodeCommand.rokuDeviceViewCopyScreenshot, () => { // In order for copy to be successful the webview has to have focus this.view.show(false); }); @@ -34,20 +34,14 @@ export class RokuDeviceViewViewProvider extends BaseRdbViewProvider { }); } const result = await this.dependencies.rtaManager.device.getScreenshot(); - this.postOrQueueMessage({ - ...message, - response: { - success: true, - arrayBuffer: result.buffer.buffer - } + this.createResponseMessage(message, { + success: true, + arrayBuffer: result.buffer.buffer }); } catch (e) { - this.postOrQueueMessage({ - ...message, - response: { - success: false - } - }); + this.postOrQueueMessage(this.createResponseMessage(message, { + success: false + })); } return true; }); diff --git a/src/viewProviders/RokuFileSystemViewViewProvider.ts b/src/viewProviders/RokuFileSystemViewViewProvider.ts index 59e07b3c..09778ed6 100644 --- a/src/viewProviders/RokuFileSystemViewViewProvider.ts +++ b/src/viewProviders/RokuFileSystemViewViewProvider.ts @@ -13,7 +13,7 @@ export class RokuFileSystemViewViewProvider extends BaseRdbViewProvider { constructor(context: vscode.ExtensionContext, dependencies) { super(context, dependencies); - this.registerCommandWithWebViewNotifier(context, VscodeCommand.rokuFileSystemViewRefresh); + this.registerCommandWithWebViewNotifier(VscodeCommand.rokuFileSystemViewRefresh); this.addMessageCommandCallback(ViewProviderCommand.openRokuFile, async (message) => { const pathContentsInfo = message.context; diff --git a/src/viewProviders/RokuReplViewProvider.ts b/src/viewProviders/RokuReplViewProvider.ts new file mode 100644 index 00000000..c3da59e3 --- /dev/null +++ b/src/viewProviders/RokuReplViewProvider.ts @@ -0,0 +1,184 @@ +import { BaseRdbViewProvider } from './BaseRdbViewProvider'; +import { ViewProviderCommand } from './ViewProviderCommand'; +import { ViewProviderId } from './ViewProviderId'; +import type * as vscode from 'vscode'; +import * as JSZip from 'jszip'; +import * as fsExtra from 'fs-extra'; +import { undent } from 'undent'; +import { odc } from 'roku-test-automation'; +import { ComponentLibraryServer } from 'roku-debug'; +import * as getPort from 'get-port'; +import * as path from 'path'; +import * as os from 'os'; +import { Parser } from 'brighterscript'; + +export class RokuReplViewProvider extends BaseRdbViewProvider { + public readonly id = ViewProviderId.rokuReplView; + private componentLibraryServer: ComponentLibraryServer; + private componentLibraryIncrementor = 0; + private componentLibraryFolder = path.join(os.tmpdir(), 'replComponentLibraryServer'); + private componentLibraryFileName = 'repl.zip'; + private componentLibraryHost = ''; + private componentLibraryPort = 0; + + constructor(context: vscode.ExtensionContext, dependencies) { + super(context, dependencies); + + this.addMessageCommandCallback(ViewProviderCommand.sendReplRequest, async (message) => { + try { + // Verify the code is valid first + const replBrsContents = this.getREPLBrs(message.context.replCode); + const parser = Parser.parse(replBrsContents); + if (parser.diagnostics.length > 0) { + this.postOrQueueMessage(this.createResponseMessage(message, { + replOutput: { + error: parser.diagnostics[0] + } + })); + return true; + } + + if (!this.componentLibraryServer) { + this.componentLibraryServer = new ComponentLibraryServer(); + this.componentLibraryPort = await getPort(); + await fsExtra.ensureDir(this.componentLibraryFolder); + await this.componentLibraryServer.startStaticFileHosting(this.componentLibraryFolder, this.componentLibraryPort, console.log); + } + + const zip = new JSZip(); + zip.file('manifest', this.getManifestContents()); + zip.file('components/REPL.xml', this.getREPLXml()); + zip.file('components/REPL.brs', replBrsContents); + const content = await zip.generateAsync({ type: 'nodebuffer', compressionOptions: { level: 2 } }); + await fsExtra.outputFile(`${this.componentLibraryFolder}/${this.componentLibraryFileName}`, content); + + // Check if we already added the component library + const { value } = await odc.getValue({ + keyPath: '#replContainer.id' + }); + if (!value) { + // We use the fact that the container doesn't exist to know we need to do our initial setup + // If it doesn't exist then add it + await odc.createChild({ + subtype: 'Group', + fields: { + id: 'replContainer' + } + }); + + await odc.createChild({ + keyPath: '#replContainer', + subtype: 'ComponentLibrary', + fields: { + id: 'replComponentLibrary' + } + }); + + // Figure out what network interface the Roku device is accessing us from + const { host } = await odc.getServerHost(); + this.componentLibraryHost = host; + } + + const url = `http://${this.componentLibraryHost}:${this.componentLibraryPort}/${this.componentLibraryFileName}?i=${this.componentLibraryIncrementor++}&rokuForce=.zip`; + await odc.setValue({ + keyPath: '#replContainer.#replComponentLibrary.uri', + value: url + }); + + await odc.onFieldChangeOnce({ + keyPath: '#replContainer.#replComponentLibrary.loadStatus', + match: 'ready' + }); + + const replInstanceId = `replInstance${this.componentLibraryIncrementor}`; + await odc.createChild({ + keyPath: '#replContainer', + subtype: 'BrightScriptREPL:REPL', + fields: { + id: replInstanceId + } + }, { + timeout: 60000 // All of the repl code will run during this operation + }); + + const replInstanceKeypath = `#replContainer.#${replInstanceId}`; + const { value: replOutput } = await odc.onFieldChangeOnce({ + keyPath: `${replInstanceKeypath}.output`, + match: { + keyPath: `${replInstanceKeypath}.output.finished`, + value: true + } + }); + + await odc.removeNode({ + keyPath: replInstanceKeypath + }); + + this.postOrQueueMessage(this.createResponseMessage(message, { + replOutput: replOutput + })); + } catch (e) { + this.postOrQueueMessage(this.createResponseMessage(message, { + replOutput: { + error: { + message: e.message + } + } + })); + } + return true; + }); + + } + + private getManifestContents() { + const contents = undent` + title=BrightScript REPL + sg_component_libs_provided=BrightScriptREPL + hidden=1 + rsg_version=1.2 + major_version=1 + minor_version=0 + build_version=0 + `; + return contents; + } + + private getREPLXml() { + const contents = undent` + + + + + + + +
+ {#if odcAvailable} + + + + + + + + +
+ Run +     + {#if loading} + + {:else} + {replTimeTaken >= 0 ? `Last run took ${replTimeTaken}ms` : ''} + {/if} +
+ + {#if !loading && (replResponse !== undefined || replError !== '')} + + {#if replResponse !== undefined} + Returned value: +
{replResponse}
+ {/if} +
{replError}
+ {/if} + {:else} + + {/if} +