From df3d034a08cdbace70c08b548aa7e0786f3583b9 Mon Sep 17 00:00:00 2001 From: BoxBoxJason Date: Sun, 22 Mar 2026 16:32:22 +0100 Subject: [PATCH 1/5] chore: harden lint configuration Signed-off-by: BoxBoxJason --- CHANGELOG.md | 223 +++--- eslint.config.mjs | 117 ++- package-lock.json | 1751 ++++++++++++++++++++++++++++++++++++++++++++- package.json | 4 + 4 files changed, 1973 insertions(+), 122 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0966343..2b52dab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,140 +5,169 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.4.0] - 2026-03-22 + +### Changed +- Bump package version by @BoxBoxJason +- Ignore files & directories in files achievements by @BoxBoxJason in [#46](https://github.com/BoxBoxJason/achievements/pull/46) +- Update all node dependencies by @BoxBoxJason + +### Fixed +- Quick open - close database erasure by @BoxBoxJason + +### Removed +- Remove ignore comment by @BoxBoxJason in [#45](https://github.com/BoxBoxJason/achievements/pull/45) + +## [0.3.1] - 2026-01-05 + +### Added +- Add contributing guide by @BoxBoxJason +- Add issues templates by @BoxBoxJason +- Add vscode custom files by @BoxBoxJason +- Add watch commands by @BoxBoxJason + ## [0.3.0] - 2026-01-02 ### Added -- Add git cliff configuration -- Add database lockfile +- Add git cliff configuration by @BoxBoxJason +- Add database lockfile by @BoxBoxJason ### Changed -- Optimize database & queries -- Upgrade all +- Optimize database & queries by @BoxBoxJason +- Upgrade all by @BoxBoxJason ### Fixed -- Code monkey progression +- Code monkey progression by @BoxBoxJason ## [0.2.0] - 2025-11-24 ### Added -- Add connection streak achievement +- Add connection streak achievement by @BoxBoxJason in [#32](https://github.com/BoxBoxJason/achievements/pull/32) ## [0.1.2] - 2025-11-23 ### Added -- Add icon -- Add license -- Add CHANGELOG for vsce publish +- Add icon by @BoxBoxJason +- Add license by @BoxBoxJason +- Add CHANGELOG for vsce publish by @BoxBoxJason ## [0.1.1] - 2025-11-22 ### Added -- Add unit tests +- Add unit tests by @BoxBoxJason - Add renovate configuration file ### Changed -- Migrate from better-sqlite3 to sql.js +- Migrate from better-sqlite3 to sql.js by @BoxBoxJason - Update dependency node to v24 - Update all-dependencies - Update all-dependencies - Update actions/setup-node action to v6 ### Fixed -- Display text alignment +- Display text alignment by @BoxBoxJason ### Removed -- Remove useless deps -- Remove dependabot +- Remove useless deps by @BoxBoxJason +- Remove dependabot by @BoxBoxJason in [#30](https://github.com/BoxBoxJason/achievements/pull/30) + +### New Contributors +* @ made their first contribution ## [0.1.0] - 2025-09-29 ### Added -- Add publish workflows -- Add (temporary) speaker icons -- Add productivity icons -- Add extensions icons -- Add shortcuts icons -- Add debugger icons -- Add files icons -- Add terminal tasks icons -- Add git achievements icons -- Add creator achievements logos -- Add new file edited listeners -- Add debug listeners -- Add extensions listeners -- Add tab events listeners -- Add terminal event listeners -- Add webview profile section -- Add time time tracking -- Add docstrings everywhere -- Add git related achievements listeners -- Add resource creation / deletion listeners -- Add containers styling -- Add separate module to handle frontend requests -- Add generic AchievementRequirement SQL script -- Add toggle notifications command -- Add proper README -- Add skeleton for Achievements react webview -- Add pusheen icons -- Add extensions commands -- Add separate database populate module -- Add separate db migrations manager module -- Add config manager module (specific to vscode) -- Add new achievements linked constants -- Add vscode specific logger module -- Add achievements creating classes +- Add publish workflows by @BoxBoxJason +- Add (temporary) speaker icons by @BoxBoxJason +- Add productivity icons by @BoxBoxJason +- Add extensions icons by @BoxBoxJason +- Add shortcuts icons by @BoxBoxJason +- Add debugger icons by @BoxBoxJason +- Add files icons by @BoxBoxJason +- Add terminal tasks icons by @BoxBoxJason +- Add git achievements icons by @BoxBoxJason +- Add creator achievements logos by @BoxBoxJason +- Add new file edited listeners by @BoxBoxJason +- Add debug listeners by @BoxBoxJason +- Add extensions listeners by @BoxBoxJason +- Add tab events listeners by @BoxBoxJason +- Add terminal event listeners by @BoxBoxJason +- Add webview profile section by @BoxBoxJason +- Add time time tracking by @BoxBoxJason +- Add docstrings everywhere by @BoxBoxJason +- Add git related achievements listeners by @BoxBoxJason +- Add resource creation / deletion listeners by @BoxBoxJason +- Add containers styling by @BoxBoxJason +- Add separate module to handle frontend requests by @BoxBoxJason +- Add generic AchievementRequirement SQL script by @BoxBoxJason +- Add toggle notifications command by @BoxBoxJason +- Add proper README by @BoxBoxJason +- Add skeleton for Achievements react webview by @BoxBoxJason +- Add pusheen icons by @BoxBoxJason +- Add extensions commands by @BoxBoxJason +- Add separate database populate module by @BoxBoxJason +- Add separate db migrations manager module by @BoxBoxJason +- Add config manager module (specific to vscode) by @BoxBoxJason +- Add new achievements linked constants by @BoxBoxJason +- Add vscode specific logger module by @BoxBoxJason +- Add achievements creating classes by @BoxBoxJason ### Changed -- Update changelog and install -- Complete build method -- Upgrade all dependencies -- Configuration -- Apply code formatters -- Prepare release -- Style using tailwindcss -- Proper image packaging -- Condition listeners setup -- Move settings from raw JSON to VSCode -- Update project description -- Replace terminal by tasks -- Rename points to EXP -- Cleanup db init to iterate over StackingTemplates -- UX -- Update logger module to accept any length / type arguments -- First UI release -- Upgrade progressions model (100x speedup) -- Yet another achievements model rework -- Upgrade achievements model (100x speedup) -- Move communication / requests to proper spots -- Move logger module -- Create Achievement webview page -- Upgrade Achievements controller -- Upgrade achievement model -- House cleaning -- House cleaning -- Create proper achievements workflow controller -- Standardize StackingTemplates -- Create progression management model -- Move and upgrade Achievements model -- Update model to use better-sqlite3 -- Housekeeping -- Prepare build & config for better-sqlite3 -- Replace Python achievements builder with typescript -- Standardize points attribution -- Create files stacking templates -- Create all productivity stacking templates -- Default vscode extension setup +- Update changelog and install by @BoxBoxJason +- Complete build method by @BoxBoxJason +- Upgrade all dependencies by @BoxBoxJason +- Configuration by @BoxBoxJason +- Apply code formatters by @BoxBoxJason +- Prepare release by @BoxBoxJason +- Style using tailwindcss by @BoxBoxJason +- Proper image packaging by @BoxBoxJason +- Condition listeners setup by @BoxBoxJason +- Move settings from raw JSON to VSCode by @BoxBoxJason +- Update project description by @BoxBoxJason +- Replace terminal by tasks by @BoxBoxJason +- Rename points to EXP by @BoxBoxJason +- Cleanup db init to iterate over StackingTemplates by @BoxBoxJason +- UX by @BoxBoxJason +- Update logger module to accept any length / type arguments by @BoxBoxJason +- First UI release by @BoxBoxJason +- Upgrade progressions model (100x speedup) by @BoxBoxJason +- Yet another achievements model rework by @BoxBoxJason +- Upgrade achievements model (100x speedup) by @BoxBoxJason +- Move communication / requests to proper spots by @BoxBoxJason +- Move logger module by @BoxBoxJason +- Create Achievement webview page by @BoxBoxJason +- Upgrade Achievements controller by @BoxBoxJason +- Upgrade achievement model by @BoxBoxJason +- House cleaning by @BoxBoxJason +- House cleaning by @BoxBoxJason +- Create proper achievements workflow controller by @BoxBoxJason +- Standardize StackingTemplates by @BoxBoxJason +- Create progression management model by @BoxBoxJason +- Move and upgrade Achievements model by @BoxBoxJason +- Update model to use better-sqlite3 by @BoxBoxJason +- Housekeeping by @BoxBoxJason +- Prepare build & config for better-sqlite3 by @BoxBoxJason +- Replace Python achievements builder with typescript by @BoxBoxJason +- Standardize points attribution by @BoxBoxJason +- Create files stacking templates by @BoxBoxJason +- Create all productivity stacking templates by @BoxBoxJason +- Default vscode extension setup by @BoxBoxJason ### Fixed -- Issues fix -- Change some constants to enums & fix awarder -- Errors in some default achievements -- Fix progressions model & controller workflow -- Leave error messages in lowercase - -[0.3.0]: https://github.com///compare/0.2.0...0.3.0 -[0.2.0]: https://github.com///compare/0.1.2...0.2.0 -[0.1.2]: https://github.com///compare/0.1.1...0.1.2 -[0.1.1]: https://github.com///compare/0.1.0...0.1.1 +- Issues fix by @BoxBoxJason +- Change some constants to enums & fix awarder by @BoxBoxJason +- Errors in some default achievements by @BoxBoxJason +- Fix progressions model & controller workflow by @BoxBoxJason +- Leave error messages in lowercase by @BoxBoxJason + +### New Contributors +* @BoxBoxJason made their first contribution + +[0.4.0]: https://github.com/BoxBoxJason/achievements/compare/0.3.1...0.4.0 +[0.3.1]: https://github.com/BoxBoxJason/achievements/compare/0.3.0...0.3.1 +[0.3.0]: https://github.com/BoxBoxJason/achievements/compare/0.2.0...0.3.0 +[0.2.0]: https://github.com/BoxBoxJason/achievements/compare/0.1.2...0.2.0 +[0.1.2]: https://github.com/BoxBoxJason/achievements/compare/0.1.1...0.1.2 +[0.1.1]: https://github.com/BoxBoxJason/achievements/compare/0.1.0...0.1.1 diff --git a/eslint.config.mjs b/eslint.config.mjs index ccf7156..bceea92 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,22 +1,95 @@ +import eslint from "@eslint/js"; import typescriptEslint from "@typescript-eslint/eslint-plugin"; import tsParser from "@typescript-eslint/parser"; +import promisePlugin from "eslint-plugin-promise"; export default [ + // Ignore patterns { - files: ["**/*.ts"], + ignores: ["dist/**", "node_modules/**", "*.d.ts"], }, + + // ESLint recommended baseline for all files + eslint.configs.recommended, + + // TypeScript and TSX files configuration { + files: ["**/*.ts", "**/*.tsx"], + plugins: { "@typescript-eslint": typescriptEslint, + promise: promisePlugin, }, languageOptions: { parser: tsParser, - ecmaVersion: 2022, - sourceType: "module", + parserOptions: { + ecmaVersion: 2022, + sourceType: "module", + projectService: true, + ecmaFeatures: { + jsx: true, + }, + }, + globals: { + // Browser API globals (for webview/React components) + window: "readonly", + document: "readonly", + MessageEvent: "readonly", + navigator: "readonly", + fetch: "readonly", + console: "readonly", + + // Node.js globals (for extension backend code) + process: "readonly", + Buffer: "readonly", + global: "readonly", + __dirname: "readonly", + __filename: "readonly", + setImmediate: "readonly", + clearImmediate: "readonly", + setInterval: "readonly", + clearInterval: "readonly", + setTimeout: "readonly", + clearTimeout: "readonly", + + // Mocha test globals + describe: "readonly", + it: "readonly", + before: "readonly", + after: "readonly", + beforeEach: "readonly", + afterEach: "readonly", + suite: "readonly", + test: "readonly", + setup: "readonly", + teardown: "readonly", + suiteSetup: "readonly", + suiteTeardown: "readonly", + + React: "readonly", + }, }, rules: { + "no-unused-vars": "off", + + // TypeScript ESLint recommended rules (non-type-checked) + "@typescript-eslint/no-unused-vars": [ + "warn", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + }, + ], + "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/no-non-null-assertion": "warn", + "@typescript-eslint/no-inferrable-types": "warn", + "@typescript-eslint/no-empty-interface": "warn", + "@typescript-eslint/no-var-requires": "warn", + "@typescript-eslint/prefer-as-const": "warn", + + // Naming conventions "@typescript-eslint/naming-convention": [ "warn", { @@ -25,10 +98,48 @@ export default [ }, ], + // Code quality and consistency rules curly: "warn", eqeqeq: "warn", "no-throw-literal": "warn", + "prefer-promise-reject-errors": "warn", + "no-unsafe-finally": "warn", + "no-async-promise-executor": "warn", + "@typescript-eslint/only-throw-error": "warn", + "@typescript-eslint/no-floating-promises": "warn", + "@typescript-eslint/no-misused-promises": [ + "warn", + { + checksVoidReturn: false, + }, + ], + "@typescript-eslint/use-unknown-in-catch-callback-variable": "warn", + "promise/catch-or-return": "warn", + "promise/always-return": "warn", + "promise/param-names": "warn", + "promise/no-return-wrap": "warn", + "no-useless-catch": "warn", semi: "warn", + "no-console": [ + "warn", + { + allow: ["warn", "error"], + }, + ], + "no-var": "warn", + "prefer-const": "warn", + "prefer-arrow-callback": "warn", + "no-empty-function": "warn", + }, + }, + + // Test files - slightly relaxed + { + files: ["**/*.test.ts", "**/*.spec.ts", "src/test/**"], + rules: { + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "no-console": "off", }, }, ]; diff --git a/package-lock.json b/package-lock.json index 8dbc92a..6feb140 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "sql.js": "^1.14.1" }, "devDependencies": { + "@eslint/js": "10.0.1", "@tailwindcss/cli": "4.2.2", "@types/mocha": "10.0.10", "@types/node": "25.5.0", @@ -29,13 +30,16 @@ "@vscode/vsce": "3.7.1", "esbuild": "0.27.4", "eslint": "10.1.0", + "eslint-plugin-promise": "^7.2.1", + "eslint-plugin-react": "7.37.5", + "eslint-plugin-react-hooks": "^4.6.0", "nyc": "^18.0.0", "ovsx": "^0.10.9", "ts-node": "10.9.2", "typescript": "5.9.3" }, "engines": { - "vscode": "^1.107.0" + "vscode": "^1.110.0" } }, "node_modules/@azu/format-text": { @@ -1088,6 +1092,27 @@ "node": "^20.19.0 || ^22.13.0 || >=24" } }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, "node_modules/@eslint/object-schema": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.3.tgz", @@ -3532,6 +3557,144 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -3542,6 +3705,16 @@ "node": ">=8" } }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -3549,6 +3722,22 @@ "dev": true, "license": "MIT" }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/azure-devops-node-api": { "version": "12.5.0", "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz", @@ -3593,9 +3782,9 @@ "optional": true }, "node_modules/baseline-browser-mapping": { - "version": "2.10.9", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.9.tgz", - "integrity": "sha512-OZd0e2mU11ClX8+IdXe3r0dbqMEznRiT4TfbhYIbcRPZkqJ7Qwer8ij3GZAmLsRKa+II9V1v5czCkvmHH3XZBg==", + "version": "2.10.10", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.10.tgz", + "integrity": "sha512-sUoJ3IMxx4AyRqO4MLeHlnGDkyXRoUG0/AI9fjK+vS72ekpV0yWVY7O0BVjmBcRtkNcsAO2QDZ4tdKKGoI6YaQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -3879,6 +4068,25 @@ "semver": "bin/semver.js" } }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -4290,6 +4498,60 @@ "dev": true, "license": "MIT" }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -4478,6 +4740,19 @@ "node": ">=0.3.1" } }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -4665,6 +4940,75 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/es-abstract": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", + "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -4685,6 +5029,35 @@ "node": ">= 0.4" } }, + "node_modules/es-iterator-helpers": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.1.tgz", + "integrity": "sha512-zWwRvqWiuBPr0muUG/78cW3aHROFCNIQ3zpmYDpwdbnt2m+xlNyRWpHBpa2lJjSBit7BQ+RXA1iwbSmu5yJ/EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.1", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.1.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.3.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.5", + "math-intrinsics": "^1.1.0", + "safe-array-concat": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -4714,6 +5087,37 @@ "node": ">= 0.4" } }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", @@ -4842,26 +5246,132 @@ } } }, - "node_modules/eslint-scope": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", - "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "node_modules/eslint-plugin-promise": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-7.2.1.tgz", + "integrity": "sha512-SWKjd+EuvWkYaS+uN2csvj0KoP43YTu7+phKQ5v+xw6+A0gutVX2yqCeCkC3uLCJFiPfR2dD8Es5L7yUsmvEaA==", "dev": true, - "license": "BSD-2-Clause", + "license": "ISC", "dependencies": { - "@types/esrecurse": "^4.3.1", - "@types/estree": "^1.0.8", - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "@eslint-community/eslint-utils": "^4.4.0" }, "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, - "node_modules/eslint-visitor-keys": { + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "dev": true, + "license": "MIT", + "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/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "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==", @@ -5268,6 +5778,22 @@ } } }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", @@ -5371,6 +5897,47 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -5453,6 +6020,24 @@ "node": ">= 0.4" } }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", @@ -5586,6 +6171,19 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "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", @@ -5609,6 +6207,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -5859,6 +6473,75 @@ "license": "ISC", "optional": true }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -5872,6 +6555,36 @@ "node": ">=8" } }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-ci": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", @@ -5885,6 +6598,57 @@ "is-ci": "bin.js" } }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-docker": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", @@ -5911,6 +6675,22 @@ "node": ">=0.10.0" } }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -5921,6 +6701,26 @@ "node": ">=8" } }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -5979,6 +6779,32 @@ "node": ">=12" } }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5989,6 +6815,23 @@ "node": ">=0.12.0" } }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -6006,20 +6849,119 @@ "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-typedarray": { @@ -6042,6 +6984,52 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "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", @@ -6228,6 +7216,24 @@ "url": "https://bevry.me/fund" } }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", @@ -6364,6 +7370,22 @@ "npm": ">=6" } }, + "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, + "license": "MIT", + "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/jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", @@ -6839,6 +7861,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -7241,6 +8276,35 @@ "dev": true, "license": "MIT" }, + "node_modules/node-exports-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", + "integrity": "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/node-exports-info/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, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -7631,6 +8695,16 @@ "node": ">=6" } }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -7654,6 +8728,81 @@ "node": ">= 0.4" } }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "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", @@ -7856,6 +9005,24 @@ "node": ">= 6" } }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -8065,6 +9232,13 @@ "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, "node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", @@ -8208,6 +9382,16 @@ "node": ">=4" } }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/prebuild-install": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", @@ -8267,6 +9451,18 @@ "node": ">=8" } }, + "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, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, "node_modules/proper-lockfile": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", @@ -8425,6 +9621,13 @@ "react": "^19.2.4" } }, + "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, + "license": "MIT" + }, "node_modules/read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -8533,6 +9736,50 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/release-zalgo": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", @@ -8573,6 +9820,30 @@ "dev": true, "license": "ISC" }, + "node_modules/resolve": { + "version": "2.0.0-next.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.6.tgz", + "integrity": "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -8722,6 +9993,33 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "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, + "license": "MIT" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -8743,6 +10041,48 @@ ], "license": "MIT" }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply/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, + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -8818,6 +10158,55 @@ "dev": true, "license": "ISC" }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -9175,6 +10564,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -9269,6 +10672,104 @@ "node": ">=8" } }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/strip-ansi": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", @@ -9385,6 +10886,19 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/table": { "version": "6.9.0", "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", @@ -9710,6 +11224,84 @@ "node": ">=8" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typed-rest-client": { "version": "1.8.11", "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", @@ -9753,6 +11345,25 @@ "dev": true, "license": "MIT" }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/underscore": { "version": "1.13.8", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz", @@ -9958,6 +11569,80 @@ "node": ">= 8" } }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/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, + "license": "MIT" + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/which-module": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", @@ -9965,6 +11650,28 @@ "dev": true, "license": "ISC" }, + "node_modules/which-typed-array": { + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", diff --git a/package.json b/package.json index 4f80567..32fc408 100644 --- a/package.json +++ b/package.json @@ -160,6 +160,7 @@ "changelog": "git-cliff -c cliff.toml -o CHANGELOG.md" }, "devDependencies": { + "@eslint/js": "10.0.1", "@tailwindcss/cli": "4.2.2", "@types/mocha": "10.0.10", "@types/node": "25.5.0", @@ -175,6 +176,9 @@ "@vscode/vsce": "3.7.1", "esbuild": "0.27.4", "eslint": "10.1.0", + "eslint-plugin-promise": "^7.2.1", + "eslint-plugin-react": "7.37.5", + "eslint-plugin-react-hooks": "^4.6.0", "nyc": "^18.0.0", "ovsx": "^0.10.9", "ts-node": "10.9.2", From f8c69a3a73e38d4e1e7db9ce6bcb38840e2bc3b2 Mon Sep 17 00:00:00 2001 From: BoxBoxJason Date: Sun, 22 Mar 2026 17:04:47 +0100 Subject: [PATCH 2/5] fix: correct all lint errors & warns Signed-off-by: BoxBoxJason --- src/config/config.ts | 52 ++++---- src/database/controller/achievements.ts | 4 +- src/database/controller/progressions.ts | 37 +++--- src/database/controller/timespent.ts | 21 ++-- src/database/model/init/init.ts | 2 +- src/database/model/migrations.ts | 2 +- src/database/model/model.ts | 34 ++++-- src/database/model/tables/Achievement.ts | 107 ++++++++++------- src/database/model/tables/DailySession.ts | 67 +++++------ src/database/model/tables/Progression.ts | 40 ++++--- src/extension.ts | 36 +++--- src/listeners/awarder.ts | 18 ++- src/listeners/debug.ts | 10 +- src/listeners/extensions.ts | 26 ++-- src/listeners/files.ts | 2 +- src/listeners/git.ts | 44 +++---- src/test/connection-streak.test.ts | 2 +- src/test/database.test.ts | 14 ++- src/test/extension.ui.test.ts | 4 +- src/test/listeners/extensions.test.ts | 108 +++++++++-------- src/test/listeners/files.test.ts | 4 +- src/test/runTest.ts | 32 ++--- src/test/utils.ts | 125 +++++++++++--------- src/utils/logger.ts | 21 ++-- src/utils/types.ts | 13 +- src/views/components/AchievementDisplay.tsx | 13 +- src/views/components/AchievementsHolder.tsx | 9 +- src/views/components/SearchBar.tsx | 7 +- src/views/components/UserStats.tsx | 27 +++-- src/views/icons.ts | 12 +- src/views/index.tsx | 4 +- src/views/management.ts | 24 ++-- src/views/requests/backend.ts | 25 ++-- src/views/window.d.ts | 10 ++ 34 files changed, 520 insertions(+), 436 deletions(-) create mode 100644 src/views/window.d.ts diff --git a/src/config/config.ts b/src/config/config.ts index 2b6299a..c21ab8d 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -36,7 +36,7 @@ export interface Config { } // ==================== VARIABLES ==================== -let defaultLogDir: string = ""; +let defaultLogDir = ""; // ==================== MODULE FUNCTIONS ==================== /** @@ -71,7 +71,7 @@ export namespace config { // Prompt the user to set an username if it is the default one if (config.username === webview.DEFAULT_USER) { - handleSetUsername(); + void handleSetUsername(); } } @@ -83,29 +83,25 @@ export namespace config { * * @returns {void} */ - function handleSetUsername() { - vscode.window - .showInformationMessage( - "For a better experience, please set your username", - "Set Username", - ) - .then((selection) => { - if (selection === "Set Username") { - vscode.window - .showInputBox({ - prompt: "Enter your username", - placeHolder: webview.DEFAULT_USER, - validateInput: (input) => { - return input.trim() ? null : "Username cannot be empty"; - }, - }) - .then((username) => { - if (username) { - setUsername(username); - } - }); - } + async function handleSetUsername() { + const selection = await vscode.window.showInformationMessage( + "For a better experience, please set your username", + "Set Username", + ); + + if (selection === "Set Username") { + const username = await vscode.window.showInputBox({ + prompt: "Enter your username", + placeHolder: webview.DEFAULT_USER, + validateInput: (input) => { + return input.trim() ? null : "Username cannot be empty"; + }, }); + + if (username) { + setUsername(username); + } + } } /** @@ -120,7 +116,7 @@ export namespace config { export function getConfig(): Readonly { const extensionRawConfig = vscode.workspace.getConfiguration("achievements"); - let extensionConfig: Config = { + const extensionConfig: Config = { enabled: extensionRawConfig.get("enabled", true), logLevel: extensionRawConfig.get("logLevel", "info"), notifications: extensionRawConfig.get("notifications", true), @@ -193,8 +189,8 @@ export namespace config { const enabled = !config.enabled; updateConfig("enabled", enabled); - let enabledString = enabled ? "enabled" : "disabled"; - let enabledMessage = `Achievement ${enabledString}!`; + const enabledString = enabled ? "enabled" : "disabled"; + const enabledMessage = `Achievement ${enabledString}!`; logger.info(enabledMessage); vscode.window.showInformationMessage(enabledMessage); } @@ -245,7 +241,7 @@ export namespace config { return getConfig().username; } - function updateConfig(key: string, value: any) { + function updateConfig(key: string, value: unknown) { const config = vscode.workspace.getConfiguration("achievements"); config.update(key, value, vscode.ConfigurationTarget.Global); } diff --git a/src/database/controller/achievements.ts b/src/database/controller/achievements.ts index 0049a6a..873ff8e 100644 --- a/src/database/controller/achievements.ts +++ b/src/database/controller/achievements.ts @@ -188,7 +188,7 @@ export namespace AchievementController { // Trim the criterias and check if they are empty if (filters.criterias !== undefined) { - let trimmedCriterias: string[] = []; + const trimmedCriterias: string[] = []; for (let criteria of filters.criterias) { criteria = criteria.trim(); if (criteria !== "") { @@ -204,7 +204,7 @@ export namespace AchievementController { // Trim the labels and check if they are empty if (filters.labels !== undefined) { - let trimmedLabels: string[] = []; + const trimmedLabels: string[] = []; for (let label of filters.labels) { label = label.trim(); if (label !== "") { diff --git a/src/database/controller/progressions.ts b/src/database/controller/progressions.ts index 99e4806..5255822 100644 --- a/src/database/controller/progressions.ts +++ b/src/database/controller/progressions.ts @@ -34,8 +34,8 @@ export namespace ProgressionController { */ export async function getProgressions(): Promise { const progressions = await Progression.getProgressions({}); - let progressionDict: ProgressionDict = Object(); - for (let progression of progressions) { + const progressionDict: ProgressionDict = Object(); + for (const progression of progressions) { progressionDict[progression.name] = progression.value; } @@ -54,26 +54,25 @@ export namespace ProgressionController { */ export async function increaseProgression( criteriaName: string, - increase: number | string = 1 + increase: number | string = 1, ): Promise { // Update the progression value and retrieve all progressions try { const updatedProgressionsIds = await Progression.addValue( { name: criteriaName }, - increase + increase, ); const updatedAchievements = await Progression.achieveCompletedAchievements( - updatedProgressionsIds.map((progression) => progression.id) + updatedProgressionsIds.map((progression) => progression.id), ); - let awardedPoints = 0; - for (let achievement of updatedAchievements) { + for (const achievement of updatedAchievements) { // Notify the user of the unlocked achievement - awardAchievement(achievement); + void awardAchievement(achievement); } } catch (error) { logger.error( - `Failed to increase progression: ${(error as Error).message}` + `Failed to increase progression: ${(error as Error).message}`, ); } } @@ -91,21 +90,21 @@ export namespace ProgressionController { export async function updateProgression( criteriaName: string, value: string | number | Date | boolean, - maximize: boolean = false + maximize = false, ): Promise { try { const updatedProgressionsIds = await Progression.updateValue( { name: criteriaName }, value.toString(), - maximize + maximize, ); const updatedAchievements = await Progression.achieveCompletedAchievements( - updatedProgressionsIds.map((progression) => progression.id) + updatedProgressionsIds.map((progression) => progression.id), ); - for (let achievement of updatedAchievements) { + for (const achievement of updatedAchievements) { // Notify the user of the unlocked achievement - awardAchievement(achievement); + void awardAchievement(achievement); } } catch (error) { logger.error(`Failed to update progression: ${(error as Error).message}`); @@ -126,7 +125,7 @@ export namespace ProgressionController { name: string; value: string | number | Date | boolean; maximize?: boolean; - }> + }>, ): Promise { try { const allUpdatedIds: number[] = []; @@ -134,7 +133,7 @@ export namespace ProgressionController { const updatedProgressionsIds = await Progression.updateValue( { name: update.name }, update.value.toString(), - update.maximize + update.maximize, ); allUpdatedIds.push(...updatedProgressionsIds.map((p) => p.id)); } @@ -142,13 +141,13 @@ export namespace ProgressionController { if (allUpdatedIds.length > 0) { const updatedAchievements = await Progression.achieveCompletedAchievements(allUpdatedIds); - for (let achievement of updatedAchievements) { - awardAchievement(achievement); + for (const achievement of updatedAchievements) { + void awardAchievement(achievement); } } } catch (error) { logger.error( - `Failed to update progressions: ${(error as Error).message}` + `Failed to update progressions: ${(error as Error).message}`, ); } } diff --git a/src/database/controller/timespent.ts b/src/database/controller/timespent.ts index bf85a75..8b3ae35 100644 --- a/src/database/controller/timespent.ts +++ b/src/database/controller/timespent.ts @@ -19,14 +19,14 @@ export namespace TimeSpentController { const currentDateString = currentDate.toISOString().split("T")[0]; const fourteenDaysAgo = new Date( - currentDate.getTime() - 14 * 24 * 60 * 60 * 1000 + currentDate.getTime() - 14 * 24 * 60 * 60 * 1000, ); const fourteenDaysAgoString = fourteenDaysAgo.toISOString().split("T")[0]; const firstDayOfMonth = new Date( currentDate.getFullYear(), currentDate.getMonth(), - 1 + 1, ); const firstDayOfMonthString = firstDayOfMonth.toISOString().split("T")[0]; @@ -39,7 +39,7 @@ export namespace TimeSpentController { currentDateString, fourteenDaysAgoString, firstDayOfMonthString, - firstDayOfYearString + firstDayOfYearString, ); await ProgressionController.updateProgressions([ @@ -85,9 +85,7 @@ export namespace TimeSpentController { constants.criteria.TOTAL_TIME_SPENT, ] as string[]; return Object.fromEntries( - Object.entries(progressions).filter(([key, value]) => - toLookFor.includes(key) - ) + Object.entries(progressions).filter(([key]) => toLookFor.includes(key)), ); } @@ -121,9 +119,8 @@ export namespace TimeSpentController { yesterdayDate.setDate(yesterdayDate.getDate() - 1); const yesterdayDateString = yesterdayDate.toISOString().split("T")[0]; - const yesterdaySession = await DailySession.getOrCreate( - yesterdayDateString - ); + const yesterdaySession = + await DailySession.getOrCreate(yesterdayDateString); let newStreak = 1; @@ -142,20 +139,20 @@ export namespace TimeSpentController { // Update current streak await ProgressionController.updateProgression( constants.criteria.CURRENT_CONNECTION_STREAK, - newStreak + newStreak, ); // Update max streak await ProgressionController.updateProgression( constants.criteria.MAX_CONNECTION_STREAK, newStreak, - true + true, ); // Update last streak date await ProgressionController.updateProgression( constants.criteria.LAST_STREAK_DATE, - currentDateString + currentDateString, ); } } diff --git a/src/database/model/init/init.ts b/src/database/model/init/init.ts index 7552388..28bbd5f 100644 --- a/src/database/model/init/init.ts +++ b/src/database/model/init/init.ts @@ -97,7 +97,7 @@ export namespace db_init { */ async function createIntegerProgressions(): Promise { logger.debug("Creating integer progressions"); - let progressions: Progression[] = []; + const progressions: Progression[] = []; for (const criteria of Object.values(constants.criteria)) { if ( diff --git a/src/database/model/migrations.ts b/src/database/model/migrations.ts index 03cc249..67580a0 100644 --- a/src/database/model/migrations.ts +++ b/src/database/model/migrations.ts @@ -32,7 +32,7 @@ interface Migration { */ export async function applyMigration( db: Database, - wantedVersion: number = -1 + wantedVersion = -1 ): Promise { const migrations: { [key: number]: Migration } = { 1: { diff --git a/src/database/model/model.ts b/src/database/model/model.ts index 356d83c..d4072a4 100644 --- a/src/database/model/model.ts +++ b/src/database/model/model.ts @@ -9,7 +9,7 @@ import * as path from "node:path"; import * as fs from "node:fs"; import logger from "../../utils/logger"; import * as vscode from "vscode"; -import initSqlJs, { Database, SqlJsStatic } from "sql.js"; +import initSqlJs, { Database, SqlJsStatic, SqlValue } from "sql.js"; import { applyMigration } from "./migrations"; import { db_init } from "./init/init"; import { db_lock } from "../lock"; @@ -151,7 +151,7 @@ export namespace db_model { let hasLock = false; try { - let databaseDir = context.globalStorageUri.fsPath; + const databaseDir = context.globalStorageUri.fsPath; await fs.promises.mkdir(databaseDir, { recursive: true }); DATABASE_PATH = dbPath || path.join(databaseDir, DATABASE_FILENAME); @@ -226,31 +226,39 @@ export namespace db_model { * @param {any[]} params The parameters to bind to the query * @returns {any[]} The result rows */ - export function getAll(db: Database, query: string, params?: any[]): any[] { + export function get( + db: Database, + query: string, + params?: SqlValue[], + ): T | null { const stmt = db.prepare(query); stmt.bind(params); - const result = []; - while (stmt.step()) { - result.push(stmt.getAsObject()); + let result: T | null = null; + if (stmt.step()) { + result = stmt.getAsObject() as T; } stmt.free(); return result; } /** - * Execute a query and return the first row as an object. + * Execute a query and return all rows as objects. * * @param {Database} db The database connection object * @param {string} query The query to execute - * @param {any[]} params The parameters to bind to the query - * @returns {any} The result row + * @param {SqlValue[]} params The parameters to bind to the query + * @returns {T[]} The result rows */ - export function get(db: Database, query: string, params?: any[]): any { + export function getAll( + db: Database, + query: string, + params?: SqlValue[], + ): T[] { const stmt = db.prepare(query); stmt.bind(params); - let result = null; - if (stmt.step()) { - result = stmt.getAsObject(); + const result: T[] = []; + while (stmt.step()) { + result.push(stmt.getAsObject() as T); } stmt.free(); return result; diff --git a/src/database/model/tables/Achievement.ts b/src/database/model/tables/Achievement.ts index 9ae4608..00b3479 100644 --- a/src/database/model/tables/Achievement.ts +++ b/src/database/model/tables/Achievement.ts @@ -7,6 +7,7 @@ import { db_model } from "../model"; import { parseValue } from "../../../utils/types"; +import { SqlValue } from "sql.js"; // ==================== TYPES ==================== @@ -18,7 +19,7 @@ export interface StackingAchievementTemplate { group: string; labels: string[]; criterias: string[]; - criteriasFunctions: ((tier: number) => any)[]; + criteriasFunctions: ((tier: number) => number)[]; description: string; minTier: number; maxTier: number; @@ -34,7 +35,7 @@ export interface AchievementDict { category: string; group: string; labels: string[]; - criteria: { [key: string]: any }; + criteria: { [key: string]: unknown }; description: string; tier: number; exp: number; @@ -96,7 +97,7 @@ export interface AchievementRow { requirements: number[]; criteria: Array<{ progression_name: string; - required_value: any; + required_value: unknown; type: string; }>; } @@ -192,14 +193,14 @@ class Achievement { public category: string; public group: string; public labels: string[]; - public criteria: { [key: string]: any }; + public criteria: { [key: string]: unknown }; public description: string; public tier: number; public exp: number; public hidden: boolean; public requires: number[]; public repeatable: boolean; - public achieved: boolean = false; + public achieved = false; public achievedAt: Date | undefined; /** @@ -213,15 +214,15 @@ class Achievement { */ constructor(data: AchievementDict) { // Destructuring data object for validation and assignment - let { + const { id, - title, - icon, - category, - group, + title: rawTitle, + icon: rawIcon, + category: rawCategory, + group: rawGroup, labels, criteria, - description, + description: rawDescription, tier, exp, hidden, @@ -229,6 +230,12 @@ class Achievement { repeatable, } = data; + let title = rawTitle; + let icon = rawIcon; + let category = rawCategory; + let group = rawGroup; + let description = rawDescription; + // Input validation title = title.trim(); if (!title) { @@ -304,7 +311,7 @@ class Achievement { */ static async fromStackingTemplateToDB( template: StackingAchievementTemplate, - multiplier: number = 1 + multiplier = 1, ): Promise { const { title, @@ -322,11 +329,25 @@ class Achievement { requires, } = template; - const achievementData: any[] = []; - const criteriaData: any[] = []; - const requirementData: any[] = []; - const requirementByIdData: any[] = []; - const labelsData: any[] = []; + const achievementData: Array< + [ + string, + string, + string, + string, + string, + number, + number, + number, + number, + number, + null, + ] + > = []; + const criteriaData: Array<[number, string, string, string]> = []; + const requirementData: Array<[string, string]> = []; + const requirementByIdData: Array<[number, string]> = []; + const labelsData: Array<[string, string]> = []; const tierTitles: string[] = []; // Prepare achievement data @@ -334,14 +355,14 @@ class Achievement { const currentTitle = title.replace("%d", (tier - minTier + 1).toString()); // Calculate criteria values and update description - const criteriaMap: { [key: string]: any } = {}; + const criteriaMap: { [key: string]: number } = {}; let currentDescription = description; for (let i = 0; i < criterias.length; i++) { const value = criteriasFunctions[i](tier); criteriaMap[criterias[i]] = value * multiplier; currentDescription = currentDescription.replace( criterias[i], - String(value) + String(value), ); } @@ -468,7 +489,7 @@ class Achievement { category: row.category, group: row.group, labels: row.labels, - criteria: row.criteria.reduce((acc: any, c: any) => { + criteria: row.criteria.reduce((acc: Record, c) => { acc[c.progression_name] = parseValue(c.required_value, c.type); return acc; }, {}), @@ -494,7 +515,7 @@ class Achievement { * @param {boolean} achieved - The achieved status of the achievement * @returns {Promise} */ - async updateAchieved(achieved: boolean = true): Promise { + async updateAchieved(achieved = true): Promise { this.achieved = achieved; this.achievedAt = achieved ? new Date() : undefined; const query = `UPDATE achievements SET achieved = ?, achievedAt = ? WHERE id = ?`; @@ -526,7 +547,7 @@ class Achievement { */ static async updateAchievedFromId( id: number, - achieved: boolean = true + achieved = true, ): Promise { const query = `UPDATE achievements SET achieved = ?, achievedAt = ? WHERE id = ?`; @@ -554,7 +575,7 @@ class Achievement { * @returns {Promise<{ count: number | null; achievements: AchievementRow[] }>} - The list of achievements */ static async getAchievementsRawFormat( - filters: AchievementSelectRequestFilters + filters: AchievementSelectRequestFilters, ): Promise<{ count: number | null; achievements: AchievementRow[]; @@ -562,7 +583,7 @@ class Achievement { const db = await db_model.getDB(); // Base query for achievements - let baseQuery = ` + const baseQuery = ` FROM achievements a LEFT JOIN achievement_requirements ar ON a.id = ar.achievement_id LEFT JOIN achievements r ON ar.requirement_id = r.id @@ -572,7 +593,7 @@ class Achievement { `; const conditions: string[] = []; - const values: any[] = []; + const values: SqlValue[] = []; // Apply filters if (filters.category) { @@ -587,7 +608,7 @@ class Achievement { // Match achievements with all provided labels const labelConditions = filters.labels.map( () => - "EXISTS (SELECT 1 FROM achievement_labels al WHERE al.achievement_id = a.id AND al.label = ?)" + "EXISTS (SELECT 1 FROM achievement_labels al WHERE al.achievement_id = a.id AND al.label = ?)", ); conditions.push(`(${labelConditions.join(" AND ")})`); values.push(...filters.labels); @@ -643,10 +664,8 @@ class Achievement { ${baseQuery} ${whereClause} `; - const countRow = db_model.get(db, countQuery, values) as { - total: number; - }; - count = countRow.total; + const countRow = db_model.get<{ total: number }>(db, countQuery, values); + count = countRow?.total ?? 0; } // Query to get the achievements @@ -686,11 +705,11 @@ class Achievement { values.push(filters.offset); } - const rows = db_model.getAll( + const rows = db_model.getAll( db, achievementsQuery, - values - ) as RawAchievementRow[]; + values, + ); // Parse JSON fields const achievements = rows.map((row) => ({ @@ -714,14 +733,13 @@ class Achievement { * @returns {Promise<{ count: number | null; achievements: Achievement[] }>} - The list of achievements */ static async getAchievements( - filters: AchievementSelectRequestFilters + filters: AchievementSelectRequestFilters, ): Promise<{ count: number | null; achievements: Achievement[]; }> { - const { count, achievements } = await Achievement.getAchievementsRawFormat( - filters - ); + const { count, achievements } = + await Achievement.getAchievementsRawFormat(filters); return { count, achievements: achievements.map(Achievement.fromRow), @@ -768,8 +786,11 @@ class Achievement { */ static async getGroups(): Promise { const db = await db_model.getDB(); - const rows = db_model.getAll(db, 'SELECT DISTINCT "group" FROM achievements'); - return rows.map((row) => (row as any).group); + const rows = db_model.getAll( + db, + 'SELECT DISTINCT "group" FROM achievements', + ); + return rows.map((row) => (row as { group: string }).group); } /** @@ -785,9 +806,9 @@ class Achievement { const db = await db_model.getDB(); const rows = db_model.getAll( db, - "SELECT DISTINCT category FROM achievements" + "SELECT DISTINCT category FROM achievements", ); - return rows.map((row) => (row as any).category); + return rows.map((row) => (row as { category: string }).category); } /** @@ -803,9 +824,9 @@ class Achievement { const db = await db_model.getDB(); const rows = db_model.getAll( db, - "SELECT DISTINCT label FROM achievement_labels" + "SELECT DISTINCT label FROM achievement_labels", ); - return rows.map((row) => (row as any).label); + return rows.map((row) => (row as { label: string }).label); } } diff --git a/src/database/model/tables/DailySession.ts b/src/database/model/tables/DailySession.ts index 58bb15e..3a98e6c 100644 --- a/src/database/model/tables/DailySession.ts +++ b/src/database/model/tables/DailySession.ts @@ -17,10 +17,7 @@ export class DailySession { this.id = id; } - static async getOrCreate( - date?: string, - duration: number = 0 - ): Promise { + static async getOrCreate(date?: string, duration = 0): Promise { const dateStr = date || new Date().toISOString().split("T")[0]; if (!dateStr.match(/^\d{4}-\d{2}-\d{2}$/)) { throw new Error("date must be in the format YYYY-MM-DD"); @@ -30,17 +27,17 @@ export class DailySession { } const db = await db_model.getDB(); - const existingSession = db_model.get( + const existingSession = db_model.get( db, `SELECT * FROM daily_sessions WHERE date = ?`, - [dateStr] - ) as DailySessionDict; + [dateStr], + ); if (existingSession) { return new DailySession( existingSession.date, existingSession.duration, - existingSession.id + existingSession.id, ); } else { const statement = db.prepare(DailySession.INSERT_QUERY); @@ -53,15 +50,18 @@ export class DailySession { // Better would be to use RETURNING clause if supported or a separate select. // SQLite supports RETURNING since 3.35.0. sql.js is based on recent SQLite. // Let's try to fetch it back by date which is unique. - const newSession = db_model.get( + const newSession = db_model.get( db, `SELECT * FROM daily_sessions WHERE date = ?`, - [dateStr] - ) as DailySessionDict; + [dateStr], + ); + if (!newSession) { + throw new Error("Failed to create daily session"); + } return new DailySession( newSession.date, newSession.duration, - newSession.id + newSession.id, ); } } @@ -90,22 +90,22 @@ export class DailySession { static async getRawSessions( firstDate: string, - lastDate: string + lastDate: string, ): Promise { const db = await db_model.getDB(); - return db_model.getAll( + return db_model.getAll( db, ` SELECT * FROM daily_sessions WHERE date BETWEEN ? AND ? ORDER BY date`, - [firstDate, lastDate] - ) as DailySessionDict[]; + [firstDate, lastDate], + ); } static async getSessions( firstDate: string, - lastDate: string + lastDate: string, ): Promise { const rawSessions = await this.getRawSessions(firstDate, lastDate); return rawSessions.map(DailySession.fromRow); @@ -113,25 +113,25 @@ export class DailySession { static async calculateDuration( firstDate: string, - lastDate: string + lastDate: string, ): Promise { const db = await db_model.getDB(); - const res = db_model.get( + const res = db_model.get<{ total_duration: number | null }>( db, ` SELECT SUM(duration) as total_duration FROM daily_sessions WHERE date BETWEEN ? AND ?`, - [firstDate, lastDate] + [firstDate, lastDate], ); - return res.total_duration as number; + return res?.total_duration ?? 0; } static async getStatsSummary( today: string, twoWeeksAgo: string, monthStart: string, - yearStart: string + yearStart: string, ): Promise<{ daily: number; twoWeeks: number; @@ -149,18 +149,19 @@ export class DailySession { SUM(duration) as total FROM daily_sessions `; - const result = db_model.get(db, query, [ - today, - twoWeeksAgo, - monthStart, - yearStart, - ]); + const result = db_model.get<{ + daily: number | null; + twoWeeks: number | null; + monthly: number | null; + yearly: number | null; + total: number | null; + }>(db, query, [today, twoWeeksAgo, monthStart, yearStart]); return { - daily: result.daily || 0, - twoWeeks: result.twoWeeks || 0, - monthly: result.monthly || 0, - yearly: result.yearly || 0, - total: result.total || 0, + daily: result?.daily || 0, + twoWeeks: result?.twoWeeks || 0, + monthly: result?.monthly || 0, + yearly: result?.yearly || 0, + total: result?.total || 0, }; } } diff --git a/src/database/model/tables/Progression.ts b/src/database/model/tables/Progression.ts index 5027351..ac5510d 100644 --- a/src/database/model/tables/Progression.ts +++ b/src/database/model/tables/Progression.ts @@ -6,6 +6,7 @@ */ import { db_model } from "../model"; +import { SqlValue } from "sql.js"; // ==================== TYPES ==================== @@ -75,7 +76,7 @@ class Progression { * @param {any} row - The database row to create an instance from. * @returns {Progression} - An instance of Progression. */ - static fromRow(row: any): Progression { + static fromRow(row: ProgressionRow): Progression { let value = row.value as string | number | Date | boolean; switch (row.type) { case "string": @@ -115,7 +116,7 @@ class Progression { static async fromDB(): Promise { const db = await db_model.getDB(); const query = "SELECT * FROM progressions"; - const rows = db_model.getAll(db, query); + const rows = db_model.getAll(db, query); return rows.map((row) => Progression.fromRow(row)); } @@ -146,7 +147,10 @@ class Progression { await db_model.saveDB(); // Change the id of the instance to the id of the row if it was inserted - const idRow = db_model.get(db, "SELECT last_insert_rowid() as id"); + const idRow = db_model.get<{ id: number }>( + db, + "SELECT last_insert_rowid() as id", + ); if (idRow?.id) { this.id = Number(idRow.id); } @@ -201,7 +205,7 @@ class Progression { * @returns {Promise<{ id: number; title: string; achievedAt: string }[]>} - An array of newly achieved achievements. */ static async achieveCompletedAchievements( - progressionIds: number[] + progressionIds: number[], ): Promise<{ id: number; title: string; achievedAt: string; exp: number }[]> { if (progressionIds.length === 0) { return []; // No progressions to process @@ -246,7 +250,7 @@ class Progression { const rows = db_model.getAll( db, updateAchievementsQuery, - progressionIds + progressionIds, ) as { id: number; title: string; @@ -268,7 +272,7 @@ class Progression { */ static async addValue( filters: ProgressionSelectRequestFilters, - value: number | string = 1 + value: number | string = 1, ): Promise<{ id: number }[]> { const ADD_VALUE_QUERY = ` UPDATE progressions @@ -292,7 +296,7 @@ class Progression { const rows = db_model.getAll( db, ADD_VALUE_QUERY.replace("SELECTOR_PLACEHOLDER", selectorColumn), - [value, value, value, value, value, value, selectorValue] + [value, value, value, value, value, value, selectorValue], ) as { id: number; }[]; @@ -314,7 +318,7 @@ class Progression { static async updateValue( filters: ProgressionSelectRequestFilters, value: string, - maximize: boolean = false + maximize = false, ): Promise<{ id: number }[]> { const UPDATE_VALUE_QUERY = maximize ? ` @@ -329,17 +333,17 @@ class Progression { WHERE SELECTOR_PLACEHOLDER RETURNING id; `; - let [selectorColumn, selectorValue] = parseUpdateFilters(filters); - let query = UPDATE_VALUE_QUERY.replace( + const [selectorColumn, selectorValue] = parseUpdateFilters(filters); + const query = UPDATE_VALUE_QUERY.replace( "SELECTOR_PLACEHOLDER", - selectorColumn + selectorColumn, ); const db = await db_model.getDB(); const rows = db_model.getAll( db, query, - maximize ? [value, selectorValue, value] : [value, selectorValue] + maximize ? [value, selectorValue, value] : [value, selectorValue], ) as { id: number }[]; await db_model.saveDB(); return rows; @@ -358,12 +362,12 @@ class Progression { * @returns {Promise} - An array of progressions in raw format. */ static async getProgressionsRawFormat( - filters: ProgressionSelectRequestFilters + filters: ProgressionSelectRequestFilters, ): Promise { const db = await db_model.getDB(); let query = "SELECT * FROM progressions"; - let where = []; - let values = []; + const where: string[] = []; + const values: SqlValue[] = []; if (filters.name) { where.push("name = ?"); @@ -389,7 +393,7 @@ class Progression { values.push(filters.offset); } - return db_model.getAll(db, query, values) as ProgressionRow[]; + return db_model.getAll(db, query, values); } /** @@ -403,7 +407,7 @@ class Progression { * @returns {Promise} - An array of progressions. */ static async getProgressions( - filters: ProgressionSelectRequestFilters + filters: ProgressionSelectRequestFilters, ): Promise { const rows = await Progression.getProgressionsRawFormat(filters); return rows.map((row) => Progression.fromRow(row)); @@ -411,7 +415,7 @@ class Progression { } function parseUpdateFilters( - filters: ProgressionSelectRequestFilters + filters: ProgressionSelectRequestFilters, ): [string, string] { let selectorValue: string; let selectorColumn: string; diff --git a/src/extension.ts b/src/extension.ts index 84360f4..f821309 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -25,22 +25,24 @@ export function showReadOnlyUI(context: vscode.ExtensionContext): void { "Achievements: Running in read-only mode because another VS Code instance is using the database. Achievements won't be tracked."; // Show a persistent warning with an action to open settings - vscode.window - .showWarningMessage(message, "Open Settings") - .then((selection) => { - if (selection === "Open Settings") { - vscode.commands.executeCommand( - "workbench.action.openSettings", - "@ext:boxboxjason.achievements" - ); - } - }); + void (async () => { + const selection = await vscode.window.showWarningMessage( + message, + "Open Settings", + ); + if (selection === "Open Settings") { + await vscode.commands.executeCommand( + "workbench.action.openSettings", + "@ext:boxboxjason.achievements", + ); + } + })(); // Add a status bar item to make the state visible at all times try { const statusBarItem = vscode.window.createStatusBarItem( vscode.StatusBarAlignment.Left, - 100 + 100, ); statusBarItem.text = "$(lock) Achievements (read-only)"; statusBarItem.tooltip = message; @@ -58,7 +60,7 @@ export function showReadOnlyUI(context: vscode.ExtensionContext): void { export async function activate(context: vscode.ExtensionContext) { // ==================== CONFIG ==================== config.activate(context); - let configuration = config.getConfig(); + const configuration = config.getConfig(); // ==================== DATABASE ==================== // hasWriteAccess will be false if another instance has the lock @@ -75,7 +77,7 @@ export async function activate(context: vscode.ExtensionContext) { "achievements.enable", () => { config.enableExtension(); - } + }, ); context.subscriptions.push(enableCommand); @@ -85,9 +87,9 @@ export async function activate(context: vscode.ExtensionContext) { () => { vscode.commands.executeCommand( "workbench.action.openSettings", - "@ext:boxboxjason.achievements" + "@ext:boxboxjason.achievements", ); - } + }, ); context.subscriptions.push(configurationCommand); @@ -112,10 +114,10 @@ export async function activate(context: vscode.ExtensionContext) { currentPanel = undefined; }, null, - context.subscriptions + context.subscriptions, ); } - } + }, ); context.subscriptions.push(showAchievementsCommand); diff --git a/src/listeners/awarder.ts b/src/listeners/awarder.ts index 4c4ad19..335dea4 100644 --- a/src/listeners/awarder.ts +++ b/src/listeners/awarder.ts @@ -25,13 +25,19 @@ export async function awardAchievement(achievement: { }): Promise { const message = `Achievement unlocked: ${achievement.title} (${achievement.exp} exp)`; if (config.notificationsEnabled()) { - vscode.window + void vscode.window .showInformationMessage(`🏆 ${message}`, "Browse Achievements") - .then((selection) => { - if (selection === "Browse Achievements") { - vscode.commands.executeCommand("achievements.show"); - } - }); + .then( + (selection) => { + if (selection === "Browse Achievements") { + return vscode.commands.executeCommand("achievements.show"); + } + return undefined; + }, + (error: unknown) => { + logger.error(error); + }, + ); } await Progression.addValue({ name: constants.criteria.EXP }, achievement.exp); logger.info(message); diff --git a/src/listeners/debug.ts b/src/listeners/debug.ts index bf42c47..d6d777c 100644 --- a/src/listeners/debug.ts +++ b/src/listeners/debug.ts @@ -29,23 +29,23 @@ export namespace debugListeners { logger.info("Starting debug events listeners"); vscode.debug.onDidStartDebugSession( - async (event: vscode.DebugSession) => { + async (_event: vscode.DebugSession) => { await ProgressionController.increaseProgression( - constants.criteria.DEBUGGER_SESSIONS + constants.criteria.DEBUGGER_SESSIONS, ); }, null, - context.subscriptions + context.subscriptions, ); vscode.debug.onDidChangeBreakpoints( async (event: vscode.BreakpointsChangeEvent) => { for (const _ of event.added) { await ProgressionController.increaseProgression( - constants.criteria.BREAKPOINTS + constants.criteria.BREAKPOINTS, ); } - } + }, ); logger.debug("Debug listeners activated"); diff --git a/src/listeners/extensions.ts b/src/listeners/extensions.ts index 3f7e394..522cad4 100644 --- a/src/listeners/extensions.ts +++ b/src/listeners/extensions.ts @@ -30,19 +30,17 @@ export namespace extensionsListeners { await ProgressionController.updateProgression( constants.criteria.EXTENSIONS_INSTALLED, extensionCount, - true + true, ); - const themesExtensionsCount = vscode.extensions.all.filter( - (extension) => { - const contributes = extension.packageJSON.contributes; - return contributes?.themes; - } - ).length; + const themesExtensionsCount = vscode.extensions.all.filter((extension) => { + const contributes = extension.packageJSON.contributes; + return contributes?.themes; + }).length; await ProgressionController.updateProgression( constants.criteria.THEMES_INSTALLED, themesExtensionsCount, - true + true, ); } @@ -53,9 +51,11 @@ export namespace extensionsListeners { * @param {vscode.ColorTheme} event - The theme change event * @returns {Promise} */ - export async function handleThemeChange(event: vscode.ColorTheme): Promise { + export async function handleThemeChange( + _event: vscode.ColorTheme, + ): Promise { await ProgressionController.increaseProgression( - constants.criteria.THEME_CHANGED + constants.criteria.THEME_CHANGED, ); } @@ -72,19 +72,19 @@ export namespace extensionsListeners { vscode.extensions.onDidChange( checkExtensions, null, - context.subscriptions + context.subscriptions, ); vscode.window.onDidChangeActiveColorTheme( handleThemeChange, null, - context.subscriptions + context.subscriptions, ); logger.debug("Extensions listeners activated"); // Check the total number of installed extensions at the boot - checkExtensions().catch((err) => logger.error(err)); + checkExtensions().catch((err: unknown) => logger.error(err)); } else { logger.info("Extensions events listeners are disabled"); } diff --git a/src/listeners/files.ts b/src/listeners/files.ts index 09a277a..ce3af91 100644 --- a/src/listeners/files.ts +++ b/src/listeners/files.ts @@ -278,7 +278,7 @@ export namespace fileListeners { return 0; } - let fileErrorCounts = new Map(); + const fileErrorCounts = new Map(); let errorCounterFree = true; export async function handleDiagnosticChangedEvent( diff --git a/src/listeners/git.ts b/src/listeners/git.ts index 097992c..be984f8 100644 --- a/src/listeners/git.ts +++ b/src/listeners/git.ts @@ -28,45 +28,39 @@ export namespace gitListeners { if (config.isListenerEnabled(constants.listeners.GIT)) { logger.info("Starting git events listeners"); - const gitExtension = vscode.extensions.getExtension("vscode.git") - ?.exports; + const gitExtension = + vscode.extensions.getExtension("vscode.git")?.exports; if (!gitExtension) { logger.error( - "Git extension not found, git listeners will not be created" + "Git extension not found, git listeners will not be created", ); return; } const gitAPI = gitExtension.getAPI(1); - // Handle current workspace repositories commits + // Handle current workspace repositories commits for (const repository of gitAPI.repositories) { - repository.onDidCommit( - handleCommit, - null, - context.subscriptions - ); + repository.onDidCommit(handleCommit, null, context.subscriptions); } // Handle new repositories commits gitAPI.onDidOpenRepository( - (repository: any) => { - repository.onDidCommit( - handleCommit, - null, - context.subscriptions - ); + (repository: { + onDidCommit: ( + handler: () => Promise, + thisArg: null, + disposables: vscode.Disposable[], + ) => void; + }) => { + repository.onDidCommit(handleCommit, null, context.subscriptions); }, null, - context.subscriptions + context.subscriptions, ); // Handle push event - gitAPI.onDidPublish( - handlePublish, - null, - context.subscriptions - ); + gitAPI.onDidPublish(handlePublish, null, context.subscriptions); logger.debug("Git listeners activated"); } else { @@ -75,14 +69,10 @@ export namespace gitListeners { } export async function handleCommit() { - await ProgressionController.increaseProgression( - constants.criteria.COMMITS - ); + await ProgressionController.increaseProgression(constants.criteria.COMMITS); } export async function handlePublish() { - await ProgressionController.increaseProgression( - constants.criteria.PUSHES - ); + await ProgressionController.increaseProgression(constants.criteria.PUSHES); } } diff --git a/src/test/connection-streak.test.ts b/src/test/connection-streak.test.ts index b76ec30..82a7e35 100644 --- a/src/test/connection-streak.test.ts +++ b/src/test/connection-streak.test.ts @@ -143,7 +143,7 @@ suite("Connection Streak Test Suite", () => { mockDate("2023-01-01T12:00:00Z"); // First update - let session = await DailySession.getOrCreate("2023-01-01"); + const session = await DailySession.getOrCreate("2023-01-01"); await session.increase(100); await TimeSpentController.updateConnectionStreak(); diff --git a/src/test/database.test.ts b/src/test/database.test.ts index d4459bf..50999da 100644 --- a/src/test/database.test.ts +++ b/src/test/database.test.ts @@ -51,12 +51,20 @@ suite("Database Model Test Suite", () => { db.run("INSERT INTO test (name) VALUES (?)", ["test1"]); db.run("INSERT INTO test (name) VALUES (?)", ["test2"]); - const all = db_model.getAll(db, "SELECT * FROM test"); + const all = db_model.getAll<{ id: number; name: string }>( + db, + "SELECT * FROM test", + ); assert.strictEqual(all.length, 2); assert.strictEqual(all[0].name, "test1"); assert.strictEqual(all[1].name, "test2"); - const one = db_model.get(db, "SELECT * FROM test WHERE id = ?", [1]); + const one = db_model.get<{ id: number; name: string }>( + db, + "SELECT * FROM test WHERE id = ?", + [1], + ); + assert.ok(one, "Expected one row from test query"); assert.strictEqual(one.name, "test1"); }); @@ -73,7 +81,7 @@ suite("Database Model Test Suite", () => { assert.strictEqual( isLocked, false, - "Lock should be released after deactivate" + "Lock should be released after deactivate", ); }); }); diff --git a/src/test/extension.ui.test.ts b/src/test/extension.ui.test.ts index 6a49aa3..fd822c8 100644 --- a/src/test/extension.ui.test.ts +++ b/src/test/extension.ui.test.ts @@ -23,7 +23,7 @@ suite("Extension UI Test Suite", () => { let called = false; (vscode.window as any).showWarningMessage = ( msg: string, - ...items: any[] + ..._items: any[] ) => { called = true; assert.ok(msg.includes("read-only"), "Message should mention read-only"); @@ -42,7 +42,7 @@ suite("Extension UI Test Suite", () => { (s: any) => s && typeof s.text === "string" && - s.text.includes("Achievements (read-only)") + s.text.includes("Achievements (read-only)"), ); assert.ok(found, "A status bar item should be present in subscriptions"); }); diff --git a/src/test/listeners/extensions.test.ts b/src/test/listeners/extensions.test.ts index b1ae058..b628c92 100644 --- a/src/test/listeners/extensions.test.ts +++ b/src/test/listeners/extensions.test.ts @@ -1,59 +1,65 @@ -import * as assert from 'node:assert'; -import * as vscode from 'vscode'; -import { extensionsListeners } from '../../listeners/extensions'; -import { ProgressionController } from '../../database/controller/progressions'; -import { constants } from '../../constants'; -import { config } from '../../config/config'; +import * as assert from "node:assert"; +import * as vscode from "vscode"; +import { extensionsListeners } from "../../listeners/extensions"; +import { ProgressionController } from "../../database/controller/progressions"; +import { constants } from "../../constants"; +import { config } from "../../config/config"; -suite('Extensions Listeners Test Suite', () => { - test('activate should register listeners', () => { - const originalIsListenerEnabled = config.isListenerEnabled; - config.isListenerEnabled = () => true; +suite("Extensions Listeners Test Suite", () => { + test("activate should register listeners", () => { + const originalIsListenerEnabled = config.isListenerEnabled; + config.isListenerEnabled = () => true; - const context = { subscriptions: [] } as unknown as vscode.ExtensionContext; + const context = { subscriptions: [] } as unknown as vscode.ExtensionContext; - try { - extensionsListeners.activate(context); - // If no error, it passed. - // We can't easily verify listeners were registered without mocking vscode. - // But this covers the activate function lines. - } finally { - config.isListenerEnabled = originalIsListenerEnabled; - } - }); + try { + extensionsListeners.activate(context); + // If no error, it passed. + // We can't easily verify listeners were registered without mocking vscode. + // But this covers the activate function lines. + } finally { + config.isListenerEnabled = originalIsListenerEnabled; + } + }); - test('checkExtensions should update EXTENSIONS_INSTALLED and THEMES_INSTALLED', async () => { - let updatedCriteria: string[] = []; - const originalUpdate = ProgressionController.updateProgression; - ProgressionController.updateProgression = async (criteria: string, value: string | number | boolean | Date, absolute?: boolean) => { - updatedCriteria.push(criteria); - }; + test("checkExtensions should update EXTENSIONS_INSTALLED and THEMES_INSTALLED", async () => { + const updatedCriteria: string[] = []; + const originalUpdate = ProgressionController.updateProgression; + ProgressionController.updateProgression = async ( + criteria: string, + _value: string | number | boolean | Date, + _absolute?: boolean, + ) => { + updatedCriteria.push(criteria); + }; - try { - await extensionsListeners.checkExtensions(); - assert.ok(updatedCriteria.includes(constants.criteria.EXTENSIONS_INSTALLED)); - assert.ok(updatedCriteria.includes(constants.criteria.THEMES_INSTALLED)); - } finally { - ProgressionController.updateProgression = originalUpdate; - } - }); + try { + await extensionsListeners.checkExtensions(); + assert.ok( + updatedCriteria.includes(constants.criteria.EXTENSIONS_INSTALLED), + ); + assert.ok(updatedCriteria.includes(constants.criteria.THEMES_INSTALLED)); + } finally { + ProgressionController.updateProgression = originalUpdate; + } + }); - test('handleThemeChange should increase THEME_CHANGED', async () => { - let increasedCriteria: string | undefined; - const originalIncrease = ProgressionController.increaseProgression; - ProgressionController.increaseProgression = async (criteria: string) => { - if (criteria === constants.criteria.THEME_CHANGED) { - increasedCriteria = criteria; - } - }; + test("handleThemeChange should increase THEME_CHANGED", async () => { + let increasedCriteria: string | undefined; + const originalIncrease = ProgressionController.increaseProgression; + ProgressionController.increaseProgression = async (criteria: string) => { + if (criteria === constants.criteria.THEME_CHANGED) { + increasedCriteria = criteria; + } + }; - try { - // Mock event - const event = { kind: vscode.ColorThemeKind.Dark } as vscode.ColorTheme; - await extensionsListeners.handleThemeChange(event); - assert.strictEqual(increasedCriteria, constants.criteria.THEME_CHANGED); - } finally { - ProgressionController.increaseProgression = originalIncrease; - } - }); + try { + // Mock event + const event = { kind: vscode.ColorThemeKind.Dark } as vscode.ColorTheme; + await extensionsListeners.handleThemeChange(event); + assert.strictEqual(increasedCriteria, constants.criteria.THEME_CHANGED); + } finally { + ProgressionController.increaseProgression = originalIncrease; + } + }); }); diff --git a/src/test/listeners/files.test.ts b/src/test/listeners/files.test.ts index 95d3274..7126578 100644 --- a/src/test/listeners/files.test.ts +++ b/src/test/listeners/files.test.ts @@ -26,7 +26,7 @@ suite("File Listeners Test Suite", () => { fs.writeFileSync(testFile, "content"); const uri = vscode.Uri.file(testFile); - let increasedCriteria: string[] = []; + const increasedCriteria: string[] = []; const originalIncrease = ProgressionController.increaseProgression; ProgressionController.increaseProgression = async (criteria: string) => { increasedCriteria.push(criteria); @@ -154,7 +154,7 @@ suite("File Listeners Test Suite", () => { ], }; - let calls: Array<{ criteria: string; amount: number | string }> = []; + const calls: Array<{ criteria: string; amount: number | string }> = []; const originalIncrease = ProgressionController.increaseProgression; ProgressionController.increaseProgression = async ( criteria: string, diff --git a/src/test/runTest.ts b/src/test/runTest.ts index fcee2af..5731d90 100644 --- a/src/test/runTest.ts +++ b/src/test/runTest.ts @@ -1,22 +1,22 @@ -import * as path from 'node:path'; -import { runTests } from '@vscode/test-electron'; +import * as path from "node:path"; +import { runTests } from "@vscode/test-electron"; async function main() { - try { - // The folder containing the Extension Manifest package.json - // Passed to `--extensionDevelopmentPath` - const extensionDevelopmentPath = path.resolve(__dirname, '../../'); + try { + // The folder containing the Extension Manifest package.json + // Passed to `--extensionDevelopmentPath` + const extensionDevelopmentPath = path.resolve(__dirname, "../../"); - // The path to test runner - // Passed to --extensionTestsPath - const extensionTestsPath = path.resolve(__dirname, './index'); + // The path to test runner + // Passed to --extensionTestsPath + const extensionTestsPath = path.resolve(__dirname, "./index"); - // Download VS Code, unzip it and run the integration test - await runTests({ extensionDevelopmentPath, extensionTestsPath }); - } catch (err) { - console.error('Failed to run tests', err); - process.exit(1); - } + // Download VS Code, unzip it and run the integration test + await runTests({ extensionDevelopmentPath, extensionTestsPath }); + } catch (err) { + console.error("Failed to run tests", err); + process.exit(1); + } } -main(); +void main(); diff --git a/src/test/utils.ts b/src/test/utils.ts index f0f2dbc..8fe38af 100644 --- a/src/test/utils.ts +++ b/src/test/utils.ts @@ -1,66 +1,77 @@ -import * as vscode from 'vscode'; -import * as path from 'node:path'; -import * as os from 'node:os'; -import * as fs from 'node:fs'; +import * as vscode from "vscode"; +import * as path from "node:path"; +import * as os from "node:os"; +import * as fs from "node:fs"; export const getMockContext = (): vscode.ExtensionContext => { - // Assuming the tests are running from dist/test - const extensionPath = path.resolve(__dirname, '../../'); - const storagePath = path.join(os.tmpdir(), 'achievements-test-storage-' + Math.random().toString(36).substring(7)); + // Assuming the tests are running from dist/test + const extensionPath = path.resolve(__dirname, "../../"); + const storagePath = path.join( + os.tmpdir(), + "achievements-test-storage-" + Math.random().toString(36).substring(7), + ); - if (!fs.existsSync(storagePath)) { - fs.mkdirSync(storagePath, { recursive: true }); - } + if (!fs.existsSync(storagePath)) { + fs.mkdirSync(storagePath, { recursive: true }); + } - return { - subscriptions: [], - workspaceState: { - get: () => undefined, - update: () => Promise.resolve(), - keys: () => [] - }, - globalState: { - get: () => undefined, - update: () => Promise.resolve(), - keys: () => [], - setKeysForSync: () => {} - }, - extensionPath: extensionPath, - storageUri: vscode.Uri.file(storagePath), - globalStorageUri: vscode.Uri.file(storagePath), - logUri: vscode.Uri.file(path.join(storagePath, 'log')), - extensionUri: vscode.Uri.file(extensionPath), - environmentVariableCollection: {} as any, - extensionMode: vscode.ExtensionMode.Test, - asAbsolutePath: (relativePath: string) => path.join(extensionPath, relativePath), - storagePath: storagePath, - globalStoragePath: storagePath, - logPath: path.join(storagePath, 'log'), - secrets: { - get: () => Promise.resolve(undefined), - store: () => Promise.resolve(), - delete: () => Promise.resolve(), - onDidChange: new vscode.EventEmitter().event - }, - extension: { - id: 'boxboxjason.achievements', - extensionUri: vscode.Uri.file(extensionPath), - extensionPath: extensionPath, - isActive: true, - packageJSON: {}, - exports: undefined, - activate: () => Promise.resolve(), - extensionKind: vscode.ExtensionKind.UI - } - } as unknown as vscode.ExtensionContext; + return { + subscriptions: [], + workspaceState: { + get: () => undefined, + update: () => Promise.resolve(), + keys: () => [], + }, + globalState: { + get: () => undefined, + update: () => Promise.resolve(), + keys: () => [], + setKeysForSync: () => undefined, + }, + extensionPath: extensionPath, + storageUri: vscode.Uri.file(storagePath), + globalStorageUri: vscode.Uri.file(storagePath), + logUri: vscode.Uri.file(path.join(storagePath, "log")), + extensionUri: vscode.Uri.file(extensionPath), + environmentVariableCollection: {} as any, + extensionMode: vscode.ExtensionMode.Test, + asAbsolutePath: (relativePath: string) => + path.join(extensionPath, relativePath), + storagePath: storagePath, + globalStoragePath: storagePath, + logPath: path.join(storagePath, "log"), + secrets: { + get: () => Promise.resolve(undefined), + store: () => Promise.resolve(), + delete: () => Promise.resolve(), + onDidChange: new vscode.EventEmitter() + .event, + }, + extension: { + id: "boxboxjason.achievements", + extensionUri: vscode.Uri.file(extensionPath), + extensionPath: extensionPath, + isActive: true, + packageJSON: {}, + exports: undefined, + activate: () => Promise.resolve(), + extensionKind: vscode.ExtensionKind.UI, + }, + } as unknown as vscode.ExtensionContext; }; export const cleanupMockContext = (context: vscode.ExtensionContext) => { - if (context.globalStorageUri && fs.existsSync(context.globalStorageUri.fsPath)) { - try { - fs.rmSync(context.globalStorageUri.fsPath, { recursive: true, force: true }); - } catch (err) { - console.error(`Failed to cleanup mock context: ${err}`); - } + if ( + context.globalStorageUri && + fs.existsSync(context.globalStorageUri.fsPath) + ) { + try { + fs.rmSync(context.globalStorageUri.fsPath, { + recursive: true, + force: true, + }); + } catch (err) { + console.error(`Failed to cleanup mock context: ${err}`); } + } }; diff --git a/src/utils/logger.ts b/src/utils/logger.ts index af10aed..8f74d3d 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -80,7 +80,7 @@ export namespace logger { * @param {any[]} args - The message to log * @returns void */ - export function debug(...args: any[]) { + export function debug(...args: unknown[]) { if (logLevel <= LOG_LEVELS.DEBUG) { logMessage(LOG_LEVELS_SLUG.DEBUG, ...args); } @@ -95,7 +95,7 @@ export namespace logger { * @param {any[]} args - The message to log * @returns void */ - export function info(...args: any[]) { + export function info(...args: unknown[]) { if (logLevel <= LOG_LEVELS.INFO) { logMessage(LOG_LEVELS_SLUG.INFO, ...args); } @@ -110,7 +110,7 @@ export namespace logger { * @param {any[]} args - The message to log * @returns void */ - export function notify(...args: any[]) { + export function notify(...args: unknown[]) { if (config.notificationsEnabled()) { vscode.window.showInformationMessage(args.join(" ")); } @@ -128,7 +128,7 @@ export namespace logger { * @param {any[]} args - The message to log * @returns void */ - export function warn(...args: any[]) { + export function warn(...args: unknown[]) { if (logLevel <= LOG_LEVELS.WARN) { logMessage(LOG_LEVELS_SLUG.WARN, ...args); } @@ -143,7 +143,7 @@ export namespace logger { * @param {any[]} args - The message to log * @returns void */ - export function error(...args: any[]) { + export function error(...args: unknown[]) { if (logLevel <= LOG_LEVELS.ERROR) { logMessage(LOG_LEVELS_SLUG.ERROR, ...args); vscode.window.showErrorMessage(args.join(" ")); @@ -159,7 +159,7 @@ export namespace logger { * @param {any[]} args - The message to log * @returns void */ - export function fatal(...args: any[]) { + export function fatal(...args: unknown[]) { if (logLevel <= LOG_LEVELS.FATAL) { logMessage(LOG_LEVELS_SLUG.FATAL, ...args); vscode.window.showErrorMessage(args.join(" ")); @@ -177,14 +177,13 @@ export namespace logger { * @param {any[]} args - The message to log * @returns void */ - function logMessage(level: string, ...args: any[]) { + function logMessage(level: string, ...args: unknown[]) { const timestamp = getFormattedTime(); const logMessage = `ACHIEVEMENTS ${timestamp}: ${level}: ${args .map((arg) => formatArg(arg)) .join(" ")}`; outputChannel.appendLine(logMessage); - console.log(logMessage); logToFile(logMessage); } @@ -197,7 +196,7 @@ export namespace logger { * @param {any} * @returns {string} the formatted argument */ - function formatArg(arg: any): string { + function formatArg(arg: unknown): string { if (typeof arg === "object") { try { return JSON.stringify(arg); @@ -227,7 +226,7 @@ export namespace logger { outputChannel.appendLine( `${LOG_LEVELS_SLUG.ERROR}: Failed to write log to file: ${ (error as Error).message - }` + }`, ); } } @@ -251,7 +250,7 @@ export namespace logger { } else { const rotatedLogFilePath = logFilePath.replace( /\.log$/, - `_${Date.now()}.log` + `_${Date.now()}.log`, ); try { fs.renameSync(logFilePath, rotatedLogFilePath); diff --git a/src/utils/types.ts b/src/utils/types.ts index 8db079f..d03998c 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -1,10 +1,11 @@ -export function parseValue(value: any, type: string): any { +export function parseValue(value: unknown, type: string): unknown { try { + const textValue = String(value); switch (type.toLowerCase()) { case "integer": case "number": case "float": { - const number = parseFloat(value); + const number = parseFloat(textValue); return isNaN(number) ? value : number; } case "boolean": @@ -12,14 +13,18 @@ export function parseValue(value: any, type: string): any { value === "1" || value === 1 || value === "true" || value === true ); case "date": - case "datetime": - const date = new Date(value); + case "datetime": { + const date = new Date(textValue); return isNaN(date.getTime()) ? value : date; + } case "json": case "object": case "array": case "map": case "set": { + if (typeof value !== "string") { + return value; + } return JSON.parse(value); } default: diff --git a/src/views/components/AchievementDisplay.tsx b/src/views/components/AchievementDisplay.tsx index 5f2fb71..30b8aeb 100644 --- a/src/views/components/AchievementDisplay.tsx +++ b/src/views/components/AchievementDisplay.tsx @@ -1,12 +1,15 @@ import * as React from 'react'; import { AchievementDict } from '../../database/model/tables/Achievement'; -import { webview } from '../viewconst'; const AchievementDisplay: React.FC = (achievementDict: AchievementDict) => { - const imageUris = (window as any).imageUris || {}; + const imageUris = + (window as Window & { imageUris?: Record }).imageUris || + {}; - const parseDateString = (dateString: string): string => { + const parseDateString = (dateValue: string | Date): string => { + const dateString = + typeof dateValue === 'string' ? dateValue : dateValue.toISOString(); const splitDate = dateString.split('T'); const date = splitDate[0]; const time = splitDate[1].split('.')[0]; @@ -19,7 +22,7 @@ const AchievementDisplay: React.FC = (achievementDict: Achievem { - e.currentTarget.src = imageUris.PUSHEEN_ERROR + e.currentTarget.src = imageUris.PUSHEEN_ERROR; }} alt={`${achievementDict.title} Icon`} style={{ @@ -42,7 +45,7 @@ const AchievementDisplay: React.FC = (achievementDict: Achievem {/* Status */} {achievementDict.achieved && achievementDict.achievedAt - ? `Unlocked: ${parseDateString(achievementDict.achievedAt as any) || 'Date not available'}` + ? `Unlocked: ${parseDateString(achievementDict.achievedAt) || 'Date not available'}` : 'Not Achieved'} diff --git a/src/views/components/AchievementsHolder.tsx b/src/views/components/AchievementsHolder.tsx index e3acbf9..7efb4f5 100644 --- a/src/views/components/AchievementsHolder.tsx +++ b/src/views/components/AchievementsHolder.tsx @@ -5,7 +5,7 @@ import { PostMessage } from '../icons'; import { webview } from '../viewconst'; interface AchievementHolderProps { - filters: Record; + filters: Record; limit: number; } @@ -22,7 +22,7 @@ const AchievementHolder: React.FC = ({ filters, limit }) }, []); useEffect(() => { - (window as any).vscode.postMessage( + window.vscode.postMessage( JSON.stringify({ command: webview.commands.RETRIEVE_ACHIEVEMENTS, data: { count: true, offset, limit, ...filters }, @@ -35,8 +35,9 @@ const AchievementHolder: React.FC = ({ filters, limit }) const data: PostMessage = event.data; if (data.command === webview.commands.DISPLAY_ACHIEVEMENTS) { - setAchievements(data.data.achievements); - setMaxCount(data.data.count); + const payload = data.data as { achievements: Achievement[]; count: number }; + setAchievements(payload.achievements); + setMaxCount(payload.count); } } catch (e) { console.error('Invalid message data:', e); diff --git a/src/views/components/SearchBar.tsx b/src/views/components/SearchBar.tsx index a000cc3..0c3acf0 100644 --- a/src/views/components/SearchBar.tsx +++ b/src/views/components/SearchBar.tsx @@ -3,7 +3,7 @@ import { queries, webview } from '../viewconst'; import { PostMessage } from '../icons'; interface SearchBarProps { - setFilters: React.Dispatch>>; + setFilters: React.Dispatch>>; limit: number; setLimit: React.Dispatch>; } @@ -21,7 +21,7 @@ const SearchBar: React.FC = ({ setFilters, limit, setLimit }) => useEffect(() => { window.addEventListener('message', handleMessage); - (window as any).vscode.postMessage( + window.vscode.postMessage( JSON.stringify({ command: webview.commands.RETRIEVE_ACHIEVEMENTS_FILTERS, }) @@ -49,7 +49,8 @@ const SearchBar: React.FC = ({ setFilters, limit, setLimit }) => const data: PostMessage = event.data; if (data.command === webview.commands.DISPLAY_ACHIEVEMENTS_FILTERS) { - setAvailableLabels(data.data.labels); + const payload = data.data as { labels: string[] }; + setAvailableLabels(payload.labels); } } catch (e) { console.error('Invalid message data:', e); diff --git a/src/views/components/UserStats.tsx b/src/views/components/UserStats.tsx index 9ee1778..262e1a2 100644 --- a/src/views/components/UserStats.tsx +++ b/src/views/components/UserStats.tsx @@ -7,7 +7,7 @@ const UserStats: React.FC = () => { const [totalAchievements, setTotalAchievements] = useState(0); const [totalExp, setTotalExp] = useState(0); const [achievedCount, setAchievedCount] = useState(0); - const [timeSpent, setTimeSpent] = useState({ + const [timeSpent, setTimeSpent] = useState>({ [queries.criteria.DAILY_TIME_SPENT]: 0, [queries.criteria.TWO_WEEKS_TIME_SPENT]: 0, [queries.criteria.MONTHLY_TIME_SPENT]: 0, @@ -18,7 +18,7 @@ const UserStats: React.FC = () => { useEffect(() => { window.addEventListener('message', handleMessage); - (window as any).vscode.postMessage( + window.vscode.postMessage( JSON.stringify({ command: webview.commands.RETRIEVE_PROFILE, }) @@ -33,16 +33,23 @@ const UserStats: React.FC = () => { try { const data: PostMessage = message.data; if (data.command === webview.commands.SET_PROFILE) { - setUsername(data.data.username); - setTotalAchievements(data.data.totalAchievements); - setTotalExp(data.data.totalExp); - setAchievedCount(data.data.achievedCount); - setTimeSpent(data.data.timeSpent); + const payload = data.data as { + username: string; + totalAchievements: number; + totalExp: number; + achievedCount: number; + timeSpent: Record; + }; + setUsername(payload.username); + setTotalAchievements(payload.totalAchievements); + setTotalExp(payload.totalExp); + setAchievedCount(payload.achievedCount); + setTimeSpent(payload.timeSpent); } } catch (error) { console.error('Failed to parse message data: ' + error); } - } + }; return (
@@ -74,7 +81,7 @@ const UserStats: React.FC = () => {
); -} +}; const ProfileBox: React.FC<{ value: string, label: string }> = ({ value, label }) => { return ( @@ -83,6 +90,6 @@ const ProfileBox: React.FC<{ value: string, label: string }> = ({ value, label } {label} ); -} +}; export default UserStats; diff --git a/src/views/icons.ts b/src/views/icons.ts index 8240572..5282710 100644 --- a/src/views/icons.ts +++ b/src/views/icons.ts @@ -4,16 +4,16 @@ import { webview } from "./viewconst"; export interface PostMessage { command: string; - data: any; + data: unknown; } export function getWebviewImageUri( context: vscode.ExtensionContext, webview: vscode.Webview, - relativePath: string + relativePath: string, ): vscode.Uri { const imagePath = vscode.Uri.file( - path.join(context.extensionPath, relativePath) + path.join(context.extensionPath, relativePath), ); return webview.asWebviewUri(imagePath); @@ -21,12 +21,12 @@ export function getWebviewImageUri( export function getPackagedImages( context: vscode.ExtensionContext, - view: vscode.Webview + view: vscode.Webview, ): { [key: string]: string } { const images: { [key: string]: string } = {}; // Merge all flat icons maps - let iconsMap = { + const iconsMap = { ...webview.icons.pusheen, ...webview.icons.achievements.git, ...webview.icons.achievements.terminal, @@ -43,7 +43,7 @@ export function getPackagedImages( images[key] = getWebviewImageUri( context, view, - path.join("assets", ...iconsMap[key]) + path.join("assets", ...iconsMap[key]), ).toString(); } diff --git a/src/views/index.tsx b/src/views/index.tsx index 18f48f4..08446c2 100644 --- a/src/views/index.tsx +++ b/src/views/index.tsx @@ -5,7 +5,9 @@ import AchievementHolder from "./components/AchievementsHolder"; import UserStats from "./components/UserStats"; const App = () => { - const imageUris = (window as any).imageUris || {}; + const imageUris = + (window as Window & { imageUris?: Record }).imageUris || + {}; const [filters, setFilters] = useState({}); const [limit, setLimit] = useState(50); diff --git a/src/views/management.ts b/src/views/management.ts index e805664..0f34191 100644 --- a/src/views/management.ts +++ b/src/views/management.ts @@ -9,10 +9,10 @@ import logger from "../utils/logger"; */ export namespace AchievementsWebview { export function setupAchievementsPanel( - context: vscode.ExtensionContext + context: vscode.ExtensionContext, ): vscode.WebviewPanel { // Create and show the webview panel - let panel: vscode.WebviewPanel | undefined = + const panel: vscode.WebviewPanel | undefined = vscode.window.createWebviewPanel( "achievements", "Achievements", @@ -25,23 +25,23 @@ export namespace AchievementsWebview { vscode.Uri.file(path.join(context.extensionPath, "dist", "style")), vscode.Uri.file(path.join(context.extensionPath, "dist")), ], - } + }, ); panel.webview.html = getDefaultWebviewContentReact(context, panel); // Receive messages from the webview event panel.webview.onDidReceiveMessage( - (message) => { + async (message) => { try { const parsedMessage = JSON.parse(message) as PostMessage; - backendRequests.handleMessage(parsedMessage, panel); + await backendRequests.handleMessage(parsedMessage, panel); } catch (e) { logger.error("Cannot parse message: " + e); } }, undefined, - context.subscriptions + context.subscriptions, ); return panel; @@ -49,10 +49,10 @@ export namespace AchievementsWebview { function getDefaultWebviewContentReact( context: vscode.ExtensionContext, - panel: vscode.WebviewPanel + panel: vscode.WebviewPanel, ): string { - let reactScriptUri = panel.webview.asWebviewUri( - vscode.Uri.file(path.join(__dirname, "webview.js")) + const reactScriptUri = panel.webview.asWebviewUri( + vscode.Uri.file(path.join(__dirname, "webview.js")), ); return ` @@ -61,8 +61,8 @@ export namespace AchievementsWebview { Achievements @@ -70,7 +70,7 @@ export namespace AchievementsWebview { diff --git a/src/views/requests/backend.ts b/src/views/requests/backend.ts index 136d648..a80c68e 100644 --- a/src/views/requests/backend.ts +++ b/src/views/requests/backend.ts @@ -13,11 +13,14 @@ import * as vscode from "vscode"; export namespace backendRequests { export async function handleMessage( message: PostMessage, - panel: vscode.WebviewPanel + panel: vscode.WebviewPanel, ): Promise { switch (message.command) { case webview.commands.RETRIEVE_ACHIEVEMENTS: - await handleAchievementsSelect(message.data, panel); + await handleAchievementsSelect( + (message.data ?? null) as AchievementSelectRequestFilters | null, + panel, + ); break; case webview.commands.RETRIEVE_ACHIEVEMENTS_FILTERS: await handleAchievementsSelectFilters(panel); @@ -35,7 +38,7 @@ export namespace backendRequests { export async function handleAchievementsSelect( filters: AchievementSelectRequestFilters | null, - panel: vscode.WebviewPanel + panel: vscode.WebviewPanel, ): Promise { if (filters) { const achievements = await AchievementController.getAchievements(filters); @@ -49,7 +52,7 @@ export namespace backendRequests { } export async function handleAchievementsSelectFilters( - panel: vscode.WebviewPanel + panel: vscode.WebviewPanel, ): Promise { const filters = await AchievementController.getJsonFilters(); panel.webview.postMessage({ @@ -58,7 +61,9 @@ export namespace backendRequests { }); } - export async function handleProgressionsSelect(panel: vscode.WebviewPanel): Promise { + export async function handleProgressionsSelect( + panel: vscode.WebviewPanel, + ): Promise { const progressions = await ProgressionController.getProgressions(); panel.webview.postMessage({ command: webview.commands.SET_PROGRESSIONS, @@ -66,16 +71,18 @@ export namespace backendRequests { }); } - export async function handleProfileSelect(panel: vscode.WebviewPanel): Promise { - const progressions = await ProgressionController.getProgressions() as { - [key: string]: any; + export async function handleProfileSelect( + panel: vscode.WebviewPanel, + ): Promise { + const progressions = (await ProgressionController.getProgressions()) as { + [key: string]: number; }; panel.webview.postMessage({ command: webview.commands.SET_PROFILE, data: { username: config.getUsername(), timeSpent: TimeSpentController.getTimeSpent(progressions), - ...await Achievement.getAchievementStats(), + ...(await Achievement.getAchievementStats()), totalExp: progressions[constants.criteria.EXP], }, }); diff --git a/src/views/window.d.ts b/src/views/window.d.ts new file mode 100644 index 0000000..da0b10a --- /dev/null +++ b/src/views/window.d.ts @@ -0,0 +1,10 @@ +declare global { + interface Window { + vscode: { + postMessage: (message: string) => void; + }; + imageUris?: Record; + } +} + +export {}; \ No newline at end of file From 4c43519c969d907d177d97aca10ce23ae6c68927 Mon Sep 17 00:00:00 2001 From: BoxBoxJason Date: Sun, 22 Mar 2026 17:06:02 +0100 Subject: [PATCH 3/5] chore: prepare version Signed-off-by: BoxBoxJason --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6feb140..b3daa8c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "achievements", - "version": "0.4.0", + "version": "0.4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "achievements", - "version": "0.4.0", + "version": "0.4.1", "dependencies": { "proper-lockfile": "^4.1.2", "react": "19.2.4", diff --git a/package.json b/package.json index 32fc408..90ce607 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "author": { "name": "BoxBoxJason" }, - "version": "0.4.0", + "version": "0.4.1", "engines": { "vscode": "^1.110.0" }, From 525b4aa25f241f254914db0f0e72a18ad9428d74 Mon Sep 17 00:00:00 2001 From: BoxBoxJason Date: Sun, 22 Mar 2026 17:10:11 +0100 Subject: [PATCH 4/5] ci: legacy peer deps Signed-off-by: BoxBoxJason --- .github/workflows/build.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6500cea..821879b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,7 +27,7 @@ jobs: cache: "npm" - name: Install dependencies - run: npm ci + run: npm ci --legacy-peer-deps - name: Type Check run: npm run check-types diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cbf880e..5dfa98b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,7 +31,7 @@ jobs: cache: "npm" - name: Install dependencies - run: npm ci + run: npm ci --legacy-peer-deps - name: Build run: npm run package From 146c45ae68a91d54aa20b3594f18b1ca43381288 Mon Sep 17 00:00:00 2001 From: BoxBoxJason Date: Sun, 22 Mar 2026 20:35:46 +0100 Subject: [PATCH 5/5] fix: missing lint, type errors Signed-off-by: BoxBoxJason --- eslint.config.mjs | 18 +++ package-lock.json | 156 +++++++++++++++--------- package.json | 18 +-- src/database/controller/progressions.ts | 41 +++++-- src/database/model/model.ts | 6 +- src/extension.ts | 20 +-- src/views/index.tsx | 2 +- 7 files changed, 171 insertions(+), 90 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index bceea92..5239116 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -2,6 +2,8 @@ import eslint from "@eslint/js"; import typescriptEslint from "@typescript-eslint/eslint-plugin"; import tsParser from "@typescript-eslint/parser"; import promisePlugin from "eslint-plugin-promise"; +import reactPlugin from "eslint-plugin-react"; +import reactHooksPlugin from "eslint-plugin-react-hooks"; export default [ // Ignore patterns @@ -19,6 +21,14 @@ export default [ plugins: { "@typescript-eslint": typescriptEslint, promise: promisePlugin, + react: reactPlugin, + "react-hooks": reactHooksPlugin, + }, + + settings: { + react: { + version: "19.2", + }, }, languageOptions: { @@ -130,6 +140,14 @@ export default [ "prefer-const": "warn", "prefer-arrow-callback": "warn", "no-empty-function": "warn", + + // React rules + "react/react-in-jsx-scope": "off", + "react/prop-types": "off", // Using TypeScript for prop validation + "react/no-unescaped-entities": "warn", + "react/display-name": "warn", + "react-hooks/rules-of-hooks": "warn", + "react-hooks/exhaustive-deps": "warn", }, }, diff --git a/package-lock.json b/package-lock.json index b3daa8c..35f4392 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,33 +8,33 @@ "name": "achievements", "version": "0.4.1", "dependencies": { - "proper-lockfile": "^4.1.2", + "proper-lockfile": "4.1.2", "react": "19.2.4", "react-dom": "19.2.4", - "sql.js": "^1.14.1" + "sql.js": "1.14.1" }, "devDependencies": { "@eslint/js": "10.0.1", "@tailwindcss/cli": "4.2.2", "@types/mocha": "10.0.10", "@types/node": "25.5.0", - "@types/proper-lockfile": "^4.1.4", + "@types/proper-lockfile": "4.1.4", "@types/react": "19.2.14", "@types/react-dom": "19.2.3", - "@types/sql.js": "^1.4.10", + "@types/sql.js": "1.4.10", "@types/vscode": "1.110.0", "@typescript-eslint/eslint-plugin": "8.57.1", "@typescript-eslint/parser": "8.57.1", - "@vscode/test-cli": "^0.0.12", + "@vscode/test-cli": "0.0.12", "@vscode/test-electron": "2.5.2", "@vscode/vsce": "3.7.1", "esbuild": "0.27.4", "eslint": "10.1.0", - "eslint-plugin-promise": "^7.2.1", + "eslint-plugin-promise": "7.2.1", "eslint-plugin-react": "7.37.5", - "eslint-plugin-react-hooks": "^4.6.0", - "nyc": "^18.0.0", - "ovsx": "^0.10.9", + "eslint-plugin-react-hooks": "7.0.1", + "nyc": "18.0.0", + "ovsx": "0.10.9", "ts-node": "10.9.2", "typescript": "5.9.3" }, @@ -284,13 +284,6 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -335,16 +328,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -355,13 +338,6 @@ "semver": "bin/semver.js" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, "node_modules/@babel/helper-globals": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", @@ -4426,9 +4402,9 @@ "license": "MIT" }, "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, "license": "MIT" }, @@ -5299,16 +5275,23 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", - "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", + "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, "engines": { - "node": ">=10" + "node": ">=18" }, "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "node_modules/eslint-plugin-react/node_modules/balanced-match": { @@ -6292,6 +6275,23 @@ "he": "bin/he" } }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, "node_modules/hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", @@ -6305,6 +6305,26 @@ "node": ">=10" } }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -7875,16 +7895,13 @@ } }, "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "license": "ISC", "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "yallist": "^3.0.2" } }, "node_modules/magic-string": { @@ -8461,6 +8478,13 @@ "wrap-ansi": "^6.2.0" } }, + "node_modules/nyc/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT" + }, "node_modules/nyc/node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -11498,13 +11522,6 @@ "node": ">=10.12.0" } }, - "node_modules/v8-to-istanbul/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -11866,9 +11883,9 @@ } }, "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, "license": "ISC" }, @@ -12001,6 +12018,29 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } } } } diff --git a/package.json b/package.json index 90ce607..ebe8fbe 100644 --- a/package.json +++ b/package.json @@ -164,31 +164,31 @@ "@tailwindcss/cli": "4.2.2", "@types/mocha": "10.0.10", "@types/node": "25.5.0", - "@types/proper-lockfile": "^4.1.4", + "@types/proper-lockfile": "4.1.4", "@types/react": "19.2.14", "@types/react-dom": "19.2.3", - "@types/sql.js": "^1.4.10", + "@types/sql.js": "1.4.10", "@types/vscode": "1.110.0", "@typescript-eslint/eslint-plugin": "8.57.1", "@typescript-eslint/parser": "8.57.1", - "@vscode/test-cli": "^0.0.12", + "@vscode/test-cli": "0.0.12", "@vscode/test-electron": "2.5.2", "@vscode/vsce": "3.7.1", "esbuild": "0.27.4", "eslint": "10.1.0", - "eslint-plugin-promise": "^7.2.1", + "eslint-plugin-promise": "7.2.1", "eslint-plugin-react": "7.37.5", - "eslint-plugin-react-hooks": "^4.6.0", - "nyc": "^18.0.0", - "ovsx": "^0.10.9", + "eslint-plugin-react-hooks": "7.0.1", + "nyc": "18.0.0", + "ovsx": "0.10.9", "ts-node": "10.9.2", "typescript": "5.9.3" }, "dependencies": { - "proper-lockfile": "^4.1.2", + "proper-lockfile": "4.1.2", "react": "19.2.4", "react-dom": "19.2.4", - "sql.js": "^1.14.1" + "sql.js": "1.14.1" }, "files": [ "dist", diff --git a/src/database/controller/progressions.ts b/src/database/controller/progressions.ts index 5255822..c6cdd68 100644 --- a/src/database/controller/progressions.ts +++ b/src/database/controller/progressions.ts @@ -66,10 +66,16 @@ export namespace ProgressionController { await Progression.achieveCompletedAchievements( updatedProgressionsIds.map((progression) => progression.id), ); - for (const achievement of updatedAchievements) { - // Notify the user of the unlocked achievement - void awardAchievement(achievement); - } + // Award achievements and handle any errors from each award + await Promise.all( + updatedAchievements.map((achievement) => + awardAchievement(achievement).catch((err: unknown) => { + logger.error( + `Failed to award achievement "${achievement.title}": ${String(err)}`, + ); + }), + ), + ); } catch (error) { logger.error( `Failed to increase progression: ${(error as Error).message}`, @@ -102,10 +108,16 @@ export namespace ProgressionController { await Progression.achieveCompletedAchievements( updatedProgressionsIds.map((progression) => progression.id), ); - for (const achievement of updatedAchievements) { - // Notify the user of the unlocked achievement - void awardAchievement(achievement); - } + // Award achievements and handle any errors from each award + await Promise.all( + updatedAchievements.map((achievement) => + awardAchievement(achievement).catch((err: unknown) => { + logger.error( + `Failed to award achievement "${achievement.title}": ${String(err)}`, + ); + }), + ), + ); } catch (error) { logger.error(`Failed to update progression: ${(error as Error).message}`); } @@ -141,9 +153,16 @@ export namespace ProgressionController { if (allUpdatedIds.length > 0) { const updatedAchievements = await Progression.achieveCompletedAchievements(allUpdatedIds); - for (const achievement of updatedAchievements) { - void awardAchievement(achievement); - } + // Award achievements and handle any errors from each award + await Promise.all( + updatedAchievements.map((achievement) => + awardAchievement(achievement).catch((err: unknown) => { + logger.error( + `Failed to award achievement "${achievement.title}": ${String(err)}`, + ); + }), + ), + ); } } catch (error) { logger.error( diff --git a/src/database/model/model.ts b/src/database/model/model.ts index d4072a4..ceb1756 100644 --- a/src/database/model/model.ts +++ b/src/database/model/model.ts @@ -219,12 +219,12 @@ export namespace db_model { } /** - * Execute a query and return all rows as objects. + * Execute a query and return the first row as an object (or null if no rows). * * @param {Database} db The database connection object * @param {string} query The query to execute - * @param {any[]} params The parameters to bind to the query - * @returns {any[]} The result rows + * @param {SqlValue[]} params The parameters to bind to the query + * @returns {T | null} The first result row or null */ export function get( db: Database, diff --git a/src/extension.ts b/src/extension.ts index f821309..1396010 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -26,15 +26,19 @@ export function showReadOnlyUI(context: vscode.ExtensionContext): void { // Show a persistent warning with an action to open settings void (async () => { - const selection = await vscode.window.showWarningMessage( - message, - "Open Settings", - ); - if (selection === "Open Settings") { - await vscode.commands.executeCommand( - "workbench.action.openSettings", - "@ext:boxboxjason.achievements", + try { + const selection = await vscode.window.showWarningMessage( + message, + "Open Settings", ); + if (selection === "Open Settings") { + await vscode.commands.executeCommand( + "workbench.action.openSettings", + "@ext:boxboxjason.achievements", + ); + } + } catch (err) { + logger.error("Failed to show read-only warning UI: " + String(err)); } })(); diff --git a/src/views/index.tsx b/src/views/index.tsx index 08446c2..2cb71c9 100644 --- a/src/views/index.tsx +++ b/src/views/index.tsx @@ -8,7 +8,7 @@ const App = () => { const imageUris = (window as Window & { imageUris?: Record }).imageUris || {}; - const [filters, setFilters] = useState({}); + const [filters, setFilters] = useState>({}); const [limit, setLimit] = useState(50); return (