diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..20bc9cc --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,10 @@ +/* eslint-env node */ +module.exports = { + extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], + root: true, + rules: { + '@typescript-eslint/consistent-type-imports': 'error', + } + }; \ No newline at end of file diff --git a/.github/workflows/action-ci.yml b/.github/workflows/action-ci.yml index d8af104..80b58e4 100644 --- a/.github/workflows/action-ci.yml +++ b/.github/workflows/action-ci.yml @@ -6,9 +6,9 @@ name: CI on: # Triggers the workflow on push or pull request events but only for the master branch push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: @@ -22,14 +22,15 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: - - uses: actions/checkout@v2 - - name: Use Node.js - uses: actions/setup-node@v2 - with: - node-version: 'lts/Hydrogen' - - run: npm ci - - run: npm run test-ci - - name: Report Coverage - uses: davelosert/vitest-coverage-report-action@v2 - if: always() - - run: npm run build --if-present + - uses: actions/checkout@v2 + - name: Use Node.js + uses: actions/setup-node@v2 + with: + node-version: "lts/Hydrogen" + - run: npm ci + - run: npm run lint + - run: npm run test-ci + - name: Report Coverage + uses: davelosert/vitest-coverage-report-action@v2 + if: always() + - run: npm run build --if-present diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index ac20152..d56aaf6 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -14,8 +14,9 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: 'lts/Hydrogen' + node-version: "lts/Hydrogen" - run: npm ci + - run: npm run lint - run: npm test-ci - name: report coverage uses: davelosert/vitest-coverage-report-action@v2 @@ -28,10 +29,10 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: 'lts/Hydrogen' + node-version: "lts/Hydrogen" registry-url: https://registry.npmjs.org/ - run: npm ci - run: npm version "${GITHUB_REF#refs/tags/}" --no-git-tag-version - run: npm run publish-npm env: - NODE_AUTH_TOKEN: ${{secrets.npm_token}} + NODE_AUTH_TOKEN: ${{secrets.npm_token}} diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..403ed0f --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": false, + "printWidth": 120 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 00ad71f..9518fac 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,5 @@ { - "typescript.tsdk": "node_modules\\typescript\\lib" + "typescript.tsdk": "node_modules\\typescript\\lib", + "prettier.enable": true, + "editor.defaultFormatter": "esbenp.prettier-vscode" } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 0c8dff1..2f66c2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,17 +9,34 @@ "version": "2.0.0-dev.local", "license": "ISC", "devDependencies": { - "@types/node-fetch": "^2.5.12", + "@typescript-eslint/eslint-plugin": "^6.16.0", + "@typescript-eslint/parser": "^6.16.0", "@vitest/coverage-v8": "^1.1.0", "chai": "^4.3.4", "cpx": "^1.5.0", - "node-fetch": "^3.3.2", + "eslint": "^8.2.0", + "eslint-config-airbnb": "^19.0.4", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-prettier": "^5.1.2", + "eslint-plugin-react": "^7.28.0", + "eslint-plugin-react-hooks": "^4.3.0", "rimraf": "^5.0.5", "ts-node": "^10.0.0", "typescript": "^5.3.3", "vitest": "^1.1.0" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@ampproject/remapping": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", @@ -63,6 +80,43 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz", + "integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.23.6.tgz", + "integrity": "sha512-Djs/ZTAnpyj0nyg7p1J6oiE/tZ9G2stqAFlLGZynrW+F3k2w2jGK2mLOBxzYIOcZYA89+c3d3wXKpYLcpwcU6w==", + "dev": true, + "dependencies": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3/node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "node_modules/@babel/runtime/node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, "node_modules/@babel/types": { "version": "7.23.6", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", @@ -463,6 +517,82 @@ "node": ">=12" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.6.0.tgz", + "integrity": "sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -628,6 +758,41 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -638,6 +803,18 @@ "node": ">=14" } }, + "node_modules/@pkgr/core": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.0.tgz", + "integrity": "sha512-Zwq5OCzuwJC2jwqmpEQt7Ds1DTi6BWSwoGkbb1n9pO3hzb35BoJELx7c0T23iDkBGkh2e7tvOtjF3tr3OaQHDQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.1.tgz", @@ -843,23 +1020,276 @@ "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "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/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, "node_modules/@types/node": { "version": "20.10.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", "dev": true, + "peer": true, "dependencies": { "undici-types": "~5.26.4" } }, - "node_modules/@types/node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-bQVlnMLFJ2d35DkPNjEPmd9ueO/rh5EiaZt2bhqiSarPjZIuIV6bPQVqcrEyvNo+AfTrRGVazle1tl597w3gfA==", + "node_modules/@types/semver": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.16.0.tgz", + "integrity": "sha512-O5f7Kv5o4dLWQtPX4ywPPa+v9G+1q1x8mz0Kr0pXUtKsevo+gIJHLkGc8RxaZWtP8RrhwhSNIWThnW42K9/0rQ==", "dev": true, "dependencies": { - "@types/node": "*", - "form-data": "^4.0.0" + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.16.0", + "@typescript-eslint/type-utils": "6.16.0", + "@typescript-eslint/utils": "6.16.0", + "@typescript-eslint/visitor-keys": "6.16.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.16.0.tgz", + "integrity": "sha512-H2GM3eUo12HpKZU9njig3DF5zJ58ja6ahj1GoHEHOgQvYxzoFJJEvC1MQ7T2l9Ha+69ZSOn7RTxOdpC/y3ikMw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.16.0", + "@typescript-eslint/types": "6.16.0", + "@typescript-eslint/typescript-estree": "6.16.0", + "@typescript-eslint/visitor-keys": "6.16.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.16.0.tgz", + "integrity": "sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.16.0", + "@typescript-eslint/visitor-keys": "6.16.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.16.0.tgz", + "integrity": "sha512-ThmrEOcARmOnoyQfYkHw/DX2SEYBalVECmoldVuH6qagKROp/jMnfXpAU/pAIWub9c4YTxga+XwgAkoA0pxfmg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.16.0", + "@typescript-eslint/utils": "6.16.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.16.0.tgz", + "integrity": "sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.16.0.tgz", + "integrity": "sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.16.0", + "@typescript-eslint/visitor-keys": "6.16.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/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": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/utils": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.16.0.tgz", + "integrity": "sha512-T83QPKrBm6n//q9mv7oiSvy/Xq/7Hyw9SzSEhMHJwznEmQayfBM87+oAlkNAMEO7/MjIwKyOHgBJbxB0s7gx2A==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.16.0", + "@typescript-eslint/types": "6.16.0", + "@typescript-eslint/typescript-estree": "6.16.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz", + "integrity": "sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.16.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, "node_modules/@vitest/coverage-v8": { @@ -996,6 +1426,15 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/acorn-walk": { "version": "8.3.1", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", @@ -1005,6 +1444,31 @@ "node": ">=0.4.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/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1045,6 +1509,25 @@ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, "node_modules/arr-diff": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", @@ -1075,15 +1558,113 @@ "node": ">=0.10.0" } }, - "node_modules/array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha512-G2n5bG5fSUCpnsXz4+8FUkYsGPkNfLn9YvS66U5qbTIXI2Ynnlo4Bi42bWv+omKUCqz+ejzfClwne0alJWJPhg==", + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha512-G2n5bG5fSUCpnsXz4+8FUkYsGPkNfLn9YvS66U5qbTIXI2Ynnlo4Bi42bWv+omKUCqz+ejzfClwne0alJWJPhg==", "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -1102,6 +1683,12 @@ "node": ">=0.10.0" } }, + "node_modules/ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", + "dev": true + }, "node_modules/async-each": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", @@ -1114,12 +1701,6 @@ } ] }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, "node_modules/atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -1132,6 +1713,33 @@ "node": ">= 4.5.0" } }, + "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": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.8.3.tgz", + "integrity": "sha512-d5ZQHPSPkF9Tw+yfyDcRoUOc4g/8UloJJe5J8m4L5+c7AtDdjDLRxew/knnI4CxvtdxEUVgWz4x3OIQUIFiMfw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", + "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", + "dev": true + }, "node_modules/babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", @@ -1268,6 +1876,29 @@ "node": ">=0.10.0" } }, + "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/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/chai": { "version": "4.3.10", "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", @@ -1286,6 +1917,22 @@ "node": ">=4" } }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/check-error": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", @@ -1398,18 +2045,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/component-emitter": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", @@ -1425,6 +2060,12 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -1448,6 +2089,17 @@ "dev": true, "hasInstallScript": true }, + "node_modules/core-js-pure": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.34.0.tgz", + "integrity": "sha512-pmhivkYXkymswFfbXsANmBAewXx86UBfmagP+w0wkK06kLsLlTK5oQmsURPivzMkIBQiYq2cjamcZExIwlFQIg==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -1496,14 +2148,11 @@ "node": ">= 8" } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "dev": true, - "engines": { - "node": ">= 12" - } + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true }, "node_modules/debug": { "version": "4.3.4", @@ -1543,6 +2192,43 @@ "node": ">=6" } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "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/define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", @@ -1565,15 +2251,6 @@ "node": ">=0.10.0" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -1583,6 +2260,30 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", @@ -1601,6 +2302,112 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/es-abstract": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/esbuild": { "version": "0.19.10", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.10.tgz", @@ -1639,65 +2446,598 @@ "@esbuild/win32-x64": "0.19.10" } }, - "node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, "engines": { - "node": ">=16.17" + "node": ">=10" }, "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha512-hxx03P2dJxss6ceIeri9cmYOT4SRs3Zk3afZwWpOsRqLqprhTR8u++SlC+sFGsQr7WGFPdMF7Gjc1njDLDK6UA==", - "dev": true, - "dependencies": { - "is-posix-bracket": "^0.1.0" + "node_modules/eslint": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.2.0.tgz", + "integrity": "sha512-erw7XmM+CLxTOickrimJ1SiF55jiNlVSp2qqm0NuBWPtHYQCegD5ZMaW0c3i5ytPqL+SSLaCxdvQXFPLJn+ABw==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.0.4", + "@humanwhocodes/config-array": "^0.6.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^6.0.0", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.2.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" }, "engines": { - "node": ">=0.10.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha512-AFASGfIlnIbkKPQwX1yHaDjFvh/1gyKJODme52V6IORh69uEYgZp0o9C+qsIGNVEiuuhQU0CSSl++Rlegg1qvA==", + "node_modules/eslint-config-airbnb": { + "version": "19.0.4", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", + "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", "dev": true, "dependencies": { - "fill-range": "^2.1.0" + "eslint-config-airbnb-base": "^15.0.0", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5" }, "engines": { - "node": ">=0.10.0" + "node": "^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.28.0", + "eslint-plugin-react-hooks": "^4.3.0" } }, - "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "node_modules/eslint-config-airbnb-base": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", + "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", "dev": true, "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" }, "engines": { - "node": ">=0.10.0" - } + "node": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.2" + } + }, + "node_modules/eslint-config-airbnb-base/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.25.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz", + "integrity": "sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.1", + "has": "^1.0.3", + "is-core-module": "^2.8.0", + "is-glob": "^4.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.5", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz", + "integrity": "sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.16.3", + "aria-query": "^4.2.2", + "array-includes": "^3.1.4", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.3.5", + "axobject-query": "^2.2.0", + "damerau-levenshtein": "^1.0.7", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.2.1", + "language-tags": "^1.0.5", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.2.tgz", + "integrity": "sha512-dhlpWc9vOwohcWmClFcA+HjlvUpuyynYs0Rf+L/P6/0iQE6vlHW9l5bkfzN62/Stm9fbq8ku46qzde76T1xlSg==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz", + "integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.4", + "array.prototype.flatmap": "^1.2.5", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.0.4", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.0", + "object.values": "^1.1.5", + "prop-types": "^15.7.2", + "resolve": "^2.0.0-next.3", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.6" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz", + "integrity": "sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "dependencies": { + "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/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz", + "integrity": "sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint/node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "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/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/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha512-hxx03P2dJxss6ceIeri9cmYOT4SRs3Zk3afZwWpOsRqLqprhTR8u++SlC+sFGsQr7WGFPdMF7Gjc1njDLDK6UA==", + "dev": true, + "dependencies": { + "is-posix-bracket": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha512-AFASGfIlnIbkKPQwX1yHaDjFvh/1gyKJODme52V6IORh69uEYgZp0o9C+qsIGNVEiuuhQU0CSSl++Rlegg1qvA==", + "dev": true, + "dependencies": { + "fill-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, "node_modules/extend-shallow/node_modules/is-extendable": { "version": "1.0.1", @@ -1723,27 +3063,135 @@ "node": ">=0.10.0" } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "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-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" }, "engines": { - "node": "^12.20 || >= 14.13" + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-glob/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-glob/node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-glob/node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-glob/node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "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/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" } }, "node_modules/file-uri-to-path": { @@ -1784,6 +3232,50 @@ "integrity": "sha512-uJ5vWrfBKMcE6y2Z8834dwEZj9mNGxYa3t3I53OwFeuZ8D9oc2E5zcsrkuhX6h4iYrjhiv0T3szQmxlAV9uxDg==", "dev": true }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "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/for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -1821,32 +3313,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dev": true, - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -1893,6 +3359,39 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "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", @@ -1902,6 +3401,21 @@ "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/get-stream": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", @@ -1914,6 +3428,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -1952,29 +3482,100 @@ "glob-parent": "^2.0.0", "is-glob": "^2.0.0" }, - "engines": { - "node": ">=0.10.0" + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==", + "dev": true, + "dependencies": { + "is-glob": "^2.0.0" + } + }, + "node_modules/glob2base": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", + "integrity": "sha512-ZyqlgowMbfj2NPjxaZZ/EtsXlOch28FRXgMd64vqZWk1bT9+wvSRLYD1om9M7QfQru51zJPAT17qXm4/zd+9QA==", + "dev": true, + "dependencies": { + "find-index": "^0.1.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==", + "node_modules/globby/node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", "dev": true, - "dependencies": { - "is-glob": "^2.0.0" + "engines": { + "node": ">= 4" } }, - "node_modules/glob2base": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", - "integrity": "sha512-ZyqlgowMbfj2NPjxaZZ/EtsXlOch28FRXgMd64vqZWk1bT9+wvSRLYD1om9M7QfQru51zJPAT17qXm4/zd+9QA==", + "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": { - "find-index": "^0.1.1" + "get-intrinsic": "^1.1.3" }, - "engines": { - "node": ">= 0.10" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/graceful-fs": { @@ -1983,6 +3584,30 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1992,6 +3617,57 @@ "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/has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -2091,6 +3767,40 @@ "node": ">=16.17.0" } }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -2107,6 +3817,20 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/internal-slot": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/is-accessor-descriptor": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", @@ -2119,6 +3843,32 @@ "node": ">= 0.10" } }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", @@ -2131,12 +3881,40 @@ "node": ">=0.10.0" } }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "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-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, + "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", @@ -2161,6 +3939,21 @@ "node": ">= 0.4" } }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-descriptor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", @@ -2234,6 +4027,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", @@ -2246,6 +4051,21 @@ "node": ">=0.10.0" } }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "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", @@ -2285,6 +4105,34 @@ "node": ">=0.10.0" } }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "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-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", @@ -2297,6 +4145,63 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -2389,22 +4294,70 @@ "node": ">=8" } }, - "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "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/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "minimist": "^1.2.0" }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "bin": { + "json5": "lib/cli.js" } }, "node_modules/jsonc-parser": { @@ -2413,6 +4366,30 @@ "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", "dev": true }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -2425,6 +4402,37 @@ "node": ">=0.10.0" } }, + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/local-pkg": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", @@ -2441,6 +4449,24 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/loupe": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", @@ -2536,6 +4562,15 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/micromatch": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", @@ -2560,27 +4595,6 @@ "node": ">=0.10.0" } }, - "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/mimic-fn": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", @@ -2734,42 +4748,11 @@ "node": ">=0.10.0" } }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "dev": true, - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true }, "node_modules/normalize-path": { "version": "2.1.1", @@ -2810,6 +4793,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", @@ -2849,6 +4841,24 @@ "node": ">= 0.4" } }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "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-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", @@ -2870,6 +4880,68 @@ "node": ">=0.10.0" } }, + "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/object.entries": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", + "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.hasown": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", + "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object.omit": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", @@ -2904,6 +4976,23 @@ "node": ">=0.10.0" } }, + "node_modules/object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2928,6 +5017,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/parse-glob": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", @@ -2992,6 +5110,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/pathe": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz", @@ -3013,6 +5140,18 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pkg-types": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", @@ -3079,6 +5218,15 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/preserve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", @@ -3088,6 +5236,34 @@ "node": ">=0.10.0" } }, + "node_modules/prettier": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz", + "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==", + "dev": true, + "peer": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -3120,6 +5296,61 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "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/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "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/randomatic": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", @@ -3494,6 +5725,35 @@ "node": ">=0.10.0" } }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, "node_modules/remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -3535,6 +5795,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -3551,6 +5820,16 @@ "node": ">=0.12" } }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rimraf": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", @@ -3658,6 +5937,53 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "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": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -3687,6 +6013,20 @@ "ret": "~0.1.10" } }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -3714,6 +6054,35 @@ "node": ">=10" } }, + "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/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", @@ -3771,6 +6140,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/siginfo": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", @@ -3789,6 +6172,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -4052,6 +6444,71 @@ "node": ">=8" } }, + "node_modules/string.prototype.matchall": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", + "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "regexp.prototype.flags": "^1.5.0", + "set-function-name": "^2.0.0", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -4077,6 +6534,15 @@ "node": ">=8" } }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/strip-final-newline": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", @@ -4089,6 +6555,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strip-literal": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz", @@ -4134,6 +6612,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -4148,6 +6642,12 @@ "node": ">=8" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "node_modules/tinybench": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.1.tgz", @@ -4208,6 +6708,39 @@ "node": ">=0.10.0" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/to-regex-range/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", @@ -4260,6 +6793,36 @@ "node": ">=0.3.1" } }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -4269,6 +6832,83 @@ "node": ">=4" } }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typescript": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", @@ -4288,11 +6928,27 @@ "integrity": "sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==", "dev": true }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "dev": true, + "peer": true }, "node_modules/union-value": { "version": "1.0.1", @@ -4366,6 +7022,15 @@ "node": ">=0.10.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/urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", @@ -4388,6 +7053,12 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/v8-compile-cache": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "dev": true + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -4575,15 +7246,6 @@ } } }, - "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4599,6 +7261,41 @@ "node": ">= 8" } }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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", diff --git a/package.json b/package.json index 94115c5..bcdb4ee 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,8 @@ "build": "rimraf dist && tsc", "test": "vitest run", "test-ci": "vitest run --coverage.enabled true", + "lint": "npx eslint ./src ./test && npx prettier -c src test", + "lint:fix": "npx eslint --fix ./src ./test && npx prettier -w src test", "pack": "npm run build && cpx {package.json,README.md} dist && npm pack ./dist --dry-run", "publish-npm": "npm run build && cpx {package.json,README.md} dist && npm publish ./dist" }, @@ -25,12 +27,21 @@ "url": "https://github.com/cbrianball/ts-odata-client/issues" }, "homepage": "https://github.com/cbrianball/ts-odata-client#readme", + "sideEffects": false, "devDependencies": { - "@types/node-fetch": "^2.5.12", + "@typescript-eslint/eslint-plugin": "^6.16.0", + "@typescript-eslint/parser": "^6.16.0", "@vitest/coverage-v8": "^1.1.0", "chai": "^4.3.4", "cpx": "^1.5.0", - "node-fetch": "^3.3.2", + "eslint": "^8.2.0", + "eslint-config-airbnb": "^19.0.4", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-prettier": "^5.1.2", + "eslint-plugin-react": "^7.28.0", + "eslint-plugin-react-hooks": "^4.3.0", "rimraf": "^5.0.5", "ts-node": "^10.0.0", "typescript": "^5.3.3", diff --git a/src/index.ts b/src/index.ts index 11dc162..ca79601 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ export { ODataContext } from "./lib/ODataContext"; export { ODataQuery } from "./lib/ODataQuery"; export * from "./v4"; -export * from "./lib/ProxyFilterTypes"; \ No newline at end of file +export * from "./lib/ProxyFilterTypes"; diff --git a/src/lib/BooleanPredicateBuilder.ts b/src/lib/BooleanPredicateBuilder.ts index 19c426e..8ad5002 100644 --- a/src/lib/BooleanPredicateBuilder.ts +++ b/src/lib/BooleanPredicateBuilder.ts @@ -5,32 +5,31 @@ import { ExpressionOperator } from "./ExpressionOperator"; * Builds predicates based on boolean conditions. */ export class BooleanPredicateBuilder { + constructor(public readonly expression?: Expression) {} - constructor(public readonly expression?: Expression) { } + /** + * Create an AND condition with a previous filter clause. + * @param predicate Use the same FilterBuilder that this method chain was invoked with. + */ + public and(predicate: BooleanPredicateBuilder) { + if (!this.expression) throw new Error(`'and' predicate must come after a non-empty Predicate`); + if (!predicate.expression) throw new Error(`'and' predicate must have at least one non-empty Predicate`); - /** - * Create an AND condition with a previous filter clause. - * @param predicate Use the same FilterBuilder that this method chain was invoked with. - */ - public and(predicate: BooleanPredicateBuilder) { - if (!this.expression) - throw new Error(`'and' predicate must come after a non-empty Predicate`); - if (!predicate.expression) - throw new Error(`'and' predicate must have at least one non-empty Predicate`); + return new BooleanPredicateBuilder( + new Expression(ExpressionOperator.And, [this.expression, predicate.expression]), + ); + } - return new BooleanPredicateBuilder(new Expression(ExpressionOperator.And, [this.expression, predicate.expression])); - } + /** + * Create an OR condition with a previous filter clause. + * @param predicate Use the same FilterBuilder that this method chain was invoked with. + */ + public or(predicate: BooleanPredicateBuilder) { + if (!this.expression) throw new Error(`'or' predicate must come after a non-empty Predicate`); + if (!predicate.expression) throw new Error(`'or' predicate must have at least one non-empty Predicate`); - /** - * Create an OR condition with a previous filter clause. - * @param predicate Use the same FilterBuilder that this method chain was invoked with. - */ - public or(predicate: BooleanPredicateBuilder) { - if (!this.expression) - throw new Error(`'or' predicate must come after a non-empty Predicate`); - if (!predicate.expression) - throw new Error(`'or' predicate must have at least one non-empty Predicate`); - - return new BooleanPredicateBuilder(new Expression(ExpressionOperator.Or, [this.expression, predicate.expression])); - } -} \ No newline at end of file + return new BooleanPredicateBuilder( + new Expression(ExpressionOperator.Or, [this.expression, predicate.expression]), + ); + } +} diff --git a/src/lib/ExcludeProperties.ts b/src/lib/ExcludeProperties.ts index 5000c7c..eebdda8 100644 --- a/src/lib/ExcludeProperties.ts +++ b/src/lib/ExcludeProperties.ts @@ -2,6 +2,9 @@ * From T Exclude set of properties that extend TK. * Example: Exclude<{name: string, age: number}, number> will result in the type {name: string} * */ -export type ExcludeProperties = Pick; \ No newline at end of file +export type ExcludeProperties = Pick< + T, + { + [K in keyof T]: T[K] extends TK ? never : K; + }[keyof T] +>; diff --git a/src/lib/Expression.ts b/src/lib/Expression.ts index 2b7e061..c62773a 100644 --- a/src/lib/Expression.ts +++ b/src/lib/Expression.ts @@ -5,19 +5,23 @@ import { ExpressionOperator } from "./ExpressionOperator"; * Provides a way of expression operations that can be evaluated at run-time */ export class Expression { - constructor(public operator: ExpressionOperator, public operands: any[], public previous?: Expression) { } + constructor( + public operator: ExpressionOperator, + public operands: unknown[], + public previous?: Expression, + ) {} - /** - * Helper method to create a literal value with an optional type provided. - * @param value The literal value. - * @param literalType The type of the literal value (may be different than the runtime type given). - */ - static literal(value: T, literalType: string = typeof value) { - return new TypedExpression(ExpressionOperator.Literal, [new Literal(value, literalType)]); - } + /** + * Helper method to create a literal value with an optional type provided. + * @param value The literal value. + * @param literalType The type of the literal value (may be different than the runtime type given). + */ + static literal(value: T, literalType: string = typeof value) { + return new TypedExpression(ExpressionOperator.Literal, [new Literal(value, literalType)]); + } } /** * An @type {Expression} that indicates the type of the result. Primarily used for providing type checking for TypeScript. */ -export class TypedExpression extends Expression { } \ No newline at end of file +export class TypedExpression extends Expression {} diff --git a/src/lib/ExpressionOperator.ts b/src/lib/ExpressionOperator.ts index 183786f..ea3e1cf 100644 --- a/src/lib/ExpressionOperator.ts +++ b/src/lib/ExpressionOperator.ts @@ -2,32 +2,32 @@ * The supported @type {Expression} operators. */ export const enum ExpressionOperator { - And = "and", - Contains = "contains", - EndsWith = "endsWith", - Equals = "equals", - Expand = "expand", - ExpandAll = "expandAll", - FieldReference = "fieldReference", - GetByKey = "getByKey", - GetWithCount = "getWithCount", - GreaterThan = "greaterThan", - GreaterThanOrEqualTo = "greaterThanOrEqualTo", - In = "in", - LessThan = "lessThan", - LessThanOrEqualTo = "lessThanOrEqualTo", - Literal = "literal", - Not = "not", - NotEquals = "notEquals", - Or = "or", - OrderBy = "orderBy", - OrderByDescending = "orderByDescending", - Predicate = "predicate", - Select = "select", - Skip = "skip", - StartsWith = "startsWith", - Top = "top", - Any = "any", - All = "all", - Value = "value", -} \ No newline at end of file + And = "and", + Contains = "contains", + EndsWith = "endsWith", + Equals = "equals", + Expand = "expand", + ExpandAll = "expandAll", + FieldReference = "fieldReference", + GetByKey = "getByKey", + GetWithCount = "getWithCount", + GreaterThan = "greaterThan", + GreaterThanOrEqualTo = "greaterThanOrEqualTo", + In = "in", + LessThan = "lessThan", + LessThanOrEqualTo = "lessThanOrEqualTo", + Literal = "literal", + Not = "not", + NotEquals = "notEquals", + Or = "or", + OrderBy = "orderBy", + OrderByDescending = "orderByDescending", + Predicate = "predicate", + Select = "select", + Skip = "skip", + StartsWith = "startsWith", + Top = "top", + Any = "any", + All = "all", + Value = "value", +} diff --git a/src/lib/ExpressionVisitor.ts b/src/lib/ExpressionVisitor.ts index d902b82..4b781ce 100644 --- a/src/lib/ExpressionVisitor.ts +++ b/src/lib/ExpressionVisitor.ts @@ -1,9 +1,8 @@ -import { Expression } from "./Expression"; +import type { Expression } from "./Expression"; /** * Interface used by any type that translates an Expression into a Domain Specific Language (DSL). */ export interface ExpressionVisitor { - visit(expression: Expression): void; + visit(expression: Expression): void; } - diff --git a/src/lib/FieldReference.ts b/src/lib/FieldReference.ts index 2b69875..546ab3c 100644 --- a/src/lib/FieldReference.ts +++ b/src/lib/FieldReference.ts @@ -4,6 +4,8 @@ import type { FieldsFor } from "./FieldsForType"; * Represnets a reference to a field (instead of a literal value). */ export class FieldReference { - constructor(public field: FieldsFor) { } - public toString() { return this.field; } -} \ No newline at end of file + constructor(public field: FieldsFor) {} + public toString() { + return this.field; + } +} diff --git a/src/lib/FieldsForType.ts b/src/lib/FieldsForType.ts index 947b9ec..1c2307c 100644 --- a/src/lib/FieldsForType.ts +++ b/src/lib/FieldsForType.ts @@ -1,4 +1,4 @@ /** * Returns all fields within type T that are strings (e.g., not symbols or numbers) */ -export type FieldsFor = string & keyof T; \ No newline at end of file +export type FieldsFor = string & keyof T; diff --git a/src/lib/FilterAccessoryFunctions.ts b/src/lib/FilterAccessoryFunctions.ts index 7e086ee..9bb2674 100644 --- a/src/lib/FilterAccessoryFunctions.ts +++ b/src/lib/FilterAccessoryFunctions.ts @@ -6,35 +6,32 @@ import { ExpressionOperator } from "./ExpressionOperator"; * Provides additional functionality for the .filter() method on @type {ODataQuery} */ export class FilterAccessoryFunctions { - constructor() { - // Ensure the methods are bound to this object; - // Even if they become detatched (e.g., destructuring) - this.and = this.and.bind(this); - this.or = this.or.bind(this); - this.not = this.not.bind(this); - } + constructor() { + // Ensure the methods are bound to this object; + // Even if they become detatched (e.g., destructuring) + this.and = this.and.bind(this); + this.or = this.or.bind(this); + this.not = this.not.bind(this); + } - and(...predicates: BooleanPredicateBuilder[]) { - return this.combinePredicates(ExpressionOperator.And, ...predicates); - } + and(...predicates: BooleanPredicateBuilder[]) { + return this.combinePredicates(ExpressionOperator.And, ...predicates); + } - or(...predicates: BooleanPredicateBuilder[]) { - return this.combinePredicates(ExpressionOperator.Or, ...predicates); - } + or(...predicates: BooleanPredicateBuilder[]) { + return this.combinePredicates(ExpressionOperator.Or, ...predicates); + } - not(predicate: BooleanPredicateBuilder) { - return new BooleanPredicateBuilder(new Expression(ExpressionOperator.Not, [predicate.expression])); - } + not(predicate: BooleanPredicateBuilder) { + return new BooleanPredicateBuilder(new Expression(ExpressionOperator.Not, [predicate.expression])); + } - private combinePredicates(operator: ExpressionOperator, ...predicates: BooleanPredicateBuilder[]) { - if (predicates.length === 0) - throw new Error('At least one predicate must be provided'); + private combinePredicates(operator: ExpressionOperator, ...predicates: BooleanPredicateBuilder[]) { + if (predicates.length === 0) throw new Error("At least one predicate must be provided"); - return predicates - .reduce((acc, predicate, index) => { - if (index === 0) - return predicate; - return new BooleanPredicateBuilder(new Expression(operator, [acc.expression, predicate.expression])); - }); - } -} \ No newline at end of file + return predicates.reduce((acc, predicate, index) => { + if (index === 0) return predicate; + return new BooleanPredicateBuilder(new Expression(operator, [acc.expression, predicate.expression])); + }); + } +} diff --git a/src/lib/JsonPrimitiveTypes.ts b/src/lib/JsonPrimitiveTypes.ts index dfba975..e636ff0 100644 --- a/src/lib/JsonPrimitiveTypes.ts +++ b/src/lib/JsonPrimitiveTypes.ts @@ -1,4 +1,4 @@ /** * Simple types that can be expressed in JSON format */ -export type JsonPrimitiveValueTypes = number | string | boolean; \ No newline at end of file +export type JsonPrimitiveValueTypes = number | string | boolean; diff --git a/src/lib/Literal.ts b/src/lib/Literal.ts index 206aab5..ca23424 100644 --- a/src/lib/Literal.ts +++ b/src/lib/Literal.ts @@ -2,5 +2,8 @@ * Represents a literal value, the provided type may be different than that of the runtime type (e.g., Guid instead of a string). */ export class Literal { - constructor(public value: any, public literalType?: string) { } -} \ No newline at end of file + constructor( + public value: unknown, + public literalType?: string, + ) {} +} diff --git a/src/lib/ODataContext.ts b/src/lib/ODataContext.ts index ff97ca8..1dcf2ed 100644 --- a/src/lib/ODataContext.ts +++ b/src/lib/ODataContext.ts @@ -1,15 +1,15 @@ -import { ODataQuery } from "./ODataQuery"; +import type { ODataQuery } from "./ODataQuery"; import type { ExcludeProperties } from "./ExcludeProperties"; /** * Base ODataContext class; expected to implement specific versions of OData. */ export abstract class ODataContext { - constructor(protected basePath: string) { } + constructor(protected basePath: string) {} - /** - * Creates an @type {ODataQuery} instance used to query the provided endpoint. - * @param endpoint The path, relative to the basePath provided to the contructor. - */ - protected abstract createQuery>(endpoint: string): ODataQuery; -} \ No newline at end of file + /** + * Creates an @type {ODataQuery} instance used to query the provided endpoint. + * @param endpoint The path, relative to the basePath provided to the contructor. + */ + protected abstract createQuery>(endpoint: string): ODataQuery; +} diff --git a/src/lib/ODataQuery.ts b/src/lib/ODataQuery.ts index f6fef17..2aaa81a 100644 --- a/src/lib/ODataQuery.ts +++ b/src/lib/ODataQuery.ts @@ -1,202 +1,233 @@ -import { ODataQueryProvider } from "./ODataQueryProvider"; +import type { ODataQueryProvider } from "./ODataQueryProvider"; import { FieldReference } from "./FieldReference"; import { Expression } from "./Expression"; -import { ODataQueryResponse, ODataQueryResponseWithCount, ODataResponse } from "./ODataResponse"; -import { BooleanPredicateBuilder } from "./BooleanPredicateBuilder"; +import type { ODataQueryResponse, ODataQueryResponseWithCount, ODataResponse } from "./ODataResponse"; +import type { BooleanPredicateBuilder } from "./BooleanPredicateBuilder"; import { ExpressionOperator } from "./ExpressionOperator"; -import { SubType } from "./SubType"; -import { ExcludeProperties } from "./ExcludeProperties"; -import { ODataV4QueryProvider, ODataV4Options } from "./ODataV4QueryProvider"; +import type { ExcludeProperties } from "./ExcludeProperties"; +import type { ODataV4Options } from "./ODataV4QueryProvider"; +import { ODataV4QueryProvider } from "./ODataV4QueryProvider"; import { FilterAccessoryFunctions } from "./FilterAccessoryFunctions"; -import { createProxiedEntity, resolveQuery, ReplaceDateWithString, ProjectorType } from "./ProxyFilterTypes"; -import { EntityProxy, PropertyProxy, propertyPath, proxyProperties } from "./ProxyTypes"; -import { FieldsFor } from "./FieldsForType"; +import type { ReplaceDateWithString, ProjectorType } from "./ProxyFilterTypes"; +import { createProxiedEntity, resolveQuery } from "./ProxyFilterTypes"; +import type { EntityProxy, PropertyProxy } from "./ProxyTypes"; +import { propertyPath, proxyProperties } from "./ProxyTypes"; +import type { FieldsFor } from "./FieldsForType"; import type { JsonPrimitiveValueTypes } from "./JsonPrimitiveTypes"; /** * Represents a query against an OData source. * This query is agnostic of the version of OData supported by the server (the provided @type {ODataQueryProvider} is responsible for translating the query into the correct syntax for the desired OData version supported by the endpoint). */ -export class ODataQuery> { - - static forV4(endpoint: string, options?: Partial) { - return new ODataQuery(new ODataV4QueryProvider(endpoint, options)); - } - - constructor(public readonly provider: ODataQueryProvider, public readonly expression?: Expression) { } - - /** - * Limits the fields that are returned; the most recent call to select() will be used. - * @param fields - */ - public select>(...fields: U[]): ODataQuery; - public select(projector: (proxy: T) => U): ODataQuery; - public select(...args: [(proxy: T) => U | FieldsFor, ...FieldsFor[]]) { - if (args.length === 0) throw new Error('Parameters are requird'); - - const firstArg = args[0]; - if (typeof firstArg === "function") { - const proxy = this.provider[createProxiedEntity](); - firstArg(proxy as unknown as T); - const expression = new Expression(ExpressionOperator.Select, [firstArg, ...getUsedPropertyPaths(proxy)], this.expression); - return this.provider.createQuery(expression); - } - - const expression = new Expression(ExpressionOperator.Select, (args as FieldsFor[]).map(v => new FieldReference(v)), this.expression); - return this.provider.createQuery(expression); - } - - /** - * Returns the top n records; the most recent call to top() will be used. - * @param n - */ - public top(n: number) { - const expression = new Expression(ExpressionOperator.Top, [n], this.expression); - return this.provider.createQuery(expression); - } - - /** - * Omits the first n records from appear in the returned records; the most recent call to skip() will be used. - * @param n - */ - public skip(n: number) { - const expression = new Expression(ExpressionOperator.Skip, [n], this.expression); - return this.provider.createQuery(expression); - } - - /** - * Determines the sort order (ascending) of the records; calls or orderBy() and orderByDescending() are cumulative. - * @param fields - */ - public orderBy(fields: (entity: EntityProxy) => PropertyProxy | Array>) { - const proxy = this.provider[createProxiedEntity](); - const properties = [fields(proxy)].flat() - const expression = new Expression(ExpressionOperator.OrderBy, - properties.map(f => new FieldReference(f[propertyPath].join('/') as unknown as FieldsFor)), - this.expression); - return this.provider.createQuery(expression); - } - - /** - * Determines the sort order (descending) of the records; calls to orderBy() and orderByDescending() are cumulative. - * @param fields - */ - public orderByDescending(fields: (entity: EntityProxy) => PropertyProxy | Array>) { - const proxy = this.provider[createProxiedEntity](); - const properties = [fields(proxy)].flat() - const expression = new Expression(ExpressionOperator.OrderByDescending, - properties.map((f => new FieldReference(f[propertyPath].join('/') as unknown as FieldsFor))), - this.expression); - return this.provider.createQuery(expression); - } - - /** - * Filters the records based on the provided expression; multiple calls to filter() are cumulative (as well as UNIONed (AND)) - * @param predicate A function that takes in an entity proxy and returns a BooleanPredicateBuilder. - */ - public filter(predicate: BooleanPredicateBuilder | ((builder: EntityProxy, functions: FilterAccessoryFunctions) => BooleanPredicateBuilder)) { - if (typeof predicate === "function") - predicate = predicate(this.provider[createProxiedEntity]() as unknown as EntityProxy, new FilterAccessoryFunctions()); - - const expression = new Expression(ExpressionOperator.Predicate, [predicate], this.expression); - return this.provider.createQuery(expression); - } - - /** - * Includes the indicated arrays are to be returned as part of the query results. - * @param fields - */ - public expand | Date | ArrayLike>>(...fields: K[]) { - const expression = new Expression(ExpressionOperator.Expand, fields.map(f => new FieldReference(f)), this.expression); - return this.provider.createQuery>(expression); - } - - /** - * Includes all arrays as part of the query results. - * @param fields - */ - public expandAll() { - const expression = new Expression(ExpressionOperator.ExpandAll, [], this.expression); - return this.provider.createQuery(expression); - } - - /** - * Returns a single record with the provided key value. Some functions (such as top, skip, filter, etc.) are ignored when this function is invoked. - * @param key - */ - public async getAsync(key: any) { - const expression = new Expression(ExpressionOperator.GetByKey, [key], this.expression); - // return await this.provider.executeQueryAsync>(expression); - const result = await this.provider.executeQueryAsync>(expression); - const selectMap = getSelectMap(expression); - if (selectMap == null) return result; - - const newResult = selectMap(result) as unknown as ODataResponse & ReplaceDateWithString; - newResult["@odata.context"] = result["@odata.context"]; - return newResult; - } - - /** - * Returns a set of records. - */ - public async getManyAsync() { - const results = await this.provider.executeQueryAsync>>(this.expression); - const selectMap = getSelectMap(this.expression); - if (selectMap != null) { - results.value = results.value.map(selectMap) as unknown as ReplaceDateWithString[]; - } - return results; - } - - /** - * Returns a set of records, including the total count of records, which may not be the same as the number of records return if the results are paginated. - */ - public async getManyWithCountAsync() { - const expression = new Expression(ExpressionOperator.GetWithCount, [], this.expression); - const results = await this.provider.executeQueryAsync>>(expression); - const selectMap = getSelectMap(expression); - if (selectMap != null) { - results.value = results.value.map(selectMap) as unknown as ReplaceDateWithString[]; - } - return results; - } - - public async getValueAsync() { - const expression = new Expression(ExpressionOperator.Value, [], this.expression); - return await this.provider.executeRequestAsync(expression) - .then(r => r.blob()); - - } - - [resolveQuery]() { - return this.provider.buildQuery(this.expression); - } +export class ODataQuery> { + static forV4(endpoint: string, options?: Partial) { + return new ODataQuery(new ODataV4QueryProvider(endpoint, options)); + } + + constructor( + public readonly provider: ODataQueryProvider, + public readonly expression?: Expression, + ) {} + + /** + * Limits the fields that are returned; the most recent call to select() will be used. + * @param fields + */ + public select>(...fields: U[]): ODataQuery; + public select(projector: (proxy: T) => U): ODataQuery; + public select(...args: [(proxy: T) => U | FieldsFor, ...FieldsFor[]]) { + if (args.length === 0) throw new Error("Parameters are requird"); + + const firstArg = args[0]; + if (typeof firstArg === "function") { + const proxy = this.provider[createProxiedEntity](); + firstArg(proxy as unknown as T); + const expression = new Expression( + ExpressionOperator.Select, + [firstArg, ...getUsedPropertyPaths(proxy)], + this.expression, + ); + return this.provider.createQuery(expression); + } + + const expression = new Expression( + ExpressionOperator.Select, + (args as FieldsFor[]).map((v) => new FieldReference(v)), + this.expression, + ); + return this.provider.createQuery(expression); + } + + /** + * Returns the top n records; the most recent call to top() will be used. + * @param n + */ + public top(n: number) { + const expression = new Expression(ExpressionOperator.Top, [n], this.expression); + return this.provider.createQuery(expression); + } + + /** + * Omits the first n records from appear in the returned records; the most recent call to skip() will be used. + * @param n + */ + public skip(n: number) { + const expression = new Expression(ExpressionOperator.Skip, [n], this.expression); + return this.provider.createQuery(expression); + } + + /** + * Determines the sort order (ascending) of the records; calls or orderBy() and orderByDescending() are cumulative. + * @param fields + */ + public orderBy(fields: (entity: EntityProxy) => PropertyProxy | Array>) { + const proxy = this.provider[createProxiedEntity](); + const properties = [fields(proxy)].flat(); + const expression = new Expression( + ExpressionOperator.OrderBy, + properties.map((f) => new FieldReference(f[propertyPath].join("/") as unknown as FieldsFor)), + this.expression, + ); + return this.provider.createQuery(expression); + } + + /** + * Determines the sort order (descending) of the records; calls to orderBy() and orderByDescending() are cumulative. + * @param fields + */ + public orderByDescending(fields: (entity: EntityProxy) => PropertyProxy | Array>) { + const proxy = this.provider[createProxiedEntity](); + const properties = [fields(proxy)].flat(); + const expression = new Expression( + ExpressionOperator.OrderByDescending, + properties.map((f) => new FieldReference(f[propertyPath].join("/") as unknown as FieldsFor)), + this.expression, + ); + return this.provider.createQuery(expression); + } + + /** + * Filters the records based on the provided expression; multiple calls to filter() are cumulative (as well as UNIONed (AND)) + * @param predicate A function that takes in an entity proxy and returns a BooleanPredicateBuilder. + */ + public filter( + predicate: + | BooleanPredicateBuilder + | ((builder: EntityProxy, functions: FilterAccessoryFunctions) => BooleanPredicateBuilder), + ) { + if (typeof predicate === "function") + predicate = predicate( + this.provider[createProxiedEntity]() as unknown as EntityProxy, + new FilterAccessoryFunctions(), + ); + + const expression = new Expression(ExpressionOperator.Predicate, [predicate], this.expression); + return this.provider.createQuery(expression); + } + + /** + * Includes the indicated arrays are to be returned as part of the query results. + * @param fields + */ + public expand< + K extends keyof ExcludeProperties< + T, + JsonPrimitiveValueTypes | ArrayLike | Date | ArrayLike + >, + >(...fields: K[]) { + const expression = new Expression( + ExpressionOperator.Expand, + fields.map((f) => new FieldReference(f as unknown as FieldsFor)), + this.expression, + ); + return this.provider.createQuery>(expression); + } + + /** + * Includes all arrays as part of the query results. + * @param fields + */ + public expandAll() { + const expression = new Expression(ExpressionOperator.ExpandAll, [], this.expression); + return this.provider.createQuery(expression); + } + + /** + * Returns a single record with the provided key value. Some functions (such as top, skip, filter, etc.) are ignored when this function is invoked. + * @param key + */ + public async getAsync(key: unknown) { + const expression = new Expression(ExpressionOperator.GetByKey, [key], this.expression); + // return await this.provider.executeQueryAsync>(expression); + const result = await this.provider.executeQueryAsync>(expression); + const selectMap = getSelectMap(expression); + if (selectMap == null) return result; + + const newResult = selectMap(result) as unknown as ODataResponse & ReplaceDateWithString; + newResult["@odata.context"] = result["@odata.context"]; + return newResult; + } + + /** + * Returns a set of records. + */ + public async getManyAsync() { + const results = await this.provider.executeQueryAsync>>( + this.expression, + ); + const selectMap = getSelectMap(this.expression); + if (selectMap != null) { + results.value = results.value.map(selectMap) as unknown as ReplaceDateWithString[]; + } + return results; + } + + /** + * Returns a set of records, including the total count of records, which may not be the same as the number of records return if the results are paginated. + */ + public async getManyWithCountAsync() { + const expression = new Expression(ExpressionOperator.GetWithCount, [], this.expression); + const results = + await this.provider.executeQueryAsync>>(expression); + const selectMap = getSelectMap(expression); + if (selectMap != null) { + results.value = results.value.map(selectMap) as unknown as ReplaceDateWithString[]; + } + return results; + } + + public async getValueAsync() { + const expression = new Expression(ExpressionOperator.Value, [], this.expression); + return await this.provider.executeRequestAsync(expression).then((r) => r.blob()); + } + + [resolveQuery]() { + return this.provider.buildQuery(this.expression); + } } - - /** * Function that returns all OData paths that were used by the proxy. - * @param projectTarget + * @param projectTarget * @returns An array of paths found within the object (if the same path is used more than once, the duplicates are removed) */ function getUsedPropertyPaths(proxy: EntityProxy): string[] { - const paths: string[] = []; - for (const p of proxy[proxyProperties]) { - if (p[proxyProperties].length === 0) paths.push(p[propertyPath].join('/')); - else paths.push(...getUsedPropertyPaths(p)); - } + const paths: string[] = []; + for (const p of proxy[proxyProperties]) { + if (p[proxyProperties].length === 0) paths.push(p[propertyPath].join("/")); + else paths.push(...getUsedPropertyPaths(p)); + } - return Array.from(new Set(paths.flat())); + return Array.from(new Set(paths.flat())); } function getSelectMap(expression?: Expression): ((entity: T) => U) | undefined { - while (expression != null) { - if (expression.operator === ExpressionOperator.Select) { - const firstOperand = expression.operands[0]; - return (typeof firstOperand === "function") ? firstOperand : undefined; - } - expression = expression.previous; - } - return; -} \ No newline at end of file + while (expression != null) { + if (expression.operator === ExpressionOperator.Select) { + const firstOperand = expression.operands[0]; + return typeof firstOperand === "function" ? (firstOperand as (entity: T) => U) : undefined; + } + expression = expression.previous; + } + return; +} diff --git a/src/lib/ODataQueryProvider.ts b/src/lib/ODataQueryProvider.ts index dfc1ba3..dddaaa0 100644 --- a/src/lib/ODataQueryProvider.ts +++ b/src/lib/ODataQueryProvider.ts @@ -1,92 +1,95 @@ -import { ODataResponse } from "./ODataResponse"; +import type { ODataResponse } from "./ODataResponse"; import { ODataQuery } from "./ODataQuery"; -import { Expression } from "./Expression"; +import type { Expression } from "./Expression"; import { ProxyPropertyPredicate } from "./ProxyPropertyPredicate"; import { createProxiedEntity } from "./ProxyFilterTypes"; -import { lambdaVariable, proxyProperties, propertyPath, EntityProxy, PropertyProxy } from "./ProxyTypes"; - - +import type { EntityProxy, PropertyProxy } from "./ProxyTypes"; +import { lambdaVariable, proxyProperties, propertyPath } from "./ProxyTypes"; /** * Base type used by all @type {ODataQueryProvider} implementations. */ export abstract class ODataQueryProvider { - /** - * Creates a new @type {ODataQuery} using the current provider. - * @param expression The @type {Expression} the query will be based on. - */ - createQuery(expression?: Expression) { - return new ODataQuery(this, expression); - } + /** + * Creates a new @type {ODataQuery} using the current provider. + * @param expression The @type {Expression} the query will be based on. + */ + createQuery(expression?: Expression) { + return new ODataQuery(this, expression); + } - /** - * Executes the provided @type {Expression} and returns the results as a JSON object. - * @param expression - */ - abstract executeQueryAsync(expression?: Expression): Promise; + /** + * Executes the provided @type {Expression} and returns the results as a JSON object. + * @param expression + */ + abstract executeQueryAsync(expression?: Expression): Promise; - /** - * Executed the provided @type {Expression} and returns the raw response. - * @param expression - */ - abstract executeRequestAsync(expression?: Expression): Promise; + /** + * Executed the provided @type {Expression} and returns the raw response. + * @param expression + */ + abstract executeRequestAsync(expression?: Expression): Promise; - /** - * Returns the value that represents the query that will be executed. - * @param expression - */ - abstract buildQuery(expression?: Expression): any; + /** + * Returns the value that represents the query that will be executed. + * @param expression + */ + abstract buildQuery(expression?: Expression): unknown; - private lambdaProxyCounter = 0; - [createProxiedEntity](isLambdaProxy = false): EntityProxy { - const lambdaVariableName = isLambdaProxy ? `p${this.lambdaProxyCounter++}` : ''; - return new Proxy({ [lambdaVariable]: lambdaVariableName, [proxyProperties]: [] }, { - get: (instance: any, property: string | Symbol) => { - if (typeof property === "symbol") { - switch(property) { - case lambdaVariable: - return instance[lambdaVariable]; - case proxyProperties: - return instance[proxyProperties]; - default: - throw new Error('Unkonwn symbol'); - } - } - const path = [property as string]; - if (isLambdaProxy) { - path.unshift(lambdaVariableName); - } - const proxyProperty = this.createPropertyProxy(path); - instance[proxyProperties].push(proxyProperty); - return proxyProperty; + private lambdaProxyCounter = 0; + [createProxiedEntity](isLambdaProxy = false): EntityProxy { + const lambdaVariableName = isLambdaProxy ? `p${this.lambdaProxyCounter++}` : ""; + return new Proxy( + { [lambdaVariable]: lambdaVariableName, [proxyProperties]: new Array>() }, + { + get: (instance, property) => { + if (typeof property === "symbol") { + switch (property) { + case lambdaVariable: + return instance[lambdaVariable]; + case proxyProperties: + return instance[proxyProperties]; + default: + throw new Error("Unkonwn symbol"); } - }); - } + } + const path = [property as string]; + if (isLambdaProxy) { + path.unshift(lambdaVariableName); + } + const proxyProperty = this.createPropertyProxy(path); + instance[proxyProperties].push(proxyProperty); + return proxyProperty; + }, + }, + ) as unknown as EntityProxy; + } - private createPropertyProxy(navigationPath: string[]): PropertyProxy { - if (navigationPath.length === 0) throw new Error('PropertyProxy must be initialized with at least one proprety path'); - const target = { [propertyPath]: navigationPath, [proxyProperties]: [] }; - const predicate = new ProxyPropertyPredicate(target as unknown as PropertyProxy, this); - return new Proxy(target, { - get: (target: any, property: string | symbol) => { - if(typeof property === "symbol") { - switch(property) { - case propertyPath: - return target[propertyPath]; - case proxyProperties: - return target[proxyProperties]; - default: - throw new Error('Unknown symbol'); - } - } - - if ((property).startsWith("$")) { - return ((predicate as unknown as any)[property.slice(1)] as Function).bind(predicate); - } - const propertyProxy = this.createPropertyProxy([...navigationPath, property]); - target[proxyProperties].push(propertyProxy); - return propertyProxy; - } - }); - } -} \ No newline at end of file + private createPropertyProxy(navigationPath: string[]): PropertyProxy { + if (navigationPath.length === 0) + throw new Error("PropertyProxy must be initialized with at least one proprety path"); + const target = { [propertyPath]: navigationPath, [proxyProperties]: new Array>() }; + const predicate = new ProxyPropertyPredicate(target as unknown as PropertyProxy, this); + return new Proxy(target, { + get: (target, property) => { + if (typeof property === "symbol") { + switch (property) { + case propertyPath: + return target[propertyPath]; + case proxyProperties: + return target[proxyProperties]; + default: + throw new Error("Unknown symbol"); + } + } + + if (property.startsWith("$")) { + return (predicate as unknown as Record unknown>)[property.slice(1)].bind(predicate); + } + const propertyProxy = this.createPropertyProxy([...navigationPath, property]); + target[proxyProperties].push(propertyProxy); + return propertyProxy; + }, + }) as unknown as PropertyProxy; + } +} diff --git a/src/lib/ODataResponse.ts b/src/lib/ODataResponse.ts index f41e535..2c7c94f 100644 --- a/src/lib/ODataResponse.ts +++ b/src/lib/ODataResponse.ts @@ -2,25 +2,25 @@ * Represents an OData response with a single entity. */ export interface ODataResponse { - /** - * Type information about the result(s) returned. - */ - ["@odata.context"]: string; + /** + * Type information about the result(s) returned. + */ + ["@odata.context"]: string; } /** * Represents an OData response with 0 or more results. */ export interface ODataQueryResponse extends ODataResponse { - /** - * If server-side paging is implemented, this will hold the complete URL of the query used to retrieve the next 'page' of results. - */ - ["@odata.nextLink"]?: string; + /** + * If server-side paging is implemented, this will hold the complete URL of the query used to retrieve the next 'page' of results. + */ + ["@odata.nextLink"]?: string; - /** - * The results of the OData query - */ - value: T[]; + /** + * The results of the OData query + */ + value: T[]; } /** @@ -28,5 +28,5 @@ export interface ODataQueryResponse extends ODataResponse { * This value will be different than the number of items in @member {value} if server-side paging is implemented. */ export interface ODataQueryResponseWithCount extends ODataQueryResponse { - ["@odata.count"]?: number; -} \ No newline at end of file + ["@odata.count"]?: number; +} diff --git a/src/lib/ODataType.ts b/src/lib/ODataType.ts index 1187384..240152a 100644 --- a/src/lib/ODataType.ts +++ b/src/lib/ODataType.ts @@ -2,8 +2,8 @@ * Types specific to OData */ export const enum ODataType { - /**Represents a single calendar day (e.g., 1/1/1970) */ - Date = "date", - /**Represents a GUID */ - Guid = "guid", -} \ No newline at end of file + /**Represents a single calendar day (e.g., 1/1/1970) */ + Date = "date", + /**Represents a GUID */ + Guid = "guid", +} diff --git a/src/lib/ODataV4Context.ts b/src/lib/ODataV4Context.ts index 30573b4..cf47c7a 100644 --- a/src/lib/ODataV4Context.ts +++ b/src/lib/ODataV4Context.ts @@ -1,17 +1,21 @@ -import { ODataV4QueryProvider, ODataV4Options } from "./ODataV4QueryProvider"; +import type { ODataV4Options } from "./ODataV4QueryProvider"; +import { ODataV4QueryProvider } from "./ODataV4QueryProvider"; import { ODataContext } from "./ODataContext"; -import { ExcludeProperties } from "./ExcludeProperties"; +import type { ExcludeProperties } from "./ExcludeProperties"; /** * Base ODataContext class; use this class as a base for communicating with services that are compatible with OData v4. * This context uses the fetch library; if the runtime environment does not support fetch, please use a polyfill. */ export abstract class ODataV4Context extends ODataContext { - constructor(basePath: string, protected options?: Partial) { - super(basePath); - } + constructor( + basePath: string, + protected options?: Partial, + ) { + super(basePath); + } - protected createQuery>(endpoint: string) { - return new ODataV4QueryProvider(this.basePath + endpoint, this.options).createQuery(); - } -} \ No newline at end of file + protected createQuery>(endpoint: string) { + return new ODataV4QueryProvider(this.basePath + endpoint, this.options).createQuery(); + } +} diff --git a/src/lib/ODataV4ExpressionVisitor.ts b/src/lib/ODataV4ExpressionVisitor.ts index f466d02..2b9bd9b 100644 --- a/src/lib/ODataV4ExpressionVisitor.ts +++ b/src/lib/ODataV4ExpressionVisitor.ts @@ -1,230 +1,212 @@ import { TypedExpressionVisitor } from "./TypedExpressionVisitor"; import { FieldReference } from "./FieldReference"; -import { BooleanPredicateBuilder } from "./BooleanPredicateBuilder"; +import type { BooleanPredicateBuilder } from "./BooleanPredicateBuilder"; import { Expression } from "./Expression"; import { Literal } from "./Literal"; import { ExpressionOperator } from "./ExpressionOperator"; import { ODataType } from "./ODataType"; -type Sort = { field: string, sort?: 'desc' }; +type Sort = { field: string; sort?: "desc" }; export interface ODataV4QuerySegments { - select?: string[]; - orderBy?: Sort[]; - skip?: number; - top?: number; - filter?: string; - key?: any; - count?: boolean; - expand?: string[]; - value?: boolean; + select?: string[]; + orderBy?: Sort[]; + skip?: number; + top?: number; + filter?: string; + key?: unknown; + count?: boolean; + expand?: string[]; + value?: boolean; } /** * Converts a version-agnistic @type {Expression} into an object that holds information that adheres to ODataV4 speifications. */ export class ODataV4ExpressionVisitor extends TypedExpressionVisitor { + public readonly oDataQuery: ODataV4QuerySegments = {}; - public readonly oDataQuery: ODataV4QuerySegments = {} + selectVisitor(...fields: [FieldReference, ...FieldReference[]]) { + this.oDataQuery.select = fields.filter((v) => typeof v !== "function").map((f) => f.toString()); + } - selectVisitor(...fields: [Function | FieldReference, ...FieldReference[]]) { - this.oDataQuery.select = fields - .filter(v => typeof v !== "function") - .map(f => f.toString()); - } - - orderByVisitor(...fields: FieldReference[]) { - if (!this.oDataQuery.orderBy) this.oDataQuery.orderBy = []; - this.oDataQuery.orderBy.push(...fields.map(f => ({ field: f.toString() }))); - } - - orderByDescendingVisitor(...fields: FieldReference[]) { - if (!this.oDataQuery.orderBy) this.oDataQuery.orderBy = []; - this.oDataQuery.orderBy.push(...fields.map(f => ({ field: f.toString(), sort: 'desc' }))); - } + orderByVisitor(...fields: FieldReference[]) { + if (!this.oDataQuery.orderBy) this.oDataQuery.orderBy = []; + this.oDataQuery.orderBy.push(...fields.map((f) => ({ field: f.toString() }))); + } - skipVisitor(value: number) { - this.oDataQuery.skip = value; - } + orderByDescendingVisitor(...fields: FieldReference[]) { + if (!this.oDataQuery.orderBy) this.oDataQuery.orderBy = []; + this.oDataQuery.orderBy.push(...fields.map((f) => ({ field: f.toString(), sort: "desc" }))); + } - topVisitor(value: number) { - this.oDataQuery.top = value; - } + skipVisitor(value: number) { + this.oDataQuery.skip = value; + } - expandVisitor(...fields: FieldReference[]) { - if (!this.oDataQuery.expand || - this.oDataQuery.expand.some(v => v === "*")) - this.oDataQuery.expand = []; + topVisitor(value: number) { + this.oDataQuery.top = value; + } - this.oDataQuery.expand.push(...fields.map(f => f.toString())); + expandVisitor(...fields: FieldReference[]) { + if (!this.oDataQuery.expand || this.oDataQuery.expand.some((v) => v === "*")) this.oDataQuery.expand = []; - //ensure unique values - this.oDataQuery.expand = Array.from(new Set(this.oDataQuery.expand)); - } - - expandAllVisitor() { - this.oDataQuery.expand = ["*"]; - } + this.oDataQuery.expand.push(...fields.map((f) => f.toString())); - getWithCountVisitor() { - this.oDataQuery.count = true; - } + //ensure unique values + this.oDataQuery.expand = Array.from(new Set(this.oDataQuery.expand)); + } - getByKeyVisitor(key: any) { - if (key instanceof Expression) { - if (key.operator !== ExpressionOperator.Literal) - throw new Error(`Only literal expressions allowed for ${ExpressionOperator.Literal} expession types`); + expandAllVisitor() { + this.oDataQuery.expand = ["*"]; + } - key = key.operands[0]; - } + getWithCountVisitor() { + this.oDataQuery.count = true; + } - if (!(key instanceof Literal)) - key = new Literal(key); + getByKeyVisitor(key: unknown) { + if (key instanceof Expression) { + if (key.operator !== ExpressionOperator.Literal) + throw new Error(`Only literal expressions allowed for ${ExpressionOperator.Literal} expession types`); - this.oDataQuery.key = this.deriveLiteral(key); + key = key.operands[0]; } - valueVisitor() { - this.oDataQuery.value = true; - } + if (!(key instanceof Literal)) key = new Literal(key); - predicateVisitor(predicate: BooleanPredicateBuilder) { - if (!predicate.expression) return; + this.oDataQuery.key = this.deriveLiteral(key as Literal); + } - if (predicate.expression.previous) - throw new Error(`Filter Expressions cannot have a value for 'previous', only operands`); + valueVisitor() { + this.oDataQuery.value = true; + } - let filter = this.translatePredicateExpression(predicate.expression); + predicateVisitor(predicate: BooleanPredicateBuilder) { + if (!predicate.expression) return; - if (this.oDataQuery.filter && filter.length > 1) { - filter = ['(', ...filter, ')']; - } + if (predicate.expression.previous) + throw new Error(`Filter Expressions cannot have a value for 'previous', only operands`); - if (!this.oDataQuery.filter) - this.oDataQuery.filter = ""; + let filter = this.translatePredicateExpression(predicate.expression); - this.oDataQuery.filter += filter.join(' '); + if (this.oDataQuery.filter && filter.length > 1) { + filter = ["(", ...filter, ")"]; } - private translatePredicateExpression(expression: Expression): string[] { - let translation: string[][] = []; - for (let operand of expression.operands) { - if (operand instanceof Literal) { - translation.push([this.deriveLiteral(operand)]); - } - else if (operand instanceof FieldReference) { - translation.push([operand.toString()]); - } - else if (operand instanceof Expression) { - translation.push(this.translatePredicateExpression(operand)); - } - else if (operand instanceof Array) { - translation.push([operand.map(i => this.deriveLiteral(new Literal(i))).join(',')]); - } - else //assume this is a literal without the type specified - translation.push([this.deriveLiteral(new Literal(operand))]); - } - - if (translation.length === 1) { - switch (expression.operator) { - case ExpressionOperator.Not: - return ['not ' + this.reduceTranslatedExpression(translation[0])]; - default: - throw new Error(`Operator '${expression.operator}' is not supported`); - } - - } - else if (translation.length === 2) { - let [left, right] = translation; - - switch (expression.operator) { - case ExpressionOperator.And: - return [this.reduceTranslatedExpression(left), 'and', this.reduceTranslatedExpression(right)]; - case ExpressionOperator.Or: - return [this.reduceTranslatedExpression(left), 'or', this.reduceTranslatedExpression(right)]; - case ExpressionOperator.Equals: - return [`${this.reduceTranslatedExpression(left)} eq ${this.reduceTranslatedExpression(right)}`]; - case ExpressionOperator.GreaterThan: - return [`${this.reduceTranslatedExpression(left)} gt ${this.reduceTranslatedExpression(right)}`]; - case ExpressionOperator.GreaterThanOrEqualTo: - return [`${this.reduceTranslatedExpression(left)} ge ${this.reduceTranslatedExpression(right)}`]; - case ExpressionOperator.LessThan: - return [`${this.reduceTranslatedExpression(left)} lt ${this.reduceTranslatedExpression(right)}`]; - case ExpressionOperator.LessThanOrEqualTo: - return [`${this.reduceTranslatedExpression(left)} le ${this.reduceTranslatedExpression(right)}`]; - case ExpressionOperator.NotEquals: - return [`${this.reduceTranslatedExpression(left)} ne ${this.reduceTranslatedExpression(right)}`]; - case ExpressionOperator.Contains: - return [`contains(${this.reduceTranslatedExpression(left)},${this.reduceTranslatedExpression(right)})`]; - case ExpressionOperator.StartsWith: - return [`startsWith(${this.reduceTranslatedExpression(left)},${this.reduceTranslatedExpression(right)})`]; - case ExpressionOperator.EndsWith: - return [`endsWith(${this.reduceTranslatedExpression(left)},${this.reduceTranslatedExpression(right)})`]; - case ExpressionOperator.In: - return [`${this.reduceTranslatedExpression(left)} in (${this.reduceTranslatedExpression(right)})`]; - default: - throw new Error(`Operator '${expression.operator}' is not supported`); - } - } - else if (translation.length === 3) { - let [left, center, right] = translation; - switch (expression.operator) { - case ExpressionOperator.Any: - return [`${this.reduceTranslatedExpression(left)}/any(${center}: ${this.reduceTranslatedExpression(right)})`]; - case ExpressionOperator.All: - return [`${this.reduceTranslatedExpression(left)}/all(${center}: ${this.reduceTranslatedExpression(right)})`]; - default: - throw new Error(`Operator '${expression.operator}' is not supported`); - } - } - - throw new Error(`Operator '${expression.operator}' is not supported`); + if (!this.oDataQuery.filter) this.oDataQuery.filter = ""; + + this.oDataQuery.filter += filter.join(" "); + } + + private translatePredicateExpression(expression: Expression): string[] { + const translation: string[][] = []; + for (const operand of expression.operands) { + if (operand instanceof Literal) { + translation.push([this.deriveLiteral(operand)]); + } else if (operand instanceof FieldReference) { + translation.push([operand.toString()]); + } else if (operand instanceof Expression) { + translation.push(this.translatePredicateExpression(operand)); + } else if (operand instanceof Array) { + translation.push([operand.map((i) => this.deriveLiteral(new Literal(i))).join(",")]); + } //assume this is a literal without the type specified + else translation.push([this.deriveLiteral(new Literal(operand))]); + } + if (translation.length === 1) { + switch (expression.operator) { + case ExpressionOperator.Not: + return ["not " + this.reduceTranslatedExpression(translation[0])]; + default: + throw new Error(`Operator '${expression.operator}' is not supported`); + } + } else if (translation.length === 2) { + const [left, right] = translation; + + switch (expression.operator) { + case ExpressionOperator.And: + return [this.reduceTranslatedExpression(left), "and", this.reduceTranslatedExpression(right)]; + case ExpressionOperator.Or: + return [this.reduceTranslatedExpression(left), "or", this.reduceTranslatedExpression(right)]; + case ExpressionOperator.Equals: + return [`${this.reduceTranslatedExpression(left)} eq ${this.reduceTranslatedExpression(right)}`]; + case ExpressionOperator.GreaterThan: + return [`${this.reduceTranslatedExpression(left)} gt ${this.reduceTranslatedExpression(right)}`]; + case ExpressionOperator.GreaterThanOrEqualTo: + return [`${this.reduceTranslatedExpression(left)} ge ${this.reduceTranslatedExpression(right)}`]; + case ExpressionOperator.LessThan: + return [`${this.reduceTranslatedExpression(left)} lt ${this.reduceTranslatedExpression(right)}`]; + case ExpressionOperator.LessThanOrEqualTo: + return [`${this.reduceTranslatedExpression(left)} le ${this.reduceTranslatedExpression(right)}`]; + case ExpressionOperator.NotEquals: + return [`${this.reduceTranslatedExpression(left)} ne ${this.reduceTranslatedExpression(right)}`]; + case ExpressionOperator.Contains: + return [`contains(${this.reduceTranslatedExpression(left)},${this.reduceTranslatedExpression(right)})`]; + case ExpressionOperator.StartsWith: + return [`startsWith(${this.reduceTranslatedExpression(left)},${this.reduceTranslatedExpression(right)})`]; + case ExpressionOperator.EndsWith: + return [`endsWith(${this.reduceTranslatedExpression(left)},${this.reduceTranslatedExpression(right)})`]; + case ExpressionOperator.In: + return [`${this.reduceTranslatedExpression(left)} in (${this.reduceTranslatedExpression(right)})`]; + default: + throw new Error(`Operator '${expression.operator}' is not supported`); + } + } else if (translation.length === 3) { + const [left, center, right] = translation; + switch (expression.operator) { + case ExpressionOperator.Any: + return [`${this.reduceTranslatedExpression(left)}/any(${center}: ${this.reduceTranslatedExpression(right)})`]; + case ExpressionOperator.All: + return [`${this.reduceTranslatedExpression(left)}/all(${center}: ${this.reduceTranslatedExpression(right)})`]; + default: + throw new Error(`Operator '${expression.operator}' is not supported`); + } } - private reduceTranslatedExpression(value: string[]) { - if (value.length === 0) return ""; + throw new Error(`Operator '${expression.operator}' is not supported`); + } - if (value.length === 1) - return `${value[0]}`; + private reduceTranslatedExpression(value: string[]) { + if (value.length === 0) return ""; - return `(${value.join(' ')})`; - } + if (value.length === 1) return `${value[0]}`; + + return `(${value.join(" ")})`; + } - private deriveLiteral(literal: Literal): string { - const value = literal.value; - - switch (literal.literalType) { - case ODataType.Date: - return new Date(value).toISOString().substring(0, 10); - case ODataType.Guid: - return value.toString(); - } - - switch (typeof value) { - case "string": - return `'${value}'`; - case "number": - case "boolean": - return value.toString(); - case "undefined": - return 'null'; - case "function": - throw new Error("function not supported"); - case "symbol": - throw new Error("symbol not supported"); - case "object": - //objects handled below - break; - default: - throw new Error(`Unhandled primitive type: ${value}`); - } - - if (value === null) - return "null"; - if (value instanceof Date) - return value.toISOString(); + private deriveLiteral(literal: Literal): string { + const value = literal.value; + switch (literal.literalType) { + case ODataType.Date: + return new Date(value as string).toISOString().substring(0, 10); + case ODataType.Guid: + return (value as string).toString(); + } + + switch (typeof value) { + case "string": + return `'${value}'`; + case "number": + case "boolean": return value.toString(); + case "undefined": + return "null"; + case "function": + throw new Error("function not supported"); + case "symbol": + throw new Error("symbol not supported"); + case "object": + //objects handled below + break; + default: + throw new Error(`Unhandled primitive type: ${value}`); } -} \ No newline at end of file + + if (value === null) return "null"; + if (value instanceof Date) return value.toISOString(); + + return value.toString(); + } +} diff --git a/src/lib/ODataV4QueryProvider.ts b/src/lib/ODataV4QueryProvider.ts index 6f96aa0..f180114 100644 --- a/src/lib/ODataV4QueryProvider.ts +++ b/src/lib/ODataV4QueryProvider.ts @@ -1,11 +1,12 @@ import { ODataQueryProvider } from "./ODataQueryProvider"; -import { Expression } from "./Expression"; -import { ODataResponse } from "./ODataResponse"; -import { ODataV4ExpressionVisitor, ODataV4QuerySegments } from "./ODataV4ExpressionVisitor"; -import { ExcludeProperties } from "./ExcludeProperties"; +import type { Expression } from "./Expression"; +import type { ODataResponse } from "./ODataResponse"; +import type { ODataV4QuerySegments } from "./ODataV4ExpressionVisitor"; +import { ODataV4ExpressionVisitor } from "./ODataV4ExpressionVisitor"; +import type { ExcludeProperties } from "./ExcludeProperties"; export interface ODataV4Options { - requestInit: () => RequestInit | Promise; + requestInit: () => RequestInit | Promise; } /** @@ -13,89 +14,87 @@ export interface ODataV4Options { * Consumed by ODataContext classes; can also be used directly in lieu of creating an ODataContext class. */ export class ODataV4QueryProvider extends ODataQueryProvider { + constructor( + private readonly path: string, + private readonly options?: Partial, + ) { + super(); + } - constructor(private readonly path: string, private readonly options?: Partial) { - super(); - } - - static createQuery(path: string, options?: Partial) { - return new ODataV4QueryProvider(path, options) - .createQuery>(); - } + static createQuery(path: string, options?: Partial) { + return new ODataV4QueryProvider(path, options).createQuery>(); + } - private async sendRequest(expression?: Expression) { - const url = this.buildQuery(expression); + private async sendRequest(expression?: Expression) { + const url = this.buildQuery(expression); - let init = this.options?.requestInit?.() ?? {}; - if (init instanceof Promise) init = await init; + let init = this.options?.requestInit?.() ?? {}; + if (init instanceof Promise) init = await init; - return await fetch(url, init); - } + return await fetch(url, init); + } - async executeQueryAsync(expression?: Expression) { - const response = await this.sendRequest(expression); + async executeQueryAsync(expression?: Expression) { + const response = await this.sendRequest(expression); - if (response.ok) return await response.json() as T; + if (response.ok) return (await response.json()) as T; - throw new Error(JSON.stringify(await response.json())); - } + throw new Error(JSON.stringify(await response.json())); + } - async executeRequestAsync(expression?: Expression) { - const response = await this.sendRequest(expression); + async executeRequestAsync(expression?: Expression) { + const response = await this.sendRequest(expression); - if (response.ok) return response; + if (response.ok) return response; - throw new Error(await response.text()); - } + throw new Error(await response.text()); + } - buildQuery(expression?: Expression) { - return expression ? this.generateUrl(expression) : this.path; - } + buildQuery(expression?: Expression) { + return expression ? this.generateUrl(expression) : this.path; + } - private generateUrl(expression: Expression) { - const visitor = new ODataV4ExpressionVisitor(); - visitor.visit(expression); + private generateUrl(expression: Expression) { + const visitor = new ODataV4ExpressionVisitor(); + visitor.visit(expression); - let path = this.path; + let path = this.path; - if (visitor.oDataQuery.key) - path += `(${visitor.oDataQuery.key})`; + if (visitor.oDataQuery.key) path += `(${visitor.oDataQuery.key})`; - if(visitor.oDataQuery.value === true) { - path += "/$value"; - } + if (visitor.oDataQuery.value === true) { + path += "/$value"; + } - const queryString = this.buildQueryString(visitor.oDataQuery); + const queryString = this.buildQueryString(visitor.oDataQuery); - return path + queryString; - } + return path + queryString; + } - private buildQueryString(query: ODataV4QuerySegments) { - const queryString: string[] = []; + private buildQueryString(query: ODataV4QuerySegments) { + const queryString: string[] = []; - if (query.filter) - queryString.push(`$filter=${encodeURIComponent(query.filter)}`); + if (query.filter) queryString.push(`$filter=${encodeURIComponent(query.filter)}`); - if (query.orderBy) { - queryString.push(`$orderby=${encodeURIComponent(query.orderBy.map(o => o.sort ? `${o.field} ${o.sort}` : o.field).join(','))}`); - } + if (query.orderBy) { + queryString.push( + `$orderby=${encodeURIComponent( + query.orderBy.map((o) => (o.sort ? `${o.field} ${o.sort}` : o.field)).join(","), + )}`, + ); + } - if (query.select) - queryString.push(`$select=${encodeURIComponent(query.select.join(','))}`); + if (query.select) queryString.push(`$select=${encodeURIComponent(query.select.join(","))}`); - if (query.skip) - queryString.push(`$skip=${Math.floor(query.skip)}`); + if (query.skip) queryString.push(`$skip=${Math.floor(query.skip)}`); - if (typeof query.top === "number" && query.top >= 0) - queryString.push(`$top=${Math.floor(query.top)}`); + if (typeof query.top === "number" && query.top >= 0) queryString.push(`$top=${Math.floor(query.top)}`); - if (query.count) - queryString.push("$count=true"); + if (query.count) queryString.push("$count=true"); - if (query.expand) - queryString.push(`$expand=${encodeURIComponent(query.expand.join(','))}`); + if (query.expand) queryString.push(`$expand=${encodeURIComponent(query.expand.join(","))}`); - if (queryString.length > 0) return '?' + queryString.join("&"); - return ""; - } -} \ No newline at end of file + if (queryString.length > 0) return "?" + queryString.join("&"); + return ""; + } +} diff --git a/src/lib/ProxyFilterTypes.ts b/src/lib/ProxyFilterTypes.ts index c067c52..a610136 100644 --- a/src/lib/ProxyFilterTypes.ts +++ b/src/lib/ProxyFilterTypes.ts @@ -5,61 +5,87 @@ import type { EntityProxy, PropertyProxy } from "./ProxyTypes"; export const resolveQuery = Symbol(); export const createProxiedEntity = Symbol(); - type PrefixMembers = { - [P in string & keyof T as `${Prefix}${P}`]: T[P]; -} + [P in string & keyof T as `${Prefix}${P}`]: T[P]; +}; -export type ProxyFilterMethods = - PrefixMembers< - T extends boolean ? BooleanProxyFieldPredicate : - T extends number ? NumberProxyFieldPredicate : - T extends string ? StringProxyFieldPredicate : - T extends Date ? DateProxyFieldPredicate : - T extends Array ? ArrayProxyFieldPredicate : - // TODO: Array - unknown, '$'> +export type ProxyFilterMethods = PrefixMembers< + T extends boolean + ? BooleanProxyFieldPredicate + : T extends number + ? NumberProxyFieldPredicate + : T extends string + ? StringProxyFieldPredicate + : T extends Date + ? DateProxyFieldPredicate + : T extends Array + ? ArrayProxyFieldPredicate + : // TODO: Array + unknown, + "$" +>; export type PredicateArgument = T | PropertyProxy | null | undefined; export interface EqualityProxyFieldPredicate { - equals(value: PredicateArgument): BooleanPredicateBuilder; - notEquals(value: PredicateArgument): BooleanPredicateBuilder; - in(value: ArrayLike> | Iterable>): BooleanPredicateBuilder; + equals(value: PredicateArgument): BooleanPredicateBuilder; + notEquals(value: PredicateArgument): BooleanPredicateBuilder; + in(value: ArrayLike> | Iterable>): BooleanPredicateBuilder; } export interface InequalityProxyFieldPredicate { - lessThan(value: PredicateArgument): BooleanPredicateBuilder; - lessThanOrEqualTo(value: PredicateArgument): BooleanPredicateBuilder; - greaterThan(value: PredicateArgument): BooleanPredicateBuilder; - greaterThanOrEqualTo(value: PredicateArgument): BooleanPredicateBuilder; + lessThan(value: PredicateArgument): BooleanPredicateBuilder; + lessThanOrEqualTo(value: PredicateArgument): BooleanPredicateBuilder; + greaterThan(value: PredicateArgument): BooleanPredicateBuilder; + greaterThanOrEqualTo(value: PredicateArgument): BooleanPredicateBuilder; } -export interface BooleanProxyFieldPredicate extends EqualityProxyFieldPredicate { } -export interface NumberProxyFieldPredicate extends EqualityProxyFieldPredicate, InequalityProxyFieldPredicate { } -export interface DateProxyFieldPredicate extends EqualityProxyFieldPredicate, InequalityProxyFieldPredicate { } +export interface BooleanProxyFieldPredicate extends EqualityProxyFieldPredicate {} +export interface NumberProxyFieldPredicate + extends EqualityProxyFieldPredicate, + InequalityProxyFieldPredicate {} +export interface DateProxyFieldPredicate + extends EqualityProxyFieldPredicate, + InequalityProxyFieldPredicate {} /** * This only exists as something for the @type {ProxyFieldPredicate} to implement. * If it tried to implement @type {StringProxyFieldReference} directly, then TypeScript complains. */ - export interface StringProxyFieldPredicateInterface { - contains(value: PredicateArgument): BooleanPredicateBuilder; - startsWith(value: PredicateArgument): BooleanPredicateBuilder; - endsWith(value: PredicateArgument): BooleanPredicateBuilder; +export interface StringProxyFieldPredicateInterface { + contains(value: PredicateArgument): BooleanPredicateBuilder; + startsWith(value: PredicateArgument): BooleanPredicateBuilder; + endsWith(value: PredicateArgument): BooleanPredicateBuilder; } export interface ArrayProxyFieldPredicateInterface { - any(value: (entity: EntityProxy, compound: FilterAccessoryFunctions) => BooleanPredicateBuilder): BooleanPredicateBuilder; - all(value: (entity: EntityProxy, compound: FilterAccessoryFunctions) => BooleanPredicateBuilder): BooleanPredicateBuilder; + any( + value: ( + entity: EntityProxy, + compound: FilterAccessoryFunctions, + ) => BooleanPredicateBuilder, + ): BooleanPredicateBuilder; + all( + value: ( + entity: EntityProxy, + compound: FilterAccessoryFunctions, + ) => BooleanPredicateBuilder, + ): BooleanPredicateBuilder; } -interface ArrayProxyFieldPredicate> { - any(value: (entity: EntityProxy, compound: FilterAccessoryFunctions) => BooleanPredicateBuilder): BooleanPredicateBuilder; - all(value: (entity: EntityProxy, compound: FilterAccessoryFunctions) => BooleanPredicateBuilder): BooleanPredicateBuilder; +interface ArrayProxyFieldPredicate> { + any( + value: (entity: EntityProxy, compound: FilterAccessoryFunctions) => BooleanPredicateBuilder, + ): BooleanPredicateBuilder; + all( + value: (entity: EntityProxy, compound: FilterAccessoryFunctions) => BooleanPredicateBuilder, + ): BooleanPredicateBuilder; } -interface StringProxyFieldPredicate extends EqualityProxyFieldPredicate, InequalityProxyFieldPredicate, StringProxyFieldPredicateInterface { } +interface StringProxyFieldPredicate + extends EqualityProxyFieldPredicate, + InequalityProxyFieldPredicate, + StringProxyFieldPredicateInterface {} /** * Returned type from OData call. JSON does not natively support dates. @@ -67,10 +93,12 @@ interface StringProxyFieldPredicate extends EqualityProxyFieldPredicate, * but when data is actually received from OData service, the type, at runtime, will be a string. */ export type ReplaceDateWithString = { - [P in keyof T]: T[P] extends Date ? string : - T[P] extends boolean | string | number | Array ? T[P] : - ReplaceDateWithString; -} + [P in keyof T]: T[P] extends Date + ? string + : T[P] extends boolean | string | number | Array + ? T[P] + : ReplaceDateWithString; +}; /** * Useful to correctly type a class property that will be assigned a method's return value @@ -81,8 +109,12 @@ export type ReplaceDateWithString = { * } * If getUsers's return type is inferred, then any updates to the OData Query will automatically be reflected in the users field type. */ - export type AwaitedReturnType any> = T extends (...args: any) => infer R ? R extends Promise ? P : R : any; +export type AwaitedReturnType unknown> = T extends (...args: unknown[]) => infer R + ? R extends Promise + ? P + : R + : unknown; - export type ProjectorType = { - [K: string]: boolean | number | string | Date | Array | ProjectorType; - } \ No newline at end of file +export type ProjectorType = { + [K: string]: boolean | number | string | Date | Array | ProjectorType; +}; diff --git a/src/lib/ProxyPropertyPredicate.ts b/src/lib/ProxyPropertyPredicate.ts index 98b24fb..afdd815 100644 --- a/src/lib/ProxyPropertyPredicate.ts +++ b/src/lib/ProxyPropertyPredicate.ts @@ -2,100 +2,119 @@ import { BooleanPredicateBuilder } from "./BooleanPredicateBuilder"; import { Expression } from "./Expression"; import { ExpressionOperator } from "./ExpressionOperator"; import { FieldReference } from "./FieldReference"; -import { FieldsFor } from "./FieldsForType"; +import type { FieldsFor } from "./FieldsForType"; import { FilterAccessoryFunctions } from "./FilterAccessoryFunctions"; -import { ODataQueryProvider } from "./ODataQueryProvider"; -import { ArrayProxyFieldPredicateInterface, EqualityProxyFieldPredicate, InequalityProxyFieldPredicate, PredicateArgument, StringProxyFieldPredicateInterface, createProxiedEntity } from "./ProxyFilterTypes"; -import { EntityProxy, propertyPath, lambdaVariable, PropertyProxy } from "./ProxyTypes"; - -export class ProxyPropertyPredicate implements +import type { ODataQueryProvider } from "./ODataQueryProvider"; +import type { + ArrayProxyFieldPredicateInterface, + EqualityProxyFieldPredicate, + InequalityProxyFieldPredicate, + PredicateArgument, + StringProxyFieldPredicateInterface, +} from "./ProxyFilterTypes"; +import { createProxiedEntity } from "./ProxyFilterTypes"; +import type { EntityProxy, PropertyProxy } from "./ProxyTypes"; +import { propertyPath, lambdaVariable } from "./ProxyTypes"; + +export class ProxyPropertyPredicate + implements EqualityProxyFieldPredicate, InequalityProxyFieldPredicate, StringProxyFieldPredicateInterface, - ArrayProxyFieldPredicateInterface { - private readonly fieldReference: FieldReference; - - constructor(propertyProxy: PropertyProxy, private readonly provider: ODataQueryProvider) { - this.fieldReference = this.getFieldReference(propertyProxy); - } - - equals(value: PredicateArgument) { - return this.buildPredicateBuilder(value, ExpressionOperator.Equals); - } - - notEquals(value: PredicateArgument) { - return this.buildPredicateBuilder(value, ExpressionOperator.NotEquals); - } - - in(value: ArrayLike> | Iterable>) { - return this.buildPredicateBuilder(Array.from(value), ExpressionOperator.In); - } - - lessThan(value: PredicateArgument) { - return this.buildPredicateBuilder(value, ExpressionOperator.LessThan); - } - - lessThanOrEqualTo(value: PredicateArgument) { - return this.buildPredicateBuilder(value, ExpressionOperator.LessThanOrEqualTo); - } - - greaterThan(value: PredicateArgument) { - return this.buildPredicateBuilder(value, ExpressionOperator.GreaterThan); - } - - greaterThanOrEqualTo(value: PredicateArgument) { - return this.buildPredicateBuilder(value, ExpressionOperator.GreaterThanOrEqualTo); - } - - contains(value: PredicateArgument) { - return this.buildPredicateBuilder(value, ExpressionOperator.Contains); - } - - startsWith(value: PredicateArgument) { - return this.buildPredicateBuilder(value, ExpressionOperator.StartsWith); - } - - endsWith(value: PredicateArgument) { - return this.buildPredicateBuilder(value, ExpressionOperator.EndsWith); - } - - any(value: (entity: EntityProxy, compound: FilterAccessoryFunctions) => BooleanPredicateBuilder) { - const proxy = this.provider[createProxiedEntity](true); - const expression = value(proxy as unknown as EntityProxy, new FilterAccessoryFunctions()).expression; - - return this.buildCollectionFilterPredicateBuilder(expression!, ExpressionOperator.Any, proxy); - } - - all(value: (entity: EntityProxy, compound: FilterAccessoryFunctions) => BooleanPredicateBuilder) { - const proxy = this.provider[createProxiedEntity](true); - const expression = value(proxy as unknown as EntityProxy, new FilterAccessoryFunctions()).expression; - - return this.buildCollectionFilterPredicateBuilder(expression!, ExpressionOperator.All, proxy); - } - - private buildCollectionFilterPredicateBuilder

