├── .eslintrc.json ├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ ├── commitlint.yml │ └── release.yml ├── .gitignore ├── .npmignore ├── .reuse └── dep5 ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── CONTRIBUTING.md ├── LICENSE ├── LICENSES └── Apache-2.0.txt ├── README.md ├── commitlint.config.js ├── example-ws ├── .eslintignore ├── .eslintrc.json ├── .vscode │ └── launch.json ├── README.md ├── package-lock.json ├── package.json ├── src │ ├── index.ts │ ├── rpc │ │ ├── rpc-common.ts │ │ └── rpc-extension-ws.ts │ └── static │ │ ├── index.html │ │ └── rpc │ │ ├── rpc-browser-ws.js │ │ ├── rpc-browser.js │ │ └── rpc-common.js └── tsconfig.json ├── example ├── .vscode │ └── launch.json ├── .vscodeignore ├── CHANGELOG.md ├── README.md ├── out │ ├── extension.js │ ├── extension.js.map │ └── test │ │ ├── runTest.js │ │ ├── runTest.js.map │ │ └── suite │ │ ├── extension.test.js │ │ ├── extension.test.js.map │ │ ├── index.js │ │ └── index.js.map ├── package-lock.json ├── package.json ├── src │ ├── extension.ts │ └── media │ │ ├── index.html │ │ └── main.js ├── tsconfig.json ├── tslint.json └── vsc-extension-quickstart.md ├── jest.config.unit.js ├── package-lock.json ├── package.json ├── src ├── noop-logger.ts ├── rpc-browser-ws.ts ├── rpc-browser.ts ├── rpc-common.ts ├── rpc-extension-ws.ts ├── rpc-extension.ts └── test │ ├── logger.spec.ts │ ├── rpc-mock.ts │ └── rpc.test.ts ├── tsconfig.browser.json ├── tsconfig.ext.json └── tsconfig.test.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "node": true 6 | }, 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:@typescript-eslint/eslint-recommended" 10 | ], 11 | "globals": { 12 | "Atomics": "readonly", 13 | "SharedArrayBuffer": "readonly" 14 | }, 15 | "parser": "@typescript-eslint/parser", 16 | "parserOptions": { 17 | "ecmaVersion": 2018, 18 | "sourceType": "module", 19 | "project": ["./tsconfig.ext.json", "./tsconfig.browser.json", "./tsconfig.test.json"] 20 | }, 21 | "plugins": [ 22 | "@typescript-eslint" 23 | ], 24 | "rules": { 25 | "no-unused-vars": "off", 26 | "@typescript-eslint/no-unused-vars": "error", 27 | // "indent": [ 28 | // "error", 29 | // 2 30 | // ], 31 | // "linebreak-style": [ 32 | // "error", 33 | // "unix" 34 | // ], 35 | "quotes": [ 36 | "error", 37 | "double" 38 | ], 39 | "semi": [ 40 | "error", 41 | "always" 42 | ] 43 | } 44 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | # Maintain dependencies for GitHub Actions 9 | - package-ecosystem: "github-actions" 10 | directory: "/" 11 | schedule: 12 | interval: "weekly" 13 | ignore: 14 | - dependency-name: actions/checkout 15 | 16 | # Maintain dependencies for npm 17 | - package-ecosystem: npm 18 | directory: "/" 19 | schedule: 20 | interval: weekly 21 | ignore: 22 | - dependency-name: "ws" 23 | - dependency-name: "@types/node" 24 | - dependency-name: "@types/vscode" 25 | - dependency-name: "@types/ws" 26 | - dependency-name: "typescript" 27 | versions: ["5.x"] 28 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | on: 3 | # Trigger the workflow on push or pull request, 4 | # but only for the master branch 5 | # See: https://github.community/t/duplicate-checks-on-push-and-pull-request-simultaneous-event/18012 6 | push: 7 | branches: 8 | - master* 9 | pull_request: 10 | branches: 11 | - master* 12 | 13 | jobs: 14 | build: 15 | name: Full Build (node ${{ matrix.node_version }}) 16 | runs-on: ubuntu-latest 17 | strategy: 18 | matrix: 19 | node_version: [18.x, 20.x] 20 | # https://stackoverflow.com/questions/61070925/github-actions-disable-auto-cancel-when-job-fails 21 | fail-fast: false 22 | 23 | steps: 24 | # using `v1` because of: https://github.com/actions/checkout/issues/246 25 | - uses: actions/checkout@v1 26 | - uses: actions/setup-node@v4 27 | with: 28 | node-version: ${{ matrix.node_version }} 29 | 30 | - name: Install dependencies 31 | run: npm install 32 | 33 | - name: Build 34 | run: npm run ci 35 | -------------------------------------------------------------------------------- /.github/workflows/commitlint.yml: -------------------------------------------------------------------------------- 1 | name: Lint Commit Messages 2 | on: 3 | # Trigger the workflow on push or pull request, 4 | # but only for the master branch 5 | # See: https://github.community/t/duplicate-checks-on-push-and-pull-request-simultaneous-event/18012 6 | push: 7 | branches: 8 | - master 9 | pull_request: 10 | branches: 11 | - master 12 | 13 | jobs: 14 | commitlint: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | with: 19 | fetch-depth: 0 20 | - uses: wagoid/commitlint-github-action@v6 21 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | tags: 5 | - "v*.*.*" 6 | 7 | jobs: 8 | release: 9 | runs-on: ubuntu-latest 10 | steps: 11 | # using `v1` because of: https://github.com/actions/checkout/issues/246 12 | - uses: actions/checkout@v1 13 | - uses: actions/setup-node@v4 14 | with: 15 | node-version: '18.x' 16 | registry-url: 'https://registry.npmjs.org' 17 | 18 | - name: Install dependencies 19 | run: npm install 20 | 21 | - name: Build 22 | run: npm run ci 23 | 24 | - name: Publish to NPM 25 | run: npm publish 26 | env: 27 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 28 | 29 | - name: Create Github Release 30 | uses: softprops/action-gh-release@v2 31 | with: 32 | files: sap-devx-webview-rpc-*.tgz 33 | fail_on_unmatched_files: true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | #IntelliJ 9 | .idea 10 | 11 | # Runtime data 12 | pids 13 | *.pid 14 | *.seed 15 | *.pid.lock 16 | 17 | # Directory for instrumented libs generated by jscoverage/JSCover 18 | lib-cov 19 | 20 | # Coverage directory used by tools like istanbul 21 | coverage 22 | 23 | # nyc test coverage 24 | .nyc_output 25 | 26 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 27 | .grunt 28 | 29 | # Bower dependency directory (https://bower.io/) 30 | bower_components 31 | 32 | # node-waf configuration 33 | .lock-wscript 34 | 35 | # Compiled binary addons (https://nodejs.org/api/addons.html) 36 | build/Release 37 | 38 | # Dependency directories 39 | **/node_modules/ 40 | jspm_packages/ 41 | 42 | # TypeScript v1 declaration files 43 | typings/ 44 | 45 | # Optional npm cache directory 46 | .npm 47 | 48 | # Optional eslint cache 49 | .eslintcache 50 | 51 | # Optional REPL history 52 | .node_repl_history 53 | 54 | # Output of 'npm pack' 55 | *.tgz 56 | 57 | # Yarn Integrity file 58 | .yarn-integrity 59 | 60 | # dotenv environment variables file 61 | .env 62 | 63 | # next.js build output 64 | .next 65 | 66 | # auto generated folders 67 | **/out/ 68 | out.ext 69 | out.browser 70 | out.test 71 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | **/* 2 | !.reuse/dep5 3 | !CONTRIBUTING.md 4 | !LICENSE 5 | !README.md 6 | !package.json 7 | !out.browser/*.js 8 | !out.browser/*.d.ts 9 | !out.ext/*.js 10 | !out.ext/*.d.ts 11 | 12 | -------------------------------------------------------------------------------- /.reuse/dep5: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: vscode-webview-rpc-lib 3 | Upstream-Contact: Rima Sirich 4 | Source: https://github.com/SAP/vscode-webview-rpc-lib 5 | 6 | Files: * 7 | Copyright: 2021 SAP SE or an SAP affiliate company and yeoman-ui contributors 8 | License: Apache-2.0 9 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Debug Jest Tests", 10 | "type": "node", 11 | "request": "launch", 12 | "runtimeArgs": [ 13 | "--inspect-brk", 14 | "${workspaceRoot}/node_modules/jest/bin/jest.js", 15 | "--runInBand", 16 | "--config", 17 | "jest.config.unit.js" 18 | ], 19 | "console": "integratedTerminal", 20 | "internalConsoleOptions": "neverOpen", 21 | "port": 9229 22 | }, 23 | { 24 | "name": "Run Extension", 25 | "type": "extensionHost", 26 | "request": "launch", 27 | "runtimeExecutable": "${execPath}", 28 | "args": ["--extensionDevelopmentPath=${workspaceFolder}/example"], 29 | "outFiles": ["${workspaceFolder}/example/out/**/*.js"], 30 | "preLaunchTask": "npm: watch" 31 | }, 32 | { 33 | "name": "Extension Tests", 34 | "type": "extensionHost", 35 | "request": "launch", 36 | "runtimeExecutable": "${execPath}", 37 | "args": [ 38 | "--extensionDevelopmentPath=${workspaceFolder}/example", 39 | "--extensionTestsPath=${workspaceFolder}/example/out/test/suite/index" 40 | ], 41 | "outFiles": ["${workspaceFolder}/example/out/test/**/*.js"], 42 | "preLaunchTask": "npm: watch" 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off" 11 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "shell", 8 | "command": "npm run web", 9 | "label": "Run web" 10 | }, 11 | { 12 | "type": "npm", 13 | "script": "watch", 14 | "problemMatcher": "$tsc-watch", 15 | "isBackground": true, 16 | "presentation": { 17 | "reveal": "never" 18 | }, 19 | "options": { 20 | "cwd": "${workspaceFolder}" 21 | }, 22 | "group": { 23 | "kind": "build", 24 | "isDefault": true 25 | } 26 | }, 27 | { 28 | "type": "npm", 29 | "script": "test", 30 | "group": { 31 | "kind": "test", 32 | "isDefault": true 33 | } 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | ## Report an Issue 4 | 5 | To report an issue please use the github issue tracker. Please try to make sure you have these in your issue: 6 | * No duplicate 7 | * Reproducible 8 | * Good summary 9 | * Well-documented 10 | * Minimal example 11 | 12 | ## Issue handling process 13 | When an issue is reported, a committer will look at it and either confirm it as a real issue (by giving the "in progress" label), close it if it is not an issue, or ask for more details. In-progress issues are then either assigned to a committer in GitHub, reported in our internal issue handling system, or left open as "contribution welcome" for easy or not urgent fixes. 14 | 15 | An issue that is about a real bug is closed as soon as the fix is committed. 16 | 17 | ## Contribute Code 18 | You are welcome to contribute code. PRs will be examined and if it fits the quality requirements and the roadmap of the product they will be merged. 19 | 20 | ## Commit Messages 21 | This project uses [conventional commits standard](https://www.conventionalcommits.org/en/v1.0.0-beta.2/#specification) with the [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional). 22 | Recommanded: Use `git cz` to build conventional commit messages. 23 | - requires [commitizen](https://github.com/commitizen/cz-cli#installing-the-command-line-tool) to be installed. 24 | 25 | ## Developer Certificate of Origin (DCO) 26 | Due to legal reasons, contributors will be asked to accept a DCO before they submit the first pull request to this projects, this happens in an automated fashion during the submission process. SAP uses [the standard DCO text of the Linux Foundation](https://developercertificate.org/). 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2021 SAP SE or an SAP affiliate company and vscode-webview-rpc-lib contributors 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSES/Apache-2.0.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CircleCI](https://circleci.com/gh/SAP/vscode-webview-rpc-lib.svg?style=svg)](https://circleci.com/gh/SAP/vscode-webview-rpc-lib) 2 | [![Coverage Status](https://coveralls.io/repos/github/SAP/vscode-webview-rpc-lib/badge.svg?branch=master)](https://coveralls.io/github/SAP/vscode-webview-rpc-lib?branch=master) 3 | [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) 4 | ![GitHub license](https://img.shields.io/badge/license-Apache_2.0-blue.svg) 5 | [![REUSE status](https://api.reuse.software/badge/github.com/SAP/vscode-webview-rpc-lib)](https://api.reuse.software/info/github.com/SAP/vscode-webview-rpc-lib) 6 | [![dependentbot](https://api.dependabot.com/badges/status?host=github&repo=SAP/vscode-webview-rpc-lib)](https://dependabot.com/) 7 | 8 | # vscode-webview-rpc-lib 9 | 10 | ## Description 11 | Provides a conventient way to communicate between VSCode extension and its webviews. Use RPC calls to invoke functions on the webview, receive callbacks and vice versa. 12 | 13 | ## Requirements 14 | You need to have [node.js](https://www.npmjs.com/package/node) installed on your machine. 15 | Also, to use this library, you need to run it inside a VSCode extension using [VSCode](https://code.visualstudio.com/) or [Theia](https://www.theia-ide.org/). 16 | 17 | ## How to use 18 | *An example of using this libary can be seen under the "example" folder.* 19 | 20 | ### Installation 21 | * Create VSCode extension with a Webview. To create your extension go to https://code.visualstudio.com/api/extension-guides/webview. 22 | * Install using npm 23 | ```bash 24 | npm install @sap-devx/webview-rpc 25 | ``` 26 | This will install the library in your node_modules folder. The extension library can be used as any node.js module (with TypeScript). The webview library needs to be imported to your html. 27 | * Add the following script to the root html of your Webview 28 | ```html 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | ### Initializations 37 | Create new instance of the Rpc in the extension side and the Webview side 38 | * In the extension code use the following example to start new instance of the RpcExtension: 39 | ```ts 40 | this._rpc = new RpcExtension(this._panel.webview); 41 | ``` 42 | * In the Webview JS code use the following example to start new instance of the RpcBrowser: 43 | ```js 44 | const vscode = acquireVsCodeApi(); 45 | let rpc = new RpcBrowser(window, vscode); 46 | ``` 47 | ### Register methods 48 | In order to invoke an extension method from the webbiew or webview method from the extension, you will have to register the functions that can be invoked. 49 | Here is an example on how to register the methods 50 | ```js 51 | function add(a,b) { 52 | return a+b; 53 | } 54 | 55 | rpc.registerMethod({func: add}); 56 | ``` 57 | ### Usage 58 | To invoke a method use the *invoke* method on the rpc instance. You can pass a callback that will be invoked once the response received.\ 59 | ***For version ^0.x.y*** : 60 | ```js 61 | rpc.invoke("add", [1,2]).then((response)=>{ 62 | console.log("1+2="+response); 63 | }); 64 | ``` 65 | ***Since version 1.x.y*** : 66 | ```js 67 | rpc.invoke("add", 1,2).then((response)=>{ 68 | console.log("1+2="+response); 69 | }); 70 | ``` 71 | 72 | ## Build and Development 73 | To build for development purpose do the following: 74 | * Run "*npm install*" on the repo to download the project dependencies. 75 | ```bash 76 | npm install @sap-devx/webview-rpc 77 | ``` 78 | * Run "*npm run compile-ext*" to compile the extension library sources to javascript. The compilation results will be on the directory "out.ext". 79 | ```bash 80 | npm run compile-ext 81 | ``` 82 | * Run "*npm run compile-browser*" to compile the browser library sources to javascript. The compilation results will be on the directory "out.browser". 83 | ```bash 84 | npm run compile-browser 85 | ``` 86 | * Run the test using "*npm run test*". 87 | ```bash 88 | npm run test 89 | ``` 90 | 91 | ## Known Issues 92 | * Browser library is does not generate d.ts files. 93 | 94 | * overcome Cors issue preventing post message to get through and hit the window: 95 | use the setHost method and sent the host name from the webview - and then the message should get through. 96 | 97 | ## How to obtain support 98 | * To get more help, support and information please open a github issue. 99 | ## Contributing 100 | Contributing information can be found in the [CONTRIBUTING.md](CONTRIBUTING.md) file. 101 | 102 | ## To-Do (upcoming changes) 103 | * remove the need to decalre exposed functions 104 | 105 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | // override commitlint ignores as suggested by https://github.com/dependabot/dependabot-core/issues/2445#issuecomment-949633412 2 | module.exports = { 3 | extends: ["@commitlint/config-conventional"], 4 | ignores: [(message) => /^Bumps \[.+]\(.+\) from .+ to .+\.$/m.test(message)], 5 | }; 6 | -------------------------------------------------------------------------------- /example-ws/.eslintignore: -------------------------------------------------------------------------------- 1 | **/*.js -------------------------------------------------------------------------------- /example-ws/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "node": true 6 | }, 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:@typescript-eslint/eslint-recommended" 10 | ], 11 | "globals": { 12 | "Atomics": "readonly", 13 | "SharedArrayBuffer": "readonly" 14 | }, 15 | "parser": "@typescript-eslint/parser", 16 | "parserOptions": { 17 | "ecmaVersion": 2018, 18 | "sourceType": "module", 19 | "project": ["./tsconfig.json"] 20 | }, 21 | "plugins": [ 22 | "@typescript-eslint" 23 | ], 24 | "rules": { 25 | "no-unused-vars": "off", 26 | "@typescript-eslint/no-unused-vars": "error", 27 | "indent": [ 28 | "error", 29 | 2 30 | ], 31 | // "linebreak-style": [ 32 | // "error", 33 | // "unix" 34 | // ], 35 | "quotes": [ 36 | "error", 37 | "double" 38 | ], 39 | "semi": [ 40 | "error", 41 | "always" 42 | ] 43 | } 44 | } -------------------------------------------------------------------------------- /example-ws/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "type": "chrome", 10 | "request": "launch", 11 | "name": "Launch Chrome", 12 | "url": "http://127.0.0.1:8080/index.html" 13 | }, 14 | { 15 | "type": "node", 16 | "request": "launch", 17 | "name": "Run WebSocket Example", 18 | "program": "${workspaceFolder}/out/index.js" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /example-ws/README.md: -------------------------------------------------------------------------------- 1 | # RPC WebSockets Example 2 | 3 | ## Setup and Usage 4 | Run `npm install` to install dependencies. 5 | 6 | Run `npm run compile` to compile TypeScript files and to copy artifacts to the out directory. 7 | 8 | Run `node out/index.js` 9 | 10 | Open the browser to this address: http://127.0.0.1:8080/index.html 11 | -------------------------------------------------------------------------------- /example-ws/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example-ws", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "watch": "tsc -w -p .", 8 | "prep": "cd .. && npm run compile && copyfiles -u 1 ./out.browser/*.js ./example-ws/src/static/rpc/ && copyfiles -u 1 ./src/rpc-common.ts ./example-ws/src/rpc/ && copyfiles -u 1 ./src/rpc-extension-ws.ts ./example-ws/src/rpc/", 9 | "compile": "rimraf out && tsc -p . && copyfiles -u 1 ./src/static/** ./out/", 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "lint": "eslint ./**/*.ts" 12 | }, 13 | "author": "Eyal Barlev", 14 | "publisher": "SAP", 15 | "license": "Apache 2.0", 16 | "devDependencies": { 17 | "@types/ws": "^7.2.3", 18 | "copyfiles": "^2.4.1", 19 | "eslint": "^8.56.0", 20 | "rimraf": "^5.0.5", 21 | "typescript": "^4.2.3" 22 | }, 23 | "dependencies": { 24 | "ws": "^7.2.3", 25 | "@braintree/sanitize-url": "7.0.1" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /example-ws/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as http from "http"; 2 | import * as fs from "fs"; 3 | import * as WebSocket from "ws"; 4 | import { IRpc } from "./rpc/rpc-common"; 5 | import { RpcExtensionWebSockets } from "./rpc/rpc-extension-ws"; 6 | import { sanitizeUrl } from "@braintree/sanitize-url"; 7 | 8 | // web socket server 9 | const wss = new WebSocket.Server({ port: 8081 }, () => { 10 | console.log("websocket server is listening on port 8081"); 11 | }); 12 | 13 | const sub = (a: number, b: number): number => { 14 | return a-b; 15 | }; 16 | 17 | wss.on("connection", function connection(ws) { 18 | console.log("new ws connection"); 19 | 20 | // logger is optional second parameter, implementing interface IChildLogger: 21 | // https://github.com/SAP/vscode-logging/blob/master/packages/types/api.d.ts#L17 22 | const rpc: IRpc = new RpcExtensionWebSockets(ws); 23 | rpc.setResponseTimeout(30000); 24 | rpc.registerMethod({func: sub}); 25 | 26 | rpc.invoke("sum", ...[1,2]).then((val) => { 27 | console.log(`sum is ${val}`); 28 | }).catch((err) => { 29 | console.error(err); 30 | }); 31 | }); 32 | 33 | // static content http server 34 | http.createServer(function (req, res) { 35 | const url = sanitizeUrl(req.url); 36 | fs.readFile(`${__dirname}/static${url}`, function (err,data) { 37 | if (err) { 38 | res.writeHead(404); 39 | res.end(JSON.stringify(err)); 40 | return; 41 | } 42 | if (url && url.includes(".js")) { 43 | res.setHeader("Content-Type", "application/javascript"); 44 | } 45 | res.writeHead(200,); 46 | res.end(data); 47 | }); 48 | }).listen(8080, ()=> { 49 | console.log("static content server is listening on port 8080"); 50 | }); 51 | -------------------------------------------------------------------------------- /example-ws/src/rpc/rpc-common.ts: -------------------------------------------------------------------------------- 1 | export interface IRpc { 2 | invoke(method: string, ...params: any[]): Promise; 3 | sendRequest(id: number, method: string, params?: any[]): void; 4 | sendResponse(id: number, response: any, success?: boolean): void; 5 | handleResponse(message: any): void; 6 | handleRequest(message: any): void; 7 | registerMethod(method: IMethod): void; 8 | setResponseTimeout(timeout: number): void; 9 | } 10 | 11 | export interface IPromiseCallbacks { 12 | resolve: Function; 13 | reject: Function; 14 | } 15 | 16 | export interface IMethod { 17 | func: Function; 18 | thisArg?: any; 19 | name?: string; 20 | } 21 | 22 | export abstract class RpcCommon implements IRpc { 23 | abstract sendRequest(id: number, method: string, params?: any[]): void; 24 | abstract sendResponse(id: number, response: any, success?: boolean): void; 25 | protected promiseCallbacks: Map; // promise resolve and reject callbacks that are called when returning from remote 26 | protected methods: Map; 27 | // TODO: timeouts do not make sense for user interactions. consider not using timeouts by default 28 | protected timeout: number = 3600000; // timeout for response from remote in milliseconds 29 | 30 | constructor() { 31 | this.promiseCallbacks = new Map(); 32 | this.methods = new Map(); 33 | this.registerMethod({ func: this.listLocalMethods, thisArg: this }); 34 | } 35 | 36 | public setResponseTimeout(timeout: number): void { 37 | this.timeout = timeout; 38 | } 39 | 40 | public registerMethod(method: IMethod): void { 41 | this.methods.set((method.name ? method.name : method.func.name), method); 42 | } 43 | 44 | public unregisterMethod(method: IMethod): void { 45 | this.methods.delete((method.name ? method.name : method.func.name)); 46 | } 47 | 48 | public listLocalMethods(): string[] { 49 | return Array.from(this.methods.keys()); 50 | } 51 | 52 | public listRemoteMethods(): Promise { 53 | return this.invoke("listLocalMethods"); 54 | } 55 | 56 | invoke(method: string, ...params: any[]): Promise { 57 | // TODO: change to something more unique (or check to see if id doesn't alreday exist in this.promiseCallbacks) 58 | const id = Math.random(); 59 | const promise = new Promise((resolve, reject) => { 60 | this.promiseCallbacks.set(id, { resolve: resolve, reject: reject }); 61 | }); 62 | 63 | this.sendRequest(id, method, params); 64 | return promise; 65 | } 66 | 67 | handleResponse(message: any): void { 68 | const promiseCallbacks: IPromiseCallbacks | undefined = this.promiseCallbacks.get(message.id); 69 | if (promiseCallbacks) { 70 | if (message.success) { 71 | promiseCallbacks.resolve(message.response); 72 | } else { 73 | promiseCallbacks.reject(message.response); 74 | } 75 | this.promiseCallbacks.delete(message.id); 76 | } 77 | } 78 | 79 | async handleRequest(message: any): Promise { 80 | const method: IMethod | undefined = this.methods.get(message.method); 81 | if (method) { 82 | const func: Function = method.func; 83 | const thisArg: any = method.thisArg; 84 | try { 85 | let response: any = func.apply(thisArg, message.params); 86 | // if response is a promise, delay the response until the promise is fulfilled 87 | if (typeof response.then === "function") { 88 | response = await response; 89 | } 90 | this.sendResponse(message.id, response); 91 | } catch (err) { 92 | this.sendResponse(message.id, err, false); 93 | } 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /example-ws/src/rpc/rpc-extension-ws.ts: -------------------------------------------------------------------------------- 1 | import { RpcCommon, IPromiseCallbacks } from "./rpc-common"; 2 | import * as WebSocket from "ws"; 3 | 4 | export class RpcExtensionWebSockets extends RpcCommon { 5 | ws: WebSocket; 6 | 7 | constructor(ws: WebSocket) { 8 | super(); 9 | this.ws = ws; 10 | this.ws.on("message", message => { 11 | // assuming message is a stringified JSON 12 | const messageObject: any = JSON.parse(message as string); 13 | switch (messageObject.command) { 14 | case "rpc-response": 15 | this.handleResponse(messageObject); 16 | break; 17 | case "rpc-request": 18 | this.handleRequest(messageObject); 19 | break; 20 | } 21 | }); 22 | } 23 | 24 | sendRequest(id: number, method: string, params?: any[]) { 25 | // consider cancelling the timer if the promise if fulfilled before timeout is reached 26 | setTimeout(() => { 27 | const promiseCallbacks: IPromiseCallbacks | undefined = this.promiseCallbacks.get(id); 28 | if (promiseCallbacks) { 29 | promiseCallbacks.reject("Request timed out"); 30 | this.promiseCallbacks.delete(id); 31 | } 32 | }, this.timeout); 33 | 34 | const requestObject: any = { 35 | command: "rpc-request", 36 | id: id, 37 | method: method, 38 | params: params 39 | }; 40 | 41 | this.ws.send(JSON.stringify(requestObject)); 42 | } 43 | 44 | sendResponse(id: number, response: any, success: boolean = true): void { 45 | const responseObject: any = { 46 | command: "rpc-response", 47 | id: id, 48 | response: response, 49 | success: success 50 | }; 51 | 52 | this.ws.send(JSON.stringify(responseObject)); 53 | } 54 | } -------------------------------------------------------------------------------- /example-ws/src/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | RPC WebSockets Example 5 | 6 | 7 | 42 | 43 | 44 | 45 |

RPC WebSockets Example

46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | 56 | 57 | -------------------------------------------------------------------------------- /example-ws/src/static/rpc/rpc-browser-ws.js: -------------------------------------------------------------------------------- 1 | // must specify ".js" for import in browser to locate rpc-common.js 2 | // see: https://github.com/microsoft/TypeScript/issues/16577#issuecomment-343610106 3 | import { RpcCommon } from "./rpc-common.js"; 4 | export class RpcBrowserWebSockets extends RpcCommon { 5 | constructor(ws) { 6 | super(); 7 | this.ws = ws; 8 | this.ws.addEventListener("message", (event) => { 9 | const message = JSON.parse(event.data); 10 | switch (message.command) { 11 | case "rpc-response": 12 | this.handleResponse(message); 13 | break; 14 | case "rpc-request": 15 | this.handleRequest(message); 16 | break; 17 | } 18 | }); 19 | } 20 | sendRequest(id, method, params) { 21 | // TODO: consider cancelling the timer if the promise if fulfilled before timeout is reached 22 | setTimeout(() => { 23 | const promiseCallbacks = this.promiseCallbacks.get(id); 24 | if (promiseCallbacks) { 25 | promiseCallbacks.reject("Request timed out"); 26 | this.promiseCallbacks.delete(id); 27 | } 28 | }, this.timeout); 29 | // TODO: find an alternative to appending vscode to the global scope (perhaps providing vscode as parameter to constructor) 30 | const requestBody = { 31 | command: "rpc-request", 32 | id: id, 33 | method: method, 34 | params: params 35 | }; 36 | this.ws.send(JSON.stringify(requestBody)); 37 | } 38 | sendResponse(id, response, success = true) { 39 | const responseBody = { 40 | command: "rpc-response", 41 | id: id, 42 | response: response, 43 | success: success 44 | }; 45 | this.ws.send(JSON.stringify(responseBody)); 46 | } 47 | } 48 | //# sourceMappingURL=rpc-browser-ws.js.map -------------------------------------------------------------------------------- /example-ws/src/static/rpc/rpc-browser.js: -------------------------------------------------------------------------------- 1 | /* must specify ".js" for import in browser to locate rpc-common.js 2 | see: https://github.com/microsoft/TypeScript/issues/16577#issuecomment-343610106 3 | */ 4 | import { RpcCommon } from "./rpc-common.js"; 5 | export class RpcBrowser extends RpcCommon { 6 | constructor(window, vscode) { 7 | super(); 8 | this.window = window; 9 | this.vscode = vscode; 10 | this.window.addEventListener("message", (event) => { 11 | const message = event.data; 12 | switch (message.command) { 13 | case "rpc-response": 14 | this.handleResponse(message); 15 | break; 16 | case "rpc-request": 17 | this.handleRequest(message); 18 | break; 19 | } 20 | }); 21 | } 22 | sendRequest(id, method, params) { 23 | // TODO: consider cancelling the timer if the promise if fulfilled before timeout is reached 24 | setTimeout(() => { 25 | const promiseCallbacks = this.promiseCallbacks.get(id); 26 | if (promiseCallbacks) { 27 | promiseCallbacks.reject("Request timed out"); 28 | this.promiseCallbacks.delete(id); 29 | } 30 | }, this.timeout); 31 | // TODO: find an alternative to appending vscode to the global scope (perhaps providing vscode as parameter to constructor) 32 | this.vscode.postMessage({ 33 | command: "rpc-request", 34 | id: id, 35 | method: method, 36 | params: params 37 | }); 38 | } 39 | sendResponse(id, response, success = true) { 40 | this.vscode.postMessage({ 41 | command: "rpc-response", 42 | id: id, 43 | response: response, 44 | success: success 45 | }); 46 | } 47 | } 48 | //# sourceMappingURL=rpc-browser.js.map -------------------------------------------------------------------------------- /example-ws/src/static/rpc/rpc-common.js: -------------------------------------------------------------------------------- 1 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 2 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 3 | return new (P || (P = Promise))(function (resolve, reject) { 4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 6 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 7 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 8 | }); 9 | }; 10 | export class RpcCommon { 11 | constructor() { 12 | this.timeout = 15000; // timeout for response from remote in milliseconds 13 | this.promiseCallbacks = new Map(); 14 | this.methods = new Map(); 15 | this.registerMethod({ func: this.listLocalMethods, thisArg: this }); 16 | } 17 | setResponseTimeout(timeout) { 18 | this.timeout = timeout; 19 | } 20 | registerMethod(method) { 21 | this.methods.set((method.name ? method.name : method.func.name), method); 22 | } 23 | unregisterMethod(method) { 24 | this.methods.delete((method.name ? method.name : method.func.name)); 25 | } 26 | listLocalMethods() { 27 | return Array.from(this.methods.keys()); 28 | } 29 | listRemoteMethods() { 30 | return this.invoke("listLocalMethods"); 31 | } 32 | invoke(method, params) { 33 | // TODO: change to something more unique (or check to see if id doesn't alreday exist in this.promiseCallbacks) 34 | const id = Math.random(); 35 | const promise = new Promise((resolve, reject) => { 36 | this.promiseCallbacks.set(id, { resolve: resolve, reject: reject }); 37 | }); 38 | this.sendRequest(id, method, params); 39 | return promise; 40 | } 41 | handleResponse(message) { 42 | this.logger.trace(`handleResponse: processing response for id: ${message.id} method: ${message.method} message success flag is: ${message.success}`); 43 | const promiseCallbacks = this.promiseCallbacks.get(message.id); 44 | if (promiseCallbacks) { 45 | if (message.success) { 46 | promiseCallbacks.resolve(message.response); 47 | } 48 | else { 49 | promiseCallbacks.reject(message.response); 50 | } 51 | this.promiseCallbacks.delete(message.id); 52 | } 53 | } 54 | handleRequest(message) { 55 | return __awaiter(this, void 0, void 0, function* () { 56 | this.logger.trace(`handleRequest: processing request id: ${message.id} method: ${message.method} parameters: ${JSON.stringify(message.params)}`); 57 | const method = this.methods.get(message.method); 58 | if (method) { 59 | const func = method.func; 60 | const thisArg = method.thisArg; 61 | try { 62 | let response = func.call(thisArg, ...message.params); 63 | // if response is a promise, delay the response until the promise is fulfilled 64 | if (typeof response.then === "function") { 65 | response = yield response; 66 | } 67 | this.sendResponse(message.id, response); 68 | } 69 | catch (err) { 70 | this.logger.error(`handleRequest: Failed processing request id: ${message.id}`, { error: err }); 71 | this.sendResponse(message.id, err, false); 72 | } 73 | } 74 | }); 75 | } 76 | } 77 | //# sourceMappingURL=rpc-common.js.map -------------------------------------------------------------------------------- /example-ws/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": ["es6"], 7 | "sourceMap": true, 8 | "rootDir": "src", 9 | "strict": true 10 | }, 11 | "include": ["src/**/*.ts"], 12 | "exclude": ["node_modules"] 13 | } 14 | -------------------------------------------------------------------------------- /example/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "extensionHost", 9 | "request": "launch", 10 | "name": "Launch Extension", 11 | "runtimeExecutable": "${execPath}", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ], 15 | "outFiles": [ 16 | "${workspaceFolder}/out/**/*.js" 17 | ] 18 | } 19 | 20 | ] 21 | } -------------------------------------------------------------------------------- /example/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | src/** 5 | .gitignore 6 | vsc-extension-quickstart.md 7 | **/tsconfig.json 8 | **/tslint.json 9 | **/*.map 10 | **/*.ts -------------------------------------------------------------------------------- /example/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "rpc-example" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | ## [Unreleased] 8 | 9 | - Initial release -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # rpc-example README 2 | 3 | This is the README for your extension "rpc-example". After writing up a brief description, we recommend including the following sections. 4 | 5 | ## Features 6 | 7 | Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file. 8 | 9 | For example if there is an image subfolder under your extension project workspace: 10 | 11 | \!\[feature X\]\(images/feature-x.png\) 12 | 13 | > Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow. 14 | 15 | ## Requirements 16 | 17 | If you have any requirements or dependencies, add a section describing those and how to install and configure them. 18 | 19 | ## Extension Settings 20 | 21 | Include if your extension adds any VS Code settings through the `contributes.configuration` extension point. 22 | 23 | For example: 24 | 25 | This extension contributes the following settings: 26 | 27 | * `myExtension.enable`: enable/disable this extension 28 | * `myExtension.thing`: set to `blah` to do something 29 | 30 | ## Known Issues 31 | 32 | Calling out known issues can help limit users opening duplicate issues against your extension. 33 | 34 | ## Release Notes 35 | 36 | Users appreciate release notes as you update your extension. 37 | 38 | ### 1.0.0 39 | 40 | Initial release of ... 41 | 42 | ### 1.0.1 43 | 44 | Fixed issue #. 45 | 46 | ### 1.1.0 47 | 48 | Added features X, Y, and Z. 49 | 50 | ----------------------------------------------------------------------------------------------------------- 51 | 52 | ## Working with Markdown 53 | 54 | **Note:** You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts: 55 | 56 | * Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux) 57 | * Toggle preview (`Shift+CMD+V` on macOS or `Shift+Ctrl+V` on Windows and Linux) 58 | * Press `Ctrl+Space` (Windows, Linux) or `Cmd+Space` (macOS) to see a list of Markdown snippets 59 | 60 | ### For more information 61 | 62 | * [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown) 63 | * [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/) 64 | 65 | **Enjoy!** 66 | -------------------------------------------------------------------------------- /example/out/extension.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.deactivate = exports.activate = void 0; 13 | // The module 'vscode' contains the VS Code extensibility API 14 | // Import the module and reference it with the alias vscode in your code below 15 | const path = require("path"); 16 | const vscode = require("vscode"); 17 | const fs = require("fs"); 18 | const rpc_extension_1 = require("@sap-devx/webview-rpc/out.ext/rpc-extension"); 19 | // this method is called when your extension is activated 20 | // your extension is activated the very first time the command is executed 21 | function activate(context) { 22 | let cmd1 = vscode.commands.registerCommand('extension.openwebview', () => { 23 | RpcExamplePanel.createOrShow(context.extensionPath); 24 | }); 25 | context.subscriptions.push(cmd1); 26 | let cmd2 = vscode.commands.registerCommand('extension.sendMessage', () => { 27 | RpcExamplePanel.sendMessage(); 28 | }); 29 | context.subscriptions.push(cmd2); 30 | if (vscode.window.registerWebviewPanelSerializer) { 31 | // Make sure we register a serializer in activation event 32 | vscode.window.registerWebviewPanelSerializer(RpcExamplePanel.viewType, { 33 | deserializeWebviewPanel(webviewPanel, state) { 34 | return __awaiter(this, void 0, void 0, function* () { 35 | console.log(`Got state: ${state}`); 36 | RpcExamplePanel.revive(webviewPanel, context.extensionPath); 37 | }); 38 | } 39 | }); 40 | } 41 | } 42 | exports.activate = activate; 43 | /** 44 | * Manages cat coding webview panels 45 | */ 46 | class RpcExamplePanel { 47 | static sendMessage() { 48 | this.currentPanel._rpc.invoke("runFunctionInWebview", "message from extension").then((response => { 49 | vscode.window.showInformationMessage(response); 50 | })); 51 | } 52 | static createOrShow(extensionPath) { 53 | const column = vscode.window.activeTextEditor 54 | ? vscode.window.activeTextEditor.viewColumn 55 | : undefined; 56 | // If we already have a panel, show it. 57 | if (RpcExamplePanel.currentPanel) { 58 | RpcExamplePanel.currentPanel._panel.reveal(column); 59 | return; 60 | } 61 | // Otherwise, create a new panel. 62 | const panel = vscode.window.createWebviewPanel(RpcExamplePanel.viewType, 'Webview Example', column || vscode.ViewColumn.One, { 63 | // Enable javascript in the webview 64 | enableScripts: true 65 | }); 66 | RpcExamplePanel.currentPanel = new RpcExamplePanel(panel, extensionPath); 67 | } 68 | static revive(panel, extensionPath) { 69 | RpcExamplePanel.currentPanel = new RpcExamplePanel(panel, extensionPath); 70 | } 71 | constructor(panel, extensionPath) { 72 | this._disposables = []; 73 | this._panel = panel; 74 | this._extensionPath = extensionPath; 75 | let functions = { 76 | showMessage: (message) => { 77 | let _vscode = vscode; 78 | return new Promise((resolve, reject) => { 79 | _vscode.window.showInformationMessage(message, "yes", "no").then((res) => { 80 | resolve(res); 81 | }); 82 | }); 83 | } 84 | }; 85 | // logger is optional second parameter, implementing interface IChildLogger: 86 | // https://github.com/SAP/vscode-logging/blob/master/packages/types/api.d.ts#L17 87 | // see example on how to initialize it from extension here: 88 | // https://github.com/SAP/vscode-logging/blob/master/examples/extension/lib/passing-logger-to-library.js 89 | this._rpc = new rpc_extension_1.RpcExtension(this._panel.webview); 90 | this._rpc.registerMethod({ func: functions.showMessage }); 91 | // Set the webview's initial html content 92 | this.update(this._panel.webview); 93 | // Listen for when the panel is disposed 94 | // This happens when the user closes the panel or when the panel is closed programatically 95 | this._panel.onDidDispose(() => this.dispose(), null, this._disposables); 96 | // Update the content based on view changes 97 | this._panel.onDidChangeViewState(e => { 98 | if (this._panel.visible) { 99 | this.update(this._panel.webview); 100 | } 101 | }, null, this._disposables); 102 | } 103 | dispose() { 104 | RpcExamplePanel.currentPanel = undefined; 105 | // Clean up our resources 106 | this._panel.dispose(); 107 | while (this._disposables.length) { 108 | const x = this._disposables.pop(); 109 | if (x) { 110 | x.dispose(); 111 | } 112 | } 113 | } 114 | update(webview) { 115 | this._panel.title = "RPC Example"; 116 | this._panel.webview.html = this._getHtmlForWebview(webview); 117 | } 118 | _getHtmlForWebview(webview) { 119 | // Local path to main script run in the webview 120 | const scriptsPathOnDisk = vscode.Uri.file(path.join(this._extensionPath)); 121 | // And the uri we use to load this script in the webview 122 | const scriptsUri = webview.asWebviewUri(scriptsPathOnDisk); 123 | let html = fs.readFileSync(path.join(this._extensionPath, 'out', 'media', 'index.html'), "utf8"); 124 | html = html.replace(/vscode-scheme/g, scriptsUri.toString()).replace(/%3A/g, ":"); 125 | return html; 126 | } 127 | } 128 | RpcExamplePanel.viewType = 'rpcExample'; 129 | // this method is called when your extension is deactivated 130 | function deactivate() { } 131 | exports.deactivate = deactivate; 132 | //# sourceMappingURL=extension.js.map -------------------------------------------------------------------------------- /example/out/extension.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6DAA6D;AAC7D,8EAA8E;AAC9E,6BAA6B;AAC7B,iCAAiC;AACjC,yBAAyB;AACzB,+EAA2E;AAE3E,yDAAyD;AACzD,0EAA0E;AAC1E,SAAgB,QAAQ,CAAC,OAAgC;IAExD,IAAI,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACxE,eAAe,CAAC,YAAY,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEjC,IAAI,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACxE,eAAe,CAAC,WAAW,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEjC,IAAI,MAAM,CAAC,MAAM,CAAC,8BAA8B,EAAE;QACjD,yDAAyD;QACzD,MAAM,CAAC,MAAM,CAAC,8BAA8B,CAAC,eAAe,CAAC,QAAQ,EAAE;YAChE,uBAAuB,CAAC,YAAiC,EAAE,KAAU;;oBAC1E,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,EAAE,CAAC,CAAC;oBACnC,eAAe,CAAC,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;gBAC7D,CAAC;aAAA;SACD,CAAC,CAAC;KACH;AAGF,CAAC;AAzBD,4BAyBC;AAGD;;GAEG;AACH,MAAM,eAAe;IAcb,MAAM,CAAC,WAAW;QACxB,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,sBAAsB,EAAE,wBAAwB,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE;YAChG,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC,CAAC;IACL,CAAC;IAEM,MAAM,CAAC,YAAY,CAAC,aAAqB;QAC/C,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,gBAAgB;YAC5C,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,UAAU;YAC3C,CAAC,CAAC,SAAS,CAAC;QAGb,uCAAuC;QACvC,IAAI,eAAe,CAAC,YAAY,EAAE;YACjC,eAAe,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACnD,OAAO;SACP;QAED,iCAAiC;QACjC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAC7C,eAAe,CAAC,QAAQ,EACxB,iBAAiB,EACjB,MAAM,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,EAC/B;YACC,mCAAmC;YACnC,aAAa,EAAE,IAAI;SACnB,CACD,CAAC;QAEF,eAAe,CAAC,YAAY,GAAG,IAAI,eAAe,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IAC1E,CAAC;IAEM,MAAM,CAAC,MAAM,CAAC,KAA0B,EAAE,aAAqB;QACrE,eAAe,CAAC,YAAY,GAAG,IAAI,eAAe,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IAC1E,CAAC;IAED,YAAoB,KAA0B,EAAE,aAAqB;QAvC7D,iBAAY,GAAwB,EAAE,CAAC;QAwC9C,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,cAAc,GAAG,aAAa,CAAC;QAEpC,IAAI,SAAS,GAAG;YACf,WAAW,EAAE,CAAC,OAAO,EAAE,EAAE;gBACxB,IAAI,OAAO,GAAG,MAAM,CAAC;gBACrB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;oBACtC,OAAO,CAAC,MAAM,CAAC,sBAAsB,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;wBACxE,OAAO,CAAC,GAAG,CAAC,CAAC;oBACd,CAAC,CAAC,CAAC;gBACJ,CAAC,CAAC,CAAC;YACF,CAAC;SACH,CAAC;QACF,4EAA4E;QAC5E,gFAAgF;QAChF,2DAA2D;QAC3D,wGAAwG;QACxG,IAAI,CAAC,IAAI,GAAG,IAAI,4BAAY,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC;QAE1D,yCAAyC;QACzC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEjC,wCAAwC;QACxC,0FAA0F;QAC1F,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAExE,2CAA2C;QAC3C,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAC/B,CAAC,CAAC,EAAE;YACH,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;gBACxB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;aACjC;QACF,CAAC,EACD,IAAI,EACJ,IAAI,CAAC,YAAY,CACjB,CAAC;IACH,CAAC;IAEM,OAAO;QACb,eAAe,CAAC,YAAY,GAAG,SAAS,CAAC;QAEzC,yBAAyB;QACzB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAEtB,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE;YAChC,MAAM,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC;YAClC,IAAI,CAAC,EAAE;gBACN,CAAC,CAAC,OAAO,EAAE,CAAC;aACZ;SACD;IACF,CAAC;IAEO,MAAM,CAAC,OAAuB;QACrC,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,aAAa,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC7D,CAAC;IAEO,kBAAkB,CAAC,OAAuB;QACjD,+CAA+C;QAC/C,MAAM,iBAAiB,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CACxC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAC9B,CAAC;QAEF,wDAAwD;QACxD,MAAM,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;QAE3D,IAAI,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,CAAC;QACjG,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAElF,OAAO,IAAI,CAAC;IACb,CAAC;;AApHsB,wBAAQ,GAAG,YAAY,CAAC;AAuHhD,2DAA2D;AAC3D,SAAgB,UAAU,KAAK,CAAC;AAAhC,gCAAgC"} -------------------------------------------------------------------------------- /example/out/test/runTest.js: -------------------------------------------------------------------------------- 1 | // import * as path from 'path'; 2 | // import { runTests } from 'vscode-test'; 3 | // async function main() { 4 | // try { 5 | // // The folder containing the Extension Manifest package.json 6 | // // Passed to `--extensionDevelopmentPath` 7 | // const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 8 | // // The path to test runner 9 | // // Passed to --extensionTestsPath 10 | // const extensionTestsPath = path.resolve(__dirname, './suite/index'); 11 | // // Download VS Code, unzip it and run the integration test 12 | // await runTests({ extensionDevelopmentPath, extensionTestsPath }); 13 | // } catch (err) { 14 | // console.error('Failed to run tests'); 15 | // process.exit(1); 16 | // } 17 | // } 18 | // main(); 19 | //# sourceMappingURL=runTest.js.map -------------------------------------------------------------------------------- /example/out/test/runTest.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"runTest.js","sourceRoot":"","sources":["../../src/test/runTest.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAEhC,0CAA0C;AAE1C,0BAA0B;AAC1B,SAAS;AACT,iEAAiE;AACjE,8CAA8C;AAC9C,wEAAwE;AAExE,+BAA+B;AAC/B,sCAAsC;AACtC,yEAAyE;AAEzE,+DAA+D;AAC/D,sEAAsE;AACtE,mBAAmB;AACnB,0CAA0C;AAC1C,qBAAqB;AACrB,KAAK;AACL,IAAI;AAEJ,UAAU"} -------------------------------------------------------------------------------- /example/out/test/suite/extension.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const assert = require("assert"); 4 | // You can import and use all API from the 'vscode' module 5 | // as well as import your extension to test it 6 | const vscode = require("vscode"); 7 | // import * as myExtension from '../extension'; 8 | suite('Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | test('Sample test', () => { 11 | assert.equal(-1, [1, 2, 3].indexOf(5)); 12 | assert.equal(-1, [1, 2, 3].indexOf(0)); 13 | }); 14 | }); 15 | //# sourceMappingURL=extension.test.js.map -------------------------------------------------------------------------------- /example/out/test/suite/extension.test.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"extension.test.js","sourceRoot":"","sources":["../../../src/test/suite/extension.test.ts"],"names":[],"mappings":";;AAAA,iCAAiC;AAEjC,0DAA0D;AAC1D,8CAA8C;AAC9C,iCAAiC;AACjC,+CAA+C;AAE/C,KAAK,CAAC,sBAAsB,EAAE,GAAG,EAAE;IAClC,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,kBAAkB,CAAC,CAAC;IAEzD,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE;QACxB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"} -------------------------------------------------------------------------------- /example/out/test/suite/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const path = require("path"); 4 | const Mocha = require("mocha"); 5 | const glob = require("glob"); 6 | function run() { 7 | // Create the mocha test 8 | const mocha = new Mocha({ 9 | ui: 'tdd', 10 | }); 11 | mocha.useColors(true); 12 | const testsRoot = path.resolve(__dirname, '..'); 13 | return new Promise((c, e) => { 14 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 15 | if (err) { 16 | return e(err); 17 | } 18 | // Add files to the test suite 19 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 20 | try { 21 | // Run the mocha test 22 | mocha.run(failures => { 23 | if (failures > 0) { 24 | e(new Error(`${failures} tests failed.`)); 25 | } 26 | else { 27 | c(); 28 | } 29 | }); 30 | } 31 | catch (err) { 32 | e(err); 33 | } 34 | }); 35 | }); 36 | } 37 | exports.run = run; 38 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /example/out/test/suite/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/test/suite/index.ts"],"names":[],"mappings":";;AAAA,6BAA6B;AAC7B,+BAA+B;AAC/B,6BAA6B;AAE7B,SAAgB,GAAG;IAClB,wBAAwB;IACxB,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC;QACvB,EAAE,EAAE,KAAK;KACT,CAAC,CAAC;IACH,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAEtB,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAEhD,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC3B,IAAI,CAAC,eAAe,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YACxD,IAAI,GAAG,EAAE;gBACR,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC;aACd;YAED,8BAA8B;YAC9B,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAE9D,IAAI;gBACH,qBAAqB;gBACrB,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;oBACpB,IAAI,QAAQ,GAAG,CAAC,EAAE;wBACjB,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,QAAQ,gBAAgB,CAAC,CAAC,CAAC;qBAC1C;yBAAM;wBACN,CAAC,EAAE,CAAC;qBACJ;gBACF,CAAC,CAAC,CAAC;aACH;YAAC,OAAO,GAAG,EAAE;gBACb,CAAC,CAAC,GAAG,CAAC,CAAC;aACP;QACF,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACJ,CAAC;AAhCD,kBAgCC"} -------------------------------------------------------------------------------- /example/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rpc-example", 3 | "version": "0.0.1", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "rpc-example", 9 | "version": "0.0.1", 10 | "dependencies": { 11 | "@sap-devx/webview-rpc": "1.0.0" 12 | }, 13 | "devDependencies": { 14 | "@types/glob": "^7.1.1", 15 | "@types/node": "^18.11.1", 16 | "@types/vscode": "^1.44.0", 17 | "copyfiles": "^2.4.1", 18 | "glob": "^7.1.6", 19 | "mocha": "^10.4.0", 20 | "rimraf": "^5.0.5", 21 | "typescript": "^4.2.3", 22 | "vscode-test": "^1.6.1" 23 | }, 24 | "engines": { 25 | "vscode": "^1.38.0" 26 | } 27 | }, 28 | " ../out.ext": { 29 | "extraneous": true 30 | }, 31 | "../../out.ext": { 32 | "extraneous": true 33 | }, 34 | "node_modules/@isaacs/cliui": { 35 | "version": "8.0.2", 36 | "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", 37 | "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", 38 | "dev": true, 39 | "dependencies": { 40 | "string-width": "^5.1.2", 41 | "string-width-cjs": "npm:string-width@^4.2.0", 42 | "strip-ansi": "^7.0.1", 43 | "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", 44 | "wrap-ansi": "^8.1.0", 45 | "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" 46 | }, 47 | "engines": { 48 | "node": ">=12" 49 | } 50 | }, 51 | "node_modules/@isaacs/cliui/node_modules/ansi-regex": { 52 | "version": "6.0.1", 53 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", 54 | "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", 55 | "dev": true, 56 | "engines": { 57 | "node": ">=12" 58 | }, 59 | "funding": { 60 | "url": "https://github.com/chalk/ansi-regex?sponsor=1" 61 | } 62 | }, 63 | "node_modules/@isaacs/cliui/node_modules/ansi-styles": { 64 | "version": "6.2.1", 65 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", 66 | "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", 67 | "dev": true, 68 | "engines": { 69 | "node": ">=12" 70 | }, 71 | "funding": { 72 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 73 | } 74 | }, 75 | "node_modules/@isaacs/cliui/node_modules/emoji-regex": { 76 | "version": "9.2.2", 77 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", 78 | "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", 79 | "dev": true 80 | }, 81 | "node_modules/@isaacs/cliui/node_modules/string-width": { 82 | "version": "5.1.2", 83 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", 84 | "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", 85 | "dev": true, 86 | "dependencies": { 87 | "eastasianwidth": "^0.2.0", 88 | "emoji-regex": "^9.2.2", 89 | "strip-ansi": "^7.0.1" 90 | }, 91 | "engines": { 92 | "node": ">=12" 93 | }, 94 | "funding": { 95 | "url": "https://github.com/sponsors/sindresorhus" 96 | } 97 | }, 98 | "node_modules/@isaacs/cliui/node_modules/strip-ansi": { 99 | "version": "7.1.0", 100 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", 101 | "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", 102 | "dev": true, 103 | "dependencies": { 104 | "ansi-regex": "^6.0.1" 105 | }, 106 | "engines": { 107 | "node": ">=12" 108 | }, 109 | "funding": { 110 | "url": "https://github.com/chalk/strip-ansi?sponsor=1" 111 | } 112 | }, 113 | "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { 114 | "version": "8.1.0", 115 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", 116 | "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", 117 | "dev": true, 118 | "dependencies": { 119 | "ansi-styles": "^6.1.0", 120 | "string-width": "^5.0.1", 121 | "strip-ansi": "^7.0.1" 122 | }, 123 | "engines": { 124 | "node": ">=12" 125 | }, 126 | "funding": { 127 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 128 | } 129 | }, 130 | "node_modules/@pkgjs/parseargs": { 131 | "version": "0.11.0", 132 | "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", 133 | "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", 134 | "dev": true, 135 | "optional": true, 136 | "engines": { 137 | "node": ">=14" 138 | } 139 | }, 140 | "node_modules/@sap-devx/webview-rpc": { 141 | "version": "1.0.0", 142 | "resolved": "file:../sap-devx-webview-rpc-1.0.0.tgz", 143 | "integrity": "sha512-0pqdm95C0CPfJ46rDcYsV/AmhDjq8nwgTt3vqgaHiglYmTQyjGyEy7a5tGJEYRAAbUu4fyrT0zOW90Mdtg6nZA==", 144 | "license": "Apache 2.0", 145 | "dependencies": { 146 | "ws": "^7.2.3" 147 | } 148 | }, 149 | "node_modules/@tootallnate/once": { 150 | "version": "1.1.2", 151 | "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", 152 | "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", 153 | "dev": true, 154 | "engines": { 155 | "node": ">= 6" 156 | } 157 | }, 158 | "node_modules/@types/events": { 159 | "version": "3.0.0", 160 | "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", 161 | "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", 162 | "dev": true 163 | }, 164 | "node_modules/@types/glob": { 165 | "version": "7.1.1", 166 | "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", 167 | "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", 168 | "dev": true, 169 | "dependencies": { 170 | "@types/events": "*", 171 | "@types/minimatch": "*", 172 | "@types/node": "*" 173 | } 174 | }, 175 | "node_modules/@types/minimatch": { 176 | "version": "3.0.3", 177 | "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", 178 | "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", 179 | "dev": true 180 | }, 181 | "node_modules/@types/node": { 182 | "version": "18.19.31", 183 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz", 184 | "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==", 185 | "dev": true, 186 | "dependencies": { 187 | "undici-types": "~5.26.4" 188 | } 189 | }, 190 | "node_modules/@types/vscode": { 191 | "version": "1.44.0", 192 | "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.44.0.tgz", 193 | "integrity": "sha512-WJZtZlinE3meRdH+I7wTsIhpz/GLhqEQwmPGeh4s1irWLwMzCeTV8WZ+pgPTwrDXoafVUWwo1LiZ9HJVHFlJSQ==", 194 | "dev": true 195 | }, 196 | "node_modules/agent-base": { 197 | "version": "6.0.2", 198 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", 199 | "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", 200 | "dev": true, 201 | "dependencies": { 202 | "debug": "4" 203 | }, 204 | "engines": { 205 | "node": ">= 6.0.0" 206 | } 207 | }, 208 | "node_modules/ansi-colors": { 209 | "version": "4.1.1", 210 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 211 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 212 | "dev": true, 213 | "engines": { 214 | "node": ">=6" 215 | } 216 | }, 217 | "node_modules/ansi-regex": { 218 | "version": "5.0.1", 219 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 220 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 221 | "dev": true, 222 | "engines": { 223 | "node": ">=8" 224 | } 225 | }, 226 | "node_modules/ansi-styles": { 227 | "version": "4.3.0", 228 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 229 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 230 | "dev": true, 231 | "dependencies": { 232 | "color-convert": "^2.0.1" 233 | }, 234 | "engines": { 235 | "node": ">=8" 236 | }, 237 | "funding": { 238 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 239 | } 240 | }, 241 | "node_modules/anymatch": { 242 | "version": "3.1.3", 243 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 244 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 245 | "dev": true, 246 | "dependencies": { 247 | "normalize-path": "^3.0.0", 248 | "picomatch": "^2.0.4" 249 | }, 250 | "engines": { 251 | "node": ">= 8" 252 | } 253 | }, 254 | "node_modules/argparse": { 255 | "version": "2.0.1", 256 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 257 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 258 | "dev": true 259 | }, 260 | "node_modules/balanced-match": { 261 | "version": "1.0.0", 262 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 263 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 264 | "dev": true 265 | }, 266 | "node_modules/big-integer": { 267 | "version": "1.6.52", 268 | "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", 269 | "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", 270 | "dev": true, 271 | "engines": { 272 | "node": ">=0.6" 273 | } 274 | }, 275 | "node_modules/binary": { 276 | "version": "0.3.0", 277 | "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", 278 | "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", 279 | "dev": true, 280 | "dependencies": { 281 | "buffers": "~0.1.1", 282 | "chainsaw": "~0.1.0" 283 | }, 284 | "engines": { 285 | "node": "*" 286 | } 287 | }, 288 | "node_modules/binary-extensions": { 289 | "version": "2.3.0", 290 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", 291 | "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", 292 | "dev": true, 293 | "engines": { 294 | "node": ">=8" 295 | }, 296 | "funding": { 297 | "url": "https://github.com/sponsors/sindresorhus" 298 | } 299 | }, 300 | "node_modules/bluebird": { 301 | "version": "3.4.7", 302 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", 303 | "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", 304 | "dev": true 305 | }, 306 | "node_modules/brace-expansion": { 307 | "version": "1.1.11", 308 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 309 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 310 | "dev": true, 311 | "dependencies": { 312 | "balanced-match": "^1.0.0", 313 | "concat-map": "0.0.1" 314 | } 315 | }, 316 | "node_modules/braces": { 317 | "version": "3.0.2", 318 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 319 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 320 | "dev": true, 321 | "dependencies": { 322 | "fill-range": "^7.0.1" 323 | }, 324 | "engines": { 325 | "node": ">=8" 326 | } 327 | }, 328 | "node_modules/browser-stdout": { 329 | "version": "1.3.1", 330 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 331 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 332 | "dev": true 333 | }, 334 | "node_modules/buffer-indexof-polyfill": { 335 | "version": "1.0.2", 336 | "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", 337 | "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", 338 | "dev": true, 339 | "engines": { 340 | "node": ">=0.10" 341 | } 342 | }, 343 | "node_modules/buffers": { 344 | "version": "0.1.1", 345 | "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", 346 | "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", 347 | "dev": true, 348 | "engines": { 349 | "node": ">=0.2.0" 350 | } 351 | }, 352 | "node_modules/camelcase": { 353 | "version": "6.3.0", 354 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", 355 | "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", 356 | "dev": true, 357 | "engines": { 358 | "node": ">=10" 359 | }, 360 | "funding": { 361 | "url": "https://github.com/sponsors/sindresorhus" 362 | } 363 | }, 364 | "node_modules/chainsaw": { 365 | "version": "0.1.0", 366 | "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", 367 | "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", 368 | "dev": true, 369 | "dependencies": { 370 | "traverse": ">=0.3.0 <0.4" 371 | }, 372 | "engines": { 373 | "node": "*" 374 | } 375 | }, 376 | "node_modules/chalk": { 377 | "version": "4.1.2", 378 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 379 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 380 | "dev": true, 381 | "dependencies": { 382 | "ansi-styles": "^4.1.0", 383 | "supports-color": "^7.1.0" 384 | }, 385 | "engines": { 386 | "node": ">=10" 387 | }, 388 | "funding": { 389 | "url": "https://github.com/chalk/chalk?sponsor=1" 390 | } 391 | }, 392 | "node_modules/chalk/node_modules/supports-color": { 393 | "version": "7.2.0", 394 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 395 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 396 | "dev": true, 397 | "dependencies": { 398 | "has-flag": "^4.0.0" 399 | }, 400 | "engines": { 401 | "node": ">=8" 402 | } 403 | }, 404 | "node_modules/chokidar": { 405 | "version": "3.5.3", 406 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 407 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 408 | "dev": true, 409 | "funding": [ 410 | { 411 | "type": "individual", 412 | "url": "https://paulmillr.com/funding/" 413 | } 414 | ], 415 | "dependencies": { 416 | "anymatch": "~3.1.2", 417 | "braces": "~3.0.2", 418 | "glob-parent": "~5.1.2", 419 | "is-binary-path": "~2.1.0", 420 | "is-glob": "~4.0.1", 421 | "normalize-path": "~3.0.0", 422 | "readdirp": "~3.6.0" 423 | }, 424 | "engines": { 425 | "node": ">= 8.10.0" 426 | }, 427 | "optionalDependencies": { 428 | "fsevents": "~2.3.2" 429 | } 430 | }, 431 | "node_modules/cliui": { 432 | "version": "7.0.4", 433 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 434 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 435 | "dev": true, 436 | "dependencies": { 437 | "string-width": "^4.2.0", 438 | "strip-ansi": "^6.0.0", 439 | "wrap-ansi": "^7.0.0" 440 | } 441 | }, 442 | "node_modules/color-convert": { 443 | "version": "2.0.1", 444 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 445 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 446 | "dev": true, 447 | "dependencies": { 448 | "color-name": "~1.1.4" 449 | }, 450 | "engines": { 451 | "node": ">=7.0.0" 452 | } 453 | }, 454 | "node_modules/color-name": { 455 | "version": "1.1.4", 456 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 457 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 458 | "dev": true 459 | }, 460 | "node_modules/concat-map": { 461 | "version": "0.0.1", 462 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 463 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 464 | "dev": true 465 | }, 466 | "node_modules/copyfiles": { 467 | "version": "2.4.1", 468 | "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", 469 | "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", 470 | "dev": true, 471 | "dependencies": { 472 | "glob": "^7.0.5", 473 | "minimatch": "^3.0.3", 474 | "mkdirp": "^1.0.4", 475 | "noms": "0.0.0", 476 | "through2": "^2.0.1", 477 | "untildify": "^4.0.0", 478 | "yargs": "^16.1.0" 479 | }, 480 | "bin": { 481 | "copyfiles": "copyfiles", 482 | "copyup": "copyfiles" 483 | } 484 | }, 485 | "node_modules/core-util-is": { 486 | "version": "1.0.2", 487 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 488 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 489 | "dev": true 490 | }, 491 | "node_modules/cross-spawn": { 492 | "version": "7.0.3", 493 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 494 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 495 | "dev": true, 496 | "dependencies": { 497 | "path-key": "^3.1.0", 498 | "shebang-command": "^2.0.0", 499 | "which": "^2.0.1" 500 | }, 501 | "engines": { 502 | "node": ">= 8" 503 | } 504 | }, 505 | "node_modules/debug": { 506 | "version": "4.3.4", 507 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 508 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 509 | "dev": true, 510 | "dependencies": { 511 | "ms": "2.1.2" 512 | }, 513 | "engines": { 514 | "node": ">=6.0" 515 | }, 516 | "peerDependenciesMeta": { 517 | "supports-color": { 518 | "optional": true 519 | } 520 | } 521 | }, 522 | "node_modules/debug/node_modules/ms": { 523 | "version": "2.1.2", 524 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 525 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 526 | "dev": true 527 | }, 528 | "node_modules/decamelize": { 529 | "version": "4.0.0", 530 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", 531 | "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", 532 | "dev": true, 533 | "engines": { 534 | "node": ">=10" 535 | }, 536 | "funding": { 537 | "url": "https://github.com/sponsors/sindresorhus" 538 | } 539 | }, 540 | "node_modules/diff": { 541 | "version": "5.0.0", 542 | "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", 543 | "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", 544 | "dev": true, 545 | "engines": { 546 | "node": ">=0.3.1" 547 | } 548 | }, 549 | "node_modules/duplexer2": { 550 | "version": "0.1.4", 551 | "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", 552 | "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", 553 | "dev": true, 554 | "dependencies": { 555 | "readable-stream": "^2.0.2" 556 | } 557 | }, 558 | "node_modules/duplexer2/node_modules/isarray": { 559 | "version": "1.0.0", 560 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 561 | "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", 562 | "dev": true 563 | }, 564 | "node_modules/duplexer2/node_modules/readable-stream": { 565 | "version": "2.3.8", 566 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", 567 | "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", 568 | "dev": true, 569 | "dependencies": { 570 | "core-util-is": "~1.0.0", 571 | "inherits": "~2.0.3", 572 | "isarray": "~1.0.0", 573 | "process-nextick-args": "~2.0.0", 574 | "safe-buffer": "~5.1.1", 575 | "string_decoder": "~1.1.1", 576 | "util-deprecate": "~1.0.1" 577 | } 578 | }, 579 | "node_modules/duplexer2/node_modules/string_decoder": { 580 | "version": "1.1.1", 581 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 582 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 583 | "dev": true, 584 | "dependencies": { 585 | "safe-buffer": "~5.1.0" 586 | } 587 | }, 588 | "node_modules/eastasianwidth": { 589 | "version": "0.2.0", 590 | "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", 591 | "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", 592 | "dev": true 593 | }, 594 | "node_modules/emoji-regex": { 595 | "version": "8.0.0", 596 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 597 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 598 | "dev": true 599 | }, 600 | "node_modules/escalade": { 601 | "version": "3.1.2", 602 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", 603 | "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", 604 | "dev": true, 605 | "engines": { 606 | "node": ">=6" 607 | } 608 | }, 609 | "node_modules/escape-string-regexp": { 610 | "version": "4.0.0", 611 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 612 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 613 | "dev": true, 614 | "engines": { 615 | "node": ">=10" 616 | }, 617 | "funding": { 618 | "url": "https://github.com/sponsors/sindresorhus" 619 | } 620 | }, 621 | "node_modules/fill-range": { 622 | "version": "7.0.1", 623 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 624 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 625 | "dev": true, 626 | "dependencies": { 627 | "to-regex-range": "^5.0.1" 628 | }, 629 | "engines": { 630 | "node": ">=8" 631 | } 632 | }, 633 | "node_modules/find-up": { 634 | "version": "5.0.0", 635 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 636 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 637 | "dev": true, 638 | "dependencies": { 639 | "locate-path": "^6.0.0", 640 | "path-exists": "^4.0.0" 641 | }, 642 | "engines": { 643 | "node": ">=10" 644 | }, 645 | "funding": { 646 | "url": "https://github.com/sponsors/sindresorhus" 647 | } 648 | }, 649 | "node_modules/flat": { 650 | "version": "5.0.2", 651 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", 652 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", 653 | "dev": true, 654 | "bin": { 655 | "flat": "cli.js" 656 | } 657 | }, 658 | "node_modules/foreground-child": { 659 | "version": "3.1.1", 660 | "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", 661 | "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", 662 | "dev": true, 663 | "dependencies": { 664 | "cross-spawn": "^7.0.0", 665 | "signal-exit": "^4.0.1" 666 | }, 667 | "engines": { 668 | "node": ">=14" 669 | }, 670 | "funding": { 671 | "url": "https://github.com/sponsors/isaacs" 672 | } 673 | }, 674 | "node_modules/fs.realpath": { 675 | "version": "1.0.0", 676 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 677 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 678 | "dev": true 679 | }, 680 | "node_modules/fsevents": { 681 | "version": "2.3.3", 682 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 683 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 684 | "dev": true, 685 | "hasInstallScript": true, 686 | "optional": true, 687 | "os": [ 688 | "darwin" 689 | ], 690 | "engines": { 691 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 692 | } 693 | }, 694 | "node_modules/fstream": { 695 | "version": "1.0.12", 696 | "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", 697 | "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", 698 | "dev": true, 699 | "dependencies": { 700 | "graceful-fs": "^4.1.2", 701 | "inherits": "~2.0.0", 702 | "mkdirp": ">=0.5 0", 703 | "rimraf": "2" 704 | }, 705 | "engines": { 706 | "node": ">=0.6" 707 | } 708 | }, 709 | "node_modules/fstream/node_modules/mkdirp": { 710 | "version": "0.5.6", 711 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", 712 | "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", 713 | "dev": true, 714 | "dependencies": { 715 | "minimist": "^1.2.6" 716 | }, 717 | "bin": { 718 | "mkdirp": "bin/cmd.js" 719 | } 720 | }, 721 | "node_modules/fstream/node_modules/rimraf": { 722 | "version": "2.7.1", 723 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 724 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 725 | "dev": true, 726 | "dependencies": { 727 | "glob": "^7.1.3" 728 | }, 729 | "bin": { 730 | "rimraf": "bin.js" 731 | } 732 | }, 733 | "node_modules/get-caller-file": { 734 | "version": "2.0.5", 735 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 736 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 737 | "dev": true, 738 | "engines": { 739 | "node": "6.* || 8.* || >= 10.*" 740 | } 741 | }, 742 | "node_modules/glob": { 743 | "version": "7.1.6", 744 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 745 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 746 | "dev": true, 747 | "dependencies": { 748 | "fs.realpath": "^1.0.0", 749 | "inflight": "^1.0.4", 750 | "inherits": "2", 751 | "minimatch": "^3.0.4", 752 | "once": "^1.3.0", 753 | "path-is-absolute": "^1.0.0" 754 | }, 755 | "engines": { 756 | "node": "*" 757 | }, 758 | "funding": { 759 | "url": "https://github.com/sponsors/isaacs" 760 | } 761 | }, 762 | "node_modules/glob-parent": { 763 | "version": "5.1.2", 764 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 765 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 766 | "dev": true, 767 | "dependencies": { 768 | "is-glob": "^4.0.1" 769 | }, 770 | "engines": { 771 | "node": ">= 6" 772 | } 773 | }, 774 | "node_modules/graceful-fs": { 775 | "version": "4.2.11", 776 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 777 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", 778 | "dev": true 779 | }, 780 | "node_modules/has-flag": { 781 | "version": "4.0.0", 782 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 783 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 784 | "dev": true, 785 | "engines": { 786 | "node": ">=8" 787 | } 788 | }, 789 | "node_modules/he": { 790 | "version": "1.2.0", 791 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 792 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 793 | "dev": true, 794 | "bin": { 795 | "he": "bin/he" 796 | } 797 | }, 798 | "node_modules/http-proxy-agent": { 799 | "version": "4.0.1", 800 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", 801 | "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", 802 | "dev": true, 803 | "dependencies": { 804 | "@tootallnate/once": "1", 805 | "agent-base": "6", 806 | "debug": "4" 807 | }, 808 | "engines": { 809 | "node": ">= 6" 810 | } 811 | }, 812 | "node_modules/https-proxy-agent": { 813 | "version": "5.0.1", 814 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", 815 | "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", 816 | "dev": true, 817 | "dependencies": { 818 | "agent-base": "6", 819 | "debug": "4" 820 | }, 821 | "engines": { 822 | "node": ">= 6" 823 | } 824 | }, 825 | "node_modules/inflight": { 826 | "version": "1.0.6", 827 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 828 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 829 | "dev": true, 830 | "dependencies": { 831 | "once": "^1.3.0", 832 | "wrappy": "1" 833 | } 834 | }, 835 | "node_modules/inherits": { 836 | "version": "2.0.4", 837 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 838 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 839 | "dev": true 840 | }, 841 | "node_modules/is-binary-path": { 842 | "version": "2.1.0", 843 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 844 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 845 | "dev": true, 846 | "dependencies": { 847 | "binary-extensions": "^2.0.0" 848 | }, 849 | "engines": { 850 | "node": ">=8" 851 | } 852 | }, 853 | "node_modules/is-extglob": { 854 | "version": "2.1.1", 855 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 856 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 857 | "dev": true, 858 | "engines": { 859 | "node": ">=0.10.0" 860 | } 861 | }, 862 | "node_modules/is-fullwidth-code-point": { 863 | "version": "3.0.0", 864 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 865 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 866 | "dev": true, 867 | "engines": { 868 | "node": ">=8" 869 | } 870 | }, 871 | "node_modules/is-glob": { 872 | "version": "4.0.3", 873 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 874 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 875 | "dev": true, 876 | "dependencies": { 877 | "is-extglob": "^2.1.1" 878 | }, 879 | "engines": { 880 | "node": ">=0.10.0" 881 | } 882 | }, 883 | "node_modules/is-number": { 884 | "version": "7.0.0", 885 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 886 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 887 | "dev": true, 888 | "engines": { 889 | "node": ">=0.12.0" 890 | } 891 | }, 892 | "node_modules/is-plain-obj": { 893 | "version": "2.1.0", 894 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", 895 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", 896 | "dev": true, 897 | "engines": { 898 | "node": ">=8" 899 | } 900 | }, 901 | "node_modules/is-unicode-supported": { 902 | "version": "0.1.0", 903 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", 904 | "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", 905 | "dev": true, 906 | "engines": { 907 | "node": ">=10" 908 | }, 909 | "funding": { 910 | "url": "https://github.com/sponsors/sindresorhus" 911 | } 912 | }, 913 | "node_modules/isarray": { 914 | "version": "0.0.1", 915 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 916 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 917 | "dev": true 918 | }, 919 | "node_modules/isexe": { 920 | "version": "2.0.0", 921 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 922 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 923 | "dev": true 924 | }, 925 | "node_modules/jackspeak": { 926 | "version": "2.3.6", 927 | "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", 928 | "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", 929 | "dev": true, 930 | "dependencies": { 931 | "@isaacs/cliui": "^8.0.2" 932 | }, 933 | "engines": { 934 | "node": ">=14" 935 | }, 936 | "funding": { 937 | "url": "https://github.com/sponsors/isaacs" 938 | }, 939 | "optionalDependencies": { 940 | "@pkgjs/parseargs": "^0.11.0" 941 | } 942 | }, 943 | "node_modules/js-yaml": { 944 | "version": "4.1.0", 945 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 946 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 947 | "dev": true, 948 | "dependencies": { 949 | "argparse": "^2.0.1" 950 | }, 951 | "bin": { 952 | "js-yaml": "bin/js-yaml.js" 953 | } 954 | }, 955 | "node_modules/listenercount": { 956 | "version": "1.0.1", 957 | "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", 958 | "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", 959 | "dev": true 960 | }, 961 | "node_modules/locate-path": { 962 | "version": "6.0.0", 963 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 964 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 965 | "dev": true, 966 | "dependencies": { 967 | "p-locate": "^5.0.0" 968 | }, 969 | "engines": { 970 | "node": ">=10" 971 | }, 972 | "funding": { 973 | "url": "https://github.com/sponsors/sindresorhus" 974 | } 975 | }, 976 | "node_modules/log-symbols": { 977 | "version": "4.1.0", 978 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", 979 | "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", 980 | "dev": true, 981 | "dependencies": { 982 | "chalk": "^4.1.0", 983 | "is-unicode-supported": "^0.1.0" 984 | }, 985 | "engines": { 986 | "node": ">=10" 987 | }, 988 | "funding": { 989 | "url": "https://github.com/sponsors/sindresorhus" 990 | } 991 | }, 992 | "node_modules/lru-cache": { 993 | "version": "10.2.0", 994 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", 995 | "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", 996 | "dev": true, 997 | "engines": { 998 | "node": "14 || >=16.14" 999 | } 1000 | }, 1001 | "node_modules/minimatch": { 1002 | "version": "3.0.4", 1003 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1004 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1005 | "dev": true, 1006 | "dependencies": { 1007 | "brace-expansion": "^1.1.7" 1008 | }, 1009 | "engines": { 1010 | "node": "*" 1011 | } 1012 | }, 1013 | "node_modules/minimist": { 1014 | "version": "1.2.8", 1015 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", 1016 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", 1017 | "dev": true, 1018 | "funding": { 1019 | "url": "https://github.com/sponsors/ljharb" 1020 | } 1021 | }, 1022 | "node_modules/minipass": { 1023 | "version": "7.0.4", 1024 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", 1025 | "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", 1026 | "dev": true, 1027 | "engines": { 1028 | "node": ">=16 || 14 >=14.17" 1029 | } 1030 | }, 1031 | "node_modules/mkdirp": { 1032 | "version": "1.0.4", 1033 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", 1034 | "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", 1035 | "dev": true, 1036 | "bin": { 1037 | "mkdirp": "bin/cmd.js" 1038 | }, 1039 | "engines": { 1040 | "node": ">=10" 1041 | } 1042 | }, 1043 | "node_modules/mocha": { 1044 | "version": "10.4.0", 1045 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.4.0.tgz", 1046 | "integrity": "sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==", 1047 | "dev": true, 1048 | "dependencies": { 1049 | "ansi-colors": "4.1.1", 1050 | "browser-stdout": "1.3.1", 1051 | "chokidar": "3.5.3", 1052 | "debug": "4.3.4", 1053 | "diff": "5.0.0", 1054 | "escape-string-regexp": "4.0.0", 1055 | "find-up": "5.0.0", 1056 | "glob": "8.1.0", 1057 | "he": "1.2.0", 1058 | "js-yaml": "4.1.0", 1059 | "log-symbols": "4.1.0", 1060 | "minimatch": "5.0.1", 1061 | "ms": "2.1.3", 1062 | "serialize-javascript": "6.0.0", 1063 | "strip-json-comments": "3.1.1", 1064 | "supports-color": "8.1.1", 1065 | "workerpool": "6.2.1", 1066 | "yargs": "16.2.0", 1067 | "yargs-parser": "20.2.4", 1068 | "yargs-unparser": "2.0.0" 1069 | }, 1070 | "bin": { 1071 | "_mocha": "bin/_mocha", 1072 | "mocha": "bin/mocha.js" 1073 | }, 1074 | "engines": { 1075 | "node": ">= 14.0.0" 1076 | } 1077 | }, 1078 | "node_modules/mocha/node_modules/brace-expansion": { 1079 | "version": "2.0.1", 1080 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 1081 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 1082 | "dev": true, 1083 | "dependencies": { 1084 | "balanced-match": "^1.0.0" 1085 | } 1086 | }, 1087 | "node_modules/mocha/node_modules/glob": { 1088 | "version": "8.1.0", 1089 | "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", 1090 | "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", 1091 | "dev": true, 1092 | "dependencies": { 1093 | "fs.realpath": "^1.0.0", 1094 | "inflight": "^1.0.4", 1095 | "inherits": "2", 1096 | "minimatch": "^5.0.1", 1097 | "once": "^1.3.0" 1098 | }, 1099 | "engines": { 1100 | "node": ">=12" 1101 | }, 1102 | "funding": { 1103 | "url": "https://github.com/sponsors/isaacs" 1104 | } 1105 | }, 1106 | "node_modules/mocha/node_modules/minimatch": { 1107 | "version": "5.0.1", 1108 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", 1109 | "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", 1110 | "dev": true, 1111 | "dependencies": { 1112 | "brace-expansion": "^2.0.1" 1113 | }, 1114 | "engines": { 1115 | "node": ">=10" 1116 | } 1117 | }, 1118 | "node_modules/ms": { 1119 | "version": "2.1.3", 1120 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1121 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1122 | "dev": true 1123 | }, 1124 | "node_modules/noms": { 1125 | "version": "0.0.0", 1126 | "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", 1127 | "integrity": "sha1-2o69nzr51nYJGbJ9nNyAkqczKFk=", 1128 | "dev": true, 1129 | "dependencies": { 1130 | "inherits": "^2.0.1", 1131 | "readable-stream": "~1.0.31" 1132 | } 1133 | }, 1134 | "node_modules/normalize-path": { 1135 | "version": "3.0.0", 1136 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1137 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1138 | "dev": true, 1139 | "engines": { 1140 | "node": ">=0.10.0" 1141 | } 1142 | }, 1143 | "node_modules/once": { 1144 | "version": "1.4.0", 1145 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1146 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1147 | "dev": true, 1148 | "dependencies": { 1149 | "wrappy": "1" 1150 | } 1151 | }, 1152 | "node_modules/p-limit": { 1153 | "version": "3.1.0", 1154 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 1155 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 1156 | "dev": true, 1157 | "dependencies": { 1158 | "yocto-queue": "^0.1.0" 1159 | }, 1160 | "engines": { 1161 | "node": ">=10" 1162 | }, 1163 | "funding": { 1164 | "url": "https://github.com/sponsors/sindresorhus" 1165 | } 1166 | }, 1167 | "node_modules/p-locate": { 1168 | "version": "5.0.0", 1169 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 1170 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 1171 | "dev": true, 1172 | "dependencies": { 1173 | "p-limit": "^3.0.2" 1174 | }, 1175 | "engines": { 1176 | "node": ">=10" 1177 | }, 1178 | "funding": { 1179 | "url": "https://github.com/sponsors/sindresorhus" 1180 | } 1181 | }, 1182 | "node_modules/path-exists": { 1183 | "version": "4.0.0", 1184 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 1185 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 1186 | "dev": true, 1187 | "engines": { 1188 | "node": ">=8" 1189 | } 1190 | }, 1191 | "node_modules/path-is-absolute": { 1192 | "version": "1.0.1", 1193 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1194 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1195 | "dev": true, 1196 | "engines": { 1197 | "node": ">=0.10.0" 1198 | } 1199 | }, 1200 | "node_modules/path-key": { 1201 | "version": "3.1.1", 1202 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 1203 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 1204 | "dev": true, 1205 | "engines": { 1206 | "node": ">=8" 1207 | } 1208 | }, 1209 | "node_modules/path-scurry": { 1210 | "version": "1.10.2", 1211 | "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", 1212 | "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", 1213 | "dev": true, 1214 | "dependencies": { 1215 | "lru-cache": "^10.2.0", 1216 | "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" 1217 | }, 1218 | "engines": { 1219 | "node": ">=16 || 14 >=14.17" 1220 | }, 1221 | "funding": { 1222 | "url": "https://github.com/sponsors/isaacs" 1223 | } 1224 | }, 1225 | "node_modules/picomatch": { 1226 | "version": "2.3.1", 1227 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1228 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1229 | "dev": true, 1230 | "engines": { 1231 | "node": ">=8.6" 1232 | }, 1233 | "funding": { 1234 | "url": "https://github.com/sponsors/jonschlinkert" 1235 | } 1236 | }, 1237 | "node_modules/process-nextick-args": { 1238 | "version": "2.0.1", 1239 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 1240 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", 1241 | "dev": true 1242 | }, 1243 | "node_modules/randombytes": { 1244 | "version": "2.1.0", 1245 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 1246 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 1247 | "dev": true, 1248 | "dependencies": { 1249 | "safe-buffer": "^5.1.0" 1250 | } 1251 | }, 1252 | "node_modules/readable-stream": { 1253 | "version": "1.0.34", 1254 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", 1255 | "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", 1256 | "dev": true, 1257 | "dependencies": { 1258 | "core-util-is": "~1.0.0", 1259 | "inherits": "~2.0.1", 1260 | "isarray": "0.0.1", 1261 | "string_decoder": "~0.10.x" 1262 | } 1263 | }, 1264 | "node_modules/readdirp": { 1265 | "version": "3.6.0", 1266 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 1267 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1268 | "dev": true, 1269 | "dependencies": { 1270 | "picomatch": "^2.2.1" 1271 | }, 1272 | "engines": { 1273 | "node": ">=8.10.0" 1274 | } 1275 | }, 1276 | "node_modules/require-directory": { 1277 | "version": "2.1.1", 1278 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 1279 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 1280 | "dev": true, 1281 | "engines": { 1282 | "node": ">=0.10.0" 1283 | } 1284 | }, 1285 | "node_modules/rimraf": { 1286 | "version": "5.0.5", 1287 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", 1288 | "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", 1289 | "dev": true, 1290 | "dependencies": { 1291 | "glob": "^10.3.7" 1292 | }, 1293 | "bin": { 1294 | "rimraf": "dist/esm/bin.mjs" 1295 | }, 1296 | "engines": { 1297 | "node": ">=14" 1298 | }, 1299 | "funding": { 1300 | "url": "https://github.com/sponsors/isaacs" 1301 | } 1302 | }, 1303 | "node_modules/rimraf/node_modules/brace-expansion": { 1304 | "version": "2.0.1", 1305 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 1306 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 1307 | "dev": true, 1308 | "dependencies": { 1309 | "balanced-match": "^1.0.0" 1310 | } 1311 | }, 1312 | "node_modules/rimraf/node_modules/glob": { 1313 | "version": "10.3.12", 1314 | "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", 1315 | "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", 1316 | "dev": true, 1317 | "dependencies": { 1318 | "foreground-child": "^3.1.0", 1319 | "jackspeak": "^2.3.6", 1320 | "minimatch": "^9.0.1", 1321 | "minipass": "^7.0.4", 1322 | "path-scurry": "^1.10.2" 1323 | }, 1324 | "bin": { 1325 | "glob": "dist/esm/bin.mjs" 1326 | }, 1327 | "engines": { 1328 | "node": ">=16 || 14 >=14.17" 1329 | }, 1330 | "funding": { 1331 | "url": "https://github.com/sponsors/isaacs" 1332 | } 1333 | }, 1334 | "node_modules/rimraf/node_modules/minimatch": { 1335 | "version": "9.0.4", 1336 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", 1337 | "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", 1338 | "dev": true, 1339 | "dependencies": { 1340 | "brace-expansion": "^2.0.1" 1341 | }, 1342 | "engines": { 1343 | "node": ">=16 || 14 >=14.17" 1344 | }, 1345 | "funding": { 1346 | "url": "https://github.com/sponsors/isaacs" 1347 | } 1348 | }, 1349 | "node_modules/safe-buffer": { 1350 | "version": "5.1.2", 1351 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1352 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 1353 | "dev": true 1354 | }, 1355 | "node_modules/serialize-javascript": { 1356 | "version": "6.0.0", 1357 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", 1358 | "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", 1359 | "dev": true, 1360 | "dependencies": { 1361 | "randombytes": "^2.1.0" 1362 | } 1363 | }, 1364 | "node_modules/setimmediate": { 1365 | "version": "1.0.5", 1366 | "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", 1367 | "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", 1368 | "dev": true 1369 | }, 1370 | "node_modules/shebang-command": { 1371 | "version": "2.0.0", 1372 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 1373 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 1374 | "dev": true, 1375 | "dependencies": { 1376 | "shebang-regex": "^3.0.0" 1377 | }, 1378 | "engines": { 1379 | "node": ">=8" 1380 | } 1381 | }, 1382 | "node_modules/shebang-regex": { 1383 | "version": "3.0.0", 1384 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 1385 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 1386 | "dev": true, 1387 | "engines": { 1388 | "node": ">=8" 1389 | } 1390 | }, 1391 | "node_modules/signal-exit": { 1392 | "version": "4.1.0", 1393 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", 1394 | "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", 1395 | "dev": true, 1396 | "engines": { 1397 | "node": ">=14" 1398 | }, 1399 | "funding": { 1400 | "url": "https://github.com/sponsors/isaacs" 1401 | } 1402 | }, 1403 | "node_modules/string_decoder": { 1404 | "version": "0.10.31", 1405 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 1406 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", 1407 | "dev": true 1408 | }, 1409 | "node_modules/string-width": { 1410 | "version": "4.2.3", 1411 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1412 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1413 | "dev": true, 1414 | "dependencies": { 1415 | "emoji-regex": "^8.0.0", 1416 | "is-fullwidth-code-point": "^3.0.0", 1417 | "strip-ansi": "^6.0.1" 1418 | }, 1419 | "engines": { 1420 | "node": ">=8" 1421 | } 1422 | }, 1423 | "node_modules/string-width-cjs": { 1424 | "name": "string-width", 1425 | "version": "4.2.3", 1426 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1427 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1428 | "dev": true, 1429 | "dependencies": { 1430 | "emoji-regex": "^8.0.0", 1431 | "is-fullwidth-code-point": "^3.0.0", 1432 | "strip-ansi": "^6.0.1" 1433 | }, 1434 | "engines": { 1435 | "node": ">=8" 1436 | } 1437 | }, 1438 | "node_modules/strip-ansi": { 1439 | "version": "6.0.1", 1440 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1441 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1442 | "dev": true, 1443 | "dependencies": { 1444 | "ansi-regex": "^5.0.1" 1445 | }, 1446 | "engines": { 1447 | "node": ">=8" 1448 | } 1449 | }, 1450 | "node_modules/strip-ansi-cjs": { 1451 | "name": "strip-ansi", 1452 | "version": "6.0.1", 1453 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1454 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1455 | "dev": true, 1456 | "dependencies": { 1457 | "ansi-regex": "^5.0.1" 1458 | }, 1459 | "engines": { 1460 | "node": ">=8" 1461 | } 1462 | }, 1463 | "node_modules/strip-json-comments": { 1464 | "version": "3.1.1", 1465 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 1466 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 1467 | "dev": true, 1468 | "engines": { 1469 | "node": ">=8" 1470 | }, 1471 | "funding": { 1472 | "url": "https://github.com/sponsors/sindresorhus" 1473 | } 1474 | }, 1475 | "node_modules/supports-color": { 1476 | "version": "8.1.1", 1477 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 1478 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 1479 | "dev": true, 1480 | "dependencies": { 1481 | "has-flag": "^4.0.0" 1482 | }, 1483 | "engines": { 1484 | "node": ">=10" 1485 | }, 1486 | "funding": { 1487 | "url": "https://github.com/chalk/supports-color?sponsor=1" 1488 | } 1489 | }, 1490 | "node_modules/through2": { 1491 | "version": "2.0.5", 1492 | "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", 1493 | "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", 1494 | "dev": true, 1495 | "dependencies": { 1496 | "readable-stream": "~2.3.6", 1497 | "xtend": "~4.0.1" 1498 | } 1499 | }, 1500 | "node_modules/through2/node_modules/isarray": { 1501 | "version": "1.0.0", 1502 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1503 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 1504 | "dev": true 1505 | }, 1506 | "node_modules/through2/node_modules/readable-stream": { 1507 | "version": "2.3.7", 1508 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", 1509 | "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", 1510 | "dev": true, 1511 | "dependencies": { 1512 | "core-util-is": "~1.0.0", 1513 | "inherits": "~2.0.3", 1514 | "isarray": "~1.0.0", 1515 | "process-nextick-args": "~2.0.0", 1516 | "safe-buffer": "~5.1.1", 1517 | "string_decoder": "~1.1.1", 1518 | "util-deprecate": "~1.0.1" 1519 | } 1520 | }, 1521 | "node_modules/through2/node_modules/string_decoder": { 1522 | "version": "1.1.1", 1523 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1524 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1525 | "dev": true, 1526 | "dependencies": { 1527 | "safe-buffer": "~5.1.0" 1528 | } 1529 | }, 1530 | "node_modules/to-regex-range": { 1531 | "version": "5.0.1", 1532 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1533 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1534 | "dev": true, 1535 | "dependencies": { 1536 | "is-number": "^7.0.0" 1537 | }, 1538 | "engines": { 1539 | "node": ">=8.0" 1540 | } 1541 | }, 1542 | "node_modules/traverse": { 1543 | "version": "0.3.9", 1544 | "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", 1545 | "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", 1546 | "dev": true, 1547 | "engines": { 1548 | "node": "*" 1549 | } 1550 | }, 1551 | "node_modules/typescript": { 1552 | "version": "4.9.5", 1553 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", 1554 | "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", 1555 | "dev": true, 1556 | "bin": { 1557 | "tsc": "bin/tsc", 1558 | "tsserver": "bin/tsserver" 1559 | }, 1560 | "engines": { 1561 | "node": ">=4.2.0" 1562 | } 1563 | }, 1564 | "node_modules/undici-types": { 1565 | "version": "5.26.5", 1566 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", 1567 | "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", 1568 | "dev": true 1569 | }, 1570 | "node_modules/untildify": { 1571 | "version": "4.0.0", 1572 | "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", 1573 | "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", 1574 | "dev": true, 1575 | "engines": { 1576 | "node": ">=8" 1577 | } 1578 | }, 1579 | "node_modules/unzipper": { 1580 | "version": "0.10.14", 1581 | "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", 1582 | "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", 1583 | "dev": true, 1584 | "dependencies": { 1585 | "big-integer": "^1.6.17", 1586 | "binary": "~0.3.0", 1587 | "bluebird": "~3.4.1", 1588 | "buffer-indexof-polyfill": "~1.0.0", 1589 | "duplexer2": "~0.1.4", 1590 | "fstream": "^1.0.12", 1591 | "graceful-fs": "^4.2.2", 1592 | "listenercount": "~1.0.1", 1593 | "readable-stream": "~2.3.6", 1594 | "setimmediate": "~1.0.4" 1595 | } 1596 | }, 1597 | "node_modules/unzipper/node_modules/isarray": { 1598 | "version": "1.0.0", 1599 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1600 | "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", 1601 | "dev": true 1602 | }, 1603 | "node_modules/unzipper/node_modules/readable-stream": { 1604 | "version": "2.3.8", 1605 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", 1606 | "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", 1607 | "dev": true, 1608 | "dependencies": { 1609 | "core-util-is": "~1.0.0", 1610 | "inherits": "~2.0.3", 1611 | "isarray": "~1.0.0", 1612 | "process-nextick-args": "~2.0.0", 1613 | "safe-buffer": "~5.1.1", 1614 | "string_decoder": "~1.1.1", 1615 | "util-deprecate": "~1.0.1" 1616 | } 1617 | }, 1618 | "node_modules/unzipper/node_modules/string_decoder": { 1619 | "version": "1.1.1", 1620 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1621 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1622 | "dev": true, 1623 | "dependencies": { 1624 | "safe-buffer": "~5.1.0" 1625 | } 1626 | }, 1627 | "node_modules/util-deprecate": { 1628 | "version": "1.0.2", 1629 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1630 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 1631 | "dev": true 1632 | }, 1633 | "node_modules/vscode-test": { 1634 | "version": "1.6.1", 1635 | "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.6.1.tgz", 1636 | "integrity": "sha512-086q88T2ca1k95mUzffvbzb7esqQNvJgiwY4h29ukPhFo8u+vXOOmelUoU5EQUHs3Of8+JuQ3oGdbVCqaxuTXA==", 1637 | "deprecated": "This package has been renamed to @vscode/test-electron, please update to the new name", 1638 | "dev": true, 1639 | "dependencies": { 1640 | "http-proxy-agent": "^4.0.1", 1641 | "https-proxy-agent": "^5.0.0", 1642 | "rimraf": "^3.0.2", 1643 | "unzipper": "^0.10.11" 1644 | }, 1645 | "engines": { 1646 | "node": ">=8.9.3" 1647 | } 1648 | }, 1649 | "node_modules/vscode-test/node_modules/rimraf": { 1650 | "version": "3.0.2", 1651 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 1652 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 1653 | "dev": true, 1654 | "dependencies": { 1655 | "glob": "^7.1.3" 1656 | }, 1657 | "bin": { 1658 | "rimraf": "bin.js" 1659 | }, 1660 | "funding": { 1661 | "url": "https://github.com/sponsors/isaacs" 1662 | } 1663 | }, 1664 | "node_modules/which": { 1665 | "version": "2.0.2", 1666 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 1667 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1668 | "dev": true, 1669 | "dependencies": { 1670 | "isexe": "^2.0.0" 1671 | }, 1672 | "bin": { 1673 | "node-which": "bin/node-which" 1674 | }, 1675 | "engines": { 1676 | "node": ">= 8" 1677 | } 1678 | }, 1679 | "node_modules/workerpool": { 1680 | "version": "6.2.1", 1681 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", 1682 | "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", 1683 | "dev": true 1684 | }, 1685 | "node_modules/wrap-ansi": { 1686 | "version": "7.0.0", 1687 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1688 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1689 | "dev": true, 1690 | "dependencies": { 1691 | "ansi-styles": "^4.0.0", 1692 | "string-width": "^4.1.0", 1693 | "strip-ansi": "^6.0.0" 1694 | }, 1695 | "engines": { 1696 | "node": ">=10" 1697 | }, 1698 | "funding": { 1699 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 1700 | } 1701 | }, 1702 | "node_modules/wrap-ansi-cjs": { 1703 | "name": "wrap-ansi", 1704 | "version": "7.0.0", 1705 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1706 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1707 | "dev": true, 1708 | "dependencies": { 1709 | "ansi-styles": "^4.0.0", 1710 | "string-width": "^4.1.0", 1711 | "strip-ansi": "^6.0.0" 1712 | }, 1713 | "engines": { 1714 | "node": ">=10" 1715 | }, 1716 | "funding": { 1717 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 1718 | } 1719 | }, 1720 | "node_modules/wrappy": { 1721 | "version": "1.0.2", 1722 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1723 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1724 | "dev": true 1725 | }, 1726 | "node_modules/ws": { 1727 | "version": "7.5.9", 1728 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", 1729 | "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", 1730 | "engines": { 1731 | "node": ">=8.3.0" 1732 | }, 1733 | "peerDependencies": { 1734 | "bufferutil": "^4.0.1", 1735 | "utf-8-validate": "^5.0.2" 1736 | }, 1737 | "peerDependenciesMeta": { 1738 | "bufferutil": { 1739 | "optional": true 1740 | }, 1741 | "utf-8-validate": { 1742 | "optional": true 1743 | } 1744 | } 1745 | }, 1746 | "node_modules/xtend": { 1747 | "version": "4.0.2", 1748 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 1749 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", 1750 | "dev": true, 1751 | "engines": { 1752 | "node": ">=0.4" 1753 | } 1754 | }, 1755 | "node_modules/y18n": { 1756 | "version": "5.0.8", 1757 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 1758 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 1759 | "dev": true, 1760 | "engines": { 1761 | "node": ">=10" 1762 | } 1763 | }, 1764 | "node_modules/yargs": { 1765 | "version": "16.2.0", 1766 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", 1767 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", 1768 | "dev": true, 1769 | "dependencies": { 1770 | "cliui": "^7.0.2", 1771 | "escalade": "^3.1.1", 1772 | "get-caller-file": "^2.0.5", 1773 | "require-directory": "^2.1.1", 1774 | "string-width": "^4.2.0", 1775 | "y18n": "^5.0.5", 1776 | "yargs-parser": "^20.2.2" 1777 | }, 1778 | "engines": { 1779 | "node": ">=10" 1780 | } 1781 | }, 1782 | "node_modules/yargs-parser": { 1783 | "version": "20.2.4", 1784 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", 1785 | "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", 1786 | "dev": true, 1787 | "engines": { 1788 | "node": ">=10" 1789 | } 1790 | }, 1791 | "node_modules/yargs-unparser": { 1792 | "version": "2.0.0", 1793 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", 1794 | "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", 1795 | "dev": true, 1796 | "dependencies": { 1797 | "camelcase": "^6.0.0", 1798 | "decamelize": "^4.0.0", 1799 | "flat": "^5.0.2", 1800 | "is-plain-obj": "^2.1.0" 1801 | }, 1802 | "engines": { 1803 | "node": ">=10" 1804 | } 1805 | }, 1806 | "node_modules/yocto-queue": { 1807 | "version": "0.1.0", 1808 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 1809 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 1810 | "dev": true, 1811 | "engines": { 1812 | "node": ">=10" 1813 | }, 1814 | "funding": { 1815 | "url": "https://github.com/sponsors/sindresorhus" 1816 | } 1817 | } 1818 | } 1819 | } 1820 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rpc-example", 3 | "displayName": "rpc-example", 4 | "description": "", 5 | "version": "0.0.1", 6 | "engines": { 7 | "vscode": "^1.38.0" 8 | }, 9 | "categories": [ 10 | "Other" 11 | ], 12 | "activationEvents": [ 13 | "onCommand:extension.openwebview", 14 | "onCommand:extension.sendMessage" 15 | ], 16 | "main": "./out/extension", 17 | "contributes": { 18 | "commands": [ 19 | { 20 | "command": "extension.openwebview", 21 | "title": "Open Webview" 22 | }, 23 | { 24 | "command": "extension.sendMessage", 25 | "title": "Send Message to Webview" 26 | } 27 | ] 28 | }, 29 | "scripts": { 30 | "vscode:prepublish": "npm run compile", 31 | "compile": "tsc -p ./", 32 | "watch": "tsc -watch -p ./", 33 | "copy": "rimraf ./out/media && copyfiles -u 1 ./src/media/** ./out/", 34 | "pretest": "npm run compile" 35 | }, 36 | "devDependencies": { 37 | "@types/glob": "^7.1.1", 38 | "@types/node": "^18.11.1", 39 | "@types/vscode": "^1.44.0", 40 | "copyfiles": "^2.4.1", 41 | "glob": "^7.1.6", 42 | "mocha": "^10.4.0", 43 | "rimraf": "^5.0.5", 44 | "typescript": "^4.2.3", 45 | "vscode-test": "^1.6.1" 46 | }, 47 | "dependencies": { 48 | "@sap-devx/webview-rpc": "1.0.0" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /example/src/extension.ts: -------------------------------------------------------------------------------- 1 | // The module 'vscode' contains the VS Code extensibility API 2 | // Import the module and reference it with the alias vscode in your code below 3 | import * as path from 'path'; 4 | import * as vscode from 'vscode'; 5 | import * as fs from 'fs'; 6 | import { RpcExtension } from '@sap-devx/webview-rpc/out.ext/rpc-extension'; 7 | 8 | // this method is called when your extension is activated 9 | // your extension is activated the very first time the command is executed 10 | export function activate(context: vscode.ExtensionContext) { 11 | 12 | let cmd1 = vscode.commands.registerCommand('extension.openwebview', () => { 13 | RpcExamplePanel.createOrShow(context.extensionPath); 14 | }); 15 | 16 | context.subscriptions.push(cmd1); 17 | 18 | let cmd2 = vscode.commands.registerCommand('extension.sendMessage', () => { 19 | RpcExamplePanel.sendMessage(); 20 | }); 21 | 22 | context.subscriptions.push(cmd2); 23 | 24 | if (vscode.window.registerWebviewPanelSerializer) { 25 | // Make sure we register a serializer in activation event 26 | vscode.window.registerWebviewPanelSerializer(RpcExamplePanel.viewType, { 27 | async deserializeWebviewPanel(webviewPanel: vscode.WebviewPanel, state: any) { 28 | console.log(`Got state: ${state}`); 29 | RpcExamplePanel.revive(webviewPanel, context.extensionPath); 30 | } 31 | }); 32 | } 33 | 34 | 35 | } 36 | 37 | 38 | /** 39 | * Manages cat coding webview panels 40 | */ 41 | class RpcExamplePanel { 42 | /** 43 | * Track the currently panel. Only allow a single panel to exist at a time. 44 | */ 45 | public static currentPanel: RpcExamplePanel | undefined; 46 | 47 | public static readonly viewType = 'rpcExample'; 48 | 49 | private context : any; 50 | private readonly _panel: vscode.WebviewPanel; 51 | private readonly _extensionPath: string; 52 | private _disposables: vscode.Disposable[] = []; 53 | private _rpc: RpcExtension; 54 | 55 | public static sendMessage() { 56 | this.currentPanel._rpc.invoke("runFunctionInWebview", "message from extension").then((response => { 57 | vscode.window.showInformationMessage(response); 58 | })); 59 | } 60 | 61 | public static createOrShow(extensionPath: string) { 62 | const column = vscode.window.activeTextEditor 63 | ? vscode.window.activeTextEditor.viewColumn 64 | : undefined; 65 | 66 | 67 | // If we already have a panel, show it. 68 | if (RpcExamplePanel.currentPanel) { 69 | RpcExamplePanel.currentPanel._panel.reveal(column); 70 | return; 71 | } 72 | 73 | // Otherwise, create a new panel. 74 | const panel = vscode.window.createWebviewPanel( 75 | RpcExamplePanel.viewType, 76 | 'Webview Example', 77 | column || vscode.ViewColumn.One, 78 | { 79 | // Enable javascript in the webview 80 | enableScripts: true 81 | } 82 | ); 83 | 84 | RpcExamplePanel.currentPanel = new RpcExamplePanel(panel, extensionPath); 85 | } 86 | 87 | public static revive(panel: vscode.WebviewPanel, extensionPath: string) { 88 | RpcExamplePanel.currentPanel = new RpcExamplePanel(panel, extensionPath); 89 | } 90 | 91 | private constructor(panel: vscode.WebviewPanel, extensionPath: string) { 92 | this._panel = panel; 93 | this._extensionPath = extensionPath; 94 | 95 | let functions = { 96 | showMessage: (message) => { 97 | let _vscode = vscode; 98 | return new Promise((resolve, reject) => { 99 | _vscode.window.showInformationMessage(message, "yes", "no").then((res) => { 100 | resolve(res); 101 | }); 102 | }); 103 | } 104 | }; 105 | // logger is optional second parameter, implementing interface IChildLogger: 106 | // https://github.com/SAP/vscode-logging/blob/master/packages/types/api.d.ts#L17 107 | // see example on how to initialize it from extension here: 108 | // https://github.com/SAP/vscode-logging/blob/master/examples/extension/lib/passing-logger-to-library.js 109 | this._rpc = new RpcExtension(this._panel.webview); 110 | this._rpc.registerMethod({ func: functions.showMessage }); 111 | 112 | // Set the webview's initial html content 113 | this.update(this._panel.webview); 114 | 115 | // Listen for when the panel is disposed 116 | // This happens when the user closes the panel or when the panel is closed programatically 117 | this._panel.onDidDispose(() => this.dispose(), null, this._disposables); 118 | 119 | // Update the content based on view changes 120 | this._panel.onDidChangeViewState( 121 | e => { 122 | if (this._panel.visible) { 123 | this.update(this._panel.webview); 124 | } 125 | }, 126 | null, 127 | this._disposables 128 | ); 129 | } 130 | 131 | public dispose() { 132 | RpcExamplePanel.currentPanel = undefined; 133 | 134 | // Clean up our resources 135 | this._panel.dispose(); 136 | 137 | while (this._disposables.length) { 138 | const x = this._disposables.pop(); 139 | if (x) { 140 | x.dispose(); 141 | } 142 | } 143 | } 144 | 145 | private update(webview: vscode.Webview) { 146 | this._panel.title = "RPC Example"; 147 | this._panel.webview.html = this._getHtmlForWebview(webview); 148 | } 149 | 150 | private _getHtmlForWebview(webview: vscode.Webview) { 151 | // Local path to main script run in the webview 152 | const scriptsPathOnDisk = vscode.Uri.file( 153 | path.join(this._extensionPath) 154 | ); 155 | 156 | // And the uri we use to load this script in the webview 157 | const scriptsUri = webview.asWebviewUri(scriptsPathOnDisk); 158 | 159 | let html = fs.readFileSync(path.join(this._extensionPath, 'out', 'media', 'index.html'), "utf8"); 160 | html = html.replace(/vscode-scheme/g, scriptsUri.toString()).replace(/%3A/g, ":"); 161 | 162 | return html; 163 | } 164 | } 165 | 166 | // this method is called when your extension is deactivated 167 | export function deactivate() { } 168 | -------------------------------------------------------------------------------- /example/src/media/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

RPC Webview Example

13 | 14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /example/src/media/main.js: -------------------------------------------------------------------------------- 1 | import { RpcBrowser } from "../../node_modules/@sap-devx/webview-rpc/out.browser/rpc-browser.js"; 2 | 3 | let functions = { 4 | runFunctionInWebview: runFunctionInWebview 5 | } 6 | 7 | const vscode = acquireVsCodeApi(); 8 | // logger is optional third parameter, implementing interface IChildLogger: 9 | // https://github.com/SAP/vscode-logging/blob/master/packages/types/api.d.ts#L17 10 | let rpc = new RpcBrowser(window, vscode); 11 | rpc.registerMethod({func: functions.runFunctionInWebview}); 12 | 13 | window.onload = function(){ 14 | document.getElementById("btnShowMessage").addEventListener("click",showMessage); 15 | } 16 | 17 | function showMessage() { 18 | rpc.invoke("showMessage", "I'm a message").then((response)=>{ 19 | document.getElementById("responsediv").innerText = response; 20 | }) 21 | } 22 | 23 | function runFunctionInWebview(res) { 24 | document.getElementById("responsediv").innerText = res; 25 | return "updated"; 26 | } -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src" 11 | }, 12 | "exclude": [ 13 | "node_modules", 14 | ".vscode-test" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /example/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-string-throw": true, 4 | "no-unused-expression": true, 5 | "no-duplicate-variable": true, 6 | "curly": true, 7 | "class-name": true, 8 | "semicolon": [ 9 | true, 10 | "always" 11 | ], 12 | "triple-equals": true 13 | }, 14 | "defaultSeverity": "warning" 15 | } 16 | -------------------------------------------------------------------------------- /example/vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your VS Code Extension 2 | 3 | ## What's in the folder 4 | 5 | * This folder contains all of the files necessary for your extension. 6 | * `package.json` - this is the manifest file in which you declare your extension and command. 7 | * The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. 8 | * `src/extension.ts` - this is the main file where you will provide the implementation of your command. 9 | * The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. 10 | * We pass the function containing the implementation of the command as the second parameter to `registerCommand`. 11 | 12 | ## Get up and running straight away 13 | 14 | * Press `F5` to open a new window with your extension loaded. 15 | * Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`. 16 | * Set breakpoints in your code inside `src/extension.ts` to debug your extension. 17 | * Find output from your extension in the debug console. 18 | 19 | ## Make changes 20 | 21 | * You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`. 22 | * You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 23 | 24 | 25 | ## Explore the API 26 | 27 | * You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`. 28 | 29 | ## Run tests 30 | 31 | * Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`. 32 | * Press `F5` to run the tests in a new window with your extension loaded. 33 | * See the output of the test result in the debug console. 34 | * Make changes to `src/test/suite/extension.test.ts` or create new test files inside the `test/suite` folder. 35 | * The provided test runner will only consider files matching the name pattern `**.test.ts`. 36 | * You can create folders inside the `test` folder to structure your tests any way you want. 37 | 38 | ## Go further 39 | 40 | * Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension). 41 | * [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VSCode extension marketplace. 42 | * Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration). 43 | -------------------------------------------------------------------------------- /jest.config.unit.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | "^.+\\.ts$": "ts-jest" 4 | }, 5 | moduleFileExtensions: ["ts", "js", "json", "node" ], 6 | roots: ["/src"], 7 | preset: "ts-jest", 8 | coveragePathIgnorePatterns: ["src/test/.*"] 9 | }; 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sap-devx/webview-rpc", 3 | "version": "1.0.0", 4 | "description": "An RPC library for VSCode WebViews", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/SAP/vscode-webview-rpc-lib" 8 | }, 9 | "license": "Apache 2.0", 10 | "author": "Ido Perez", 11 | "publisher": "SAP", 12 | "scripts": { 13 | "ci": "npm run compile && npm run lint && npm run test && npm pack", 14 | "clean": "rimraf ./out.*", 15 | "compile": "npm run clean && npm run compile-ext && npm run compile-browser && npm run compile-test", 16 | "compile-browser": "rimraf ./out.browser && tsc -p tsconfig.browser.json", 17 | "compile-ext": "rimraf ./out.ext && tsc -p ./tsconfig.ext.json", 18 | "compile-test": "rimraf ./out.test && tsc -p tsconfig.test.json", 19 | "lint": "eslint ./**/*.ts", 20 | "test": "jest --config jest.config.unit.js --coverage", 21 | "watch": "npm run watch-ext && npm run watch-test", 22 | "watch-browser": "tsc -w -p ./tsconfig.browser.json", 23 | "watch-ext": "tsc -w -p ./tsconfig.ext.json", 24 | "watch-test": "tsc -w -p ./tsconfig.test.json" 25 | }, 26 | "husky": { 27 | "hooks": { 28 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" 29 | } 30 | }, 31 | "commitlint": { 32 | "extends": [ 33 | "@commitlint/config-conventional" 34 | ] 35 | }, 36 | "config": { 37 | "commitizen": { 38 | "path": "cz-conventional-changelog" 39 | } 40 | }, 41 | "dependencies": { 42 | "ws": "^7.2.3" 43 | }, 44 | "devDependencies": { 45 | "@commitlint/cli": "19.3.0", 46 | "@commitlint/config-conventional": "19.2.2", 47 | "@types/jest": "^29.5.12", 48 | "@types/node": "^18.0.1", 49 | "@types/vscode": "^1.83.0", 50 | "@types/ws": "^7.4.0", 51 | "@typescript-eslint/eslint-plugin": "^7.7.0", 52 | "@typescript-eslint/parser": "^7.7.0", 53 | "@vscode-logging/types": "^2.0.0", 54 | "coveralls": "3.1.1", 55 | "cz-conventional-changelog": "3.3.0", 56 | "eslint": "^8.56.0", 57 | "husky": "9.0.11", 58 | "jest": "^29.7.0", 59 | "rimraf": "^5.0.5", 60 | "ts-jest": "^29.1.2", 61 | "typescript": "^4.2.3" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/noop-logger.ts: -------------------------------------------------------------------------------- 1 | const NO_OPERATION = () => {}; 2 | 3 | /** 4 | * Empty Implementation of the Logger in case none is provided via Dependency Injection. 5 | * An alternative implementation could log to the console or provide another (real) implementation. 6 | * 7 | * @type {IChildLogger} 8 | */ 9 | export const noopLogger = { 10 | fatal: NO_OPERATION, 11 | error: NO_OPERATION, 12 | warn: NO_OPERATION, 13 | info: NO_OPERATION, 14 | debug: NO_OPERATION, 15 | trace: NO_OPERATION, 16 | getChildLogger: function () { 17 | return noopLogger; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /src/rpc-browser-ws.ts: -------------------------------------------------------------------------------- 1 | // must specify ".js" for import in browser to locate rpc-common.js 2 | // see: https://github.com/microsoft/TypeScript/issues/16577#issuecomment-343610106 3 | 4 | import { RpcCommon, IPromiseCallbacks } from "./rpc-common.js"; 5 | import { IChildLogger } from "@vscode-logging/types"; 6 | import { noopLogger } from "./noop-logger"; 7 | 8 | export class RpcBrowserWebSockets extends RpcCommon { 9 | private static readonly className = "RpcBrowserWebSockets"; 10 | private readonly logger: IChildLogger; 11 | ws: WebSocket; 12 | 13 | constructor(ws: WebSocket, logger: IChildLogger = noopLogger) { 14 | super(logger.getChildLogger({ label: RpcBrowserWebSockets.className })); 15 | this.logger = logger.getChildLogger({ label: RpcBrowserWebSockets.className }); 16 | this.ws = ws; 17 | this.ws.addEventListener("message", (event) => { 18 | const message: any = JSON.parse(event.data as string); 19 | this.logger.debug(`Event Listener: Received event: ${JSON.stringify(message)}`); 20 | switch (message.command) { 21 | case "rpc-response": 22 | this.handleResponse(message); 23 | break; 24 | case "rpc-request": 25 | this.handleRequest(message); 26 | break; 27 | } 28 | }); 29 | } 30 | 31 | sendRequest(id: number, method: string, params?: any[]) { 32 | // TODO: consider cancelling the timer if the promise if fulfilled before timeout is reached 33 | setTimeout(() => { 34 | const promiseCallbacks: IPromiseCallbacks | undefined = this.promiseCallbacks.get(id); 35 | if (promiseCallbacks) { 36 | this.logger.warn(`sendRequest: Request ${id} method ${method} has timed out`); 37 | promiseCallbacks.reject("Request timed out"); 38 | this.promiseCallbacks.delete(id); 39 | } 40 | }, this.timeout); 41 | 42 | // TODO: find an alternative to appending vscode to the global scope (perhaps providing vscode as parameter to constructor) 43 | const requestBody: any = { 44 | command: "rpc-request", 45 | id: id, 46 | method: method, 47 | params: params 48 | }; 49 | 50 | this.ws.send(JSON.stringify(requestBody)); 51 | } 52 | 53 | sendResponse(id: number, response: any, success: boolean = true): void { 54 | const responseBody: any = { 55 | command: "rpc-response", 56 | id: id, 57 | response: response, 58 | success: success 59 | }; 60 | 61 | this.ws.send(JSON.stringify(responseBody)); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/rpc-browser.ts: -------------------------------------------------------------------------------- 1 | /* must specify ".js" for import in browser to locate rpc-common.js 2 | see: https://github.com/microsoft/TypeScript/issues/16577#issuecomment-343610106 3 | */ 4 | 5 | import { RpcCommon, IPromiseCallbacks } from "./rpc-common.js"; 6 | import { IChildLogger } from "@vscode-logging/types"; 7 | import { noopLogger } from "./noop-logger.js"; 8 | 9 | export class RpcBrowser extends RpcCommon { 10 | private static readonly className = "RpcBrowser"; 11 | private readonly logger: IChildLogger; 12 | window: Window; 13 | vscode: WebviewFrame; 14 | host: string | undefined; 15 | 16 | constructor(window: Window, vscode: WebviewFrame, logger: IChildLogger = noopLogger) { 17 | super(logger.getChildLogger({ label: RpcBrowser.className })); 18 | this.logger = logger.getChildLogger({ label: RpcBrowser.className }); 19 | this.window = window; 20 | this.vscode = vscode; 21 | this.host = undefined; 22 | this.window.addEventListener("message", (event) => { 23 | const message = event.data; 24 | this.logger.debug(`Event Listener: Received event: ${JSON.stringify(message)}`); 25 | switch (message.command) { 26 | case "rpc-response": 27 | this.handleResponse(message); 28 | break; 29 | case "rpc-request": 30 | this.handleRequest(message); 31 | break; 32 | } 33 | }); 34 | } 35 | 36 | setHost(host: string) { 37 | this.host = host; 38 | } 39 | 40 | sendRequest(id: number, method: string, params?: any[]) { 41 | // TODO: consider cancelling the timer if the promise if fulfilled before timeout is reached 42 | setTimeout(() => { 43 | const promiseCallbacks: IPromiseCallbacks | undefined = this.promiseCallbacks.get(id); 44 | if (promiseCallbacks) { 45 | promiseCallbacks.reject("Request timed out"); 46 | this.promiseCallbacks.delete(id); 47 | } 48 | }, this.timeout); 49 | 50 | // TODO: find an alternative to appending vscode to the global scope (perhaps providing vscode as parameter to constructor) 51 | this.vscode.postMessage({ 52 | command: "rpc-request", 53 | id: id, 54 | method: method, 55 | params: params 56 | }, this.host); 57 | } 58 | 59 | sendResponse(id: number, response: any, success: boolean = true): void { 60 | this.vscode.postMessage({ 61 | command: "rpc-response", 62 | id: id, 63 | response: response, 64 | success: success 65 | }, this.host); 66 | } 67 | } 68 | 69 | interface WebviewFrame{ 70 | postMessage(message: any , host?: string): Thenable; 71 | } 72 | -------------------------------------------------------------------------------- /src/rpc-common.ts: -------------------------------------------------------------------------------- 1 | import { IChildLogger } from "@vscode-logging/types"; 2 | 3 | export interface IRpc { 4 | invoke(method: string, ...params: any[]): Promise; 5 | sendRequest(id: number, method: string, params?: any[]): void; 6 | sendResponse(id: number, response: any, success?: boolean): void; 7 | handleResponse(message: any): void; 8 | handleRequest(message: any): void; 9 | registerMethod(method: IMethod): void; 10 | unregisterMethod(method: IMethod): void; 11 | setResponseTimeout(timeout: number): void; 12 | listLocalMethods(): string[]; 13 | listRemoteMethods(): Promise; 14 | } 15 | 16 | export interface IPromiseCallbacks { 17 | resolve: Function; 18 | reject: Function; 19 | } 20 | 21 | export interface IMethod { 22 | func: Function; 23 | thisArg?: any; 24 | name?: string; 25 | } 26 | 27 | export abstract class RpcCommon implements IRpc { 28 | abstract sendRequest(id: number, method: string, params?: any[]): void; 29 | abstract sendResponse(id: number, response: any, success?: boolean): void; 30 | protected promiseCallbacks: Map; // promise resolve and reject callbacks that are called when returning from remote 31 | protected methods: Map; 32 | private readonly baseLogger: IChildLogger; 33 | // TODO: timeouts do not make sense for user interactions. consider not using timeouts by default 34 | protected timeout: number = 3600000; // timeout for response from remote in milliseconds 35 | 36 | constructor(logger: IChildLogger) { 37 | this.promiseCallbacks = new Map(); 38 | this.methods = new Map(); 39 | this.baseLogger = logger.getChildLogger({ label: "RpcCommon" }); 40 | this.registerMethod({ func: this.listLocalMethods, thisArg: this }); 41 | } 42 | 43 | public setResponseTimeout(timeout: number): void { 44 | this.timeout = timeout; 45 | } 46 | 47 | public registerMethod(method: IMethod): void { 48 | this.methods.set((method.name ? method.name : method.func.name), method); 49 | } 50 | 51 | public unregisterMethod(method: IMethod): void { 52 | this.methods.delete((method.name ? method.name : method.func.name)); 53 | } 54 | 55 | public listLocalMethods(): string[] { 56 | return Array.from(this.methods.keys()); 57 | } 58 | 59 | public listRemoteMethods(): Promise { 60 | return this.invoke("listLocalMethods"); 61 | } 62 | 63 | invoke(method: string, ...params: any[]): Promise { 64 | // TODO: change to something more unique (or check to see if id doesn't already exist in this.promiseCallbacks) 65 | const id = Math.random(); 66 | const promise = new Promise((resolve, reject) => { 67 | this.promiseCallbacks.set(id, { resolve: resolve, reject: reject }); 68 | }); 69 | 70 | this.sendRequest(id, method, params); 71 | return promise; 72 | } 73 | 74 | handleResponse(message: any): void { 75 | const promiseCallbacks: IPromiseCallbacks | undefined = this.promiseCallbacks.get(message.id); 76 | if (promiseCallbacks) { 77 | this.baseLogger.trace(`handleResponse: processing response for id: ${message.id} message success flag is: ${message.success}`); 78 | if (message.success) { 79 | promiseCallbacks.resolve(message.response); 80 | } else { 81 | this.baseLogger.warn(`handleResponse: Message id ${message.id} rejected, response: ${message.response}`); 82 | promiseCallbacks.reject(message.response); 83 | } 84 | this.promiseCallbacks.delete(message.id); 85 | } 86 | } 87 | 88 | async handleRequest(message: any): Promise { 89 | const method: IMethod | undefined = this.methods.get(message.method); 90 | this.baseLogger.trace(`handleRequest: processing request id: ${message.id} method: ${message.method} parameters: ${JSON.stringify(message.params)}`); 91 | if (method) { 92 | const func: Function = method.func; 93 | const thisArg: any = method.thisArg; 94 | try { 95 | let response: any = func.apply(thisArg, message.params); 96 | // if response is a promise, delay the response until the promise is fulfilled 97 | if (response && typeof response.then === "function") { 98 | response = await response; 99 | } 100 | this.sendResponse(message.id, response); 101 | } catch (err) { 102 | this.baseLogger.error(`handleRequest: Failed processing request ${message.command} id: ${message.id}`, { error: err }); 103 | this.sendResponse(message.id, err, false); 104 | } 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /src/rpc-extension-ws.ts: -------------------------------------------------------------------------------- 1 | import { RpcCommon, IPromiseCallbacks } from "./rpc-common"; 2 | import * as WebSocket from "ws"; 3 | import { IChildLogger } from "@vscode-logging/types"; 4 | import { noopLogger } from "./noop-logger"; 5 | 6 | export class RpcExtensionWebSockets extends RpcCommon { 7 | private static readonly className = "RpcExtensionWebSockets"; 8 | private readonly logger: IChildLogger; 9 | ws: WebSocket; 10 | 11 | constructor(ws: WebSocket, logger: IChildLogger = noopLogger) { 12 | super(logger.getChildLogger({ label: RpcExtensionWebSockets.className })); 13 | this.logger = logger.getChildLogger({ label: RpcExtensionWebSockets.className }); 14 | this.ws = ws; 15 | this.ws.on("message", message => { 16 | // assuming message is a stringified JSON 17 | const messageObject: any = JSON.parse(message as string); 18 | this.logger.debug(`Event Listener: Received event: ${message as string}`); 19 | switch (messageObject.command) { 20 | case "rpc-response": 21 | this.handleResponse(messageObject); 22 | break; 23 | case "rpc-request": 24 | this.handleRequest(messageObject); 25 | break; 26 | } 27 | }); 28 | } 29 | 30 | sendRequest(id: number, method: string, params?: any[]) { 31 | // consider cancelling the timer if the promise if fulfilled before timeout is reached 32 | setTimeout(() => { 33 | const promiseCallbacks: IPromiseCallbacks | undefined = this.promiseCallbacks.get(id); 34 | if (promiseCallbacks) { 35 | this.logger.warn(`sendRequest: Request ${id} method ${method} has timed out`); 36 | promiseCallbacks.reject("Request timed out"); 37 | this.promiseCallbacks.delete(id); 38 | } 39 | }, this.timeout); 40 | 41 | const requestObject: any = { 42 | command: "rpc-request", 43 | id: id, 44 | method: method, 45 | params: params 46 | }; 47 | 48 | this.ws.send(JSON.stringify(requestObject)); 49 | } 50 | 51 | sendResponse(id: number, response: any, success: boolean = true): void { 52 | const responseObject: any = { 53 | command: "rpc-response", 54 | id: id, 55 | response: response, 56 | success: success 57 | }; 58 | 59 | this.ws.send(JSON.stringify(responseObject)); 60 | } 61 | } -------------------------------------------------------------------------------- /src/rpc-extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { RpcCommon, IPromiseCallbacks } from "./rpc-common"; 3 | import { IChildLogger } from "@vscode-logging/types"; 4 | import { noopLogger } from "./noop-logger"; 5 | 6 | export class RpcExtension extends RpcCommon { 7 | private static readonly className = "RpcExtension"; 8 | private readonly logger: IChildLogger; 9 | webview: vscode.Webview; 10 | 11 | 12 | constructor(webview: vscode.Webview, logger: IChildLogger = noopLogger) { 13 | super(logger.getChildLogger({ label: RpcExtension.className })); 14 | this.logger = logger.getChildLogger({ label: RpcExtension.className }); 15 | this.webview = webview; 16 | this.webview.onDidReceiveMessage(message => { 17 | this.logger.debug(`Event Listener: Received event: ${JSON.stringify(message)}`); 18 | switch (message.command) { 19 | case "rpc-response": 20 | this.handleResponse(message); 21 | break; 22 | case "rpc-request": 23 | this.handleRequest(message); 24 | break; 25 | } 26 | }); 27 | } 28 | 29 | sendRequest(id: number, method: string, params?: any[]) { 30 | // consider cancelling the timer if the promise if fulfilled before timeout is reached 31 | setTimeout(() => { 32 | const promiseCallbacks: IPromiseCallbacks | undefined = this.promiseCallbacks.get(id); 33 | if (promiseCallbacks) { 34 | this.logger.warn(`sendRequest: Request ${id} method ${method} has timed out`); 35 | promiseCallbacks.reject("Request timed out"); 36 | this.promiseCallbacks.delete(id); 37 | } 38 | }, this.timeout); 39 | 40 | this.webview.postMessage({ 41 | command: "rpc-request", 42 | id: id, 43 | method: method, 44 | params: params 45 | }); 46 | } 47 | 48 | sendResponse(id: number, response: any, success: boolean = true): void { 49 | this.webview.postMessage({ 50 | command: "rpc-response", 51 | id: id, 52 | response: response, 53 | success: success 54 | }); 55 | } 56 | } -------------------------------------------------------------------------------- /src/test/logger.spec.ts: -------------------------------------------------------------------------------- 1 | import { IChildLogger } from "@vscode-logging/types"; 2 | import { noopLogger } from "../noop-logger"; 3 | import { IRpc } from "../rpc-common"; 4 | import { RpcMock } from "./rpc-mock"; 5 | 6 | const sum = (a: number, b: number): number => { 7 | return a + b; 8 | }; 9 | 10 | describe("Logger tests", () => { 11 | afterEach(() => { 12 | jest.clearAllMocks(); 13 | }); 14 | 15 | it("When logger is not passed noop is used", () => { 16 | const rpc1: IRpc = new RpcMock(); 17 | const rpc2: IRpc = new RpcMock(); 18 | (rpc1 as RpcMock).setPeer(rpc2 as RpcMock); 19 | (rpc2 as RpcMock).setPeer(rpc1 as RpcMock); 20 | const trace = jest.spyOn(noopLogger, "trace"); 21 | 22 | rpc1.registerMethod({ func: sum }); 23 | const param1: number = 1; 24 | const param2: number = 2; 25 | rpc2.invoke("sum", param1, param2).then((value) => { 26 | console.log(`sum is ${value}`); 27 | expect(value).toBe(param1 + param2); 28 | }); 29 | expect(trace).toHaveBeenCalledTimes(2); 30 | expect(trace).toHaveBeenCalledWith( 31 | expect.stringMatching( 32 | /handleRequest: processing request id: \d\.\d+ method: sum parameters: \[1,2\]/ 33 | ) 34 | ); 35 | expect(trace).toHaveBeenCalledWith( 36 | expect.stringMatching( 37 | /handleResponse: processing response for id: \d\.\d+ message success flag is: true/ 38 | ) 39 | ); 40 | }); 41 | 42 | it("When logger is passed it is used", () => { 43 | const CONSOLE_LOG = (msg: string, ...args: any[]): void => { console.log(msg, args); }; 44 | const customLogger: IChildLogger = { 45 | fatal: CONSOLE_LOG, 46 | error: CONSOLE_LOG, 47 | warn: CONSOLE_LOG, 48 | info: CONSOLE_LOG, 49 | debug: CONSOLE_LOG, 50 | trace: CONSOLE_LOG, 51 | getChildLogger: function () { 52 | return customLogger; 53 | }, 54 | }; 55 | const rpc1: IRpc = new RpcMock(customLogger); 56 | const rpc2: IRpc = new RpcMock(customLogger); 57 | (rpc1 as RpcMock).setPeer(rpc2 as RpcMock); 58 | (rpc2 as RpcMock).setPeer(rpc1 as RpcMock); 59 | 60 | const trace = jest.spyOn(customLogger, "trace"); 61 | const warn = jest.spyOn(customLogger, "warn"); 62 | const error = jest.spyOn(customLogger, "error"); 63 | 64 | const bad = (a: number, b: number) => { 65 | if(typeof a === "number" && typeof b ==="number") { 66 | throw "bad parameter type"; 67 | } 68 | 69 | }; 70 | 71 | rpc1.registerMethod({ func: bad }); 72 | const param1: number = 1; 73 | const param2: number = 0; 74 | rpc2.invoke("bad", ...[param1, param2]).then((value) => { 75 | console.log(`result is is ${value}`); 76 | expect(value).toBe(param1 + param2); 77 | }).catch(e => { 78 | expect(e).toBe("bad parameter type"); 79 | }); 80 | expect(trace).toHaveBeenCalledTimes(2); 81 | 82 | expect(trace).toHaveBeenCalledWith( 83 | expect.stringMatching( 84 | /handleRequest: processing request id: \d\.\d+ method: bad parameters: \[1,0\]/ 85 | ) 86 | ); 87 | 88 | expect(trace).toHaveBeenCalledWith( 89 | expect.stringMatching( 90 | /handleResponse: processing response for id: \d\.\d+ message success flag is: false/ 91 | ) 92 | ); 93 | 94 | expect(error).toHaveBeenCalledWith(expect.stringMatching(/handleRequest: Failed processing request rpc-request id: \d\.\d+/), {"error": "bad parameter type"}); 95 | 96 | expect(warn).toHaveBeenCalledWith(expect.stringMatching(/handleResponse: Message id \d\.\d+ rejected, response: bad parameter type/)); 97 | 98 | }); 99 | }); 100 | -------------------------------------------------------------------------------- /src/test/rpc-mock.ts: -------------------------------------------------------------------------------- 1 | // must specify ".js" for import in browser to locate rpc-common.js 2 | // see: https://github.com/microsoft/TypeScript/issues/16577#issuecomment-343610106 3 | 4 | import { IChildLogger } from "@vscode-logging/types"; 5 | import { noopLogger } from "../noop-logger"; 6 | import { RpcCommon, IPromiseCallbacks } from "../rpc-common"; 7 | 8 | export class RpcMock extends RpcCommon { 9 | peer: RpcMock | undefined; 10 | 11 | constructor(logger: IChildLogger = noopLogger) { 12 | super(logger); 13 | } 14 | 15 | setPeer(peer: RpcMock) { 16 | this.peer = peer; 17 | } 18 | 19 | sendRequest(id: number, method: string, params?: any[]) { 20 | // TODO: consider cancelling the timer if the promise if fulfilled before timeout is reached 21 | setTimeout(() => { 22 | const promiseCallbacks: IPromiseCallbacks | undefined = this.promiseCallbacks.get(id); 23 | if (promiseCallbacks) { 24 | promiseCallbacks.reject("Request timed out"); 25 | this.promiseCallbacks.delete(id); 26 | } 27 | }, this.timeout); 28 | 29 | // TODO: find an alternative to appending vscode to the global scope (perhaps providing vscode as parameter to constructor) 30 | const requestBody: any = { 31 | command: "rpc-request", 32 | id: id, 33 | method: method, 34 | params: params 35 | }; 36 | 37 | this.send(JSON.stringify(requestBody)); 38 | } 39 | 40 | sendResponse(id: number, response: any, success: boolean = true): void { 41 | const responseBody: any = { 42 | command: "rpc-response", 43 | id: id, 44 | response: response, 45 | success: success 46 | }; 47 | 48 | this.send(JSON.stringify(responseBody)); 49 | } 50 | 51 | send(message: string) { 52 | if (this.peer) { 53 | this.peer.receive(message); 54 | } 55 | } 56 | 57 | receive(message: string) { 58 | const messageObject: any = JSON.parse(message); 59 | switch (messageObject.command) { 60 | case "rpc-response": 61 | this.handleResponse(messageObject); 62 | break; 63 | case "rpc-request": 64 | this.handleRequest(messageObject); 65 | break; 66 | } 67 | 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/test/rpc.test.ts: -------------------------------------------------------------------------------- 1 | // import * as jest from "jest"; 2 | import { RpcMock } from "./rpc-mock"; 3 | import { IRpc } from "../rpc-common"; 4 | import { noopLogger } from "../noop-logger"; 5 | 6 | const mock1: IRpc = new RpcMock(); 7 | const mock2: IRpc = new RpcMock(); 8 | (mock1 as RpcMock).setPeer(mock2 as RpcMock); 9 | (mock2 as RpcMock).setPeer(mock1 as RpcMock); 10 | 11 | const longFunc = (): Promise => { 12 | return new Promise((resolve) => { 13 | setTimeout(() => { 14 | resolve("done"); 15 | }, 500); 16 | }); 17 | }; 18 | 19 | const noParams = (): string => { 20 | return "no params"; 21 | }; 22 | 23 | const badFunc = (): void => { 24 | throw("bad"); 25 | }; 26 | 27 | const sum = (a: number, b: number): number => { 28 | return a + b; 29 | }; 30 | 31 | test("One large test", () => { 32 | mock1.registerMethod({func: sum}); 33 | const param1: number = 1; 34 | const param2: number = 2; 35 | mock2.invoke("sum", param1, param2).then((value) => { 36 | console.log(`sum is ${value}`); 37 | expect(value).toBe(param1 + param2); 38 | }); 39 | 40 | let localMethodsMock1: string[] = mock1.listLocalMethods(); 41 | expect(localMethodsMock1.length).toBe(2); 42 | expect(localMethodsMock1[1]).toBe("sum"); 43 | 44 | mock2.listRemoteMethods().then((value) => { 45 | expect(value.length).toBe(2); 46 | expect(value[1]).toBe("sum"); 47 | }); 48 | 49 | // TODO: call method that throws exception 50 | mock2.invoke("sumx").then((value) => { 51 | expect(value).toBe(param1 + param2); 52 | }); 53 | 54 | mock1.unregisterMethod({func: sum}); 55 | localMethodsMock1 = mock1.listLocalMethods(); 56 | expect(localMethodsMock1.length).toBe(1); 57 | 58 | mock1.registerMethod({func: noParams}); 59 | mock2.invoke("noParams").then((value) => { 60 | expect(value).toBe("no params"); 61 | }); 62 | 63 | mock1.registerMethod({func: badFunc}); 64 | return mock2.invoke("badFunc").catch((reason) => { 65 | expect(reason).toBe("bad"); 66 | }); 67 | }); 68 | 69 | test("Delayed test", () => { 70 | mock2.setResponseTimeout(0); 71 | mock1.registerMethod({func: longFunc}); 72 | 73 | return mock2.invoke("longFunc").catch((reason) => { 74 | expect(reason).toBe("Request timed out"); 75 | }); 76 | }); 77 | 78 | test("Get child logger returns noopLogger", () => { 79 | const logger = noopLogger; 80 | expect(logger.getChildLogger()).toEqual(logger); 81 | }); 82 | -------------------------------------------------------------------------------- /tsconfig.browser.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "target": "es6", 5 | "outDir": "out.browser", 6 | "lib": ["es6", "dom"], 7 | "sourceMap": true, 8 | "rootDir": "src", 9 | "strict": true, 10 | "declaration": true 11 | }, 12 | "exclude": ["node_modules", "src/rpc-extension.ts", "src/rpc-extension-ws.ts", "example", "example-ws"] 13 | } -------------------------------------------------------------------------------- /tsconfig.ext.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out.ext", 6 | "lib": ["es6"], 7 | "sourceMap": true, 8 | "rootDir": "src", 9 | "strict": true, 10 | "declaration": true 11 | }, 12 | "exclude": ["node_modules", "src/rpc-browser.ts", "src/rpc-browser-ws.ts", "example", "example-ws"] 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out.test", 6 | "lib": ["es6"], 7 | "sourceMap": true, 8 | "rootDir": "src", 9 | "strict": true 10 | }, 11 | "exclude": ["node_modules", "example", "example-ws"], 12 | "include": ["src/rpc-common.ts", "src/test/*.ts"] 13 | } 14 | --------------------------------------------------------------------------------