diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml new file mode 100644 index 000000000..bcd8ef593 --- /dev/null +++ b/.github/workflows/claude.yml @@ -0,0 +1,37 @@ +name: Claude Code + +on: + issue_comment: + types: [created] + pull_request_review_comment: + types: [created] + issues: + types: [opened, assigned] + pull_request_review: + types: [submitted] + +jobs: + claude: + if: | + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || + (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read + issues: read + id-token: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Claude Code + id: claude + uses: anthropics/claude-code-action@beta + with: + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + diff --git a/.gitignore b/.gitignore index dddc42bd7..4aa9fa6cc 100644 --- a/.gitignore +++ b/.gitignore @@ -119,4 +119,5 @@ tmp .nx/workspace-data *.tsbuildinfo - +.cursor/rules/nx-rules.mdc +.github/instructions/nx.instructions.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..cb6541380 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,33 @@ +# Guidelines for Codex + +This repository uses Nx as the task runner. Nx Cloud requires internet access, which is not available in the Codex environment, so **all nx commands must be executed with `NX_NO_CLOUD=true`**. + +## Required checks + +When modifying rule implementations or documentation, run the following commands and ensure they pass (noting the comments that explain what to do if any of these checks fail): + +```bash +pnpm format-check # run pnpm nx format and commit the result if this check fails +pnpm nx sync:check # run pnpm nx sync and commit the result if this check fails +NX_NO_CLOUD=true pnpm nx run-many -t check-rule-docs # run NX_NO_CLOUD=true pnpm nx run-many -t update-rule-docs and commit the result if this check fails +NX_NO_CLOUD=true pnpm nx run-many -t check-rule-lists # run NX_NO_CLOUD=true pnpm nx run-many -t update-rule-lists and commit the result if this check fails +NX_NO_CLOUD=true pnpm nx run-many -t check-rule-configs # run NX_NO_CLOUD=true pnpm nx run-many -t update-rule-configs and commit the result if this check fails +``` + +Additionally, run tests and lints for any affected project. For example, changes to `eslint-plugin-template` require: + +```bash +NX_NO_CLOUD=true pnpm nx test eslint-plugin-template +NX_NO_CLOUD=true pnpm nx lint eslint-plugin-template +``` + +If there are memory issues with jest tests, try passing `--runInBand` to the test command. + +## Commit conventions + +Use [Conventional Commits](https://www.conventionalcommits.org/) for commit messages and PR titles. + +- When a change affects a single project, include its name as the scope: `feat(eslint-plugin-template): add new rule`. +- When multiple projects are affected, omit the scope: `fix: correct lint configuration`. + +By convention, if only updating a single rule within a single project, for example the `alt-text` rule within the `eslint-plugin-template` project, the commit message should be `fix(eslint-plugin-template): [alt-text] description of the change`. diff --git a/CHANGELOG.md b/CHANGELOG.md index b2ceeba88..44f4d6797 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,33 @@ +## 19.5.0 (2025-05-25) + +### πŸš€ Features + +- **builder:** add stats option ([#2453](https://github.com/angular-eslint/angular-eslint/pull/2453)) +- **eslint-plugin:** introduce sort keys in type-decorator rule ([#2187](https://github.com/angular-eslint/angular-eslint/pull/2187)) +- **eslint-plugin-template:** [no-nested-tags] add rule ([#2398](https://github.com/angular-eslint/angular-eslint/pull/2398)) +- **eslint-plugin-template:** add rule prefer-at-empty ([#2352](https://github.com/angular-eslint/angular-eslint/pull/2352)) +- **schematics:** support --skip-install for ng-add ([#2451](https://github.com/angular-eslint/angular-eslint/pull/2451)) + +### 🩹 Fixes + +- update dependency semver to v7.7.2 ([#2421](https://github.com/angular-eslint/angular-eslint/pull/2421)) +- update typescript-eslint packages to v8.32.1 ([#2422](https://github.com/angular-eslint/angular-eslint/pull/2422)) +- update dependency @angular/compiler to v19.2.13 ([#2438](https://github.com/angular-eslint/angular-eslint/pull/2438)) +- update dependency eslint to v9.27.0 ([#2431](https://github.com/angular-eslint/angular-eslint/pull/2431)) +- **builder:** correct option name in flat config error ([#2443](https://github.com/angular-eslint/angular-eslint/pull/2443)) +- **eslint-plugin-template:** [prefer-template-literal] handle parentheses in autofix ([#2418](https://github.com/angular-eslint/angular-eslint/pull/2418)) +- **eslint-plugin-template:** [alt-text] ensure multiple attributes do not cause false negatives ([#2441](https://github.com/angular-eslint/angular-eslint/pull/2441)) +- **eslint-plugin-template:** [cyclomatic-complexity] handle new control flow syntax ([#2447](https://github.com/angular-eslint/angular-eslint/pull/2447)) +- **eslint-plugin-template:** [prefer-at-empty] remove closing brace from @if when no longer needed ([#2450](https://github.com/angular-eslint/angular-eslint/pull/2450)) + +### ❀️ Thank You + +- Alexander von Weiss @sod +- Benjamin SchΓ€ublin +- Dave @reduckted +- Guillaume DROUARD +- James Henry @JamesHenry + ## 19.4.0 (2025-05-08) ### πŸš€ Features diff --git a/docs/CONFIGURING_FLAT_CONFIG.md b/docs/CONFIGURING_FLAT_CONFIG.md index b988977a1..c6cc1db3b 100644 --- a/docs/CONFIGURING_FLAT_CONFIG.md +++ b/docs/CONFIGURING_FLAT_CONFIG.md @@ -192,7 +192,8 @@ module.exports = tseslint.config([ // we already applied the rootConfig above which has them) files: ['**/*.ts'], extends: [prettierRecommended], // here we inherit from the recommended setup from eslint-plugin-prettier for TS - rules: { + rules: {}, + }, { // Any project level overrides or additional rules for HTML files can go here // (we don't need to extend from any angular-eslint configs because diff --git a/docs/MIGRATING_FROM_TSLINT.md b/docs/MIGRATING_FROM_TSLINT.md index 118f78256..c6ce557ad 100644 --- a/docs/MIGRATING_FROM_TSLINT.md +++ b/docs/MIGRATING_FROM_TSLINT.md @@ -42,7 +42,7 @@ If you just have a single project in your workspace you can just run: ng g @angular-eslint/schematics:convert-tslint-to-eslint ``` -If you have a `projects/` directory or similar in your workspace, you will have multiple entries in your `projects` configuration and you will need to chose which one you want to migrate using the `convert-tslint-to-eslint` schematic: +If you have a `projects/` directory or similar in your workspace, you will have multiple entries in your `projects` configuration and you will need to choose which one you want to migrate using the `convert-tslint-to-eslint` schematic: ```sh ng g @angular-eslint/schematics:convert-tslint-to-eslint {{YOUR_PROJECT_NAME_GOES_HERE}} diff --git a/e2e/src/__snapshots__/inline-template-fixer.test.ts.snap b/e2e/src/__snapshots__/inline-template-fixer.test.ts.snap index 92fb75f40..907223b4f 100644 --- a/e2e/src/__snapshots__/inline-template-fixer.test.ts.snap +++ b/e2e/src/__snapshots__/inline-template-fixer.test.ts.snap @@ -22,7 +22,7 @@ exports[`inline-template-fixer should generate the expected inline template fixe "@angular/compiler-cli": "^19.X.X", "@types/jasmine": "~5.1.0", "angular-eslint": "0.0.0-e2e", - "eslint": "^9.26.0", + "eslint": "^9.27.0", "jasmine-core": "~5.6.0", "karma": "~6.4.0", "karma-chrome-launcher": "~3.2.0", @@ -30,6 +30,6 @@ exports[`inline-template-fixer should generate the expected inline template fixe "karma-jasmine": "~5.1.0", "karma-jasmine-html-reporter": "~2.1.0", "typescript": "~5.X.X", - "typescript-eslint": "8.32.0" + "typescript-eslint": "8.32.1" } `; diff --git a/e2e/src/__snapshots__/new-workspace-create-application-false-ng-add-then-project.test.ts.snap b/e2e/src/__snapshots__/new-workspace-create-application-false-ng-add-then-project.test.ts.snap index 63b0418df..9df6244be 100644 --- a/e2e/src/__snapshots__/new-workspace-create-application-false-ng-add-then-project.test.ts.snap +++ b/e2e/src/__snapshots__/new-workspace-create-application-false-ng-add-then-project.test.ts.snap @@ -7,7 +7,7 @@ exports[`new-workspace-create-application-false-ng-add-then-project should pass "@angular/compiler-cli": "^19.X.X", "@types/jasmine": "~5.1.0", "angular-eslint": "0.0.0-e2e", - "eslint": "^9.26.0", + "eslint": "^9.27.0", "jasmine-core": "~5.6.0", "karma": "~6.4.0", "karma-chrome-launcher": "~3.2.0", @@ -15,7 +15,7 @@ exports[`new-workspace-create-application-false-ng-add-then-project should pass "karma-jasmine": "~5.1.0", "karma-jasmine-html-reporter": "~2.1.0", "typescript": "~5.X.X", - "typescript-eslint": "8.32.0" + "typescript-eslint": "8.32.1" } `; diff --git a/e2e/src/__snapshots__/new-workspace-create-application-false-project-then-ng-add.test.ts.snap b/e2e/src/__snapshots__/new-workspace-create-application-false-project-then-ng-add.test.ts.snap index b9ee1500d..4212310fb 100644 --- a/e2e/src/__snapshots__/new-workspace-create-application-false-project-then-ng-add.test.ts.snap +++ b/e2e/src/__snapshots__/new-workspace-create-application-false-project-then-ng-add.test.ts.snap @@ -7,7 +7,7 @@ exports[`new-workspace-create-application-false-project-then-ng-add should pass "@angular/compiler-cli": "^19.X.X", "@types/jasmine": "~5.1.0", "angular-eslint": "0.0.0-e2e", - "eslint": "^9.26.0", + "eslint": "^9.27.0", "jasmine-core": "~5.6.0", "karma": "~6.4.0", "karma-chrome-launcher": "~3.2.0", @@ -15,7 +15,7 @@ exports[`new-workspace-create-application-false-project-then-ng-add should pass "karma-jasmine": "~5.1.0", "karma-jasmine-html-reporter": "~2.1.0", "typescript": "~5.X.X", - "typescript-eslint": "8.32.0" + "typescript-eslint": "8.32.1" } `; diff --git a/e2e/src/__snapshots__/new-workspace-type-module.test.ts.snap b/e2e/src/__snapshots__/new-workspace-type-module.test.ts.snap index cffb198ee..717107473 100644 --- a/e2e/src/__snapshots__/new-workspace-type-module.test.ts.snap +++ b/e2e/src/__snapshots__/new-workspace-type-module.test.ts.snap @@ -7,7 +7,7 @@ exports[`new-workspace-type-module should pass linting after creating a new work "@angular/compiler-cli": "^19.X.X", "@types/jasmine": "~5.1.0", "angular-eslint": "0.0.0-e2e", - "eslint": "^9.26.0", + "eslint": "^9.27.0", "jasmine-core": "~5.6.0", "karma": "~6.4.0", "karma-chrome-launcher": "~3.2.0", @@ -16,7 +16,7 @@ exports[`new-workspace-type-module should pass linting after creating a new work "karma-jasmine-html-reporter": "~2.1.0", "ng-packagr": "^19.X.X", "typescript": "~5.X.X", - "typescript-eslint": "8.32.0" + "typescript-eslint": "8.32.1" } `; diff --git a/e2e/src/__snapshots__/new-workspace.test.ts.snap b/e2e/src/__snapshots__/new-workspace.test.ts.snap index 8b66528c8..9296c6367 100644 --- a/e2e/src/__snapshots__/new-workspace.test.ts.snap +++ b/e2e/src/__snapshots__/new-workspace.test.ts.snap @@ -7,7 +7,7 @@ exports[`new-workspace should pass linting after creating a new workspace from s "@angular/compiler-cli": "^19.X.X", "@types/jasmine": "~5.1.0", "angular-eslint": "0.0.0-e2e", - "eslint": "^9.26.0", + "eslint": "^9.27.0", "jasmine-core": "~5.6.0", "karma": "~6.4.0", "karma-chrome-launcher": "~3.2.0", @@ -16,7 +16,7 @@ exports[`new-workspace should pass linting after creating a new workspace from s "karma-jasmine-html-reporter": "~2.1.0", "ng-packagr": "^19.X.X", "typescript": "~5.X.X", - "typescript-eslint": "8.32.0" + "typescript-eslint": "8.32.1" } `; diff --git a/nx.json b/nx.json index 2ee63d848..f702e5e30 100644 --- a/nx.json +++ b/nx.json @@ -1,6 +1,6 @@ { "$schema": "./node_modules/nx/schemas/nx-schema.json", - "nxCloudAccessToken": "NzNkMDZiM2MtMzVlOS00YzVlLWE1MGQtNWZlYzI3MjRkOTRmfHJlYWQ=", + "nxCloudId": "601e8ec60a30c421b31beed9", "plugins": [ { "plugin": "@nx/eslint/plugin", diff --git a/package.json b/package.json index 567b204b5..79939e490 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,9 @@ "private": true, "description": "The tooling which enables ESLint to work with Angular projects", "volta": { - "node": "20.19.1" + "node": "20.19.2" }, - "packageManager": "pnpm@10.10.0", + "packageManager": "pnpm@10.11.0", "contributors": [ "James Henry " ], @@ -48,46 +48,46 @@ ] }, "devDependencies": { - "@angular/cli": "19.2.11", - "@angular/compiler": "19.2.10", + "@angular/cli": "19.2.13", + "@angular/compiler": "19.2.13", "@commitlint/cli": "19.8.1", "@commitlint/config-conventional": "19.8.1", - "@mdn/browser-compat-data": "6.0.12", - "@nx/devkit": "21.0.2", - "@nx/esbuild": "21.0.2", - "@nx/eslint": "21.0.2", - "@nx/eslint-plugin": "21.0.2", - "@nx/jest": "21.0.2", - "@nx/js": "21.0.2", - "@nx/plugin": "21.0.2", - "@nx/workspace": "21.0.2", - "@schematics/angular": "19.2.11", + "@mdn/browser-compat-data": "6.0.17", + "@nx/devkit": "21.1.2", + "@nx/esbuild": "21.1.2", + "@nx/eslint": "21.1.2", + "@nx/eslint-plugin": "21.1.2", + "@nx/jest": "21.1.2", + "@nx/js": "21.1.2", + "@nx/plugin": "21.1.2", + "@nx/workspace": "21.1.2", + "@schematics/angular": "19.2.13", "@swc-node/register": "1.10.10", - "@swc/cli": "0.7.5", - "@swc/core": "1.11.24", + "@swc/cli": "0.7.7", + "@swc/core": "1.11.29", "@swc/helpers": "0.5.17", "@types/eslint": "9.6.1", - "@types/eslint-scope": "3.7.7", + "@types/eslint-scope": "8.3.0", "@types/jest": "29.5.14", - "@types/node": "20.17.45", + "@types/node": "20.17.50", "@types/semver": "^7.5.8", "@types/yargs": "^17.0.33", - "@typescript-eslint/rule-tester": "8.32.0", - "@typescript-eslint/types": "8.32.0", - "@typescript-eslint/utils": "8.32.0", + "@typescript-eslint/rule-tester": "8.32.1", + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/utils": "8.32.1", "cz-conventional-changelog": "3.3.0", "esbuild": "^0.25.0", - "eslint": "9.26.0", - "eslint-config-prettier": "10.1.3", + "eslint": "9.27.0", + "eslint-config-prettier": "10.1.5", "execa": "5.1.1", "husky": "9.1.7", "jest": "29.7.0", "json-schema-to-typescript": "15.0.4", "json-schema-traverse": "1.0.0", "jsonc-eslint-parser": "^2.1.0", - "lint-staged": "15.5.2", + "lint-staged": "16.0.0", "ncp": "2.0.0", - "nx": "21.0.2", + "nx": "21.1.2", "picocolors": "1.1.1", "prettier": "3.5.3", "prettier-v2-for-jest-inline-snapshots": "npm:prettier@^2", @@ -98,7 +98,7 @@ "tslib": "^2.4.1", "tsx": "^4.7.3", "typescript": "5.8.3", - "typescript-eslint": "8.32.0", + "typescript-eslint": "8.32.1", "verdaccio": "6.1.2", "yargs": "17.7.2" }, diff --git a/packages/angular-eslint/CHANGELOG.md b/packages/angular-eslint/CHANGELOG.md index ec32a79d7..a5dca3ec5 100644 --- a/packages/angular-eslint/CHANGELOG.md +++ b/packages/angular-eslint/CHANGELOG.md @@ -1,3 +1,17 @@ +## 19.5.0 (2025-05-25) + +### πŸš€ Features + +- **eslint-plugin-template:** add rule prefer-at-empty ([#2352](https://github.com/angular-eslint/angular-eslint/pull/2352)) +- **eslint-plugin:** introduce sort keys in type-decorator rule ([#2187](https://github.com/angular-eslint/angular-eslint/pull/2187)) +- **eslint-plugin-template:** [no-nested-tags] add rule ([#2398](https://github.com/angular-eslint/angular-eslint/pull/2398)) + +### ❀️ Thank You + +- Alexander von Weiss @sod +- Benjamin SchΓ€ublin +- Dave @reduckted + ## 19.4.0 (2025-05-08) ### πŸš€ Features diff --git a/packages/angular-eslint/package.json b/packages/angular-eslint/package.json index 6c876df59..ba76b28e3 100644 --- a/packages/angular-eslint/package.json +++ b/packages/angular-eslint/package.json @@ -1,6 +1,6 @@ { "name": "angular-eslint", - "version": "19.4.0", + "version": "19.5.0", "description": "The tooling which enables ESLint to work with Angular projects", "license": "MIT", "main": "dist/index.js", diff --git a/packages/angular-eslint/src/configs/template-all.ts b/packages/angular-eslint/src/configs/template-all.ts index 8598dd46b..82bd87454 100644 --- a/packages/angular-eslint/src/configs/template-all.ts +++ b/packages/angular-eslint/src/configs/template-all.ts @@ -37,7 +37,9 @@ export default ( '@angular-eslint/template/no-inline-styles': 'error', '@angular-eslint/template/no-interpolation-in-attributes': 'error', '@angular-eslint/template/no-negated-async': 'error', + '@angular-eslint/template/no-nested-tags': 'error', '@angular-eslint/template/no-positive-tabindex': 'error', + '@angular-eslint/template/prefer-at-empty': 'error', '@angular-eslint/template/prefer-contextual-for-variables': 'error', '@angular-eslint/template/prefer-control-flow': 'error', '@angular-eslint/template/prefer-ngsrc': 'error', diff --git a/packages/angular-eslint/src/configs/ts-all.ts b/packages/angular-eslint/src/configs/ts-all.ts index 2be622fa7..fa71b3684 100644 --- a/packages/angular-eslint/src/configs/ts-all.ts +++ b/packages/angular-eslint/src/configs/ts-all.ts @@ -50,6 +50,7 @@ export default ( '@angular-eslint/require-lifecycle-on-prototype': 'error', '@angular-eslint/require-localize-metadata': 'error', '@angular-eslint/runtime-localize': 'error', + '@angular-eslint/sort-keys-in-type-decorator': 'error', '@angular-eslint/sort-lifecycle-methods': 'error', '@angular-eslint/use-component-selector': 'error', '@angular-eslint/use-component-view-encapsulation': 'error', diff --git a/packages/builder/CHANGELOG.md b/packages/builder/CHANGELOG.md index eab9ad61e..540698bae 100644 --- a/packages/builder/CHANGELOG.md +++ b/packages/builder/CHANGELOG.md @@ -1,3 +1,17 @@ +## 19.5.0 (2025-05-25) + +### πŸš€ Features + +- **builder:** add stats option ([#2453](https://github.com/angular-eslint/angular-eslint/pull/2453)) + +### 🩹 Fixes + +- **builder:** correct option name in flat config error ([#2443](https://github.com/angular-eslint/angular-eslint/pull/2443)) + +### ❀️ Thank You + +- James Henry @JamesHenry + ## 19.4.0 (2025-05-08) This was a version bump only for builder to align it with other projects, there were no code changes. diff --git a/packages/builder/README.md b/packages/builder/README.md index cbc81ec1e..f13dc172f 100644 --- a/packages/builder/README.md +++ b/packages/builder/README.md @@ -5,3 +5,13 @@ Please see https://github.com/angular-eslint/angular-eslint for full usage instr The `@angular-eslint/builder` package is a custom Angular CLI builder that allows you to run ESLint on your Angular CLI projects. It wraps the ESLint programmatic node API (https://eslint.org/docs/latest/integrate/nodejs-api) to provide a seamless experience via `ng lint` that is closely equivalent to using the `eslint` CLI directly. + +## Performance statistics + +You can profile rule execution times by enabling ESLint's stats output: + +```bash +ng lint --stats +``` + +This option requires a flat ESLint configuration (`eslint.config.js/ts/mjs`). Using `--stats` with legacy `.eslintrc.*` files will cause an error. diff --git a/packages/builder/package.json b/packages/builder/package.json index 93cf90b9c..37cb62da2 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@angular-eslint/builder", - "version": "19.4.0", + "version": "19.5.0", "description": "Angular CLI builder for ESLint", "license": "MIT", "main": "dist/index.js", diff --git a/packages/builder/src/lint.impl.spec.ts b/packages/builder/src/lint.impl.spec.ts index 8ea1e128c..cf344917a 100644 --- a/packages/builder/src/lint.impl.spec.ts +++ b/packages/builder/src/lint.impl.spec.ts @@ -83,6 +83,7 @@ function createValidRunBuilderOptions( silent: false, ignorePath: null, outputFile: null, + stats: false, noEslintrc: false, rulesdir: [], resolvePluginsRelativeTo: null, @@ -171,6 +172,7 @@ describe('Linter Builder', () => { format: 'stylish', force: false, silent: false, + stats: false, maxWarnings: -1, outputFile: null, ignorePath: null, @@ -195,6 +197,7 @@ describe('Linter Builder', () => { format: 'stylish', force: false, silent: false, + stats: false, useEslintrc: null, maxWarnings: -1, outputFile: null, @@ -233,6 +236,7 @@ describe('Linter Builder', () => { format: 'stylish', force: false, silent: false, + stats: false, useEslintrc: null, maxWarnings: -1, outputFile: null, @@ -271,6 +275,7 @@ describe('Linter Builder', () => { format: 'stylish', force: false, silent: false, + stats: false, useEslintrc: null, maxWarnings: -1, outputFile: null, @@ -309,6 +314,7 @@ describe('Linter Builder', () => { format: 'stylish', force: false, silent: false, + stats: false, useEslintrc: null, maxWarnings: -1, outputFile: null, @@ -760,4 +766,48 @@ describe('Linter Builder', () => { mockFormatter.format(mockReports), ); }); + + it('should pass stats option to resolveAndInstantiateESLint', async () => { + jest.spyOn(fs, 'existsSync').mockImplementation((path: any) => { + if (basename(path) === 'eslint.config.js') { + return true; + } + return false; + }); + + await runBuilder( + createValidRunBuilderOptions({ + stats: true, + }), + ); + + expect(mockResolveAndInstantiateESLint).toHaveBeenCalledTimes(1); + expect(mockResolveAndInstantiateESLint).toHaveBeenCalledWith( + undefined, + { + stats: true, // stats pass through correctly + lintFilePatterns: [], + eslintConfig: null, + exclude: ['excludedFile1'], + fix: true, + quiet: false, + cache: true, + cacheLocation: `cacheLocation1${sep}`, + cacheStrategy: 'content', + format: 'stylish', + force: false, + silent: false, + useEslintrc: null, + maxWarnings: -1, + outputFile: null, + ignorePath: null, + noEslintrc: false, + noConfigLookup: null, + rulesdir: [], + resolvePluginsRelativeTo: null, + reportUnusedDisableDirectives: null, + }, + true, // useFlatConfig + ); + }); }); diff --git a/packages/builder/src/schema.d.ts b/packages/builder/src/schema.d.ts index 3909d9884..f788fdb44 100644 --- a/packages/builder/src/schema.d.ts +++ b/packages/builder/src/schema.d.ts @@ -14,6 +14,7 @@ export interface Schema extends JsonObject { eslintConfig: string | null; ignorePath: string | null; outputFile: string | null; + stats: boolean; noEslintrc: boolean; rulesdir: string[]; resolvePluginsRelativeTo: string | null; diff --git a/packages/builder/src/schema.json b/packages/builder/src/schema.json index c1fa862f2..38b97ff22 100644 --- a/packages/builder/src/schema.json +++ b/packages/builder/src/schema.json @@ -26,6 +26,11 @@ "type": "string", "description": "File to write report to instead of the console." }, + "stats": { + "type": "boolean", + "description": "Output performance statistics for ESLint rules", + "default": false + }, "cacheStrategy": { "type": "string", "description": "Strategy to use for detecting changed files in the cache.", diff --git a/packages/builder/src/utils/eslint-utils.spec.ts b/packages/builder/src/utils/eslint-utils.spec.ts index bad04b7a7..9c591ba9d 100644 --- a/packages/builder/src/utils/eslint-utils.spec.ts +++ b/packages/builder/src/utils/eslint-utils.spec.ts @@ -2,7 +2,12 @@ jest.mock('eslint', () => ({ ESLint: jest.fn(), })); +jest.mock('eslint/use-at-your-own-risk', () => ({ + FlatESLint: jest.fn(), +})); + import { ESLint } from 'eslint'; +import { FlatESLint } from 'eslint/use-at-your-own-risk'; import { resolveAndInstantiateESLint } from './eslint-utils'; describe('eslint-utils', () => { @@ -211,4 +216,35 @@ describe('eslint-utils', () => { ); }); }); + + describe('stats option', () => { + it('should create the ESLint instance with "stats" set to true when using flat config', async () => { + await resolveAndInstantiateESLint( + './eslint.config.js', + { + stats: true, + } as any, + true, + ); + expect(FlatESLint).toHaveBeenCalledWith({ + cache: false, + cacheLocation: undefined, + cacheStrategy: undefined, + errorOnUnmatchedPattern: false, + fix: false, + overrideConfigFile: './eslint.config.js', + stats: true, + }); + }); + + it('should throw when "stats" is used with eslintrc config', async () => { + await expect( + resolveAndInstantiateESLint( + './.eslintrc.json', + { stats: true } as any, + false, + ), + ).rejects.toThrow('The --stats option requires ESLint Flat Config'); + }); + }); }); diff --git a/packages/builder/src/utils/eslint-utils.ts b/packages/builder/src/utils/eslint-utils.ts index 7e75ee105..3d3fe9e45 100644 --- a/packages/builder/src/utils/eslint-utils.ts +++ b/packages/builder/src/utils/eslint-utils.ts @@ -33,6 +33,9 @@ export async function resolveAndInstantiateESLint( options: Schema, useFlatConfig = false, ) { + if (options.stats && !useFlatConfig) { + throw new Error('The --stats option requires ESLint Flat Config'); + } if ( useFlatConfig && eslintConfigPath && @@ -63,6 +66,7 @@ export async function resolveAndInstantiateESLint( }; if (useFlatConfig) { + eslintOptions.stats = !!options.stats; if (typeof options.useEslintrc !== 'undefined') { throw new Error( 'For Flat Config, the `useEslintrc` option is not applicable. See https://eslint.org/docs/latest/use/configure/configuration-files-new', @@ -80,7 +84,7 @@ export async function resolveAndInstantiateESLint( } if (options.reportUnusedDisableDirectives) { throw new Error( - 'For Flat Config, ESLint removed `reportedUnusedDisableDirectives` and so it is not supported as an option. See https://eslint.org/docs/latest/use/configure/configuration-files-new', + 'For Flat Config, ESLint removed `reportUnusedDisableDirectives` and so it is not supported as an option. See https://eslint.org/docs/latest/use/configure/configuration-files-new', ); } diff --git a/packages/bundled-angular-compiler/CHANGELOG.md b/packages/bundled-angular-compiler/CHANGELOG.md index fc51d5781..ea6ecdb1c 100644 --- a/packages/bundled-angular-compiler/CHANGELOG.md +++ b/packages/bundled-angular-compiler/CHANGELOG.md @@ -1,3 +1,7 @@ +## 19.5.0 (2025-05-25) + +This was a version bump only for bundled-angular-compiler to align it with other projects, there were no code changes. + ## 19.4.0 (2025-05-08) This was a version bump only for bundled-angular-compiler to align it with other projects, there were no code changes. diff --git a/packages/bundled-angular-compiler/package.json b/packages/bundled-angular-compiler/package.json index e851e2f9c..1464184e2 100644 --- a/packages/bundled-angular-compiler/package.json +++ b/packages/bundled-angular-compiler/package.json @@ -1,6 +1,6 @@ { "name": "@angular-eslint/bundled-angular-compiler", - "version": "19.4.0", + "version": "19.5.0", "description": "A CJS bundled version of @angular/compiler", "license": "MIT", "main": "dist/index.js", diff --git a/packages/eslint-plugin-template/CHANGELOG.md b/packages/eslint-plugin-template/CHANGELOG.md index c3adb7cd9..4b92162aa 100644 --- a/packages/eslint-plugin-template/CHANGELOG.md +++ b/packages/eslint-plugin-template/CHANGELOG.md @@ -1,3 +1,24 @@ +## 19.5.0 (2025-05-25) + +### πŸš€ Features + +- **eslint-plugin-template:** add rule prefer-at-empty ([#2352](https://github.com/angular-eslint/angular-eslint/pull/2352)) +- **eslint-plugin-template:** [no-nested-tags] add rule ([#2398](https://github.com/angular-eslint/angular-eslint/pull/2398)) + +### 🩹 Fixes + +- **eslint-plugin-template:** [prefer-at-empty] remove closing brace from @if when no longer needed ([#2450](https://github.com/angular-eslint/angular-eslint/pull/2450)) +- **eslint-plugin-template:** [cyclomatic-complexity] handle new control flow syntax ([#2447](https://github.com/angular-eslint/angular-eslint/pull/2447)) +- **eslint-plugin-template:** [alt-text] ensure multiple attributes do not cause false negatives ([#2441](https://github.com/angular-eslint/angular-eslint/pull/2441)) +- **eslint-plugin-template:** [prefer-template-literal] handle parentheses in autofix ([#2418](https://github.com/angular-eslint/angular-eslint/pull/2418)) + +### ❀️ Thank You + +- Alexander von Weiss @sod +- Dave @reduckted +- Guillaume DROUARD +- James Henry @JamesHenry + ## 19.4.0 (2025-05-08) ### πŸš€ Features diff --git a/packages/eslint-plugin-template/README.md b/packages/eslint-plugin-template/README.md index f28cb7178..f49602f07 100644 --- a/packages/eslint-plugin-template/README.md +++ b/packages/eslint-plugin-template/README.md @@ -23,6 +23,7 @@ Please see https://github.com/angular-eslint/angular-eslint for full usage instr | Rule | Description | :white_check_mark: | :wrench: | :bulb: | :accessibility: | | --- | --- | --- | --- | --- | --- | | [`no-duplicate-attributes`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/no-duplicate-attributes.md) | Ensures that there are no duplicate input properties or output event listeners | | | :bulb: | | +| [`no-nested-tags`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/no-nested-tags.md) | Denies nesting of

and tags. | | | | | @@ -61,6 +62,7 @@ Please see https://github.com/angular-eslint/angular-eslint for full usage instr | [`no-interpolation-in-attributes`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/no-interpolation-in-attributes.md) | Ensures that property-binding is used instead of interpolation in attributes. | | | | | | [`no-negated-async`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/no-negated-async.md) | Ensures that async pipe results, as well as values used with the async pipe, are not negated | :white_check_mark: | | :bulb: | | | [`no-positive-tabindex`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/no-positive-tabindex.md) | Ensures that the `tabindex` attribute is not positive | | | :bulb: | | +| [`prefer-at-empty`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/prefer-at-empty.md) | Prefer using `@empty` with `@for` loops instead of a separate `@if` or `@else` block to reduce code and make it easier to read. | | :wrench: | | | | [`prefer-contextual-for-variables`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/prefer-contextual-for-variables.md) | Ensures that contextual variables are used in @for blocks where possible instead of aliasing them. | | :wrench: | | | | [`prefer-control-flow`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/prefer-control-flow.md) | Ensures that the built-in control flow is used. | | | | | | [`prefer-ngsrc`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/prefer-ngsrc.md) | Ensures ngSrc is used instead of src for img elements | | | | | diff --git a/packages/eslint-plugin-template/docs/rules/alt-text.md b/packages/eslint-plugin-template/docs/rules/alt-text.md index 4da71cb96..b94efbf4b 100644 --- a/packages/eslint-plugin-template/docs/rules/alt-text.md +++ b/packages/eslint-plugin-template/docs/rules/alt-text.md @@ -408,6 +408,32 @@ The rule does not have any configuration options. #### βœ… Valid Code +```html + +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/alt-text": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + ```html ``` @@ -486,6 +512,32 @@ The rule does not have any configuration options. #### βœ… Valid Code +```html +desc +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/alt-text": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + ```html ``` @@ -568,6 +620,110 @@ The rule does not have any configuration options. ``` +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/alt-text": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html + +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/alt-text": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html + +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/alt-text": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html + +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/alt-text": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html + +``` +
diff --git a/packages/eslint-plugin-template/docs/rules/cyclomatic-complexity.md b/packages/eslint-plugin-template/docs/rules/cyclomatic-complexity.md index a8e048c67..931e74775 100644 --- a/packages/eslint-plugin-template/docs/rules/cyclomatic-complexity.md +++ b/packages/eslint-plugin-template/docs/rules/cyclomatic-complexity.md @@ -132,6 +132,42 @@ interface Options { ``` +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/template/cyclomatic-complexity": [ + "error", + { + "maxComplexity": 3 + } + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (cond) { + @for (item of items; track item.id) { + @switch (item) { + @case ('a') {} + @default {} + } + } +} +``` +
@@ -241,6 +277,103 @@ interface Options { ``` +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/template/cyclomatic-complexity": [ + "error", + { + "maxComplexity": 1 + } + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +@if (condition) { +

Content
+} @else { +
Other
+} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/template/cyclomatic-complexity": [ + "error", + { + "maxComplexity": 1 + } + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +@for (item of items; track item.id) { + {{ item }} +} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/template/cyclomatic-complexity": [ + "error", + { + "maxComplexity": 3 + } + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +@switch (value) { + @case ('a') { A } + @case ('b') { B } + @default { Default } +} +``` +
diff --git a/packages/eslint-plugin-template/docs/rules/no-nested-tags.md b/packages/eslint-plugin-template/docs/rules/no-nested-tags.md new file mode 100644 index 000000000..63acdb97d --- /dev/null +++ b/packages/eslint-plugin-template/docs/rules/no-nested-tags.md @@ -0,0 +1,231 @@ + + +
+ +# `@angular-eslint/template/no-nested-tags` + +Denies nesting of

and tags. + +- Type: problem + +
+ +## Rule Options + +The rule does not have any configuration options. + +
+ +## Usage Examples + +> The following examples are generated automatically from the actual unit tests within the plugin, so you can be assured that their behavior is accurate based on the current commit. + +
+ +

+❌ - Toggle examples of incorrect code for this rule + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/no-nested-tags": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +
+ ~~~~~~~ +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/no-nested-tags": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +

@if(true) {

}

+ ~~~~~~~ +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/no-nested-tags": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +
+``` + +
+ +
+ +--- + +
+ +
+βœ… - Toggle examples of correct code for this rule + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/no-nested-tags": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html + +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/no-nested-tags": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html + +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/no-nested-tags": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +

+``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/no-nested-tags": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +

+``` + +
+ +
diff --git a/packages/eslint-plugin-template/docs/rules/prefer-at-empty.md b/packages/eslint-plugin-template/docs/rules/prefer-at-empty.md new file mode 100644 index 000000000..d2cf1cd95 --- /dev/null +++ b/packages/eslint-plugin-template/docs/rules/prefer-at-empty.md @@ -0,0 +1,1496 @@ + + +
+ +# `@angular-eslint/template/prefer-at-empty` + +Prefer using `@empty` with `@for` loops instead of a separate `@if` or `@else` block to reduce code and make it easier to read. + +- Type: suggestion +- πŸ”§ Supports autofix (`--fix`) + +
+ +## Rule Options + +The rule does not have any configuration options. + +
+ +## Usage Examples + +> The following examples are generated automatically from the actual unit tests within the plugin, so you can be assured that their behavior is accurate based on the current commit. + +
+ +
+❌ - Toggle examples of incorrect code for this rule + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@for (item of items; track $index) {} +@if (items.length === 0) { +~~~~ + No items +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@for (item of items; track $index) {} +@if (items.length == 0) { +~~~~ + No items +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@for (item of items; track $index) {} +@if (0 === items.length) { +~~~~ + No items +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@for (item of items; track $index) {} +@if (0 == items.length) { +~~~~ + No items +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@for (item of items; track $index) {} +@if (!items.length) { +~~~~ + No items +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (items.length === 0) { +~~~~ + No items +} +@for (item of items; track $index) {} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (items.length == 0) { +~~~~ + No items +} +@for (item of items; track $index) {} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (0 === items.length) { +~~~~ + No items +} +@for (item of items; track $index) {} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (0 == items.length) { +~~~~ + No items +} +@for (item of items; track $index) {} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (!items.length) { +~~~~ + No items +} +@for (item of items; track $index) {} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (items.length > 0) { +~~~~ + @for (item of items; track $index) {} +} @else { + No items +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (items.length !== 0) { +~~~~ + @for (item of items; track $index) {} +} @else { + No items +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (items.length != 0) { +~~~~ + @for (item of items; track $index) {} +} @else { + No items +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (0 < items.length) { +~~~~ + @for (item of items; track $index) {} +} @else { + No items +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (0 !== items.length) { +~~~~ + @for (item of items; track $index) {} +} @else { + No items +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (0 != items.length) { +~~~~ + @for (item of items; track $index) {} +} @else { + No items +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (items.length) { +~~~~ + @for (item of items; track $index) {} +} @else { + No items +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (items.length === 0) { +~~~~ + No items +} @else { + @for (item of items; track $index) {} +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (items.length == 0) { +~~~~ + No items +} @else { + @for (item of items; track $index) {} +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (0 === items.length) { +~~~~ + No items +} @else { + @for (item of items; track $index) {} +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (0 == items.length) { +~~~~ + No items +} @else { + @for (item of items; track $index) {} +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (!items.length) { +~~~~ + No items +} @else { + @for (item of items; track $index) {} +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (items.length > 0) { +~~~~ + @for (item of items; track $index) {} +} +@if (items.length === 0) { + No items +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (items.length === 0) { + No items +} +@if (items.length > 0) { +~~~~ + @for (item of items; track $index) {} +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (items.length > 0) { +~~~~ + @for (item of items; track $index) {} +} @else if (condition) { + Condition is true +} @else { + Condition is false +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@for (item of items; track $index) {} + +@if (items.length === 0) { +~~~~ + No items +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html + +@for (item of items; track $index) {} +  +@if (items.length === 0) { +~~~~ + Not empty +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (items.length === 0) { +~~~~ + Not empty +} +@for (item of items; track $index) {} +@empty { + Existing +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@for (item of items; track $index) {} +@empty { + Existing +} +@if (items.length === 0) { +~~~~ + Not empty +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (items.length > 0) { +~~~~ + @for (item of items; track $index) {} + @empty { + Existing + } +} @else { + Empty +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (items.length === 0) { +~~~~ + Empty +} @else { + @for (item of items; track $index) {} + @empty { + Existing + } +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (items.length === 0) { +~~~~ + Empty +} @else { + @for (item of items; track $index) {} +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (items.length > 0) { +~~~~ + + @for (item of items; track $index) {} + +} @else { + Empty +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +@if (items.length === 0) { +~~~~ + Empty +} @else { + + @for (item of items; track $index) {} + +} +``` + +
+ +
+ +--- + +
+ +
+βœ… - Toggle examples of correct code for this rule + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +@for (item of items; track $index) {} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +@for (item of items; track $index) {} @empty {} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +@if (alpha.length > 0) { + @for (item of beta; track $index) {} +} @else { + No items +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +@if (items.length > 0) { + Items: + @for (item of items; track $index) {} +} @else { + No items +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +@if (items.length === 0) { + No items +} @else { + Items: + @for (item of items; track $index) {} +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +@if (items.length > 0) { + @for (item of items; track $index) {} + Total: {{ $count }} +} @else { + No items +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +@if (items.length === 0) { + No items +} @else { + @for (item of items; track $index) {} + Total: {{ $count }} +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +@if (items.length > 0) { + @for (item of items; track $index) {} +} +@if (items.length > 0) { + Not empty +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +@if (items.length > 0) { + @for (item of items; track $index) {} +} +--- +@if (items.length === 0) { + Not empty +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +@for (item of items; track $index) {} +--- +@if (items.length === 0) { + Not empty +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +@for (item of items; track $index) {} +@if (items.length > 0) { + Not empty +} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +@if (items.length > 0) { + Not empty +} +@for (item of items; track $index) {} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-at-empty": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```html +@if (beta.length > 0) { + @for (item of alpha; track $index) {} + @for (item of beta; track $index) {} +} @else { + Empty +} +``` + +
+ +
diff --git a/packages/eslint-plugin-template/docs/rules/prefer-template-literal.md b/packages/eslint-plugin-template/docs/rules/prefer-template-literal.md index c8f23457f..998a28a25 100644 --- a/packages/eslint-plugin-template/docs/rules/prefer-template-literal.md +++ b/packages/eslint-plugin-template/docs/rules/prefer-template-literal.md @@ -541,6 +541,60 @@ The rule does not have any configuration options. #### ❌ Invalid Code +```html +{{ 'prefix-' + (condition ? 'true' : 'false') }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-template-literal": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +{{ 'prefix-' + ('value' | pipe) }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-template-literal": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + ```html {{ "prefix-" + 42 }} ~~~~~~~~~~~~~~ @@ -730,6 +784,60 @@ The rule does not have any configuration options. #### ❌ Invalid Code +```html +{{ 'prefix-' + (condition ? 'true' : 'false') }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-template-literal": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +{{ 'prefix-' + ('value' | pipe) }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-template-literal": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + ```html {{ `prefix-${value}-suffix` + 42 }} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -919,6 +1027,60 @@ The rule does not have any configuration options. #### ❌ Invalid Code +```html +{{ `prefix-${value}-suffix` + (condition ? 'true' : 'false') }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-template-literal": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +{{ `prefix-${value}-suffix` + ('value' | pipe) }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-template-literal": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + ```html {{ 42 + '-suffix' }} ~~~~~~~~~~~~~~ @@ -1135,6 +1297,60 @@ The rule does not have any configuration options. #### ❌ Invalid Code +```html +{{ (condition ? 'true' : 'false') + '-suffix' }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-template-literal": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +{{ ('value' | pipe) + '-suffix' }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-template-literal": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + ```html {{ 42 + "-suffix" }} ~~~~~~~~~~~~~~ @@ -1351,6 +1567,60 @@ The rule does not have any configuration options. #### ❌ Invalid Code +```html +{{ (condition ? 'true' : 'false') + "-suffix" }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-template-literal": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +{{ ('value' | pipe) + "-suffix" }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-template-literal": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + ```html {{ 42 + `prefix-${value}-suffix` }} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1518,6 +1788,60 @@ The rule does not have any configuration options. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-template-literal": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +{{ (condition ? 'true' : 'false') + `prefix-${value}-suffix` }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/template/prefer-template-literal": [ + "error" + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +{{ ('value' | pipe) + `prefix-${value}-suffix` }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` +
diff --git a/packages/eslint-plugin-template/package.json b/packages/eslint-plugin-template/package.json index 683ff1c6b..710d8d19f 100644 --- a/packages/eslint-plugin-template/package.json +++ b/packages/eslint-plugin-template/package.json @@ -1,6 +1,6 @@ { "name": "@angular-eslint/eslint-plugin-template", - "version": "19.4.0", + "version": "19.5.0", "description": "ESLint plugin for Angular Templates", "license": "MIT", "main": "dist/index.js", diff --git a/packages/eslint-plugin-template/src/configs/all.json b/packages/eslint-plugin-template/src/configs/all.json index 5fcd30d67..794598dec 100644 --- a/packages/eslint-plugin-template/src/configs/all.json +++ b/packages/eslint-plugin-template/src/configs/all.json @@ -23,7 +23,9 @@ "@angular-eslint/template/no-inline-styles": "error", "@angular-eslint/template/no-interpolation-in-attributes": "error", "@angular-eslint/template/no-negated-async": "error", + "@angular-eslint/template/no-nested-tags": "error", "@angular-eslint/template/no-positive-tabindex": "error", + "@angular-eslint/template/prefer-at-empty": "error", "@angular-eslint/template/prefer-contextual-for-variables": "error", "@angular-eslint/template/prefer-control-flow": "error", "@angular-eslint/template/prefer-ngsrc": "error", diff --git a/packages/eslint-plugin-template/src/index.ts b/packages/eslint-plugin-template/src/index.ts index 45db70eb0..ca708a9d7 100644 --- a/packages/eslint-plugin-template/src/index.ts +++ b/packages/eslint-plugin-template/src/index.ts @@ -58,12 +58,18 @@ import noInterpolationInAttributes, { import noNegatedAsync, { RULE_NAME as noNegatedAsyncRuleName, } from './rules/no-negated-async'; +import noNestedTags, { + RULE_NAME as noNestedTagsRuleName, +} from './rules/no-nested-tags'; import noPositiveTabindex, { RULE_NAME as noPositiveTabindexRuleName, } from './rules/no-positive-tabindex'; import preferNgsrc, { RULE_NAME as preferNgsrcRuleName, } from './rules/prefer-ngsrc'; +import preferAtEmpty, { + RULE_NAME as preferAtEmptyRuleName, +} from './rules/prefer-at-empty'; import preferContextualForVariables, { RULE_NAME as preferContextualForVariablesRuleName, } from './rules/prefer-contextual-for-variables'; @@ -117,10 +123,12 @@ export = { [noCallExpressionRuleName]: noCallExpression, [noDistractingElementsRuleName]: noDistractingElements, [noDuplicateAttributesRuleName]: noDuplicateAttributes, + [noNestedTagsRuleName]: noNestedTags, [noInlineStylesRuleName]: noInlineStyles, [noInterpolationInAttributesRuleName]: noInterpolationInAttributes, [noNegatedAsyncRuleName]: noNegatedAsync, [noPositiveTabindexRuleName]: noPositiveTabindex, + [preferAtEmptyRuleName]: preferAtEmpty, [preferContextualForVariablesRuleName]: preferContextualForVariables, [preferControlFlowRuleName]: preferControlFlow, [preferSelfClosingTagsRuleName]: preferSelfClosingTags, diff --git a/packages/eslint-plugin-template/src/rules/alt-text.ts b/packages/eslint-plugin-template/src/rules/alt-text.ts index 7a5ceb791..dee5d1f11 100644 --- a/packages/eslint-plugin-template/src/rules/alt-text.ts +++ b/packages/eslint-plugin-template/src/rules/alt-text.ts @@ -81,8 +81,9 @@ function isValidObjectNode(node: TmplAstElement): boolean { hasAriaLabelAttribute = false; for (const attribute of node.attributes) { - hasTitleAttribute = attribute.name === 'title'; - hasAriaLabelAttribute = isAriaLabel(attribute.name); + hasTitleAttribute = hasTitleAttribute || attribute.name === 'title'; + hasAriaLabelAttribute = + hasAriaLabelAttribute || isAriaLabel(attribute.name); } // Note that we return "early" before looping through `element.inputs`. @@ -96,8 +97,8 @@ function isValidObjectNode(node: TmplAstElement): boolean { hasAriaLabelBinding = false; for (const input of node.inputs) { - hasTitleBinding = input.name === 'title'; - hasAriaLabelBinding = isAriaLabel(input.name); + hasTitleBinding = hasTitleBinding || input.name === 'title'; + hasAriaLabelBinding = hasAriaLabelBinding || isAriaLabel(input.name); } if (hasTitleBinding || hasAriaLabelBinding) { @@ -119,8 +120,9 @@ function isValidAreaNode(node: TmplAstElement): boolean { hasAriaLabelAttribute = false; for (const attribute of node.attributes) { - hasAltAttribute = isAlt(attribute.name); - hasAriaLabelAttribute = isAriaLabel(attribute.name); + hasAltAttribute = hasAltAttribute || isAlt(attribute.name); + hasAriaLabelAttribute = + hasAriaLabelAttribute || isAriaLabel(attribute.name); } // Note that we return "early" before looping through `element.inputs`. @@ -134,8 +136,8 @@ function isValidAreaNode(node: TmplAstElement): boolean { hasAriaLabelBinding = false; for (const input of node.inputs) { - hasAltBinding = isAlt(input.name); - hasAriaLabelBinding = isAriaLabel(input.name); + hasAltBinding = hasAltBinding || isAlt(input.name); + hasAriaLabelBinding = hasAriaLabelBinding || isAriaLabel(input.name); } return hasAltBinding || hasAriaLabelBinding; diff --git a/packages/eslint-plugin-template/src/rules/cyclomatic-complexity.ts b/packages/eslint-plugin-template/src/rules/cyclomatic-complexity.ts index 733e3c9f7..1e7faf280 100644 --- a/packages/eslint-plugin-template/src/rules/cyclomatic-complexity.ts +++ b/packages/eslint-plugin-template/src/rules/cyclomatic-complexity.ts @@ -1,6 +1,11 @@ -import type { +import { + Node, TmplAstBoundAttribute, TmplAstTextAttribute, + TmplAstIfBlock, + TmplAstForLoopBlock, + TmplAstSwitchBlockCase, + ParseSourceSpan, } from '@angular-eslint/bundled-angular-compiler'; import { getTemplateParserServices } from '@angular-eslint/utils'; import { createESLintRule } from '../utils/create-eslint-rule'; @@ -40,21 +45,39 @@ export default createESLintRule({ let totalComplexity = 0; const parserServices = getTemplateParserServices(context); - return { - 'BoundAttribute[name=/^(ngForOf|ngIf|ngSwitchCase)$/], TextAttribute[name="ngSwitchDefault"]'({ - sourceSpan, - }: TmplAstBoundAttribute | TmplAstTextAttribute) { - totalComplexity += 1; + function increment(node: { sourceSpan: ParseSourceSpan }): void { + totalComplexity += 1; + + if (totalComplexity <= maxComplexity) return; - if (totalComplexity <= maxComplexity) return; + const loc = parserServices.convertNodeSourceSpanToLoc(node.sourceSpan); - const loc = parserServices.convertNodeSourceSpanToLoc(sourceSpan); + context.report({ + messageId: 'cyclomaticComplexity', + loc, + data: { maxComplexity, totalComplexity }, + }); + } - context.report({ - messageId: 'cyclomaticComplexity', - loc, - data: { maxComplexity, totalComplexity }, - }); + return { + '*': (node: Node) => { + if ( + node instanceof TmplAstBoundAttribute && + /^(ngForOf|ngIf|ngSwitchCase)$/.test(node.name) + ) { + increment(node); + } else if ( + node instanceof TmplAstTextAttribute && + node.name === 'ngSwitchDefault' + ) { + increment(node); + } else if ( + node instanceof TmplAstIfBlock || + node instanceof TmplAstForLoopBlock || + node instanceof TmplAstSwitchBlockCase + ) { + increment(node); + } }, }; }, diff --git a/packages/eslint-plugin-template/src/rules/no-nested-tags.ts b/packages/eslint-plugin-template/src/rules/no-nested-tags.ts new file mode 100644 index 000000000..a636d18a0 --- /dev/null +++ b/packages/eslint-plugin-template/src/rules/no-nested-tags.ts @@ -0,0 +1,64 @@ +import { TmplAstElement } from '@angular-eslint/bundled-angular-compiler'; +import { getTemplateParserServices } from '@angular-eslint/utils'; +import { createESLintRule } from '../utils/create-eslint-rule'; + +export type Options = []; +export type MessageIds = 'noNestedTags'; +export const RULE_NAME = 'no-nested-tags'; + +type TmplAstElementWithAncestor = TmplAstElement & { + parent?: TmplAstElementWithAncestor; +}; + +export default createESLintRule({ + name: RULE_NAME, + meta: { + type: 'problem', + docs: { + description: 'Denies nesting of

and tags.', + }, + schema: [], + messages: { + noNestedTags: + '<{{tag}}> elements must not be nested! This breaks angular incremental hydration as all browsers will convert "<{{tag}}>1<{{tag}}>23" into "<{{tag}}>1<{{tag}}>23", creating a DOM mismatch between SSR and Angular', + }, + }, + defaultOptions: [], + create(context) { + const parserServices = getTemplateParserServices(context); + + return { + 'Element[name=/^(p|a)$/]'(node: TmplAstElementWithAncestor) { + const hasInvalidNesting = hasAncestorOfSameType(node); + + if (hasInvalidNesting) { + const loc = parserServices.convertElementSourceSpanToLoc( + context, + node, + ); + context.report({ + loc, + messageId: 'noNestedTags', + data: { + tag: node.name, + }, + }); + } + }, + }; + }, +}); + +function hasAncestorOfSameType(node: TmplAstElementWithAncestor) { + let parent = node.parent; + + while (parent) { + if (parent instanceof TmplAstElement && parent.name === node.name) { + return true; + } + + parent = parent.parent; + } + + return false; +} diff --git a/packages/eslint-plugin-template/src/rules/prefer-at-empty.ts b/packages/eslint-plugin-template/src/rules/prefer-at-empty.ts new file mode 100644 index 000000000..589d88ee6 --- /dev/null +++ b/packages/eslint-plugin-template/src/rules/prefer-at-empty.ts @@ -0,0 +1,644 @@ +import { + AST, + ASTWithSource, + Binary, + LiteralPrimitive, + Node, + ParseSourceSpan, + PrefixNot, + PropertyRead, + TmplAstForLoopBlock, + TmplAstIfBlock, + TmplAstIfBlockBranch, + TmplAstText, +} from '@angular-eslint/bundled-angular-compiler'; +import { getTemplateParserServices } from '@angular-eslint/utils'; +import { createESLintRule } from '../utils/create-eslint-rule'; +import { areEquivalentASTs } from '../utils/are-equivalent-asts'; + +export type Options = []; +export type MessageIds = 'preferAtEmpty'; +export const RULE_NAME = 'prefer-at-empty'; + +export default createESLintRule({ + name: RULE_NAME, + meta: { + type: 'suggestion', + fixable: 'code', + docs: { + description: + 'Prefer using `@empty` with `@for` loops instead of a separate `@if` or `@else` block to reduce code and make it easier to read.', + }, + schema: [], + messages: { + preferAtEmpty: 'Prefer using `@for (...) {...} @empty {...}`.', + }, + }, + defaultOptions: [], + create(context) { + const parserServices = getTemplateParserServices(context); + const previousNodeStack: (NodeInfo | undefined)[] = [undefined]; + + function getOnlyForBlock( + node: TmplAstIfBlockBranch, + ): TmplAstForLoopBlock | undefined { + let forBlock: TmplAstForLoopBlock | undefined; + + // Find the only `@for` block in the children, + // ignoring any text nodes that are only whitespace. + for (const child of node.children) { + if (child instanceof TmplAstForLoopBlock) { + if (forBlock) { + return undefined; + } + forBlock = child; + } else if (child instanceof TmplAstText) { + // The `value` property contains the HTML-decoded + // value, so we need to look at the raw source code + // to see if the content is only whitespace. + if ( + context.sourceCode.text + .slice(child.sourceSpan.start.offset, child.sourceSpan.end.offset) + .trim() !== '' + ) { + return undefined; + } + } else { + return undefined; + } + } + + return forBlock; + } + + function checkFor( + forInfo: ForNodeInfo, + previous: NodeInfo | undefined, + ): void { + // If the `@for` block is immediately preceded by an "if empty" + // block for the same collection, then that `@if` block can + // be moved into the `@empty` block. + if (previous?.kind === 'if-empty') { + if (areEquivalentASTs(forInfo.collection, previous.collection)) { + const branch = previous.node.branches[0]; + const branchEnd = branch.endSourceSpan; + context.report({ + loc: parserServices.convertNodeSourceSpanToLoc( + previous.node.nameSpan, + ), + messageId: 'preferAtEmpty', + fix: branchEnd + ? function* (fixer) { + // Remove the entire `@if` block. + yield fixer.removeRange(toRange(previous.node.sourceSpan)); + + if (forInfo.node.empty) { + // There is already an `@empty` block. The contents of the + // `@if` block and the contents of the `@empty` block would + // both be shown in the collection is empty, so we need to + // combine the two blocks. The `@if` block would be rendered + // first, so it needs to be inserted before the existing + // contents of the `@empty` block. + yield fixer.insertTextAfterRange( + [ + forInfo.node.empty.nameSpan.end.offset, + forInfo.node.empty.startSourceSpan.end.offset, + ], + context.sourceCode.text.slice( + branch.startSourceSpan.end.offset, + // The end offset is after the closing `}`, so we + // need to subtract one to ensure it's not included. + branchEnd.end.offset - 1, + ), + ); + } else { + // Take the contents of the `@if` block and move + // it into an `@empty` block after the `@for` block. + yield fixer.insertTextAfterRange( + toRange(forInfo.node.sourceSpan), + ` @empty {${context.sourceCode.text.slice( + branch.startSourceSpan.end.offset, + branchEnd.end.offset, + )}`, + ); + } + } + : undefined, + }); + } + } + } + + function checkIfEmpty( + ifInfo: IfNodeInfo, + previous: NodeInfo | undefined, + ): void { + if (!previous) { + return; + } + + // If the `@if` block is immediately preceded by a `@for` + // block for the same collection, then that `@if` block + // can be moved into the `@empty` block. + switch (previous.kind) { + case 'for': + if (areEquivalentASTs(ifInfo.collection, previous.collection)) { + // The `@if` block can be moved into the `@for` block, + // so report the problem on the `@if` block. + context.report({ + loc: parserServices.convertNodeSourceSpanToLoc( + ifInfo.node.nameSpan, + ), + messageId: 'preferAtEmpty', + fix: function* (fixer) { + if (previous.node.empty?.endSourceSpan) { + // There is already an `@empty` block. The contents of + // the `@empty` block and the `@if` block would both be + // rendered. The `@empty` block would appear first, so + // we need to move the contents of the `@if` block after + // the existing contents of the `@empty` block. This can + // easily be achieved by removing the closing brace of the + // `@empty` block and removing the `@if` statement. + yield fixer.removeRange( + toRange(previous.node.empty.endSourceSpan), + ); + yield fixer.removeRange(toRange(ifInfo.node.startSourceSpan)); + } else { + // There is not already an `@empty` block, so + // we can create one by replacing the entire + // `@if (...) {` segment with `@empty {`. + yield fixer.replaceTextRange( + toRange(ifInfo.node.startSourceSpan), + '@empty {', + ); + } + }, + }); + } + break; + + case 'if-not-empty': + if (areEquivalentASTs(ifInfo.collection, previous.collection)) { + const forBlock = getOnlyForBlock(previous.node.branches[0]); + if ( + forBlock && + areEquivalentASTs(ifInfo.collection, forBlock.expression.ast) + ) { + const previousIfBlockEnd = previous.node.endSourceSpan; + + // The previous `@if` block can be removed and the current `@if` + // block moved into the `@for` block's `@empty` block, so report + // the problem on the previous `@if` block. + context.report({ + loc: parserServices.convertNodeSourceSpanToLoc( + previous.node.nameSpan, + ), + messageId: 'preferAtEmpty', + fix: previousIfBlockEnd + ? (fixer) => [ + // Remove the previous `@if` statement. + fixer.removeRange(toRange(previous.node.startSourceSpan)), + + // Remove the closing brace from the previous `@if` block. + fixer.removeRange(toRange(previousIfBlockEnd)), + + // Take the contents of the current `@if` block and move + // it into the `@empty` block of the previous `@for` block. + fixer.insertTextAfterRange( + toRange(forBlock.sourceSpan), + ` @empty {${context.sourceCode.text.slice( + ifInfo.node.startSourceSpan.end.offset, + // The end offset includes the closing brace. + ifInfo.node.sourceSpan.end.offset, + )}`, + ), + + // Remove the entirety of the current `@if` block. + fixer.removeRange(toRange(ifInfo.node.sourceSpan)), + ] + : undefined, + }); + } + } + } + } + + function checkIfEmptyElse(info: IfNodeInfo): void { + // Look for an `@for` block in the `@else` branch. + const forBlock = getOnlyForBlock(info.node.branches[1]); + if ( + forBlock && + areEquivalentASTs(info.collection, forBlock.expression.ast) + ) { + const ifBranchEnd = info.node.branches[0].endSourceSpan; + + // The contents of the `@if` block can be moved into an + // `@empty` block, so report the problem on the `@if` block. + context.report({ + loc: parserServices.convertNodeSourceSpanToLoc(info.node.nameSpan), + messageId: 'preferAtEmpty', + fix: ifBranchEnd + ? function* (fixer) { + // Remove the entire `@if` branch through to the + // start of the body of the `@else` block. + yield fixer.removeRange([ + info.node.sourceSpan.start.offset, + info.node.branches[1].startSourceSpan.end.offset, + ]); + + // Take the contents of the `@if` branch and move + // it into an `@empty` block after the `@for` block. + const empty = context.sourceCode.text.slice( + info.node.startSourceSpan.end.offset, + ifBranchEnd.start.offset, + ); + if (forBlock.empty?.endSourceSpan) { + // There is already an `@empty` block, but because the `@for` + // block was inside an `@else` block, the `@empty` block + // would never have be rendered, so we can replace its contents. + yield fixer.replaceTextRange( + [ + forBlock.empty.startSourceSpan.end.offset, + forBlock.empty.endSourceSpan.start.offset, + ], + empty, + ); + + // Remove the closing brace from the end of the `@else` block. + if (info.node.endSourceSpan) { + yield fixer.removeRange([ + info.node.endSourceSpan.start.offset, + info.node.endSourceSpan.end.offset, + ]); + } + } else { + // There isn't an existing `@empty` block, so we can create + // one. We don't need to include a closing brace, because + // we can reuse the one from the end of the @`if` block. + yield fixer.insertTextAfterRange( + toRange(forBlock.sourceSpan), + ` @empty {${empty}`, + ); + } + } + : undefined, + }); + } + } + + function checkIfNotEmpty( + ifNotInfo: IfNodeInfo, + previous: NodeInfo | undefined, + ): void { + if (previous?.kind === 'if-empty') { + if (areEquivalentASTs(ifNotInfo.collection, previous.collection)) { + const forBlock = getOnlyForBlock(ifNotInfo.node.branches[0]); + if ( + forBlock && + areEquivalentASTs(ifNotInfo.collection, forBlock.expression.ast) + ) { + // The `@if` block can be removed and the contents of + // the `@else` block moved into an `@empty` block, + // so report the problem on the `@if` block. + context.report({ + loc: parserServices.convertNodeSourceSpanToLoc( + ifNotInfo.node.nameSpan, + ), + messageId: 'preferAtEmpty', + fix: (fixer) => [ + // Remove the entire previous `@if` block. + fixer.removeRange(toRange(previous.node.sourceSpan)), + + // Remove the current `@if` statement. + fixer.removeRange(toRange(ifNotInfo.node.startSourceSpan)), + + // Take the contents of the previous `@if` block and move + // it into the `@empty` block after the `@for` block. + fixer.insertTextAfterRange( + toRange(forBlock.sourceSpan), + ` @empty {${context.sourceCode.text.slice( + previous.node.startSourceSpan.end.offset, + // The end offset is after the closing `}`, so we + // need to subtract one to ensure it gets removed. + previous.node.sourceSpan.end.offset - 1, + )}`, + ), + ], + }); + } + } + } + } + + function checkIfNotEmptyElse(info: IfNodeInfo): void { + const forBlock = getOnlyForBlock(info.node.branches[0]); + if ( + forBlock && + areEquivalentASTs(info.collection, forBlock.expression.ast) + ) { + const ifBranchEnd = info.node.branches[0].endSourceSpan; + const ifEnd = info.node.endSourceSpan; + + // The `@if` block can be removed and the contents of + // the `@else` block moved into an `@empty` block, + // so report the problem on the `@if` block. + context.report({ + loc: parserServices.convertNodeSourceSpanToLoc(info.node.nameSpan), + messageId: 'preferAtEmpty', + fix: + ifBranchEnd && ifEnd + ? function* (fixer) { + if (forBlock.empty) { + // Because the `@for` block was inside an `@if` + // block, the `@empty` block would never be rendered, + // so we can remove it. We could try to replace it, + // but it's easier to remove it and create a new one. + yield fixer.removeRange(toRange(forBlock.empty.sourceSpan)); + } + + // Remove the entire `@if (...) {` segment. + yield fixer.removeRange(toRange(info.node.startSourceSpan)); + + const elseBranch = info.node.branches[1]; + if (elseBranch.expression) { + // The second branch is an `@else if` branch. We + // need to turn it into its own `@if` block. Replace + // the `@else if` text with the start of the `@empty` + // block and the start of the `@if` block, then put + // a closing brace after the original `@if` block + // to close the `@empty` block. + yield fixer.replaceTextRange( + [ + ifBranchEnd.end.offset - 1, + elseBranch.nameSpan.end.offset, + ], + '@empty { @if ', + ); + yield fixer.insertTextAfterRange(toRange(ifEnd), '}'); + } else { + // The second branch is just an `@else` branch, so we + // can replace from end of the `@if` branch through to + // the end of the `@else` statement with `@empty {`. + // The children of the `@else` branch, and the closing + // `}`, will become part of the `@empty` block. + yield fixer.replaceTextRange( + [ + // The end offset is after the closing `}`, so we + // need to subtract one to ensure it gets removed. + ifBranchEnd.end.offset - 1, + elseBranch.startSourceSpan.end.offset, + ], + '@empty {', + ); + } + } + : undefined, + }); + } + } + + return { + // We need to visit `@for` and `@if` blocks, but we + // also need to know if there are any nodes immediately + // before them, so we need to visit all nodes. + '*'(node: Node) { + const current = getNodeInfo(node); + + if (current !== undefined) { + switch (current.kind) { + case 'for': + checkFor(current, previousNodeStack.at(-1)); + break; + + case 'if-empty': + checkIfEmpty(current, previousNodeStack.at(-1)); + break; + + case 'if-empty-else': + checkIfEmptyElse(current); + break; + + case 'if-not-empty': + checkIfNotEmpty(current, previousNodeStack.at(-1)); + break; + + case 'if-not-empty-else': + checkIfNotEmptyElse(current); + break; + } + } + + // Record this current node as the previous node so that + // we can get the info when we look at the next sibling. + previousNodeStack[previousNodeStack.length - 1] = current; + + // We are about to visit the children of this node, + // so push a new "previous node info" onto the stack. + // The previous node of the first child is undefined. + previousNodeStack.push(undefined); + }, + '*:exit'() { + // We've finished visiting the children of this node, + // so pop the "previous node info" off the stack. + previousNodeStack.pop(); + }, + }; + }, +}); + +function getNodeInfo(node: Node): NodeInfo | undefined { + if (node instanceof TmplAstForLoopBlock) { + return { + node, + kind: 'for', + collection: node.expression.ast, + }; + } + + if (node instanceof TmplAstIfBlock) { + if (node.branches.length === 0) { + return undefined; + } + + if (!node.branches[0].expression) { + return undefined; + } + + let collection = getNotEmptyTestCollection(node.branches[0].expression); + if (collection) { + // The block is either: + // + // @if (collection.length > 0) { + // } + // + // or: + // + // @if (collection.length > 0) { + // } @else { + // } + // + // or: + // + // @if (collection.length > 0) { + // } @else if (condition){ + // } + // + // or: + // + // @if (collection.length > 0) { + // } @else if (condition) { + // } @else { + // } + // + // In any case, we treat this as one of the "if not empty" + // nodes, because if there is an `@for` block in the `@if` + // branch, then whatever is in the `@else if` or @else` + // branches, could be moved into the `@empty` block. + return { + node, + kind: node.branches.length === 1 ? 'if-not-empty' : 'if-not-empty-else', + collection, + }; + } + + collection = getEmptyTestCollection(node.branches[0].expression); + if (collection) { + // Unlike the "if not empty" cases, there are only two cases + // that could be considered an "if empty" case: + // + // @if (collection.length === 0) { + // } + // + // or: + // + // @if (collection.length > 0) { + // } @else { + // } + // + // If there is an `@else if`, then whatever is in the `@if` + // branch could not safely be moved into an `@empty` block + // because of the condition in the `@else if` branch. + if (node.branches.length === 1) { + return { + node, + kind: 'if-empty', + collection, + }; + } else if (node.branches.length === 2 && !node.branches[1].expression) { + return { + node, + kind: 'if-empty-else', + collection, + }; + } + } + } + + return undefined; +} + +function getNotEmptyTestCollection(node: AST): AST | undefined { + if (node instanceof ASTWithSource) { + node = node.ast; + } + + if (isLengthRead(node)) { + // @if (collection.length) + return node.receiver; + } + + if (node instanceof Binary) { + if (isLengthRead(node.left)) { + if ( + node.operation === '!==' || + node.operation === '>' || + node.operation === '!=' + ) { + if (isZero(node.right)) { + // @if (collection.length !== 0) + // @if (collection.length > 0) + // @if (collection.length != 0) + return node.left.receiver; + } + } + } else if (isZero(node.left)) { + if ( + node.operation === '!==' || + node.operation === '<' || + node.operation === '!=' + ) { + if (isLengthRead(node.right)) { + // @if (0 !== collection.length) + // @if (0 < collection.length) + // @if (0 != collection.length) + return node.right.receiver; + } + } + } + } + + return undefined; +} + +function getEmptyTestCollection(node: AST): AST | undefined { + if (node instanceof ASTWithSource) { + node = node.ast; + } + + if (node instanceof PrefixNot) { + if (isLengthRead(node.expression)) { + // @if (!collection.length) + return node.expression.receiver; + } + } else if (node instanceof Binary) { + if (isLengthRead(node.left)) { + if (node.operation === '===' || node.operation === '==') { + if (isZero(node.right)) { + // @if (collection.length === 0) + // @if (collection.length == 0) + return node.left.receiver; + } + } + } else if (isZero(node.left)) { + if (node.operation === '===' || node.operation === '==') { + if (isLengthRead(node.right)) { + // @if (0 === collection.length) + // @if (0 == collection.length) + return node.right.receiver; + } + } + } + } + + return undefined; +} + +function isLengthRead(node: AST): node is PropertyRead { + return node instanceof PropertyRead && node.name === 'length'; +} + +function isZero(node: AST): boolean { + return node instanceof LiteralPrimitive && node.value === 0; +} + +function toRange(span: ParseSourceSpan): [number, number] { + return [span.start.offset, span.end.offset]; +} + +interface ForNodeInfo { + readonly node: TmplAstForLoopBlock; + readonly kind: 'for'; + readonly collection: AST; +} + +interface IfNodeInfo { + readonly node: TmplAstIfBlock; + readonly kind: + | 'if-empty' + | 'if-empty-else' + | 'if-not-empty' + | 'if-not-empty-else'; + readonly collection: AST; +} + +type NodeInfo = ForNodeInfo | IfNodeInfo; diff --git a/packages/eslint-plugin-template/src/rules/prefer-template-literal.ts b/packages/eslint-plugin-template/src/rules/prefer-template-literal.ts index 22a896453..e82568357 100644 --- a/packages/eslint-plugin-template/src/rules/prefer-template-literal.ts +++ b/packages/eslint-plugin-template/src/rules/prefer-template-literal.ts @@ -69,6 +69,13 @@ export default createESLintRule({ return '`'; } + function hasParentheses(node: AST): boolean { + const { start, end } = node.sourceSpan; + const text = sourceCode.text.slice(start - 1, end + 1); + + return text.startsWith('(') && text.endsWith(')'); + } + context.report({ loc: { start: sourceCode.getLocFromIndex(start), @@ -88,19 +95,69 @@ export default createESLintRule({ ); } - const fixes = new Array(); + const fixes = Array(); + + const leftHasParentheses = hasParentheses(left); + const rightHasParentheses = hasParentheses(right); + + // Remove the left first parenthesis if it exists + if (leftHasParentheses) { + fixes.push( + fixer.removeRange([ + left.sourceSpan.start - 1, + left.sourceSpan.start, + ]), + ); + } // Fix the left side fixes.push(...getLeftSideFixes(fixer, left)); + // Remove the left last parenthesis if it exists + if (leftHasParentheses) { + fixes.push( + fixer.removeRange([ + left.sourceSpan.end, + left.sourceSpan.end + 1, + ]), + ); + } + // Remove the `+` sign fixes.push( - fixer.removeRange([left.sourceSpan.end, right.sourceSpan.start]), + fixer.removeRange([ + leftHasParentheses + ? left.sourceSpan.end + 1 + : left.sourceSpan.end, + rightHasParentheses + ? right.sourceSpan.start - 1 + : right.sourceSpan.start, + ]), ); + // Remove the right first parenthesis if it exists + if (rightHasParentheses) { + fixes.push( + fixer.removeRange([ + right.sourceSpan.start - 1, + right.sourceSpan.start, + ]), + ); + } + // Fix the right side fixes.push(...getRightSideFixes(fixer, right)); + // Remove the right last parenthesis if it exists + if (rightHasParentheses) { + fixes.push( + fixer.removeRange([ + right.sourceSpan.end, + right.sourceSpan.end + 1, + ]), + ); + } + return fixes; }, }); @@ -115,7 +172,9 @@ function getLeftSideFixes(fixer: RuleFixer, left: AST): readonly RuleFix[] { if (left instanceof TemplateLiteral) { // Remove the end ` sign from the left side return [fixer.removeRange([end - 1, end])]; - } else if (isLiteralPrimitive(left)) { + } + + if (isLiteralPrimitive(left)) { // Transform left side to template literal return [ fixer.replaceTextRange( @@ -123,13 +182,13 @@ function getLeftSideFixes(fixer: RuleFixer, left: AST): readonly RuleFix[] { `\`${getLiteralPrimitiveStringValue(left, '`')}`, ), ]; - } else { - // Transform left side to template literal - return [ - fixer.insertTextBeforeRange([start, end], '`${'), - fixer.insertTextAfterRange([start, end], '}'), - ]; } + + // Transform left side to template literal + return [ + fixer.insertTextBeforeRange([start, end], '`${'), + fixer.insertTextAfterRange([start, end], '}'), + ]; } function getRightSideFixes(fixer: RuleFixer, right: AST): readonly RuleFix[] { @@ -138,7 +197,9 @@ function getRightSideFixes(fixer: RuleFixer, right: AST): readonly RuleFix[] { if (right instanceof TemplateLiteral) { // Remove the start ` sign from the right side return [fixer.removeRange([start, start + 1])]; - } else if (isLiteralPrimitive(right)) { + } + + if (isLiteralPrimitive(right)) { // Transform right side to template literal if it's a string return [ fixer.replaceTextRange( @@ -146,11 +207,11 @@ function getRightSideFixes(fixer: RuleFixer, right: AST): readonly RuleFix[] { `${getLiteralPrimitiveStringValue(right, '`')}\``, ), ]; - } else { - // Transform right side to template literal - return [ - fixer.insertTextBeforeRange([start, end], '${'), - fixer.insertTextAfterRange([start, end], '}`'), - ]; } + + // Transform right side to template literal + return [ + fixer.insertTextBeforeRange([start, end], '${'), + fixer.insertTextAfterRange([start, end], '}`'), + ]; } diff --git a/packages/eslint-plugin-template/tests/rules/alt-text/cases.ts b/packages/eslint-plugin-template/tests/rules/alt-text/cases.ts index 4aac19c28..2859d50c7 100644 --- a/packages/eslint-plugin-template/tests/rules/alt-text/cases.ts +++ b/packages/eslint-plugin-template/tests/rules/alt-text/cases.ts @@ -16,13 +16,19 @@ export const valid: readonly (string | ValidTestCase)[] = [ '', 'Meaningful description', '', + '', '', '', 'This is descriptive!', + 'desc', '', '', '', '', + '', + '', + '', + '', ]; export const invalid: readonly InvalidTestCase[] = [ diff --git a/packages/eslint-plugin-template/tests/rules/cyclomatic-complexity/cases.ts b/packages/eslint-plugin-template/tests/rules/cyclomatic-complexity/cases.ts index 154a9aed0..dbbd7cbcd 100644 --- a/packages/eslint-plugin-template/tests/rules/cyclomatic-complexity/cases.ts +++ b/packages/eslint-plugin-template/tests/rules/cyclomatic-complexity/cases.ts @@ -44,6 +44,34 @@ export const valid: readonly (string | ValidTestCase)[] = [ `, options: [{ maxComplexity: 5 }], }, + { + code: ` + @if (condition) { +
Content
+ } @else { +
Other
+ } + `, + options: [{ maxComplexity: 1 }], + }, + { + code: ` + @for (item of items; track item.id) { + {{ item }} + } + `, + options: [{ maxComplexity: 1 }], + }, + { + code: ` + @switch (value) { + @case ('a') { A } + @case ('b') { B } + @default { Default } + } + `, + options: [{ maxComplexity: 3 }], + }, ]; export const invalid: readonly InvalidTestCase[] = [ @@ -124,4 +152,23 @@ export const invalid: readonly InvalidTestCase[] = [ ], options: [{ maxComplexity: 6 }], }), + { + code: ` + @if (cond) { + @for (item of items; track item.id) { + @switch (item) { + @case ('a') {} + @default {} + } + } + } + `, + options: [{ maxComplexity: 3 }], + errors: [ + { + messageId, + data: { maxComplexity: 3, totalComplexity: 4 }, + }, + ], + }, ]; diff --git a/packages/eslint-plugin-template/tests/rules/no-nested-tags/cases.ts b/packages/eslint-plugin-template/tests/rules/no-nested-tags/cases.ts new file mode 100644 index 000000000..a3f4f0917 --- /dev/null +++ b/packages/eslint-plugin-template/tests/rules/no-nested-tags/cases.ts @@ -0,0 +1,47 @@ +import { convertAnnotatedSourceToFailureCase } from '@angular-eslint/test-utils'; +import type { + InvalidTestCase, + ValidTestCase, +} from '@typescript-eslint/rule-tester'; +import type { MessageIds, Options } from '../../../src/rules/no-nested-tags'; + +const messageId: MessageIds = 'noNestedTags'; + +export const valid: readonly (string | ValidTestCase)[] = [ + '', + '', + '

', + '

', +]; + +export const invalid: readonly InvalidTestCase[] = [ + convertAnnotatedSourceToFailureCase({ + messageId, + description: 'should fail on nested a tag', + annotatedSource: ` + + ~~~~~~~ + `, + data: { tag: 'a' }, + }), + convertAnnotatedSourceToFailureCase({ + messageId, + description: 'should fail on nested p tag', + annotatedSource: ` +

@if(true) {

}

+ ~~~~~~~ + `, + data: { tag: 'p' }, + }), + convertAnnotatedSourceToFailureCase({ + messageId, + description: 'should fail on arbitrary depth', + annotatedSource: ` + ${'
'.repeat(20)} + fail + ~~~~~~~~~~~ + ${'
'.repeat(20)} + `, + data: { tag: 'a' }, + }), +]; diff --git a/packages/eslint-plugin-template/tests/rules/no-nested-tags/spec.ts b/packages/eslint-plugin-template/tests/rules/no-nested-tags/spec.ts new file mode 100644 index 000000000..5a5499ca0 --- /dev/null +++ b/packages/eslint-plugin-template/tests/rules/no-nested-tags/spec.ts @@ -0,0 +1,14 @@ +import { RuleTester } from '@angular-eslint/test-utils'; +import rule, { RULE_NAME } from '../../../src/rules/no-nested-tags'; +import { invalid, valid } from './cases'; + +const ruleTester = new RuleTester({ + languageOptions: { + parser: require('@angular-eslint/template-parser'), + }, +}); + +ruleTester.run(RULE_NAME, rule, { + valid, + invalid, +}); diff --git a/packages/eslint-plugin-template/tests/rules/prefer-at-empty/cases.ts b/packages/eslint-plugin-template/tests/rules/prefer-at-empty/cases.ts new file mode 100644 index 000000000..ed7f4049d --- /dev/null +++ b/packages/eslint-plugin-template/tests/rules/prefer-at-empty/cases.ts @@ -0,0 +1,487 @@ +import { convertAnnotatedSourceToFailureCase } from '@angular-eslint/test-utils'; +import type { + InvalidTestCase, + ValidTestCase, +} from '@typescript-eslint/rule-tester'; +import type { MessageIds, Options } from '../../../src/rules/prefer-at-empty'; + +const messageId: MessageIds = 'preferAtEmpty'; + +export const valid: readonly (string | ValidTestCase)[] = [ + `@for (item of items; track $index) {}`, + `@for (item of items; track $index) {} @empty {}`, + ` + @if (alpha.length > 0) { + @for (item of beta; track $index) {} + } @else { + No items + } + `, + ` + @if (items.length > 0) { + Items: + @for (item of items; track $index) {} + } @else { + No items + } + `, + ` + @if (items.length === 0) { + No items + } @else { + Items: + @for (item of items; track $index) {} + } + `, + ` + @if (items.length > 0) { + @for (item of items; track $index) {} + Total: {{ $count }} + } @else { + No items + } + `, + ` + @if (items.length === 0) { + No items + } @else { + @for (item of items; track $index) {} + Total: {{ $count }} + } + `, + ` + @if (items.length > 0) { + @for (item of items; track $index) {} + } + @if (items.length > 0) { + Not empty + } + `, + ` + @if (items.length > 0) { + @for (item of items; track $index) {} + } + --- + @if (items.length === 0) { + Not empty + } + `, + ` + @for (item of items; track $index) {} + --- + @if (items.length === 0) { + Not empty + } + `, + ` + @for (item of items; track $index) {} + @if (items.length > 0) { + Not empty + } + `, + ` + @if (items.length > 0) { + Not empty + } + @for (item of items; track $index) {} + `, + ` + @if (beta.length > 0) { + @for (item of alpha; track $index) {} + @for (item of beta; track $index) {} + } @else { + Empty + } + `, +]; + +export const invalid: readonly InvalidTestCase[] = [ + ...[ + 'items.length === 0', + 'items.length == 0', + '0 === items.length', + '0 == items.length', + '!items.length', + ].map( + (condition): InvalidTestCase => + convertAnnotatedSourceToFailureCase({ + description: `fails when '@for' block is followed by '@if (${condition})'`, + annotatedSource: ` + @for (item of items; track $index) {} + @if (${condition}) { + ~~~~ + No items + } + `, + messageId, + annotatedOutput: ` + @for (item of items; track $index) {} + @empty { + + No items + } + `, + }), + ), + ...[ + 'items.length === 0', + 'items.length == 0', + '0 === items.length', + '0 == items.length', + '!items.length', + ].map( + (condition): InvalidTestCase => + convertAnnotatedSourceToFailureCase({ + description: `fails when '@for' block is followed by '@if (${condition})'`, + annotatedSource: ` + @if (${condition}) { + ~~~~ + No items + } + @for (item of items; track $index) {} + `, + messageId, + annotatedOutput: ` + + @for (item of items; track $index) {} @empty { + + No items + } + `, + }), + ), + ...[ + 'items.length > 0', + 'items.length !== 0', + 'items.length != 0', + '0 < items.length', + '0 !== items.length', + '0 != items.length', + 'items.length', + ].map( + (condition): InvalidTestCase => + convertAnnotatedSourceToFailureCase({ + description: `fails when '@for' block is in '@if (${condition})' block`, + annotatedSource: ` + @if (${condition}) { + ~~~~ + @for (item of items; track $index) {} + } @else { + No items + } + `, + messageId, + annotatedOutput: ` + + + @for (item of items; track $index) {} + @empty { + No items + } + `, + }), + ), + ...[ + 'items.length === 0', + 'items.length == 0', + '0 === items.length', + '0 == items.length', + '!items.length', + ].map( + (condition): InvalidTestCase => + convertAnnotatedSourceToFailureCase({ + description: `fails when '@for' block is in '@else' block of '@if (${condition})'`, + annotatedSource: ` + @if (${condition}) { + ~~~~ + No items + } @else { + @for (item of items; track $index) {} + } + `, + messageId, + annotatedOutput: ` + + @for (item of items; track $index) {} @empty { + + No items + + } + `, + }), + ), + convertAnnotatedSourceToFailureCase({ + description: `fails when '@for' block is in '@if (items.length > 0)' and is followed by '@if (items.length === 0)'`, + annotatedSource: ` + @if (items.length > 0) { + ~~~~ + @for (item of items; track $index) {} + } + @if (items.length === 0) { + No items + } + `, + messageId, + annotatedOutput: ` + + + @for (item of items; track $index) {} @empty { + No items + } + + + `, + }), + convertAnnotatedSourceToFailureCase({ + description: `fails when '@if (items.length === 0)' is followed by '@if (items.length > 0)' block that contains the '@for' block`, + annotatedSource: ` + @if (items.length === 0) { + No items + } + @if (items.length > 0) { + ~~~~ + @for (item of items; track $index) {} + } + `, + messageId, + annotatedOutput: ` + + + + @for (item of items; track $index) {} @empty { + No items + + } + `, + }), + convertAnnotatedSourceToFailureCase({ + description: `fails when '@for' block inside '@if' block with '@else if' branch`, + annotatedSource: ` + @if (items.length > 0) { + ~~~~ + @for (item of items; track $index) {} + } @else if (condition) { + Condition is true + } @else { + Condition is false + } + `, + messageId, + annotatedOutput: ` + + + @for (item of items; track $index) {} + @empty { @if (condition) { + Condition is true + } @else { + Condition is false + }} + `, + }), + convertAnnotatedSourceToFailureCase({ + description: `fails when comment separates '@for' block and '@if' block`, + annotatedSource: ` + @for (item of items; track $index) {} + + @if (items.length === 0) { + ~~~~ + No items + } + `, + messageId, + annotatedOutput: ` + @for (item of items; track $index) {} + + @empty { + + No items + } + `, + }), + convertAnnotatedSourceToFailureCase({ + description: `fails when '@for' block is separated from '@if' block by  `, + annotatedSource: ` + + @for (item of items; track $index) {} +   + @if (items.length === 0) { + ~~~~ + Not empty + } + `, + messageId, + annotatedOutput: ` + + @for (item of items; track $index) {} +   + @empty { + + Not empty + } + `, + }), + convertAnnotatedSourceToFailureCase({ + description: `'@empty' block already exists and '@if' block is before it`, + annotatedSource: ` + @if (items.length === 0) { + ~~~~ + Not empty + } + @for (item of items; track $index) {} + @empty { + Existing + } + `, + messageId, + annotatedOutput: ` + + @for (item of items; track $index) {} + @empty { + ~~~~ + Not empty + + Existing + } + `, + }), + convertAnnotatedSourceToFailureCase({ + description: `'@empty' block already exists and '@if' block is after it`, + annotatedSource: ` + @for (item of items; track $index) {} + @empty { + Existing + } + @if (items.length === 0) { + ~~~~ + Not empty + } + `, + messageId, + annotatedOutput: ` + @for (item of items; track $index) {} + @empty { + Existing + + + + Not empty + } + `, + }), + convertAnnotatedSourceToFailureCase({ + description: `replaces '@empty' block when '@for' block is inside '@if' block`, + annotatedSource: ` + @if (items.length > 0) { + ~~~~ + @for (item of items; track $index) {} + @empty { + Existing + } + } @else { + Empty + } + `, + messageId, + annotatedOutput: ` + + + @for (item of items; track $index) {} + + @empty { + Empty + } + `, + }), + convertAnnotatedSourceToFailureCase({ + description: `replaces '@empty' block when '@for' block is inside '@else' block`, + annotatedSource: ` + @if (items.length === 0) { + ~~~~ + Empty + } @else { + @for (item of items; track $index) {} + @empty { + Existing + } + } + `, + messageId, + annotatedOutput: ` + + @for (item of items; track $index) {} + @empty { + + Empty + } + + `, + }), + convertAnnotatedSourceToFailureCase({ + description: `adds '@empty' block when '@for' block without '@empty' block is inside '@else' block`, + annotatedSource: ` + @if (items.length === 0) { + ~~~~ + Empty + } @else { + @for (item of items; track $index) {} + } + `, + messageId, + annotatedOutput: ` + + @for (item of items; track $index) {} @empty { + + Empty + + } + `, + }), + convertAnnotatedSourceToFailureCase({ + description: `comments around '@for' block in '@if' block are kept`, + annotatedSource: ` + @if (items.length > 0) { + ~~~~ + + @for (item of items; track $index) {} + + } @else { + Empty + } + `, + messageId, + annotatedOutput: ` + + + + @for (item of items; track $index) {} + + @empty { + Empty + } + `, + }), + convertAnnotatedSourceToFailureCase({ + description: `comments around '@for' block in '@else' block are kept`, + annotatedSource: ` + @if (items.length === 0) { + ~~~~ + Empty + } @else { + + @for (item of items; track $index) {} + + } + `, + messageId, + annotatedOutput: ` + + + @for (item of items; track $index) {} @empty { + + Empty + + + } + `, + }), +]; diff --git a/packages/eslint-plugin-template/tests/rules/prefer-at-empty/spec.ts b/packages/eslint-plugin-template/tests/rules/prefer-at-empty/spec.ts new file mode 100644 index 000000000..60d89180a --- /dev/null +++ b/packages/eslint-plugin-template/tests/rules/prefer-at-empty/spec.ts @@ -0,0 +1,14 @@ +import { RuleTester } from '@angular-eslint/test-utils'; +import rule, { RULE_NAME } from '../../../src/rules/prefer-at-empty'; +import { invalid, valid } from './cases'; + +const ruleTester = new RuleTester({ + languageOptions: { + parser: require('@angular-eslint/template-parser'), + }, +}); + +ruleTester.run(RULE_NAME, rule, { + valid, + invalid, +}); diff --git a/packages/eslint-plugin-template/tests/rules/prefer-template-literal/cases.ts b/packages/eslint-plugin-template/tests/rules/prefer-template-literal/cases.ts index ed154e09a..d9a888132 100644 --- a/packages/eslint-plugin-template/tests/rules/prefer-template-literal/cases.ts +++ b/packages/eslint-plugin-template/tests/rules/prefer-template-literal/cases.ts @@ -266,6 +266,32 @@ export const invalid: readonly InvalidTestCase[] = [ `, }), + convertAnnotatedSourceToFailureCase({ + messageId, + description: + 'should fail concatenation (left: simple quote, right: ternary in parentheses)', + annotatedSource: ` + {{ 'prefix-' + (condition ? 'true' : 'false') }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + `, + annotatedOutput: ` + {{ \`prefix-\${condition ? 'true' : 'false'}\` }} + + `, + }), + convertAnnotatedSourceToFailureCase({ + messageId, + description: + 'should fail concatenation (left: simple quote, right: pipe in parentheses)', + annotatedSource: ` + {{ 'prefix-' + ('value' | pipe) }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + `, + annotatedOutput: ` + {{ \`prefix-\${'value' | pipe}\` }} + + `, + }), // Left : double quote convertAnnotatedSourceToFailureCase({ @@ -356,6 +382,32 @@ export const invalid: readonly InvalidTestCase[] = [ `, }), + convertAnnotatedSourceToFailureCase({ + messageId, + description: + 'should fail concatenation (left: double quote, right: ternary in parentheses)', + annotatedSource: ` + {{ 'prefix-' + (condition ? 'true' : 'false') }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + `, + annotatedOutput: ` + {{ \`prefix-\${condition ? 'true' : 'false'}\` }} + + `, + }), + convertAnnotatedSourceToFailureCase({ + messageId, + description: + 'should fail concatenation (left: double quote, right: pipe in parentheses)', + annotatedSource: ` + {{ 'prefix-' + ('value' | pipe) }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + `, + annotatedOutput: ` + {{ \`prefix-\${'value' | pipe}\` }} + + `, + }), // Left : template convertAnnotatedSourceToFailureCase({ @@ -443,6 +495,32 @@ export const invalid: readonly InvalidTestCase[] = [ `, }), + convertAnnotatedSourceToFailureCase({ + messageId, + description: + 'should fail concatenation (left: template, right: ternary in parentheses)', + annotatedSource: ` + {{ \`prefix-\${value}-suffix\` + (condition ? 'true' : 'false') }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + `, + annotatedOutput: ` + {{ \`prefix-\${value}-suffix\${condition ? 'true' : 'false'}\` }} + + `, + }), + convertAnnotatedSourceToFailureCase({ + messageId, + description: + 'should fail concatenation (left: template, right: pipe in parentheses)', + annotatedSource: ` + {{ \`prefix-\${value}-suffix\` + ('value' | pipe) }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + `, + annotatedOutput: ` + {{ \`prefix-\${value}-suffix\${'value' | pipe}\` }} + + `, + }), // Right : simple quote convertAnnotatedSourceToFailureCase({ @@ -546,6 +624,32 @@ export const invalid: readonly InvalidTestCase[] = [ `, }), + convertAnnotatedSourceToFailureCase({ + messageId, + description: + 'should fail concatenation (left: ternary in parentheses, right: simple quote)', + annotatedSource: ` + {{ (condition ? 'true' : 'false') + '-suffix' }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + `, + annotatedOutput: ` + {{ \`\${condition ? 'true' : 'false'}-suffix\` }} + + `, + }), + convertAnnotatedSourceToFailureCase({ + messageId, + description: + 'should fail concatenation (left: pipe in parentheses, right: simple quote)', + annotatedSource: ` + {{ ('value' | pipe) + '-suffix' }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + `, + annotatedOutput: ` + {{ \`\${'value' | pipe}-suffix\` }} + + `, + }), // Right : double quote convertAnnotatedSourceToFailureCase({ @@ -649,6 +753,32 @@ export const invalid: readonly InvalidTestCase[] = [ `, }), + convertAnnotatedSourceToFailureCase({ + messageId, + description: + 'should fail concatenation (left: ternary in parentheses, right: double quote)', + annotatedSource: ` + {{ (condition ? 'true' : 'false') + "-suffix" }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + `, + annotatedOutput: ` + {{ \`\${condition ? 'true' : 'false'}-suffix\` }} + + `, + }), + convertAnnotatedSourceToFailureCase({ + messageId, + description: + 'should fail concatenation (left: pipe in parentheses, right: double quote)', + annotatedSource: ` + {{ ('value' | pipe) + "-suffix" }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + `, + annotatedOutput: ` + {{ \`\${'value' | pipe}-suffix\` }} + + `, + }), // Right : template convertAnnotatedSourceToFailureCase({ @@ -736,4 +866,30 @@ export const invalid: readonly InvalidTestCase[] = [ `, }), + convertAnnotatedSourceToFailureCase({ + messageId, + description: + 'should fail concatenation (left: ternary in parentheses, right: template)', + annotatedSource: ` + {{ (condition ? 'true' : 'false') + \`prefix-\${value}-suffix\` }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + `, + annotatedOutput: ` + {{ \`\${condition ? 'true' : 'false'}prefix-\${value}-suffix\` }} + + `, + }), + convertAnnotatedSourceToFailureCase({ + messageId, + description: + 'should fail concatenation (left: pipe in parentheses, right: template)', + annotatedSource: ` + {{ ('value' | pipe) + \`prefix-\${value}-suffix\` }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + `, + annotatedOutput: ` + {{ \`\${'value' | pipe}prefix-\${value}-suffix\` }} + + `, + }), ]; diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index bba2f8782..b88f82c61 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -1,3 +1,13 @@ +## 19.5.0 (2025-05-25) + +### πŸš€ Features + +- **eslint-plugin:** introduce sort keys in type-decorator rule ([#2187](https://github.com/angular-eslint/angular-eslint/pull/2187)) + +### ❀️ Thank You + +- Benjamin SchΓ€ublin + ## 19.4.0 (2025-05-08) ### πŸš€ Features diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index 1058e5c6d..bade7d022 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -73,6 +73,7 @@ Please see https://github.com/angular-eslint/angular-eslint for full usage instr | [`relative-url-prefix`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/relative-url-prefix.md) | The ./ and ../ prefix is standard syntax for relative URLs; don't depend on Angular's current ability to do without that prefix. See more at https://angular.dev/style-guide#style-05-04 | | | | | [`require-localize-metadata`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/require-localize-metadata.md) | Ensures that $localize tagged messages contain helpful metadata to aid with translations. | | | | | [`runtime-localize`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/runtime-localize.md) | Ensures that $localize tagged messages can use runtime-loaded translations. | | | | +| [`sort-keys-in-type-decorator`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/sort-keys-in-type-decorator.md) | Ensures that keys in type decorators (Component, Directive, NgModule, Pipe) are sorted in a consistent order | | :wrench: | | | [`use-component-selector`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/use-component-selector.md) | Component selector must be declared | | | | | [`use-component-view-encapsulation`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/use-component-view-encapsulation.md) | Disallows using `ViewEncapsulation.None` | | | :bulb: | | [`use-injectable-provided-in`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/use-injectable-provided-in.md) | Using the `providedIn` property makes `Injectables` tree-shakable | | | :bulb: | diff --git a/packages/eslint-plugin/docs/rules/sort-keys-in-type-decorator.md b/packages/eslint-plugin/docs/rules/sort-keys-in-type-decorator.md new file mode 100644 index 000000000..d4793e734 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/sort-keys-in-type-decorator.md @@ -0,0 +1,917 @@ + + +
+ +# `@angular-eslint/sort-keys-in-type-decorator` + +Ensures that keys in type decorators (Component, Directive, NgModule, Pipe) are sorted in a consistent order + +- Type: suggestion +- πŸ”§ Supports autofix (`--fix`) + +
+ +## Rule Options + +The rule accepts an options object with the following properties: + +```ts +interface Options { + /** + * Default: `["selector","imports","standalone","templateUrl","template","styleUrl","styleUrls","styles","encapsulation","changeDetection"]` + */ + Component?: string[]; + /** + * Default: `["selector","standalone"]` + */ + Directive?: string[]; + /** + * Default: `["declarations","imports","exports","providers","bootstrap"]` + */ + NgModule?: string[]; + /** + * Default: `["name","standalone"]` + */ + Pipe?: string[]; +} + +``` + +
+ +## Usage Examples + +> The following examples are generated automatically from the actual unit tests within the plugin, so you can be assured that their behavior is accurate based on the current commit. + +
+ +
+❌ - Toggle examples of incorrect code for this rule + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "Component": [ + "selector", + "imports", + "standalone", + "templateUrl", + "styleUrl", + "encapsulation", + "changeDetection" + ] + } + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```ts +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + selector: 'app-root', + imports: [CommonModule], + standalone: true, + templateUrl: './app.component.html', + styleUrl: './app.component.css', + encapsulation: ViewEncapsulation.None +}) +class Test { +} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "Directive": [ + "selector", + "standalone" + ] + } + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```ts +@Directive({ + standalone: true, + ~~~~~~~~~~~~~~~~ + selector: '[app-test]' +}) +class Test { +} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "NgModule": [ + "declarations", + "imports" + ] + } + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```ts +@NgModule({ + imports: [CommonModule], + ~~~~~~~~~~~~~~~~~~~~~~~ + declarations: [AppComponent] +}) +class Test { +} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "Pipe": [ + "name", + "standalone" + ] + } + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```ts +@Pipe({ + standalone: true, + ~~~~~~~~~~~~~~~~ + name: 'myPipe' +}) +class Test { +} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "Component": [ + "selector", + "imports", + "standalone", + "templateUrl", + "styleUrl", + "encapsulation", + "changeDetection" + ] + } + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```ts +@Component({ + styleUrl: './app.component.css', + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + selector: 'app-root', + templateUrl: './app.component.html' +}) +class Test { +} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "NgModule": [ + "declarations", + "imports", + "exports", + "providers", + "bootstrap" + ] + } + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```ts +@NgModule({ + exports: [AppComponent], + ~~~~~~~~~~~~~~~~~~~~~~~ + declarations: [AppComponent] +}) +class Test { +} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "Component": [ + "selector", + "styleUrl" + ] + } + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```ts +@Component({ + styleUrl: './app.component.css', // Inline comment for styleUrl + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + selector: 'app-root' // Inline comment for selector +}) +class Test {} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "Component": [ + "selector", + "styleUrl" + ] + } + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```ts +@Component({ + // Comment above styleUrl + styleUrl: './app.component.css', + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Comment above selector + selector: 'app-root' +}) +class Test {} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "Component": [ + "selector", + "styleUrl" + ] + } + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```ts +@Component({ + /* This is a multi-line comment + above styleUrl property */ + styleUrl: './app.component.css', + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + /* This is a multi-line comment + above selector property */ + selector: 'app-root' +}) +class Test {} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "Component": [ + "selector", + "imports", + "standalone", + "templateUrl", + "styleUrl", + "encapsulation", + "changeDetection" + ] + } + ] + } +} +``` + +
+ +#### ❌ Invalid Code + +```ts +@Component({ + // Comment above changeDetection + changeDetection: ChangeDetectionStrategy.OnPush, // Inline comment for changeDetection + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + /* Multi-line comment + above selector */ + selector: 'app-root', /* Inline multi-line comment after selector */ + // Comment above imports + imports: [ + // Comment inside imports array + CommonModule, // Comment after CommonModule + FormsModule /* Comment after FormsModule */ + ], + /* Comment above standalone */ + standalone: true, // Comment after standalone + // Comment above templateUrl + templateUrl: './app.component.html', + /* Multi-line comment + above styleUrl */ + styleUrl: './app.component.css', + // Comment above encapsulation + encapsulation: ViewEncapsulation.None /* Inline comment for encapsulation */ +}) +class Test {} +``` + +
+ +
+ +--- + +
+ +
+βœ… - Toggle examples of correct code for this rule + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```ts +@Type({ + a: 'a', + b: 'b', + c: 'c' +}) +class Test {} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```ts +@Type({}) +class Test {} +``` + +
+ +--- + +
+ +#### Default Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error" + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```ts +@Type({ + a: 'a' +}) +class Test {} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "Component": [ + "selector", + "imports", + "standalone", + "templateUrl", + "styleUrl", + "encapsulation", + "changeDetection" + ] + } + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```ts +@Component({ + selector: 'app-root', + imports: [CommonModule], + standalone: true, + templateUrl: './app.component.html', + styleUrl: './app.component.css', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush +}) +class Test {} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "Directive": [ + "selector", + "standalone" + ] + } + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```ts +@Directive({ + selector: '[app-test]', + standalone: true +}) +class Test {} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "NgModule": [ + "declarations", + "imports" + ] + } + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```ts +@NgModule({ + declarations: [AppComponent], + imports: [CommonModule] +}) +class Test {} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "Pipe": [ + "name", + "standalone" + ] + } + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```ts +@Pipe({ + name: 'myPipe', + standalone: true +}) +class Test {} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "Component": [ + "selector", + "imports", + "standalone", + "templateUrl", + "styleUrl", + "encapsulation", + "changeDetection" + ] + } + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```ts +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrl: './app.component.css' +}) +class Test {} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "NgModule": [ + "declarations", + "imports", + "exports", + "providers", + "bootstrap" + ] + } + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```ts +@NgModule({ + declarations: [AppComponent], + exports: [AppComponent] +}) +class Test {} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "Component": [ + "selector", + "imports", + "standalone", + "templateUrl", + "styleUrl", + "encapsulation", + "changeDetection" + ] + } + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```ts +@Component({ + // Comment above selector + selector: 'app-root', // Inline comment for selector + /* Multi-line comment + above imports */ + imports: [ + CommonModule, + FormsModule + ], // Inline comment after imports + standalone: true, + templateUrl: './app.component.html', + styleUrl: './app.component.css', + // Comment above encapsulation + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush +}) +class Test {} +``` + +
+ +--- + +
+ +#### Custom Config + +```json +{ + "rules": { + "@angular-eslint/sort-keys-in-type-decorator": [ + "error", + { + "NgModule": [ + "declarations", + "imports", + "exports", + "providers", + "bootstrap" + ] + } + ] + } +} +``` + +
+ +#### βœ… Valid Code + +```ts +@NgModule({ + // Leading comment for declarations + declarations: [ + /* Component list comment */ + AppComponent, + HeaderComponent + ], + imports: [ + CommonModule, // Common module comment + RouterModule /* Router module comment */ + ], + /* Multi-line export comment + with multiple lines + before the property */ + exports: [AppComponent] +}) +class Test {} +``` + +
+ +
diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index c43aad63f..200271483 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@angular-eslint/eslint-plugin", - "version": "19.4.0", + "version": "19.5.0", "description": "ESLint plugin for Angular applications, following https://angular.dev/style-guide", "license": "MIT", "main": "dist/index.js", diff --git a/packages/eslint-plugin/src/configs/all.json b/packages/eslint-plugin/src/configs/all.json index 433f79d34..e34434e1a 100644 --- a/packages/eslint-plugin/src/configs/all.json +++ b/packages/eslint-plugin/src/configs/all.json @@ -36,6 +36,7 @@ "@angular-eslint/require-lifecycle-on-prototype": "error", "@angular-eslint/require-localize-metadata": "error", "@angular-eslint/runtime-localize": "error", + "@angular-eslint/sort-keys-in-type-decorator": "error", "@angular-eslint/sort-lifecycle-methods": "error", "@angular-eslint/use-component-selector": "error", "@angular-eslint/use-component-view-encapsulation": "error", diff --git a/packages/eslint-plugin/src/index.ts b/packages/eslint-plugin/src/index.ts index 65c28d877..5c6b3824b 100644 --- a/packages/eslint-plugin/src/index.ts +++ b/packages/eslint-plugin/src/index.ts @@ -34,6 +34,9 @@ import noAttributeDecorator, { import noConflictingLifecycle, { RULE_NAME as noConflictingLifecycleRuleName, } from './rules/no-conflicting-lifecycle'; +import noDuplicatesInMetadataArrays, { + RULE_NAME as noDuplicatesInMetadataArraysRuleName, +} from './rules/no-duplicates-in-metadata-arrays'; import noEmptyLifecycleMethod, { RULE_NAME as noEmptyLifecycleMethodRuleName, } from './rules/no-empty-lifecycle-method'; @@ -100,6 +103,9 @@ import requireLocalizeMetadata, { import runtimeLocalize, { RULE_NAME as runtimeLocalizeRuleName, } from './rules/runtime-localize'; +import sortKeysInTypeDecorator, { + RULE_NAME as sortKeysInTypeDecoratorRuleName, +} from './rules/sort-keys-in-type-decorator'; import sortLifecycleMethods, { RULE_NAME as sortLifecycleMethodsRuleName, } from './rules/sort-lifecycle-methods'; @@ -118,9 +124,6 @@ import useLifecycleInterface, { import usePipeTransformInterface, { RULE_NAME as usePipeTransformInterfaceRuleName, } from './rules/use-pipe-transform-interface'; -import noDuplicatesInMetadataArrays, { - RULE_NAME as noDuplicatesInMetadataArraysRuleName, -} from './rules/no-duplicates-in-metadata-arrays'; export = { configs: { @@ -163,6 +166,7 @@ export = { [requireLifecycleOnPrototypeRuleName]: requireLifecycleOnPrototype, [requireLocalizeMetadataRuleName]: requireLocalizeMetadata, [runtimeLocalizeRuleName]: runtimeLocalize, + [sortKeysInTypeDecoratorRuleName]: sortKeysInTypeDecorator, [sortLifecycleMethodsRuleName]: sortLifecycleMethods, [useComponentSelectorRuleName]: useComponentSelector, [useComponentViewEncapsulationRuleName]: useComponentViewEncapsulation, diff --git a/packages/eslint-plugin/src/rules/sort-keys-in-type-decorator.ts b/packages/eslint-plugin/src/rules/sort-keys-in-type-decorator.ts new file mode 100644 index 000000000..1048743c6 --- /dev/null +++ b/packages/eslint-plugin/src/rules/sort-keys-in-type-decorator.ts @@ -0,0 +1,256 @@ +import { ASTUtils, CommentUtils, Selectors } from '@angular-eslint/utils'; +import { TSESLint, TSESTree } from '@typescript-eslint/utils'; +import { createESLintRule } from '../utils/create-eslint-rule'; + +export type Options = [ + { + [key: string]: string[]; + }, +]; + +export type MessageIds = 'incorrectOrder'; + +const DEFAULT_ORDER = { + Component: [ + 'selector', + 'imports', + 'standalone', + 'templateUrl', + 'template', + 'styleUrl', + 'styleUrls', + 'styles', + 'encapsulation', + 'changeDetection', + ], + Directive: ['selector', 'standalone'], + NgModule: ['declarations', 'imports', 'exports', 'providers', 'bootstrap'], + Pipe: ['name', 'standalone'], +}; + +export const RULE_NAME = 'sort-keys-in-type-decorator'; + +export default createESLintRule({ + name: RULE_NAME, + meta: { + type: 'suggestion', + docs: { + description: + 'Ensures that keys in type decorators (Component, Directive, NgModule, Pipe) are sorted in a consistent order', + }, + fixable: 'code', + schema: [ + { + type: 'object', + properties: { + Component: { + type: 'array', + items: { + type: 'string', + }, + }, + Directive: { + type: 'array', + items: { + type: 'string', + }, + }, + NgModule: { + type: 'array', + items: { + type: 'string', + }, + }, + Pipe: { + type: 'array', + items: { + type: 'string', + }, + }, + }, + additionalProperties: false, + }, + ], + messages: { + incorrectOrder: + 'Keys in @{{decorator}} decorator should be ordered: {{expectedOrder}}', + }, + }, + defaultOptions: [DEFAULT_ORDER], + create( + context: Readonly>, + [orderConfig]: Readonly, + ) { + function checkContext( + node: TSESTree.Decorator, + decoratorName: string, + ): void { + const expectedOrder = orderConfig[decoratorName]; + if (!expectedOrder) { + return; + } + + const argument = ASTUtils.getDecoratorArgument(node); + if (!argument) { + return; + } + + const properties = ASTUtils.getDecoratorProperties(node); + if (properties.length <= 1) { + return; + } + + const firstConfiguredIndex = properties.findIndex(({ key }) => + expectedOrder.includes((key as TSESTree.Identifier).name), + ); + const lastNonConfiguredIndex = properties.findIndex( + ({ key }) => !expectedOrder.includes((key as TSESTree.Identifier).name), + ); + + if ( + firstConfiguredIndex !== -1 && + lastNonConfiguredIndex !== -1 && + lastNonConfiguredIndex < firstConfiguredIndex + ) { + createInvalidSortRuleForDecorator( + context, + decoratorName, + expectedOrder, + properties, + properties[lastNonConfiguredIndex], + ); + return; + } + + const configuredProperties = properties.filter(({ key }) => + expectedOrder.includes((key as TSESTree.Identifier).name), + ); + + if (configuredProperties.length) { + const actualConfiguredOrder = configuredProperties.map( + ({ key }) => (key as TSESTree.Identifier).name, + ); + const expectedConfiguredOrder = expectedOrder.filter((key: string) => + actualConfiguredOrder.includes(key), + ); + + if ( + actualConfiguredOrder.length && + JSON.stringify(actualConfiguredOrder) !== + JSON.stringify(expectedConfiguredOrder) + ) { + const firstOutOfOrderIndex = actualConfiguredOrder.findIndex( + (key, index) => key !== expectedConfiguredOrder[index], + ); + const outOfOrderProperty = configuredProperties[firstOutOfOrderIndex]; + + createInvalidSortRuleForDecorator( + context, + decoratorName, + expectedOrder, + properties, + outOfOrderProperty, + ); + } + } + } + + return { + [Selectors.COMPONENT_CLASS_DECORATOR](node: TSESTree.Decorator) { + checkContext(node, ASTUtils.AngularClassDecorators.Component); + }, + [Selectors.DIRECTIVE_CLASS_DECORATOR](node: TSESTree.Decorator) { + checkContext(node, ASTUtils.AngularClassDecorators.Directive); + }, + [Selectors.INJECTABLE_CLASS_DECORATOR](node: TSESTree.Decorator) { + checkContext(node, ASTUtils.AngularClassDecorators.Injectable); + }, + [Selectors.MODULE_CLASS_DECORATOR](node: TSESTree.Decorator) { + checkContext(node, ASTUtils.AngularClassDecorators.NgModule); + }, + [Selectors.PIPE_CLASS_DECORATOR](node: TSESTree.Decorator) { + checkContext(node, ASTUtils.AngularClassDecorators.Pipe); + }, + }; + }, +}); + +function createInvalidSortRuleForDecorator( + context: Readonly>, + decoratorName: string, + expectedOrder: string[], + properties: TSESTree.Property[], + node: TSESTree.Property, +): void { + const presentProps = properties.map( + (prop) => (prop.key as TSESTree.Identifier).name, + ); + + const relevantExpectedOrder = expectedOrder.filter((propName) => + presentProps.includes(propName), + ); + + const data = { + decorator: decoratorName, + expectedOrder: relevantExpectedOrder.join(', '), + }; + + reportAndFix( + context, + node, + 'incorrectOrder', + data, + properties, + expectedOrder, + node.parent as TSESTree.Expression, + ); +} + +function reportAndFix( + context: Readonly>, + node: TSESTree.Property, + messageId: MessageIds, + data: { decorator: string; expectedOrder: string }, + properties: TSESTree.Property[], + expectedOrder: string[], + objectExpression: TSESTree.Expression, +): void { + const sourceCode = context.sourceCode; + + context.report({ + node, + messageId, + data, + fix(fixer) { + const indentation = CommentUtils.getObjectIndentation( + sourceCode, + objectExpression, + ); + + const propNames = properties.map( + (p) => (p.key as TSESTree.Identifier).name, + ); + const filteredOrder = expectedOrder.filter((name) => + propNames.includes(name), + ); + + const propInfoMap = CommentUtils.extractPropertyComments( + sourceCode, + properties, + objectExpression, + indentation, + ); + + const sortedText = CommentUtils.buildSortedPropertiesWithComments( + filteredOrder, + propInfoMap, + indentation, + ); + + return fixer.replaceText( + objectExpression, + `{\n${sortedText}\n${indentation.slice(0, -2)}}`, + ); + }, + }); +} diff --git a/packages/eslint-plugin/tests/rules/sort-keys-in-type-decorator/cases.ts b/packages/eslint-plugin/tests/rules/sort-keys-in-type-decorator/cases.ts new file mode 100644 index 000000000..4201c14e2 --- /dev/null +++ b/packages/eslint-plugin/tests/rules/sort-keys-in-type-decorator/cases.ts @@ -0,0 +1,606 @@ +import { convertAnnotatedSourceToFailureCase } from '@angular-eslint/test-utils'; +import type { + InvalidTestCase, + ValidTestCase, +} from '@typescript-eslint/rule-tester'; +import type { + MessageIds, + Options, +} from '../../../src/rules/sort-keys-in-type-decorator'; + +export const valid: readonly ValidTestCase[] = [ + { + code: ` + @Type({ + a: 'a', + b: 'b', + c: 'c' + }) + class Test {} + `, + }, + { + code: ` + @Type({}) + class Test {} + `, + }, + { + code: ` + @Type({ + a: 'a' + }) + class Test {} + `, + }, + { + code: ` + @Component({ + selector: 'app-root', + imports: [CommonModule], + standalone: true, + templateUrl: './app.component.html', + styleUrl: './app.component.css', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush + }) + class Test {} + `, + options: [ + { + Component: [ + 'selector', + 'imports', + 'standalone', + 'templateUrl', + 'styleUrl', + 'encapsulation', + 'changeDetection', + ], + }, + ], + }, + { + code: ` + @Directive({ + selector: '[app-test]', + standalone: true + }) + class Test {} + `, + options: [ + { + Directive: ['selector', 'standalone'], + }, + ], + }, + { + code: ` + @NgModule({ + declarations: [AppComponent], + imports: [CommonModule] + }) + class Test {} + `, + options: [ + { + NgModule: ['declarations', 'imports'], + }, + ], + }, + { + code: ` + @Pipe({ + name: 'myPipe', + standalone: true + }) + class Test {} + `, + options: [ + { + Pipe: ['name', 'standalone'], + }, + ], + }, + { + code: ` + @Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrl: './app.component.css' + }) + class Test {} + `, + options: [ + { + Component: [ + 'selector', + 'imports', + 'standalone', + 'templateUrl', + 'styleUrl', + 'encapsulation', + 'changeDetection', + ], + }, + ], + }, + { + code: ` + @NgModule({ + declarations: [AppComponent], + exports: [AppComponent] + }) + class Test {} + `, + options: [ + { + NgModule: [ + 'declarations', + 'imports', + 'exports', + 'providers', + 'bootstrap', + ], + }, + ], + }, + { + code: ` + @Component({ + // Comment above selector + selector: 'app-root', // Inline comment for selector + /* Multi-line comment + above imports */ + imports: [ + CommonModule, + FormsModule + ], // Inline comment after imports + standalone: true, + templateUrl: './app.component.html', + styleUrl: './app.component.css', + // Comment above encapsulation + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush + }) + class Test {} + `, + options: [ + { + Component: [ + 'selector', + 'imports', + 'standalone', + 'templateUrl', + 'styleUrl', + 'encapsulation', + 'changeDetection', + ], + }, + ], + }, + { + code: ` + @NgModule({ + // Leading comment for declarations + declarations: [ + /* Component list comment */ + AppComponent, + HeaderComponent + ], + imports: [ + CommonModule, // Common module comment + RouterModule /* Router module comment */ + ], + /* Multi-line export comment + with multiple lines + before the property */ + exports: [AppComponent] + }) + class Test {} + `, + options: [ + { + NgModule: [ + 'declarations', + 'imports', + 'exports', + 'providers', + 'bootstrap', + ], + }, + ], + }, +]; + +export const invalid: readonly InvalidTestCase[] = [ + convertAnnotatedSourceToFailureCase({ + description: + 'should fail when Component decorator keys are not sorted according to specified order', + annotatedSource: ` + @Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + selector: 'app-root', + imports: [CommonModule], + standalone: true, + templateUrl: './app.component.html', + styleUrl: './app.component.css', + encapsulation: ViewEncapsulation.None + }) + class Test { + } + `, + messageId: 'incorrectOrder', + data: { + decorator: 'Component', + expectedOrder: + 'selector, imports, standalone, templateUrl, styleUrl, encapsulation, changeDetection', + }, + options: [ + { + Component: [ + 'selector', + 'imports', + 'standalone', + 'templateUrl', + 'styleUrl', + 'encapsulation', + 'changeDetection', + ], + }, + ], + annotatedOutput: ` + @Component({ + selector: 'app-root', + imports: [CommonModule], + standalone: true, + templateUrl: './app.component.html', + styleUrl: './app.component.css', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush + }) + class Test { + } + `, + }), + convertAnnotatedSourceToFailureCase({ + description: + 'should fail when Directive decorator keys are not sorted according to specified order', + annotatedSource: ` + @Directive({ + standalone: true, + ~~~~~~~~~~~~~~~~ + selector: '[app-test]' + }) + class Test { + } + `, + messageId: 'incorrectOrder', + data: { + decorator: 'Directive', + expectedOrder: 'selector, standalone', + }, + options: [ + { + Directive: ['selector', 'standalone'], + }, + ], + annotatedOutput: ` + @Directive({ + selector: '[app-test]', + standalone: true + }) + class Test { + } + `, + }), + convertAnnotatedSourceToFailureCase({ + description: + 'should fail when NgModule decorator keys are not sorted according to specified order', + annotatedSource: ` + @NgModule({ + imports: [CommonModule], + ~~~~~~~~~~~~~~~~~~~~~~~ + declarations: [AppComponent] + }) + class Test { + } + `, + messageId: 'incorrectOrder', + data: { + decorator: 'NgModule', + expectedOrder: 'declarations, imports', + }, + options: [ + { + NgModule: ['declarations', 'imports'], + }, + ], + annotatedOutput: ` + @NgModule({ + declarations: [AppComponent], + imports: [CommonModule] + }) + class Test { + } + `, + }), + convertAnnotatedSourceToFailureCase({ + description: + 'should fail when Pipe decorator keys are not sorted according to specified order', + annotatedSource: ` + @Pipe({ + standalone: true, + ~~~~~~~~~~~~~~~~ + name: 'myPipe' + }) + class Test { + } + `, + messageId: 'incorrectOrder', + data: { + decorator: 'Pipe', + expectedOrder: 'name, standalone', + }, + options: [ + { + Pipe: ['name', 'standalone'], + }, + ], + annotatedOutput: ` + @Pipe({ + name: 'myPipe', + standalone: true + }) + class Test { + } + `, + }), + convertAnnotatedSourceToFailureCase({ + description: 'should fail when partial properties are not in correct order', + annotatedSource: ` + @Component({ + styleUrl: './app.component.css', + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + selector: 'app-root', + templateUrl: './app.component.html' + }) + class Test { + } + `, + messageId: 'incorrectOrder', + data: { + decorator: 'Component', + expectedOrder: 'selector, templateUrl, styleUrl', + }, + options: [ + { + Component: [ + 'selector', + 'imports', + 'standalone', + 'templateUrl', + 'styleUrl', + 'encapsulation', + 'changeDetection', + ], + }, + ], + annotatedOutput: ` + @Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrl: './app.component.css' + }) + class Test { + } + `, + }), + convertAnnotatedSourceToFailureCase({ + description: + 'should fail when partial NgModule properties are not in correct order', + annotatedSource: ` + @NgModule({ + exports: [AppComponent], + ~~~~~~~~~~~~~~~~~~~~~~~ + declarations: [AppComponent] + }) + class Test { + } + `, + messageId: 'incorrectOrder', + data: { + decorator: 'NgModule', + expectedOrder: 'declarations, exports', + }, + options: [ + { + NgModule: [ + 'declarations', + 'imports', + 'exports', + 'providers', + 'bootstrap', + ], + }, + ], + annotatedOutput: ` + @NgModule({ + declarations: [AppComponent], + exports: [AppComponent] + }) + class Test { + } + `, + }), + convertAnnotatedSourceToFailureCase({ + description: 'should handle basic inline comments when sorting properties', + annotatedSource: ` + @Component({ + styleUrl: './app.component.css', // Inline comment for styleUrl + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + selector: 'app-root' // Inline comment for selector + }) + class Test {} + `, + messageId: 'incorrectOrder', + data: { + decorator: 'Component', + expectedOrder: 'selector, styleUrl', + }, + options: [ + { + Component: ['selector', 'styleUrl'], + }, + ], + annotatedOutput: ` + @Component({ + selector: 'app-root', // Inline comment for selector + styleUrl: './app.component.css' // Inline comment for styleUrl + }) + class Test {} + `, + }), + convertAnnotatedSourceToFailureCase({ + description: 'should preserve leading comments when sorting properties', + annotatedSource: ` + @Component({ + // Comment above styleUrl + styleUrl: './app.component.css', + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Comment above selector + selector: 'app-root' + }) + class Test {} + `, + messageId: 'incorrectOrder', + data: { + decorator: 'Component', + expectedOrder: 'selector, styleUrl', + }, + options: [ + { + Component: ['selector', 'styleUrl'], + }, + ], + annotatedOutput: ` + @Component({ + // Comment above selector + selector: 'app-root', + // Comment above styleUrl + styleUrl: './app.component.css' + }) + class Test {} + `, + }), + convertAnnotatedSourceToFailureCase({ + description: 'should preserve multi-line comments when sorting properties', + annotatedSource: ` + @Component({ + /* This is a multi-line comment + above styleUrl property */ + styleUrl: './app.component.css', + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + /* This is a multi-line comment + above selector property */ + selector: 'app-root' + }) + class Test {} + `, + messageId: 'incorrectOrder', + data: { + decorator: 'Component', + expectedOrder: 'selector, styleUrl', + }, + options: [ + { + Component: ['selector', 'styleUrl'], + }, + ], + annotatedOutput: ` + @Component({ + /* This is a multi-line comment + above selector property */ + selector: 'app-root', + /* This is a multi-line comment + above styleUrl property */ + styleUrl: './app.component.css' + }) + class Test {} + `, + }), + convertAnnotatedSourceToFailureCase({ + description: 'should properly handle comments when sorting properties', + annotatedSource: ` + @Component({ + // Comment above changeDetection + changeDetection: ChangeDetectionStrategy.OnPush, // Inline comment for changeDetection + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + /* Multi-line comment + above selector */ + selector: 'app-root', /* Inline multi-line comment after selector */ + // Comment above imports + imports: [ + // Comment inside imports array + CommonModule, // Comment after CommonModule + FormsModule /* Comment after FormsModule */ + ], + /* Comment above standalone */ + standalone: true, // Comment after standalone + // Comment above templateUrl + templateUrl: './app.component.html', + /* Multi-line comment + above styleUrl */ + styleUrl: './app.component.css', + // Comment above encapsulation + encapsulation: ViewEncapsulation.None /* Inline comment for encapsulation */ + }) + class Test {} + `, + messageId: 'incorrectOrder', + data: { + decorator: 'Component', + expectedOrder: + 'selector, imports, standalone, templateUrl, styleUrl, encapsulation, changeDetection', + }, + options: [ + { + Component: [ + 'selector', + 'imports', + 'standalone', + 'templateUrl', + 'styleUrl', + 'encapsulation', + 'changeDetection', + ], + }, + ], + annotatedOutput: ` + @Component({ + /* Multi-line comment + above selector */ + selector: 'app-root', /* Inline multi-line comment after selector */ + // Comment above imports + imports: [ + // Comment inside imports array + CommonModule, // Comment after CommonModule + FormsModule /* Comment after FormsModule */ + ], + /* Comment above standalone */ + standalone: true, // Comment after standalone + // Comment above templateUrl + templateUrl: './app.component.html', + /* Multi-line comment + above styleUrl */ + styleUrl: './app.component.css', + // Comment above encapsulation + encapsulation: ViewEncapsulation.None, /* Inline comment for encapsulation */ + // Comment above changeDetection + changeDetection: ChangeDetectionStrategy.OnPush // Inline comment for changeDetection + }) + class Test {} + `, + }), +]; diff --git a/packages/eslint-plugin/tests/rules/sort-keys-in-type-decorator/spec.ts b/packages/eslint-plugin/tests/rules/sort-keys-in-type-decorator/spec.ts new file mode 100644 index 000000000..be8e7fb7d --- /dev/null +++ b/packages/eslint-plugin/tests/rules/sort-keys-in-type-decorator/spec.ts @@ -0,0 +1,12 @@ +import { RuleTester } from '@angular-eslint/test-utils'; +import rule, { + RULE_NAME, +} from '../../../src/rules/sort-keys-in-type-decorator'; +import { invalid, valid } from './cases'; + +const ruleTester = new RuleTester(); + +ruleTester.run(RULE_NAME, rule, { + valid, + invalid, +}); diff --git a/packages/schematics/CHANGELOG.md b/packages/schematics/CHANGELOG.md index 8492e09af..da5821382 100644 --- a/packages/schematics/CHANGELOG.md +++ b/packages/schematics/CHANGELOG.md @@ -1,3 +1,19 @@ +## 19.5.0 (2025-05-25) + +### πŸš€ Features + +- **schematics:** support --skip-install for ng-add ([#2451](https://github.com/angular-eslint/angular-eslint/pull/2451)) + +### 🩹 Fixes + +- update dependency eslint to v9.27.0 ([#2431](https://github.com/angular-eslint/angular-eslint/pull/2431)) +- update typescript-eslint packages to v8.32.1 ([#2422](https://github.com/angular-eslint/angular-eslint/pull/2422)) +- update dependency semver to v7.7.2 ([#2421](https://github.com/angular-eslint/angular-eslint/pull/2421)) + +### ❀️ Thank You + +- James Henry @JamesHenry + ## 19.4.0 (2025-05-08) ### 🩹 Fixes diff --git a/packages/schematics/README.md b/packages/schematics/README.md index 1522b359f..130ccbf45 100644 --- a/packages/schematics/README.md +++ b/packages/schematics/README.md @@ -3,3 +3,13 @@ Please see https://github.com/angular-eslint/angular-eslint for full usage instructions and guidance. The `@angular-eslint/schematics` package is a set of custom Angular CLI Schematics which are used to add and update dependencies and configuration files which are relevant for running ESLint on an Angular workspace. + +## Options + +### `--skip-install` + +Skips installing npm packages when running `ng add @angular-eslint/schematics`. This can be useful when the schematic is executed as part of a larger workflow that handles dependency installation separately. + +``` +ng add @angular-eslint/schematics --skip-install +``` diff --git a/packages/schematics/package.json b/packages/schematics/package.json index 213bc6e6f..2444d993a 100644 --- a/packages/schematics/package.json +++ b/packages/schematics/package.json @@ -1,6 +1,6 @@ { "name": "@angular-eslint/schematics", - "version": "19.4.0", + "version": "19.5.0", "description": "Angular Schematics for angular-eslint", "license": "MIT", "main": "dist/index.js", @@ -41,12 +41,12 @@ "@angular-eslint/eslint-plugin": "workspace:*", "@angular-eslint/eslint-plugin-template": "workspace:*", "ignore": "7.0.4", - "semver": "7.7.1", + "semver": "7.7.2", "strip-json-comments": "3.1.1" }, "devDependencies": { - "@typescript-eslint/utils": "8.32.0", - "eslint": "9.26.0" + "@typescript-eslint/utils": "8.32.1", + "eslint": "9.27.0" }, "gitHead": "e2006e5e9c99e5a943d1a999e0efa5247d29ec24" } diff --git a/packages/schematics/src/ng-add/index.ts b/packages/schematics/src/ng-add/index.ts index 648c4e549..142701c7d 100644 --- a/packages/schematics/src/ng-add/index.ts +++ b/packages/schematics/src/ng-add/index.ts @@ -1,6 +1,7 @@ import type { Rule, SchematicContext, Tree } from '@angular-devkit/schematics'; import { chain, schematic } from '@angular-devkit/schematics'; import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks'; +import type { Schema } from './schema'; import { createRootESLintConfig, createStringifiedRootESLintConfig, @@ -21,6 +22,7 @@ const packageJSON = require('../../package.json'); function addAngularESLintPackages( json: Record, useFlatConfig: boolean, + options: Schema, ) { return (host: Tree, context: SchematicContext) => { if (!host.exists('package.json')) { @@ -62,13 +64,21 @@ function addAngularESLintPackages( json.devDependencies = sortObjectByKeys(json.devDependencies); host.overwrite('package.json', JSON.stringify(json, null, 2)); - context.addTask(new NodePackageInstallTask()); + if (!options.skipInstall) { + context.addTask(new NodePackageInstallTask({ allowScripts: false })); - context.logger.info(` + context.logger.info(` All angular-eslint dependencies have been successfully installed πŸŽ‰ Please see https://github.com/angular-eslint/angular-eslint for how to add ESLint configuration to your project. `); + } else { + context.logger.info(` +All angular-eslint dependencies have been successfully added. Run your package manager install command to complete setup. + +Please see https://github.com/angular-eslint/angular-eslint for how to add ESLint configuration to your project. +`); + } return host; }; @@ -212,7 +222,12 @@ Please see https://github.com/angular-eslint/angular-eslint for more information }; } -export default function (): Rule { +/** + * Entry point for the ng-add schematic. + * + * @param options Configuration options passed to the schematic. + */ +export default function (options: Schema): Rule { return (host: Tree, context: SchematicContext) => { const workspacePackageJSON = (host.read('package.json') as Buffer).toString( 'utf-8', @@ -221,7 +236,7 @@ export default function (): Rule { const useFlatConfig = shouldUseFlatConfig(host, json); return chain([ - addAngularESLintPackages(json, useFlatConfig), + addAngularESLintPackages(json, useFlatConfig, options), applyESLintConfigIfSingleProjectWithNoExistingTSLint(useFlatConfig), ])(host, context); }; diff --git a/packages/schematics/src/ng-add/schema.json b/packages/schematics/src/ng-add/schema.json index bed495d4e..eb603ca20 100644 --- a/packages/schematics/src/ng-add/schema.json +++ b/packages/schematics/src/ng-add/schema.json @@ -3,6 +3,13 @@ "$id": "add-angular-eslint", "title": "Add angular-eslint to an existing workspace", "type": "object", - "properties": {}, + "properties": { + "skipInstall": { + "type": "boolean", + "description": "Skip package installation after adding dependencies", + "default": false, + "alias": "skip-install" + } + }, "required": [] } diff --git a/packages/schematics/src/ng-add/schema.ts b/packages/schematics/src/ng-add/schema.ts new file mode 100644 index 000000000..fa0abb11e --- /dev/null +++ b/packages/schematics/src/ng-add/schema.ts @@ -0,0 +1,9 @@ +/** + * Options available to the ng-add schematic. + */ +export interface Schema { + /** + * Skip installing dependencies after modifying package.json. + */ + skipInstall?: boolean; +} diff --git a/packages/template-parser/CHANGELOG.md b/packages/template-parser/CHANGELOG.md index 81bfd014f..bbad5c345 100644 --- a/packages/template-parser/CHANGELOG.md +++ b/packages/template-parser/CHANGELOG.md @@ -1,3 +1,7 @@ +## 19.5.0 (2025-05-25) + +This was a version bump only for template-parser to align it with other projects, there were no code changes. + ## 19.4.0 (2025-05-08) This was a version bump only for template-parser to align it with other projects, there were no code changes. diff --git a/packages/template-parser/package.json b/packages/template-parser/package.json index bba9a77b1..933048cdb 100644 --- a/packages/template-parser/package.json +++ b/packages/template-parser/package.json @@ -1,6 +1,6 @@ { "name": "@angular-eslint/template-parser", - "version": "19.4.0", + "version": "19.5.0", "description": "Angular Template parser for ESLint", "license": "MIT", "main": "dist/index.js", diff --git a/packages/template-parser/src/index.ts b/packages/template-parser/src/index.ts index 615bc53c7..fa38d423f 100644 --- a/packages/template-parser/src/index.ts +++ b/packages/template-parser/src/index.ts @@ -250,7 +250,7 @@ function parseForESLint( options: ParserOptions, ): { ast: AST; - scopeManager: ScopeManager; + scopeManager: InstanceType; visitorKeys: VisitorKeys; services: { convertElementSourceSpanToLoc: typeof convertElementSourceSpanToLoc; @@ -281,10 +281,7 @@ function parseForESLint( value: code, }; - // @ts-expect-error The types for ScopeManager seem to be wrong, it requires a configuration object or it will throw at runtime const scopeManager = new ScopeManager({}); - - // @ts-expect-error Create a global scope for the ScopeManager, the types for Scope also seem to be wrong new Scope(scopeManager, 'module', null, ast, false); preprocessNode(ast); diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index 8cc5df289..7f0665eb6 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,3 +1,7 @@ +## 19.5.0 (2025-05-25) + +This was a version bump only for @angular-eslint/test-utils to align it with other projects, there were no code changes. + ## 19.4.0 (2025-05-08) This was a version bump only for @angular-eslint/test-utils to align it with other projects, there were no code changes. diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 0bad5023b..f88b9518b 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@angular-eslint/test-utils", - "version": "19.4.0", + "version": "19.5.0", "license": "MIT", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index 89660e978..80dc755a2 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -1,3 +1,13 @@ +## 19.5.0 (2025-05-25) + +### πŸš€ Features + +- **eslint-plugin:** introduce sort keys in type-decorator rule ([#2187](https://github.com/angular-eslint/angular-eslint/pull/2187)) + +### ❀️ Thank You + +- Benjamin SchΓ€ublin + ## 19.4.0 (2025-05-08) This was a version bump only for @angular-eslint/utils to align it with other projects, there were no code changes. diff --git a/packages/utils/package.json b/packages/utils/package.json index 200f725a1..a90c8e969 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@angular-eslint/utils", - "version": "19.4.0", + "version": "19.5.0", "license": "MIT", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/utils/src/eslint-plugin/ast-utils.ts b/packages/utils/src/eslint-plugin/ast-utils.ts index 24af11c0b..e5f375b96 100644 --- a/packages/utils/src/eslint-plugin/ast-utils.ts +++ b/packages/utils/src/eslint-plugin/ast-utils.ts @@ -442,13 +442,19 @@ export function getPropertyDefinitionName({ ); } +export const getDecoratorProperties = ( + decorator: TSESTree.Decorator, +): TSESTree.Property[] => { + return getDecoratorArgument(decorator)?.properties.filter(isProperty) ?? []; +}; + export const getDecoratorProperty = ( decorator: TSESTree.Decorator, name: string, ): TSESTree.Property | undefined => { - return getDecoratorArgument(decorator) - ?.properties.filter(isProperty) - .find(({ key }) => ASTUtils.isIdentifier(key) && key.name === name); + return getDecoratorProperties(decorator).find( + ({ key }) => ASTUtils.isIdentifier(key) && key.name === name, + ); }; export const getDecoratorPropertyValue = ( diff --git a/packages/utils/src/eslint-plugin/comment-utils.ts b/packages/utils/src/eslint-plugin/comment-utils.ts new file mode 100644 index 000000000..e303fda31 --- /dev/null +++ b/packages/utils/src/eslint-plugin/comment-utils.ts @@ -0,0 +1,128 @@ +import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; + +export interface PropInfo { + name: string; + leadingComments: string[]; + value: string; + trailingComments: string[]; +} + +export function extractPropertyComments( + sourceCode: Readonly, + properties: TSESTree.Property[], + objectExpression: TSESTree.Expression, + indentation: string, +): Map { + const allComments = sourceCode.getAllComments(); + const processedCommentRanges = new Set(); + const propInfoMap = new Map(); + const commentLineMap = new Map(); + + for (const comment of allComments) { + const line = sourceCode.getLocFromIndex(comment.range[0]).line; + if (!commentLineMap.has(line)) { + commentLineMap.set(line, []); + } + commentLineMap.get(line)?.push(comment); + } + + const makeRangeKey = (start: number, end: number) => `${start}-${end}`; + + for (let i = 0; i < properties.length; i++) { + const prop = properties[i]; + const name = (prop.key as TSESTree.Identifier).name; + const propRange = prop.range; + const leadingComments: string[] = []; + const prevPropEnd = + i > 0 ? properties[i - 1].range[1] : objectExpression.range[0] + 1; + + for (const comment of allComments) { + const rangeKey = makeRangeKey(comment.range[0], comment.range[1]); + if ( + comment.range[0] > prevPropEnd && + comment.range[0] < propRange[0] && + !processedCommentRanges.has(rangeKey) + ) { + leadingComments.push(indentation + sourceCode.getText(comment)); + processedCommentRanges.add(rangeKey); + } + } + + const propText = sourceCode.getText(prop).replace(/,\s*$/, ''); + const trailingComments: string[] = []; + const propEndLine = sourceCode.getLocFromIndex(propRange[1]).line; + + if (commentLineMap.has(propEndLine)) { + const commentsOnLine = commentLineMap.get(propEndLine) || []; + for (const comment of commentsOnLine) { + const rangeKey = makeRangeKey(comment.range[0], comment.range[1]); + if ( + comment.range[0] > propRange[1] && + !processedCommentRanges.has(rangeKey) + ) { + const spaceBefore = sourceCode + .getText() + .substring(propRange[1], comment.range[0]) + .replace(/,/g, ''); + + trailingComments.push(spaceBefore + sourceCode.getText(comment)); + processedCommentRanges.add(rangeKey); + } + } + } + + propInfoMap.set(name, { + name, + leadingComments, + value: propText, + trailingComments, + }); + } + + return propInfoMap; +} + +export function buildSortedPropertiesWithComments( + filteredOrder: string[], + propInfoMap: Map, + indentation: string, +): string { + const sortedParts: string[] = []; + + for (let i = 0; i < filteredOrder.length; i++) { + const propName = filteredOrder[i]; + const info = propInfoMap.get(propName); + + if (info) { + if (info.leadingComments.length > 0) { + sortedParts.push(...info.leadingComments); + } + + const isLast = i === filteredOrder.length - 1; + let finalPropText = indentation + info.value; + + if (!isLast) { + finalPropText += ','; + } + + if (info.trailingComments.length > 0) { + info.trailingComments.forEach((comment) => { + finalPropText += comment; + }); + } + + sortedParts.push(finalPropText); + } + } + + return sortedParts.join('\n'); +} + +export function getObjectIndentation( + sourceCode: Readonly, + objectExpression: TSESTree.Expression, +): string { + const objectExpressionText = sourceCode.getText(objectExpression); + const lines = objectExpressionText.split('\n'); + return lines[1] ? lines[1].match(/^\s*/)?.[0] || '' : ''; +} diff --git a/packages/utils/src/eslint-plugin/get-native-event-names.ts b/packages/utils/src/eslint-plugin/get-native-event-names.ts index 3642c4ae5..01d6acb5f 100644 --- a/packages/utils/src/eslint-plugin/get-native-event-names.ts +++ b/packages/utils/src/eslint-plugin/get-native-event-names.ts @@ -9,7 +9,7 @@ let nativeEventNames: ReadonlySet | null = null; /** * Check MDN events page for details https://developer.mozilla.org/en-US/docs/Web/Events * - * Event names sourced from @mdn/browser-compat-data@6.0.12 + * Event names sourced from @mdn/browser-compat-data@6.0.17 */ export function getNativeEventNames(): ReadonlySet { return ( diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 5b494d11c..34060cea3 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -12,6 +12,7 @@ export { getAriaAttributeKeys } from './eslint-plugin/get-aria-attribute-keys'; export { getNativeEventNames } from './eslint-plugin/get-native-event-names'; export * as ASTUtils from './eslint-plugin/ast-utils'; +export * as CommentUtils from './eslint-plugin/comment-utils'; export * as RuleFixes from './eslint-plugin/rule-fixes'; export * as Selectors from './eslint-plugin/selectors'; export * as SelectorUtils from './eslint-plugin/selector-utils'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c7adcfa9a..c9eb169c3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,9 +5,9 @@ settings: excludeLinksFromLockfile: false overrides: - '@typescript-eslint/parser': 8.32.0 - '@typescript-eslint/rule-tester': 8.32.0 - '@typescript-eslint/utils': 8.32.0 + '@typescript-eslint/parser': 8.32.1 + '@typescript-eslint/rule-tester': 8.32.1 + '@typescript-eslint/utils': 8.32.1 patchedDependencies: '@typescript-eslint/rule-tester': @@ -19,56 +19,56 @@ importers: .: devDependencies: '@angular/cli': - specifier: 19.2.11 - version: 19.2.11(@types/node@20.17.45) + specifier: 19.2.13 + version: 19.2.13(@types/node@20.17.50) '@angular/compiler': - specifier: 19.2.10 - version: 19.2.10 + specifier: 19.2.13 + version: 19.2.13 '@commitlint/cli': specifier: 19.8.1 - version: 19.8.1(@types/node@20.17.45)(typescript@5.8.3) + version: 19.8.1(@types/node@20.17.50)(typescript@5.8.3) '@commitlint/config-conventional': specifier: 19.8.1 version: 19.8.1 '@mdn/browser-compat-data': - specifier: 6.0.12 - version: 6.0.12 + specifier: 6.0.17 + version: 6.0.17 '@nx/devkit': - specifier: 21.0.2 - version: 21.0.2(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))) + specifier: 21.1.2 + version: 21.1.2(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) '@nx/esbuild': - specifier: 21.0.2 - version: 21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(esbuild@0.25.4)(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) + specifier: 21.1.2 + version: 21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.25.4)(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) '@nx/eslint': - specifier: 21.0.2 - version: 21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(@zkochan/js-yaml@0.0.7)(eslint@9.26.0(jiti@2.4.2))(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) + specifier: 21.1.2 + version: 21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@zkochan/js-yaml@0.0.7)(eslint@9.27.0(jiti@2.4.2))(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) '@nx/eslint-plugin': - specifier: 21.0.2 - version: 21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(@typescript-eslint/parser@8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint-config-prettier@10.1.3(eslint@9.26.0(jiti@2.4.2)))(eslint@9.26.0(jiti@2.4.2))(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(typescript@5.8.3)(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) + specifier: 21.1.2 + version: 21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@typescript-eslint/parser@8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3))(eslint-config-prettier@10.1.5(eslint@9.27.0(jiti@2.4.2)))(eslint@9.27.0(jiti@2.4.2))(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(typescript@5.8.3)(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) '@nx/jest': - specifier: 21.0.2 - version: 21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(babel-plugin-macros@3.1.0)(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3))(typescript@5.8.3)(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) + specifier: 21.1.2 + version: 21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3))(typescript@5.8.3)(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) '@nx/js': - specifier: 21.0.2 - version: 21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) + specifier: 21.1.2 + version: 21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) '@nx/plugin': - specifier: 21.0.2 - version: 21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(@zkochan/js-yaml@0.0.7)(babel-plugin-macros@3.1.0)(eslint@9.26.0(jiti@2.4.2))(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3))(typescript@5.8.3)(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) + specifier: 21.1.2 + version: 21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(@zkochan/js-yaml@0.0.7)(babel-plugin-macros@3.1.0)(eslint@9.27.0(jiti@2.4.2))(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3))(typescript@5.8.3)(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) '@nx/workspace': - specifier: 21.0.2 - version: 21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)) + specifier: 21.1.2 + version: 21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)) '@schematics/angular': - specifier: 19.2.11 - version: 19.2.11 + specifier: 19.2.13 + version: 19.2.13 '@swc-node/register': specifier: 1.10.10 - version: 1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3) + version: 1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3) '@swc/cli': - specifier: 0.7.5 - version: 0.7.5(@swc/core@1.11.24(@swc/helpers@0.5.17)) + specifier: 0.7.7 + version: 0.7.7(@swc/core@1.11.29(@swc/helpers@0.5.17)) '@swc/core': - specifier: 1.11.24 - version: 1.11.24(@swc/helpers@0.5.17) + specifier: 1.11.29 + version: 1.11.29(@swc/helpers@0.5.17) '@swc/helpers': specifier: 0.5.17 version: 0.5.17 @@ -76,14 +76,14 @@ importers: specifier: 9.6.1 version: 9.6.1 '@types/eslint-scope': - specifier: 3.7.7 - version: 3.7.7 + specifier: 8.3.0 + version: 8.3.0 '@types/jest': specifier: 29.5.14 version: 29.5.14 '@types/node': - specifier: 20.17.45 - version: 20.17.45 + specifier: 20.17.50 + version: 20.17.50 '@types/semver': specifier: ^7.5.8 version: 7.7.0 @@ -91,26 +91,26 @@ importers: specifier: ^17.0.33 version: 17.0.33 '@typescript-eslint/rule-tester': - specifier: 8.32.0 - version: 8.32.0(patch_hash=0395d56159bca55b94596b2ce1a79005dd964f4b648c29e0c04c6dfcb85e13cf)(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + specifier: 8.32.1 + version: 8.32.1(patch_hash=0395d56159bca55b94596b2ce1a79005dd964f4b648c29e0c04c6dfcb85e13cf)(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) '@typescript-eslint/types': - specifier: 8.32.0 - version: 8.32.0 + specifier: 8.32.1 + version: 8.32.1 '@typescript-eslint/utils': - specifier: 8.32.0 - version: 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + specifier: 8.32.1 + version: 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) cz-conventional-changelog: specifier: 3.3.0 - version: 3.3.0(@types/node@20.17.45)(typescript@5.8.3) + version: 3.3.0(@types/node@20.17.50)(typescript@5.8.3) esbuild: specifier: ^0.25.0 version: 0.25.4 eslint: - specifier: 9.26.0 - version: 9.26.0(jiti@2.4.2) + specifier: 9.27.0 + version: 9.27.0(jiti@2.4.2) eslint-config-prettier: - specifier: 10.1.3 - version: 10.1.3(eslint@9.26.0(jiti@2.4.2)) + specifier: 10.1.5 + version: 10.1.5(eslint@9.27.0(jiti@2.4.2)) execa: specifier: 5.1.1 version: 5.1.1 @@ -119,7 +119,7 @@ importers: version: 9.1.7 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@20.17.45)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3)) + version: 29.7.0(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3)) json-schema-to-typescript: specifier: 15.0.4 version: 15.0.4 @@ -130,14 +130,14 @@ importers: specifier: ^2.1.0 version: 2.4.0 lint-staged: - specifier: 15.5.2 - version: 15.5.2 + specifier: 16.0.0 + version: 16.0.0 ncp: specifier: 2.0.0 version: 2.0.0 nx: - specifier: 21.0.2 - version: 21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)) + specifier: 21.1.2 + version: 21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)) picocolors: specifier: 1.1.1 version: 1.1.1 @@ -152,13 +152,13 @@ importers: version: 5.0.10 semver: specifier: ^7.6.2 - version: 7.7.1 + version: 7.7.2 tree-kill: specifier: 1.2.2 version: 1.2.2 ts-jest: specifier: 29.2.4 - version: 29.2.4(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.45)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3)))(typescript@5.8.3) + version: 29.2.4(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3)))(typescript@5.8.3) tslib: specifier: ^2.4.1 version: 2.8.1 @@ -169,8 +169,8 @@ importers: specifier: 5.8.3 version: 5.8.3 typescript-eslint: - specifier: 8.32.0 - version: 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + specifier: 8.32.1 + version: 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) verdaccio: specifier: 6.1.2 version: 6.1.2(encoding@0.1.13)(typanion@3.14.0) @@ -182,10 +182,10 @@ importers: dependencies: '@angular-devkit/core': specifier: '>= 19.0.0 < 20.0.0' - version: 19.2.11 + version: 19.2.13 '@angular-devkit/schematics': specifier: '>= 19.0.0 < 20.0.0' - version: 19.2.11 + version: 19.2.13 '@angular-eslint/builder': specifier: workspace:* version: link:../builder @@ -203,31 +203,31 @@ importers: version: link:../template-parser '@typescript-eslint/types': specifier: ^8.0.0 - version: 8.32.0 + version: 8.32.1 '@typescript-eslint/utils': - specifier: 8.32.0 - version: 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + specifier: 8.32.1 + version: 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) eslint: specifier: ^8.57.0 || ^9.0.0 - version: 9.26.0(jiti@2.4.2) + version: 9.27.0(jiti@2.4.2) typescript: specifier: '*' version: 5.8.3 typescript-eslint: specifier: ^8.0.0 - version: 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + version: 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) packages/builder: dependencies: '@angular-devkit/architect': specifier: '>= 0.1900.0 < 0.2000.0' - version: 0.1902.11 + version: 0.1902.13 '@angular-devkit/core': specifier: '>= 19.0.0 < 20.0.0' - version: 19.2.11 + version: 19.2.13 eslint: specifier: ^8.57.0 || ^9.0.0 - version: 9.26.0(jiti@2.4.2) + version: 9.27.0(jiti@2.4.2) typescript: specifier: '*' version: 5.8.3 @@ -243,11 +243,11 @@ importers: specifier: workspace:* version: link:../utils '@typescript-eslint/utils': - specifier: 8.32.0 - version: 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + specifier: 8.32.1 + version: 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) eslint: specifier: ^8.57.0 || ^9.0.0 - version: 9.26.0(jiti@2.4.2) + version: 9.27.0(jiti@2.4.2) typescript: specifier: '*' version: 5.8.3 @@ -266,10 +266,10 @@ importers: version: link:../utils '@typescript-eslint/types': specifier: ^7.11.0 || ^8.0.0 - version: 8.32.0 + version: 8.32.1 '@typescript-eslint/utils': - specifier: 8.32.0 - version: 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + specifier: 8.32.1 + version: 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) aria-query: specifier: 5.3.2 version: 5.3.2 @@ -278,7 +278,7 @@ importers: version: 4.1.0 eslint: specifier: ^8.57.0 || ^9.0.0 - version: 9.26.0(jiti@2.4.2) + version: 9.27.0(jiti@2.4.2) typescript: specifier: '*' version: 5.8.3 @@ -299,10 +299,10 @@ importers: dependencies: '@angular-devkit/core': specifier: '>= 19.0.0 < 20.0.0' - version: 19.2.11 + version: 19.2.13 '@angular-devkit/schematics': specifier: '>= 19.0.0 < 20.0.0' - version: 19.2.11 + version: 19.2.13 '@angular-eslint/eslint-plugin': specifier: workspace:* version: link:../eslint-plugin @@ -313,18 +313,18 @@ importers: specifier: 7.0.4 version: 7.0.4 semver: - specifier: 7.7.1 - version: 7.7.1 + specifier: 7.7.2 + version: 7.7.2 strip-json-comments: specifier: 3.1.1 version: 3.1.1 devDependencies: '@typescript-eslint/utils': - specifier: 8.32.0 - version: 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + specifier: 8.32.1 + version: 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) eslint: - specifier: 9.26.0 - version: 9.26.0(jiti@2.4.2) + specifier: 9.27.0 + version: 9.27.0(jiti@2.4.2) packages/template-parser: dependencies: @@ -333,7 +333,7 @@ importers: version: link:../bundled-angular-compiler eslint: specifier: ^8.57.0 || ^9.0.0 - version: 9.26.0(jiti@2.4.2) + version: 9.27.0(jiti@2.4.2) eslint-scope: specifier: ^8.0.2 version: 8.3.0 @@ -347,17 +347,17 @@ importers: specifier: workspace:* version: link:../template-parser '@typescript-eslint/parser': - specifier: 8.32.0 - version: 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + specifier: 8.32.1 + version: 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) '@typescript-eslint/rule-tester': - specifier: 8.32.0 - version: 8.32.0(patch_hash=0395d56159bca55b94596b2ce1a79005dd964f4b648c29e0c04c6dfcb85e13cf)(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + specifier: 8.32.1 + version: 8.32.1(patch_hash=0395d56159bca55b94596b2ce1a79005dd964f4b648c29e0c04c6dfcb85e13cf)(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) '@typescript-eslint/utils': - specifier: 8.32.0 - version: 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + specifier: 8.32.1 + version: 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) eslint: specifier: ^8.57.0 || ^9.0.0 - version: 9.26.0(jiti@2.4.2) + version: 9.27.0(jiti@2.4.2) typescript: specifier: '*' version: 5.8.3 @@ -368,11 +368,11 @@ importers: specifier: workspace:* version: link:../bundled-angular-compiler '@typescript-eslint/utils': - specifier: 8.32.0 - version: 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + specifier: 8.32.1 + version: 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) eslint: specifier: ^8.57.0 || ^9.0.0 - version: 9.26.0(jiti@2.4.2) + version: 9.27.0(jiti@2.4.2) typescript: specifier: '*' version: 5.8.3 @@ -383,12 +383,12 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@angular-devkit/architect@0.1902.11': - resolution: {integrity: sha512-Zz/4ySZ4i8WXU4U4WwUGQm8wjwAyrMo5kjFt7O2SGmHQx7L/hChvcMLCGVkpHr27Xdsmrl//OXfbjkPgb6DFBg==} + '@angular-devkit/architect@0.1902.13': + resolution: {integrity: sha512-ZMj+PjK22Ph2U8usG6L7LqEfvWlbaOvmiWXSrEt9YiC9QJt6rsumCkOgUIsmHQtucm/lK+9CMtyYdwH2fYycjg==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@angular-devkit/core@19.2.11': - resolution: {integrity: sha512-hXacCEbLbVo/PYPHBhaU2LThFm0Q1tIGTsWSkQjtsQpW8e4xqgSnFIWaHdsPiiGryxtdtvNE2cr9qa0ddAJOnA==} + '@angular-devkit/core@19.2.13': + resolution: {integrity: sha512-iq73hE5Uvms1w3uMUSk4i4NDXDMQ863VAifX8LOTadhG6U0xISjNJ11763egVCxQmaKmg7zbG4rda88wHJATzA==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: chokidar: ^4.0.0 @@ -396,17 +396,17 @@ packages: chokidar: optional: true - '@angular-devkit/schematics@19.2.11': - resolution: {integrity: sha512-R5g18xBhMHRtti5kDd2tlEMMxfRi8gQZ6LoT5xbox3w2kGSt7NtkSa3SUoF7Ns7JfPLrKsTQbVLFd5AggBLbHQ==} + '@angular-devkit/schematics@19.2.13': + resolution: {integrity: sha512-NhSPz3lI9njEo8eMUlZVGtlXl12UcNZv5lWTBZY/FGWUu6P5ciD/9iJINbc1jiaDH5E/DLEicUNuai0Q91X4Nw==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@angular/cli@19.2.11': - resolution: {integrity: sha512-U+Sapv4S1v+LEywyCImhQf12c6vmhuJhBS58nBxWDUVn1kmYzdUCAKNDDgMQqWQmg/Dek1YI88XYDToUvEdD1g==} + '@angular/cli@19.2.13': + resolution: {integrity: sha512-dDRCS73/lrItWx9j4SmwHR56GiZsW8ObNi2q9l/1ny813CG9K43STYFG/wJvGS7ZF3y5hvjIiJOwBx2YIouOIw==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} hasBin: true - '@angular/compiler@19.2.10': - resolution: {integrity: sha512-XI4VVaTHIsvDu25b/hOqFBIub4RoEVqVrBYo1rKRF9NI+mxg2Wy30qyJ7rYGbF7qUPomC54pen0qQgw359YhMA==} + '@angular/compiler@19.2.13': + resolution: {integrity: sha512-xAj1peVrQtb65NsULmz8ocH4QZ4ESG5YiiVzJ0tLz8t280xY+QhJiM6C0+jaCVHLXvZp0c7GEzsYjL6x1HmabQ==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} '@apidevtools/json-schema-ref-parser@11.7.2': @@ -1304,24 +1304,24 @@ packages: resolution: {integrity: sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.13.0': - resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} + '@eslint/core@0.14.0': + resolution: {integrity: sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/eslintrc@3.3.1': resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.26.0': - resolution: {integrity: sha512-I9XlJawFdSMvWjDt6wksMCrgns5ggLNfFwFvnShsleWruvXM514Qxk8V246efTw+eo9JABvVz+u3q2RiAowKxQ==} + '@eslint/js@9.27.0': + resolution: {integrity: sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.6': resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.2.8': - resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==} + '@eslint/plugin-kit@0.3.1': + resolution: {integrity: sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@humanfs/core@0.19.1': @@ -1581,12 +1581,8 @@ packages: peerDependencies: '@inquirer/prompts': '>= 3 < 8' - '@mdn/browser-compat-data@6.0.12': - resolution: {integrity: sha512-lQ6p212jKeJBG+L7UYRKchTCcnQbp6yOj5swKxGLjvuW4SmbgWgd/WyA1Dxq1GGT86C7jVTEaKry36LmsBp8SQ==} - - '@modelcontextprotocol/sdk@1.11.0': - resolution: {integrity: sha512-k/1pb70eD638anoi0e8wUGAlbMJXyvdV4p62Ko+EZ7eBe1xMx8Uhak1R5DgfoofsK5IBBnRwsYGTaLZl+6/+RQ==} - engines: {node: '>=18'} + '@mdn/browser-compat-data@6.0.17': + resolution: {integrity: sha512-yBMooSEtOoVz6vUP5OeGUnq4JBVMyE4vWsGalbrOLoGaXXNwA3YAE2mkgT4YPcOhGuPosSIk901PQI9pSMzgVg==} '@napi-rs/nice-android-arm-eabi@1.0.1': resolution: {integrity: sha512-5qpvOu5IGwDo7MEKVqqyAxF90I6aLj4n07OzpARdgDRfz8UbBztTByBp0RC59r3J1Ij8uzYi6jI7r5Lws7nn6w==} @@ -1751,30 +1747,30 @@ packages: resolution: {integrity: sha512-q9C0uHrb6B6cm3qXVM32UmpqTKuFGbtP23O2K5sLvPMz2hilKd0ptqGXSpuunOuOmPQb/aT5F/kCXFc1P2gO/A==} engines: {node: ^18.17.0 || >=20.5.0} - '@nx/devkit@21.0.2': - resolution: {integrity: sha512-FF1+CYkqRmNUznAj9kWiRHZT91KrpZkLYmAoP5RlaXwSxgiiBTXL3FOIp0/LcHUlOUHur3079beBwreApfbvBA==} + '@nx/devkit@21.1.2': + resolution: {integrity: sha512-1dgjwSsNDdp/VXydZnSfzfVwySEB3C9yjzeIw6+3+nRvZfH16a7ggZE7MF5sJTq4d+01hAgIDz3KyvGa6Jf73g==} peerDependencies: - nx: 21.0.2 + nx: 21.1.2 - '@nx/esbuild@21.0.2': - resolution: {integrity: sha512-muxyNOW253izBdXSU6LYfrMTBJi5lZpX6SS+ghBWvvZhgw+kcRwGdNwSCrPLuILTTXRMYUoAJcAXXp0UFz8orQ==} + '@nx/esbuild@21.1.2': + resolution: {integrity: sha512-6h3f8mC/5e2JxFAJaE4kLALkaoAs0nVB3aFBV+nd3+0mwywbcnMQ+dibvGCrBz2EPYlWczo43upAFEvvqpdUag==} peerDependencies: - esbuild: ^0.19.2 + esbuild: '>=0.19.2 <1.0.0' peerDependenciesMeta: esbuild: optional: true - '@nx/eslint-plugin@21.0.2': - resolution: {integrity: sha512-LbLq4WewxZ7nqw6rgg+ik0CXHCS+dkUN7Mew5z058IzBoB9XytkWdpv0I9r1Ry0qE/ZGEtGYfvT6PROUPQL8wA==} + '@nx/eslint-plugin@21.1.2': + resolution: {integrity: sha512-kwhwe6e8dZ0pf5CYPq4OBck15NEJrfuivCEGRTIDZWu3WDYJIw7OvhfyCdGuoZLeHGoCVRjIU6xV5hOzkD9RSw==} peerDependencies: - '@typescript-eslint/parser': 8.32.0 + '@typescript-eslint/parser': 8.32.1 eslint-config-prettier: ^10.0.0 peerDependenciesMeta: eslint-config-prettier: optional: true - '@nx/eslint@21.0.2': - resolution: {integrity: sha512-uZwzaqiMWXFaF+A86HK3K4AQIIOuGA3UAgnS6PUk6c7vUuLkJw1FLdFbdCA5LdyHoVu8BHdsinshxbiVl5tn2Q==} + '@nx/eslint@21.1.2': + resolution: {integrity: sha512-Mp8u0RlkhxYtZ47d2ou6t8XIpRy7N/n23OzikqMro4Wt/DK1irGyShSoNIqdGdwalAE5MG1OFXspttXB+y/wOQ==} peerDependencies: '@zkochan/js-yaml': 0.0.7 eslint: ^8.0.0 || ^9.0.0 @@ -1782,72 +1778,72 @@ packages: '@zkochan/js-yaml': optional: true - '@nx/jest@21.0.2': - resolution: {integrity: sha512-k9jJHHOE7OK9V6NOMc92AOw/Y0a5rpq3bYVs3wkRRo8F/230wQK+ea+ftsJ25rghJoCzqRnGVZe0cZcd4gBNDQ==} + '@nx/jest@21.1.2': + resolution: {integrity: sha512-y4VZita9LFb6XajulRIwjMcqHU6/f73C4SNSH6IM5BYmkN68ovICmzTGvoaL7wGTaYrA4Moh/WoKwEwQWKxRPQ==} - '@nx/js@21.0.2': - resolution: {integrity: sha512-AhqAUkqu2YDbMXqr0g/5Qhlm/ERV1FockmpK6ltYHRDaQu/yW/VKIPQtj0ndrSAKfZ74pjt8koyhFdGZjt9cMg==} + '@nx/js@21.1.2': + resolution: {integrity: sha512-ZF6Zf4Ys+RBvH0GoQHio94C/0N07Px/trAvseMuQ8PKc0tSkXycu/EBc1uAZQvgJThR5o3diAKtIQug77pPYMQ==} peerDependencies: verdaccio: ^6.0.5 peerDependenciesMeta: verdaccio: optional: true - '@nx/nx-darwin-arm64@21.0.2': - resolution: {integrity: sha512-C2A94y4TJpAsxbyAZufCzcWNDFKvHNcGCxSwdMxyaDBHXOxDasSYH6KsUTj95sZtjMiHvMn9J4xforTwF/tE7w==} + '@nx/nx-darwin-arm64@21.1.2': + resolution: {integrity: sha512-9dO32jd+h7SrvQafJph6b7Bsmp2IotTE0w7dAGb4MGBQni3JWCXaxlMMpWUZXWW1pM5uIkFJO5AASW4UOI7w2w==} cpu: [arm64] os: [darwin] - '@nx/nx-darwin-x64@21.0.2': - resolution: {integrity: sha512-eWHM0gmOZBuqFw0QrO6h/ku0+LxbjmTYaWFJerPjqfAyOHKI9CEY/nPWHuJRkq7algUQdlgX5Utf+oQ+6aJlTQ==} + '@nx/nx-darwin-x64@21.1.2': + resolution: {integrity: sha512-5sf+4PRVg9pDVgD53NE1hoPz4lC8Ni34UovQsOrZgDvwU5mqPbIhTzVYRDH86i/086AcCvjT5tEt7rEcuRwlKw==} cpu: [x64] os: [darwin] - '@nx/nx-freebsd-x64@21.0.2': - resolution: {integrity: sha512-k9bPYiHscJhinxlWC/iZTObpZo6SEBqEaObvgBH4csZpirQ5sQSy/tHB0H1pPKzDwLqkRtUHn3Z6hdWwjF1hdQ==} + '@nx/nx-freebsd-x64@21.1.2': + resolution: {integrity: sha512-E5HR44fimXlQuAgn/tP9esmvxbzt/92AIl0PBT6L3Juh/xYiXKWhda63H4+UNT8AcLRxVXwfZrGPuGCDs+7y/Q==} cpu: [x64] os: [freebsd] - '@nx/nx-linux-arm-gnueabihf@21.0.2': - resolution: {integrity: sha512-4u9TIfaeG+H9p8+LWXkBMJzqEVqfae0SMB06r7WB4RDRRe5elkU7sOtJK1LRs2MogBpTC6AErShFHXGEgQhSIQ==} + '@nx/nx-linux-arm-gnueabihf@21.1.2': + resolution: {integrity: sha512-V4n6DE+r12gwJHFjZs+e2GmWYZdhpgA2DYWbsYWRYb1XQCNUg4vPzt+YFzWZ+K2o91k93EBnlLfrag7CqxUslw==} cpu: [arm] os: [linux] - '@nx/nx-linux-arm64-gnu@21.0.2': - resolution: {integrity: sha512-415Rj9nXUUyqFB/YwkK1Ag41jgymn0BNAqTZ/9sv1NZR1K/B5hA938Cc8eqFmrk5tFbLzqIwr5EA3QGrGZKN9Q==} + '@nx/nx-linux-arm64-gnu@21.1.2': + resolution: {integrity: sha512-NFhsp27O+mS3r7PWLmJgyZy42WQ72c2pTQSpYfhaBbZPTI5DqBHdANa0sEPmV+ON24qkl5CZKvsmhzjsNmyW6A==} cpu: [arm64] os: [linux] - '@nx/nx-linux-arm64-musl@21.0.2': - resolution: {integrity: sha512-gkA/TzOY4/sNHQF0k4EeLR6Pt79c1/PiVOmVN5tdjgljOzTkbrPzeeaBWlS/JH/e005+tkZZmceAZmXYEP9vGw==} + '@nx/nx-linux-arm64-musl@21.1.2': + resolution: {integrity: sha512-BgS9npARwcnw+hoaRsbas6vdBAJRBAj5qSeL57LO8Dva+e/6PYqoNyVJ0BgJ98xPXDpzM/NnpeRsndQGpLyhDw==} cpu: [arm64] os: [linux] - '@nx/nx-linux-x64-gnu@21.0.2': - resolution: {integrity: sha512-F7PT9gJCdtUmVXecVOjU6kRbN8vs3FPI4G0Kuuh9n5OQ+y8uqTMIrSD8//yyn0S4tfz4Esd/UjtWB9Inw1WMgQ==} + '@nx/nx-linux-x64-gnu@21.1.2': + resolution: {integrity: sha512-tjBINbymQgxnIlNK/m6B0P5eiGRSHSYPNkFdh3+sra80AP/ymHGLRxxZy702Ga2xg8RVr9zEvuXYHI+QBa1YmA==} cpu: [x64] os: [linux] - '@nx/nx-linux-x64-musl@21.0.2': - resolution: {integrity: sha512-a/qEWf7E7xjnh3XonnPKbzBbIhmCset7pJuDAWHyaoMRfjdYI3/uxs8mvRUZAMwThg7KMwmxx5QLAqEcMRgoyw==} + '@nx/nx-linux-x64-musl@21.1.2': + resolution: {integrity: sha512-+0V0YAOWMh1wvpQZuayQ7y+sj2MhE3l7z0JMD9SX/4xv9zLOWGv+EiUmN/fGoU/mwsSkH2wTCo6G6quKF1E8jQ==} cpu: [x64] os: [linux] - '@nx/nx-win32-arm64-msvc@21.0.2': - resolution: {integrity: sha512-vZIv4/fS30WZ2yQA8tq2oQeyq3Pq9stx6NA7VW/Vtw2/Uv9QY0kXKysf7/pBY81h3pKNGi8FNaOOAgoT/+dz9w==} + '@nx/nx-win32-arm64-msvc@21.1.2': + resolution: {integrity: sha512-E+ECMQIMJ6R47BMW5YpDyOhTqczvFaL8k24umRkcvlRh3SraczyxBVPkYHDukDp7tCeIszc5EvdWc83C3W8U4w==} cpu: [arm64] os: [win32] - '@nx/nx-win32-x64-msvc@21.0.2': - resolution: {integrity: sha512-GJFjODSuNhcEjSm1sBHJ8GZ4quE299nnuWADoZYpXkkAhjCElyZJME/nuOpbh8r2E7cCFRbv04qTbkA/73UcFw==} + '@nx/nx-win32-x64-msvc@21.1.2': + resolution: {integrity: sha512-J9rNTBOS7Ld6CybU/cou1Fg52AHSYsiwpZISM2RNM0XIoVSDk3Jsvh4OJgS2rvV0Sp/cgDg3ieOMAreekH+TKw==} cpu: [x64] os: [win32] - '@nx/plugin@21.0.2': - resolution: {integrity: sha512-FPhCGiJnYQdfP1EjP/r6Vx0MyJrBgHp7veCbAIHtvA6cQbRnqvciYE2i1kAvPHZtsjvKN4hvsX5Hd2NWvmoHLg==} + '@nx/plugin@21.1.2': + resolution: {integrity: sha512-+iiyI5/JiIyWAwdmXe6kkLYH+8tFLlkvzzr5XcWY3pyW3RjW6XuMRa56K1t4IU9DkQt3gEFBiYWV/8NlX929Lw==} - '@nx/workspace@21.0.2': - resolution: {integrity: sha512-E1luDXSflU8Ix9z8xTsfCS9LHALCqn8kFkuPACexUPlQRB5P2eF2j+vIUHf7zw3a4xUvgjsik+ed3jfL8Q/GJg==} + '@nx/workspace@21.1.2': + resolution: {integrity: sha512-I4e/X/GN0Vx3FDZv/7bFYmXfOPmcMI3cDO/rg+TqudsuxVM7tJ7+8jtwdpU4I2IEpI6oU9FZ7Fu9R2uNqL5rrQ==} '@oxc-resolver/binding-darwin-arm64@5.2.0': resolution: {integrity: sha512-3v2eS1swAUZ/OPrBpTB5Imn4Xhbz4zKPa/mugnYCAC4pVt/miBQLBNciBRZG8oyHiGmLtjw/qanZC36uB6MITQ==} @@ -1923,8 +1919,8 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@schematics/angular@19.2.11': - resolution: {integrity: sha512-Xkqur8OJrrfR5CeMXj2FqdiqGp//w9cZ7q9RBfRr3lZgW5QUiZw7iJNQHUIDNsCBKK5yFpPIDckpdVx8jLGclg==} + '@schematics/angular@19.2.13': + resolution: {integrity: sha512-SOpK4AwH0isXo7Y2SkgXLyGLMw4GxWPAun6sCLiprmop4KlqKGGALn4xIW0yjq0s5GS0Vx0FFjz8bBfPkgnawA==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} '@sec-ant/readable-stream@0.4.1': @@ -1983,8 +1979,8 @@ packages: '@swc-node/sourcemap-support@0.5.1': resolution: {integrity: sha512-JxIvIo/Hrpv0JCHSyRpetAdQ6lB27oFYhv0PKCNf1g2gUXOjpeR1exrXccRxLMuAV5WAmGFBwRnNOJqN38+qtg==} - '@swc/cli@0.7.5': - resolution: {integrity: sha512-RlUYAxOhsecBB7qFVdDXhXXW3GDVxXpJx90q8Tlj+KuJVUPXViI7tNAvu54u3hbIZAL3LtrQKZHBWF6O5cXxZQ==} + '@swc/cli@0.7.7': + resolution: {integrity: sha512-j4yYm9bx3pxWofaJKX1BFwj/3ngUDynN4UIQ2Xd2h0h/7Gt7zkReBTpDN7g5S13mgAYxacaTHTOUsz18097E8w==} engines: {node: '>= 16.14.0'} hasBin: true peerDependencies: @@ -1994,68 +1990,68 @@ packages: chokidar: optional: true - '@swc/core-darwin-arm64@1.11.24': - resolution: {integrity: sha512-dhtVj0PC1APOF4fl5qT2neGjRLgHAAYfiVP8poJelhzhB/318bO+QCFWAiimcDoyMgpCXOhTp757gnoJJrheWA==} + '@swc/core-darwin-arm64@1.11.29': + resolution: {integrity: sha512-whsCX7URzbuS5aET58c75Dloby3Gtj/ITk2vc4WW6pSDQKSPDuONsIcZ7B2ng8oz0K6ttbi4p3H/PNPQLJ4maQ==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-x64@1.11.24': - resolution: {integrity: sha512-H/3cPs8uxcj2Fe3SoLlofN5JG6Ny5bl8DuZ6Yc2wr7gQFBmyBkbZEz+sPVgsID7IXuz7vTP95kMm1VL74SO5AQ==} + '@swc/core-darwin-x64@1.11.29': + resolution: {integrity: sha512-S3eTo/KYFk+76cWJRgX30hylN5XkSmjYtCBnM4jPLYn7L6zWYEPajsFLmruQEiTEDUg0gBEWLMNyUeghtswouw==} engines: {node: '>=10'} cpu: [x64] os: [darwin] - '@swc/core-linux-arm-gnueabihf@1.11.24': - resolution: {integrity: sha512-PHJgWEpCsLo/NGj+A2lXZ2mgGjsr96ULNW3+T3Bj2KTc8XtMUkE8tmY2Da20ItZOvPNC/69KroU7edyo1Flfbw==} + '@swc/core-linux-arm-gnueabihf@1.11.29': + resolution: {integrity: sha512-o9gdshbzkUMG6azldHdmKklcfrcMx+a23d/2qHQHPDLUPAN+Trd+sDQUYArK5Fcm7TlpG4sczz95ghN0DMkM7g==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm64-gnu@1.11.24': - resolution: {integrity: sha512-C2FJb08+n5SD4CYWCTZx1uR88BN41ZieoHvI8A55hfVf2woT8+6ZiBzt74qW2g+ntZ535Jts5VwXAKdu41HpBg==} + '@swc/core-linux-arm64-gnu@1.11.29': + resolution: {integrity: sha512-sLoaciOgUKQF1KX9T6hPGzvhOQaJn+3DHy4LOHeXhQqvBgr+7QcZ+hl4uixPKTzxk6hy6Hb0QOvQEdBAAR1gXw==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-arm64-musl@1.11.24': - resolution: {integrity: sha512-ypXLIdszRo0re7PNNaXN0+2lD454G8l9LPK/rbfRXnhLWDBPURxzKlLlU/YGd2zP98wPcVooMmegRSNOKfvErw==} + '@swc/core-linux-arm64-musl@1.11.29': + resolution: {integrity: sha512-PwjB10BC0N+Ce7RU/L23eYch6lXFHz7r3NFavIcwDNa/AAqywfxyxh13OeRy+P0cg7NDpWEETWspXeI4Ek8otw==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-x64-gnu@1.11.24': - resolution: {integrity: sha512-IM7d+STVZD48zxcgo69L0yYptfhaaE9cMZ+9OoMxirNafhKKXwoZuufol1+alEFKc+Wbwp+aUPe/DeWC/Lh3dg==} + '@swc/core-linux-x64-gnu@1.11.29': + resolution: {integrity: sha512-i62vBVoPaVe9A3mc6gJG07n0/e7FVeAvdD9uzZTtGLiuIfVfIBta8EMquzvf+POLycSk79Z6lRhGPZPJPYiQaA==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-linux-x64-musl@1.11.24': - resolution: {integrity: sha512-DZByJaMVzSfjQKKQn3cqSeqwy6lpMaQDQQ4HPlch9FWtDx/dLcpdIhxssqZXcR2rhaQVIaRQsCqwV6orSDGAGw==} + '@swc/core-linux-x64-musl@1.11.29': + resolution: {integrity: sha512-YER0XU1xqFdK0hKkfSVX1YIyCvMDI7K07GIpefPvcfyNGs38AXKhb2byySDjbVxkdl4dycaxxhRyhQ2gKSlsFQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-win32-arm64-msvc@1.11.24': - resolution: {integrity: sha512-Q64Ytn23y9aVDKN5iryFi8mRgyHw3/kyjTjT4qFCa8AEb5sGUuSj//AUZ6c0J7hQKMHlg9do5Etvoe61V98/JQ==} + '@swc/core-win32-arm64-msvc@1.11.29': + resolution: {integrity: sha512-po+WHw+k9g6FAg5IJ+sMwtA/fIUL3zPQ4m/uJgONBATCVnDDkyW6dBA49uHNVtSEvjvhuD8DVWdFP847YTcITw==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-ia32-msvc@1.11.24': - resolution: {integrity: sha512-9pKLIisE/Hh2vJhGIPvSoTK4uBSPxNVyXHmOrtdDot4E1FUUI74Vi8tFdlwNbaj8/vusVnb8xPXsxF1uB0VgiQ==} + '@swc/core-win32-ia32-msvc@1.11.29': + resolution: {integrity: sha512-h+NjOrbqdRBYr5ItmStmQt6x3tnhqgwbj9YxdGPepbTDamFv7vFnhZR0YfB3jz3UKJ8H3uGJ65Zw1VsC+xpFkg==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-x64-msvc@1.11.24': - resolution: {integrity: sha512-sybnXtOsdB+XvzVFlBVGgRHLqp3yRpHK7CrmpuDKszhj/QhmsaZzY/GHSeALlMtLup13M0gqbcQvsTNlAHTg3w==} + '@swc/core-win32-x64-msvc@1.11.29': + resolution: {integrity: sha512-Q8cs2BDV9wqDvqobkXOYdC+pLUSEpX/KvI0Dgfun1F+LzuLotRFuDhrvkU9ETJA6OnD2+Fn/ieHgloiKA/Mn/g==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core@1.11.24': - resolution: {integrity: sha512-MaQEIpfcEMzx3VWWopbofKJvaraqmL6HbLlw2bFZ7qYqYw3rkhM0cQVEgyzbHtTWwCwPMFZSC2DUbhlZgrMfLg==} + '@swc/core@1.11.29': + resolution: {integrity: sha512-g4mThMIpWbNhV8G2rWp5a5/Igv8/2UFRJx2yImrLGMgrDDYZIopqZ/z0jZxDgqNA1QDx93rpwNF7jGsxVWcMlA==} engines: {node: '>=10'} peerDependencies: '@swc/helpers': '>=0.5.17' @@ -2120,8 +2116,8 @@ packages: '@types/conventional-commits-parser@5.0.1': resolution: {integrity: sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ==} - '@types/eslint-scope@3.7.7': - resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} + '@types/eslint-scope@8.3.0': + resolution: {integrity: sha512-FaY/QEfIyGJzJdkObuvtaROKv7A0zArw+be0tgXfWd1s1/AqPzEbyf7eyK0Pg0YezUpKrSwK4kgBn/kjzQOjtQ==} '@types/eslint@9.6.1': resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} @@ -2153,8 +2149,8 @@ packages: '@types/lodash@4.17.13': resolution: {integrity: sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==} - '@types/node@20.17.45': - resolution: {integrity: sha512-vO9+E1smq+149wsmmLdM8SKVW7gRzLjfo0mU7kiykhV6rL+GEUhUmW7VywJNSxJHQzt9QBIHEo+3SG4MrFTqbA==} + '@types/node@20.17.50': + resolution: {integrity: sha512-Mxiq0ULv/zo1OzOhwPqOA13I81CV/W3nvd3ChtQZRT5Cwz3cr0FKo/wMSsbTqL3EXpaBAEQhva2B8ByRkOIh9A==} '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -2171,78 +2167,57 @@ packages: '@types/yargs@17.0.33': resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} - '@typescript-eslint/eslint-plugin@8.32.0': - resolution: {integrity: sha512-/jU9ettcntkBFmWUzzGgsClEi2ZFiikMX5eEQsmxIAWMOn4H3D4rvHssstmAHGVvrYnaMqdWWWg0b5M6IN/MTQ==} + '@typescript-eslint/eslint-plugin@8.32.1': + resolution: {integrity: sha512-6u6Plg9nP/J1GRpe/vcjjabo6Uc5YQPAMxsgQyGC/I0RuukiG1wIe3+Vtg3IrSCVJDmqK3j8adrtzXSENRtFgg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': 8.32.0 + '@typescript-eslint/parser': 8.32.1 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/parser@8.32.0': - resolution: {integrity: sha512-B2MdzyWxCE2+SqiZHAjPphft+/2x2FlO9YBx7eKE1BCb+rqBlQdhtAEhzIEdozHd55DXPmxBdpMygFJjfjjA9A==} + '@typescript-eslint/parser@8.32.1': + resolution: {integrity: sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/rule-tester@8.32.0': - resolution: {integrity: sha512-kfR6D4RdosBZiwa3/fuuRggzg3YPlMKaEdohVjv5nSyu9ZFD5fr6E/kydvMt0nkM1PLNzMAEtODriEz7RI/cqw==} + '@typescript-eslint/rule-tester@8.32.1': + resolution: {integrity: sha512-XUCGJUbBBn6HNFnihX2bm50F4J1LndwdzTlw7kfSnqukXoRkW/SEwMIhDLSiTcSPXZPVbO8R/Aw35J9zm4kD4w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - '@typescript-eslint/scope-manager@8.32.0': - resolution: {integrity: sha512-jc/4IxGNedXkmG4mx4nJTILb6TMjL66D41vyeaPWvDUmeYQzF3lKtN15WsAeTr65ce4mPxwopPSo1yUUAWw0hQ==} + '@typescript-eslint/scope-manager@8.32.1': + resolution: {integrity: sha512-7IsIaIDeZn7kffk7qXC3o6Z4UblZJKV3UBpkvRNpr5NSyLji7tvTcvmnMNYuYLyh26mN8W723xpo3i4MlD33vA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@8.31.0': - resolution: {integrity: sha512-DJ1N1GdjI7IS7uRlzJuEDCgDQix3ZVYVtgeWEyhyn4iaoitpMBX6Ndd488mXSx0xah/cONAkEaYyylDyAeHMHg==} + '@typescript-eslint/type-utils@8.32.1': + resolution: {integrity: sha512-mv9YpQGA8iIsl5KyUPi+FGLm7+bA4fgXaeRcFKRDRwDMu4iwrSHeDPipwueNXhdIIZltwCJv+NkxftECbIZWfA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/type-utils@8.32.0': - resolution: {integrity: sha512-t2vouuYQKEKSLtJaa5bB4jHeha2HJczQ6E5IXPDPgIty9EqcJxpr1QHQ86YyIPwDwxvUmLfP2YADQ5ZY4qddZg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' - - '@typescript-eslint/types@8.31.0': - resolution: {integrity: sha512-Ch8oSjVyYyJxPQk8pMiP2FFGYatqXQfQIaMp+TpuuLlDachRWpUAeEu1u9B/v/8LToehUIWyiKcA/w5hUFRKuQ==} + '@typescript-eslint/types@8.32.1': + resolution: {integrity: sha512-YmybwXUJcgGqgAp6bEsgpPXEg6dcCyPyCSr0CAAueacR/CCBi25G3V8gGQ2kRzQRBNol7VQknxMs9HvVa9Rvfg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.32.0': - resolution: {integrity: sha512-O5Id6tGadAZEMThM6L9HmVf5hQUXNSxLVKeGJYWNhhVseps/0LddMkp7//VDkzwJ69lPL0UmZdcZwggj9akJaA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/typescript-estree@8.31.0': - resolution: {integrity: sha512-xLmgn4Yl46xi6aDSZ9KkyfhhtnYI15/CvHbpOy/eR5NWhK/BK8wc709KKwhAR0m4ZKRP7h07bm4BWUYOCuRpQQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <5.9.0' - - '@typescript-eslint/typescript-estree@8.32.0': - resolution: {integrity: sha512-pU9VD7anSCOIoBFnhTGfOzlVFQIA1XXiQpH/CezqOBaDppRwTglJzCC6fUQGpfwey4T183NKhF1/mfatYmjRqQ==} + '@typescript-eslint/typescript-estree@8.32.1': + resolution: {integrity: sha512-Y3AP9EIfYwBb4kWGb+simvPaqQoT5oJuzzj9m0i6FCY6SPvlomY2Ei4UEMm7+FXtlNJbor80ximyslzaQF6xhg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/utils@8.32.0': - resolution: {integrity: sha512-8S9hXau6nQ/sYVtC3D6ISIDoJzS1NsCK+gluVhLN2YkBPX+/1wkwyUiDKnxRh15579WoOIyVWnoyIf3yGI9REw==} + '@typescript-eslint/utils@8.32.1': + resolution: {integrity: sha512-DsSFNIgLSrc89gpq1LJB7Hm1YpuhK086DRDJSNrewcGvYloWW1vZLHBTIvarKZDcAORIy/uWNx8Gad+4oMpkSA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/visitor-keys@8.31.0': - resolution: {integrity: sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/visitor-keys@8.32.0': - resolution: {integrity: sha512-1rYQTCLFFzOI5Nl0c8LUpJT8HxpwVRn9E4CkMsYfuN6ctmQqExjSTzzSk0Tz2apmXy7WU6/6fyaZVVA/thPN+w==} + '@typescript-eslint/visitor-keys@8.32.1': + resolution: {integrity: sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@verdaccio/auth@8.0.0-next-8.15': @@ -2387,10 +2362,6 @@ packages: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} - accepts@2.0.0: - resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} - engines: {node: '>= 0.6'} - acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -2634,10 +2605,6 @@ packages: resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - body-parser@2.2.0: - resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} - engines: {node: '>=18'} - brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -2880,10 +2847,6 @@ packages: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} - content-disposition@1.0.0: - resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} - engines: {node: '>= 0.6'} - content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} @@ -2910,10 +2873,6 @@ packages: cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - cookie-signature@1.2.2: - resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} - engines: {node: '>=6.6.0'} - cookie@0.7.1: resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} engines: {node: '>= 0.6'} @@ -3223,8 +3182,8 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - eslint-config-prettier@10.1.3: - resolution: {integrity: sha512-vDo4d9yQE+cS2tdIT4J02H/16veRvkHgiLDRpej+WL67oCfbOb97itZXn8wMPJ/GsiEBVjrjs//AVNw2Cp1EcA==} + eslint-config-prettier@10.1.5: + resolution: {integrity: sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==} hasBin: true peerDependencies: eslint: '>=7.0.0' @@ -3241,8 +3200,8 @@ packages: resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.26.0: - resolution: {integrity: sha512-Hx0MOjPh6uK9oq9nVsATZKE/Wlbai7KFjfCuw9UHaguDW3x+HF0O5nIi3ud39TWgrTjTO5nHxmL3R1eANinWHQ==} + eslint@9.27.0: + resolution: {integrity: sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -3295,22 +3254,10 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - eventsource-parser@3.0.1: - resolution: {integrity: sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==} - engines: {node: '>=18.0.0'} - - eventsource@3.0.6: - resolution: {integrity: sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==} - engines: {node: '>=18.0.0'} - execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} - execa@8.0.1: - resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} - engines: {node: '>=16.17'} - exit@0.1.2: resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} engines: {node: '>= 0.8.0'} @@ -3329,20 +3276,10 @@ packages: express-rate-limit@5.5.1: resolution: {integrity: sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg==} - express-rate-limit@7.5.0: - resolution: {integrity: sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==} - engines: {node: '>= 16'} - peerDependencies: - express: ^4.11 || 5 || ^5.0.0-beta.1 - express@4.21.2: resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} engines: {node: '>= 0.10.0'} - express@5.1.0: - resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} - engines: {node: '>= 18'} - ext-list@2.2.2: resolution: {integrity: sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==} engines: {node: '>=0.10.0'} @@ -3438,10 +3375,6 @@ packages: resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} engines: {node: '>= 0.8'} - finalhandler@2.1.0: - resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} - engines: {node: '>= 0.8'} - find-node-modules@2.1.3: resolution: {integrity: sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==} @@ -3511,10 +3444,6 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} - fresh@2.0.0: - resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} - engines: {node: '>= 0.8'} - front-matter@4.0.2: resolution: {integrity: sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==} @@ -3576,10 +3505,6 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} - get-stream@8.0.1: - resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} - engines: {node: '>=16'} - get-stream@9.0.1: resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} engines: {node: '>=18'} @@ -3743,10 +3668,6 @@ packages: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} - human-signals@5.0.0: - resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} - engines: {node: '>=16.17.0'} - husky@9.1.7: resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} engines: {node: '>=18'} @@ -3897,17 +3818,10 @@ packages: is-promise@2.2.2: resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} - is-promise@4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - is-stream@4.0.1: resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} engines: {node: '>=18'} @@ -4234,15 +4148,19 @@ packages: resolution: {integrity: sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - lint-staged@15.5.2: - resolution: {integrity: sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==} - engines: {node: '>=18.12.0'} + lint-staged@16.0.0: + resolution: {integrity: sha512-sUCprePs6/rbx4vKC60Hez6X10HPkpDJaGcy3D1NdwR7g1RcNkWL8q9mJMreOqmHBTs+1sNFp+wOiX9fr+hoOQ==} + engines: {node: '>=20.18'} hasBin: true listr2@8.2.5: resolution: {integrity: sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ==} engines: {node: '>=18.0.0'} + listr2@8.3.3: + resolution: {integrity: sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==} + engines: {node: '>=18.0.0'} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -4374,10 +4292,6 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} - media-typer@1.1.0: - resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} - engines: {node: '>= 0.8'} - meow@12.1.1: resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} engines: {node: '>=16.10'} @@ -4385,10 +4299,6 @@ packages: merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} - merge-descriptors@2.0.0: - resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} - engines: {node: '>=18'} - merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -4423,10 +4333,6 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} - mime-types@3.0.1: - resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} - engines: {node: '>= 0.6'} - mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} @@ -4446,10 +4352,6 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} - mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} - mimic-function@5.0.1: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} @@ -4561,6 +4463,10 @@ packages: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} + nano-spawn@1.0.1: + resolution: {integrity: sha512-BfcvzBlUTxSDWfT+oH7vd6CbUV+rThLLHCIym/QO6GGLBsyVXleZs00fto2i2jzC/wPiBYk5jyOmpXWg4YopiA==} + engines: {node: '>=20.18'} + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -4659,13 +4565,8 @@ packages: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} - npm-run-path@5.3.0: - resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - nx@21.0.2: - resolution: {integrity: sha512-Kkf7d4XgQH5KglwuWxtjY0scHClEf3G3I3wZpBWRdUd52t/a1kxUPL4lDcJ7hwkW+FWgSxFB+jmp/kMbroMXOg==} - engines: {node: ^20.19.0 || ^22.12.0} + nx@21.1.2: + resolution: {integrity: sha512-oczAEOOkQHElxCXs2g2jXDRabDRsmub/h5SAgqAUDSJ2CRnYGVVlgZX7l+o+A9kSqfONyLy5FlJ1pSWlvPuG4w==} hasBin: true peerDependencies: '@swc-node/register': ^1.8.0 @@ -4703,10 +4604,6 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} - onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} - onetime@7.0.0: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} @@ -4817,10 +4714,6 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} @@ -4831,10 +4724,6 @@ packages: path-to-regexp@0.1.12: resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} - path-to-regexp@8.2.0: - resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} - engines: {node: '>=16'} - path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -4892,10 +4781,6 @@ packages: piscina@4.7.0: resolution: {integrity: sha512-b8hvkpp9zS0zsfa939b/jXbe64Z2gZv0Ha7FYPNUiDIB1y2AtxcOZdfP8xN8HFjUaqQiT9gRlfjAsoL8vdJ1Iw==} - pkce-challenge@5.0.0: - resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} - engines: {node: '>=16.20.0'} - pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -5012,10 +4897,6 @@ packages: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} engines: {node: '>= 0.8'} - raw-body@3.0.0: - resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} - engines: {node: '>= 0.8'} - react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} @@ -5124,10 +5005,6 @@ packages: resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} hasBin: true - router@2.2.0: - resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} - engines: {node: '>= 18'} - run-async@2.4.1: resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} engines: {node: '>=0.12.0'} @@ -5177,22 +5054,19 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + send@0.19.0: resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} - send@1.2.0: - resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} - engines: {node: '>= 18'} - serve-static@1.16.2: resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} - serve-static@2.2.0: - resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} - engines: {node: '>= 18'} - set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -5398,10 +5272,6 @@ packages: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} - strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} - strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -5602,12 +5472,8 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} - type-is@2.0.1: - resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} - engines: {node: '>= 0.6'} - - typescript-eslint@8.32.0: - resolution: {integrity: sha512-UMq2kxdXCzinFFPsXc9o2ozIpYCCOiEC46MG3yEh5Vipq6BO27otTtEBZA1fQ66DulEUgE97ucQ/3YY66CPg0A==} + typescript-eslint@8.32.1: + resolution: {integrity: sha512-D7el+eaDHAmXvrZBy1zpzSNIRqnCOrkwTgZxTu3MUqRWk8k0q9m9Ho4+vPf7iHtgUfrK/o8IZaEApsxPlHTFCg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -5831,8 +5697,8 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} - yaml@2.7.0: - resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==} + yaml@2.7.1: + resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==} engines: {node: '>= 14'} hasBin: true @@ -5864,14 +5730,6 @@ packages: resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==} engines: {node: '>=18'} - zod-to-json-schema@3.24.5: - resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} - peerDependencies: - zod: ^3.24.1 - - zod@3.24.4: - resolution: {integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==} - snapshots: '@ampproject/remapping@2.3.0': @@ -5879,14 +5737,14 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@angular-devkit/architect@0.1902.11': + '@angular-devkit/architect@0.1902.13': dependencies: - '@angular-devkit/core': 19.2.11 + '@angular-devkit/core': 19.2.13 rxjs: 7.8.1 transitivePeerDependencies: - chokidar - '@angular-devkit/core@19.2.11': + '@angular-devkit/core@19.2.13': dependencies: ajv: 8.17.1 ajv-formats: 3.0.1(ajv@8.17.1) @@ -5895,9 +5753,9 @@ snapshots: rxjs: 7.8.1 source-map: 0.7.4 - '@angular-devkit/schematics@19.2.11': + '@angular-devkit/schematics@19.2.13': dependencies: - '@angular-devkit/core': 19.2.11 + '@angular-devkit/core': 19.2.13 jsonc-parser: 3.3.1 magic-string: 0.30.17 ora: 5.4.1 @@ -5905,14 +5763,14 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular/cli@19.2.11(@types/node@20.17.45)': + '@angular/cli@19.2.13(@types/node@20.17.50)': dependencies: - '@angular-devkit/architect': 0.1902.11 - '@angular-devkit/core': 19.2.11 - '@angular-devkit/schematics': 19.2.11 - '@inquirer/prompts': 7.3.2(@types/node@20.17.45) - '@listr2/prompt-adapter-inquirer': 2.0.18(@inquirer/prompts@7.3.2(@types/node@20.17.45)) - '@schematics/angular': 19.2.11 + '@angular-devkit/architect': 0.1902.13 + '@angular-devkit/core': 19.2.13 + '@angular-devkit/schematics': 19.2.13 + '@inquirer/prompts': 7.3.2(@types/node@20.17.50) + '@listr2/prompt-adapter-inquirer': 2.0.18(@inquirer/prompts@7.3.2(@types/node@20.17.50)) + '@schematics/angular': 19.2.13 '@yarnpkg/lockfile': 1.1.0 ini: 5.0.0 jsonc-parser: 3.3.1 @@ -5930,7 +5788,7 @@ snapshots: - chokidar - supports-color - '@angular/compiler@19.2.10': + '@angular/compiler@19.2.13': dependencies: tslib: 2.8.1 @@ -6727,11 +6585,11 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} - '@commitlint/cli@19.8.1(@types/node@20.17.45)(typescript@5.8.3)': + '@commitlint/cli@19.8.1(@types/node@20.17.50)(typescript@5.8.3)': dependencies: '@commitlint/format': 19.8.1 '@commitlint/lint': 19.8.1 - '@commitlint/load': 19.8.1(@types/node@20.17.45)(typescript@5.8.3) + '@commitlint/load': 19.8.1(@types/node@20.17.50)(typescript@5.8.3) '@commitlint/read': 19.8.1 '@commitlint/types': 19.8.1 tinyexec: 1.0.1 @@ -6778,7 +6636,7 @@ snapshots: '@commitlint/is-ignored@19.8.1': dependencies: '@commitlint/types': 19.8.1 - semver: 7.7.1 + semver: 7.7.2 '@commitlint/lint@19.8.1': dependencies: @@ -6787,7 +6645,7 @@ snapshots: '@commitlint/rules': 19.8.1 '@commitlint/types': 19.8.1 - '@commitlint/load@19.5.0(@types/node@20.17.45)(typescript@5.8.3)': + '@commitlint/load@19.5.0(@types/node@20.17.50)(typescript@5.8.3)': dependencies: '@commitlint/config-validator': 19.5.0 '@commitlint/execute-rule': 19.5.0 @@ -6795,7 +6653,7 @@ snapshots: '@commitlint/types': 19.8.0 chalk: 5.4.1 cosmiconfig: 9.0.0(typescript@5.8.3) - cosmiconfig-typescript-loader: 5.1.0(@types/node@20.17.45)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3) + cosmiconfig-typescript-loader: 5.1.0(@types/node@20.17.50)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 @@ -6804,7 +6662,7 @@ snapshots: - typescript optional: true - '@commitlint/load@19.8.1(@types/node@20.17.45)(typescript@5.8.3)': + '@commitlint/load@19.8.1(@types/node@20.17.50)(typescript@5.8.3)': dependencies: '@commitlint/config-validator': 19.8.1 '@commitlint/execute-rule': 19.8.1 @@ -6812,7 +6670,7 @@ snapshots: '@commitlint/types': 19.8.1 chalk: 5.4.1 cosmiconfig: 9.0.0(typescript@5.8.3) - cosmiconfig-typescript-loader: 6.1.0(@types/node@20.17.45)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3) + cosmiconfig-typescript-loader: 6.1.0(@types/node@20.17.50)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 @@ -6993,14 +6851,14 @@ snapshots: '@esbuild/win32-x64@0.25.4': optional: true - '@eslint-community/eslint-utils@4.4.1(eslint@9.26.0(jiti@2.4.2))': + '@eslint-community/eslint-utils@4.4.1(eslint@9.27.0(jiti@2.4.2))': dependencies: - eslint: 9.26.0(jiti@2.4.2) + eslint: 9.27.0(jiti@2.4.2) eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.7.0(eslint@9.26.0(jiti@2.4.2))': + '@eslint-community/eslint-utils@4.7.0(eslint@9.27.0(jiti@2.4.2))': dependencies: - eslint: 9.26.0(jiti@2.4.2) + eslint: 9.27.0(jiti@2.4.2) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} @@ -7015,7 +6873,7 @@ snapshots: '@eslint/config-helpers@0.2.1': {} - '@eslint/core@0.13.0': + '@eslint/core@0.14.0': dependencies: '@types/json-schema': 7.0.15 @@ -7033,13 +6891,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.26.0': {} + '@eslint/js@9.27.0': {} '@eslint/object-schema@2.1.6': {} - '@eslint/plugin-kit@0.2.8': + '@eslint/plugin-kit@0.3.1': dependencies: - '@eslint/core': 0.13.0 + '@eslint/core': 0.14.0 levn: 0.4.1 '@humanfs/core@0.19.1': {} @@ -7055,27 +6913,27 @@ snapshots: '@humanwhocodes/retry@0.4.2': {} - '@inquirer/checkbox@4.1.2(@types/node@20.17.45)': + '@inquirer/checkbox@4.1.2(@types/node@20.17.50)': dependencies: - '@inquirer/core': 10.1.7(@types/node@20.17.45) + '@inquirer/core': 10.1.7(@types/node@20.17.50) '@inquirer/figures': 1.0.10 - '@inquirer/type': 3.0.4(@types/node@20.17.45) + '@inquirer/type': 3.0.4(@types/node@20.17.50) ansi-escapes: 4.3.2 yoctocolors-cjs: 2.1.2 optionalDependencies: - '@types/node': 20.17.45 + '@types/node': 20.17.50 - '@inquirer/confirm@5.1.6(@types/node@20.17.45)': + '@inquirer/confirm@5.1.6(@types/node@20.17.50)': dependencies: - '@inquirer/core': 10.1.7(@types/node@20.17.45) - '@inquirer/type': 3.0.4(@types/node@20.17.45) + '@inquirer/core': 10.1.7(@types/node@20.17.50) + '@inquirer/type': 3.0.4(@types/node@20.17.50) optionalDependencies: - '@types/node': 20.17.45 + '@types/node': 20.17.50 - '@inquirer/core@10.1.7(@types/node@20.17.45)': + '@inquirer/core@10.1.7(@types/node@20.17.50)': dependencies: '@inquirer/figures': 1.0.10 - '@inquirer/type': 3.0.4(@types/node@20.17.45) + '@inquirer/type': 3.0.4(@types/node@20.17.50) ansi-escapes: 4.3.2 cli-width: 4.1.0 mute-stream: 2.0.0 @@ -7083,97 +6941,97 @@ snapshots: wrap-ansi: 6.2.0 yoctocolors-cjs: 2.1.2 optionalDependencies: - '@types/node': 20.17.45 + '@types/node': 20.17.50 - '@inquirer/editor@4.2.7(@types/node@20.17.45)': + '@inquirer/editor@4.2.7(@types/node@20.17.50)': dependencies: - '@inquirer/core': 10.1.7(@types/node@20.17.45) - '@inquirer/type': 3.0.4(@types/node@20.17.45) + '@inquirer/core': 10.1.7(@types/node@20.17.50) + '@inquirer/type': 3.0.4(@types/node@20.17.50) external-editor: 3.1.0 optionalDependencies: - '@types/node': 20.17.45 + '@types/node': 20.17.50 - '@inquirer/expand@4.0.9(@types/node@20.17.45)': + '@inquirer/expand@4.0.9(@types/node@20.17.50)': dependencies: - '@inquirer/core': 10.1.7(@types/node@20.17.45) - '@inquirer/type': 3.0.4(@types/node@20.17.45) + '@inquirer/core': 10.1.7(@types/node@20.17.50) + '@inquirer/type': 3.0.4(@types/node@20.17.50) yoctocolors-cjs: 2.1.2 optionalDependencies: - '@types/node': 20.17.45 + '@types/node': 20.17.50 '@inquirer/figures@1.0.10': {} - '@inquirer/input@4.1.6(@types/node@20.17.45)': + '@inquirer/input@4.1.6(@types/node@20.17.50)': dependencies: - '@inquirer/core': 10.1.7(@types/node@20.17.45) - '@inquirer/type': 3.0.4(@types/node@20.17.45) + '@inquirer/core': 10.1.7(@types/node@20.17.50) + '@inquirer/type': 3.0.4(@types/node@20.17.50) optionalDependencies: - '@types/node': 20.17.45 + '@types/node': 20.17.50 - '@inquirer/number@3.0.9(@types/node@20.17.45)': + '@inquirer/number@3.0.9(@types/node@20.17.50)': dependencies: - '@inquirer/core': 10.1.7(@types/node@20.17.45) - '@inquirer/type': 3.0.4(@types/node@20.17.45) + '@inquirer/core': 10.1.7(@types/node@20.17.50) + '@inquirer/type': 3.0.4(@types/node@20.17.50) optionalDependencies: - '@types/node': 20.17.45 + '@types/node': 20.17.50 - '@inquirer/password@4.0.9(@types/node@20.17.45)': + '@inquirer/password@4.0.9(@types/node@20.17.50)': dependencies: - '@inquirer/core': 10.1.7(@types/node@20.17.45) - '@inquirer/type': 3.0.4(@types/node@20.17.45) + '@inquirer/core': 10.1.7(@types/node@20.17.50) + '@inquirer/type': 3.0.4(@types/node@20.17.50) ansi-escapes: 4.3.2 optionalDependencies: - '@types/node': 20.17.45 - - '@inquirer/prompts@7.3.2(@types/node@20.17.45)': - dependencies: - '@inquirer/checkbox': 4.1.2(@types/node@20.17.45) - '@inquirer/confirm': 5.1.6(@types/node@20.17.45) - '@inquirer/editor': 4.2.7(@types/node@20.17.45) - '@inquirer/expand': 4.0.9(@types/node@20.17.45) - '@inquirer/input': 4.1.6(@types/node@20.17.45) - '@inquirer/number': 3.0.9(@types/node@20.17.45) - '@inquirer/password': 4.0.9(@types/node@20.17.45) - '@inquirer/rawlist': 4.0.9(@types/node@20.17.45) - '@inquirer/search': 3.0.9(@types/node@20.17.45) - '@inquirer/select': 4.0.9(@types/node@20.17.45) + '@types/node': 20.17.50 + + '@inquirer/prompts@7.3.2(@types/node@20.17.50)': + dependencies: + '@inquirer/checkbox': 4.1.2(@types/node@20.17.50) + '@inquirer/confirm': 5.1.6(@types/node@20.17.50) + '@inquirer/editor': 4.2.7(@types/node@20.17.50) + '@inquirer/expand': 4.0.9(@types/node@20.17.50) + '@inquirer/input': 4.1.6(@types/node@20.17.50) + '@inquirer/number': 3.0.9(@types/node@20.17.50) + '@inquirer/password': 4.0.9(@types/node@20.17.50) + '@inquirer/rawlist': 4.0.9(@types/node@20.17.50) + '@inquirer/search': 3.0.9(@types/node@20.17.50) + '@inquirer/select': 4.0.9(@types/node@20.17.50) optionalDependencies: - '@types/node': 20.17.45 + '@types/node': 20.17.50 - '@inquirer/rawlist@4.0.9(@types/node@20.17.45)': + '@inquirer/rawlist@4.0.9(@types/node@20.17.50)': dependencies: - '@inquirer/core': 10.1.7(@types/node@20.17.45) - '@inquirer/type': 3.0.4(@types/node@20.17.45) + '@inquirer/core': 10.1.7(@types/node@20.17.50) + '@inquirer/type': 3.0.4(@types/node@20.17.50) yoctocolors-cjs: 2.1.2 optionalDependencies: - '@types/node': 20.17.45 + '@types/node': 20.17.50 - '@inquirer/search@3.0.9(@types/node@20.17.45)': + '@inquirer/search@3.0.9(@types/node@20.17.50)': dependencies: - '@inquirer/core': 10.1.7(@types/node@20.17.45) + '@inquirer/core': 10.1.7(@types/node@20.17.50) '@inquirer/figures': 1.0.10 - '@inquirer/type': 3.0.4(@types/node@20.17.45) + '@inquirer/type': 3.0.4(@types/node@20.17.50) yoctocolors-cjs: 2.1.2 optionalDependencies: - '@types/node': 20.17.45 + '@types/node': 20.17.50 - '@inquirer/select@4.0.9(@types/node@20.17.45)': + '@inquirer/select@4.0.9(@types/node@20.17.50)': dependencies: - '@inquirer/core': 10.1.7(@types/node@20.17.45) + '@inquirer/core': 10.1.7(@types/node@20.17.50) '@inquirer/figures': 1.0.10 - '@inquirer/type': 3.0.4(@types/node@20.17.45) + '@inquirer/type': 3.0.4(@types/node@20.17.50) ansi-escapes: 4.3.2 yoctocolors-cjs: 2.1.2 optionalDependencies: - '@types/node': 20.17.45 + '@types/node': 20.17.50 '@inquirer/type@1.5.5': dependencies: mute-stream: 1.0.0 - '@inquirer/type@3.0.4(@types/node@20.17.45)': + '@inquirer/type@3.0.4(@types/node@20.17.50)': optionalDependencies: - '@types/node': 20.17.45 + '@types/node': 20.17.50 '@isaacs/cliui@8.0.2': dependencies: @@ -7201,27 +7059,27 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 20.17.45 + '@types/node': 20.17.50 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3))': + '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.45 + '@types/node': 20.17.50 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.17.45)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3)) + jest-config: 29.7.0(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -7246,7 +7104,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.45 + '@types/node': 20.17.50 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -7264,7 +7122,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.17.45 + '@types/node': 20.17.50 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -7286,7 +7144,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.25 - '@types/node': 20.17.45 + '@types/node': 20.17.50 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -7356,7 +7214,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.17.45 + '@types/node': 20.17.50 '@types/yargs': 17.0.33 chalk: 4.1.2 @@ -7385,27 +7243,12 @@ snapshots: '@jsdevtools/ono@7.1.3': {} - '@listr2/prompt-adapter-inquirer@2.0.18(@inquirer/prompts@7.3.2(@types/node@20.17.45))': + '@listr2/prompt-adapter-inquirer@2.0.18(@inquirer/prompts@7.3.2(@types/node@20.17.50))': dependencies: - '@inquirer/prompts': 7.3.2(@types/node@20.17.45) + '@inquirer/prompts': 7.3.2(@types/node@20.17.50) '@inquirer/type': 1.5.5 - '@mdn/browser-compat-data@6.0.12': {} - - '@modelcontextprotocol/sdk@1.11.0': - dependencies: - content-type: 1.0.5 - cors: 2.8.5 - cross-spawn: 7.0.6 - eventsource: 3.0.6 - express: 5.1.0 - express-rate-limit: 7.5.0(express@5.1.0) - pkce-challenge: 5.0.0 - raw-body: 3.0.0 - zod: 3.24.4 - zod-to-json-schema: 3.24.5(zod@3.24.4) - transitivePeerDependencies: - - supports-color + '@mdn/browser-compat-data@6.0.17': {} '@napi-rs/nice-android-arm-eabi@1.0.1': optional: true @@ -7522,11 +7365,11 @@ snapshots: '@npmcli/fs@3.1.1': dependencies: - semver: 7.7.1 + semver: 7.7.2 '@npmcli/fs@4.0.0': dependencies: - semver: 7.7.1 + semver: 7.7.2 '@npmcli/git@6.0.1': dependencies: @@ -7537,7 +7380,7 @@ snapshots: proc-log: 5.0.0 promise-inflight: 1.0.1 promise-retry: 2.0.1 - semver: 7.7.1 + semver: 7.7.2 which: 5.0.0 transitivePeerDependencies: - bluebird @@ -7557,7 +7400,7 @@ snapshots: json-parse-even-better-errors: 4.0.0 normalize-package-data: 7.0.0 proc-log: 5.0.0 - semver: 7.7.1 + semver: 7.7.2 transitivePeerDependencies: - bluebird @@ -7579,22 +7422,22 @@ snapshots: - bluebird - supports-color - '@nx/devkit@21.0.2(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))': + '@nx/devkit@21.1.2(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))': dependencies: ejs: 3.1.10 enquirer: 2.3.6 ignore: 5.3.2 minimatch: 9.0.3 - nx: 21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)) - semver: 7.7.1 + nx: 21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)) + semver: 7.7.2 tmp: 0.2.3 tslib: 2.8.1 yargs-parser: 21.1.1 - '@nx/esbuild@21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(esbuild@0.25.4)(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0))': + '@nx/esbuild@21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.25.4)(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0))': dependencies: - '@nx/devkit': 21.0.2(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))) - '@nx/js': 21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) + '@nx/devkit': 21.1.2(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) + '@nx/js': 21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) picocolors: 1.1.1 tinyglobby: 0.2.12 tsconfig-paths: 4.2.0 @@ -7610,21 +7453,21 @@ snapshots: - supports-color - verdaccio - '@nx/eslint-plugin@21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(@typescript-eslint/parser@8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint-config-prettier@10.1.3(eslint@9.26.0(jiti@2.4.2)))(eslint@9.26.0(jiti@2.4.2))(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(typescript@5.8.3)(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0))': + '@nx/eslint-plugin@21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@typescript-eslint/parser@8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3))(eslint-config-prettier@10.1.5(eslint@9.27.0(jiti@2.4.2)))(eslint@9.27.0(jiti@2.4.2))(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(typescript@5.8.3)(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0))': dependencies: - '@nx/devkit': 21.0.2(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))) - '@nx/js': 21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) - '@typescript-eslint/parser': 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) - '@typescript-eslint/type-utils': 8.31.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) - '@typescript-eslint/utils': 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + '@nx/devkit': 21.1.2(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) + '@nx/js': 21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) + '@typescript-eslint/parser': 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/type-utils': 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/utils': 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) chalk: 4.1.2 confusing-browser-globals: 1.0.11 globals: 15.12.0 jsonc-eslint-parser: 2.4.0 - semver: 7.7.1 + semver: 7.7.2 tslib: 2.8.1 optionalDependencies: - eslint-config-prettier: 10.1.3(eslint@9.26.0(jiti@2.4.2)) + eslint-config-prettier: 10.1.5(eslint@9.27.0(jiti@2.4.2)) transitivePeerDependencies: - '@babel/traverse' - '@swc-node/register' @@ -7636,12 +7479,12 @@ snapshots: - typescript - verdaccio - '@nx/eslint@21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(@zkochan/js-yaml@0.0.7)(eslint@9.26.0(jiti@2.4.2))(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0))': + '@nx/eslint@21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@zkochan/js-yaml@0.0.7)(eslint@9.27.0(jiti@2.4.2))(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0))': dependencies: - '@nx/devkit': 21.0.2(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))) - '@nx/js': 21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) - eslint: 9.26.0(jiti@2.4.2) - semver: 7.7.1 + '@nx/devkit': 21.1.2(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) + '@nx/js': 21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) + eslint: 9.27.0(jiti@2.4.2) + semver: 7.7.2 tslib: 2.8.1 typescript: 5.7.3 optionalDependencies: @@ -7655,21 +7498,21 @@ snapshots: - supports-color - verdaccio - '@nx/jest@21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(babel-plugin-macros@3.1.0)(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3))(typescript@5.8.3)(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0))': + '@nx/jest@21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3))(typescript@5.8.3)(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0))': dependencies: '@jest/reporters': 29.7.0 '@jest/test-result': 29.7.0 - '@nx/devkit': 21.0.2(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))) - '@nx/js': 21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) + '@nx/devkit': 21.1.2(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) + '@nx/js': 21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) '@phenomnomnominal/tsquery': 5.0.1(typescript@5.8.3) identity-obj-proxy: 3.0.0 - jest-config: 29.7.0(@types/node@20.17.45)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3)) + jest-config: 29.7.0(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3)) jest-resolve: 29.7.0 jest-util: 29.7.0 minimatch: 9.0.3 picocolors: 1.1.1 resolve.exports: 2.0.3 - semver: 7.7.1 + semver: 7.7.2 tslib: 2.8.1 yargs-parser: 21.1.1 transitivePeerDependencies: @@ -7686,7 +7529,7 @@ snapshots: - typescript - verdaccio - '@nx/js@21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0))': + '@nx/js@21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.0) @@ -7695,8 +7538,8 @@ snapshots: '@babel/preset-env': 7.26.0(@babel/core@7.26.0) '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) '@babel/runtime': 7.26.0 - '@nx/devkit': 21.0.2(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))) - '@nx/workspace': 21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)) + '@nx/devkit': 21.1.2(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) + '@nx/workspace': 21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)) '@zkochan/js-yaml': 0.0.7 babel-plugin-const-enum: 1.2.0(@babel/core@7.26.0) babel-plugin-macros: 3.1.0 @@ -7713,7 +7556,7 @@ snapshots: ora: 5.3.0 picocolors: 1.1.1 picomatch: 4.0.2 - semver: 7.7.1 + semver: 7.7.2 source-map-support: 0.5.19 tinyglobby: 0.2.12 tslib: 2.8.1 @@ -7727,42 +7570,42 @@ snapshots: - nx - supports-color - '@nx/nx-darwin-arm64@21.0.2': + '@nx/nx-darwin-arm64@21.1.2': optional: true - '@nx/nx-darwin-x64@21.0.2': + '@nx/nx-darwin-x64@21.1.2': optional: true - '@nx/nx-freebsd-x64@21.0.2': + '@nx/nx-freebsd-x64@21.1.2': optional: true - '@nx/nx-linux-arm-gnueabihf@21.0.2': + '@nx/nx-linux-arm-gnueabihf@21.1.2': optional: true - '@nx/nx-linux-arm64-gnu@21.0.2': + '@nx/nx-linux-arm64-gnu@21.1.2': optional: true - '@nx/nx-linux-arm64-musl@21.0.2': + '@nx/nx-linux-arm64-musl@21.1.2': optional: true - '@nx/nx-linux-x64-gnu@21.0.2': + '@nx/nx-linux-x64-gnu@21.1.2': optional: true - '@nx/nx-linux-x64-musl@21.0.2': + '@nx/nx-linux-x64-musl@21.1.2': optional: true - '@nx/nx-win32-arm64-msvc@21.0.2': + '@nx/nx-win32-arm64-msvc@21.1.2': optional: true - '@nx/nx-win32-x64-msvc@21.0.2': + '@nx/nx-win32-x64-msvc@21.1.2': optional: true - '@nx/plugin@21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(@zkochan/js-yaml@0.0.7)(babel-plugin-macros@3.1.0)(eslint@9.26.0(jiti@2.4.2))(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3))(typescript@5.8.3)(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0))': + '@nx/plugin@21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(@zkochan/js-yaml@0.0.7)(babel-plugin-macros@3.1.0)(eslint@9.27.0(jiti@2.4.2))(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3))(typescript@5.8.3)(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0))': dependencies: - '@nx/devkit': 21.0.2(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))) - '@nx/eslint': 21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(@zkochan/js-yaml@0.0.7)(eslint@9.26.0(jiti@2.4.2))(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) - '@nx/jest': 21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(babel-plugin-macros@3.1.0)(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3))(typescript@5.8.3)(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) - '@nx/js': 21.0.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) + '@nx/devkit': 21.1.2(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) + '@nx/eslint': 21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@zkochan/js-yaml@0.0.7)(eslint@9.27.0(jiti@2.4.2))(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) + '@nx/jest': 21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3))(typescript@5.8.3)(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) + '@nx/js': 21.1.2(@babel/traverse@7.25.9)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(verdaccio@6.1.2(encoding@0.1.13)(typanion@3.14.0)) tslib: 2.8.1 transitivePeerDependencies: - '@babel/traverse' @@ -7780,13 +7623,13 @@ snapshots: - typescript - verdaccio - '@nx/workspace@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))': + '@nx/workspace@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))': dependencies: - '@nx/devkit': 21.0.2(nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17))) + '@nx/devkit': 21.1.2(nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) '@zkochan/js-yaml': 0.0.7 chalk: 4.1.2 enquirer: 2.3.6 - nx: 21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)) + nx: 21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)) picomatch: 4.0.2 tslib: 2.8.1 yargs-parser: 21.1.1 @@ -7844,10 +7687,10 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@schematics/angular@19.2.11': + '@schematics/angular@19.2.13': dependencies: - '@angular-devkit/core': 19.2.11 - '@angular-devkit/schematics': 19.2.11 + '@angular-devkit/core': 19.2.13 + '@angular-devkit/schematics': 19.2.13 jsonc-parser: 3.3.1 transitivePeerDependencies: - chokidar @@ -7898,16 +7741,16 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 - '@swc-node/core@1.13.3(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)': + '@swc-node/core@1.13.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)': dependencies: - '@swc/core': 1.11.24(@swc/helpers@0.5.17) + '@swc/core': 1.11.29(@swc/helpers@0.5.17) '@swc/types': 0.1.21 - '@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3)': + '@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3)': dependencies: - '@swc-node/core': 1.13.3(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21) + '@swc-node/core': 1.13.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21) '@swc-node/sourcemap-support': 0.5.1 - '@swc/core': 1.11.24(@swc/helpers@0.5.17) + '@swc/core': 1.11.29(@swc/helpers@0.5.17) colorette: 2.0.20 debug: 4.4.0 oxc-resolver: 5.2.0 @@ -7923,64 +7766,64 @@ snapshots: source-map-support: 0.5.21 tslib: 2.8.1 - '@swc/cli@0.7.5(@swc/core@1.11.24(@swc/helpers@0.5.17))': + '@swc/cli@0.7.7(@swc/core@1.11.29(@swc/helpers@0.5.17))': dependencies: - '@swc/core': 1.11.24(@swc/helpers@0.5.17) + '@swc/core': 1.11.29(@swc/helpers@0.5.17) '@swc/counter': 0.1.3 '@xhmikosr/bin-wrapper': 13.0.5 commander: 8.3.0 fast-glob: 3.3.3 minimatch: 9.0.5 piscina: 4.7.0 - semver: 7.7.1 + semver: 7.7.2 slash: 3.0.0 source-map: 0.7.4 - '@swc/core-darwin-arm64@1.11.24': + '@swc/core-darwin-arm64@1.11.29': optional: true - '@swc/core-darwin-x64@1.11.24': + '@swc/core-darwin-x64@1.11.29': optional: true - '@swc/core-linux-arm-gnueabihf@1.11.24': + '@swc/core-linux-arm-gnueabihf@1.11.29': optional: true - '@swc/core-linux-arm64-gnu@1.11.24': + '@swc/core-linux-arm64-gnu@1.11.29': optional: true - '@swc/core-linux-arm64-musl@1.11.24': + '@swc/core-linux-arm64-musl@1.11.29': optional: true - '@swc/core-linux-x64-gnu@1.11.24': + '@swc/core-linux-x64-gnu@1.11.29': optional: true - '@swc/core-linux-x64-musl@1.11.24': + '@swc/core-linux-x64-musl@1.11.29': optional: true - '@swc/core-win32-arm64-msvc@1.11.24': + '@swc/core-win32-arm64-msvc@1.11.29': optional: true - '@swc/core-win32-ia32-msvc@1.11.24': + '@swc/core-win32-ia32-msvc@1.11.29': optional: true - '@swc/core-win32-x64-msvc@1.11.24': + '@swc/core-win32-x64-msvc@1.11.29': optional: true - '@swc/core@1.11.24(@swc/helpers@0.5.17)': + '@swc/core@1.11.29(@swc/helpers@0.5.17)': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.21 optionalDependencies: - '@swc/core-darwin-arm64': 1.11.24 - '@swc/core-darwin-x64': 1.11.24 - '@swc/core-linux-arm-gnueabihf': 1.11.24 - '@swc/core-linux-arm64-gnu': 1.11.24 - '@swc/core-linux-arm64-musl': 1.11.24 - '@swc/core-linux-x64-gnu': 1.11.24 - '@swc/core-linux-x64-musl': 1.11.24 - '@swc/core-win32-arm64-msvc': 1.11.24 - '@swc/core-win32-ia32-msvc': 1.11.24 - '@swc/core-win32-x64-msvc': 1.11.24 + '@swc/core-darwin-arm64': 1.11.29 + '@swc/core-darwin-x64': 1.11.29 + '@swc/core-linux-arm-gnueabihf': 1.11.29 + '@swc/core-linux-arm64-gnu': 1.11.29 + '@swc/core-linux-arm64-musl': 1.11.29 + '@swc/core-linux-x64-gnu': 1.11.29 + '@swc/core-linux-x64-musl': 1.11.29 + '@swc/core-win32-arm64-msvc': 1.11.29 + '@swc/core-win32-ia32-msvc': 1.11.29 + '@swc/core-win32-x64-msvc': 1.11.29 '@swc/helpers': 0.5.17 '@swc/counter@0.1.3': {} @@ -8047,9 +7890,9 @@ snapshots: '@types/conventional-commits-parser@5.0.1': dependencies: - '@types/node': 20.17.45 + '@types/node': 20.17.50 - '@types/eslint-scope@3.7.7': + '@types/eslint-scope@8.3.0': dependencies: '@types/eslint': 9.6.1 '@types/estree': 1.0.6 @@ -8063,7 +7906,7 @@ snapshots: '@types/graceful-fs@4.1.9': dependencies: - '@types/node': 20.17.45 + '@types/node': 20.17.50 '@types/http-cache-semantics@4.0.4': {} @@ -8086,7 +7929,7 @@ snapshots: '@types/lodash@4.17.13': {} - '@types/node@20.17.45': + '@types/node@20.17.50': dependencies: undici-types: 6.19.8 @@ -8102,127 +7945,95 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.32.0(@typescript-eslint/parser@8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)': + '@typescript-eslint/eslint-plugin@8.32.1(@typescript-eslint/parser@8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) - '@typescript-eslint/scope-manager': 8.32.0 - '@typescript-eslint/type-utils': 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) - '@typescript-eslint/utils': 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.32.0 - eslint: 9.26.0(jiti@2.4.2) + '@typescript-eslint/parser': 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.32.1 + '@typescript-eslint/type-utils': 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/utils': 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.32.1 + eslint: 9.27.0(jiti@2.4.2) graphemer: 1.4.0 - ignore: 5.3.2 + ignore: 7.0.4 natural-compare: 1.4.0 ts-api-utils: 2.1.0(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)': + '@typescript-eslint/parser@8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: - '@typescript-eslint/scope-manager': 8.32.0 - '@typescript-eslint/types': 8.32.0 - '@typescript-eslint/typescript-estree': 8.32.0(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.32.0 + '@typescript-eslint/scope-manager': 8.32.1 + '@typescript-eslint/types': 8.32.1 + '@typescript-eslint/typescript-estree': 8.32.1(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.32.1 debug: 4.4.0 - eslint: 9.26.0(jiti@2.4.2) + eslint: 9.27.0(jiti@2.4.2) typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/rule-tester@8.32.0(patch_hash=0395d56159bca55b94596b2ce1a79005dd964f4b648c29e0c04c6dfcb85e13cf)(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)': + '@typescript-eslint/rule-tester@8.32.1(patch_hash=0395d56159bca55b94596b2ce1a79005dd964f4b648c29e0c04c6dfcb85e13cf)(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: - '@typescript-eslint/parser': 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) - '@typescript-eslint/typescript-estree': 8.32.0(typescript@5.8.3) - '@typescript-eslint/utils': 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/parser': 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.32.1(typescript@5.8.3) + '@typescript-eslint/utils': 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) ajv: 6.12.6 - eslint: 9.26.0(jiti@2.4.2) + eslint: 9.27.0(jiti@2.4.2) json-stable-stringify-without-jsonify: 1.0.1 lodash.merge: 4.6.2 - semver: 7.7.1 + semver: 7.7.2 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/scope-manager@8.32.0': + '@typescript-eslint/scope-manager@8.32.1': dependencies: - '@typescript-eslint/types': 8.32.0 - '@typescript-eslint/visitor-keys': 8.32.0 + '@typescript-eslint/types': 8.32.1 + '@typescript-eslint/visitor-keys': 8.32.1 - '@typescript-eslint/type-utils@8.31.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)': + '@typescript-eslint/type-utils@8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: - '@typescript-eslint/typescript-estree': 8.31.0(typescript@5.8.3) - '@typescript-eslint/utils': 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.32.1(typescript@5.8.3) + '@typescript-eslint/utils': 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) debug: 4.4.0 - eslint: 9.26.0(jiti@2.4.2) + eslint: 9.27.0(jiti@2.4.2) ts-api-utils: 2.1.0(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)': - dependencies: - '@typescript-eslint/typescript-estree': 8.32.0(typescript@5.8.3) - '@typescript-eslint/utils': 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) - debug: 4.4.0 - eslint: 9.26.0(jiti@2.4.2) - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@8.31.0': {} + '@typescript-eslint/types@8.32.1': {} - '@typescript-eslint/types@8.32.0': {} - - '@typescript-eslint/typescript-estree@8.31.0(typescript@5.8.3)': + '@typescript-eslint/typescript-estree@8.32.1(typescript@5.8.3)': dependencies: - '@typescript-eslint/types': 8.31.0 - '@typescript-eslint/visitor-keys': 8.31.0 + '@typescript-eslint/types': 8.32.1 + '@typescript-eslint/visitor-keys': 8.32.1 debug: 4.4.0 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.1 + semver: 7.7.2 ts-api-utils: 2.1.0(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.32.0(typescript@5.8.3)': + '@typescript-eslint/utils@8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: - '@typescript-eslint/types': 8.32.0 - '@typescript-eslint/visitor-keys': 8.32.0 - debug: 4.4.0 - fast-glob: 3.3.3 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.1 - ts-api-utils: 2.1.0(typescript@5.8.3) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.27.0(jiti@2.4.2)) + '@typescript-eslint/scope-manager': 8.32.1 + '@typescript-eslint/types': 8.32.1 + '@typescript-eslint/typescript-estree': 8.32.1(typescript@5.8.3) + eslint: 9.27.0(jiti@2.4.2) typescript: 5.8.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)': + '@typescript-eslint/visitor-keys@8.32.1': dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.26.0(jiti@2.4.2)) - '@typescript-eslint/scope-manager': 8.32.0 - '@typescript-eslint/types': 8.32.0 - '@typescript-eslint/typescript-estree': 8.32.0(typescript@5.8.3) - eslint: 9.26.0(jiti@2.4.2) - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/visitor-keys@8.31.0': - dependencies: - '@typescript-eslint/types': 8.31.0 - eslint-visitor-keys: 4.2.0 - - '@typescript-eslint/visitor-keys@8.32.0': - dependencies: - '@typescript-eslint/types': 8.32.0 + '@typescript-eslint/types': 8.32.1 eslint-visitor-keys: 4.2.0 '@verdaccio/auth@8.0.0-next-8.15': @@ -8467,11 +8278,6 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 - accepts@2.0.0: - dependencies: - mime-types: 3.0.1 - negotiator: 1.0.0 - acorn-jsx@5.3.2(acorn@8.14.0): dependencies: acorn: 8.14.0 @@ -8722,7 +8528,7 @@ snapshots: bin-version-check@5.1.0: dependencies: bin-version: 6.0.0 - semver: 7.7.1 + semver: 7.7.2 semver-truncate: 3.0.0 bin-version@6.0.0: @@ -8753,20 +8559,6 @@ snapshots: transitivePeerDependencies: - supports-color - body-parser@2.2.0: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 4.4.0 - http-errors: 2.0.0 - iconv-lite: 0.6.3 - on-finished: 2.4.1 - qs: 6.14.0 - raw-body: 3.0.0 - type-is: 2.0.1 - transitivePeerDependencies: - - supports-color - brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -8982,10 +8774,10 @@ snapshots: commander@8.3.0: {} - commitizen@4.3.1(@types/node@20.17.45)(typescript@5.8.3): + commitizen@4.3.1(@types/node@20.17.50)(typescript@5.8.3): dependencies: cachedir: 2.3.0 - cz-conventional-changelog: 3.3.0(@types/node@20.17.45)(typescript@5.8.3) + cz-conventional-changelog: 3.3.0(@types/node@20.17.50)(typescript@5.8.3) dedent: 0.7.0 detect-indent: 6.1.0 find-node-modules: 2.1.3 @@ -9031,10 +8823,6 @@ snapshots: dependencies: safe-buffer: 5.2.1 - content-disposition@1.0.0: - dependencies: - safe-buffer: 5.2.1 - content-type@1.0.5: {} conventional-changelog-angular@7.0.0: @@ -9058,8 +8846,6 @@ snapshots: cookie-signature@1.0.6: {} - cookie-signature@1.2.2: {} - cookie@0.7.1: {} core-js-compat@3.39.0: @@ -9077,17 +8863,17 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 - cosmiconfig-typescript-loader@5.1.0(@types/node@20.17.45)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3): + cosmiconfig-typescript-loader@5.1.0(@types/node@20.17.50)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3): dependencies: - '@types/node': 20.17.45 + '@types/node': 20.17.50 cosmiconfig: 9.0.0(typescript@5.8.3) jiti: 1.21.6 typescript: 5.8.3 optional: true - cosmiconfig-typescript-loader@6.1.0(@types/node@20.17.45)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3): + cosmiconfig-typescript-loader@6.1.0(@types/node@20.17.50)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3): dependencies: - '@types/node': 20.17.45 + '@types/node': 20.17.50 cosmiconfig: 9.0.0(typescript@5.8.3) jiti: 2.4.2 typescript: 5.8.3 @@ -9109,13 +8895,13 @@ snapshots: optionalDependencies: typescript: 5.8.3 - create-jest@29.7.0(@types/node@20.17.45)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3)): + create-jest@29.7.0(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.17.45)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3)) + jest-config: 29.7.0(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -9133,16 +8919,16 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - cz-conventional-changelog@3.3.0(@types/node@20.17.45)(typescript@5.8.3): + cz-conventional-changelog@3.3.0(@types/node@20.17.50)(typescript@5.8.3): dependencies: chalk: 2.4.2 - commitizen: 4.3.1(@types/node@20.17.45)(typescript@5.8.3) + commitizen: 4.3.1(@types/node@20.17.50)(typescript@5.8.3) conventional-commit-types: 3.0.0 lodash.map: 4.6.0 longest: 2.0.1 word-wrap: 1.2.5 optionalDependencies: - '@commitlint/load': 19.5.0(@types/node@20.17.45)(typescript@5.8.3) + '@commitlint/load': 19.5.0(@types/node@20.17.50)(typescript@5.8.3) transitivePeerDependencies: - '@types/node' - typescript @@ -9350,9 +9136,9 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-prettier@10.1.3(eslint@9.26.0(jiti@2.4.2)): + eslint-config-prettier@10.1.5(eslint@9.27.0(jiti@2.4.2)): dependencies: - eslint: 9.26.0(jiti@2.4.2) + eslint: 9.27.0(jiti@2.4.2) eslint-scope@8.3.0: dependencies: @@ -9363,20 +9149,19 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.26.0(jiti@2.4.2): + eslint@9.27.0(jiti@2.4.2): dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.26.0(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.27.0(jiti@2.4.2)) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.20.0 '@eslint/config-helpers': 0.2.1 - '@eslint/core': 0.13.0 + '@eslint/core': 0.14.0 '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.26.0 - '@eslint/plugin-kit': 0.2.8 + '@eslint/js': 9.27.0 + '@eslint/plugin-kit': 0.3.1 '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.2 - '@modelcontextprotocol/sdk': 1.11.0 '@types/estree': 1.0.6 '@types/json-schema': 7.0.15 ajv: 6.12.6 @@ -9401,7 +9186,6 @@ snapshots: minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 - zod: 3.24.4 optionalDependencies: jiti: 2.4.2 transitivePeerDependencies: @@ -9441,12 +9225,6 @@ snapshots: events@3.3.0: {} - eventsource-parser@3.0.1: {} - - eventsource@3.0.6: - dependencies: - eventsource-parser: 3.0.1 - execa@5.1.1: dependencies: cross-spawn: 7.0.6 @@ -9459,18 +9237,6 @@ snapshots: signal-exit: 3.0.7 strip-final-newline: 2.0.0 - execa@8.0.1: - dependencies: - cross-spawn: 7.0.6 - get-stream: 8.0.1 - human-signals: 5.0.0 - is-stream: 3.0.0 - merge-stream: 2.0.0 - npm-run-path: 5.3.0 - onetime: 6.0.0 - signal-exit: 4.1.0 - strip-final-newline: 3.0.0 - exit@0.1.2: {} expand-tilde@2.0.2: @@ -9489,10 +9255,6 @@ snapshots: express-rate-limit@5.5.1: {} - express-rate-limit@7.5.0(express@5.1.0): - dependencies: - express: 5.1.0 - express@4.21.2: dependencies: accepts: 1.3.8 @@ -9529,41 +9291,9 @@ snapshots: transitivePeerDependencies: - supports-color - express@5.1.0: - dependencies: - accepts: 2.0.0 - body-parser: 2.2.0 - content-disposition: 1.0.0 - content-type: 1.0.5 - cookie: 0.7.1 - cookie-signature: 1.2.2 - debug: 4.4.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 2.1.0 - fresh: 2.0.0 - http-errors: 2.0.0 - merge-descriptors: 2.0.0 - mime-types: 3.0.1 - on-finished: 2.4.1 - once: 1.4.0 - parseurl: 1.3.3 - proxy-addr: 2.0.7 - qs: 6.14.0 - range-parser: 1.2.1 - router: 2.2.0 - send: 1.2.0 - serve-static: 2.2.0 - statuses: 2.0.1 - type-is: 2.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - ext-list@2.2.2: dependencies: - mime-db: 1.53.0 + mime-db: 1.54.0 ext-name@5.0.0: dependencies: @@ -9657,17 +9387,6 @@ snapshots: transitivePeerDependencies: - supports-color - finalhandler@2.1.0: - dependencies: - debug: 4.4.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - find-node-modules@2.1.3: dependencies: findup-sync: 4.0.0 @@ -9732,8 +9451,6 @@ snapshots: fresh@0.5.2: {} - fresh@2.0.0: {} - front-matter@4.0.2: dependencies: js-yaml: 3.14.1 @@ -9798,8 +9515,6 @@ snapshots: get-stream@6.0.1: {} - get-stream@8.0.1: {} - get-stream@9.0.1: dependencies: '@sec-ant/readable-stream': 0.4.1 @@ -9993,8 +9708,6 @@ snapshots: human-signals@2.1.0: {} - human-signals@5.0.0: {} - husky@9.1.7: {} iconv-lite@0.4.24: @@ -10004,6 +9717,7 @@ snapshots: iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 + optional: true identity-obj-proxy@3.0.0: dependencies: @@ -10117,12 +9831,8 @@ snapshots: is-promise@2.2.2: {} - is-promise@4.0.0: {} - is-stream@2.0.1: {} - is-stream@3.0.0: {} - is-stream@4.0.1: {} is-text-path@2.0.0: @@ -10167,7 +9877,7 @@ snapshots: '@babel/parser': 7.26.2 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 - semver: 7.7.1 + semver: 7.7.2 transitivePeerDependencies: - supports-color @@ -10215,7 +9925,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.45 + '@types/node': 20.17.50 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.3(babel-plugin-macros@3.1.0) @@ -10235,16 +9945,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@20.17.45)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3)): + jest-cli@29.7.0(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3)): dependencies: - '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.17.45)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3)) + create-jest: 29.7.0(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.17.45)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3)) + jest-config: 29.7.0(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -10254,7 +9964,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@20.17.45)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3)): + jest-config@29.7.0(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -10279,8 +9989,8 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 20.17.45 - ts-node: 10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3) + '@types/node': 20.17.50 + ts-node: 10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -10309,7 +10019,7 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.45 + '@types/node': 20.17.50 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -10319,7 +10029,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 20.17.45 + '@types/node': 20.17.50 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -10358,7 +10068,7 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.17.45 + '@types/node': 20.17.50 jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -10393,7 +10103,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.45 + '@types/node': 20.17.50 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -10421,7 +10131,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.45 + '@types/node': 20.17.50 chalk: 4.1.2 cjs-module-lexer: 1.4.1 collect-v8-coverage: 1.0.2 @@ -10460,14 +10170,14 @@ snapshots: jest-util: 29.7.0 natural-compare: 1.4.0 pretty-format: 29.7.0 - semver: 7.7.1 + semver: 7.7.2 transitivePeerDependencies: - supports-color jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.17.45 + '@types/node': 20.17.50 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -10486,7 +10196,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.45 + '@types/node': 20.17.50 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -10495,17 +10205,17 @@ snapshots: jest-worker@29.7.0: dependencies: - '@types/node': 20.17.45 + '@types/node': 20.17.50 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@20.17.45)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3)): + jest@29.7.0(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3)): dependencies: - '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.17.45)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3)) + jest-cli: 29.7.0(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -10569,7 +10279,7 @@ snapshots: acorn: 8.14.0 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - semver: 7.7.1 + semver: 7.7.2 jsonc-parser@3.2.0: {} @@ -10594,7 +10304,7 @@ snapshots: lodash.isstring: 4.0.1 lodash.once: 4.1.1 ms: 2.1.3 - semver: 7.7.1 + semver: 7.7.2 jsprim@2.0.2: dependencies: @@ -10635,18 +10345,18 @@ snapshots: lines-and-columns@2.0.3: {} - lint-staged@15.5.2: + lint-staged@16.0.0: dependencies: chalk: 5.4.1 commander: 13.1.0 debug: 4.4.0 - execa: 8.0.1 lilconfig: 3.1.3 - listr2: 8.2.5 + listr2: 8.3.3 micromatch: 4.0.8 + nano-spawn: 1.0.1 pidtree: 0.6.0 string-argv: 0.3.2 - yaml: 2.7.0 + yaml: 2.7.1 transitivePeerDependencies: - supports-color @@ -10659,6 +10369,15 @@ snapshots: rfdc: 1.4.1 wrap-ansi: 9.0.0 + listr2@8.3.3: + dependencies: + cli-truncate: 4.0.0 + colorette: 2.0.20 + eventemitter3: 5.0.1 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.0 + locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -10752,7 +10471,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.7.1 + semver: 7.7.2 make-error@1.3.6: {} @@ -10797,14 +10516,10 @@ snapshots: media-typer@0.3.0: {} - media-typer@1.1.0: {} - meow@12.1.1: {} merge-descriptors@1.0.3: {} - merge-descriptors@2.0.0: {} - merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -10828,10 +10543,6 @@ snapshots: dependencies: mime-db: 1.52.0 - mime-types@3.0.1: - dependencies: - mime-db: 1.54.0 - mime@1.6.0: {} mime@2.6.0: {} @@ -10840,8 +10551,6 @@ snapshots: mimic-fn@2.1.0: {} - mimic-fn@4.0.0: {} - mimic-function@5.0.1: {} mimic-response@3.1.0: {} @@ -10938,6 +10647,8 @@ snapshots: mute-stream@2.0.0: {} + nano-spawn@1.0.1: {} + natural-compare@1.4.0: {} ncp@2.0.0: {} @@ -10965,7 +10676,7 @@ snapshots: make-fetch-happen: 13.0.1 nopt: 7.2.1 proc-log: 4.2.0 - semver: 7.7.1 + semver: 7.7.2 tar: 6.2.1 which: 4.0.0 transitivePeerDependencies: @@ -10984,7 +10695,7 @@ snapshots: normalize-package-data@7.0.0: dependencies: hosted-git-info: 8.0.2 - semver: 7.7.1 + semver: 7.7.2 validate-npm-package-license: 3.0.4 normalize-path@3.0.0: {} @@ -10997,7 +10708,7 @@ snapshots: npm-install-checks@7.1.1: dependencies: - semver: 7.7.1 + semver: 7.7.2 npm-normalize-package-bin@4.0.0: {} @@ -11005,14 +10716,14 @@ snapshots: dependencies: hosted-git-info: 7.0.2 proc-log: 3.0.0 - semver: 7.7.1 + semver: 7.7.2 validate-npm-package-name: 5.0.1 npm-package-arg@12.0.2: dependencies: hosted-git-info: 8.0.2 proc-log: 5.0.0 - semver: 7.7.1 + semver: 7.7.2 validate-npm-package-name: 6.0.0 npm-packlist@9.0.0: @@ -11024,7 +10735,7 @@ snapshots: npm-install-checks: 7.1.1 npm-normalize-package-bin: 4.0.0 npm-package-arg: 12.0.2 - semver: 7.7.1 + semver: 7.7.2 npm-registry-fetch@18.0.2: dependencies: @@ -11043,11 +10754,7 @@ snapshots: dependencies: path-key: 3.1.1 - npm-run-path@5.3.0: - dependencies: - path-key: 4.0.0 - - nx@21.0.2(@swc-node/register@1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.24(@swc/helpers@0.5.17)): + nx@21.1.2(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)): dependencies: '@napi-rs/wasm-runtime': 0.2.4 '@yarnpkg/lockfile': 1.1.0 @@ -11074,29 +10781,29 @@ snapshots: open: 8.4.2 ora: 5.3.0 resolve.exports: 2.0.3 - semver: 7.7.1 + semver: 7.7.2 string-width: 4.2.3 tar-stream: 2.2.0 tmp: 0.2.3 tree-kill: 1.2.2 tsconfig-paths: 4.2.0 tslib: 2.8.1 - yaml: 2.7.0 + yaml: 2.7.1 yargs: 17.7.2 yargs-parser: 21.1.1 optionalDependencies: - '@nx/nx-darwin-arm64': 21.0.2 - '@nx/nx-darwin-x64': 21.0.2 - '@nx/nx-freebsd-x64': 21.0.2 - '@nx/nx-linux-arm-gnueabihf': 21.0.2 - '@nx/nx-linux-arm64-gnu': 21.0.2 - '@nx/nx-linux-arm64-musl': 21.0.2 - '@nx/nx-linux-x64-gnu': 21.0.2 - '@nx/nx-linux-x64-musl': 21.0.2 - '@nx/nx-win32-arm64-msvc': 21.0.2 - '@nx/nx-win32-x64-msvc': 21.0.2 - '@swc-node/register': 1.10.10(@swc/core@1.11.24(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3) - '@swc/core': 1.11.24(@swc/helpers@0.5.17) + '@nx/nx-darwin-arm64': 21.1.2 + '@nx/nx-darwin-x64': 21.1.2 + '@nx/nx-freebsd-x64': 21.1.2 + '@nx/nx-linux-arm-gnueabihf': 21.1.2 + '@nx/nx-linux-arm64-gnu': 21.1.2 + '@nx/nx-linux-arm64-musl': 21.1.2 + '@nx/nx-linux-x64-gnu': 21.1.2 + '@nx/nx-linux-x64-musl': 21.1.2 + '@nx/nx-win32-arm64-msvc': 21.1.2 + '@nx/nx-win32-x64-msvc': 21.1.2 + '@swc-node/register': 1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3) + '@swc/core': 1.11.29(@swc/helpers@0.5.17) transitivePeerDependencies: - debug @@ -11120,10 +10827,6 @@ snapshots: dependencies: mimic-fn: 2.1.0 - onetime@6.0.0: - dependencies: - mimic-fn: 4.0.0 - onetime@7.0.0: dependencies: mimic-function: 5.0.1 @@ -11268,8 +10971,6 @@ snapshots: path-key@3.1.1: {} - path-key@4.0.0: {} - path-parse@1.0.7: {} path-scurry@1.11.1: @@ -11279,8 +10980,6 @@ snapshots: path-to-regexp@0.1.12: {} - path-to-regexp@8.2.0: {} - path-type@4.0.0: {} peek-readable@5.3.1: {} @@ -11336,8 +11035,6 @@ snapshots: optionalDependencies: '@napi-rs/nice': 1.0.1 - pkce-challenge@5.0.0: {} - pkg-dir@4.2.0: dependencies: find-up: 4.1.0 @@ -11429,13 +11126,6 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 - raw-body@3.0.0: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.6.3 - unpipe: 1.0.0 - react-is@18.3.1: {} readable-stream@2.3.8: @@ -11544,16 +11234,6 @@ snapshots: dependencies: glob: 10.4.5 - router@2.2.0: - dependencies: - debug: 4.4.0 - depd: 2.0.0 - is-promise: 4.0.0 - parseurl: 1.3.3 - path-to-regexp: 8.2.0 - transitivePeerDependencies: - - supports-color - run-async@2.4.1: {} run-parallel@1.2.0: @@ -11580,7 +11260,7 @@ snapshots: semver-truncate@3.0.0: dependencies: - semver: 7.7.1 + semver: 7.7.2 semver@6.3.1: {} @@ -11588,6 +11268,8 @@ snapshots: semver@7.7.1: {} + semver@7.7.2: {} + send@0.19.0: dependencies: debug: 2.6.9 @@ -11606,22 +11288,6 @@ snapshots: transitivePeerDependencies: - supports-color - send@1.2.0: - dependencies: - debug: 4.4.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 2.0.0 - http-errors: 2.0.0 - mime-types: 3.0.1 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - serve-static@1.16.2: dependencies: encodeurl: 2.0.0 @@ -11631,15 +11297,6 @@ snapshots: transitivePeerDependencies: - supports-color - serve-static@2.2.0: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 1.2.0 - transitivePeerDependencies: - - supports-color - set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -11883,8 +11540,6 @@ snapshots: strip-final-newline@2.0.0: {} - strip-final-newline@3.0.0: {} - strip-json-comments@3.1.1: {} strtok3@9.1.1: @@ -12010,17 +11665,17 @@ snapshots: dependencies: typescript: 5.8.3 - ts-jest@29.2.4(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.45)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3)))(typescript@5.8.3): + ts-jest@29.2.4(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.25.4)(jest@29.7.0(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3)))(typescript@5.8.3): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.17.45)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3)) + jest: 29.7.0(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.7.1 + semver: 7.7.2 typescript: 5.8.3 yargs-parser: 21.1.1 optionalDependencies: @@ -12030,14 +11685,14 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.26.0) esbuild: 0.25.4 - ts-node@10.9.1(@swc/core@1.11.24(@swc/helpers@0.5.17))(@types/node@20.17.45)(typescript@5.8.3): + ts-node@10.9.1(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@20.17.50)(typescript@5.8.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.17.45 + '@types/node': 20.17.50 acorn: 8.14.1 acorn-walk: 8.3.4 arg: 4.1.3 @@ -12048,7 +11703,7 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: - '@swc/core': 1.11.24(@swc/helpers@0.5.17) + '@swc/core': 1.11.29(@swc/helpers@0.5.17) optional: true tsconfig-paths@4.2.0: @@ -12095,18 +11750,12 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 - type-is@2.0.1: - dependencies: - content-type: 1.0.5 - media-typer: 1.1.0 - mime-types: 3.0.1 - - typescript-eslint@8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3): + typescript-eslint@8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.32.0(@typescript-eslint/parser@8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) - '@typescript-eslint/parser': 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) - '@typescript-eslint/utils': 8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) - eslint: 9.26.0(jiti@2.4.2) + '@typescript-eslint/eslint-plugin': 8.32.1(@typescript-eslint/parser@8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/parser': 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/utils': 8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3) + eslint: 9.27.0(jiti@2.4.2) typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -12347,7 +11996,7 @@ snapshots: yaml@1.10.2: {} - yaml@2.7.0: {} + yaml@2.7.1: {} yargs-parser@21.1.1: {} @@ -12374,9 +12023,3 @@ snapshots: yocto-queue@1.1.1: {} yoctocolors-cjs@2.1.2: {} - - zod-to-json-schema@3.24.5(zod@3.24.4): - dependencies: - zod: 3.24.4 - - zod@3.24.4: {}