(value: Expression, operator: ExpressionOperator, proxy: EntityProxy

) { - let operand: any = value; - const propertyPaths = value == null ? null : (value as any)[propertyPath] as string[] | undefined; - if (propertyPaths != null) { - operand = this.getFieldReference(value as unknown as PropertyProxy) - } - const expression = new Expression(operator, [this.fieldReference, new String(proxy[lambdaVariable]), operand]); - return new BooleanPredicateBuilder

(expression); - } - - protected buildPredicateBuilder

(value: P | PropertyProxy

, operator: ExpressionOperator) { - let operand: any = value; - const propertyPaths = value == null ? null : (value as any)[propertyPath] as string[] | undefined; - if (propertyPaths != null) { - operand = this.getFieldReference(value as unknown as PropertyProxy) - } - const expression = new Expression(operator, [this.fieldReference, operand]); - return new BooleanPredicateBuilder

(expression); - } - - private getFieldReference(propertyProxy: PropertyProxy) { - const propertyPaths = propertyProxy[propertyPath]; - // TODO: Better handle typing here - return new FieldReference(propertyPaths.join('/') as unknown as FieldsFor); - } -} \ No newline at end of file + ArrayProxyFieldPredicateInterface +{ + private readonly fieldReference: FieldReference; + + constructor( + propertyProxy: PropertyProxy, + private readonly provider: ODataQueryProvider, + ) { + this.fieldReference = this.getFieldReference(propertyProxy); + } + + equals(value: PredicateArgument) { + return this.buildPredicateBuilder(value, ExpressionOperator.Equals); + } + + notEquals(value: PredicateArgument) { + return this.buildPredicateBuilder(value, ExpressionOperator.NotEquals); + } + + in(value: ArrayLike> | Iterable>) { + return this.buildPredicateBuilder(Array.from(value), ExpressionOperator.In); + } + + lessThan(value: PredicateArgument) { + return this.buildPredicateBuilder(value, ExpressionOperator.LessThan); + } + + lessThanOrEqualTo(value: PredicateArgument) { + return this.buildPredicateBuilder(value, ExpressionOperator.LessThanOrEqualTo); + } + + greaterThan(value: PredicateArgument) { + return this.buildPredicateBuilder(value, ExpressionOperator.GreaterThan); + } + + greaterThanOrEqualTo(value: PredicateArgument) { + return this.buildPredicateBuilder(value, ExpressionOperator.GreaterThanOrEqualTo); + } + + contains(value: PredicateArgument) { + return this.buildPredicateBuilder(value, ExpressionOperator.Contains); + } + + startsWith(value: PredicateArgument) { + return this.buildPredicateBuilder(value, ExpressionOperator.StartsWith); + } + + endsWith(value: PredicateArgument) { + return this.buildPredicateBuilder(value, ExpressionOperator.EndsWith); + } + + any(value: (entity: EntityProxy, compound: FilterAccessoryFunctions) => BooleanPredicateBuilder) { + const proxy = this.provider[createProxiedEntity](true); + const expression = value(proxy as unknown as EntityProxy, new FilterAccessoryFunctions()).expression; + + return this.buildCollectionFilterPredicateBuilder(expression!, ExpressionOperator.Any, proxy); + } + + all(value: (entity: EntityProxy, compound: FilterAccessoryFunctions) => BooleanPredicateBuilder) { + const proxy = this.provider[createProxiedEntity](true); + const expression = value(proxy as unknown as EntityProxy, new FilterAccessoryFunctions()).expression; + + return this.buildCollectionFilterPredicateBuilder(expression!, ExpressionOperator.All, proxy); + } + + private buildCollectionFilterPredicateBuilder

( + value: Expression, + operator: ExpressionOperator, + proxy: EntityProxy

, + ) { + let operand: typeof value | FieldReference = value; + const propertyPaths = + value == null ? null : typeof value === "object" && propertyPath in value ? value[propertyPath] : undefined; + if (propertyPaths != null) { + operand = this.getFieldReference(value as unknown as PropertyProxy); + } + const expression = new Expression(operator, [this.fieldReference, new String(proxy[lambdaVariable]), operand]); + return new BooleanPredicateBuilder

(expression); + } + + protected buildPredicateBuilder

(value: PredicateArgument

, operator: ExpressionOperator) { + let operand: typeof value | FieldReference = value; + const propertyPaths = + value == null ? null : typeof value === "object" && propertyPath in value ? value[propertyPath] : undefined; + if (propertyPaths != null) { + operand = this.getFieldReference(value as unknown as PropertyProxy); + } + const expression = new Expression(operator, [this.fieldReference, operand]); + return new BooleanPredicateBuilder

(expression); + } + + private getFieldReference(propertyProxy: PropertyProxy) { + const propertyPaths = propertyProxy[propertyPath]; + // TODO: Better handle typing here + return new FieldReference(propertyPaths.join("/") as unknown as FieldsFor); + } +} diff --git a/src/lib/ProxyTypes.ts b/src/lib/ProxyTypes.ts index 25e042a..7a0873b 100644 --- a/src/lib/ProxyTypes.ts +++ b/src/lib/ProxyTypes.ts @@ -5,23 +5,26 @@ export const lambdaVariable = Symbol(); export const proxyProperties = Symbol(); //If T is one of the below types, excludes that types fields/functions -type QueryableFieldsFor = - T extends number ? Exclude : - T extends string ? Exclude : - T extends Date ? Exclude : - T extends Array ? Exclude> : - T extends Object ? Exclude : - keyof T & string; //This line only shows string keys (i.e. indexes and Symbols are not allowed) +type QueryableFieldsFor = T extends number + ? Exclude + : T extends string + ? Exclude + : T extends Date + ? Exclude + : T extends Array + ? Exclude> + : T extends object + ? Exclude + : keyof T & string; //This line only shows string keys (i.e. indexes and Symbols are not allowed) export type EntityProxy = { - [P in QueryableFieldsFor]: PropertyProxy & (IncludeFilterMethods extends true ? ProxyFilterMethods : {}); + [P in QueryableFieldsFor]: PropertyProxy & + (IncludeFilterMethods extends true ? ProxyFilterMethods : object); } & { - [lambdaVariable]: string; - [proxyProperties]: PropertyProxy[]; + [lambdaVariable]: string; + [proxyProperties]: PropertyProxy[]; }; -export type PropertyProxy = EntityProxy -& {[propertyPath]: string[]}; - - - +export type PropertyProxy = EntityProxy & { + [propertyPath]: string[]; +}; diff --git a/src/lib/SubType.ts b/src/lib/SubType.ts index 29cc4de..31de0e0 100644 --- a/src/lib/SubType.ts +++ b/src/lib/SubType.ts @@ -1,7 +1,10 @@ /** - * From T Pick set of properties that extend TK + * From T Pick set of properties that extend TK * Example: SubType<{name: string, age: number}, number> will result in the type {age: number} * */ -export type SubType = Pick; \ No newline at end of file +export type SubType = Pick< + T, + { + [K in keyof T]: T[K] extends TK ? K : never; + }[keyof T] +>; diff --git a/src/lib/TypedExpressionVisitor.ts b/src/lib/TypedExpressionVisitor.ts index 1d5d9b3..e241b69 100644 --- a/src/lib/TypedExpressionVisitor.ts +++ b/src/lib/TypedExpressionVisitor.ts @@ -1,22 +1,24 @@ -import { ExpressionVisitor } from "./ExpressionVisitor"; -import { Expression } from "./Expression"; +import type { ExpressionVisitor } from "./ExpressionVisitor"; +import type { Expression } from "./Expression"; /** * Evaluates Expression by calling methods on type that follow the pattern of '[operator]Visitor'. * The operands are passed in as parameters. */ export abstract class TypedExpressionVisitor implements ExpressionVisitor { - visit(expression: Expression): void { - if (!expression) throw new Error(`'expression' is a required parameter.`); + visit(expression: Expression): void { + if (!expression) throw new Error(`'expression' is a required parameter.`); - if (expression.previous) - this.visit(expression.previous); + if (expression.previous) this.visit(expression.previous); - const member = (this as any)[expression.operator + "Visitor"]; + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- looking for existence of function in derivied type at runtime + const member = (this as any)[expression.operator + "Visitor"]; - if (typeof member !== "function") - throw new Error(`No method found named '${expression.operator}Visitor'; '${expression.operator}' operator is not supported.`); + if (typeof member !== "function") + throw new Error( + `No method found named '${expression.operator}Visitor'; '${expression.operator}' operator is not supported.`, + ); - member.apply(this, expression.operands); - } -} \ No newline at end of file + member.apply(this, expression.operands); + } +} diff --git a/src/v4.ts b/src/v4.ts index 643327e..25514f8 100644 --- a/src/v4.ts +++ b/src/v4.ts @@ -1,4 +1,4 @@ import { ODataV4Context } from "./lib/ODataV4Context"; import { ODataV4QueryProvider } from "./lib/ODataV4QueryProvider"; -export { ODataV4Context, ODataV4QueryProvider }; \ No newline at end of file +export { ODataV4Context, ODataV4QueryProvider }; diff --git a/test/ODataContext.test.ts b/test/ODataContext.test.ts index 029459c..809cf8a 100644 --- a/test/ODataContext.test.ts +++ b/test/ODataContext.test.ts @@ -3,27 +3,30 @@ import { ODataV4Context } from "../src/v4"; import { describe, it, expect } from "vitest"; class MyContext extends ODataV4Context { - constructor() { - super("http://api.purdue.io/odata/"); - } + constructor() { + super("http://api.purdue.io/odata/"); + } - get subjects() { return this.createQuery("Subjects"); } + get subjects() { + return this.createQuery("Subjects"); + } } describe("ODataConext", () => { - const context = new MyContext(); + const context = new MyContext(); - it("should create query", async () => { - const query = context.subjects.filter(p => p.Name.$contains("vet")); + it("should create query", async () => { + const query = context.subjects.filter((p) => p.Name.$contains("vet")); - expect(query[resolveQuery]().toString()).to.be.eql("http://api.purdue.io/odata/Subjects?$filter=contains(Name%2C'vet')"); - - }); + expect(query[resolveQuery]().toString()).to.be.eql( + "http://api.purdue.io/odata/Subjects?$filter=contains(Name%2C'vet')", + ); + }); }); interface Subject { - SubjectId: string, - SubjectClusterId: number, - Name: string; - Abbreviation: string; -} \ No newline at end of file + SubjectId: string; + SubjectClusterId: number; + Name: string; + Abbreviation: string; +} diff --git a/test/ODataQuery.get.test.ts b/test/ODataQuery.get.test.ts index b32707e..fc0bae4 100644 --- a/test/ODataQuery.get.test.ts +++ b/test/ODataQuery.get.test.ts @@ -3,54 +3,54 @@ import { MockFetch } from "./mock-fetch"; import { describe, beforeEach, afterEach, it, expect } from "vitest"; describe("ODataQuery", () => { - const endpoint = "/odata/users"; - const baseQuery = ODataQuery.forV4(endpoint); - let currentFetch!: MockFetch; - const oldFetch = (global as any).fetch; - - beforeEach(() => { - currentFetch = new MockFetch(); - (global as any).fetch = currentFetch.fetch.bind(currentFetch); - }); - - afterEach(() => { - (global as any).fech = oldFetch; - }); - - it("should produce base URL with no query", () => { - baseQuery.getManyAsync(); - const lastRequest = currentFetch.lastRequest!; - const url = typeof lastRequest === "string" ? lastRequest : lastRequest.url; - expect(url).to.equal(endpoint); - }); - - it("should produce base URL with key and no query", () => { - baseQuery.getAsync(123); - const lastRequest = currentFetch.lastRequest!; - const url = typeof lastRequest === "string" ? lastRequest : lastRequest.url; - expect(url).to.equal(endpoint + `(123)`); - }); - - it("should produce base URL with $value and no query", () => { - baseQuery.getValueAsync(); - const lastRequest = currentFetch.lastRequest!; - const url = typeof lastRequest === "string" ? lastRequest : lastRequest.url; - expect(url).to.equal(endpoint + '/$value'); - }); - - it("should transform results", async () => { - const query = baseQuery.select(u => ({ id: u.age, name: { first: u.firstName } })); - const result = await query.getManyAsync(); - - expect(result).to.be.eql({ value: [{ id: undefined, name: { first: undefined } }] }); - }); + const endpoint = "/odata/users"; + const baseQuery = ODataQuery.forV4(endpoint); + let currentFetch!: MockFetch; + const oldFetch = global.fetch; + + beforeEach(() => { + currentFetch = new MockFetch(); + global.fetch = currentFetch.fetch.bind(currentFetch); + }); + + afterEach(() => { + global.fech = oldFetch; + }); + + it("should produce base URL with no query", () => { + baseQuery.getManyAsync(); + const lastRequest = currentFetch.lastRequest!; + const url = typeof lastRequest === "string" ? lastRequest : lastRequest.url; + expect(url).to.equal(endpoint); + }); + + it("should produce base URL with key and no query", () => { + baseQuery.getAsync(123); + const lastRequest = currentFetch.lastRequest!; + const url = typeof lastRequest === "string" ? lastRequest : lastRequest.url; + expect(url).to.equal(endpoint + `(123)`); + }); + + it("should produce base URL with $value and no query", () => { + baseQuery.getValueAsync(); + const lastRequest = currentFetch.lastRequest!; + const url = typeof lastRequest === "string" ? lastRequest : lastRequest.url; + expect(url).to.equal(endpoint + "/$value"); + }); + + it("should transform results", async () => { + const query = baseQuery.select((u) => ({ id: u.age, name: { first: u.firstName } })); + const result = await query.getManyAsync(); + + expect(result).to.be.eql({ value: [{ id: undefined, name: { first: undefined } }] }); + }); }); interface Person { - firstName: string; - lastName: string; - age: number; - email: string; - children: string[]; - pets: string[]; -} \ No newline at end of file + firstName: string; + lastName: string; + age: number; + email: string; + children: string[]; + pets: string[]; +} diff --git a/test/ODataQuery.test.ts b/test/ODataQuery.test.ts index c277471..7e0a75d 100644 --- a/test/ODataQuery.test.ts +++ b/test/ODataQuery.test.ts @@ -2,180 +2,205 @@ import { ODataQuery } from "../src"; import { describe, it, expect } from "vitest"; describe("ODataQuery", () => { - const endpoint = "/odata/users"; - const baseQuery = ODataQuery.forV4(endpoint); + const endpoint = "/odata/users"; + const baseQuery = ODataQuery.forV4(endpoint); - it("should produce base URL with no query", () => { - expect(baseQuery.provider.buildQuery(baseQuery.expression)).to.be.eql(endpoint); - }); + it("should produce base URL with no query", () => { + expect(baseQuery.provider.buildQuery(baseQuery.expression)).to.be.eql(endpoint); + }); - it("should set select filter", () => { - const query = baseQuery.select("firstName"); + it("should set select filter", () => { + const query = baseQuery.select("firstName"); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$select=firstName`); - }); + expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$select=firstName`); + }); - it("should set select filter with mulitple fields", () => { - const query = baseQuery.select("firstName", "lastName"); + it("should set select filter with mulitple fields", () => { + const query = baseQuery.select("firstName", "lastName"); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$select=${encodeURIComponent("firstName,lastName")}`); - }); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$select=${encodeURIComponent("firstName,lastName")}`, + ); + }); - it("should set combination select filter", () => { - const query = baseQuery.select("firstName", "lastName") - .select("lastName"); + it("should set combination select filter", () => { + const query = baseQuery.select("firstName", "lastName").select("lastName"); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$select=lastName`); - }); + expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$select=lastName`); + }); - it("should set orderBy", () => { - const query = baseQuery.orderBy(p => p.firstName); + it("should set orderBy", () => { + const query = baseQuery.orderBy((p) => p.firstName); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$orderby=firstName`); - }); + expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$orderby=firstName`); + }); - it("should set orderBy with multiple fields", () => { - const query = baseQuery.orderBy(p => [p.firstName, p.lastName]); + it("should set orderBy with multiple fields", () => { + const query = baseQuery.orderBy((p) => [p.firstName, p.lastName]); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$orderby=${encodeURIComponent("firstName,lastName")}`); - }); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$orderby=${encodeURIComponent("firstName,lastName")}`, + ); + }); - it("should set orderBy multiple times", () => { - const query = baseQuery.orderBy(p => [p.firstName, p.lastName]).orderBy(p => p.age); + it("should set orderBy multiple times", () => { + const query = baseQuery.orderBy((p) => [p.firstName, p.lastName]).orderBy((p) => p.age); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$orderby=${encodeURIComponent("firstName,lastName,age")}`); - }); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$orderby=${encodeURIComponent("firstName,lastName,age")}`, + ); + }); - it("should set orderByDescending", () => { - const query = baseQuery.orderByDescending(p => p.firstName); + it("should set orderByDescending", () => { + const query = baseQuery.orderByDescending((p) => p.firstName); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$orderby=${encodeURIComponent("firstName desc")}`); - }); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$orderby=${encodeURIComponent("firstName desc")}`, + ); + }); - it("should set orderByDescending with multiple fields", () => { - const query = baseQuery.orderByDescending(p => [p.firstName, p.lastName]); + it("should set orderByDescending with multiple fields", () => { + const query = baseQuery.orderByDescending((p) => [p.firstName, p.lastName]); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$orderby=${encodeURIComponent("firstName desc,lastName desc")}`); - }); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$orderby=${encodeURIComponent("firstName desc,lastName desc")}`, + ); + }); - it("should set orderByDescending multiple times", () => { - const query = baseQuery.orderByDescending(p => [p.firstName, p.lastName]).orderByDescending(p => p.age); + it("should set orderByDescending multiple times", () => { + const query = baseQuery.orderByDescending((p) => [p.firstName, p.lastName]).orderByDescending((p) => p.age); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$orderby=${encodeURIComponent("firstName desc,lastName desc,age desc")}`); - }); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$orderby=${encodeURIComponent("firstName desc,lastName desc,age desc")}`, + ); + }); - it("should set orderBy and orderByDescending multiple times", () => { - const query = baseQuery.orderByDescending(p => p.firstName).orderBy(p => p.age).orderByDescending(p => p.lastName); + it("should set orderBy and orderByDescending multiple times", () => { + const query = baseQuery + .orderByDescending((p) => p.firstName) + .orderBy((p) => p.age) + .orderByDescending((p) => p.lastName); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$orderby=${encodeURIComponent("firstName desc,age,lastName desc")}`); - }); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$orderby=${encodeURIComponent("firstName desc,age,lastName desc")}`, + ); + }); - it("should set skip", () => { - const query = baseQuery.skip(10); + it("should set skip", () => { + const query = baseQuery.skip(10); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$skip=10`); - }); + expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$skip=10`); + }); - it("should ignore skip if set to 0", () => { - const query = baseQuery.skip(0); + it("should ignore skip if set to 0", () => { + const query = baseQuery.skip(0); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}`); - }); + expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}`); + }); - it("should set last skip value provided", () => { - const query = baseQuery.skip(10).skip(5); + it("should set last skip value provided", () => { + const query = baseQuery.skip(10).skip(5); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$skip=5`); - }); + expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$skip=5`); + }); - it("should set top", () => { - const query = baseQuery.top(10); + it("should set top", () => { + const query = baseQuery.top(10); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$top=10`); - }); + expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$top=10`); + }); - it("should set top to 0", () => { - const query = baseQuery.top(0); - - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$top=0`); - }); - - it("should set last skip value provided", () => { - const query = baseQuery.top(10).top(5); - - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$top=5`); - }); - - it("should handle cumulative expand", () => { - const query = baseQuery.expand("children"); - - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$expand=children`); - }); - - it("should handle cumulative expands", () => { - const query = baseQuery.expand("children").expand("mother"); - - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$expand=${encodeURIComponent("children,mother")}`); - }); - - it("should handle mulitple expands in one call", () => { - const query = baseQuery.expand("children", "mother"); - - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$expand=${encodeURIComponent("children,mother")}`); - }); - - it("should not repeat expands", () => { - const query = baseQuery.expand("children", "mother").expand("mother"); - - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$expand=${encodeURIComponent("children,mother")}`); - }); - - it("should allow expand on non-array types", () => { - const query = baseQuery.expand("mother"); - - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$expand=${encodeURIComponent("mother")}`); - }); - - it("should find all properties", () => { - const query = baseQuery.select(p => ({ - foo: { bar: p.email }, - baz: p.firstName, - zap: p.mother.lastName, - dupe: p.email, - constNumber: 5, - constBoolean: false, - constString: "test", - })); - - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$select=${encodeURIComponent("email,firstName,mother/lastName")}`); - - }); - - it("should find all properties", () => { - const outsideVariable = "test" - const query = baseQuery.select(p => ({ - foo: { bar: p.email }, - names: [p.firstName, p.lastName], - zap: p.mother.lastName, - dupe: p.email, - constNumber: 5, - constBoolean: false, - constString: outsideVariable, - })); - - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$select=${encodeURIComponent("email,firstName,lastName,mother/lastName")}`); - - }); + it("should set top to 0", () => { + const query = baseQuery.top(0); + + expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$top=0`); + }); + + it("should set last skip value provided", () => { + const query = baseQuery.top(10).top(5); + + expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$top=5`); + }); + it("should handle cumulative expand", () => { + const query = baseQuery.expand("children"); + + expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$expand=children`); + }); + + it("should handle cumulative expands", () => { + const query = baseQuery.expand("children").expand("mother"); + + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$expand=${encodeURIComponent("children,mother")}`, + ); + }); + + it("should handle mulitple expands in one call", () => { + const query = baseQuery.expand("children", "mother"); + + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$expand=${encodeURIComponent("children,mother")}`, + ); + }); + + it("should not repeat expands", () => { + const query = baseQuery.expand("children", "mother").expand("mother"); + + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$expand=${encodeURIComponent("children,mother")}`, + ); + }); + + it("should allow expand on non-array types", () => { + const query = baseQuery.expand("mother"); + + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$expand=${encodeURIComponent("mother")}`, + ); + }); + + it("should find all properties", () => { + const query = baseQuery.select((p) => ({ + foo: { bar: p.email }, + baz: p.firstName, + zap: p.mother.lastName, + dupe: p.email, + constNumber: 5, + constBoolean: false, + constString: "test", + })); + + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$select=${encodeURIComponent("email,firstName,mother/lastName")}`, + ); + }); + + it("should find all properties", () => { + const outsideVariable = "test"; + const query = baseQuery.select((p) => ({ + foo: { bar: p.email }, + names: [p.firstName, p.lastName], + zap: p.mother.lastName, + dupe: p.email, + constNumber: 5, + constBoolean: false, + constString: outsideVariable, + })); + + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$select=${encodeURIComponent("email,firstName,lastName,mother/lastName")}`, + ); + }); }); interface Person { - firstName: string; - lastName: string; - age: number; - email: string; - children: Person[]; - pets: string[]; - mother: Person; - dateOfBirth: Date; -} \ No newline at end of file + firstName: string; + lastName: string; + age: number; + email: string; + children: Person[]; + pets: string[]; + mother: Person; + dateOfBirth: Date; +} diff --git a/test/ODataV4ExpressionVisitor.test.ts b/test/ODataV4ExpressionVisitor.test.ts index d15d79f..44b1639 100644 --- a/test/ODataV4ExpressionVisitor.test.ts +++ b/test/ODataV4ExpressionVisitor.test.ts @@ -6,180 +6,209 @@ import { ODataType } from "../src/lib/ODataType"; import { describe, it, expect } from "vitest"; describe("ODataV4ExpressionVisitor", () => { - it("should handle single select", () => { - const visitor = new ODataV4ExpressionVisitor(); - const expression = new Expression(ExpressionOperator.Select, [new FieldReference("firstName"), new FieldReference("age")]); - visitor.visit(expression); + it("should handle single select", () => { + const visitor = new ODataV4ExpressionVisitor(); + const expression = new Expression(ExpressionOperator.Select, [ + new FieldReference("firstName"), + new FieldReference("age"), + ]); + visitor.visit(expression); + + expect(visitor.oDataQuery).to.eql({ select: ["firstName", "age"] }); + }); + + it("should handle compound select", () => { + const visitor = new ODataV4ExpressionVisitor(); + const expression = new Expression(ExpressionOperator.Select, [ + new FieldReference("firstName"), + new FieldReference("age"), + ]); + visitor.visit(new Expression(ExpressionOperator.Select, [new FieldReference("lastName")], expression)); + + expect(visitor.oDataQuery).to.eql({ select: ["lastName"] }); + }); + + it("should handle orderBy", () => { + const visitor = new ODataV4ExpressionVisitor(); + visitor.visit(new Expression(ExpressionOperator.OrderBy, [new FieldReference("firstName")])); + + expect(visitor.oDataQuery).to.eql({ orderBy: [{ field: "firstName" }] }); + }); + + it("should handle compound orderBy", () => { + const visitor = new ODataV4ExpressionVisitor(); + const expression = new Expression(ExpressionOperator.OrderBy, [new FieldReference("firstName")]); + visitor.visit(new Expression(ExpressionOperator.OrderBy, [new FieldReference("age")], expression)); + + expect(visitor.oDataQuery).to.eql({ orderBy: [{ field: "firstName" }, { field: "age" }] }); + }); + + it("should handle orderByDescending", () => { + const visitor = new ODataV4ExpressionVisitor(); + visitor.visit(new Expression(ExpressionOperator.OrderByDescending, [new FieldReference("age")])); + + expect(visitor.oDataQuery).to.eql({ orderBy: [{ field: "age", sort: "desc" }] }); + }); + + it("should handle compound orderByDescending", () => { + const visitor = new ODataV4ExpressionVisitor(); + const expression = new Expression(ExpressionOperator.OrderByDescending, [new FieldReference("firstName")]); + visitor.visit( + new Expression(ExpressionOperator.OrderByDescending, [new FieldReference("age")], expression), + ); + + expect(visitor.oDataQuery).to.eql({ + orderBy: [ + { field: "firstName", sort: "desc" }, + { field: "age", sort: "desc" }, + ], + }); + }); - expect(visitor.oDataQuery).to.eql({ select: ["firstName", "age"] }); - }); - - it("should handle compound select", () => { - const visitor = new ODataV4ExpressionVisitor(); - const expression = new Expression(ExpressionOperator.Select, [new FieldReference("firstName"), new FieldReference("age")]); - visitor.visit(new Expression(ExpressionOperator.Select, [new FieldReference("lastName")], expression)); - - expect(visitor.oDataQuery).to.eql({ select: ["lastName"] }); - }); - - it("should handle orderBy", () => { - const visitor = new ODataV4ExpressionVisitor(); - visitor.visit(new Expression(ExpressionOperator.OrderBy, [new FieldReference("firstName")])); - - expect(visitor.oDataQuery).to.eql({ orderBy: [{ field: "firstName" }] }); - }); - - it("should handle compound orderBy", () => { - const visitor = new ODataV4ExpressionVisitor(); - const expression = new Expression(ExpressionOperator.OrderBy, [new FieldReference("firstName")]); - visitor.visit(new Expression(ExpressionOperator.OrderBy, [new FieldReference("age")], expression)); - - expect(visitor.oDataQuery).to.eql({ orderBy: [{ field: "firstName" }, { field: "age" }] }); - }); - - it("should handle orderByDescending", () => { - const visitor = new ODataV4ExpressionVisitor(); - visitor.visit(new Expression(ExpressionOperator.OrderByDescending, [new FieldReference("age")])); - - expect(visitor.oDataQuery).to.eql({ orderBy: [{ field: "age", sort: 'desc' }] }); - }); - - it("should handle compound orderByDescending", () => { - const visitor = new ODataV4ExpressionVisitor(); - const expression = new Expression(ExpressionOperator.OrderByDescending, [new FieldReference("firstName")]); - visitor.visit(new Expression(ExpressionOperator.OrderByDescending, [new FieldReference("age")], expression)); - - expect(visitor.oDataQuery).to.eql({ orderBy: [{ field: "firstName", sort: 'desc' }, { field: "age", sort: 'desc' }] }); - }); + it("should handle single skip", () => { + const visitor = new ODataV4ExpressionVisitor(); + const expression = new Expression(ExpressionOperator.Skip, [3]); + visitor.visit(expression); + + expect(visitor.oDataQuery).to.eql({ skip: 3 }); + }); - it("should handle single skip", () => { - const visitor = new ODataV4ExpressionVisitor(); - const expression = new Expression(ExpressionOperator.Skip, [3]); - visitor.visit(expression); - - expect(visitor.oDataQuery).to.eql({ skip: 3 }); - }); - - it("should handle compound skip", () => { - const visitor = new ODataV4ExpressionVisitor(); - const expression = new Expression(ExpressionOperator.Skip, [2]); - visitor.visit(new Expression(ExpressionOperator.Skip, [5], expression)); - - expect(visitor.oDataQuery).to.eql({ skip: 5 }); - }); - - it("should handle single top", () => { - const visitor = new ODataV4ExpressionVisitor(); - const expression = new Expression(ExpressionOperator.Top, [3]); - visitor.visit(expression); - - expect(visitor.oDataQuery).to.eql({ top: 3 }); - }); - - it("should handle compound top", () => { - const visitor = new ODataV4ExpressionVisitor(); - const expression = new Expression(ExpressionOperator.Top, [2]); - visitor.visit(new Expression(ExpressionOperator.Top, [5], expression)); - - expect(visitor.oDataQuery).to.eql({ top: 5 }); - }); - - it("should handle 0 top", () => { - const visitor = new ODataV4ExpressionVisitor(); - const expression = new Expression(ExpressionOperator.Top, [0]); - visitor.visit(expression); - - expect(visitor.oDataQuery).to.eql({ top: 0 }); - }) - - it("should handle count", () => { - const visitor = new ODataV4ExpressionVisitor(); - visitor.visit(new Expression(ExpressionOperator.GetWithCount, [])); - - expect(visitor.oDataQuery).to.eql({ count: true }); - }); + it("should handle compound skip", () => { + const visitor = new ODataV4ExpressionVisitor(); + const expression = new Expression(ExpressionOperator.Skip, [2]); + visitor.visit(new Expression(ExpressionOperator.Skip, [5], expression)); + + expect(visitor.oDataQuery).to.eql({ skip: 5 }); + }); + + it("should handle single top", () => { + const visitor = new ODataV4ExpressionVisitor(); + const expression = new Expression(ExpressionOperator.Top, [3]); + visitor.visit(expression); + + expect(visitor.oDataQuery).to.eql({ top: 3 }); + }); + + it("should handle compound top", () => { + const visitor = new ODataV4ExpressionVisitor(); + const expression = new Expression(ExpressionOperator.Top, [2]); + visitor.visit(new Expression(ExpressionOperator.Top, [5], expression)); + + expect(visitor.oDataQuery).to.eql({ top: 5 }); + }); + + it("should handle 0 top", () => { + const visitor = new ODataV4ExpressionVisitor(); + const expression = new Expression(ExpressionOperator.Top, [0]); + visitor.visit(expression); + + expect(visitor.oDataQuery).to.eql({ top: 0 }); + }); + + it("should handle count", () => { + const visitor = new ODataV4ExpressionVisitor(); + visitor.visit(new Expression(ExpressionOperator.GetWithCount, [])); + + expect(visitor.oDataQuery).to.eql({ count: true }); + }); + + it("should handle getByKey with number", () => { + const visitor = new ODataV4ExpressionVisitor(); + visitor.visit(new Expression(ExpressionOperator.GetByKey, [5])); + + expect(visitor.oDataQuery).to.eql({ key: "5" }); + }); + + it("should handle getByKey with string", () => { + const visitor = new ODataV4ExpressionVisitor(); + visitor.visit(new Expression(ExpressionOperator.GetByKey, ["1a"])); + + expect(visitor.oDataQuery).to.eql({ key: "'1a'" }); + }); + + it("should handle getByKey with date", () => { + const visitor = new ODataV4ExpressionVisitor(); + visitor.visit(new Expression(ExpressionOperator.GetByKey, [Expression.literal(new Date(0), ODataType.Date)])); + + expect(visitor.oDataQuery).to.eql({ key: "1970-01-01" }); + }); + + it("should handle getByKey with guid", () => { + const visitor = new ODataV4ExpressionVisitor(); + visitor.visit( + new Expression(ExpressionOperator.GetByKey, [ + Expression.literal("00000000-0000-0000-000000000000", ODataType.Guid), + ]), + ); + + expect(visitor.oDataQuery).to.eql({ key: "00000000-0000-0000-000000000000" }); + }); + + it("should handle expand", () => { + const visitor = new ODataV4ExpressionVisitor(); + visitor.visit(new Expression(ExpressionOperator.Expand, [new FieldReference("children")])); + + expect(visitor.oDataQuery).to.eql({ expand: ["children"] }); + }); + + it("should error on unknown expression", () => { + const visitor = new ODataV4ExpressionVisitor(); + const expression = new Expression("fake operator" as ExpressionOperator, []); + + expect(() => visitor.visit(expression)).to.throw(); + }); + + it("should handle expandAll", () => { + const visitor = new ODataV4ExpressionVisitor(); + visitor.visit(new Expression(ExpressionOperator.ExpandAll, [])); - it("should handle getByKey with number", () => { - const visitor = new ODataV4ExpressionVisitor(); - visitor.visit(new Expression(ExpressionOperator.GetByKey, [5])); + expect(visitor.oDataQuery).to.eql({ expand: ["*"] }); + }); + + it("should handle multiple expandAll", () => { + const visitor = new ODataV4ExpressionVisitor(); + visitor.visit(new Expression(ExpressionOperator.ExpandAll, [], new Expression(ExpressionOperator.ExpandAll, []))); + + expect(visitor.oDataQuery).to.eql({ expand: ["*"] }); + }); + + it("should handle expandAll then expand", () => { + const visitor = new ODataV4ExpressionVisitor(); + visitor.visit( + new Expression( + ExpressionOperator.Expand, + [new FieldReference("children")], + new Expression(ExpressionOperator.ExpandAll, []), + ), + ); + + expect(visitor.oDataQuery).to.eql({ expand: ["children"] }); + }); + + it("should handle expand then expandAll", () => { + const visitor = new ODataV4ExpressionVisitor(); + visitor.visit( + new Expression( + ExpressionOperator.ExpandAll, + [], + new Expression(ExpressionOperator.Expand, [new FieldReference("children")]), + ), + ); + + expect(visitor.oDataQuery).to.eql({ expand: ["*"] }); + }); + + it("should handle value", () => { + const visitor = new ODataV4ExpressionVisitor(); + visitor.visit(new Expression(ExpressionOperator.Value, [])); - expect(visitor.oDataQuery).to.eql({ key: "5" }); - }); - - it("should handle getByKey with string", () => { - const visitor = new ODataV4ExpressionVisitor(); - visitor.visit(new Expression(ExpressionOperator.GetByKey, ["1a"])); - - expect(visitor.oDataQuery).to.eql({ key: "'1a'" }); - }); - - it("should handle getByKey with date", () => { - const visitor = new ODataV4ExpressionVisitor(); - visitor.visit(new Expression(ExpressionOperator.GetByKey, [Expression.literal(new Date(0), ODataType.Date)])); - - expect(visitor.oDataQuery).to.eql({ key: "1970-01-01" }); - }); - - it("should handle getByKey with guid", () => { - const visitor = new ODataV4ExpressionVisitor(); - visitor.visit(new Expression(ExpressionOperator.GetByKey, [Expression.literal("00000000-0000-0000-000000000000", ODataType.Guid)])); - - expect(visitor.oDataQuery).to.eql({ key: "00000000-0000-0000-000000000000" }); - }); - - it("should handle expand", () => { - const visitor = new ODataV4ExpressionVisitor(); - visitor.visit(new Expression(ExpressionOperator.Expand, [new FieldReference("children")])); - - expect(visitor.oDataQuery).to.eql({ expand: ["children"] }); - }); - - it("should error on unknown expression", () => { - const visitor = new ODataV4ExpressionVisitor(); - const expression = new Expression('fake operator' as ExpressionOperator, []); - - expect(() => visitor.visit(expression)).to.throw(); - }); - - it("should handle expandAll", () => { - const visitor = new ODataV4ExpressionVisitor(); - visitor.visit(new Expression(ExpressionOperator.ExpandAll, [])); - - expect(visitor.oDataQuery).to.eql({ expand: ["*"] }); - }); - - it("should handle multiple expandAll", () => { - const visitor = new ODataV4ExpressionVisitor(); - visitor.visit(new Expression(ExpressionOperator.ExpandAll, [], new Expression(ExpressionOperator.ExpandAll, []))); - - expect(visitor.oDataQuery).to.eql({ expand: ["*"] }); - }); - - it("should handle expandAll then expand", () => { - const visitor = new ODataV4ExpressionVisitor(); - visitor.visit(new Expression(ExpressionOperator.Expand, [new FieldReference("children")], new Expression(ExpressionOperator.ExpandAll, []))); - - expect(visitor.oDataQuery).to.eql({ expand: ["children"] }); - }); - - it("should handle expand then expandAll", () => { - const visitor = new ODataV4ExpressionVisitor(); - visitor.visit(new Expression(ExpressionOperator.ExpandAll, [], new Expression(ExpressionOperator.Expand, [new FieldReference("children")]))); - - expect(visitor.oDataQuery).to.eql({ expand: ["*"] }); - }); - - it("should handle value", () => { - const visitor = new ODataV4ExpressionVisitor(); - visitor.visit(new Expression(ExpressionOperator.Value, [])); - - expect(visitor.oDataQuery).to.eql({ value: true }); - }); + expect(visitor.oDataQuery).to.eql({ value: true }); + }); }); interface Person { - firstName: string; - lastName: string; - age: number; - children: string[]; -} \ No newline at end of file + firstName: string; + lastName: string; + age: number; + children: string[]; +} diff --git a/test/ProxyPredicate.test.ts b/test/ProxyPredicate.test.ts index 5947da3..b51f1a2 100644 --- a/test/ProxyPredicate.test.ts +++ b/test/ProxyPredicate.test.ts @@ -3,133 +3,191 @@ import { lambdaVariable } from "../src/lib/ProxyTypes"; import { describe, it, expect } from "vitest"; describe("useProxy", () => { - - const endpoint = "/odata/users"; - const baseQuery = ODataQuery.forV4(endpoint); - - it("should set simple filter", () => { - const query = baseQuery.filter(p => p.firstName.$equals("john")); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent("firstName eq 'john'")}`); - }); - - it("should set compound filter", () => { - const query = baseQuery.filter(p => p.firstName.$equals("john").and(p.age.$greaterThanOrEqualTo(30))); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent("firstName eq 'john' and age ge 30")}`); - }); - - it("should set complex filter", () => { - const query = baseQuery.filter(p => p.firstName.$equals("john").and(p.age.$greaterThanOrEqualTo(30).or(p.lastName.$notEquals("Jones")))); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent("firstName eq 'john' and (age ge 30 or lastName ne 'Jones')")}`); - }); - - it("should set complex filter", () => { - const query = baseQuery.filter(p => p.firstName.$equals("john").and(p.age.$greaterThanOrEqualTo(30)) - .or(p.lastName.$notEquals("Jones").and(p.email.$equals(".com")))); - - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent("(firstName eq 'john' and age ge 30) or (lastName ne 'Jones' and email eq '.com')")}`); - }); - - it("should handle contains", () => { - const query = baseQuery.filter(p => p.firstName.$contains("jac")); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent("contains(firstName,'jac')")}`); - }); - - it("should handle startsWith", () => { - const query = baseQuery.filter(p => p.firstName.$startsWith("jac")); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent("startsWith(firstName,'jac')")}`); - }); - - it("should handle endsWith", () => { - const query = baseQuery.filter(p => p.firstName.$endsWith("jac")); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent("endsWith(firstName,'jac')")}`); - }); - - it("should handle equals and notEquals", () => { - const query = baseQuery.filter((p, { and }) => and(p.firstName.$equals("jac"), p.age.$notEquals(50))); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent("firstName eq 'jac' and age ne 50")}`); - }); - - it("should handle greaterThan and greaterThanEqualTo", () => { - const query = baseQuery.filter((p, { and }) => and(p.firstName.$greaterThan("jac"), p.age.$greaterThanOrEqualTo(50))); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent("firstName gt 'jac' and age ge 50")}`); - }); - - it("should handle lessThan and lessThanEqualTo", () => { - const query = baseQuery.filter((p, { and }) => and(p.firstName.$lessThan("jac"), p.age.$lessThanOrEqualTo(50))); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent("firstName lt 'jac' and age le 50")}`); - }); - - it("should handle null comparisons", () => { - const query = baseQuery.filter(p => p.firstName.$equals(null)); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent("firstName eq null")}`); - }); - - it("should handle undefined comparisons", () => { - const query = baseQuery.filter(p => p.firstName.$equals(undefined)); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent("firstName eq null")}`); - }); - - it("should handle not", () => { - const query = baseQuery.filter((p, { not }) => not(p.firstName.$equals("John"))); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent("not firstName eq 'John'")}`); - }); - - it("should handle navigation properties", () => { - const query = baseQuery.filter((p, { not }) => not(p.mother.firstName.$equals("Jane"))); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent("not mother/firstName eq 'Jane'")}`); - }); - - it("should handle any", () => { - const query = baseQuery.filter(p => p.lastName.$in(["Jones", "Smith", "Ng"])); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent("lastName in ('Jones','Smith','Ng')")}`); - }); - - it("should work with non-filter operators", () => { - const query = baseQuery.orderBy(p => [p.age]).filter(p => p.lastName.$in(["Jones", "Smith", "Ng"])).select('firstName', 'lastName'); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent("lastName in ('Jones','Smith','Ng')")}&$orderby=age&$select=${encodeURIComponent('firstName,lastName')}`); - }); - - it("should handle 'any' entity collection query", () => { - let variable = ''; - const query = baseQuery.filter(p => p.children.$any(c => { - variable = c[lambdaVariable]; - return c.age.$equals(4); - })); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent(`children/any(${variable}: ${variable}/age eq 4)`)}`); - }); - - it("should handle 'all' entity collection query", () => { - let variable = ''; - const query = baseQuery.filter(p => p.children.$all(c => { - variable = c[lambdaVariable]; - return c.age.$equals(4); - })); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent(`children/all(${variable}: ${variable}/age eq 4)`)}`); - }); - - it("should handle 'all' entity collection query with contains", () => { - let variable = ''; - const query = baseQuery.filter(p => p.children.$all(c => { - variable = c[lambdaVariable]; - return c.firstName.$contains('efg'); - })); - expect(query.provider.buildQuery(query.expression)).to.be.eql(`${endpoint}?$filter=${encodeURIComponent(`children/all(${variable}: contains(${variable}/firstName,'efg'))`)}`); - }); + const endpoint = "/odata/users"; + const baseQuery = ODataQuery.forV4(endpoint); + + it("should set simple filter", () => { + const query = baseQuery.filter((p) => p.firstName.$equals("john")); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent("firstName eq 'john'")}`, + ); + }); + + it("should set compound filter", () => { + const query = baseQuery.filter((p) => p.firstName.$equals("john").and(p.age.$greaterThanOrEqualTo(30))); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent("firstName eq 'john' and age ge 30")}`, + ); + }); + + it("should set complex filter", () => { + const query = baseQuery.filter((p) => + p.firstName.$equals("john").and(p.age.$greaterThanOrEqualTo(30).or(p.lastName.$notEquals("Jones"))), + ); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent("firstName eq 'john' and (age ge 30 or lastName ne 'Jones')")}`, + ); + }); + + it("should set complex filter", () => { + const query = baseQuery.filter((p) => + p.firstName + .$equals("john") + .and(p.age.$greaterThanOrEqualTo(30)) + .or(p.lastName.$notEquals("Jones").and(p.email.$equals(".com"))), + ); + + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent( + "(firstName eq 'john' and age ge 30) or (lastName ne 'Jones' and email eq '.com')", + )}`, + ); + }); + + it("should handle contains", () => { + const query = baseQuery.filter((p) => p.firstName.$contains("jac")); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent("contains(firstName,'jac')")}`, + ); + }); + + it("should handle startsWith", () => { + const query = baseQuery.filter((p) => p.firstName.$startsWith("jac")); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent("startsWith(firstName,'jac')")}`, + ); + }); + + it("should handle endsWith", () => { + const query = baseQuery.filter((p) => p.firstName.$endsWith("jac")); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent("endsWith(firstName,'jac')")}`, + ); + }); + + it("should handle equals and notEquals", () => { + const query = baseQuery.filter((p, { and }) => and(p.firstName.$equals("jac"), p.age.$notEquals(50))); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent("firstName eq 'jac' and age ne 50")}`, + ); + }); + + it("should handle greaterThan and greaterThanEqualTo", () => { + const query = baseQuery.filter((p, { and }) => + and(p.firstName.$greaterThan("jac"), p.age.$greaterThanOrEqualTo(50)), + ); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent("firstName gt 'jac' and age ge 50")}`, + ); + }); + + it("should handle lessThan and lessThanEqualTo", () => { + const query = baseQuery.filter((p, { and }) => and(p.firstName.$lessThan("jac"), p.age.$lessThanOrEqualTo(50))); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent("firstName lt 'jac' and age le 50")}`, + ); + }); + + it("should handle null comparisons", () => { + const query = baseQuery.filter((p) => p.firstName.$equals(null)); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent("firstName eq null")}`, + ); + }); + + it("should handle undefined comparisons", () => { + const query = baseQuery.filter((p) => p.firstName.$equals(undefined)); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent("firstName eq null")}`, + ); + }); + + it("should handle not", () => { + const query = baseQuery.filter((p, { not }) => not(p.firstName.$equals("John"))); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent("not firstName eq 'John'")}`, + ); + }); + + it("should handle navigation properties", () => { + const query = baseQuery.filter((p, { not }) => not(p.mother.firstName.$equals("Jane"))); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent("not mother/firstName eq 'Jane'")}`, + ); + }); + + it("should handle any", () => { + const query = baseQuery.filter((p) => p.lastName.$in(["Jones", "Smith", "Ng"])); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent("lastName in ('Jones','Smith','Ng')")}`, + ); + }); + + it("should work with non-filter operators", () => { + const query = baseQuery + .orderBy((p) => [p.age]) + .filter((p) => p.lastName.$in(["Jones", "Smith", "Ng"])) + .select("firstName", "lastName"); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent( + "lastName in ('Jones','Smith','Ng')", + )}&$orderby=age&$select=${encodeURIComponent("firstName,lastName")}`, + ); + }); + + it("should handle 'any' entity collection query", () => { + let variable = ""; + const query = baseQuery.filter((p) => + p.children.$any((c) => { + variable = c[lambdaVariable]; + return c.age.$equals(4); + }), + ); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent(`children/any(${variable}: ${variable}/age eq 4)`)}`, + ); + }); + + it("should handle 'all' entity collection query", () => { + let variable = ""; + const query = baseQuery.filter((p) => + p.children.$all((c) => { + variable = c[lambdaVariable]; + return c.age.$equals(4); + }), + ); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent(`children/all(${variable}: ${variable}/age eq 4)`)}`, + ); + }); + + it("should handle 'all' entity collection query with contains", () => { + let variable = ""; + const query = baseQuery.filter((p) => + p.children.$all((c) => { + variable = c[lambdaVariable]; + return c.firstName.$contains("efg"); + }), + ); + expect(query.provider.buildQuery(query.expression)).to.be.eql( + `${endpoint}?$filter=${encodeURIComponent(`children/all(${variable}: contains(${variable}/firstName,'efg'))`)}`, + ); + }); }); interface Person { - firstName: string; - lastName: string; - age: number; - email: string; - children: Child[]; - pets: string[]; - mother: Person; - father: Person; + firstName: string; + lastName: string; + age: number; + email: string; + children: Child[]; + pets: string[]; + mother: Person; + father: Person; } interface Child { - firstName: string; - lastName: string; - age: number; -} \ No newline at end of file + firstName: string; + lastName: string; + age: number; +} diff --git a/test/mock-fetch.ts b/test/mock-fetch.ts index 9b61367..c31e395 100644 --- a/test/mock-fetch.ts +++ b/test/mock-fetch.ts @@ -1,14 +1,12 @@ -import { Response } from 'node-fetch'; - /** * Extremely simple mock of the fetch method */ export class MockFetch { - lastRequest: RequestInfo | undefined; - lastInit: RequestInit | undefined; - fetch(request: RequestInfo, options: RequestInit) { - this.lastRequest = request; - this.lastInit = options; - return Promise.resolve(new Response(`{"value":[{}]}`, {status: 200})); - } -} \ No newline at end of file + lastRequest: RequestInfo | undefined; + lastInit: RequestInit | undefined; + fetch(request: RequestInfo, options: RequestInit) { + this.lastRequest = request; + this.lastInit = options; + return Promise.resolve(new Response(`{"value":[{}]}`, { status: 200 })); + } +} diff --git a/test/network.test.ts b/test/network.test.ts index b9425ed..4cb228c 100644 --- a/test/network.test.ts +++ b/test/network.test.ts @@ -1,29 +1,25 @@ import { ODataV4QueryProvider } from "../src/v4"; -import fetch from "node-fetch"; import { describe, it, expect } from "vitest"; -(global as any).fetch = fetch; - interface Subject { - SubjectId: string, - SubjectClusterId: number, - Name: string; - Abbreviation: string; + SubjectId: string; + SubjectClusterId: number; + Name: string; + Abbreviation: string; } //do not run this test by default describe.skip("executing getManyAsync", () => { + const endpoint = "http://api.purdue.io/odata/Subjects"; + const baseQuery = ODataV4QueryProvider.createQuery(endpoint); - const endpoint = "http://api.purdue.io/odata/Subjects"; - const baseQuery = ODataV4QueryProvider.createQuery(endpoint); - - it("should not error", async () => { - const query = baseQuery.filter(p => p.Name.$contains("vet")); + it("should not error", async () => { + const query = baseQuery.filter((p) => p.Name.$contains("vet")); - let results = await query.getManyAsync(); + const results = await query.getManyAsync(); - expect(results).to.not.be.undefined; - expect(results.value).to.not.be.undefined; - results.value.forEach(v => expect(v.Name).to.match(/vet/i)); - }); -}); \ No newline at end of file + expect(results).to.not.be.undefined; + expect(results.value).to.not.be.undefined; + results.value.forEach((v) => expect(v.Name).to.match(/vet/i)); + }); +}); diff --git a/test/requestInit.test.ts b/test/requestInit.test.ts index 91e035d..5d358e7 100644 --- a/test/requestInit.test.ts +++ b/test/requestInit.test.ts @@ -1,47 +1,50 @@ import { ODataV4QueryProvider } from "../src/v4"; -import { MockFetch } from './mock-fetch'; +import { MockFetch } from "./mock-fetch"; import { describe, beforeEach, afterEach, it, expect } from "vitest"; interface Subject { - SubjectId: string, - SubjectClusterId: number, - Name: string; - Abbreviation: string; + SubjectId: string; + SubjectClusterId: number; + Name: string; + Abbreviation: string; } let currentFetch!: MockFetch; describe("requestInit", () => { - - const endpoint = "http://api.purdue.io/odata/Subjects"; - const oldFetch = (global as any).fetch; - - beforeEach(() => { - currentFetch = new MockFetch(); - (global as any).fetch = currentFetch.fetch.bind(currentFetch); - }); - - afterEach(() => { - (global as any).fech = oldFetch; - }); - - it("should not error if not provided", async () => { - const query = ODataV4QueryProvider.createQuery(endpoint).filter(p => p.Name.$contains("vet")); - await query.getManyAsync(); - expect(currentFetch.lastInit).to.be.empty; - }); - - it("should use provided object in fetch", async () => { - const requestInit: RequestInit = { method: 'POST' }; - const query = ODataV4QueryProvider.createQuery(endpoint, { requestInit: () => requestInit }).filter(p => p.Name.$contains("vet")); - await query.getManyAsync(); - expect(currentFetch.lastInit).to.equal(requestInit); - }); - - it("should use provided object via Promise in fetch", async () => { - const requestInit: RequestInit = { method: 'POST' }; - const query = ODataV4QueryProvider.createQuery(endpoint, { requestInit: () => Promise.resolve(requestInit) }).filter(p => p.Name.$contains("vet")); - await query.getManyAsync(); - expect(currentFetch.lastInit).to.equal(requestInit); - }); -}); \ No newline at end of file + const endpoint = "http://api.purdue.io/odata/Subjects"; + const oldFetch = global.fetch; + + beforeEach(() => { + currentFetch = new MockFetch(); + global.fetch = currentFetch.fetch.bind(currentFetch); + }); + + afterEach(() => { + global.fech = oldFetch; + }); + + it("should not error if not provided", async () => { + const query = ODataV4QueryProvider.createQuery(endpoint).filter((p) => p.Name.$contains("vet")); + await query.getManyAsync(); + expect(currentFetch.lastInit).to.be.empty; + }); + + it("should use provided object in fetch", async () => { + const requestInit: RequestInit = { method: "POST" }; + const query = ODataV4QueryProvider.createQuery(endpoint, { requestInit: () => requestInit }).filter((p) => + p.Name.$contains("vet"), + ); + await query.getManyAsync(); + expect(currentFetch.lastInit).to.equal(requestInit); + }); + + it("should use provided object via Promise in fetch", async () => { + const requestInit: RequestInit = { method: "POST" }; + const query = ODataV4QueryProvider.createQuery(endpoint, { + requestInit: () => Promise.resolve(requestInit), + }).filter((p) => p.Name.$contains("vet")); + await query.getManyAsync(); + expect(currentFetch.lastInit).to.equal(requestInit); + }); +});