From 02e73634d50e32b3e1d6fbff8c8cee6fc1b23d5f Mon Sep 17 00:00:00 2001 From: Myles Scolnick Date: Mon, 11 Sep 2023 09:22:26 -0400 Subject: [PATCH] Initial commit --- .eslintrc.json | 20 + .github/renovate.json | 30 + .github/workflows/ci.yml | 60 + .github/workflows/release.yml | 25 + .gitignore | 13 + .prettierrc.json | 1 + .vscode/extensions.json | 3 + .vscode/launch.json | 24 + .vscodeignore | 8 + CONTRIBUTING.md | 12 + LICENSE | 21 + README.md | 23 + images/marimo.png | Bin 0 -> 26027 bytes package.json | 178 +++ pnpm-lock.yaml | 2825 +++++++++++++++++++++++++++++++++ resources/icon.svg | 20 + src/explorer/explorer.ts | 106 ++ src/extension.ts | 65 + src/launcher/config.ts | 32 + src/launcher/controller.ts | 206 +++ src/launcher/panel.ts | 69 + src/launcher/show-commands.ts | 89 ++ src/launcher/start.ts | 48 + src/launcher/status-bar.ts | 60 + src/launcher/terminal.ts | 119 ++ src/launcher/utils.ts | 84 + src/logger.ts | 24 + tsconfig.json | 18 + tsup.config.ts | 9 + 29 files changed, 4192 insertions(+) create mode 100644 .eslintrc.json create mode 100644 .github/renovate.json create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 .prettierrc.json create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 .vscodeignore create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 images/marimo.png create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 resources/icon.svg create mode 100644 src/explorer/explorer.ts create mode 100644 src/extension.ts create mode 100644 src/launcher/config.ts create mode 100644 src/launcher/controller.ts create mode 100644 src/launcher/panel.ts create mode 100644 src/launcher/show-commands.ts create mode 100644 src/launcher/start.ts create mode 100644 src/launcher/status-bar.ts create mode 100644 src/launcher/terminal.ts create mode 100644 src/launcher/utils.ts create mode 100644 src/logger.ts create mode 100644 tsconfig.json create mode 100644 tsup.config.ts diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..a622533 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,20 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module" + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:unicorn/recommended", + "prettier" + ], + "plugins": ["@typescript-eslint"], + "ignorePatterns": ["out", "dist", "**/*.d.ts"], + "rules": { + "unicorn/prevent-abbreviations": "off", + "unicorn/no-useless-undefined": "off" + } +} diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..4d64e2d --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,30 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["config:base", "schedule:weekly"], + "labels": ["dependencies"], + "pin": false, + "rangeStrategy": "bump", + "packageRules": [ + { + "depTypeList": ["peerDependencies"], + "enabled": false + }, + { + "packageNames": ["node"], + "enabled": false + }, + { + "matchUpdateTypes": ["minor", "patch"], + "groupName": "all non-major dependencies", + "groupSlug": "all-minor-patch", + "excludePackagePatterns": [".*eslint.*"], + "excludePackageNames": ["typescript", "@types/vscode", "vscode"] + }, + { + "packagePatterns": [".*eslint.*"], + "groupName": "all eslint dependencies", + "groupSlug": "all-eslint", + "matchUpdateTypes": ["minor", "patch", "major"] + } + ] +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..cf58e00 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,60 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: ๐Ÿ›‘ Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.11.0 + + - name: โฌ‡๏ธ Checkout repo + uses: actions/checkout@v3 + + - name: โŽ” Setup pnpm + uses: pnpm/action-setup@v2 + with: + version: 8 + + - name: โŽ” Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: pnpm + + - name: ๐Ÿ“ฅ Install dependencies + run: pnpm install + + - name: ๐Ÿงน Lint + run: pnpm lint + + typecheck: + runs-on: ubuntu-latest + steps: + - name: ๐Ÿ›‘ Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.11.0 + + - name: โฌ‡๏ธ Checkout repo + uses: actions/checkout@v3 + + - name: โŽ” Setup pnpm + uses: pnpm/action-setup@v2 + with: + version: 8 + + - name: โŽ” Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: pnpm + + - name: ๐Ÿ“ฅ Install dependencies + run: pnpm install + + - name: สฆ Typecheck + run: pnpm typecheck diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..9032e7d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,25 @@ +name: Release + +permissions: + contents: write + +on: + push: + tags: + - "v*" + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - uses: actions/setup-node@v3 + with: + node-version: 18.x + + - run: npx changelogithub + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c410028 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.cache +.DS_Store +.idea +*.log +*.tgz +*.vsix +coverage +dist +lib-cov +logs +node_modules +temp +!.vscode diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1 @@ +{} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..940260d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["dbaeumer.vscode-eslint"] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..10e3522 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,24 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Run Extension", + "type": "extensionHost", + "request": "launch", + "args": ["--extensionDevelopmentPath=${workspaceFolder}"], + "outFiles": ["${workspaceFolder}/out/**/*.js"], + "preLaunchTask": "${defaultBuildTask}" + }, + { + "name": "Extension Tests", + "type": "extensionHost", + "request": "launch", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}", + "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" + ], + "outFiles": ["${workspaceFolder}/out/test/**/*.js"], + "preLaunchTask": "${defaultBuildTask}" + } + ] +} diff --git a/.vscodeignore b/.vscodeignore new file mode 100644 index 0000000..50cb928 --- /dev/null +++ b/.vscodeignore @@ -0,0 +1,8 @@ +.github +.gitignore +.vscode +**/.eslintrc.json +**/*.map +**/*.ts +**/tsconfig.json +src diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..14ea38f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,12 @@ +# Contributing + +## Development + +- Run `pnpm install` in the root directory to install dependencies. +- Run `pnpm dev` to start the compiler in watch mode. +- Press `F5` to open a new window with your extension loaded. + +### Make changes + +- Relaunch the extension from the debug toolbar after changing code in `src/extension.ts`. +- `Ctrl+R` or `Cmd+R` on Mac will reload the extension with your changes. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ab7f4c9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 marimo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f830023 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# vscode-marimo + +Visual Studio Marketplace Version + +Run marimo, directly from VSCode. + +Note: This extension requires marimo to be installed on your system: `pip install marimo`. + +Check out the marimo documentation at . + +## Features + +- Launch marimo from VSCode, in both "edit mode" and "run mode". +- View the terminal output of marimo directly in VSCode. +- View the marimo browser window directly in VSCode or in your default browser. + +## Extension Settings + +You can configure the extension using the following settings: + +- `marimo.browserType`: Browser to open marimo app ('system' or 'embedded', default: 'embedded') +- `marimo.port`: Default port for marimo server (default: 2718) +- `marimo.showTerminal`: Open the terminal when the server starts (default: false) diff --git a/images/marimo.png b/images/marimo.png new file mode 100644 index 0000000000000000000000000000000000000000..a0b41c89b8c619dd8ab992b03187753763021d2c GIT binary patch literal 26027 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.10.0" } + dev: true + + /@babel/code-frame@7.22.13: + resolution: + { + integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==, + } + engines: { node: ">=6.9.0" } + dependencies: + "@babel/highlight": 7.22.13 + chalk: 2.4.2 + dev: true + + /@babel/helper-validator-identifier@7.22.15: + resolution: + { + integrity: sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==, + } + engines: { node: ">=6.9.0" } + dev: true + + /@babel/highlight@7.22.13: + resolution: + { + integrity: sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==, + } + engines: { node: ">=6.9.0" } + dependencies: + "@babel/helper-validator-identifier": 7.22.15 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: true + + /@esbuild/android-arm64@0.18.20: + resolution: + { + integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==, + } + engines: { node: ">=12" } + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.18.20: + resolution: + { + integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==, + } + engines: { node: ">=12" } + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.18.20: + resolution: + { + integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==, + } + engines: { node: ">=12" } + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.18.20: + resolution: + { + integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==, + } + engines: { node: ">=12" } + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.18.20: + resolution: + { + integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==, + } + engines: { node: ">=12" } + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.18.20: + resolution: + { + integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==, + } + engines: { node: ">=12" } + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.18.20: + resolution: + { + integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==, + } + engines: { node: ">=12" } + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.18.20: + resolution: + { + integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==, + } + engines: { node: ">=12" } + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.18.20: + resolution: + { + integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==, + } + engines: { node: ">=12" } + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.18.20: + resolution: + { + integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==, + } + engines: { node: ">=12" } + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.18.20: + resolution: + { + integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==, + } + engines: { node: ">=12" } + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.18.20: + resolution: + { + integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==, + } + engines: { node: ">=12" } + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.18.20: + resolution: + { + integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==, + } + engines: { node: ">=12" } + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.18.20: + resolution: + { + integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==, + } + engines: { node: ">=12" } + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.18.20: + resolution: + { + integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==, + } + engines: { node: ">=12" } + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.18.20: + resolution: + { + integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==, + } + engines: { node: ">=12" } + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.18.20: + resolution: + { + integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==, + } + engines: { node: ">=12" } + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.18.20: + resolution: + { + integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==, + } + engines: { node: ">=12" } + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.18.20: + resolution: + { + integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==, + } + engines: { node: ">=12" } + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.18.20: + resolution: + { + integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==, + } + engines: { node: ">=12" } + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.18.20: + resolution: + { + integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==, + } + engines: { node: ">=12" } + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.18.20: + resolution: + { + integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==, + } + engines: { node: ">=12" } + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@eslint-community/eslint-utils@4.4.0(eslint@8.49.0): + resolution: + { + integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.49.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/regexpp@4.8.0: + resolution: + { + integrity: sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==, + } + engines: { node: ^12.0.0 || ^14.0.0 || >=16.0.0 } + dev: true + + /@eslint/eslintrc@2.1.2: + resolution: + { + integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.6.1 + globals: 13.21.0 + ignore: 5.2.4 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/js@8.49.0: + resolution: + { + integrity: sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + dev: true + + /@humanwhocodes/config-array@0.11.11: + resolution: + { + integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==, + } + engines: { node: ">=10.10.0" } + dependencies: + "@humanwhocodes/object-schema": 1.2.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/module-importer@1.0.1: + resolution: + { + integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==, + } + engines: { node: ">=12.22" } + dev: true + + /@humanwhocodes/object-schema@1.2.1: + resolution: + { + integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==, + } + dev: true + + /@jridgewell/gen-mapping@0.3.3: + resolution: + { + integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==, + } + engines: { node: ">=6.0.0" } + dependencies: + "@jridgewell/set-array": 1.1.2 + "@jridgewell/sourcemap-codec": 1.4.15 + "@jridgewell/trace-mapping": 0.3.19 + dev: true + + /@jridgewell/resolve-uri@3.1.1: + resolution: + { + integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==, + } + engines: { node: ">=6.0.0" } + dev: true + + /@jridgewell/set-array@1.1.2: + resolution: + { + integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==, + } + engines: { node: ">=6.0.0" } + dev: true + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: + { + integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==, + } + dev: true + + /@jridgewell/trace-mapping@0.3.19: + resolution: + { + integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==, + } + dependencies: + "@jridgewell/resolve-uri": 3.1.1 + "@jridgewell/sourcemap-codec": 1.4.15 + dev: true + + /@nodelib/fs.scandir@2.1.5: + resolution: + { + integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==, + } + engines: { node: ">= 8" } + dependencies: + "@nodelib/fs.stat": 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: + { + integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==, + } + engines: { node: ">= 8" } + dev: true + + /@nodelib/fs.walk@1.2.8: + resolution: + { + integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==, + } + engines: { node: ">= 8" } + dependencies: + "@nodelib/fs.scandir": 2.1.5 + fastq: 1.15.0 + dev: true + + /@tootallnate/once@1.1.2: + resolution: + { + integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==, + } + engines: { node: ">= 6" } + dev: true + + /@types/json-schema@7.0.12: + resolution: + { + integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==, + } + dev: true + + /@types/node@20.6.0: + resolution: + { + integrity: sha512-najjVq5KN2vsH2U/xyh2opaSEz6cZMR2SetLIlxlj08nOcmPOemJmUK2o4kUzfLqfrWE0PIrNeE16XhYDd3nqg==, + } + dev: true + + /@types/normalize-package-data@2.4.1: + resolution: + { + integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==, + } + dev: true + + /@types/semver@7.5.1: + resolution: + { + integrity: sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==, + } + dev: true + + /@types/vscode@1.82.0: + resolution: + { + integrity: sha512-VSHV+VnpF8DEm8LNrn8OJ8VuUNcBzN3tMvKrNpbhhfuVjFm82+6v44AbDhLvVFgCzn6vs94EJNTp7w8S6+Q1Rw==, + } + dev: true + + /@typescript-eslint/eslint-plugin@6.6.0(@typescript-eslint/parser@6.6.0)(eslint@8.49.0)(typescript@5.2.2): + resolution: + { + integrity: sha512-CW9YDGTQnNYMIo5lMeuiIG08p4E0cXrXTbcZ2saT/ETE7dWUrNxlijsQeU04qAAKkILiLzdQz+cGFxCJjaZUmA==, + } + engines: { node: ^16.0.0 || >=18.0.0 } + peerDependencies: + "@typescript-eslint/parser": ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + typescript: "*" + peerDependenciesMeta: + typescript: + optional: true + dependencies: + "@eslint-community/regexpp": 4.8.0 + "@typescript-eslint/parser": 6.6.0(eslint@8.49.0)(typescript@5.2.2) + "@typescript-eslint/scope-manager": 6.6.0 + "@typescript-eslint/type-utils": 6.6.0(eslint@8.49.0)(typescript@5.2.2) + "@typescript-eslint/utils": 6.6.0(eslint@8.49.0)(typescript@5.2.2) + "@typescript-eslint/visitor-keys": 6.6.0 + debug: 4.3.4 + eslint: 8.49.0 + graphemer: 1.4.0 + ignore: 5.2.4 + natural-compare: 1.4.0 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@6.6.0(eslint@8.49.0)(typescript@5.2.2): + resolution: + { + integrity: sha512-setq5aJgUwtzGrhW177/i+DMLqBaJbdwGj2CPIVFFLE0NCliy5ujIdLHd2D1ysmlmsjdL2GWW+hR85neEfc12w==, + } + engines: { node: ^16.0.0 || >=18.0.0 } + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: "*" + peerDependenciesMeta: + typescript: + optional: true + dependencies: + "@typescript-eslint/scope-manager": 6.6.0 + "@typescript-eslint/types": 6.6.0 + "@typescript-eslint/typescript-estree": 6.6.0(typescript@5.2.2) + "@typescript-eslint/visitor-keys": 6.6.0 + debug: 4.3.4 + eslint: 8.49.0 + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/scope-manager@6.6.0: + resolution: + { + integrity: sha512-pT08u5W/GT4KjPUmEtc2kSYvrH8x89cVzkA0Sy2aaOUIw6YxOIjA8ilwLr/1fLjOedX1QAuBpG9XggWqIIfERw==, + } + engines: { node: ^16.0.0 || >=18.0.0 } + dependencies: + "@typescript-eslint/types": 6.6.0 + "@typescript-eslint/visitor-keys": 6.6.0 + dev: true + + /@typescript-eslint/type-utils@6.6.0(eslint@8.49.0)(typescript@5.2.2): + resolution: + { + integrity: sha512-8m16fwAcEnQc69IpeDyokNO+D5spo0w1jepWWY2Q6y5ZKNuj5EhVQXjtVAeDDqvW6Yg7dhclbsz6rTtOvcwpHg==, + } + engines: { node: ^16.0.0 || >=18.0.0 } + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: "*" + peerDependenciesMeta: + typescript: + optional: true + dependencies: + "@typescript-eslint/typescript-estree": 6.6.0(typescript@5.2.2) + "@typescript-eslint/utils": 6.6.0(eslint@8.49.0)(typescript@5.2.2) + debug: 4.3.4 + eslint: 8.49.0 + ts-api-utils: 1.0.3(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types@6.6.0: + resolution: + { + integrity: sha512-CB6QpJQ6BAHlJXdwUmiaXDBmTqIE2bzGTDLADgvqtHWuhfNP3rAOK7kAgRMAET5rDRr9Utt+qAzRBdu3AhR3sg==, + } + engines: { node: ^16.0.0 || >=18.0.0 } + dev: true + + /@typescript-eslint/typescript-estree@6.6.0(typescript@5.2.2): + resolution: + { + integrity: sha512-hMcTQ6Al8MP2E6JKBAaSxSVw5bDhdmbCEhGW/V8QXkb9oNsFkA4SBuOMYVPxD3jbtQ4R/vSODBsr76R6fP3tbA==, + } + engines: { node: ^16.0.0 || >=18.0.0 } + peerDependencies: + typescript: "*" + peerDependenciesMeta: + typescript: + optional: true + dependencies: + "@typescript-eslint/types": 6.6.0 + "@typescript-eslint/visitor-keys": 6.6.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@6.6.0(eslint@8.49.0)(typescript@5.2.2): + resolution: + { + integrity: sha512-mPHFoNa2bPIWWglWYdR0QfY9GN0CfvvXX1Sv6DlSTive3jlMTUy+an67//Gysc+0Me9pjitrq0LJp0nGtLgftw==, + } + engines: { node: ^16.0.0 || >=18.0.0 } + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + "@eslint-community/eslint-utils": 4.4.0(eslint@8.49.0) + "@types/json-schema": 7.0.12 + "@types/semver": 7.5.1 + "@typescript-eslint/scope-manager": 6.6.0 + "@typescript-eslint/types": 6.6.0 + "@typescript-eslint/typescript-estree": 6.6.0(typescript@5.2.2) + eslint: 8.49.0 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys@6.6.0: + resolution: + { + integrity: sha512-L61uJT26cMOfFQ+lMZKoJNbAEckLe539VhTxiGHrWl5XSKQgA0RTBZJW2HFPy5T0ZvPVSD93QsrTKDkfNwJGyQ==, + } + engines: { node: ^16.0.0 || >=18.0.0 } + dependencies: + "@typescript-eslint/types": 6.6.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@vscode/test-electron@2.3.4: + resolution: + { + integrity: sha512-eWzIqXMhvlcoXfEFNWrVu/yYT5w6De+WZXR/bafUQhAp8+8GkQo95Oe14phwiRUPv8L+geAKl/QM2+PoT3YW3g==, + } + engines: { node: ">=16" } + dependencies: + http-proxy-agent: 4.0.1 + https-proxy-agent: 5.0.1 + jszip: 3.10.1 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /acorn-jsx@5.3.2(acorn@8.10.0): + resolution: + { + integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, + } + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.10.0 + dev: true + + /acorn@8.10.0: + resolution: + { + integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==, + } + engines: { node: ">=0.4.0" } + hasBin: true + dev: true + + /agent-base@6.0.2: + resolution: + { + integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==, + } + engines: { node: ">= 6.0.0" } + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /ajv@6.12.6: + resolution: + { + integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==, + } + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + dev: true + + /ansi-regex@5.0.1: + resolution: + { + integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, + } + engines: { node: ">=8" } + dev: true + + /ansi-styles@3.2.1: + resolution: + { + integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==, + } + engines: { node: ">=4" } + dependencies: + color-convert: 1.9.3 + dev: true + + /ansi-styles@4.3.0: + resolution: + { + integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, + } + engines: { node: ">=8" } + dependencies: + color-convert: 2.0.1 + dev: true + + /any-promise@1.3.0: + resolution: + { + integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==, + } + dev: true + + /anymatch@3.1.3: + resolution: + { + integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==, + } + engines: { node: ">= 8" } + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + + /argparse@2.0.1: + resolution: + { + integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, + } + dev: true + + /array-union@2.1.0: + resolution: + { + integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==, + } + engines: { node: ">=8" } + dev: true + + /balanced-match@1.0.2: + resolution: + { + integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, + } + dev: true + + /binary-extensions@2.2.0: + resolution: + { + integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==, + } + engines: { node: ">=8" } + dev: true + + /brace-expansion@1.1.11: + resolution: + { + integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==, + } + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /braces@3.0.2: + resolution: + { + integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==, + } + engines: { node: ">=8" } + dependencies: + fill-range: 7.0.1 + dev: true + + /builtin-modules@3.3.0: + resolution: + { + integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==, + } + engines: { node: ">=6" } + dev: true + + /bundle-require@4.0.1(esbuild@0.18.20): + resolution: + { + integrity: sha512-9NQkRHlNdNpDBGmLpngF3EFDcwodhMUuLz9PaWYciVcQF9SE4LFjM2DB/xV1Li5JiuDMv7ZUWuC3rGbqR0MAXQ==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + peerDependencies: + esbuild: ">=0.17" + dependencies: + esbuild: 0.18.20 + load-tsconfig: 0.2.5 + dev: true + + /cac@6.7.14: + resolution: + { + integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==, + } + engines: { node: ">=8" } + dev: true + + /callsites@3.1.0: + resolution: + { + integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, + } + engines: { node: ">=6" } + dev: true + + /chalk@2.4.2: + resolution: + { + integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==, + } + engines: { node: ">=4" } + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: true + + /chalk@4.1.2: + resolution: + { + integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, + } + engines: { node: ">=10" } + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /chokidar@3.5.3: + resolution: + { + integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==, + } + engines: { node: ">= 8.10.0" } + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /ci-info@3.8.0: + resolution: + { + integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==, + } + engines: { node: ">=8" } + dev: true + + /clean-regexp@1.0.0: + resolution: + { + integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==, + } + engines: { node: ">=4" } + dependencies: + escape-string-regexp: 1.0.5 + dev: true + + /color-convert@1.9.3: + resolution: + { + integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==, + } + dependencies: + color-name: 1.1.3 + dev: true + + /color-convert@2.0.1: + resolution: + { + integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, + } + engines: { node: ">=7.0.0" } + dependencies: + color-name: 1.1.4 + dev: true + + /color-name@1.1.3: + resolution: + { + integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==, + } + dev: true + + /color-name@1.1.4: + resolution: + { + integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, + } + dev: true + + /commander@4.1.1: + resolution: + { + integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==, + } + engines: { node: ">= 6" } + dev: true + + /concat-map@0.0.1: + resolution: { integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= } + dev: true + + /core-util-is@1.0.3: + resolution: + { + integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==, + } + dev: true + + /cross-spawn@7.0.3: + resolution: + { + integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==, + } + engines: { node: ">= 8" } + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /debug@4.3.4: + resolution: + { + integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==, + } + engines: { node: ">=6.0" } + peerDependencies: + supports-color: "*" + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + + /deep-is@0.1.4: + resolution: + { + integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, + } + dev: true + + /dir-glob@3.0.1: + resolution: + { + integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==, + } + engines: { node: ">=8" } + dependencies: + path-type: 4.0.0 + dev: true + + /doctrine@3.0.0: + resolution: + { + integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==, + } + engines: { node: ">=6.0.0" } + dependencies: + esutils: 2.0.3 + dev: true + + /error-ex@1.3.2: + resolution: + { + integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==, + } + dependencies: + is-arrayish: 0.2.1 + dev: true + + /esbuild@0.18.20: + resolution: + { + integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==, + } + engines: { node: ">=12" } + hasBin: true + requiresBuild: true + optionalDependencies: + "@esbuild/android-arm": 0.18.20 + "@esbuild/android-arm64": 0.18.20 + "@esbuild/android-x64": 0.18.20 + "@esbuild/darwin-arm64": 0.18.20 + "@esbuild/darwin-x64": 0.18.20 + "@esbuild/freebsd-arm64": 0.18.20 + "@esbuild/freebsd-x64": 0.18.20 + "@esbuild/linux-arm": 0.18.20 + "@esbuild/linux-arm64": 0.18.20 + "@esbuild/linux-ia32": 0.18.20 + "@esbuild/linux-loong64": 0.18.20 + "@esbuild/linux-mips64el": 0.18.20 + "@esbuild/linux-ppc64": 0.18.20 + "@esbuild/linux-riscv64": 0.18.20 + "@esbuild/linux-s390x": 0.18.20 + "@esbuild/linux-x64": 0.18.20 + "@esbuild/netbsd-x64": 0.18.20 + "@esbuild/openbsd-x64": 0.18.20 + "@esbuild/sunos-x64": 0.18.20 + "@esbuild/win32-arm64": 0.18.20 + "@esbuild/win32-ia32": 0.18.20 + "@esbuild/win32-x64": 0.18.20 + dev: true + + /escape-string-regexp@1.0.5: + resolution: + { + integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==, + } + engines: { node: ">=0.8.0" } + dev: true + + /escape-string-regexp@4.0.0: + resolution: + { + integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==, + } + engines: { node: ">=10" } + dev: true + + /eslint-config-prettier@9.0.0(eslint@8.49.0): + resolution: + { + integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==, + } + hasBin: true + peerDependencies: + eslint: ">=7.0.0" + dependencies: + eslint: 8.49.0 + dev: true + + /eslint-plugin-unicorn@48.0.1(eslint@8.49.0): + resolution: + { + integrity: sha512-FW+4r20myG/DqFcCSzoumaddKBicIPeFnTrifon2mWIzlfyvzwyqZjqVP7m4Cqr/ZYisS2aiLghkUWaPg6vtCw==, + } + engines: { node: ">=16" } + peerDependencies: + eslint: ">=8.44.0" + dependencies: + "@babel/helper-validator-identifier": 7.22.15 + "@eslint-community/eslint-utils": 4.4.0(eslint@8.49.0) + ci-info: 3.8.0 + clean-regexp: 1.0.0 + eslint: 8.49.0 + esquery: 1.5.0 + indent-string: 4.0.0 + is-builtin-module: 3.2.1 + jsesc: 3.0.2 + lodash: 4.17.21 + pluralize: 8.0.0 + read-pkg-up: 7.0.1 + regexp-tree: 0.1.27 + regjsparser: 0.10.0 + semver: 7.5.4 + strip-indent: 3.0.0 + dev: true + + /eslint-scope@7.2.2: + resolution: + { + integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-visitor-keys@3.4.3: + resolution: + { + integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + dev: true + + /eslint@8.49.0: + resolution: + { + integrity: sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + hasBin: true + dependencies: + "@eslint-community/eslint-utils": 4.4.0(eslint@8.49.0) + "@eslint-community/regexpp": 4.8.0 + "@eslint/eslintrc": 2.1.2 + "@eslint/js": 8.49.0 + "@humanwhocodes/config-array": 0.11.11 + "@humanwhocodes/module-importer": 1.0.1 + "@nodelib/fs.walk": 1.2.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.21.0 + graphemer: 1.4.0 + ignore: 5.2.4 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /espree@9.6.1: + resolution: + { + integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + dependencies: + acorn: 8.10.0 + acorn-jsx: 5.3.2(acorn@8.10.0) + eslint-visitor-keys: 3.4.3 + dev: true + + /esquery@1.5.0: + resolution: + { + integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==, + } + engines: { node: ">=0.10" } + dependencies: + estraverse: 5.3.0 + dev: true + + /esrecurse@4.3.0: + resolution: + { + integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==, + } + engines: { node: ">=4.0" } + dependencies: + estraverse: 5.3.0 + dev: true + + /estraverse@5.3.0: + resolution: + { + integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==, + } + engines: { node: ">=4.0" } + dev: true + + /esutils@2.0.3: + resolution: + { + integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==, + } + engines: { node: ">=0.10.0" } + dev: true + + /execa@5.1.1: + resolution: + { + integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==, + } + engines: { node: ">=10" } + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + + /fast-deep-equal@3.1.3: + resolution: + { + integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, + } + dev: true + + /fast-glob@3.3.1: + resolution: + { + integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==, + } + engines: { node: ">=8.6.0" } + dependencies: + "@nodelib/fs.stat": 2.0.5 + "@nodelib/fs.walk": 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + + /fast-json-stable-stringify@2.1.0: + resolution: + { + integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==, + } + dev: true + + /fast-levenshtein@2.0.6: + resolution: + { + integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, + } + dev: true + + /fastq@1.15.0: + resolution: + { + integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==, + } + dependencies: + reusify: 1.0.4 + dev: true + + /file-entry-cache@6.0.1: + resolution: + { + integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==, + } + engines: { node: ^10.12.0 || >=12.0.0 } + dependencies: + flat-cache: 3.1.0 + dev: true + + /fill-range@7.0.1: + resolution: + { + integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==, + } + engines: { node: ">=8" } + dependencies: + to-regex-range: 5.0.1 + dev: true + + /find-up@4.1.0: + resolution: + { + integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==, + } + engines: { node: ">=8" } + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + dev: true + + /find-up@5.0.0: + resolution: + { + integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==, + } + engines: { node: ">=10" } + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + + /flat-cache@3.1.0: + resolution: + { + integrity: sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==, + } + engines: { node: ">=12.0.0" } + dependencies: + flatted: 3.2.7 + keyv: 4.5.3 + rimraf: 3.0.2 + dev: true + + /flatted@3.2.7: + resolution: + { + integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==, + } + dev: true + + /fs.realpath@1.0.0: + resolution: + { + integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==, + } + dev: true + + /fsevents@2.3.3: + resolution: + { + integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, + } + engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.1: + resolution: + { + integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==, + } + dev: true + + /get-stream@6.0.1: + resolution: + { + integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==, + } + engines: { node: ">=10" } + dev: true + + /glob-parent@5.1.2: + resolution: + { + integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, + } + engines: { node: ">= 6" } + dependencies: + is-glob: 4.0.3 + dev: true + + /glob-parent@6.0.2: + resolution: + { + integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==, + } + engines: { node: ">=10.13.0" } + dependencies: + is-glob: 4.0.3 + dev: true + + /glob@7.1.6: + resolution: + { + integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==, + } + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /glob@7.2.3: + resolution: + { + integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==, + } + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /globals@13.21.0: + resolution: + { + integrity: sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==, + } + engines: { node: ">=8" } + dependencies: + type-fest: 0.20.2 + dev: true + + /globby@11.1.0: + resolution: + { + integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==, + } + engines: { node: ">=10" } + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.1 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /graphemer@1.4.0: + resolution: + { + integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==, + } + dev: true + + /has-flag@3.0.0: + resolution: + { + integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==, + } + engines: { node: ">=4" } + dev: true + + /has-flag@4.0.0: + resolution: + { + integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, + } + engines: { node: ">=8" } + dev: true + + /has@1.0.3: + resolution: + { + integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==, + } + engines: { node: ">= 0.4.0" } + dependencies: + function-bind: 1.1.1 + dev: true + + /hosted-git-info@2.8.9: + resolution: + { + integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==, + } + dev: true + + /http-proxy-agent@4.0.1: + resolution: + { + integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==, + } + engines: { node: ">= 6" } + dependencies: + "@tootallnate/once": 1.1.2 + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /https-proxy-agent@5.0.1: + resolution: + { + integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==, + } + engines: { node: ">= 6" } + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /human-signals@2.1.0: + resolution: + { + integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==, + } + engines: { node: ">=10.17.0" } + dev: true + + /ignore@5.2.4: + resolution: + { + integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==, + } + engines: { node: ">= 4" } + dev: true + + /immediate@3.0.6: + resolution: + { + integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==, + } + dev: true + + /import-fresh@3.3.0: + resolution: + { + integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==, + } + engines: { node: ">=6" } + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: true + + /imurmurhash@0.1.4: + resolution: + { + integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==, + } + engines: { node: ">=0.8.19" } + dev: true + + /indent-string@4.0.0: + resolution: + { + integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==, + } + engines: { node: ">=8" } + dev: true + + /inflight@1.0.6: + resolution: + { + integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==, + } + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits@2.0.4: + resolution: + { + integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==, + } + dev: true + + /is-arrayish@0.2.1: + resolution: + { + integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==, + } + dev: true + + /is-binary-path@2.1.0: + resolution: + { + integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==, + } + engines: { node: ">=8" } + dependencies: + binary-extensions: 2.2.0 + dev: true + + /is-builtin-module@3.2.1: + resolution: + { + integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==, + } + engines: { node: ">=6" } + dependencies: + builtin-modules: 3.3.0 + dev: true + + /is-core-module@2.13.0: + resolution: + { + integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==, + } + dependencies: + has: 1.0.3 + dev: true + + /is-extglob@2.1.1: + resolution: + { + integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, + } + engines: { node: ">=0.10.0" } + dev: true + + /is-glob@4.0.3: + resolution: + { + integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, + } + engines: { node: ">=0.10.0" } + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-number@7.0.0: + resolution: + { + integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, + } + engines: { node: ">=0.12.0" } + dev: true + + /is-path-inside@3.0.3: + resolution: + { + integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==, + } + engines: { node: ">=8" } + dev: true + + /is-stream@2.0.1: + resolution: + { + integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==, + } + engines: { node: ">=8" } + dev: true + + /isarray@1.0.0: + resolution: + { + integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==, + } + dev: true + + /isexe@2.0.0: + resolution: + { + integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, + } + dev: true + + /joycon@3.1.1: + resolution: + { + integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==, + } + engines: { node: ">=10" } + dev: true + + /js-tokens@4.0.0: + resolution: + { + integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, + } + dev: true + + /js-yaml@4.1.0: + resolution: + { + integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==, + } + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /jsesc@0.5.0: + resolution: + { + integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==, + } + hasBin: true + dev: true + + /jsesc@3.0.2: + resolution: + { + integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==, + } + engines: { node: ">=6" } + hasBin: true + dev: true + + /json-buffer@3.0.1: + resolution: + { + integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==, + } + dev: true + + /json-parse-even-better-errors@2.3.1: + resolution: + { + integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==, + } + dev: true + + /json-schema-traverse@0.4.1: + resolution: + { + integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==, + } + dev: true + + /json-stable-stringify-without-jsonify@1.0.1: + resolution: + { + integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==, + } + dev: true + + /jszip@3.10.1: + resolution: + { + integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==, + } + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + dev: true + + /keyv@4.5.3: + resolution: + { + integrity: sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==, + } + dependencies: + json-buffer: 3.0.1 + dev: true + + /levn@0.4.1: + resolution: + { + integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==, + } + engines: { node: ">= 0.8.0" } + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /lie@3.3.0: + resolution: + { + integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==, + } + dependencies: + immediate: 3.0.6 + dev: true + + /lilconfig@2.1.0: + resolution: + { + integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==, + } + engines: { node: ">=10" } + dev: true + + /lines-and-columns@1.2.4: + resolution: + { + integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, + } + dev: true + + /load-tsconfig@0.2.5: + resolution: + { + integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + dev: true + + /locate-path@5.0.0: + resolution: + { + integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==, + } + engines: { node: ">=8" } + dependencies: + p-locate: 4.1.0 + dev: true + + /locate-path@6.0.0: + resolution: + { + integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==, + } + engines: { node: ">=10" } + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash.merge@4.6.2: + resolution: + { + integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==, + } + dev: true + + /lodash.sortby@4.7.0: + resolution: + { + integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==, + } + dev: true + + /lodash@4.17.21: + resolution: + { + integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==, + } + dev: true + + /lru-cache@6.0.0: + resolution: + { + integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==, + } + engines: { node: ">=10" } + dependencies: + yallist: 4.0.0 + dev: true + + /merge-stream@2.0.0: + resolution: + { + integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==, + } + dev: true + + /merge2@1.4.1: + resolution: + { + integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==, + } + engines: { node: ">= 8" } + dev: true + + /micromatch@4.0.5: + resolution: + { + integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==, + } + engines: { node: ">=8.6" } + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: true + + /mimic-fn@2.1.0: + resolution: + { + integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==, + } + engines: { node: ">=6" } + dev: true + + /min-indent@1.0.1: + resolution: + { + integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==, + } + engines: { node: ">=4" } + dev: true + + /minimatch@3.1.2: + resolution: + { + integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, + } + dependencies: + brace-expansion: 1.1.11 + dev: true + + /ms@2.1.2: + resolution: + { + integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==, + } + dev: true + + /mz@2.7.0: + resolution: + { + integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==, + } + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + dev: true + + /natural-compare@1.4.0: + resolution: + { + integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==, + } + dev: true + + /normalize-package-data@2.5.0: + resolution: + { + integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==, + } + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.4 + semver: 5.7.2 + validate-npm-package-license: 3.0.4 + dev: true + + /normalize-path@3.0.0: + resolution: + { + integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, + } + engines: { node: ">=0.10.0" } + dev: true + + /npm-run-path@4.0.1: + resolution: + { + integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==, + } + engines: { node: ">=8" } + dependencies: + path-key: 3.1.1 + dev: true + + /object-assign@4.1.1: + resolution: + { + integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, + } + engines: { node: ">=0.10.0" } + dev: true + + /once@1.4.0: + resolution: + { + integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==, + } + dependencies: + wrappy: 1.0.2 + dev: true + + /onetime@5.1.2: + resolution: + { + integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==, + } + engines: { node: ">=6" } + dependencies: + mimic-fn: 2.1.0 + dev: true + + /optionator@0.9.3: + resolution: + { + integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==, + } + engines: { node: ">= 0.8.0" } + dependencies: + "@aashutoshrathi/word-wrap": 1.2.6 + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /p-limit@2.3.0: + resolution: + { + integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==, + } + engines: { node: ">=6" } + dependencies: + p-try: 2.2.0 + dev: true + + /p-limit@3.1.0: + resolution: + { + integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==, + } + engines: { node: ">=10" } + dependencies: + yocto-queue: 0.1.0 + dev: true + + /p-locate@4.1.0: + resolution: + { + integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==, + } + engines: { node: ">=8" } + dependencies: + p-limit: 2.3.0 + dev: true + + /p-locate@5.0.0: + resolution: + { + integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==, + } + engines: { node: ">=10" } + dependencies: + p-limit: 3.1.0 + dev: true + + /p-try@2.2.0: + resolution: + { + integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==, + } + engines: { node: ">=6" } + dev: true + + /pako@1.0.11: + resolution: + { + integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==, + } + dev: true + + /parent-module@1.0.1: + resolution: + { + integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, + } + engines: { node: ">=6" } + dependencies: + callsites: 3.1.0 + dev: true + + /parse-json@5.2.0: + resolution: + { + integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==, + } + engines: { node: ">=8" } + dependencies: + "@babel/code-frame": 7.22.13 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: true + + /path-exists@4.0.0: + resolution: + { + integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==, + } + engines: { node: ">=8" } + dev: true + + /path-is-absolute@1.0.1: + resolution: + { + integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==, + } + engines: { node: ">=0.10.0" } + dev: true + + /path-key@3.1.1: + resolution: + { + integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, + } + engines: { node: ">=8" } + dev: true + + /path-parse@1.0.7: + resolution: + { + integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, + } + dev: true + + /path-type@4.0.0: + resolution: + { + integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==, + } + engines: { node: ">=8" } + dev: true + + /picomatch@2.3.1: + resolution: + { + integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, + } + engines: { node: ">=8.6" } + dev: true + + /pirates@4.0.6: + resolution: + { + integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==, + } + engines: { node: ">= 6" } + dev: true + + /pluralize@8.0.0: + resolution: + { + integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==, + } + engines: { node: ">=4" } + dev: true + + /postcss-load-config@4.0.1: + resolution: + { + integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==, + } + engines: { node: ">= 14" } + peerDependencies: + postcss: ">=8.0.9" + ts-node: ">=9.0.0" + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 2.1.0 + yaml: 2.3.2 + dev: true + + /prelude-ls@1.2.1: + resolution: + { + integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==, + } + engines: { node: ">= 0.8.0" } + dev: true + + /prettier@3.0.3: + resolution: + { + integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==, + } + engines: { node: ">=14" } + hasBin: true + dev: true + + /process-nextick-args@2.0.1: + resolution: + { + integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==, + } + dev: true + + /punycode@2.3.0: + resolution: + { + integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==, + } + engines: { node: ">=6" } + dev: true + + /queue-microtask@1.2.3: + resolution: + { + integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, + } + dev: true + + /read-pkg-up@7.0.1: + resolution: + { + integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==, + } + engines: { node: ">=8" } + dependencies: + find-up: 4.1.0 + read-pkg: 5.2.0 + type-fest: 0.8.1 + dev: true + + /read-pkg@5.2.0: + resolution: + { + integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==, + } + engines: { node: ">=8" } + dependencies: + "@types/normalize-package-data": 2.4.1 + normalize-package-data: 2.5.0 + parse-json: 5.2.0 + type-fest: 0.6.0 + dev: true + + /readable-stream@2.3.8: + resolution: + { + integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==, + } + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + dev: true + + /readdirp@3.6.0: + resolution: + { + integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==, + } + engines: { node: ">=8.10.0" } + dependencies: + picomatch: 2.3.1 + dev: true + + /regexp-tree@0.1.27: + resolution: + { + integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==, + } + hasBin: true + dev: true + + /regjsparser@0.10.0: + resolution: + { + integrity: sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==, + } + hasBin: true + dependencies: + jsesc: 0.5.0 + dev: true + + /resolve-from@4.0.0: + resolution: + { + integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, + } + engines: { node: ">=4" } + dev: true + + /resolve-from@5.0.0: + resolution: + { + integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==, + } + engines: { node: ">=8" } + dev: true + + /resolve@1.22.4: + resolution: + { + integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==, + } + hasBin: true + dependencies: + is-core-module: 2.13.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /reusify@1.0.4: + resolution: + { + integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==, + } + engines: { iojs: ">=1.0.0", node: ">=0.10.0" } + dev: true + + /rimraf@3.0.2: + resolution: + { + integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==, + } + hasBin: true + dependencies: + glob: 7.2.3 + dev: true + + /rollup@3.29.1: + resolution: + { + integrity: sha512-c+ebvQz0VIH4KhhCpDsI+Bik0eT8ZFEVZEYw0cGMVqIP8zc+gnwl7iXCamTw7vzv2MeuZFZfdx5JJIq+ehzDlg==, + } + engines: { node: ">=14.18.0", npm: ">=8.0.0" } + hasBin: true + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /run-parallel@1.2.0: + resolution: + { + integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==, + } + dependencies: + queue-microtask: 1.2.3 + dev: true + + /safe-buffer@5.1.2: + resolution: + { + integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==, + } + dev: true + + /semver@5.7.2: + resolution: + { + integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==, + } + hasBin: true + dev: true + + /semver@7.5.4: + resolution: + { + integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==, + } + engines: { node: ">=10" } + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /setimmediate@1.0.5: + resolution: + { + integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==, + } + dev: true + + /shebang-command@2.0.0: + resolution: + { + integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, + } + engines: { node: ">=8" } + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex@3.0.0: + resolution: + { + integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, + } + engines: { node: ">=8" } + dev: true + + /signal-exit@3.0.7: + resolution: + { + integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==, + } + dev: true + + /slash@3.0.0: + resolution: + { + integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==, + } + engines: { node: ">=8" } + dev: true + + /source-map@0.8.0-beta.0: + resolution: + { + integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==, + } + engines: { node: ">= 8" } + dependencies: + whatwg-url: 7.1.0 + dev: true + + /spdx-correct@3.2.0: + resolution: + { + integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==, + } + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.13 + dev: true + + /spdx-exceptions@2.3.0: + resolution: + { + integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==, + } + dev: true + + /spdx-expression-parse@3.0.1: + resolution: + { + integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==, + } + dependencies: + spdx-exceptions: 2.3.0 + spdx-license-ids: 3.0.13 + dev: true + + /spdx-license-ids@3.0.13: + resolution: + { + integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==, + } + dev: true + + /string_decoder@1.1.1: + resolution: + { + integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==, + } + dependencies: + safe-buffer: 5.1.2 + dev: true + + /strip-ansi@6.0.1: + resolution: + { + integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, + } + engines: { node: ">=8" } + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-final-newline@2.0.0: + resolution: + { + integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==, + } + engines: { node: ">=6" } + dev: true + + /strip-indent@3.0.0: + resolution: + { + integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==, + } + engines: { node: ">=8" } + dependencies: + min-indent: 1.0.1 + dev: true + + /strip-json-comments@3.1.1: + resolution: + { + integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, + } + engines: { node: ">=8" } + dev: true + + /sucrase@3.34.0: + resolution: + { + integrity: sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==, + } + engines: { node: ">=8" } + hasBin: true + dependencies: + "@jridgewell/gen-mapping": 0.3.3 + commander: 4.1.1 + glob: 7.1.6 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + dev: true + + /supports-color@5.5.0: + resolution: + { + integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==, + } + engines: { node: ">=4" } + dependencies: + has-flag: 3.0.0 + dev: true + + /supports-color@7.2.0: + resolution: + { + integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, + } + engines: { node: ">=8" } + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-preserve-symlinks-flag@1.0.0: + resolution: + { + integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==, + } + engines: { node: ">= 0.4" } + dev: true + + /text-table@0.2.0: + resolution: + { + integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==, + } + dev: true + + /thenify-all@1.6.0: + resolution: + { + integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==, + } + engines: { node: ">=0.8" } + dependencies: + thenify: 3.3.1 + dev: true + + /thenify@3.3.1: + resolution: + { + integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==, + } + dependencies: + any-promise: 1.3.0 + dev: true + + /to-regex-range@5.0.1: + resolution: + { + integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, + } + engines: { node: ">=8.0" } + dependencies: + is-number: 7.0.0 + dev: true + + /tr46@1.0.1: + resolution: + { + integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==, + } + dependencies: + punycode: 2.3.0 + dev: true + + /tree-kill@1.2.2: + resolution: + { + integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==, + } + hasBin: true + dev: true + + /ts-api-utils@1.0.3(typescript@5.2.2): + resolution: + { + integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==, + } + engines: { node: ">=16.13.0" } + peerDependencies: + typescript: ">=4.2.0" + dependencies: + typescript: 5.2.2 + dev: true + + /ts-interface-checker@0.1.13: + resolution: + { + integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==, + } + dev: true + + /tsup@7.2.0(typescript@5.2.2): + resolution: + { + integrity: sha512-vDHlczXbgUvY3rWvqFEbSqmC1L7woozbzngMqTtL2PGBODTtWlRwGDDawhvWzr5c1QjKe4OAKqJGfE1xeXUvtQ==, + } + engines: { node: ">=16.14" } + hasBin: true + peerDependencies: + "@swc/core": ^1 + postcss: ^8.4.12 + typescript: ">=4.1.0" + peerDependenciesMeta: + "@swc/core": + optional: true + postcss: + optional: true + typescript: + optional: true + dependencies: + bundle-require: 4.0.1(esbuild@0.18.20) + cac: 6.7.14 + chokidar: 3.5.3 + debug: 4.3.4 + esbuild: 0.18.20 + execa: 5.1.1 + globby: 11.1.0 + joycon: 3.1.1 + postcss-load-config: 4.0.1 + resolve-from: 5.0.0 + rollup: 3.29.1 + source-map: 0.8.0-beta.0 + sucrase: 3.34.0 + tree-kill: 1.2.2 + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + - ts-node + dev: true + + /type-check@0.4.0: + resolution: + { + integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==, + } + engines: { node: ">= 0.8.0" } + dependencies: + prelude-ls: 1.2.1 + dev: true + + /type-fest@0.20.2: + resolution: + { + integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==, + } + engines: { node: ">=10" } + dev: true + + /type-fest@0.6.0: + resolution: + { + integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==, + } + engines: { node: ">=8" } + dev: true + + /type-fest@0.8.1: + resolution: + { + integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==, + } + engines: { node: ">=8" } + dev: true + + /typescript@5.2.2: + resolution: + { + integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==, + } + engines: { node: ">=14.17" } + hasBin: true + dev: true + + /uri-js@4.4.1: + resolution: + { + integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, + } + dependencies: + punycode: 2.3.0 + dev: true + + /util-deprecate@1.0.2: + resolution: + { + integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, + } + dev: true + + /validate-npm-package-license@3.0.4: + resolution: + { + integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==, + } + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + dev: true + + /webidl-conversions@4.0.2: + resolution: + { + integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==, + } + dev: true + + /whatwg-url@7.1.0: + resolution: + { + integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==, + } + dependencies: + lodash.sortby: 4.7.0 + tr46: 1.0.1 + webidl-conversions: 4.0.2 + dev: true + + /which@2.0.2: + resolution: + { + integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, + } + engines: { node: ">= 8" } + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /wrappy@1.0.2: + resolution: + { + integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, + } + dev: true + + /yallist@4.0.0: + resolution: + { + integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==, + } + dev: true + + /yaml@2.3.2: + resolution: + { + integrity: sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==, + } + engines: { node: ">= 14" } + dev: true + + /yocto-queue@0.1.0: + resolution: + { + integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, + } + engines: { node: ">=10" } + dev: true diff --git a/resources/icon.svg b/resources/icon.svg new file mode 100644 index 0000000..02db148 --- /dev/null +++ b/resources/icon.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/explorer/explorer.ts b/src/explorer/explorer.ts new file mode 100644 index 0000000..dc89f72 --- /dev/null +++ b/src/explorer/explorer.ts @@ -0,0 +1,106 @@ +import path from "node:path"; +import { logger } from "../logger"; +import { + Uri, + FileType, + TreeDataProvider, + EventEmitter, + Event, + workspace, + TreeItem, + TreeItemCollapsibleState, + ThemeIcon, + ExtensionContext, + window, + commands, +} from "vscode"; + +interface Entry { + uri: Uri; + type: FileType; +} + +export class MarimoAppProvider implements TreeDataProvider { + // eslint-disable-next-line unicorn/prefer-event-target + private _onDidChangeTreeData = new EventEmitter(); + readonly onDidChangeTreeData: Event = + this._onDidChangeTreeData.event; + + constructor() {} + + refresh(): void { + this._onDidChangeTreeData.fire(undefined); + } + + async getChildren(): Promise { + // Get all Python files in the workspace + const pythonFiles = await workspace.findFiles( + "**/*.py", + // ignore venv, node_modules, and .git + "{**/venv/**,**/node_modules/**,**/.git/**}", + ); + + const entries: Entry[] = []; + + for (const file of pythonFiles) { + // Open the file as a text document + const document = await workspace.openTextDocument(file); + if (document.getText().includes("app = marimo.App(")) { + entries.push({ uri: file, type: FileType.File }); + } + } + + // Sort the entries by name + entries.sort((a, b) => { + return a.uri.fsPath.localeCompare(b.uri.fsPath); + }); + + return entries; + } + + getTreeItem(element: Entry): TreeItem { + const treeItem = new TreeItem( + element.uri, + element.type === FileType.Directory + ? TreeItemCollapsibleState.Collapsed + : TreeItemCollapsibleState.None, + ); + if (element.type === FileType.File) { + treeItem.command = { + command: "marimo-explorer.openFile", + title: "Open File", + arguments: [element.uri], + }; + treeItem.contextValue = "app"; + const filePath = element.uri.fsPath; + const fileName = path.basename(filePath) || "app.py"; + const folderName = path.basename(path.dirname(filePath)); + treeItem.label = folderName ? `${folderName}/${fileName}` : fileName; + treeItem.iconPath = new ThemeIcon("book"); + treeItem.tooltip = filePath; + } + return treeItem; + } +} + +export class MarimoExplorer { + constructor(context: ExtensionContext) { + const treeDataProvider = new MarimoAppProvider(); + logger.log("marimo explorer is now active!"); + context.subscriptions.push( + window.createTreeView("marimo-explorer-applications", { + treeDataProvider, + }), + ); + commands.registerCommand("marimo-explorer.openFile", (resource) => + this.openResource(resource), + ); + commands.registerCommand("marimo-explorer.refresh", () => + treeDataProvider.refresh(), + ); + } + + private openResource(resource: Uri): void { + window.showTextDocument(resource); + } +} diff --git a/src/extension.ts b/src/extension.ts new file mode 100644 index 0000000..dd61900 --- /dev/null +++ b/src/extension.ts @@ -0,0 +1,65 @@ +import { commands, ExtensionContext, window } from "vscode"; +import { start, stop } from "./launcher/start"; +import { updateStatusBar } from "./launcher/status-bar"; +import { showCommands } from "./launcher/show-commands"; +import { Controllers, withController } from "./launcher/controller"; +import { logger } from "./logger"; +import { MarimoExplorer } from "./explorer/explorer"; + +export async function activate(extension: ExtensionContext) { + logger.log("marimo extension is now active!"); + + // These commands all operate on the current file + commands.registerCommand("vscode-marimo.edit", () => + withController(extension, async (controller) => { + await start({ controller, mode: "edit" }); + controller.open(); + }), + ); + commands.registerCommand("vscode-marimo.restart", () => { + withController(extension, async (controller) => { + const mode = controller.currentMode || "edit"; + stop(controller); + await start({ controller, mode }); + controller.open(); + }); + }); + commands.registerCommand("vscode-marimo.run", () => { + withController(extension, async (controller) => { + await start({ controller, mode: "run" }); + controller.open(); + }); + }); + commands.registerCommand("vscode-marimo.stop", () => + withController(extension, async (controller) => { + stop(controller); + }), + ); + commands.registerCommand("vscode-marimo.showCommands", () => { + withController(extension, async (controller) => { + showCommands(controller); + }); + }); + commands.registerCommand("vscode-marimo.openInBrowser", () => { + withController(extension, async (controller) => { + controller.open("system"); + }); + }); + + window.onDidCloseTerminal((error) => { + const controller = Controllers.findWithTerminal(error); + controller?.dispose(); + }); + + window.onDidChangeActiveTextEditor(() => { + updateStatusBar(extension); + }); + + updateStatusBar(extension); + + new MarimoExplorer(extension); +} + +export async function deactivate() { + Controllers.disposeAll(); +} diff --git a/src/launcher/config.ts b/src/launcher/config.ts new file mode 100644 index 0000000..01dddc4 --- /dev/null +++ b/src/launcher/config.ts @@ -0,0 +1,32 @@ +import { workspace } from "vscode"; + +export function getConfig(key: string): T | undefined; +export function getConfig(key: string, v: T): T; +export function getConfig(key: string, v?: T) { + return workspace.getConfiguration().get(`marimo.${key}`, v); +} + +export const Config = { + get root() { + return workspace.workspaceFolders?.[0]?.uri?.fsPath || ""; + }, + get browser() { + return getConfig<"system" | "embedded">("browserType", "embedded"); + }, + get showTerminal() { + return getConfig("showTerminal", false); + }, + get port() { + return getConfig("port", 2718); + }, + get host() { + return "localhost"; + }, + get https() { + return false; + }, +}; + +export function composeUrl(port: number) { + return `${Config.https ? "https" : "http"}://${Config.host}:${port}`; +} diff --git a/src/launcher/controller.ts b/src/launcher/controller.ts new file mode 100644 index 0000000..5e9b79a --- /dev/null +++ b/src/launcher/controller.ts @@ -0,0 +1,206 @@ +import { + Disposable, + ExtensionContext, + Terminal, + TextDocument, + Uri, + env, + window, + workspace, +} from "vscode"; +import { Config, composeUrl } from "./config"; +import { getCurrentFile, isMarimoApp, ping } from "./utils"; +import path from "node:path"; +import { MarimoTerminal } from "./terminal"; +import { MarimoPanelManager } from "./panel"; +import { logger } from "../logger"; +import { updateStatusBar } from "./status-bar"; + +export type AppMode = "edit" | "run"; + +export class MarimoController implements Disposable { + public terminal: MarimoTerminal; + private panel: MarimoPanelManager; + + public currentMode: AppMode | undefined; + public active: boolean = false; + public port: number | undefined; + private logger = logger.createLogger(this.appName); + + constructor( + private file: TextDocument, + private extension: ExtensionContext, + private onUpdate: () => void, + ) { + this.file = file; + const workspaceFolder = workspace.workspaceFolders?.find((folder) => + file.uri.fsPath.startsWith(folder.uri.fsPath), + )?.uri.fsPath; + + this.terminal = new MarimoTerminal( + extension, + file.uri.fsPath, + workspaceFolder, + this.appName, + ); + this.panel = new MarimoPanelManager(this.appName); + + // Try to recover state + this.tryRecoverState(); + } + + hasTerminal(term: Terminal) { + return this.terminal.is(term); + } + + async start(mode: AppMode, port: number) { + this.extension.globalState.update(this.keyFor("mode"), mode); + this.currentMode = mode; + this.extension.globalState.update(this.keyFor("port"), port); + this.port = port; + const filePath = this.terminal.relativePathFor(this.file.uri.fsPath); + + await (mode === "edit" + ? this.terminal.executeCommand( + `marimo -d edit ${filePath} --port=${port} --headless`, + ) + : this.terminal.executeCommand( + `marimo -d run ${filePath} --port=${port} --headless`, + )); + + this.active = true; + this.onUpdate(); + } + + isWebviewActive() { + return this.panel.isActive(); + } + + async open(browser = Config.browser) { + // If already opened, just focus + if (browser === "embedded" && this.panel.isReady()) { + this.panel.show(); + } + + if (browser === "system") { + // Close the panel if opened + this.panel.dispose(); + env.openExternal(Uri.parse(this.url)); + } else if (browser === "embedded") { + this.panel.create(this.url); + this.panel.show(); + } + } + + async tryRecoverState() { + if (!(await this.terminal.tryRecoverTerminal())) { + return; + } + this.logger.log("terminal recovered"); + + const port = +( + this.extension.globalState.get(this.keyFor("port")) || 0 + ); + if (!port) { + return; + } + + const url = composeUrl(port); + + if (!(await ping(url))) { + return; + } + + this.active = true; + this.port = port; + this.currentMode = + this.extension.globalState.get(this.keyFor("mode")) || "edit"; + this.logger.log("state recovered"); + + this.onUpdate(); + return true; + } + + dispose() { + this.panel.dispose(); + this.terminal.dispose(); + this.active = false; + this.extension.globalState.update(this.keyFor("mode"), undefined); + this.extension.globalState.update(this.keyFor("port"), undefined); + this.onUpdate(); + } + + public get appName() { + const filePath = this.file.uri.fsPath; + const fileName = path.basename(filePath) || "app.py"; + const folderName = path.basename(path.dirname(filePath)); + return folderName ? `${folderName}/${fileName}` : fileName; + } + + public get url() { + if (!this.port) { + return ""; + } + return composeUrl(this.port); + } + + private keyFor(key: string) { + return `marimo.${this.file.uri.fsPath}.${key}`; + } +} + +const all = new Map(); + +export const Controllers = { + getControllerForActivePanel(): MarimoController | undefined { + return [...all.values()].find((c) => c.isWebviewActive()); + }, + getOrCreate( + file: TextDocument, + extension: ExtensionContext, + ): MarimoController { + const key = file.uri.fsPath; + if (all.has(key)) { + return all.get(key)!; + } + const controller = new MarimoController(file, extension, () => + updateStatusBar(extension), + ); + all.set(key, controller); + return controller; + }, + get(file: TextDocument | undefined): MarimoController | undefined { + if (!file) { + return; + } + return all.get(file.uri.fsPath); + }, + findWithTerminal(term: Terminal): MarimoController | undefined { + return [...all.values()].find((c) => c.terminal.is(term)); + }, + disposeAll() { + for (const c of all.values()) c.dispose(); + all.clear(); + }, +}; + +export function withController( + extension: ExtensionContext, + fn: (controller: MarimoController) => T, +) { + const activePanelController = Controllers.getControllerForActivePanel(); + if (activePanelController) { + return fn(activePanelController); + } + + const file = getCurrentFile(); + if (!file) { + return; + } + if (!isMarimoApp(file)) { + window.showInformationMessage("This is not a marimo app."); + return; + } + const controller = Controllers.getOrCreate(file, extension); + return fn(controller); +} diff --git a/src/launcher/panel.ts b/src/launcher/panel.ts new file mode 100644 index 0000000..a7e0735 --- /dev/null +++ b/src/launcher/panel.ts @@ -0,0 +1,69 @@ +import { ViewColumn, WebviewPanel, window } from "vscode"; +import { logger } from "../logger"; + +export class MarimoPanelManager { + private nativePanel: WebviewPanel | undefined; + private logger = logger.createLogger(this.appName); + + constructor(private appName: string) {} + + isReady() { + return !!this.nativePanel; + } + + isActive() { + return this.nativePanel?.active ?? false; + } + + async create(url: string) { + this.logger.log("creating panel at", url); + + // Skip if already created + if (this.nativePanel) { + return; + } + + this.nativePanel = window.createWebviewPanel( + "marimo", + `marimo: ${this.appName}`, + ViewColumn.Beside, + { + enableScripts: true, + enableCommandUris: true, + }, + ); + + this.nativePanel.webview.html = getWebviewContent(url); + + this.nativePanel.onDidDispose(() => { + this.nativePanel = undefined; + }); + } + + show() { + this.logger.log("showing embedded browser"); + this.nativePanel?.reveal(); + } + + dispose() { + this.logger.log("disposing panel"); + this.nativePanel?.dispose(); + } +} + +function getWebviewContent(url: string) { + return ` + + + + + + marimo + + + + + `; +} diff --git a/src/launcher/show-commands.ts b/src/launcher/show-commands.ts new file mode 100644 index 0000000..bef1e13 --- /dev/null +++ b/src/launcher/show-commands.ts @@ -0,0 +1,89 @@ +import { QuickPickItem, window } from "vscode"; +import { start, stop } from "./start"; +import { MarimoController } from "./controller"; + +interface CommandPickItem extends QuickPickItem { + handler: () => void; + if: boolean; +} + +export async function showCommands(controller: MarimoController) { + const commands: CommandPickItem[] = [ + { + label: "$(zap) Start marimo server (edit)", + async handler() { + await start({ controller, mode: "edit" }); + controller.open(); + }, + if: !controller.active, + }, + { + label: "$(remote-explorer-documentation) Start marimo server (run)", + async handler() { + await start({ controller, mode: "run" }); + controller.open(); + }, + if: !controller.active, + }, + { + label: "$(split-horizontal) Open in embedded browser", + description: controller.url, + handler() { + controller.open("embedded"); + }, + if: controller.active, + }, + { + label: "$(link-external) Open in system browser", + description: controller.url, + handler() { + controller.open("system"); + }, + if: controller.active, + }, + { + label: `$(refresh) Restart marimo server`, + async handler() { + const mode = controller.currentMode || "edit"; + await stop(controller); + await start({ mode, controller }); + controller.open(); + }, + if: controller.active, + }, + { + label: + controller.currentMode === "run" + ? "$(package) Switch to edit mode" + : "$(package) Switch to run mode", + async handler() { + const otherMode = controller.currentMode === "run" ? "edit" : "run"; + await stop(controller); + await start({ mode: otherMode, controller }); + controller.open(); + }, + if: controller.active, + }, + { + label: "$(terminal) Show Terminal", + handler() { + controller.terminal.show(); + }, + if: controller.active, + }, + { + label: "$(close) Stop server", + handler() { + stop(controller); + }, + if: controller.active, + }, + ]; + + const filteredCommands = commands.filter((index) => index.if !== false); + const result = await window.showQuickPick(filteredCommands); + + if (result) { + result.handler(); + } +} diff --git a/src/launcher/start.ts b/src/launcher/start.ts new file mode 100644 index 0000000..467292a --- /dev/null +++ b/src/launcher/start.ts @@ -0,0 +1,48 @@ +import { window } from "vscode"; +import { Config } from "./config"; +import { tryPort } from "./utils"; +import { disposeStatusBar } from "./status-bar"; +import { MarimoController, AppMode } from "./controller"; + +export async function start({ + controller, + mode, +}: { + controller: MarimoController; + mode: AppMode; +}) { + // If its already running and the mode is the same, do nothing + if (controller.currentMode === mode && controller.active) { + const button = "Open"; + if (Config.showTerminal) { + controller.terminal.show(); + } + window + .showInformationMessage( + `${controller.appName} is already running in ${mode} mode`, + button, + ) + .then((response) => { + if (response === button) { + controller.open(); + } + }); + return; + } + + // Restart if the mode is different + if (mode !== controller.currentMode && controller.active) { + controller.dispose(); + } + + // Start with the current port if available + // Make sure the port is free, otherwise try the next one + const port = await tryPort(controller.port || Config.port); + + await controller.start(mode, port); +} + +export function stop(controller: MarimoController) { + controller.dispose(); + disposeStatusBar(); +} diff --git a/src/launcher/status-bar.ts b/src/launcher/status-bar.ts new file mode 100644 index 0000000..d34ca5a --- /dev/null +++ b/src/launcher/status-bar.ts @@ -0,0 +1,60 @@ +import { + ExtensionContext, + StatusBarAlignment, + StatusBarItem, + ThemeColor, + commands, + window, +} from "vscode"; +import { Controllers } from "./controller"; +import { getCurrentFile, isMarimoApp } from "./utils"; + +let statusBar: StatusBarItem; + +export function ensureStatusBar() { + if (!statusBar) { + statusBar = window.createStatusBarItem(StatusBarAlignment.Left, 10); + statusBar.command = "vscode-marimo.showCommands"; + statusBar.show(); + } +} + +export function disposeStatusBar() { + statusBar?.dispose(); + statusBar = undefined!; +} + +export function updateStatusBar(extension: ExtensionContext) { + ensureStatusBar(); + + const file = getCurrentFile(false); + commands.executeCommand( + "setContext", + "marimo.isMarimoApp", + isMarimoApp(file), + ); + + if (!file) { + statusBar.hide(); + return; + } + statusBar.show(); + + const activeController = + Controllers.getControllerForActivePanel() || + Controllers.getOrCreate(file, extension); + if (activeController.active) { + statusBar.text = + activeController.currentMode === "run" + ? "$(zap) marimo (run)" + : "$(zap) marimo"; + statusBar.backgroundColor = new ThemeColor( + "statusBarItem.warningBackground", + ); + statusBar.color = new ThemeColor("statusBarItem.warningForeground"); + } else { + statusBar.text = "$(play) Start marimo"; + statusBar.backgroundColor = undefined; + statusBar.color = undefined; + } +} diff --git a/src/launcher/terminal.ts b/src/launcher/terminal.ts new file mode 100644 index 0000000..0a71efb --- /dev/null +++ b/src/launcher/terminal.ts @@ -0,0 +1,119 @@ +import { + Disposable, + ExtensionContext, + Terminal, + window, + workspace, +} from "vscode"; +import { Config } from "./config"; +import { wait } from "./utils"; +import { logger } from "../logger"; +import path from "node:path"; + +export class MarimoTerminal implements Disposable { + private terminal: Terminal | undefined; + private logger = logger.createLogger(this.appName); + + constructor( + private extension: ExtensionContext, + private fsPath: string, + private cwd: string | undefined, + private appName: string, + ) {} + + private async ensureTerminal() { + if (this.isTerminalActive()) { + return; + } + + this.terminal = window.createTerminal({ + name: `marimo ${this.appName}`, + cwd: this.cwd, + }); + // Wait 1s for the terminal to 'source' the virtualenv + await wait(1000); + } + + relativePathFor(file: string) { + if (this.cwd && file.startsWith(this.cwd)) { + return path.relative(this.cwd, file); + } + return file; + } + + private isTerminalActive() { + return this.terminal && this.terminal.exitStatus == undefined; + } + + dispose() { + this.logger.log("killing terminal"); + this.endProcess(); + this.terminal?.dispose(); + this.terminal = undefined!; + this.logger.log("terminal disposed"); + } + + async show() { + this.logger.log("showing terminal"); + await this.ensureTerminal(); + this.terminal?.show(true); + } + + private endProcess() { + if (this.isTerminalActive()) { + this.terminal?.sendText("\u0003"); + this.terminal?.sendText("\u0003"); + } + this.extension.globalState.update(this.keyFor("pid"), undefined); + } + + is(term: Terminal) { + return this.terminal === term; + } + + async tryRecoverTerminal() { + this.logger.log("trying to recover terminal"); + if (this.terminal) { + return; + } + + const pid = this.extension.globalState.get(this.keyFor("pid")); + this.logger.log("recovered pid", pid); + if (!pid) { + return; + } + + const terminals = await Promise.all( + window.terminals.map(async (index) => + pid === (await index.processId) ? index : undefined, + ), + ); + + const terminal = terminals.find(Boolean); + + if (terminal) { + this.logger.log("recovered terminal"); + this.terminal = terminal; + return true; + } + return false; + } + + async executeCommand(cmd: string) { + await this.ensureTerminal(); + this.terminal?.sendText(cmd); + + if (Config.showTerminal) { + this.terminal?.show(false); + } + await wait(2000); + const pid = await this.terminal?.processId; + if (pid) { + this.extension.globalState.update(this.keyFor("pid"), pid); + } + } + + private keyFor(key: string) { + return `marimo.${this.fsPath}.${key}`; + } +} diff --git a/src/launcher/utils.ts b/src/launcher/utils.ts new file mode 100644 index 0000000..30ec386 --- /dev/null +++ b/src/launcher/utils.ts @@ -0,0 +1,84 @@ +import http from "node:http"; +import https from "node:https"; +import { TextDocument, window } from "vscode"; + +function isPortFree(port: number) { + return new Promise((resolve) => { + const server = http + .createServer() + .listen(port, () => { + server.close(); + resolve(true); + }) + .on("error", () => { + resolve(false); + }); + }); +} + +export function wait(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +export async function tryPort(start: number): Promise { + if (await isPortFree(start)) { + return start; + } + return tryPort(start + 1); +} + +export function ping(url: string) { + const promise = new Promise((resolve) => { + const useHttps = url.indexOf("https") === 0; + const module_ = useHttps ? https.request : http.request; + + const pingRequest = module_(url, () => { + resolve(true); + pingRequest.destroy(); + }); + + pingRequest.on("error", () => { + resolve(false); + pingRequest.destroy(); + }); + + pingRequest.write(""); + pingRequest.end(); + }); + return promise; +} + +export function isMarimoApp( + document: TextDocument | undefined, + includeEmpty = true, +) { + if (!document) { + return false; + } + + // If ends in .py and is empty, return true + // This is so we can create a new file and start the server + if ( + includeEmpty && + document.fileName.endsWith(".py") && + document.getText().trim() === "" + ) { + return true; + } + + // Cheap way of checking if it's a marimo app + return document.getText().includes("app = marimo.App("); +} + +export function getCurrentFile(toast: boolean = true) { + const file = [window.activeTextEditor, ...window.visibleTextEditors].find( + (editor) => isMarimoApp(editor?.document, false), + ); + if (!file) { + if (toast) { + window.showInformationMessage("No marimo file is open."); + } + return; + } + return file.document; +} diff --git a/src/logger.ts b/src/logger.ts new file mode 100644 index 0000000..33ab97a --- /dev/null +++ b/src/logger.ts @@ -0,0 +1,24 @@ +import { window } from "vscode"; + +const channel = window.createOutputChannel("marimo"); + +class Logger { + constructor(private prefix: string) {} + + log(...args: unknown[]) { + if (this.prefix) { + channel.appendLine(`${this.prefix}: ${args.join(" ")}`); + } else { + channel.appendLine(args.join(" ")); + } + } + + createLogger(prefix: string) { + if (!this.prefix) { + return new Logger(prefix); + } + return new Logger(`${this.prefix} > ${prefix}`); + } +} + +export const logger = new Logger(""); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e86f652 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "es2020", + "module": "esnext", + "outDir": "./dist", + "lib": ["esnext"], + "moduleResolution": "node", + "esModuleInterop": true, + "strict": true, + "strictNullChecks": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noUnusedParameters": true + } +} diff --git a/tsup.config.ts b/tsup.config.ts new file mode 100644 index 0000000..60fec73 --- /dev/null +++ b/tsup.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["cjs"], + shims: false, + dts: false, + external: ["vscode"], +});