diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000..7928c0d --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,10 @@ +name: Pull Request Check +on: + pull_request: + branches: + - dev/* + - master +jobs: + unit-tests: + name: Unit Tests + uses: ./.github/workflows/unit-tests.yml diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..48936a6 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,42 @@ +name: Publish +on: + push: + branches: master +jobs: + unit-tests: + name: Unit Tests + uses: ./.github/workflows/unit-tests.yml + publish: + name: Publish + needs: unit-tests + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.ref }} + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 20 + registry-url: https://registry.npmjs.org/ + - name: Get package.json + id: get-package + run: echo PACKAGE=$(cat ./package.json) >> $GITHUB_OUTPUT + - name: Get package version + id: get-package-version + run: echo VERSION="${{ fromJson(steps.get-package.outputs.PACKAGE).version }}" >> $GITHUB_OUTPUT + - name: Install + run: npm ci + - name: Build & Pack + run: npm run pack + - name: Publish + run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Tag + run: | + git config --global user.name "ponlawat-w" + git config --global user.email "ponlawat_w@outlook.co.th" + git tag -fa "v${{ steps.get-package-version.outputs.VERSION }}" -m "v${{ steps.get-package-version.outputs.VERSION }}" + git push --force origin v${{ steps.get-package-version.outputs.VERSION }} diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml new file mode 100644 index 0000000..fee5191 --- /dev/null +++ b/.github/workflows/unit-tests.yml @@ -0,0 +1,19 @@ +name: Unit Tests +on: workflow_call +jobs: + unit-tests: + name: Unit Tests + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.ref }} + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 20 + - name: Install + run: npm ci + - name: Test + run: npm run test diff --git a/.gitignore b/.gitignore index bdff158..a4ede99 100644 --- a/.gitignore +++ b/.gitignore @@ -161,3 +161,5 @@ dist .ionide # End of https://www.toptal.com/developers/gitignore/api/node,visualstudiocode + +tests/data/ignore/* diff --git a/README.md b/README.md new file mode 100644 index 0000000..dcca855 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +# GTFS-IO + +IO Operations for GTFS dataset in node / javascript. + +## Installation + +```bash +npm i gtfs-io +``` + +## Examples + +### Load Feed + +```ts +// Synchronously +import { GTFSFeedReader } from 'gtfs-io'; +const reader = GTFSFeedReader.fromZip('gtfs.zip'); +const reader = GTFSFeedReader.fromDirectory('path/to/dir'); +const feed = reader.loadFeed(); +console.log(feed.stops[0].stop_id); +console.log(feed.trips[1].trip_id); + +// Asynchronously +import { GTFSAsyncFeedReader } from 'gtfs-io'; +const reader = GTFSAsyncFeedReader.fromZip('gtfs.zip'); +const reader = GTFSAsyncFeedReader.fromDirectory('path/to/dir'); +const feed = await reader.loadFeed(); +console.log(feed.stops[0].stop_id); +console.log(feed.trips[1].trip_id); +``` + +### Write Feed + +```ts +import { GTFSLoadedFeed } from 'gtfs-io'; +const feed = new GTFSLoadedFeed({ + agency: [{ agency_id: '...', agency_name: '...', ... }, ...], + stops: [{ stop_id: '...', ... }, { ... }, ...], + routes: [{ ... }, { ... }, ...], + trips: [{ ... }, ...], + ... +}); + +// Synchronously +import { GTFSFeedWriter } from 'gtfs-io'; +GTFSFeedWriter.writeZip(feed, 'gtfs.zip'); +GTFSFeedWriter.writeDirectory(feed, 'path/to/dir'); + +// Asynchronously +import { GTFSAsyncFeedWriter } from 'gtfs-io'; +await GTFSAsyncFeedWriter.writeZip(feed, 'gtfs.zip'); +await GTFSAsyncFeedWriter.writeDirectory(feed, 'path/to/dir'); +``` + +--- diff --git a/package-lock.json b/package-lock.json index a1959ad..465b619 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,20 +1,40 @@ { "name": "gtfs-io", - "version": "0.0.0", + "version": "0.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "gtfs-io", - "version": "0.0.0", + "version": "0.0.1", "license": "ISC", "dependencies": { + "adm-zip": "^0.5.10", "csv": "^6.3.5" }, "devDependencies": { + "@types/adm-zip": "^0.5.5", "@types/node": "^20.10.1", + "assert": "^2.1.0", + "browserify-zlib": "^0.2.0", + "buffer": "^6.0.3", + "crypto-browserify": "^3.12.0", + "stream-browserify": "^3.0.0", + "typedoc": "^0.25.4", "typescript": "^5.3.2", - "vitest": "^0.34.6" + "util": "^0.12.5", + "vitest": "^0.34.6", + "webpack": "^5.89.0", + "webpack-cli": "^5.1.4" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" } }, "node_modules/@esbuild/android-arm": { @@ -381,12 +401,64 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.6.1.tgz", @@ -549,6 +621,15 @@ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, + "node_modules/@types/adm-zip": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.5.tgz", + "integrity": "sha512-YCGstVMjc4LTY5uK9/obvxBya93axZOVOyf2GSUulADzmLhYE45u2nAssCs/fWBs1Ifq5Vat75JTPwd5XZoPJw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/chai": { "version": "4.3.11", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz", @@ -564,6 +645,38 @@ "@types/chai": "*" } }, + "node_modules/@types/eslint": { + "version": "8.44.8", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.8.tgz", + "integrity": "sha512-4K8GavROwhrYl2QXDXm0Rv9epkA8GBFu0EI+XrrnnuCl7u8CWBRusX7fXJfanhZTDWSAL24gDI/UqXyUM0Injw==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, "node_modules/@types/node": { "version": "20.10.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.1.tgz", @@ -641,6 +754,208 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, "node_modules/acorn": { "version": "8.11.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", @@ -653,6 +968,15 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/acorn-walk": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", @@ -662,6 +986,45 @@ "node": ">=0.4.0" } }, + "node_modules/adm-zip": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", + "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-sequence-parser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz", + "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==", + "dev": true + }, "node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -674,6 +1037,37 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dev": true, + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/assert": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" + } + }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -683,114 +1077,591 @@ "node": "*" } }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", "dev": true, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/chai": { - "version": "4.3.10", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", - "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" - }, - "engines": { - "node": ">=4" + "balanced-match": "^1.0.0" } }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, - "node_modules/csv": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/csv/-/csv-6.3.5.tgz", - "integrity": "sha512-Y+KTCAUljtq2JaGP42ZL1bymqlU5BkfnFpZhxRczGFDZox2VXhlRHnG5DRshyUrwQzmCdEiLjSqNldCfm1OVCA==", + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, "dependencies": { - "csv-generate": "^4.3.0", - "csv-parse": "^5.5.2", - "csv-stringify": "^6.4.4", - "stream-transform": "^3.2.10" - }, - "engines": { - "node": ">= 0.1.90" + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" } }, - "node_modules/csv-generate": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-4.3.0.tgz", - "integrity": "sha512-7KdVId/2RgwPIKfWHaHtjBq7I9mgdi8ICzsUyIhP8is6UwpwVGGSC/aPnrZ8/SkgBcCP20lXrdPuP64Irs1VBg==" - }, - "node_modules/csv-parse": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-5.5.2.tgz", - "integrity": "sha512-YRVtvdtUNXZCMyK5zd5Wty1W6dNTpGKdqQd4EQ8tl/c6KW1aMBB1Kg1ppky5FONKmEqGJ/8WjLlTNLPne4ioVA==" - }, - "node_modules/csv-stringify": { - "version": "6.4.4", - "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-6.4.4.tgz", - "integrity": "sha512-NDshLupGa7gp4UG4sSNIqwYJqgSwvds0SvENntxoVoVvTzXcrHvd5gG2MWpbRpSNvk59dlmIe1IwNvSxN4IVmg==" + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", "dev": true, "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" } }, - "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "node_modules/browserify-sign": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", + "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", "dev": true, "dependencies": { - "type-detect": "^4.0.0" + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.4", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.6", + "readable-stream": "^3.6.2", + "safe-buffer": "^5.2.1" }, "engines": { - "node": ">=6" + "node": ">= 4" } }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "dependencies": { + "pako": "~1.0.5" } }, - "node_modules/esbuild": { - "version": "0.19.8", + "node_modules/browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001565", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz", + "integrity": "sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chai": { + "version": "4.3.10", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", + "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/csv": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/csv/-/csv-6.3.5.tgz", + "integrity": "sha512-Y+KTCAUljtq2JaGP42ZL1bymqlU5BkfnFpZhxRczGFDZox2VXhlRHnG5DRshyUrwQzmCdEiLjSqNldCfm1OVCA==", + "dependencies": { + "csv-generate": "^4.3.0", + "csv-parse": "^5.5.2", + "csv-stringify": "^6.4.4", + "stream-transform": "^3.2.10" + }, + "engines": { + "node": ">= 0.1.90" + } + }, + "node_modules/csv-generate": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-4.3.0.tgz", + "integrity": "sha512-7KdVId/2RgwPIKfWHaHtjBq7I9mgdi8ICzsUyIhP8is6UwpwVGGSC/aPnrZ8/SkgBcCP20lXrdPuP64Irs1VBg==" + }, + "node_modules/csv-parse": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-5.5.2.tgz", + "integrity": "sha512-YRVtvdtUNXZCMyK5zd5Wty1W6dNTpGKdqQd4EQ8tl/c6KW1aMBB1Kg1ppky5FONKmEqGJ/8WjLlTNLPne4ioVA==" + }, + "node_modules/csv-stringify": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-6.4.4.tgz", + "integrity": "sha512-NDshLupGa7gp4UG4sSNIqwYJqgSwvds0SvENntxoVoVvTzXcrHvd5gG2MWpbRpSNvk59dlmIe1IwNvSxN4IVmg==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.601", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.601.tgz", + "integrity": "sha512-SpwUMDWe9tQu8JX5QCO1+p/hChAi9AE9UpoC3rcHVc+gdCGlbT3SGb5I1klgb952HRIyvt9wZhSz9bNBYz9swA==", + "dev": true + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz", + "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.19.8", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.8.tgz", "integrity": "sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w==", "dev": true, @@ -826,35 +1697,524 @@ "@esbuild/win32-x64": "0.19.8" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "which-typed-array": "^1.1.11" + }, "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true, "engines": { - "node": "*" + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" } }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/jsonc-parser": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", "dev": true }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, "node_modules/local-pkg": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", @@ -867,6 +2227,18 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/loupe": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", @@ -876,6 +2248,12 @@ "get-func-name": "^2.0.1" } }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, "node_modules/magic-string": { "version": "0.30.5", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", @@ -888,6 +2266,102 @@ "node": ">=12" } }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/mlly": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz", @@ -924,6 +2398,61 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/p-limit": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", @@ -939,6 +2468,85 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "node_modules/parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dev": true, + "dependencies": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, "node_modules/pathe": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz", @@ -954,12 +2562,40 @@ "node": "*" } }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/pkg-types": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", @@ -971,53 +2607,175 @@ "pathe": "^1.1.0" } }, - "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "resolve": "^1.20.0" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">= 10.13.0" } }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } }, "node_modules/rollup": { "version": "4.6.1", @@ -1047,12 +2805,147 @@ "fsevents": "~2.3.2" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shiki": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.5.tgz", + "integrity": "sha512-1gCAYOcmCFONmErGTrS1fjzJLA7MGZmKzrBNX7apqSwhyITJg2O102uFzXUeBxNnEkDA9vHIKLyeKq0V083vIw==", + "dev": true, + "dependencies": { + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, "node_modules/siginfo": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -1062,6 +2955,16 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -1074,11 +2977,30 @@ "integrity": "sha512-JGUEaALvL0Mf6JCfYnJOTcobY+Nc7sG/TemDRBqCA0wEr4DER7zDchaaixTlmOxAjG1uRJmX82EQcxwTQTkqVA==", "dev": true }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dev": true, + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, "node_modules/stream-transform": { "version": "3.2.10", "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-3.2.10.tgz", "integrity": "sha512-Yu+x7zcWbWdyB0Td8dFzHt2JEyD6694CNq2lqh1rbuEBVxPtjb/GZ7xDnZcdYiU5E/RtufM54ClSEOzZDeWguA==" }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/strip-literal": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz", @@ -1091,6 +3013,94 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz", + "integrity": "sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, "node_modules/tinybench": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.1.tgz", @@ -1124,6 +3134,27 @@ "node": ">=4" } }, + "node_modules/typedoc": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.4.tgz", + "integrity": "sha512-Du9ImmpBCw54bX275yJrxPVnjdIyJO/84co0/L9mwe0R3G4FSR6rQ09AlXVRvZEGMUg09+z/usc8mgygQ1aidA==", + "dev": true, + "dependencies": { + "lunr": "^2.3.9", + "marked": "^4.3.0", + "minimatch": "^9.0.3", + "shiki": "^0.14.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 16" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x" + } + }, "node_modules/typescript": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", @@ -1149,6 +3180,64 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, "node_modules/vite": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.4.tgz", @@ -1296,14 +3385,197 @@ "playwright": { "optional": true }, - "safaridriver": { + "safaridriver": { + "optional": true + }, + "webdriverio": { + "optional": true + } + } + }, + "node_modules/vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true + }, + "node_modules/vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", + "dev": true + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", + "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { "optional": true }, - "webdriverio": { + "webpack-dev-server": { "optional": true } } }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/why-is-node-running": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", @@ -1320,6 +3592,12 @@ "node": ">=8" } }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, "node_modules/yocto-queue": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", @@ -1334,6 +3612,12 @@ } }, "dependencies": { + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true + }, "@esbuild/android-arm": { "version": "0.19.8", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.8.tgz", @@ -1497,12 +3781,55 @@ "@sinclair/typebox": "^0.27.8" } }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, + "@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "@rollup/rollup-android-arm-eabi": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.6.1.tgz", @@ -1593,6 +3920,15 @@ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, + "@types/adm-zip": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.5.tgz", + "integrity": "sha512-YCGstVMjc4LTY5uK9/obvxBya93axZOVOyf2GSUulADzmLhYE45u2nAssCs/fWBs1Ifq5Vat75JTPwd5XZoPJw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/chai": { "version": "4.3.11", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz", @@ -1608,6 +3944,38 @@ "@types/chai": "*" } }, + "@types/eslint": { + "version": "8.44.8", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.8.tgz", + "integrity": "sha512-4K8GavROwhrYl2QXDXm0Rv9epkA8GBFu0EI+XrrnnuCl7u8CWBRusX7fXJfanhZTDWSAL24gDI/UqXyUM0Injw==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, "@types/node": { "version": "20.10.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.1.tgz", @@ -1645,53 +4013,448 @@ "integrity": "sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==", "dev": true, "requires": { - "magic-string": "^0.30.1", - "pathe": "^1.1.1", - "pretty-format": "^29.5.0" + "magic-string": "^0.30.1", + "pathe": "^1.1.1", + "pretty-format": "^29.5.0" + } + }, + "@vitest/spy": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz", + "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==", + "dev": true, + "requires": { + "tinyspy": "^2.1.1" + } + }, + "@vitest/utils": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.6.tgz", + "integrity": "sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==", + "dev": true, + "requires": { + "diff-sequences": "^29.4.3", + "loupe": "^2.3.6", + "pretty-format": "^29.5.0" + } + }, + "@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "requires": {} + }, + "@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "requires": {} + }, + "@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "requires": {} + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true + }, + "acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "requires": {} + }, + "acorn-walk": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", + "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", + "dev": true + }, + "adm-zip": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", + "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==" + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "ansi-sequence-parser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz", + "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==", + "dev": true + }, + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "assert": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" + } + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dev": true, + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", + "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.4", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.6", + "readable-stream": "^3.6.2", + "safe-buffer": "^5.2.1" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" } }, - "@vitest/spy": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz", - "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==", + "browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", "dev": true, "requires": { - "tinyspy": "^2.1.1" + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" } }, - "@vitest/utils": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.6.tgz", - "integrity": "sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==", + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "dev": true, "requires": { - "diff-sequences": "^29.4.3", - "loupe": "^2.3.6", - "pretty-format": "^29.5.0" + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, - "acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "dev": true - }, - "acorn-walk": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", - "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", - "dev": true - }, - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", "dev": true }, "cac": { @@ -1700,6 +4463,23 @@ "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true }, + "call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + } + }, + "caniuse-lite": { + "version": "1.0.30001565", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz", + "integrity": "sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==", + "dev": true + }, "chai": { "version": "4.3.10", "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", @@ -1724,6 +4504,120 @@ "get-func-name": "^2.0.2" } }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, "csv": { "version": "6.3.5", "resolved": "https://registry.npmjs.org/csv/-/csv-6.3.5.tgz", @@ -1768,12 +4662,114 @@ "type-detect": "^4.0.0" } }, + "define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, + "define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "requires": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, "diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "electron-to-chromium": { + "version": "1.4.601", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.601.tgz", + "integrity": "sha512-SpwUMDWe9tQu8JX5QCO1+p/hChAi9AE9UpoC3rcHVc+gdCGlbT3SGb5I1klgb952HRIyvt9wZhSz9bNBYz9swA==", + "dev": true + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "envinfo": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz", + "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==", + "dev": true + }, + "es-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "dev": true + }, "esbuild": { "version": "0.19.8", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.8.tgz", @@ -1804,6 +4800,104 @@ "@esbuild/win32-x64": "0.19.8" } }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, "fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1811,24 +4905,286 @@ "dev": true, "optional": true }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, "get-func-name": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true }, + "get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dev": true, + "requires": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.2" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true + }, + "is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "requires": { + "hasown": "^2.0.0" + } + }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "requires": { + "which-typed-array": "^1.1.11" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "jsonc-parser": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", "dev": true }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true + }, "local-pkg": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", "dev": true }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, "loupe": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", @@ -1838,6 +5194,12 @@ "get-func-name": "^2.0.1" } }, + "lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, "magic-string": { "version": "0.30.5", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", @@ -1847,6 +5209,83 @@ "@jridgewell/sourcemap-codec": "^1.4.15" } }, + "marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, "mlly": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz", @@ -1871,6 +5310,46 @@ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, "p-limit": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", @@ -1880,6 +5359,69 @@ "yocto-queue": "^1.0.0" } }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + }, + "dependencies": { + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + } + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dev": true, + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, "pathe": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz", @@ -1892,12 +5434,34 @@ "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "dev": true }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, "pkg-types": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", @@ -1931,12 +5495,115 @@ "react-is": "^18.0.0" } }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, "react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "requires": { + "resolve": "^1.20.0" + } + }, + "resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, "rollup": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.6.1.tgz", @@ -1958,18 +5625,124 @@ "fsevents": "~2.3.2" } }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dev": true, + "requires": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "shiki": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.5.tgz", + "integrity": "sha512-1gCAYOcmCFONmErGTrS1fjzJLA7MGZmKzrBNX7apqSwhyITJg2O102uFzXUeBxNnEkDA9vHIKLyeKq0V083vIw==", + "dev": true, + "requires": { + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, "siginfo": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, "source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -1982,11 +5755,30 @@ "integrity": "sha512-JGUEaALvL0Mf6JCfYnJOTcobY+Nc7sG/TemDRBqCA0wEr4DER7zDchaaixTlmOxAjG1uRJmX82EQcxwTQTkqVA==", "dev": true }, + "stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dev": true, + "requires": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, "stream-transform": { "version": "3.2.10", "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-3.2.10.tgz", "integrity": "sha512-Yu+x7zcWbWdyB0Td8dFzHt2JEyD6694CNq2lqh1rbuEBVxPtjb/GZ7xDnZcdYiU5E/RtufM54ClSEOzZDeWguA==" }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, "strip-literal": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz", @@ -1996,6 +5788,52 @@ "acorn": "^8.10.0" } }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, + "terser": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz", + "integrity": "sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + } + }, + "terser-webpack-plugin": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + } + }, "tinybench": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.1.tgz", @@ -2020,6 +5858,18 @@ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, + "typedoc": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.4.tgz", + "integrity": "sha512-Du9ImmpBCw54bX275yJrxPVnjdIyJO/84co0/L9mwe0R3G4FSR6rQ09AlXVRvZEGMUg09+z/usc8mgygQ1aidA==", + "dev": true, + "requires": { + "lunr": "^2.3.9", + "marked": "^4.3.0", + "minimatch": "^9.0.3", + "shiki": "^0.14.1" + } + }, "typescript": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", @@ -2038,6 +5888,44 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, "vite": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.4.tgz", @@ -2096,6 +5984,128 @@ "why-is-node-running": "^2.2.2" } }, + "vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true + }, + "vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", + "dev": true + }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "webpack": { + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", + "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + } + }, + "webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "dependencies": { + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true + } + } + }, + "webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, "why-is-node-running": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", @@ -2106,6 +6116,12 @@ "stackback": "0.0.2" } }, + "wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, "yocto-queue": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", diff --git a/package.json b/package.json index 1edb415..e923747 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,12 @@ { "name": "gtfs-io", "type": "module", - "version": "0.0.0", + "version": "0.0.1", "description": "Type definitions and IO operations for GTFS datasets", "main": "dist/index.js", "scripts": { "build": "npx tsc", + "pack": "npm run build && npx webpack", "test": "npm run build && npx vitest run --config ./vitest.config.ts" }, "repository": { @@ -22,11 +23,22 @@ }, "homepage": "https://github.com/ponlawat-w/gtfs-io#readme", "devDependencies": { + "@types/adm-zip": "^0.5.5", "@types/node": "^20.10.1", + "assert": "^2.1.0", + "browserify-zlib": "^0.2.0", + "buffer": "^6.0.3", + "crypto-browserify": "^3.12.0", + "stream-browserify": "^3.0.0", + "typedoc": "^0.25.4", "typescript": "^5.3.2", - "vitest": "^0.34.6" + "util": "^0.12.5", + "vitest": "^0.34.6", + "webpack": "^5.89.0", + "webpack-cli": "^5.1.4" }, "dependencies": { + "adm-zip": "^0.5.10", "csv": "^6.3.5" } } diff --git a/src/feed/base.ts b/src/feed/base.ts new file mode 100644 index 0000000..b32a33e --- /dev/null +++ b/src/feed/base.ts @@ -0,0 +1,157 @@ +import { GTFS_FILES } from '../file-info'; +import type { GTFSTableName } from '../file-info'; +import type { GTFSAgency } from '../files/agency'; +import type { GTFSArea } from '../files/area'; +import type { GTFSAttribution } from '../files/attribution'; +import type { GTFSCalendar } from '../files/calendar'; +import type { GTFSCalendarDate } from '../files/calendar-date'; +import type { GTFSFareAttribute } from '../files/fare-attribute'; +import type { GTFSFareLegRule } from '../files/fare-leg-rule'; +import type { GTFSFareMedia } from '../files/fare-media'; +import type { GTFSFareProduct } from '../files/fare-product'; +import type { GTFSFareRule } from '../files/fare-rule'; +import type { GTFSFareTransferRule } from '../files/fare-transfer-rule'; +import type { GTFSFeedInfo } from '../files/feed-info'; +import type { GTFSFrequency } from '../files/frequency'; +import type { GTFSLevel } from '../files/level'; +import type { GTFSNetwork } from '../files/network'; +import type { GTFSPathway } from '../files/pathway'; +import type { GTFSRoute } from '../files/route'; +import type { GTFSRouteNetwork } from '../files/route-network'; +import type { GTFSShape } from '../files/shape'; +import type { GTFSStop } from '../files/stop'; +import type { GTFSStopArea } from '../files/stop-area'; +import type { GTFSStopTime } from '../files/stop-time'; +import type { GTFSTimeframe } from '../files/timeframe'; +import type { GTFSTransfer } from '../files/transfer'; +import type { GTFSTranslation } from '../files/translation'; +import type { GTFSTrip } from '../files/trip'; +import type { GTFSAsyncFileRecords, GTFSFileRecords, GTFSFileRow, GTFSIterableFeedFiles } from '../types'; + +/** Records Generic Type: R to be collection type, and T to be row type */ +type RT = + R extends GTFSFileRow[] ? T[] : + R extends GTFSFileRecords ? GTFSFileRecords : + R extends GTFSAsyncFileRecords ? GTFSAsyncFileRecords : Iterable; + +/** + * Base Feed class + */ +export abstract class GTFSFeedBase { + /** Transit agencies with service represented in this dataset. */ + public agency: RT; + /** Stops where vehicles pick up or drop off riders. */ + public stops: RT; + /** Transit routes. A route is a group of trips that are displayed to riders as a single service. */ + public routes: RT; + /** Trips for each route. */ + public trips: RT; + /** Times that a vehicle arrives at and departs from stops for each trip. */ + public stop_times: RT; + /** Service dates specified using a weekly schedule with start and end dates. */ + public calendar?: RT; + /** Exceptions for the services defined in the `calendar.txt`. */ + public calendar_dates?: RT; + /** Fare information for a transit agency's routes. */ + public fare_attributes?: RT; + /** Rules to apply fares for itineraries. */ + public fare_rules?: RT; + /** Date and time periods to use in fare rules for fares that depend on date and time factors. */ + public timeframes?: RT; + /** To describe the fare media that can be employed to use fare products. */ + public fare_media?: RT; + /** To describe the different types of tickets or fares that can be purchased by riders. */ + public fare_products?: RT; + /** Fare rules for individual legs of travel. */ + public fare_leg_rules?: RT; + /** Fare rules for transfers between legs of travel. */ + public fare_transfer_rules?: RT; + /** Area grouping of locations. */ + public areas?: RT; + /** Rules to assign stops to areas. */ + public stop_areas?: RT; + /** Network grouping of routes. */ + public networks?: RT; + /** Rules to assign routes to networks. */ + public route_networks?: RT; + /** Rules for mapping vehicle travel paths, sometimes referred to as route alignments. */ + public shapes?: RT; + /** Headway (time between trips) for headway-based service or a compressed representation of fixed-schedule service. */ + public frequencies?: RT; + /** Rules for making connections at transfer points between routes. */ + public transfers?: RT; + /** Pathways linking together locations within stations. */ + public pathways?: RT; + /** Levels within stations. */ + public levels?: RT; + /** Translations of customer-facing dataset values. */ + public translations?: RT; + /** Dataset metadata, including publisher, version, and expiration information. */ + public feed_info?: RT; + /** Dataset attributions. */ + public attributions?: RT; + + /** + * Constructor + * @param initialValues Initial values + * @param emptyValue Default empty values of RecordsType for required table but not defined in initialValues + */ + protected constructor(initialValues: Partial>>, emptyValue: () => RecordsType) { + Object.assign(this, initialValues); + this.agency = initialValues.agency as RT ?? emptyValue; + this.stops = initialValues.stops as RT ?? emptyValue; + this.routes = initialValues.routes as RT ?? emptyValue; + this.trips = initialValues.trips as RT ?? emptyValue; + this.stop_times = initialValues.stop_times as RT ?? emptyValue; + } + + /** + * Set table records. + * @param name Table name + * @param records Value + */ + public setTable(name: GTFSTableName, records: RT) { + Object.assign(this, { [name]: records }); + } + + /** + * Get table records. + * @param name Table name + * @returns RecordsType + */ + public getTable(name: GTFSTableName): RecordsType|undefined { + return this[name]! as RecordsType; + } + + /** + * Get iterator for all existing tables. + */ + public *getAllTables(): GTFSIterableFeedFiles> { + if (this.agency !== undefined) yield { name: 'agency', info: GTFS_FILES.agency, records: this.agency }; + if (this.stops !== undefined) yield { name: 'stops', info: GTFS_FILES.stops, records: this.stops }; + if (this.routes !== undefined) yield { name: 'routes', info: GTFS_FILES.routes, records: this.routes }; + if (this.trips !== undefined) yield { name: 'trips', info: GTFS_FILES.trips, records: this.trips }; + if (this.stop_times !== undefined) yield { name: 'stop_times', info: GTFS_FILES.stop_times, records: this.stop_times }; + if (this.calendar !== undefined) yield { name: 'calendar', info: GTFS_FILES.calendar, records: this.calendar }; + if (this.calendar_dates !== undefined) yield { name: 'calendar_dates', info: GTFS_FILES.calendar_dates, records: this.calendar_dates }; + if (this.fare_attributes !== undefined) yield { name: 'fare_attributes', info: GTFS_FILES.fare_attributes, records: this.fare_attributes }; + if (this.fare_rules !== undefined) yield { name: 'fare_rules', info: GTFS_FILES.fare_rules, records: this.fare_rules }; + if (this.timeframes !== undefined) yield { name: 'timeframes', info: GTFS_FILES.timeframes, records: this.timeframes }; + if (this.fare_media !== undefined) yield { name: 'fare_media', info: GTFS_FILES.fare_media, records: this.fare_media }; + if (this.fare_products !== undefined) yield { name: 'fare_products', info: GTFS_FILES.fare_products, records: this.fare_products }; + if (this.fare_leg_rules !== undefined) yield { name: 'fare_leg_rules', info: GTFS_FILES.fare_leg_rules, records: this.fare_leg_rules }; + if (this.fare_transfer_rules !== undefined) yield { name: 'fare_transfer_rules', info: GTFS_FILES.fare_transfer_rules, records: this.fare_transfer_rules }; + if (this.areas !== undefined) yield { name: 'areas', info: GTFS_FILES.areas, records: this.areas }; + if (this.stop_areas !== undefined) yield { name: 'stop_areas', info: GTFS_FILES.stop_areas, records: this.stop_areas }; + if (this.networks !== undefined) yield { name: 'networks', info: GTFS_FILES.networks, records: this.networks }; + if (this.route_networks !== undefined) yield { name: 'route_networks', info: GTFS_FILES.route_networks, records: this.route_networks }; + if (this.shapes !== undefined) yield { name: 'shapes', info: GTFS_FILES.shapes, records: this.shapes }; + if (this.frequencies !== undefined) yield { name: 'frequencies', info: GTFS_FILES.frequencies, records: this.frequencies }; + if (this.transfers !== undefined) yield { name: 'transfers', info: GTFS_FILES.transfers, records: this.transfers }; + if (this.pathways !== undefined) yield { name: 'pathways', info: GTFS_FILES.pathways, records: this.pathways }; + if (this.levels !== undefined) yield { name: 'levels', info: GTFS_FILES.levels, records: this.levels }; + if (this.translations !== undefined) yield { name: 'translations', info: GTFS_FILES.translations, records: this.translations }; + if (this.feed_info !== undefined) yield { name: 'feed_info', info: GTFS_FILES.feed_info, records: this.feed_info }; + if (this.attributions !== undefined) yield { name: 'attributions', info: GTFS_FILES.attributions, records: this.attributions }; + } +}; diff --git a/src/feed/iterable.ts b/src/feed/iterable.ts new file mode 100644 index 0000000..583676b --- /dev/null +++ b/src/feed/iterable.ts @@ -0,0 +1,85 @@ +import { GTFSFeedBase } from './base'; +import { GTFSLoadedFeed } from './loaded'; +import type { GTFSTableName } from '../file-info'; +import type { GTFSAsyncFileRecords, GTFSFileRecords, GTFSFileRow } from '../types'; + +/** + * GTFS Feed whoose records are iterable iterator. + */ +export class GTFSIterableFeed extends GTFSFeedBase { + /** + * Constructor + * @param initialValues Initial values. + */ + public constructor(initialValues: Partial> = {}) { + super(initialValues, function*() {}); + } + + /** + * Load all table records into array and return GTFSLoadedFeed. + * BEWARE NOT TO CALL ON THE SAME TABLE TWICE AS THE RECORDS TYPE IS ITERATOR. + * @returns Loaded feed + */ + public load(): GTFSLoadedFeed { + const result = new GTFSLoadedFeed(); + for (const table of this.getAllTables()) { + result.setTable(table.name, [...table.records]); + } + return result; + } + + /** + * Convert generator of the records into asynchronous. + * BEWARE NOT TO CALL ON THE SAME TABLE TWICE AS THE RECORDS TYPE IS ITERATOR. + * @returns Async iterable feed + */ + public toAsync(): GTFSAsyncIterableFeed { + const result = new GTFSAsyncIterableFeed(); + for (const table of this.getAllTables()) { + const generator = async function*() { for (const record of table.records) yield record; }; + result.setTable(table.name, generator()); + } + return result; + } +}; + +/** + * GTFS Feed whoose records are asynchornous iterable iterator. + */ +export class GTFSAsyncIterableFeed extends GTFSFeedBase { + /** + * Constructor + * @param initialValues Initial values. + */ + public constructor(initialValues: Partial> = {}) { + super(initialValues, async function*() {}); + } + + /** + * Get records of a specific table. + * BEWARE NOT TO CALL ON THE SAME TABLE TWICE AS THE RECORDS TYPE IS ITERATOR. + * @param tableName Table name + * @returns Promise of records + */ + public async getRecords(tableName: GTFSTableName): Promise { + const results = []; + const records = this.getTable(tableName); + if (records === undefined) return []; + for await (const record of records) { + results.push(record); + } + return results; + } + + /** + * Load all table records into array and return GTFSLoadedFeed. + * @returns Loaded feed + */ + public async load(): Promise { + const result = new GTFSLoadedFeed(); + for (const table of this.getAllTables()) { + result.setTable(table.name, await this.getRecords(table.name)); + } + return result; + } +}; diff --git a/src/feed/loaded.ts b/src/feed/loaded.ts new file mode 100644 index 0000000..4cfdd7c --- /dev/null +++ b/src/feed/loaded.ts @@ -0,0 +1,42 @@ +import { GTFSFeedBase } from './base'; +import { GTFSAsyncIterableFeed, GTFSIterableFeed } from './iterable'; +import type { GTFSTableName } from '../file-info'; +import type { GTFSFileRow } from '../types'; + +/** + * GTFS Feed that is loaded into memory, records type being array. + */ +export class GTFSLoadedFeed extends GTFSFeedBase { + /** + * Constructor + * @param initialValues Initial values + */ + public constructor(initialValues: Partial> = {}) { + super(initialValues, () => []); + } + + /** + * Convert records into generator function and return an instance of iterable feed. + * @returns Iterable feed + */ + public getIterable(): GTFSIterableFeed { + const feed = new GTFSIterableFeed({}); + for (const table of this.getAllTables()) { + feed.setTable(table.name, table.records.values()); + } + return feed; + } + + /** + * Convert records into asynchronous generator function and return an instance of async iterable feed. + * @returns Async iterable feed + */ + public getAsyncIterable(): GTFSAsyncIterableFeed { + const feed = new GTFSAsyncIterableFeed({}); + for (const table of this.getAllTables()) { + const generator = async function*() { for (const record of table.records) yield record; } + feed.setTable(table.name, generator()); + } + return feed; + } +}; diff --git a/src/file-info.ts b/src/file-info.ts index edbcc1e..a81b4be 100644 --- a/src/file-info.ts +++ b/src/file-info.ts @@ -1,17 +1,56 @@ /** GTFS file information */ export type GTFSFileInfo = { + /** Table name (file name without .txt) */ + tableName: GTFSTableName, /** File name including .txt */ - name: string, - /** Columns in file name, key being column name and value being type */ - columns: Record + fileName: string, + /** + * Columns in file name, key being column name and value being type: + * string: interpret value as string (using .toString()), + * int: interpret value as integer (using parseInt()), + * float: interpret value as float (using parseFloat()), + * ioe: interpret value as integer or empty string (for enumeration) + */ + columns: Record }; /** - * GTFS Files Information + * GTFS file name */ -export const GTFSFileInfos: Record = { +export type GTFSTableName = 'agency' + | 'stops' + | 'routes' + | 'trips' + | 'stop_times' + | 'calendar' + | 'calendar_dates' + | 'fare_attributes' + | 'fare_rules' + | 'timeframes' + | 'fare_media' + | 'fare_products' + | 'fare_leg_rules' + | 'fare_transfer_rules' + | 'areas' + | 'stop_areas' + | 'networks' + | 'route_networks' + | 'shapes' + | 'frequencies' + | 'transfers' + | 'pathways' + | 'levels' + | 'translations' + | 'feed_info' + | 'attributions'; + +/** + * GTFS files information + */ +export const GTFS_FILES: Record = { agency: { - name: 'agency.txt', + tableName: 'agency', + fileName: 'agency.txt', columns: { agency_id: 'string', agency_name: 'string', @@ -24,112 +63,120 @@ export const GTFSFileInfos: Record = { } }, stops: { - name: 'stops.txt', + tableName: 'stops', + fileName: 'stops.txt', columns: { stop_id: 'string', stop_code: 'string', stop_name: 'string', tts_stop_name: 'string', stop_desc: 'string', - stop_lat: 'number', - stop_lon: 'number', + stop_lat: 'float', + stop_lon: 'float', zone_id: 'string', stop_url: 'string', - location_type: 'number', + location_type: 'int', parent_station: 'string', stop_timezone: 'string', - wheelchair_boarding: 'string', + wheelchair_boarding: 'ioe', level_id: 'string', platform_code: 'string' } }, routes: { - name: 'routes.txt', + tableName: 'routes', + fileName: 'routes.txt', columns: { route_id: 'string', agency_id: 'string', route_short_name: 'string', route_long_name: 'string', route_desc: 'string', - route_type: 'number', + route_type: 'int', route_url: 'string', route_color: 'string', route_text_color: 'string', - route_sort_order: 'number', - continuous_pickup: 'number', - continuous_drop_off: 'number', + route_sort_order: 'int', + continuous_pickup: 'ioe', + continuous_drop_off: 'ioe', network_id: 'string' } }, trips: { - name: 'trips.txt', + tableName: 'trips', + fileName: 'trips.txt', columns: { route_id: 'string', service_id: 'string', trip_id: 'string', trip_headsign: 'string', trip_short_name: 'string', - direction_id: 'number', + direction_id: 'int', block_id: 'string', shape_id: 'string', - wheelchair_accessible: 'number', - bikes_allowed: 'number' + wheelchair_accessible: 'ioe', + bikes_allowed: 'ioe' } }, stop_times: { - name: 'stop_times.txt', + tableName: 'stop_times', + fileName: 'stop_times.txt', columns: { trip_id: 'string', arrival_time: 'string', departure_time: 'string', stop_id: 'string', - stop_sequence: 'number', + stop_sequence: 'int', stop_headsign: 'string', - pickup_type: 'number', - drop_off_type: 'number', - continuous_pickup: 'number', - continuous_drop_off: 'number', - shape_dist_traveled: 'number', - timepoint: 'number' + pickup_type: 'ioe', + drop_off_type: 'ioe', + continuous_pickup: 'ioe', + continuous_drop_off: 'ioe', + shape_dist_traveled: 'float', + timepoint: 'ioe' } }, calendar: { - name: 'calendar.txt', + tableName: 'calendar', + fileName: 'calendar.txt', columns: { service_id: 'string', - monday: 'number', - tuesday: 'number', - wednesday: 'number', - thursday: 'number', - friday: 'number', - saturday: 'number', - sunday: 'number', + monday: 'int', + tuesday: 'int', + wednesday: 'int', + thursday: 'int', + friday: 'int', + saturday: 'int', + sunday: 'int', start_date: 'string', end_date: 'string' } }, calendar_dates: { - name: 'calendar_dates.txt', + tableName: 'calendar_dates', + fileName: 'calendar_dates.txt', columns: { service_id: 'string', date: 'string', - exception_type: 'number' + exception_type: 'int' } }, fare_attributes: { - name: 'fare_attributes.txt', + tableName: 'fare_attributes', + fileName: 'fare_attributes.txt', columns: { fare_id: 'string', - price: 'number', + price: 'float', currency_type: 'string', - payment_method: 'number', - transfers: 'number', + payment_method: 'int', + transfers: 'ioe', agency_id: 'string', - transfer_duration: 'number' + transfer_duration: 'float' } }, fare_rules: { - name: 'fare_rules.txt', + tableName: 'fare_rules', + fileName: 'fare_rules.txt', columns: { fare_id: 'string', route_id: 'string', @@ -139,7 +186,8 @@ export const GTFSFileInfos: Record = { } }, timeframes: { - name: 'timeframes.txt', + tableName: 'timeframes', + fileName: 'timeframes.txt', columns: { timeframe_group_id: 'string', start_time: 'string', @@ -148,25 +196,28 @@ export const GTFSFileInfos: Record = { } }, fare_media: { - name: 'fare_media.txt', + tableName: 'fare_media', + fileName: 'fare_media.txt', columns: { fare_media_id: 'string', fare_media_name: 'string', - fare_media_type: 'number' + fare_media_type: 'int' } }, fare_products: { - name: 'fare_products.txt', + tableName: 'fare_products', + fileName: 'fare_products.txt', columns: { fare_product_id: 'string', fare_product_name: 'string', fare_media_id: 'string', - amount: 'number', + amount: 'float', currency: 'string' } }, fare_leg_rules: { - name: 'fare_leg_rules.txt', + tableName: 'fare_leg_rules', + fileName: 'fare_leg_rules.txt', columns: { leg_group_id: 'string', network_id: 'string', @@ -178,67 +229,75 @@ export const GTFSFileInfos: Record = { } }, fare_transfer_rules: { - name: 'fare_transfer_rules.txt', + tableName: 'fare_transfer_rules', + fileName: 'fare_transfer_rules.txt', columns: { from_leg_group_id: 'string', to_leg_group_id: 'string', - transfer_count: 'number', - duration_limit: 'number', - duration_limit_type: 'number', - fare_transfer_type: 'number', + transfer_count: 'int', + duration_limit: 'float', + duration_limit_type: 'int', + fare_transfer_type: 'int', fare_product_id: 'string' } }, areas: { - name: 'areas.txt', + tableName: 'areas', + fileName: 'areas.txt', columns: { area_id: 'string', area_name: 'string' } }, stop_areas: { - name: 'stop_areas.txt', + tableName: 'stop_areas', + fileName: 'stop_areas.txt', columns: { area_id: 'string', stop_id: 'string' } }, networks: { - name: 'networks.txt', + tableName: 'networks', + fileName: 'networks.txt', columns: { network_id: 'string', network_name: 'string' } }, route_networks: { - name: 'route_networks.txt', + tableName: 'route_networks', + fileName: 'route_networks.txt', columns: { network_id: 'string', route_id: 'string' } }, shapes: { - name: 'shapes.txt', + tableName: 'shapes', + fileName: 'shapes.txt', columns: { shape_id: 'string', - shape_pt_lat: 'number', - shape_pt_lon: 'number', - shape_pt_sequence: 'number', - shape_dist_traveled: 'number' + shape_pt_lat: 'float', + shape_pt_lon: 'float', + shape_pt_sequence: 'int', + shape_dist_traveled: 'float' } }, frequencies: { - name: 'frequencies.txt', + tableName: 'frequencies', + fileName: 'frequencies.txt', columns: { trip_id: 'string', start_time: 'string', end_time: 'string', - headway_secs: 'number', - exact_times: 'number' + headway_secs: 'float', + exact_times: 'ioe' } }, transfers: { - name: 'transfers.txt', + tableName: 'transfers', + fileName: 'transfers.txt', columns: { from_stop_id: 'string', to_stop_id: 'string', @@ -246,37 +305,40 @@ export const GTFSFileInfos: Record = { to_route_id: 'string', from_trip_id: 'string', to_trip_id: 'string', - transfer_type: 'number', - min_transfer_time: 'number' + transfer_type: 'ioe', + min_transfer_time: 'float' } }, pathways: { - name: 'pathways.txt', + tableName: 'pathways', + fileName: 'pathways.txt', columns: { pathway_id: 'string', from_stop_id: 'string', to_stop_id: 'string', - pathway_mode: 'number', - is_bidirectional: 'number', - length: 'number', - traversal_time: 'number', - stair_count: 'number', - max_slope: 'number', - min_width: 'number', + pathway_mode: 'int', + is_bidirectional: 'int', + length: 'float', + traversal_time: 'float', + stair_count: 'float', + max_slope: 'float', + min_width: 'float', signposted_as: 'string', reversed_signposted_as: 'string' } }, levels: { - name: 'levels.txt', + tableName: 'levels', + fileName: 'levels.txt', columns: { level_id: 'string', - level_index: 'number', + level_index: 'float', level_name: 'string' } }, translations: { - name: 'translations.txt', + tableName: 'translations', + fileName: 'translations.txt', columns: { table_name: 'string', field_name: 'string', @@ -288,7 +350,8 @@ export const GTFSFileInfos: Record = { } }, feed_info: { - name: 'feed_info.txt', + tableName: 'feed_info', + fileName: 'feed_info.txt', columns: { feed_publisher_name: 'string', feed_publisher_url: 'string', @@ -302,19 +365,26 @@ export const GTFSFileInfos: Record = { } }, attributions: { - name: 'attributions.txt', + tableName: 'attributions', + fileName: 'attributions.txt', columns: { attribution_id: 'string', agency_id: 'string', route_id: 'string', trip_id: 'string', organization_name: 'string', - is_producer: 'number', - is_operator: 'number', - is_authority: 'number', + is_producer: 'int', + is_operator: 'int', + is_authority: 'int', attribution_url: 'string', attribution_email: 'string', attribution_phone: 'string', } } }; + +/** + * Get array of GTFS file infos + * @returns Array of GTFS file infos + */ +export const getGTFSFileInfos = () => Object.keys(GTFS_FILES).map(name => (GTFS_FILES as any)[name] as GTFSFileInfo); diff --git a/src/files/common.ts b/src/files/common.ts index 61a7fe8..6cc0ef1 100644 --- a/src/files/common.ts +++ b/src/files/common.ts @@ -12,3 +12,15 @@ export enum GTFSContinuousPickupDropOff { /** Must coordinate with driver to arrange continuous stopping pickup / drop off. */ Driver = 3 }; + +/** Indicates wheelchair accessibility. */ +export enum GTFSWheelchairAccessbility { + /** No accessibility information. */ + Default = '', + /** No accessibility information. */ + NoInformation = 0, + /** Accessible. */ + Accessible = 1, + /** No accessible. */ + Inaccessible = 2 +}; diff --git a/src/files/stop.ts b/src/files/stop.ts index 06e19fc..fb5ce5d 100644 --- a/src/files/stop.ts +++ b/src/files/stop.ts @@ -1,3 +1,5 @@ +import type { GTFSWheelchairAccessbility } from './common'; + /** Location Type */ export enum GTFSStopLocationType { /** A location where passengers board or disembark from a transit vehicle. */ @@ -30,7 +32,7 @@ type StopBase = { /** Timezone of the location. */ stop_timezone?: string, /** Indicates whether wheelchair boardings are possible from the location. */ - wheelchair_boarding?: string, + wheelchair_boarding?: GTFSWheelchairAccessbility, /** Level of the location. */ level_id?: string, /** Platform identifier for a platform stop (a stop belonging to a station). */ diff --git a/src/files/trip.ts b/src/files/trip.ts index 591afc2..479b1eb 100644 --- a/src/files/trip.ts +++ b/src/files/trip.ts @@ -1,3 +1,5 @@ +import { GTFSWheelchairAccessbility } from './common'; + /** Indicates the direction of travel for a trip. */ export enum GTFSTripDirection { /** Travel in one direction (e.g. outbound travel). */ @@ -6,18 +8,10 @@ export enum GTFSTripDirection { OppositeDirection = 1 }; -/** Indicates wheelchair accessibility. */ -export enum GTFSTripWheelchairAccessbility { - /** No accessibility information for the trip. */ - NoInformation = 0, - /** Vehicle being used on this particular trip can accommodate at least one rider in a wheelchair. */ - Accessible = 1, - /** No riders in wheelchairs can be accommodated on this trip. */ - Inaccessible = 2 -}; - /** Indicates whether bikes are allowed. */ export enum GTFSTripBikesAllowed { + /** No bike information for the trip. */ + Empty = '', /** No bike information for the trip. */ NoInformation = 0, /** Vehicle being used on this particular trip can accommodate at least one bicycle. */ @@ -45,7 +39,7 @@ export type GTFSTrip = { /** Identifies a geospatial shape describing the vehicle travel path for a trip. */ shape_id?: string, /** Indicates wheelchair accessibility. */ - wheelchair_accessible?: GTFSTripWheelchairAccessbility|'', + wheelchair_accessible?: GTFSWheelchairAccessbility, /** Indicates whether bikes are allowed. */ - bikes_allowed?: GTFSTripBikesAllowed|'', + bikes_allowed?: GTFSTripBikesAllowed, }; diff --git a/src/index.ts b/src/index.ts index 3f16e4c..4e4ea82 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,15 @@ -export { default as GTFSFileIO } from './io/file'; +export { GTFSFileIO, GTFSAsyncFileIO } from './io/file'; +export * from './io/feed-file'; +export { GTFSFeedReader, GTFSAsyncFeedReader } from './io/feed-reader'; +export { GTFSFeedWriter, GTFSAsyncFeedWriter } from './io/feed-writer'; -export { GTFSFileInfos } from './file-info'; +export * from './feed/iterable'; +export * from './feed/loaded'; +export * from './file-info'; export { GTFSCalendarDateException } from './files/calendar-date'; export { GTFSCalendarAvailability } from './files/calendar'; -export { GTFSContinuousPickupDropOff } from './files/common'; +export { GTFSContinuousPickupDropOff, GTFSWheelchairAccessbility } from './files/common'; export { GTFSFareAttributePaymentMethod, GTFSFareAttributeTransfer } from './files/fare-attribute'; export { GTFSFareMediaType } from './files/fare-media'; export { GTFSFareTransferRuleDurationLimit, GTFSFareTransferRuleType } from './files/fare-transfer-rule'; @@ -14,11 +19,13 @@ export { GTFSRouteType } from './files/route'; export { GTFSStopTimePickupDropOff, GTFSStopTimeTimepoint } from './files/stop-time'; export { GTFSStopLocationType } from './files/stop'; export { GTFSTranferType } from './files/transfer'; -export { GTFSTripDirection, GTFSTripWheelchairAccessbility, GTFSTripBikesAllowed } from './files/trip'; +export { GTFSTripDirection, GTFSTripBikesAllowed } from './files/trip'; export type * from './file-info'; export type * from './types'; +export type * from './io/types'; + export type * from './files/agency'; export type * from './files/area'; export type * from './files/attribution'; diff --git a/src/io/feed-file.ts b/src/io/feed-file.ts new file mode 100644 index 0000000..2e16f90 --- /dev/null +++ b/src/io/feed-file.ts @@ -0,0 +1,349 @@ +import { GTFSAsyncFileIO, GTFSFileIO } from './file'; +import { GTFS_FILES } from '../file-info'; +import type { GTFSFileInfo } from '../file-info'; +import type { GTFSFileRow } from '../types'; +import type { GTFSAgency } from '../files/agency'; +import type { GTFSStop } from '../files/stop'; +import type { GTFSRoute } from '../files/route'; +import type { GTFSTrip } from '../files/trip'; +import type { GTFSStopTime } from '../files/stop-time'; +import type { GTFSCalendar } from '../files/calendar'; +import type { GTFSCalendarDate } from '../files/calendar-date'; +import type { GTFSFareAttribute } from '../files/fare-attribute'; +import type { GTFSFareRule } from '../files/fare-rule'; +import type { GTFSTimeframe } from '../files/timeframe'; +import type { GTFSFareMedia } from '../files/fare-media'; +import type { GTFSFareProduct } from '../files/fare-product'; +import type { GTFSFareLegRule } from '../files/fare-leg-rule'; +import type { GTFSFareTransferRule } from '../files/fare-transfer-rule'; +import type { GTFSArea } from '../files/area'; +import type { GTFSStopArea } from '../files/stop-area'; +import type { GTFSNetwork } from '../files/network'; +import type { GTFSRouteNetwork } from '../files/route-network'; +import type { GTFSShape } from '../files/shape'; +import type { GTFSFrequency } from '../files/frequency'; +import type { GTFSTransfer } from '../files/transfer'; +import type { GTFSPathway } from '../files/pathway'; +import type { GTFSLevel } from '../files/level'; +import type { GTFSTranslation } from '../files/translation'; +import type { GTFSFeedInfo } from '../files/feed-info'; +import type { GTFSAttribution } from '../files/attribution'; +import { GTFSIOWriteOptions } from './types'; + +/** + * IO operations of feed file. + */ +abstract class FeedFileIO { + /** File information */ + protected fileInfo: GTFSFileInfo; + + /** + * File name including .txt. + */ + public get fileName(): string { + return this.fileInfo.fileName; + } + + /** + * File columns + */ + public get columns(): string[] { + return Object.keys(this.fileInfo.columns); + } + + /** + * Constructor + * @param file File information + */ + public constructor(file: GTFSFileInfo) { + this.fileInfo = file; + } +} + +/** + * Class for IO operations on a GTFS feed file + */ +export class GTFSFeedFileIO extends FeedFileIO { + /** + * Read lines into records. + * @param chunks Iterable file content chunks + * @returns Iterable records + */ + public *read(chunks: IterableIterator): IterableIterator { + yield *GTFSFileIO.read(this.fileInfo, chunks); + return; + } + + /** + * Write records into lines. + * @param records Iterable records + * @returns Iterable lines + */ + public *write(records: IterableIterator): IterableIterator { + yield *GTFSFileIO.write(this.fileInfo, records); + return; + } + + /** + * Read file content into records array. + * @param content File content + * @returns Records array + */ + public readContent(content: string): RowType[] { + return GTFSFileIO.readContent(this.fileInfo, content); + } + + /** + * Write records array into file content. + * @param records Records array + * @returns File content + */ + public writeContent(records: RowType[]): string { + return GTFSFileIO.writeContent(this.fileInfo, records); + } +}; + +/** + * Class for asynchronous IO operations on a GTFS feed file + */ +export class GTFSAsyncFeedFileIO extends FeedFileIO { + /** + * Read lines into records. + * @param chunks Iterable file content chunks + * @returns Iterable records + */ + public async *read(chunks: AsyncIterableIterator): AsyncIterableIterator { + yield *GTFSAsyncFileIO.read(this.fileInfo, chunks); + return; + } + + /** + * Write records into lines. + * @param records Iterable records + * @returns Iterable lines + */ + public async *write(records: AsyncIterableIterator): AsyncIterableIterator { + yield *GTFSAsyncFileIO.write(this.fileInfo, records); + return; + } + + /** + * Await for all chunks and return all the records. + * @param chunks Chunks generator + * @returns Promise of all records + */ + public async readAll(chunks: AsyncIterableIterator): Promise { + return GTFSAsyncFileIO.readAll(this.fileInfo, chunks); + } + + /** + * Read file content and return all the records. + * @param content File content + * @returns Promise of all records + */ + public async readAllContent(content: string): Promise { + return GTFSAsyncFileIO.readAllContent(this.fileInfo, content); + } + + /** + * Await for all records and return file content. + * @param records Records generator + * @param options Write options + * @returns Promise of file content + */ + public async writeAll(records: AsyncIterableIterator, options?: GTFSIOWriteOptions): Promise { + return GTFSAsyncFileIO.writeAll(this.fileInfo, records, options); + } + + /** + * Write file content from given records. + * @param records Records array + * @param options Write options + * @returns Promise of all records + */ + public async writeAllRecords(records: RowType[], options?: GTFSIOWriteOptions): Promise { + return GTFSAsyncFileIO.writeAllRecords(this.fileInfo, records, options); + } +} + +/** IO Operations for agency.txt file */ +export class GTFSAgencyIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.agency); } } +/** Async IO Operations for agency.txt file */ +export class GTFSAsyncAgencyIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.agency); } } + +/** IO Operations for stops.txt file */ +export class GTFSStopIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.stops); } } +/** Async IO Operations for stops.txt file */ +export class GTFSAsyncStopIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.stops); } } + +/** IO Operations for routes.txt file */ +export class GTFSRouteIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.routes); } } +/** Async IO Operations for routes.txt file */ +export class GTFSAsyncRouteIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.routes); } } + +/** IO Operations for trips.txt file */ +export class GTFSTripIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.trips); } } +/** Async IO Operations for trips.txt file */ +export class GTFSAsyncTripIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.trips); } } + +/** IO Operations for stop_times.txt file */ +export class GTFSStopTimeIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.stop_times); } } +/** Async IO Operations for stop_times.txt file */ +export class GTFSAsyncStopTimeIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.stop_times); } } + +/** IO Operations for calendar.txt file */ +export class GTFSCalendarIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.calendar); } } +/** Async IO Operations for calendar.txt file */ +export class GTFSAsyncCalendarIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.calendar); } } + +/** IO Operations for calendar_dates.txt file */ +export class GTFSCalendarDateIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.calendar_dates); } } +/** Async IO Operations for calendar_dates.txt file */ +export class GTFSAsyncCalendarDateIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.calendar_dates); } } + +/** IO Operations for fare_attributes.txt file */ +export class GTFSFareAttributeIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.fare_attributes); } } +/** Async IO Operations for fare_attributes.txt file */ +export class GTFSAsyncFareAttributeIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.fare_attributes); } } + +/** IO Operations for fare_rules.txt file */ +export class GTFSFareRuleIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.fare_rules); } } +/** Async IO Operations for fare_rules.txt file */ +export class GTFSAsyncFareRuleIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.fare_rules); } } + +/** IO Operations for timeframes.txt file */ +export class GTFSTimeframeIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.timeframes); } } +/** Async IO Operations for timeframes.txt file */ +export class GTFSAsyncTimeframeIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.timeframes); } } + +/** IO Operations for fare_media.txt file */ +export class GTFSFareMediaIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.fare_media); } } +/** Async IO Operations for fare_media.txt file */ +export class GTFSAsyncFareMediaIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.fare_media); } } + +/** IO Operations for fare_products.txt file */ +export class GTFSFareProductIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.fare_products); } } +/** Async IO Operations for fare_products.txt file */ +export class GTFSAsyncFareProductIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.fare_products); } } + +/** IO Operations for fare_leg_rules.txt file */ +export class GTFSFareLegRuleIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.fare_leg_rules); } } +/** Async IO Operations for fare_leg_rules.txt file */ +export class GTFSAsyncFareLegRuleIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.fare_leg_rules); } } + +/** IO Operations for fare_transfer_rules.txt file */ +export class GTFSFareTransferRuleIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.fare_transfer_rules); } } +/** Async IO Operations for fare_transfer_rules.txt file */ +export class GTFSAsyncFareTransferRuleIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.fare_transfer_rules); } } + +/** IO Operations for areas.txt file */ +export class GTFSAreaIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.areas); } } +/** Async IO Operations for areas.txt file */ +export class GTFSAsyncAreaIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.areas); } } + +/** IO Operations for stop_areas.txt file */ +export class GTFSStopAreaIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.stop_areas); } } +/** Async IO Operations for stop_areas.txt file */ +export class GTFSAsyncStopAreaIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.stop_areas); } } + +/** IO Operations for networks.txt file */ +export class GTFSNetworkIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.networks); } } +/** Async IO Operations for networks.txt file */ +export class GTFSAsyncNetworkIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.networks); } } + +/** IO Operations for route_networks.txt file */ +export class GTFSRouteNetworkIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.route_networks); } } +/** Async IO Operations for route_networks.txt file */ +export class GTFSAsyncRouteNetworkIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.route_networks); } } + +/** IO Operations for shapes.txt file */ +export class GTFSShapeIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.shapes); } } +/** Async IO Operations for shapes.txt file */ +export class GTFSAsyncShapeIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.shapes); } } + +/** IO Operations for frequencies.txt file */ +export class GTFSFrequencyIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.frequencies); } } +/** Async IO Operations for frequencies.txt file */ +export class GTFSAsyncFrequencyIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.frequencies); } } + +/** IO Operations for transfers.txt file */ +export class GTFSTransferIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.transfers); } } +/** Async IO Operations for transfers.txt file */ +export class GTFSAsyncTransferIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.transfers); } } + +/** IO Operations for pathways.txt file */ +export class GTFSPathwayIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.pathways); } } +/** Async IO Operations for pathways.txt file */ +export class GTFSAsyncPathwayIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.pathways); } } + +/** IO Operations for levels.txt file */ +export class GTFSLevelIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.levels); } } +/** Async IO Operations for levels.txt file */ +export class GTFSAsyncLevelIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.levels); } } + +/** IO Operations for translations.txt file */ +export class GTFSTranslationIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.translations); } } +/** Async IO Operations for translations.txt file */ +export class GTFSAsyncTranslationIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.translations); } } + +/** IO Operations for feed_info.txt file */ +export class GTFSFeedInfoIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.feed_info); } } +/** Async IO Operations for feed_info.txt file */ +export class GTFSAsyncFeedInfoIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.feed_info); } } + +/** IO Operations for attributions.txt file */ +export class GTFSAttributionIO extends GTFSFeedFileIO { public constructor() { super(GTFS_FILES.attributions); } } +/** Async IO Operations for attributions.txt file */ +export class GTFSAsyncAttributionIO extends GTFSAsyncFeedFileIO { public constructor() { super(GTFS_FILES.attributions); } } + +/** + * Get feed file IO instance from file name. + * @param fileName File name with .txt + * @param async True for async IO class instance + * @returns GTFSFeedFileIO + */ +const fileNameToIO = (fileName: string, async: boolean): GTFSFeedFileIO|GTFSAsyncFileIO => { + switch(fileName) { + case 'agency.txt': return async ? new GTFSAsyncAgencyIO() : new GTFSAgencyIO(); + case 'stops.txt': return async ? new GTFSAsyncStopIO() : new GTFSStopIO(); + case 'routes.txt': return async ? new GTFSAsyncRouteIO() : new GTFSRouteIO(); + case 'trips.txt': return async ? new GTFSAsyncTripIO() : new GTFSTripIO(); + case 'stop_times.txt': return async ? new GTFSAsyncStopTimeIO() : new GTFSStopTimeIO(); + case 'calendar.txt': return async ? new GTFSAsyncCalendarIO() : new GTFSCalendarIO(); + case 'calendar_dates.txt': return async ? new GTFSAsyncCalendarDateIO() : new GTFSCalendarDateIO(); + case 'fare_attributes.txt': return async ? new GTFSAsyncFareAttributeIO() : new GTFSFareAttributeIO(); + case 'fare_rules.txt': return async ? new GTFSAsyncFareRuleIO() : new GTFSFareRuleIO(); + case 'timeframes.txt': return async ? new GTFSAsyncTimeframeIO() : new GTFSTimeframeIO(); + case 'fare_media.txt': return async ? new GTFSAsyncFareMediaIO() : new GTFSFareMediaIO(); + case 'fare_products.txt': return async ? new GTFSAsyncFareProductIO() : new GTFSFareProductIO(); + case 'fare_leg_rules.txt': return async ? new GTFSAsyncFareLegRuleIO() : new GTFSFareLegRuleIO(); + case 'fare_transfer_rules.txt': return async ? new GTFSAsyncFareTransferRuleIO() : new GTFSFareTransferRuleIO(); + case 'areas.txt': return async ? new GTFSAsyncAreaIO() : new GTFSAreaIO(); + case 'stop_areas.txt': return async ? new GTFSAsyncStopAreaIO() : new GTFSStopAreaIO(); + case 'networks.txt': return async ? new GTFSAsyncNetworkIO() : new GTFSNetworkIO(); + case 'route_networks.txt': return async ? new GTFSAsyncRouteNetworkIO() : new GTFSRouteNetworkIO(); + case 'shapes.txt': return async ? new GTFSAsyncShapeIO() : new GTFSShapeIO(); + case 'frequencies.txt': return async ? new GTFSAsyncFrequencyIO() : new GTFSFrequencyIO(); + case 'transfers.txt': return async ? new GTFSAsyncTransferIO() : new GTFSTransferIO(); + case 'pathways.txt': return async ? new GTFSAsyncPathwayIO() : new GTFSPathwayIO(); + case 'levels.txt': return async ? new GTFSAsyncLevelIO() : new GTFSLevelIO(); + case 'translations.txt': return async ? new GTFSAsyncTranslationIO() : new GTFSTranslationIO(); + case 'feed_info.txt': return async ? new GTFSAsyncFeedInfoIO() : new GTFSFeedInfoIO(); + case 'attributions.txt': return async ? new GTFSAsyncAttributionIO() : new GTFSAttributionIO(); + } + throw new Error(`Unknown file name ${fileName}`); +}; + +/** + * Get feed file IO instance from file name. + * @param fileName File name with .txt + * @returns GTFSFeedFileIO + */ +export const getIOFromFileName = (fileName: string): GTFSFeedFileIO => fileNameToIO(fileName, false) as GTFSFeedFileIO; + +/** + * Get feed file async IO instance from file name. + * @param fileName File name with .txt + * @returns GTFSAsyncFeedFileIO + */ +export const getAsyncIOFromFileName = (fileName: string): GTFSAsyncFeedFileIO => fileNameToIO(fileName, true) as GTFSAsyncFeedFileIO; diff --git a/src/io/feed-reader.ts b/src/io/feed-reader.ts new file mode 100644 index 0000000..469cb10 --- /dev/null +++ b/src/io/feed-reader.ts @@ -0,0 +1,318 @@ +import AdmZip from 'adm-zip'; +import { + existsSync as exists, + openSync as openFile, + read as readAsync, + readSync as readFileSync +} from 'fs'; +import { join as joinPath } from 'path'; +import { getAsyncIOFromFileName, getIOFromFileName } from './feed-file'; +import { getGTFSFileInfos } from '../file-info'; +import { GTFSFeedBase } from '../feed/base'; +import { GTFSLoadedFeed } from '../feed/loaded'; +import { GTFSAsyncIterableFeed, GTFSIterableFeed } from '../feed/iterable'; +import type { GTFSFileInfo } from '../file-info'; +import type { GTFSAsyncFileRecords, GTFSFileContent, GTFSFileRecords } from '../types'; + +/** + * GTFS file object to read + */ +type GTFSFile = { + /** File information */ + info: GTFSFileInfo, + /** File path */ + path?: string, + /** File content buffer */ + buffer?: Buffer +}; + +/** + * GTFS feed reader abstract + */ +abstract class FeedReader|Promise>> { + /** Zip object */ + protected zip?: AdmZip = undefined; + + /** File objects */ + protected files?: GTFSFile[] = undefined; + + /** + * Constructor, the object of this class is to be created by static methods. + * The constructor is limited for internal calling. + * @param zip Zip file path or buffer + * @param directoryPath Directory path + * @param fileContents Array of file content objects + */ + protected constructor( + zip?: string|Buffer|ArrayBuffer, + directoryPath?: string, + fileContents?: GTFSFileContent[] + ) { + if (zip) { + this.zip = new AdmZip(typeof zip === 'string' || Buffer.isBuffer(zip) ? zip : Buffer.from(zip)); + return; + } + this.files = []; + if (directoryPath) { + for (const info of getGTFSFileInfos()) { + const path = joinPath(directoryPath, info.fileName); + if (!exists(path)) continue; + this.files.push({ info, path }); + } + return; + } + if (fileContents) { + for (const info of getGTFSFileInfos()) { + const file = fileContents.filter(f => f.name === info.fileName); + if (!file.length) continue; + this.files.push({ info, buffer: Buffer.from(file[0].content) }) + } + return; + } + } + + /** + * Get records from an AdmZip entry. + * @param info File information + * @param entry Zip entry + */ + protected abstract getRecordsFromZipEntry(info: GTFSFileInfo, entry: AdmZip.IZipEntry): RecordsType; + /** + * Get records from file path. + * @param info File information + * @param path File path + */ + protected abstract getRecordsFromFilePath(info: GTFSFileInfo, path: string): RecordsType; + /** + * Get records from file content. + * @param info File information + * @param content File content buffer + */ + protected abstract getRecordsFromFileContent(info: GTFSFileInfo, content: Buffer): RecordsType; + /** + * Read all records and load into array in memory. + */ + public abstract loadFeed(): GTFSLoadedFeed|Promise; + + /** + * From file information, get records. + * Undefined if file does not exist in the feed. + * @param info file information + * @returns Records + */ + public getRecords(info: GTFSFileInfo): RecordsType|undefined { + if (this.zip) { + const entry = this.zip.getEntries().filter(entry => entry.entryName === info.fileName); + if (!entry.length) return undefined; + return this.getRecordsFromZipEntry(info, entry[0]); + } else if (this.files) { + const file = this.files.filter(f => f.info.fileName === info.fileName); + if (!file.length) return undefined; + if (file[0].path) { + return this.getRecordsFromFilePath(info, file[0].path); + } else if (file[0].buffer) { + return this.getRecordsFromFileContent(info, file[0].buffer); + } + } + return undefined; + } + + /** + * Get feed object with row being file name without .txt and value being iterable records. + * @returns Feed object with row being file name without .txt and value being iterable records. + */ + public abstract getFeed(): FeedType; +}; + +/** + * GTFS feed reader. + * Do not use constructor, instead, use the following static methods to initiate an instance: + * GTFSFeedReader.fromZip, + * GTFSFeedReader.fromDirectory, + * GTFSFeedReader.fromFiles + */ +export class GTFSFeedReader extends FeedReader { + /** + * Generator of iterable chunks from a file path. + * @param filePath File path + * @returns Iterable file chunks + */ + private static *readFileChunks(filePath: string): IterableIterator { + const file = openFile(filePath, 'r'); + const bufferSize = 1024; + const buffer = Buffer.alloc(bufferSize); + let leftOver = ''; + + let readPos; + while ((readPos = readFileSync(file, buffer, 0, bufferSize, null)) !== 0) { + const content = leftOver + buffer.toString('utf8', 0, readPos); + const newLineIdx = content.lastIndexOf('\n'); + yield content.slice(0, newLineIdx); + leftOver = content.slice(newLineIdx); + } + + if (leftOver) yield leftOver; + return; + } + + protected getRecordsFromZipEntry(info: GTFSFileInfo, entry: AdmZip.IZipEntry): GTFSFileRecords { + const io = getIOFromFileName(info.fileName); + return io.readContent(entry.getData().toString()).values(); + } + + protected *getRecordsFromFilePath(info: GTFSFileInfo, path: string): GTFSFileRecords { + const io = getIOFromFileName(info.fileName); + const chunks = GTFSFeedReader.readFileChunks(path); + for (const record of io.read(chunks)) { + yield record; + } + } + + protected getRecordsFromFileContent(info: GTFSFileInfo, content: Buffer): GTFSFileRecords { + const io = getIOFromFileName(info.fileName); + return io.readContent(content.toString()).values(); + } + + public getFeed(): GTFSIterableFeed { + const feed = new GTFSIterableFeed(); + + for (const fileInfo of getGTFSFileInfos()) { + const records = this.getRecords(fileInfo); + if (records === undefined) continue; + feed.setTable(fileInfo.tableName, records); + } + + return feed; + } + + public loadFeed(): GTFSLoadedFeed { + return this.getFeed().load(); + } + + /** + * Create an instance of GTFSFeedWriter from zip file. + * @param zip Zip file path or content buffer + * @returns GTFSFeedWriter instance + */ + public static fromZip(zip: string|Buffer|ArrayBuffer): GTFSFeedReader { + return new GTFSFeedReader(zip); + } + + /** + * Create an instance of GTFSFeedWriter from directory path. + * @param dirPath Path to GTFS feed directory + * @returns GTFSFeedWriter instance + */ + public static fromDirectoy(dirPath: string): GTFSFeedReader { + return new GTFSFeedReader(undefined, dirPath); + } + + /** + * Create an instance of GTFSFeedWriter from in-memory file contents. + * @param files Feed files object + * @returns GTFSFeedWriter instance + */ + public static fromFiles(files: GTFSFileContent[]): GTFSFeedReader { + return new GTFSFeedReader(undefined, undefined, files); + } +}; + +/** + * GTFS feed reader. + * Do not use constructor, instead, use the following static methods to initiate an instance: + * GTFSFeedReader.fromZip, + * GTFSFeedReader.fromDirectory, + * GTFSFeedReader.fromFiles + */ +export class GTFSAsyncFeedReader extends FeedReader> { + /** + * Generator of iterable chunks from a file path. + * @param filePath File path + * @returns Iterable file chunks + */ + private static async *readFileChunks(filePath: string): AsyncIterableIterator { + const file = openFile(filePath, 'r'); + const bufferSize = 1024; + const buffer = Buffer.alloc(bufferSize); + let leftOver = ''; + + const reads = (): Promise => new Promise((resolve, reject) => { + readAsync(file, buffer, 0, bufferSize, null, (err, pos) => { + if (err) return reject(err); + resolve(pos); + }); + }); + + let readPos = -1; + while (readPos !== 0) { + readPos = await reads(); + const content = leftOver + buffer.toString('utf8', 0, readPos); + const newLineIdx = content.lastIndexOf('\n'); + yield content.slice(0, newLineIdx); + leftOver = content.slice(newLineIdx); + } + + if (leftOver) yield leftOver; + return; + } + + protected getRecordsFromZipEntry(info: GTFSFileInfo, entry: AdmZip.IZipEntry): GTFSAsyncFileRecords { + const io = getAsyncIOFromFileName(info.fileName); + const generator = async function*() { yield entry.getData().toString(); }; + return io.read(generator()); + } + + protected getRecordsFromFilePath(info: GTFSFileInfo, path: string): GTFSAsyncFileRecords { + const io = getAsyncIOFromFileName(info.fileName); + return io.read(GTFSAsyncFeedReader.readFileChunks(path)); + } + + protected getRecordsFromFileContent(info: GTFSFileInfo, content: Buffer): GTFSAsyncFileRecords { + const io = getAsyncIOFromFileName(info.fileName); + const generator = async function*() { yield content.toString(); }; + return io.read(generator()); + } + + public async getFeed(): Promise { + const feed = new GTFSAsyncIterableFeed(); + + for (const fileInfo of getGTFSFileInfos()) { + const records = this.getRecords(fileInfo); + if (records === undefined) continue; + feed.setTable(fileInfo.tableName, records); + } + + return feed; + } + + public async loadFeed(): Promise { + return (await this.getFeed()).load(); + } + + /** + * Create an instance of GTFSFeedWriter from zip file. + * @param zip Zip file path or content buffer + * @returns GTFSFeedWriter instance + */ + public static fromZip(zip: string|Buffer|ArrayBuffer): GTFSAsyncFeedReader { + return new GTFSAsyncFeedReader(zip); + } + + /** + * Create an instance of GTFSFeedWriter from directory path. + * @param dirPath Path to GTFS feed directory + * @returns GTFSFeedWriter instance + */ + public static fromDirectoy(dirPath: string): GTFSAsyncFeedReader { + return new GTFSAsyncFeedReader(undefined, dirPath); + } + + /** + * Create an instance of GTFSFeedWriter from in-memory file contents. + * @param files Feed files object + * @returns GTFSFeedWriter instance + */ + public static fromFiles(files: GTFSFileContent[]): GTFSAsyncFeedReader { + return new GTFSAsyncFeedReader(undefined, undefined, files); + } +} diff --git a/src/io/feed-writer.ts b/src/io/feed-writer.ts new file mode 100644 index 0000000..d2b528c --- /dev/null +++ b/src/io/feed-writer.ts @@ -0,0 +1,175 @@ +import AdmZip from 'adm-zip'; +import { appendFileSync, existsSync, mkdirSync, writeFileSync } from 'fs'; +import { join as joinPath } from 'path'; +import { getAsyncIOFromFileName, getIOFromFileName } from './feed-file'; +import { GTFSAsyncIterableFeed, GTFSIterableFeed } from '../feed/iterable'; +import { GTFSLoadedFeed } from '../feed/loaded'; +import type { GTFSFileContent } from '../types'; + +/** + * GTFS feed writer. + * For static usage only. + */ +export class GTFSFeedWriter { + private constructor() {} + + /** + * Create a zip instance in memory. + * @param feed GTFS Feed + * @returns AdmZip instance + */ + public static createZip(feed: GTFSIterableFeed|GTFSLoadedFeed): AdmZip { + if (feed instanceof GTFSLoadedFeed) feed = feed.getIterable(); + + const zip = new AdmZip(); + for (const table of feed.getAllTables()) { + const io = getIOFromFileName(table.info.fileName); + zip.addFile( + io.fileName, + Buffer.from([...io.write(table.records)].join('')) + ); + } + return zip; + } + + /** + * Create file contents in memory. + * @param feed GTFS Feed + * @returns File contents + */ + public static createFileContents(feed: GTFSIterableFeed|GTFSLoadedFeed): GTFSFileContent[] { + if (feed instanceof GTFSLoadedFeed) feed = feed.getIterable(); + + const fileContents: GTFSFileContent[] = []; + for (const table of feed.getAllTables()) { + const io = getIOFromFileName(table.info.fileName); + fileContents.push({ + name: io.fileName, + content: [...io.write(table.records)].join('') + }); + } + return fileContents; + } + + /** + * Create a zip of GTFS feed and write to the specific path. + * @param feed GTFS Feed + * @param path Path to output zip file + */ + public static writeZip(feed: GTFSIterableFeed|GTFSLoadedFeed, path: string): void { + GTFSFeedWriter.createZip(feed).writeZip(path); + } + + /** + * Write GTFS feed to the specific directory path. + * @param feed GTFS Feed + * @param path Path to output directory + * @param mkdirIfNotExists True to recursively create a directory at the path if does not exist + * @returns File names without directory path, with .txt extension. + */ + public static writeDirectory(feed: GTFSIterableFeed|GTFSLoadedFeed, path: string, mkdirIfNotExists: boolean = true): string[] { + if (feed instanceof GTFSLoadedFeed) feed = feed.getIterable(); + + if (!existsSync(path) && mkdirIfNotExists) { + mkdirSync(path, { recursive: true }); + } + const fileNames = []; + for (const table of feed.getAllTables()) { + const io = getIOFromFileName(table.info.fileName); + const filePath = joinPath(path, io.fileName); + writeFileSync(filePath, ''); + const contents = io.write(table.records); + for (const content of contents) { + appendFileSync(filePath, content); + } + fileNames.push(io.fileName); + } + return fileNames; + } +}; + +/** + * GTFS feed writer. + * For static usage only. + */ +export class GTFSAsyncFeedWriter { + private constructor() {} + + /** + * Create a zip instance in memory. + * @param feed GTFS Feed + * @returns AdmZip instance + */ + public static async createZip(feed: GTFSAsyncIterableFeed|GTFSIterableFeed|GTFSLoadedFeed): Promise { + if (feed instanceof GTFSLoadedFeed) feed = feed.getAsyncIterable(); + else if (feed instanceof GTFSIterableFeed) feed = feed.toAsync(); + + const zip = new AdmZip(); + for (const table of feed.getAllTables()) { + const io = getAsyncIOFromFileName(table.info.fileName); + zip.addFile( + io.fileName, + Buffer.from(await io.writeAll(table.records)) + ); + } + return zip; + } + + /** + * Create file contents in memory. + * @param feed GTFS Feed + * @returns File contents + */ + public static async createFileContents(feed: GTFSAsyncIterableFeed|GTFSIterableFeed|GTFSLoadedFeed): Promise { + if (feed instanceof GTFSLoadedFeed) feed = feed.getAsyncIterable(); + else if (feed instanceof GTFSIterableFeed) feed = feed.toAsync(); + + const fileContents: GTFSFileContent[] = []; + for (const table of feed.getAllTables()) { + const io = getAsyncIOFromFileName(table.info.fileName); + fileContents.push({ + name: io.fileName, + content: await io.writeAll(table.records) + }); + } + return fileContents; + } + + /** + * Create a zip of GTFS feed and write to the specific path. + * @param feed GTFS Feed + * @param path Path to output zip file + */ + public static async writeZip(feed: GTFSAsyncIterableFeed|GTFSIterableFeed|GTFSLoadedFeed, path: string): Promise { + (await GTFSAsyncFeedWriter.createZip(feed)).writeZip(path); + } + + /** + * Write GTFS feed to the specific directory path. + * @param feed GTFS Feed + * @param path Path to output directory + * @param mkdirIfNotExists True to recursively create a directory at the path if does not exist + * @returns File names without directory path, with .txt extension. + */ + public static async writeDirectory(feed: GTFSAsyncIterableFeed|GTFSIterableFeed|GTFSLoadedFeed, path: string, mkdirIfNotExists: boolean = true): Promise { + if (feed instanceof GTFSLoadedFeed) feed = feed.getAsyncIterable(); + else if (feed instanceof GTFSIterableFeed) feed = feed.toAsync(); + + if (!existsSync(path) && mkdirIfNotExists) { + mkdirSync(path, { recursive: true }); + } + const fileNames = []; + for (const table of feed.getAllTables()) { + const io = getAsyncIOFromFileName(table.info.fileName); + const filePath = joinPath(path, io.fileName); + writeFileSync(filePath, ''); + const contents = io.write(table.records); + for await (const content of contents) { + appendFileSync(filePath, content); + } + fileNames.push(io.fileName); + } + return fileNames; + } +}; + diff --git a/src/io/file.ts b/src/io/file.ts index 269506d..a58378c 100644 --- a/src/io/file.ts +++ b/src/io/file.ts @@ -1,41 +1,201 @@ -import { stringify, parse } from 'csv/sync'; -import { GTFSRow } from '../types'; -import { GTFSFileInfo } from '../file-info'; - -export default class GTFSFileIO { - private constructor() {} - - public static *read(file: GTFSFileInfo, lines: IterableIterator): IterableIterator { - const head = lines.next(); - if (head.done) return; - if (!head.value || !head.value.trim()) return; - let columns = (parse(head.value) as string[][])[0] - .map(c => c.trim()) - .filter(c => file.columns[c]); - - for (const line of lines) { - if (!line.trim()) continue; - let row = (parse(line) as string[][])[0].slice(0, columns.length); - let record: Record = {}; - - for (let i = 0; i < row.length; i++) { - const column = file.columns[columns[i]]; - record[columns[i]] = column === 'string' ? row[i].toString() : parseInt(row[i]); - } - yield record as FileType; - } +import { getInitialReadChunkParams, readChunk } from './reader'; +import { getInitialWriteChunkParams, getRecordsHeader, writeRecords } from './writer'; +import type { GTFSIOWriteOptions } from './types'; +import type { GTFSFileInfo } from '../file-info'; +import type { GTFSAsyncFileRecords, GTFSFileRecords, GTFSFileRow } from '../types'; + +/** + * Create or modify given options object to define default values if not provided. + * @param options Options object + * @returns Normalised writer options + */ +function normaliseWriteOptions(options?: GTFSIOWriteOptions): GTFSIOWriteOptions { + if (!options) options = {}; + options.newline = options.newline ?? '\n'; + options.recordsBufferSize = options.recordsBufferSize ?? 64; + return options; +} +/** + * File IO + */ +export class GTFSFileIO { + protected constructor() {} + + /** + * Read chunks and returns records. + * @param file File information + * @param chunks Iterable file content chunks + * @returns Iterable records + */ + public static *read(file: GTFSFileInfo, chunks: IterableIterator): IterableIterator { + const params = getInitialReadChunkParams(file); + for (const chunk of chunks) { + params.chunk = chunk.replace(/\r?\n/g, '\n'); + readChunk(params); + for (const record of params.records) yield record; + } + if (params.leftOver) { + params.chunk = params.leftOver; + params.leftOver = undefined; + readChunk(params); + for (const record of params.records) yield record; + } return; } - public static *write(file: GTFSFileInfo, records: IterableIterator): IterableIterator { - const columns = Object.keys(file.columns); - yield stringify([columns], { record_delimiter: '' }); - + /** + * Write records into line contents. + * @param file File Information + * @param records Iterable records + * @param options write options + * @returns Iterable file contents by line + */ + public static *write(file: GTFSFileInfo, records: GTFSFileRecords, options?: GTFSIOWriteOptions): IterableIterator { + options = normaliseWriteOptions(options); + const params = getInitialWriteChunkParams(file); + yield getRecordsHeader(params, options); for (const record of records) { - yield stringify([columns.map(c => (record as Record)[c] ?? undefined)], { record_delimiter: '' }); + params.records.push(record); + if (params.records.length >= options.recordsBufferSize!) { + writeRecords(params, options); + yield params.output; + params.records = []; + } + } + if (params.records.length) { + writeRecords(params, options); + yield params.output; } - return; } + + /** + * Read file content into records array. + * @param file File information + * @param content File content + * @param newLine Line separator (default: \n) + * @returns Array of record + */ + public static readContent(file: GTFSFileInfo, content: string): RowType[] { + return [...GTFSFileIO.read(file, [content].values())]; + } + + /** + * Write records into file content. + * @param file File information + * @param records Row records + * @param options Write options + * @returns File content + */ + public static writeContent(file: GTFSFileInfo, records: RowType[], options?: GTFSIOWriteOptions): string { + return [...GTFSFileIO.write(file, records.values(), options)].join(''); + } }; + +/** + * File Async IO + */ +export class GTFSAsyncFileIO { + protected constructor() {} + + /** + * Read chunks and returns records. + * @param file File information + * @param chunks Iterable file content chunks + * @returns Iterable records + */ + public static async *read(file: GTFSFileInfo, chunks: AsyncIterableIterator): AsyncIterableIterator { + const params = getInitialReadChunkParams(file); + for await (const chunk of chunks) { + params.chunk = chunk.replace(/\r?\n/g, '\n'); + readChunk(params); + for (const record of params.records) yield record; + } + if (params.leftOver) { + params.chunk = params.leftOver; + params.leftOver = undefined; + readChunk(params); + for (const record of params.records) yield record; + } + return; + } + + /** + * Write records into line contents. + * @param file File Information + * @param records Iterable records + * @param options write options + * @returns Iterable file contents by line + */ + public static async *write(file: GTFSFileInfo, records: GTFSAsyncFileRecords, options?: GTFSIOWriteOptions): AsyncIterableIterator { + options = normaliseWriteOptions(options); + const params = getInitialWriteChunkParams(file); + yield getRecordsHeader(params, options); + for await (const record of records) { + params.records.push(record); + if (params.records.length >= options.recordsBufferSize!) { + writeRecords(params, options); + yield params.output; + params.records = []; + } + } + if (params.records.length) { + writeRecords(params, options); + yield params.output; + } + return; + } + + /** + * Await for all chunks and return all the records. + * @param file File information + * @param chunks Chunks generator + * @returns Promise of all records + */ + public static async readAll(file: GTFSFileInfo, chunks: AsyncIterableIterator): Promise { + const records: RowType[] = []; + for await (const record of GTFSAsyncFileIO.read(file, chunks)) { + records.push(record); + } + return records; + } + + /** + * Read file content and return all the records. + * @param file File information + * @param content File content + * @returns Promise of all records + */ + public static async readAllContent(file: GTFSFileInfo, content: string): Promise { + const generator = async function*() { yield content; }; + return GTFSAsyncFileIO.readAll(file, generator()); + } + + /** + * Await for all records and return file content. + * @param file File information + * @param records Records generator + * @param options Write options + * @returns Promise of file content + */ + public static async writeAll(file: GTFSFileInfo, records: AsyncIterableIterator, options?: GTFSIOWriteOptions): Promise { + let result = ''; + for await (const content of GTFSAsyncFileIO.write(file, records, options)) { + result += content; + } + return result; + } + + /** + * Write file content from given records. + * @param file File information + * @param records Records array + * @param options Write options + * @returns Promise of all records + */ + public static async writeAllRecords(file: GTFSFileInfo, records: RowType[], options?: GTFSIOWriteOptions): Promise { + const generator = async function*() { for (const record of records) yield record; }; + return GTFSAsyncFileIO.writeAll(file, generator(), options); + } +} diff --git a/src/io/reader.ts b/src/io/reader.ts new file mode 100644 index 0000000..a7b2f25 --- /dev/null +++ b/src/io/reader.ts @@ -0,0 +1,113 @@ +import { parse } from 'csv/sync'; +import type { GTFSFileInfo } from '../file-info'; +import type { GTFSFileRow } from '../types'; + +/** + * Parameter for readChunk() + */ +export type ReadChunkParam = { + /** GTFS file information, to be defined once. */ + file: GTFSFileInfo, + /** Columns (table header), array if have been read, undefined if not yet. The method alters this property. */ + columns: string[]|undefined, + /** Input, to redefine this property before calling GTFSFileIO.readChunk. */ + chunk: string, + /** Output, this will get set by the method. */ + records: RowType[], + /** + * Input, leave as is or set to undefine for the last iteration. + * It contains string (or empty string) when there is left over string from the previous iteration to prepend to the current chunk. + * It contains undefuned for the last iteration. + */ + leftOver: string|undefined +}; + +/** + * Get initial state of read chunk parameters. + * @param file File information + * @returns Object of chunk reading parameters in the initial state + */ +export function getInitialReadChunkParams(file: GTFSFileInfo): ReadChunkParam { + return { + file, + columns: undefined, + chunk: '', + records: [], + leftOver: '' + }; +}; + +/** + * Read chunk to records, this alter params object in the argument. + * @param params Chunk reading parameters + */ +export function readChunk(params: ReadChunkParam) { + params.records = []; + + // Cut the current chunk until the last occurence of new line, in case of the last line of current chunk is not complete. + // Read chunk to content by appending to the previous leftover, + // and set the next leftover to be the substring after the last occurence of new line. + let content: string; + if (params.leftOver === undefined) { + content = params.chunk; + } else { + let lastNewLineIdx = params.chunk.lastIndexOf('\n'); + if (lastNewLineIdx < 0) { + params.leftOver += params.chunk; + params.chunk = ''; + return; + } + content = params.leftOver + params.chunk.slice(0, lastNewLineIdx); + params.leftOver = params.chunk.slice(lastNewLineIdx + 1); + } + + // If content cannot be parsed due to quotes not being closed, + // cut the last line out of the content and prepend it to the leftover. + let rows: string[][] = []; + while (content) { + try { + rows = parse(content) as string[][]; + break; + } catch (ex: any) { + if (ex && ex.code && ex.code === 'CSV_QUOTE_NOT_CLOSED') { + let lastNewLineIdx = content.lastIndexOf('\n'); + content = content.slice(0, lastNewLineIdx); + params.leftOver = content.slice(lastNewLineIdx) + params.leftOver; + continue; + } + throw ex; + } + } + + if (!rows.length) { + return; + } + + // If columns are not defined, then the first row is. + if (params.columns === undefined) { + params.columns = rows[0]; + rows.splice(0, 1); + } + + // Parse rows and set records. + const { columns } = params; + params.records = rows.map(row => { + let record: Record = {}; + for (let i = 0; i < row.length; i++) { + const field = columns ? columns[i] : undefined; + if (!field) continue; + const columnType = columns ? params.file.columns[field] : undefined; + if (!columnType) continue; + if (columnType === 'int') { + record[columns![i]] = row[i].trim() ? parseInt(row[i]) : undefined; + } else if (columnType === 'float') { + record[columns![i]] = row[i].trim() ? parseFloat(row[i]) : undefined; + } else if (columnType === 'ioe') { + record[columns![i]] = row[i].trim() ? parseInt(row[i]) : ''; + } else { + record[columns![i]] = row[i].toString(); + } + } + return record as RowType; + }); +}; diff --git a/src/io/types.ts b/src/io/types.ts new file mode 100644 index 0000000..fdb7d6c --- /dev/null +++ b/src/io/types.ts @@ -0,0 +1,7 @@ +/** Options for GTFSFileIO.write */ +export type GTFSIOWriteOptions = { + /** New line delimiter */ + newline?: string, + /** Number of records to be collected for each yielded result. */ + recordsBufferSize?: number +}; diff --git a/src/io/writer.ts b/src/io/writer.ts new file mode 100644 index 0000000..070a03e --- /dev/null +++ b/src/io/writer.ts @@ -0,0 +1,48 @@ +import { stringify } from 'csv/sync'; +import type { GTFSIOWriteOptions } from './types'; +import type { GTFSFileInfo } from '../file-info'; +import type { GTFSFileRow } from '../types'; + +/** + * Parameter for writeRecords() + */ +export type WriteParam = { + /** GTFS file information, to be defined once. */ + file: GTFSFileInfo, + /** Columns (table header), to be internally altered by writeRecords(). */ + columns: string[]|undefined, + /** Records to be written. */ + records: RowType[], + /** Output string */ + output: string +}; + +/** + * Get the initial state of write records parameters. + * @param file File information + * @returns Object of writeRecords parameters in the initial state + */ +export function getInitialWriteChunkParams(file: GTFSFileInfo): WriteParam { + return { + file, + columns: undefined, + records: [], + output: '' + }; +}; + +export function getRecordsHeader(params: WriteParam, options: GTFSIOWriteOptions): string { + params.columns = Object.keys(params.file.columns); + return stringify([params.columns], { record_delimiter: options.newline }); +} + +/** + * Write records into contetn string. + * @param params WriteParam + */ +export function writeRecords(params: WriteParam, options: GTFSIOWriteOptions) { + const rows: (string|number|undefined)[][] = params.records.map( + record => params.columns!.map(column => (record as Record)[column] ?? undefined) + ); + params.output = stringify(rows, { record_delimiter: options.newline }); +} diff --git a/src/types.ts b/src/types.ts index ca1023e..b80390f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -24,9 +24,10 @@ import type { GTFSTimeframe } from './files/timeframe'; import type { GTFSTransfer } from './files/transfer'; import type { GTFSTranslation } from './files/translation'; import type { GTFSTrip } from './files/trip'; +import type { GTFSFileInfo, GTFSTableName } from './file-info'; /** A row record in a GTFS file */ -export type GTFSRow = GTFSAgency +export type GTFSFileRow = GTFSAgency | GTFSStop | GTFSRoute | GTFSTrip @@ -54,60 +55,28 @@ export type GTFSRow = GTFSAgency | GTFSAttribution; /** GTFS file records */ -export type GTFSFileRecords = IterableIterator|FileType[]; +export type GTFSFileRecords = IterableIterator; -/** GTFS Dataset feed */ -export type GTFSFeed = { - /** Transit agencies with service represented in this dataset. */ - agency: GTFSFileRecords, - /** Stops where vehicles pick up or drop off riders. */ - stops: GTFSFileRecords, - /** Transit routes. A route is a group of trips that are displayed to riders as a single service. */ - routes: GTFSFileRecords, - /** Trips for each route. */ - trips: GTFSFileRecords, - /** Times that a vehicle arrives at and departs from stops for each trip. */ - stop_times: GTFSFileRecords, - /** Service dates specified using a weekly schedule with start and end dates. */ - calendar?: GTFSFileRecords, - /** Exceptions for the services defined in the `calendar.txt`. */ - calendar_dates?: GTFSFileRecords, - /** Fare information for a transit agency's routes. */ - fare_attributes?: GTFSFileRecords, - /** Rules to apply fares for itineraries. */ - fare_rules?: GTFSFileRecords, - /** Date and time periods to use in fare rules for fares that depend on date and time factors. */ - timeframes?: GTFSFileRecords, - /** To describe the fare media that can be employed to use fare products. */ - fare_media?: GTFSFileRecords, - /** To describe the different types of tickets or fares that can be purchased by riders. */ - fare_products?: GTFSFileRecords, - /** Fare rules for individual legs of travel. */ - fare_leg_rules?: GTFSFileRecords, - /** Fare rules for transfers between legs of travel. */ - fare_transfer_rules?: GTFSFileRecords, - /** Area grouping of locations. */ - areas?: GTFSFileRecords, - /** Rules to assign stops to areas. */ - stop_areas?: GTFSFileRecords, - /** Network grouping of routes. */ - networks?: GTFSFileRecords, - /** Rules to assign routes to networks. */ - route_networks?: GTFSFileRecords, - /** Rules for mapping vehicle travel paths, sometimes referred to as route alignments. */ - shapes?: GTFSFileRecords, - /** Headway (time between trips) for headway-based service or a compressed representation of fixed-schedule service. */ - frequencies?: GTFSFileRecords, - /** Rules for making connections at transfer points between routes. */ - transfers?: GTFSFileRecords, - /** Pathways linking together locations within stations. */ - pathways?: GTFSFileRecords, - /** Levels within stations. */ - levels?: GTFSFileRecords, - /** Translations of customer-facing dataset values. */ - translations?: GTFSFileRecords, - /** Dataset metadata, including publisher, version, and expiration information. */ - feed_infos?: GTFSFileRecords, - /** Dataset attributions. */ - attributions?: GTFSFileRecords +/** GTFS async file records or loaded array */ +export type GTFSAsyncFileRecords = AsyncIterableIterator; + +/** GTFS iterable for an individual file */ +export type GTFSIterableFeedFile = { + /** File name without .txt */ + name: GTFSTableName, + /** File information */ + info: GTFSFileInfo, + /** Records */ + records: RecordsType +}; + +/** GTFS Iterable feed files */ +export type GTFSIterableFeedFiles = IterableIterator>; + +/** GTFS feed file content */ +export type GTFSFileContent = { + /** File name with .txt */ + name: string, + /** File content */ + content: string|Buffer }; diff --git a/tests/data/INFO.md b/tests/data/INFO.md new file mode 100644 index 0000000..d526368 --- /dev/null +++ b/tests/data/INFO.md @@ -0,0 +1 @@ +Test dataset from https://github.com/MobilityData/mobility-database-catalogs/blob/main/catalogs/sources/gtfs/schedule/es-barcelona-tram-gtfs-1003.json. diff --git a/tests/data/gtfs.zip b/tests/data/gtfs.zip new file mode 100644 index 0000000..d9815c7 Binary files /dev/null and b/tests/data/gtfs.zip differ diff --git a/tests/data/gtfs/agency.txt b/tests/data/gtfs/agency.txt new file mode 100644 index 0000000..f0c5375 --- /dev/null +++ b/tests/data/gtfs/agency.txt @@ -0,0 +1,2 @@ +agency_id,agency_name,agency_url,agency_timezone,agency_lang,agency_phone,agency_fare_url,agency_email +A01,This Agency,https://test.agency,Europe/Madrid,en,+34000000000,https://test.agency/fare,contact@test.agency diff --git a/tests/data/gtfs/calendar.txt b/tests/data/gtfs/calendar.txt new file mode 100644 index 0000000..790a9c1 --- /dev/null +++ b/tests/data/gtfs/calendar.txt @@ -0,0 +1,3 @@ +service_id,monday,tuesday,wednesday,thursday,friday,saturday,sunday,start_date,end_date +S01,1,1,1,1,1,0,0,20231201,20231231 +S02,0,0,0,0,0,1,1,20231201,20231231 diff --git a/tests/data/gtfs/calendar_dates.txt b/tests/data/gtfs/calendar_dates.txt new file mode 100644 index 0000000..1731afc --- /dev/null +++ b/tests/data/gtfs/calendar_dates.txt @@ -0,0 +1 @@ +service_id,date,exception_type diff --git a/tests/data/gtfs/routes.txt b/tests/data/gtfs/routes.txt new file mode 100644 index 0000000..5d21e7e --- /dev/null +++ b/tests/data/gtfs/routes.txt @@ -0,0 +1,3 @@ +route_id,agency_id,route_short_name,route_long_name,route_desc,route_type,route_url,route_color,route_text_color,route_sort_order,continuous_pickup,continuous_drop_off,network_id +R01,A01,01,Route Number 1,,3,,ffffff,000000,1,,1, +R02,A01,02,Route Number 2,,3,,000000,ffffff,2,1,1, diff --git a/tests/data/gtfs/shapes.txt b/tests/data/gtfs/shapes.txt new file mode 100644 index 0000000..471232e --- /dev/null +++ b/tests/data/gtfs/shapes.txt @@ -0,0 +1,5 @@ +shape_id,shape_pt_lat,shape_pt_lon,shape_pt_sequence,shape_dist_traveled +SH01,39.46717,-0.37727,1,0 +SH01,39.46694,-0.37485,2,0.2 +SH01,39.47166,-0.36901,3,1 +SH01,39.47324,-0.36546,4,1.29 diff --git a/tests/data/gtfs/stop_times.txt b/tests/data/gtfs/stop_times.txt new file mode 100644 index 0000000..39a54aa --- /dev/null +++ b/tests/data/gtfs/stop_times.txt @@ -0,0 +1,3 @@ +trip_id,arrival_time,departure_time,stop_id,stop_sequence,stop_headsign,pickup_type,drop_off_type,continuous_pickup,continuous_drop_off,shape_dist_traveled,timepoint +T0101,,08:00:00,ST01,1,Alameda,0,0,,,0,1 +T0101,08:03:00,,ST02,2,,0,0,1,,1.29,1 diff --git a/tests/data/gtfs/stops.txt b/tests/data/gtfs/stops.txt new file mode 100644 index 0000000..b9a2386 --- /dev/null +++ b/tests/data/gtfs/stops.txt @@ -0,0 +1,3 @@ +stop_id,stop_code,stop_name,tts_stop_name,stop_desc,stop_lat,stop_lon,zone_id,stop_url,location_type,parent_station,stop_timezone,wheelchair_boarding,level_id,platform_code +ST01,ST01,Xàtiva,,,39.46603,-0.37754,,,0,,,1,, +ST02,ST02,Alameda,,,39.47345,-0.36553,,,0,,,2,, diff --git a/tests/data/gtfs/trips.txt b/tests/data/gtfs/trips.txt new file mode 100644 index 0000000..68e55a4 --- /dev/null +++ b/tests/data/gtfs/trips.txt @@ -0,0 +1,2 @@ +route_id,service_id,trip_id,trip_headsign,trip_short_name,direction_id,block_id,shape_id,wheelchair_accessible,bikes_allowed +R01,S01,T0101,Headsign,Short Name,0,,SH01,1,2 diff --git a/tests/feed-file-io.test.ts b/tests/feed-file-io.test.ts new file mode 100644 index 0000000..12bc4a8 --- /dev/null +++ b/tests/feed-file-io.test.ts @@ -0,0 +1,211 @@ +import { test, expect } from 'vitest'; +import { GTFS_FILES, getIOFromFileName, getAsyncIOFromFileName } from '../dist'; +import type { GTFSAsyncFeedFileIO, GTFSFeedFileIO, GTFSFileInfo } from '../dist'; + +const assertSync = (io: GTFSFeedFileIO, fileName: string, fileInfo: GTFSFileInfo) => { + expect(io.fileName).toEqual(fileName); + expect(io.columns).toEqual(Object.keys(fileInfo.columns)); + + const content = io.columns.join(',') + '\n' + io.columns.map(_ => '').join(','); + const records = io.readContent(content); + expect(records.length).toEqual(1); + expect(Object.keys(records[0])).toEqual(io.columns); + + const writtenContent = io.writeContent(records); + expect(writtenContent).toEqual(content + '\n'); +}; + +const assertAsync = async(io: GTFSAsyncFeedFileIO, fileName: string, fileInfo: GTFSFileInfo) => { + expect(io.fileName).toEqual(fileName); + expect(io.columns).toEqual(Object.keys(fileInfo.columns)); + + const content = io.columns.join(',') + '\n' + io.columns.map(_ => '').join(','); + const records = await io.readAllContent(content); + expect(records.length).toEqual(1); + expect(Object.keys(records[0])).toEqual(io.columns); + + const writtenContent = await io.writeAllRecords(records); + expect(writtenContent).toEqual(content + '\n'); +}; + +test('Test agency.txt IO', async() => { + const io = getIOFromFileName('agency.txt'); + assertSync(io, 'agency.txt', GTFS_FILES.agency); + const asyncIO = getAsyncIOFromFileName('agency.txt'); + assertAsync(asyncIO, 'agency.txt', GTFS_FILES.agency); +}); + +test('Test stops.txt IO', async() => { + const io = getIOFromFileName('stops.txt'); + assertSync(io, 'stops.txt', GTFS_FILES.stops); + const asyncIO = getAsyncIOFromFileName('stops.txt'); + assertAsync(asyncIO, 'stops.txt', GTFS_FILES.stops); +}); + +test('Test routes.txt IO', async() => { + const io = getIOFromFileName('routes.txt'); + assertSync(io, 'routes.txt', GTFS_FILES.routes); + const asyncIO = getAsyncIOFromFileName('routes.txt'); + assertAsync(asyncIO, 'routes.txt', GTFS_FILES.routes); +}); + +test('Test trips.txt IO', async() => { + const io = getIOFromFileName('trips.txt'); + assertSync(io, 'trips.txt', GTFS_FILES.trips); + const asyncIO = getAsyncIOFromFileName('trips.txt'); + assertAsync(asyncIO, 'trips.txt', GTFS_FILES.trips); +}); + +test('Test stop_times.txt IO', async() => { + const io = getIOFromFileName('stop_times.txt'); + assertSync(io, 'stop_times.txt', GTFS_FILES.stop_times); + const asyncIO = getAsyncIOFromFileName('stop_times.txt'); + assertAsync(asyncIO, 'stop_times.txt', GTFS_FILES.stop_times); +}); + +test('Test calendar.txt IO', async() => { + const io = getIOFromFileName('calendar.txt'); + assertSync(io, 'calendar.txt', GTFS_FILES.calendar); + const asyncIO = getAsyncIOFromFileName('calendar.txt'); + assertAsync(asyncIO, 'calendar.txt', GTFS_FILES.calendar); +}); + +test('Test calendar_dates.txt IO', async() => { + const io = getIOFromFileName('calendar_dates.txt'); + assertSync(io, 'calendar_dates.txt', GTFS_FILES.calendar_dates); + const asyncIO = getAsyncIOFromFileName('calendar_dates.txt'); + assertAsync(asyncIO, 'calendar_dates.txt', GTFS_FILES.calendar_dates); +}); + +test('Test fare_attributes.txt IO', async() => { + const io = getIOFromFileName('fare_attributes.txt'); + assertSync(io, 'fare_attributes.txt', GTFS_FILES.fare_attributes); + const asyncIO = getAsyncIOFromFileName('fare_attributes.txt'); + assertAsync(asyncIO, 'fare_attributes.txt', GTFS_FILES.fare_attributes); +}); + +test('Test fare_rules.txt IO', async() => { + const io = getIOFromFileName('fare_rules.txt'); + assertSync(io, 'fare_rules.txt', GTFS_FILES.fare_rules); + const asyncIO = getAsyncIOFromFileName('fare_rules.txt'); + assertAsync(asyncIO, 'fare_rules.txt', GTFS_FILES.fare_rules); +}); + +test('Test timeframes.txt IO', async() => { + const io = getIOFromFileName('timeframes.txt'); + assertSync(io, 'timeframes.txt', GTFS_FILES.timeframes); + const asyncIO = getAsyncIOFromFileName('timeframes.txt'); + assertAsync(asyncIO, 'timeframes.txt', GTFS_FILES.timeframes); +}); + +test('Test fare_media.txt IO', async() => { + const io = getIOFromFileName('fare_media.txt'); + assertSync(io, 'fare_media.txt', GTFS_FILES.fare_media); + const asyncIO = getAsyncIOFromFileName('fare_media.txt'); + assertAsync(asyncIO, 'fare_media.txt', GTFS_FILES.fare_media); +}); + +test('Test fare_products.txt IO', async() => { + const io = getIOFromFileName('fare_products.txt'); + assertSync(io, 'fare_products.txt', GTFS_FILES.fare_products); + const asyncIO = getAsyncIOFromFileName('fare_products.txt'); + assertAsync(asyncIO, 'fare_products.txt', GTFS_FILES.fare_products); +}); + +test('Test fare_leg_rules.txt IO', async() => { + const io = getIOFromFileName('fare_leg_rules.txt'); + assertSync(io, 'fare_leg_rules.txt', GTFS_FILES.fare_leg_rules); + const asyncIO = getAsyncIOFromFileName('fare_leg_rules.txt'); + assertAsync(asyncIO, 'fare_leg_rules.txt', GTFS_FILES.fare_leg_rules); +}); + +test('Test fare_transfer_rules.txt IO', async() => { + const io = getIOFromFileName('fare_transfer_rules.txt'); + assertSync(io, 'fare_transfer_rules.txt', GTFS_FILES.fare_transfer_rules); + const asyncIO = getAsyncIOFromFileName('fare_transfer_rules.txt'); + assertAsync(asyncIO, 'fare_transfer_rules.txt', GTFS_FILES.fare_transfer_rules); +}); + +test('Test areas.txt IO', async() => { + const io = getIOFromFileName('areas.txt'); + assertSync(io, 'areas.txt', GTFS_FILES.areas); + const asyncIO = getAsyncIOFromFileName('areas.txt'); + assertAsync(asyncIO, 'areas.txt', GTFS_FILES.areas); +}); + +test('Test stop_areas.txt IO', async() => { + const io = getIOFromFileName('stop_areas.txt'); + assertSync(io, 'stop_areas.txt', GTFS_FILES.stop_areas); + const asyncIO = getAsyncIOFromFileName('stop_areas.txt'); + assertAsync(asyncIO, 'stop_areas.txt', GTFS_FILES.stop_areas); +}); + +test('Test networks.txt IO', async() => { + const io = getIOFromFileName('networks.txt'); + assertSync(io, 'networks.txt', GTFS_FILES.networks); + const asyncIO = getAsyncIOFromFileName('networks.txt'); + assertAsync(asyncIO, 'networks.txt', GTFS_FILES.networks); +}); + +test('Test route_networks.txt IO', async() => { + const io = getIOFromFileName('route_networks.txt'); + assertSync(io, 'route_networks.txt', GTFS_FILES.route_networks); + const asyncIO = getAsyncIOFromFileName('route_networks.txt'); + assertAsync(asyncIO, 'route_networks.txt', GTFS_FILES.route_networks); +}); + +test('Test shapes.txt IO', async() => { + const io = getIOFromFileName('shapes.txt'); + assertSync(io, 'shapes.txt', GTFS_FILES.shapes); + const asyncIO = getAsyncIOFromFileName('shapes.txt'); + assertAsync(asyncIO, 'shapes.txt', GTFS_FILES.shapes); +}); + +test('Test frequencies.txt IO', async() => { + const io = getIOFromFileName('frequencies.txt'); + assertSync(io, 'frequencies.txt', GTFS_FILES.frequencies); + const asyncIO = getAsyncIOFromFileName('frequencies.txt'); + assertAsync(asyncIO, 'frequencies.txt', GTFS_FILES.frequencies); +}); + +test('Test transfers.txt IO', async() => { + const io = getIOFromFileName('transfers.txt'); + assertSync(io, 'transfers.txt', GTFS_FILES.transfers); + const asyncIO = getAsyncIOFromFileName('transfers.txt'); + assertAsync(asyncIO, 'transfers.txt', GTFS_FILES.transfers); +}); + +test('Test pathways.txt IO', async() => { + const io = getIOFromFileName('pathways.txt'); + assertSync(io, 'pathways.txt', GTFS_FILES.pathways); + const asyncIO = getAsyncIOFromFileName('pathways.txt'); + assertAsync(asyncIO, 'pathways.txt', GTFS_FILES.pathways); +}); + +test('Test levels.txt IO', async() => { + const io = getIOFromFileName('levels.txt'); + assertSync(io, 'levels.txt', GTFS_FILES.levels); + const asyncIO = getAsyncIOFromFileName('levels.txt'); + assertAsync(asyncIO, 'levels.txt', GTFS_FILES.levels); +}); + +test('Test translations.txt IO', async() => { + const io = getIOFromFileName('translations.txt'); + assertSync(io, 'translations.txt', GTFS_FILES.translations); + const asyncIO = getAsyncIOFromFileName('translations.txt'); + assertAsync(asyncIO, 'translations.txt', GTFS_FILES.translations); +}); + +test('Test feed_info.txt IO', async() => { + const io = getIOFromFileName('feed_info.txt'); + assertSync(io, 'feed_info.txt', GTFS_FILES.feed_info); + const asyncIO = getAsyncIOFromFileName('feed_info.txt'); + assertAsync(asyncIO, 'feed_info.txt', GTFS_FILES.feed_info); +}); + +test('Test attributions.txt IO', async() => { + const io = getIOFromFileName('attributions.txt'); + assertSync(io, 'attributions.txt', GTFS_FILES.attributions); + const asyncIO = getAsyncIOFromFileName('attributions.txt'); + assertAsync(asyncIO, 'attributions.txt', GTFS_FILES.attributions); +}); diff --git a/tests/feed-reader.test.ts b/tests/feed-reader.test.ts new file mode 100644 index 0000000..dc0faa1 --- /dev/null +++ b/tests/feed-reader.test.ts @@ -0,0 +1,205 @@ +import { readFileSync } from 'fs'; +import { join } from 'path'; +import { test, expect } from 'vitest'; +import { + GTFSContinuousPickupDropOff, + GTFSFeedReader, + GTFSAsyncFeedReader, + GTFSRouteType, + GTFSStopLocationType, + GTFSStopTimePickupDropOff, + GTFSStopTimeTimepoint, + GTFSTripBikesAllowed, + GTFSTripDirection, + GTFSWheelchairAccessbility +} from '../dist'; +import type { GTFSFileContent, GTFSLoadedFeed } from '../dist'; + +const ZIP_PATH = './tests/data/gtfs.zip'; +const DIR_PATH = './tests/data/gtfs'; + +const assert = (feed: GTFSLoadedFeed) => { + expect(feed.agency).toBeDefined(); + expect(feed.calendar_dates).toBeDefined(); + expect(feed.calendar).toBeDefined(); + expect(feed.routes).toBeDefined(); + expect(feed.shapes).toBeDefined(); + expect(feed.stop_times).toBeDefined(); + expect(feed.stops).toBeDefined(); + expect(feed.trips).toBeDefined(); + + expect(feed.fare_attributes).toBeUndefined(); + expect(feed.fare_rules).toBeUndefined(); + expect(feed.timeframes).toBeUndefined(); + expect(feed.fare_media).toBeUndefined(); + expect(feed.fare_products).toBeUndefined(); + expect(feed.fare_leg_rules).toBeUndefined(); + expect(feed.fare_transfer_rules).toBeUndefined(); + expect(feed.areas).toBeUndefined(); + expect(feed.stop_areas).toBeUndefined(); + expect(feed.networks).toBeUndefined(); + expect(feed.route_networks).toBeUndefined(); + expect(feed.frequencies).toBeUndefined(); + expect(feed.transfers).toBeUndefined(); + expect(feed.pathways).toBeUndefined(); + expect(feed.levels).toBeUndefined(); + expect(feed.translations).toBeUndefined(); + expect(feed.feed_info).toBeUndefined(); + expect(feed.attributions).toBeUndefined(); + + expect(feed.agency.length).toEqual(1); + expect(feed.agency[0].agency_id).toEqual('A01'); + expect(feed.agency[0].agency_name).toEqual('This Agency'); + expect(feed.agency[0].agency_url).toEqual('https://test.agency'); + expect(feed.agency[0].agency_timezone).toEqual('Europe/Madrid'); + expect(feed.agency[0].agency_lang).toEqual('en'); + expect(feed.agency[0].agency_phone).toEqual('+34000000000'); + expect(feed.agency[0].agency_fare_url).toEqual('https://test.agency/fare'); + expect(feed.agency[0].agency_email).toEqual('contact@test.agency'); + + expect(feed.calendar_dates!.length).toEqual(0); + + expect(feed.calendar!.length).toEqual(2); + expect(feed.calendar![0].monday).toBeTypeOf('number'); + expect(feed.calendar![0].tuesday).toBeTypeOf('number'); + expect(feed.calendar![0].wednesday).toBeTypeOf('number'); + expect(feed.calendar![0].thursday).toBeTypeOf('number'); + expect(feed.calendar![0].friday).toBeTypeOf('number'); + expect(feed.calendar![0].saturday).toBeTypeOf('number'); + expect(feed.calendar![0].sunday).toBeTypeOf('number'); + expect(feed.calendar![1].service_id).toEqual('S02'); + expect(feed.calendar![1].monday).toEqual(0); + expect(feed.calendar![1].tuesday).toEqual(0); + expect(feed.calendar![1].wednesday).toEqual(0); + expect(feed.calendar![1].thursday).toEqual(0); + expect(feed.calendar![1].friday).toEqual(0); + expect(feed.calendar![1].saturday).toEqual(1); + expect(feed.calendar![1].sunday).toEqual(1); + expect(feed.calendar![1].start_date).toEqual('20231201'); + expect(feed.calendar![1].end_date).toEqual('20231231'); + + expect(feed.routes.length).toEqual(2); + expect(feed.routes![1].route_type).toBeTypeOf('number'); + expect(feed.routes![1].route_sort_order).toBeTypeOf('number'); + expect(feed.routes![1].continuous_pickup).toBeTypeOf('number'); + expect(feed.routes![1].continuous_drop_off).toBeTypeOf('number'); + expect(feed.routes![0].route_id).toEqual('R01'); + expect(feed.routes![0].agency_id).toEqual('A01'); + expect(feed.routes![0].route_short_name).toEqual('01'); + expect(feed.routes![0].route_long_name).toEqual('Route Number 1'); + expect(feed.routes![0].route_type).toEqual(GTFSRouteType.Bus); + expect(feed.routes![0].route_color).toEqual('ffffff'); + expect(feed.routes![0].route_text_color).toEqual('000000'); + expect(feed.routes![0].route_sort_order).toEqual(1); + expect(feed.routes![0].continuous_pickup).toEqual(GTFSContinuousPickupDropOff.Default); + expect(feed.routes![0].continuous_drop_off).toEqual(GTFSContinuousPickupDropOff.NoContinuous); + + expect(feed.shapes!.length).toEqual(4); + expect(feed.shapes![1].shape_pt_lat).toBeTypeOf('number'); + expect(feed.shapes![1].shape_pt_lon).toBeTypeOf('number'); + expect(feed.shapes![1].shape_pt_sequence).toBeTypeOf('number'); + expect(feed.shapes![1].shape_dist_traveled).toBeTypeOf('number'); + expect(feed.shapes![3].shape_id).toEqual('SH01'); + expect(feed.shapes![3].shape_pt_lat).toEqual(39.47324); + expect(feed.shapes![3].shape_pt_lon).toEqual(-0.36546); + expect(feed.shapes![3].shape_pt_sequence).toEqual(4); + expect(feed.shapes![3].shape_dist_traveled).toEqual(1.29); + + expect(feed.stop_times.length).toEqual(2); + expect(feed.stop_times[0].shape_dist_traveled).toBeTypeOf('number'); + expect(feed.stop_times[0].stop_sequence).toBeTypeOf('number'); + expect(feed.stop_times[1].trip_id).toEqual('T0101'); + expect(feed.stop_times[1].arrival_time).toEqual('08:03:00'); + expect(feed.stop_times[1].departure_time).toBeFalsy(); + expect(feed.stop_times[1].stop_id).toEqual('ST02'); + expect(feed.stop_times[1].stop_sequence).toEqual(2); + expect(feed.stop_times[1].pickup_type).toEqual(GTFSStopTimePickupDropOff.Scheduled); + expect(feed.stop_times[1].drop_off_type).toEqual(GTFSStopTimePickupDropOff.Scheduled); + expect(feed.stop_times[1].continuous_pickup).toEqual(GTFSContinuousPickupDropOff.NoContinuous); + expect(feed.stop_times[1].continuous_drop_off).toEqual(GTFSContinuousPickupDropOff.Default); + expect(feed.stop_times[1].shape_dist_traveled).toEqual(1.29); + expect(feed.stop_times[1].timepoint).toEqual(GTFSStopTimeTimepoint.Exact); + + expect(feed.stops.length).toEqual(2); + expect(feed.stops[0].stop_lat).toBeTypeOf('number'); + expect(feed.stops[0].stop_lon).toBeTypeOf('number'); + expect(feed.stops[0].stop_id).toEqual('ST01'); + expect(feed.stops[0].stop_code).toEqual('ST01'); + expect(feed.stops[0].stop_name).toEqual('Xàtiva'); + expect(feed.stops[1].stop_lat).toEqual(39.47345); + expect(feed.stops[1].stop_lon).toEqual(-0.36553); + expect(feed.stops[1].location_type).toEqual(GTFSStopLocationType.Stop); + expect(feed.stops[1].wheelchair_boarding).toEqual(GTFSWheelchairAccessbility.Inaccessible); + + expect(feed.trips.length).toEqual(1); + expect(feed.trips[0].route_id).toEqual('R01'); + expect(feed.trips[0].service_id).toEqual('S01'); + expect(feed.trips[0].trip_id).toEqual('T0101'); + expect(feed.trips[0].trip_headsign).toEqual('Headsign'); + expect(feed.trips[0].trip_short_name).toEqual('Short Name'); + expect(feed.trips[0].direction_id).toEqual(GTFSTripDirection.OneDirection); + expect(feed.trips[0].shape_id).toEqual('SH01'); + expect(feed.trips[0].wheelchair_accessible).toEqual(GTFSWheelchairAccessbility.Accessible); + expect(feed.trips[0].bikes_allowed).toEqual(GTFSTripBikesAllowed.NotAllowed); +}; + +const getFiles = (): GTFSFileContent[] => [ + { name: 'agency.txt', content: readFileSync(join(DIR_PATH, 'agency.txt')) }, + { name: 'calendar_dates.txt', content: readFileSync(join(DIR_PATH, 'calendar_dates.txt')) }, + { name: 'calendar.txt', content: readFileSync(join(DIR_PATH, 'calendar.txt')) }, + { name: 'routes.txt', content: readFileSync(join(DIR_PATH, 'routes.txt')) }, + { name: 'shapes.txt', content: readFileSync(join(DIR_PATH, 'shapes.txt')) }, + { name: 'stop_times.txt', content: readFileSync(join(DIR_PATH, 'stop_times.txt')) }, + { name: 'stops.txt', content: readFileSync(join(DIR_PATH, 'stops.txt')) }, + { name: 'trips.txt', content: readFileSync(join(DIR_PATH, 'trips.txt')) } +]; + +test('Test FeedReader: zip path', () => { + const reader = GTFSFeedReader.fromZip(ZIP_PATH); + const feed = reader.loadFeed(); + assert(feed); +}); + +test('Test AsyncFeedReader: zip path', async() => { + const reader = GTFSAsyncFeedReader.fromZip(ZIP_PATH); + const feed = await reader.loadFeed(); + assert(feed); +}); + +test('Test FeedReader: zip content', () => { + const zip = readFileSync(ZIP_PATH); + const reader = GTFSFeedReader.fromZip(zip); + const feed = reader.loadFeed(); + assert(feed); +}); + +test('Test AsyncFeedReader: zip content', async() => { + const zip = readFileSync(ZIP_PATH); + const reader = GTFSAsyncFeedReader.fromZip(zip); + const feed = await reader.loadFeed(); + assert(feed); +}); + +test('Test FeedReader: directory path', () => { + const reader = GTFSFeedReader.fromDirectoy(DIR_PATH); + const feed = reader.loadFeed(); + assert(feed); +}); + +test('Test AsyncFeedReader: directory path', async () => { + const reader = GTFSAsyncFeedReader.fromDirectoy(DIR_PATH); + const feed = await reader.loadFeed(); + assert(feed); +}); + +test('Test FeedReader: file contents', () => { + const reader = GTFSFeedReader.fromFiles(getFiles()); + const feed = reader.loadFeed(); + assert(feed); +}); + +test('Test AsyncFeedReader: file contents', async() => { + const reader = GTFSAsyncFeedReader.fromFiles(getFiles()); + const feed = await reader.loadFeed(); + assert(feed); +}); diff --git a/tests/feed-writer.test.ts b/tests/feed-writer.test.ts new file mode 100644 index 0000000..a781a34 --- /dev/null +++ b/tests/feed-writer.test.ts @@ -0,0 +1,218 @@ +import { expect, test } from 'vitest'; +import AdmZip from 'adm-zip'; +import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync } from 'fs'; +import { join as joinPath } from 'path'; +import { + GTFSAsyncFeedWriter, + GTFSContinuousPickupDropOff, + GTFSFeedWriter, + GTFSLoadedFeed, + GTFSRouteType, + GTFSStopTimePickupDropOff, + GTFSStopTimeTimepoint, + GTFSTripBikesAllowed, + GTFSTripDirection, + GTFSWheelchairAccessbility +} from '../dist'; + +const OUTPUT_DIR = './tests/data/ignore'; +const COMPARE_DIR = './tests/data/gtfs'; + +const getTestFeed = (): GTFSLoadedFeed => new GTFSLoadedFeed({ + agency: [{ + agency_id: 'A01', + agency_name: 'This Agency', + agency_url: 'https://test.agency', + agency_timezone: 'Europe/Madrid', + agency_lang: 'en', + agency_phone: '+34000000000', + agency_fare_url: 'https://test.agency/fare', + agency_email: 'contact@test.agency' + }], + calendar_dates: [], + calendar: [ + { service_id: 'S01', monday: 1, tuesday: 1, wednesday: 1, thursday: 1, friday: 1, saturday: 0, sunday: 0, start_date: '20231201', end_date: '20231231' }, + { service_id: 'S02', monday: 0, tuesday: 0, wednesday: 0, thursday: 0, friday: 0, saturday: 1, sunday: 1, start_date: '20231201', end_date: '20231231' } + ], + routes: [ + { + route_id: 'R01', agency_id: 'A01', route_short_name: '01', route_long_name: 'Route Number 1', route_desc: '', route_type: GTFSRouteType.Bus, + route_url: '', route_color: 'ffffff', route_text_color: '000000', route_sort_order: 1, + continuous_pickup: GTFSContinuousPickupDropOff.Default, continuous_drop_off: GTFSContinuousPickupDropOff.NoContinuous, network_id: '' + }, + { + route_id: 'R02', agency_id: 'A01', route_short_name: '02', route_long_name: 'Route Number 2', route_desc: '', route_type: GTFSRouteType.Bus, + route_url: '', route_color: '000000', route_text_color: 'ffffff', route_sort_order: 2, + continuous_pickup: GTFSContinuousPickupDropOff.NoContinuous, continuous_drop_off: GTFSContinuousPickupDropOff.NoContinuous, network_id: '' + } + ], + shapes: [ + { shape_id: 'SH01', shape_pt_lat: 39.46717, shape_pt_lon: -0.37727, shape_pt_sequence: 1, shape_dist_traveled: 0.0 }, + { shape_id: 'SH01', shape_pt_lat: 39.46694, shape_pt_lon: -0.37485, shape_pt_sequence: 2, shape_dist_traveled: 0.2 }, + { shape_id: 'SH01', shape_pt_lat: 39.47166, shape_pt_lon: -0.36901, shape_pt_sequence: 3, shape_dist_traveled: 1.0 }, + { shape_id: 'SH01', shape_pt_lat: 39.47324, shape_pt_lon: -0.36546, shape_pt_sequence: 4, shape_dist_traveled: 1.29 } + ], + stop_times: [ + { + trip_id: 'T0101', arrival_time: '', departure_time: '08:00:00', stop_id: 'ST01', stop_sequence: 1, stop_headsign: 'Alameda', + pickup_type: GTFSStopTimePickupDropOff.Scheduled, drop_off_type: GTFSStopTimePickupDropOff.Scheduled, + continuous_pickup: GTFSContinuousPickupDropOff.Default, continuous_drop_off: GTFSContinuousPickupDropOff.Default, + shape_dist_traveled: 0, timepoint: GTFSStopTimeTimepoint.Exact + }, + { + trip_id: 'T0101', arrival_time: '08:03:00', departure_time: '', stop_id: 'ST02', stop_sequence: 2, stop_headsign: '', + pickup_type: GTFSStopTimePickupDropOff.Scheduled, drop_off_type: GTFSStopTimePickupDropOff.Scheduled, + continuous_pickup: GTFSContinuousPickupDropOff.NoContinuous, continuous_drop_off: GTFSContinuousPickupDropOff.Default, + shape_dist_traveled: 1.29, timepoint: GTFSStopTimeTimepoint.Exact + } + ], + stops: [ + { + stop_id: 'ST01', stop_code: 'ST01', stop_name: 'Xàtiva', stop_lat: 39.46603, stop_lon: -0.37754, + location_type: 0, wheelchair_boarding: GTFSWheelchairAccessbility.Accessible + }, + { + stop_id: 'ST02', stop_code: 'ST02', stop_name: 'Alameda', stop_lat: 39.47345, stop_lon: -0.36553, + location_type: 0, wheelchair_boarding: GTFSWheelchairAccessbility.Inaccessible + } + ], + trips: [{ + route_id: 'R01', service_id: 'S01', trip_id: 'T0101', trip_headsign: 'Headsign', trip_short_name: 'Short Name', + direction_id: GTFSTripDirection.OneDirection, block_id: '', shape_id: 'SH01', + wheelchair_accessible: GTFSWheelchairAccessbility.Accessible, bikes_allowed: GTFSTripBikesAllowed.NotAllowed + }] +}); + +test('Test FeedWriter: zip', () => { + const dir = joinPath(OUTPUT_DIR, 'zip'); + const path = joinPath(dir, 'gtfs.zip'); + if (!existsSync(dir)) { + mkdirSync(dir, { recursive: true }); + } + GTFSFeedWriter.writeZip(getTestFeed(), path); + + expect(existsSync(path)).toBeTruthy(); + + const zip = new AdmZip(path); + const entries = zip.getEntries(); + expect(entries.length).toEqual(8); + const files = [ + 'agency.txt', 'calendar_dates.txt', 'calendar.txt', 'routes.txt', 'shapes.txt', 'stop_times.txt', 'stops.txt', 'trips.txt' + ]; + expect(entries.map(x => x.entryName).every(x => files.indexOf(x) > -1)).toBeTruthy(); + + for (const entry of entries) { + expect( + entry.getData().toString().split(/\r?\n/g), + entry.entryName + ).toEqual( + readFileSync(joinPath(COMPARE_DIR, entry.entryName)).toString().split(/\r?\n/g) + ); + } +}); + +test('Test AsyncFeedWriter: zip', async() => { + const dir = joinPath(OUTPUT_DIR, 'zip'); + const path = joinPath(dir, 'gtfs.zip'); + if (!existsSync(dir)) { + mkdirSync(dir, { recursive: true }); + } + await GTFSAsyncFeedWriter.writeZip(getTestFeed(), path); + + expect(existsSync(path)).toBeTruthy(); + + const zip = new AdmZip(path); + const entries = zip.getEntries(); + expect(entries.length).toEqual(8); + const files = [ + 'agency.txt', 'calendar_dates.txt', 'calendar.txt', 'routes.txt', 'shapes.txt', 'stop_times.txt', 'stops.txt', 'trips.txt' + ]; + expect(entries.map(x => x.entryName).every(x => files.indexOf(x) > -1)).toBeTruthy(); + + for (const entry of entries) { + expect( + entry.getData().toString().split(/\r?\n/g), + entry.entryName + ).toEqual( + readFileSync(joinPath(COMPARE_DIR, entry.entryName)).toString().split(/\r?\n/g) + ); + } +}); + +test('Test FeedWriter: dir', () => { + const path = joinPath(OUTPUT_DIR, 'gtfs'); + if (existsSync(path)) { + for (const file of readdirSync(path).filter(x => x.endsWith('.txt')).map(x => joinPath(path, x))) { + rmSync(file); + } + } + + GTFSFeedWriter.writeDirectory(getTestFeed(), path); + const files = [ + 'agency.txt', 'calendar_dates.txt', 'calendar.txt', 'routes.txt', 'shapes.txt', 'stop_times.txt', 'stops.txt', 'trips.txt' + ]; + + expect(files.every(x => existsSync(joinPath(path, x)))).toBeTruthy(); + for (const file of files) { + expect( + readFileSync(joinPath(path, file)).toString().split(/\r?\n/g), + file + ).toEqual( + readFileSync(joinPath(COMPARE_DIR, file)).toString().split(/\r?\n/g) + ); + } +}); + +test('Test AsyncFeedWriter: dir', async() => { + const path = joinPath(OUTPUT_DIR, 'gtfs'); + if (existsSync(path)) { + for (const file of readdirSync(path).filter(x => x.endsWith('.txt')).map(x => joinPath(path, x))) { + rmSync(file); + } + } + + await GTFSAsyncFeedWriter.writeDirectory(getTestFeed(), path); + const files = [ + 'agency.txt', 'calendar_dates.txt', 'calendar.txt', 'routes.txt', 'shapes.txt', 'stop_times.txt', 'stops.txt', 'trips.txt' + ]; + + expect(files.every(x => existsSync(joinPath(path, x)))).toBeTruthy(); + for (const file of files) { + expect( + readFileSync(joinPath(path, file)).toString().split(/\r?\n/g), + file + ).toEqual( + readFileSync(joinPath(COMPARE_DIR, file)).toString().split(/\r?\n/g) + ); + } +}); + +test('Test FeedWriter: contents', () => { + const contents = GTFSFeedWriter.createFileContents(getTestFeed()); + expect(contents.length).toEqual(8); + + const files = [ + 'agency.txt', 'calendar_dates.txt', 'calendar.txt', 'routes.txt', 'shapes.txt', 'stop_times.txt', 'stops.txt', 'trips.txt' + ]; + expect(contents.every(c => files.indexOf(c.name) > -1)).toBeTruthy(); + + for (const content of contents) { + expect(content.content.toString().split(/\r?\n/g), content.name) + .toEqual(readFileSync(joinPath(COMPARE_DIR, content.name)).toString().split(/\r?\n/g)); + } +}); + +test('Test AsyncFeedWriter: contents', async() => { + const contents = await GTFSAsyncFeedWriter.createFileContents(getTestFeed()); + expect(contents.length).toEqual(8); + + const files = [ + 'agency.txt', 'calendar_dates.txt', 'calendar.txt', 'routes.txt', 'shapes.txt', 'stop_times.txt', 'stops.txt', 'trips.txt' + ]; + expect(contents.every(c => files.indexOf(c.name) > -1)).toBeTruthy(); + + for (const content of contents) { + expect(content.content.toString().split(/\r?\n/g), content.name) + .toEqual(readFileSync(joinPath(COMPARE_DIR, content.name)).toString().split(/\r?\n/g)); + } +}); diff --git a/tests/file-io.test.ts b/tests/file-io.test.ts index fb67f39..4d75156 100644 --- a/tests/file-io.test.ts +++ b/tests/file-io.test.ts @@ -1,106 +1,130 @@ import { describe, expect, it } from 'vitest'; -import { parse } from 'csv/sync'; -import { GTFSAgency, GTFSFileIO, GTFSFileInfos, GTFSTripDirection } from '../dist'; -import type { GTFSRoute, GTFSStop, GTFSTrip } from '../dist'; +import { + GTFS_FILES, + GTFSAsyncFileIO, + GTFSFileIO, + GTFSStopLocationType, + GTFSTripDirection +} from '../dist'; +import type { + GTFSFileRecords, + GTFSAgency, + GTFSRoute, + GTFSStop, + GTFSTrip +} from '../dist'; describe('Test GTFSFileIO reading', () => { + const content = 'stop_id,stop_name,stop_code,stop_desc,stop_lat,stop_lon,location_type,parent_station\n' + + 'STOP_01,"Test",1001,,50.25,-23.28,1,\n' + + '"STOP_02",Test2,"1002",,50.25,-23.28,"0",STOP_01\n' + + 'STOP_03,"NameWith,Comma",1003,,50.30,-23.30,0,\n' + + 'STOP_04,Test4,1004,"Description with\nNew line",50.31,-23.48,0,\n'; + const chunks = [ + 'stop_id,stop_name,stop_code,stop_desc,stop_lat,stop_', 'lon,location_type,parent_station\n', + 'STOP_01,"Test",1001,,50.25,-23.28,1,\n"STOP_02",Test2,"1002",,50', + '.25,-23.28,"0",STOP_01\n', + 'STOP_03,"NameWith,Comma",1003,,50.30,-23.30,0,\nSTOP_04,Test4', + ',1004,"Description with', + '\nNew line",50.31,-23.48,0,\n' + ]; + it('reads rows into records', () => { - const input = function*(): IterableIterator { - yield 'stop_id,stop_name,stop_code,stop_desc,stop_lat,stop_lon,location_type,parent_station'; - yield 'STOP_01,"Test",1001,,50.25,-23.28,1,'; - yield '"STOP_02",Test2,"1002",,50.25,-23.28,"0",STOP_01'; - yield ''; - return; - }; + const records = GTFSFileIO.readContent(GTFS_FILES.stops, content); + expect(records.length).toEqual(4); + expect(records[0].stop_id).toEqual('STOP_01'); + expect(records[0].stop_code).toBeTypeOf('string'); + expect(records[0].stop_code).toEqual('1001'); + expect(records[0].stop_name).toEqual('Test'); + expect(records[0].location_type).toBeTypeOf('number'); + expect(records[0].location_type).toEqual(1); + expect(records[0].location_type).toEqual(GTFSStopLocationType.Station); + expect(records[0].parent_station).toBeFalsy(); + expect(records[1].stop_id).toBeTruthy(); + expect(records[1].stop_id).toEqual('STOP_02'); + expect(records[1].stop_code).toEqual('1002'); + expect(records[1].stop_name).toEqual('Test2'); + expect(records[1].location_type).toBeTypeOf('number'); + expect(records[1].location_type).toEqual(0); + expect(records[1].location_type).toEqual(GTFSStopLocationType.Stop); + expect(records[1].parent_station).toEqual('STOP_01'); + expect(records[2].stop_name).toEqual('NameWith,Comma'); + expect(records[2].stop_code).toEqual('1003'); + expect(records[3].stop_id).toEqual('STOP_04'); + expect(records[3].stop_desc).toEqual('Description with\nNew line'); + expect(records[3].stop_lat).toEqual(50.31); + expect(records[3].stop_lon).toEqual(-23.48); + }); + + it('reads chunks into records', () => { + const recordsFromContent = GTFSFileIO.readContent(GTFS_FILES.stops, content); + const recordsFromChunks = [...GTFSFileIO.read(GTFS_FILES.stops, chunks.values())]; + expect(recordsFromChunks.length).toEqual(recordsFromContent.length); + expect(recordsFromChunks[0]).toEqual(recordsFromContent[0]); + expect(recordsFromChunks[1]).toEqual(recordsFromContent[1]); + expect(recordsFromChunks[2]).toEqual(recordsFromContent[2]); + expect(recordsFromChunks[3]).toEqual(recordsFromContent[3]); + }); - let readRecords = [...GTFSFileIO.read(GTFSFileInfos.stops, input())]; - expect(readRecords.length).toEqual(2); - expect(readRecords[0].stop_id).toEqual('STOP_01'); - expect(readRecords[0].stop_code).toBeTypeOf('string'); - expect(readRecords[0].stop_code).toEqual('1001'); - expect(readRecords[0].stop_name).toEqual('Test'); - expect(readRecords[0].location_type).toBeTypeOf('number'); - expect(readRecords[0].location_type).toEqual(1); - expect(readRecords[0].parent_station).toBeFalsy(); - expect(readRecords[1].stop_id).toBeTruthy(); - expect(readRecords[1].stop_id).toEqual('STOP_02'); - expect(readRecords[1].stop_code).toEqual('1002'); - expect(readRecords[1].stop_name).toEqual('Test2'); - expect(readRecords[1].location_type).toBeTypeOf('number'); - expect(readRecords[1].location_type).toEqual(0); - expect(readRecords[1].parent_station).toEqual('STOP_01'); + it('asynchronously reads chunks into records', async() => { + const recordsFromContent = GTFSFileIO.readContent(GTFS_FILES.stops, content); + const chunksGenerator = async function*() { for (const chunk of chunks) yield chunk; }; + const recordsFromChunks = await GTFSAsyncFileIO.readAll(GTFS_FILES.stops, chunksGenerator()); + expect(recordsFromChunks.length).toEqual(recordsFromContent.length); + expect(recordsFromChunks[0]).toEqual(recordsFromContent[0]); + expect(recordsFromChunks[1]).toEqual(recordsFromContent[1]); + expect(recordsFromChunks[2]).toEqual(recordsFromContent[2]); + expect(recordsFromChunks[3]).toEqual(recordsFromContent[3]); }); it('handles empty file content', () => { - const input = function*(): IterableIterator { - yield 'stop_id,stop_name,stop_code,stop_desc,stop_lat,stop_lon,location_type,parent_station'; - yield ''; - return; - }; - const records = [...GTFSFileIO.read(GTFSFileInfos.stops, input())]; + const content = 'stop_id,stop_name,stop_code,stop_desc,stop_lat,stop_lon,location_type,parent_station\n'; + const records = GTFSFileIO.readContent(GTFS_FILES.stops, content); expect(records.length).toEqual(0); - const emptyInput = function*(): IterableIterator { - return; - } - expect([...GTFSFileIO.read(GTFSFileInfos.agency, emptyInput())].length).toEqual(0); + expect(GTFSFileIO.readContent(GTFS_FILES.agency, '').length).toEqual(0); }); }); describe('Test GTFSFileIO writing', () => { - it('writes records into rows', () => { - const input = function*(): IterableIterator { - yield { route_id: 'R01', service_id: 'S01', trip_id: 'T01', direction_id: GTFSTripDirection.OneDirection }, - yield { route_id: 'R01', service_id: 'S02', trip_id: 'T02', trip_headsign: 'HEADSIGN' } - return; - }; - const lines = [...GTFSFileIO.write(GTFSFileInfos.trips, input())]; - expect(lines.length).toEqual(3); + const records: GTFSTrip[] = [ + { route_id: 'R01', service_id: 'S01', trip_id: 'T01', direction_id: GTFSTripDirection.OneDirection }, + { route_id: 'R01', service_id: 'S02', trip_id: 'T02', trip_headsign: 'HEADSIGN' }, + { route_id: 'R03', service_id: 'S01', trip_id: 'T03', trip_headsign: 'with,comma' }, + { route_id: 'R02', service_id: 'S02', trip_id: 'T04', trip_headsign: 'with\nnewline' } + ]; - expect(parse(lines[0])).toContainEqual([ - 'route_id', - 'service_id', - 'trip_id', - 'trip_headsign', - 'trip_short_name', - 'direction_id', - 'block_id', - 'shape_id', - 'wheelchair_accessible', - 'bikes_allowed' - ]); + it('writes records into rows', () => { + const content = GTFSFileIO.writeContent(GTFS_FILES.trips, records, { recordsBufferSize: 2 }); + expect(content).toEqual( + 'route_id,service_id,trip_id,trip_headsign,trip_short_name,direction_id,block_id,shape_id,wheelchair_accessible,bikes_allowed\n' + + 'R01,S01,T01,,,0,,,,\n' + + 'R01,S02,T02,HEADSIGN,,,,,,\n' + + 'R03,S01,T03,"with,comma",,,,,,\n' + + 'R02,S02,T04,"with\n' + + 'newline",,,,,,\n' + ); + }); - const records = parse(lines.join('\n'), { columns: true }); - expect(records[0].route_id).toEqual('R01'); - expect(records[0].service_id).toEqual('S01'); - expect(records[0].trip_id).toEqual('T01'); - expect(parseInt(records[0].direction_id)).toEqual(0); - expect(records[0].trip_headsign).toBeFalsy(); - expect(records[0].shape_id).toBeFalsy(); - expect(records[1].route_id).toEqual('R01'); - expect(records[1].service_id).toEqual('S02'); - expect(records[1].trip_id).toEqual('T02'); - expect(records[1].trip_headsign).toEqual('HEADSIGN'); + it('asynchronously writes records into rows', async() => { + const recordsGenerator = async function*() { for (const record of records) yield record; }; + const content = await GTFSAsyncFileIO.writeAll(GTFS_FILES.trips, recordsGenerator(), { recordsBufferSize: 2 }); + expect(content).toEqual( + 'route_id,service_id,trip_id,trip_headsign,trip_short_name,direction_id,block_id,shape_id,wheelchair_accessible,bikes_allowed\n' + + 'R01,S01,T01,,,0,,,,\n' + + 'R01,S02,T02,HEADSIGN,,,,,,\n' + + 'R03,S01,T03,"with,comma",,,,,,\n' + + 'R02,S02,T04,"with\n' + + 'newline",,,,,,\n' + ); }); it('handles empty input', () => { - const input = function*(): IterableIterator { return; }; - const output = [...GTFSFileIO.write(GTFSFileInfos.routes, input())]; - expect(output.length).toEqual(1); - expect(parse(output[0])).toContainEqual([ - 'route_id', - 'agency_id', - 'route_short_name', - 'route_long_name', - 'route_desc', - 'route_type', - 'route_url', - 'route_color', - 'route_text_color', - 'route_sort_order', - 'continuous_pickup', - 'continuous_drop_off', - 'network_id' - ]); + const records: GTFSRoute[] = []; + const content = GTFSFileIO.writeContent(GTFS_FILES.routes, records); + expect(content).toEqual( + 'route_id,agency_id,route_short_name,route_long_name,route_desc,route_type,route_url,route_color,' + + 'route_text_color,route_sort_order,continuous_pickup,continuous_drop_off,network_id\n' + ); }); }); diff --git a/tests/webpack.html b/tests/webpack.html new file mode 100644 index 0000000..c948ad1 --- /dev/null +++ b/tests/webpack.html @@ -0,0 +1,105 @@ + + + + GTFS + + + + + + + + + + diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..632d32e --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,48 @@ +import { createRequire } from 'module'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import webpack from 'webpack'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const require = createRequire(import.meta.url); + +export default { + mode: 'production', + entry: './dist/index.js', + module: { + rules: [{ + test: /\.(js)$/, + resolve: { + fullySpecified: false + } + }] + }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env.NODE_DEBUG': JSON.stringify('') + }), + new webpack.ProvidePlugin({ + Buffer: ['buffer', 'Buffer'] + }) + ], + resolve: { + fallback: { + path: false, + fs: false, + assert: require.resolve('assert'), + buffer: require.resolve('buffer'), + crypto: require.resolve('crypto-browserify'), + stream: require.resolve('stream-browserify'), + util: require.resolve('util'), + zlib: require.resolve('browserify-zlib') + } + }, + output: { + path: path.resolve(__dirname, 'dist', 'bundle'), + filename: 'index.js', + library: { + type: 'var', + name: 'GTFSIO' + } + }, +};