diff --git a/.cspell.json b/.cspell.json index 6b47f72ac9..164b2aef7f 100644 --- a/.cspell.json +++ b/.cspell.json @@ -8,6 +8,8 @@ "novalidate", "pillarbox", "tabindex", + "Tmpl", + "TSES", "xlink" ] } diff --git a/.github/workflows/validate-pr.yml b/.github/workflows/validate-pr.yml index abe40b57e4..b95e843538 100644 --- a/.github/workflows/validate-pr.yml +++ b/.github/workflows/validate-pr.yml @@ -90,4 +90,5 @@ jobs: sdk/e2e-schematics sdk/eslint-config sdk/prettier-schematics + sdk/skyux-eslint sdk/testing diff --git a/.prettierignore b/.prettierignore index 3aa551369f..b91be2d731 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,6 +3,8 @@ /.nyc_output /coverage /dist +/libs/sdk/skyux-eslint/**/*.md +/libs/sdk/skyux-eslint/**/__deprecations.json /node_modules /temp /tmp @@ -18,4 +20,4 @@ CHANGELOG.md /.nx/cache -/.nx/workspace-data \ No newline at end of file +/.nx/workspace-data diff --git a/.skyuxdev.json b/.skyuxdev.json index 7955a26b7d..ca94fe5102 100644 --- a/.skyuxdev.json +++ b/.skyuxdev.json @@ -9,6 +9,7 @@ "packages", "prettier-schematics", "router", + "skyux-eslint", "storybook", "testing" ], diff --git a/apps/code-examples/eslint.config.js b/apps/code-examples/eslint.config.js index 89a9bb5697..8849e91d0b 100644 --- a/apps/code-examples/eslint.config.js +++ b/apps/code-examples/eslint.config.js @@ -1,44 +1,24 @@ -const { FlatCompat } = require('@eslint/eslintrc'); -const js = require('@eslint/js'); -const path = require('node:path'); +// @ts-check +const tsEslint = require('typescript-eslint'); +const skyux = require('../../libs/sdk/skyux-eslint/dev-transpiler.cjs'); const config = require('../../eslint-apps.config'); -const compat = new FlatCompat({ - baseDirectory: __dirname, - recommendedConfig: js.configs.recommended, -}); - -module.exports = [ +module.exports = tsEslint.config( ...config, - ...compat - .config({ - extends: ['../../libs/sdk/eslint-config/recommended'], - }) - .map((config) => ({ - files: ['**/src/app/code-examples/**/*.ts'], - languageOptions: { - ...config.languageOptions, - parserOptions: { - project: [path.join(__dirname, 'tsconfig.editor.json')], - tsconfigRootDir: '.', - }, - }, - linterOptions: { reportUnusedDisableDirectives: true }, - rules: { - ...config.rules, - 'no-alert': 'warn', - 'no-console': 'warn', - 'no-restricted-imports': [ - 'error', - { - patterns: [ - { - group: ['../*'], - message: 'Make sure to import from local files only.', - }, - ], - }, - ], - }, - })), -]; + { + files: ['**/src/app/code-examples/**/*.ts'], + extends: [...skyux.configs.tsAll], + rules: { + '@typescript-eslint/no-deprecated': 'warn', + 'no-alert': 'warn', + 'no-console': 'warn', + }, + }, + { + files: ['**/src/app/code-examples/**/*.html'], + extends: [...skyux.configs.templateAll], + rules: { + 'skyux-eslint-template/no-deprecated-directives': 'warn', + }, + }, +); diff --git a/apps/code-examples/src/app/code-examples/action-bars/summary-action-bar/modal/modal.component.html b/apps/code-examples/src/app/code-examples/action-bars/summary-action-bar/modal/modal.component.html index 8248c193f4..0ca8aa2e2f 100644 --- a/apps/code-examples/src/app/code-examples/action-bars/summary-action-bar/modal/modal.component.html +++ b/apps/code-examples/src/app/code-examples/action-bars/summary-action-bar/modal/modal.component.html @@ -1,5 +1,4 @@ - - Modal with summary action bar + Hello world! diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/basic/edit-modal.component.html b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/basic/edit-modal.component.html index b72b0ed067..b0d8d47379 100644 --- a/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/basic/edit-modal.component.html +++ b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/basic/edit-modal.component.html @@ -1,5 +1,4 @@ - - Edit employee information + - Edit employee information + - Filter employees +
- - Hide Sales employees - +
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/edit-modal.component.html b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/edit-modal.component.html index 6b5a580d8a..b194f4eb80 100644 --- a/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/edit-modal.component.html +++ b/apps/code-examples/src/app/code-examples/ag-grid/data-entry-grid/inline-help/edit-modal.component.html @@ -1,5 +1,4 @@ - - Edit employee information + diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-grid/data-manager-multiselect/filter-modal.component.html b/apps/code-examples/src/app/code-examples/ag-grid/data-grid/data-manager-multiselect/filter-modal.component.html index 06dab3d437..d8377f355b 100644 --- a/apps/code-examples/src/app/code-examples/ag-grid/data-grid/data-manager-multiselect/filter-modal.component.html +++ b/apps/code-examples/src/app/code-examples/ag-grid/data-grid/data-manager-multiselect/filter-modal.component.html @@ -1,5 +1,4 @@ - - Filter employees +
- - Hide Sales employees - +
diff --git a/apps/code-examples/src/app/code-examples/ag-grid/data-grid/data-manager/filter-modal.component.html b/apps/code-examples/src/app/code-examples/ag-grid/data-grid/data-manager/filter-modal.component.html index 06dab3d437..d8377f355b 100644 --- a/apps/code-examples/src/app/code-examples/ag-grid/data-grid/data-manager/filter-modal.component.html +++ b/apps/code-examples/src/app/code-examples/ag-grid/data-grid/data-manager/filter-modal.component.html @@ -1,5 +1,4 @@ - - Filter employees +
- - Hide Sales employees - +
diff --git a/apps/code-examples/src/app/code-examples/core/id/demo.component.html b/apps/code-examples/src/app/code-examples/core/id/demo.component.html index 2b515e31c2..f95fcb8218 100644 --- a/apps/code-examples/src/app/code-examples/core/id/demo.component.html +++ b/apps/code-examples/src/app/code-examples/core/id/demo.component.html @@ -1,11 +1 @@ - - - - - - - - - +
This DIV's id is '{{ myDiv.id }}'
diff --git a/apps/code-examples/src/app/code-examples/core/id/demo.component.ts b/apps/code-examples/src/app/code-examples/core/id/demo.component.ts index 8be3f4e720..32da3e227f 100644 --- a/apps/code-examples/src/app/code-examples/core/id/demo.component.ts +++ b/apps/code-examples/src/app/code-examples/core/id/demo.component.ts @@ -1,11 +1,10 @@ import { Component } from '@angular/core'; import { SkyIdModule } from '@skyux/core'; -import { SkyInputBoxModule } from '@skyux/forms'; @Component({ standalone: true, selector: 'app-demo', templateUrl: './demo.component.html', - imports: [SkyIdModule, SkyInputBoxModule], + imports: [SkyIdModule], }) export class DemoComponent {} diff --git a/apps/code-examples/src/app/code-examples/data-manager/data-manager/basic/filter-modal.component.html b/apps/code-examples/src/app/code-examples/data-manager/data-manager/basic/filter-modal.component.html index e24872f4a8..295ce2df6d 100644 --- a/apps/code-examples/src/app/code-examples/data-manager/data-manager/basic/filter-modal.component.html +++ b/apps/code-examples/src/app/code-examples/data-manager/data-manager/basic/filter-modal.component.html @@ -1,5 +1,4 @@ - - Filter your fruit + - - Hide orange fruits - + diff --git a/apps/code-examples/src/app/code-examples/progress-indicator/wizard/basic/modal.component.html b/apps/code-examples/src/app/code-examples/progress-indicator/wizard/basic/modal.component.html index 1bf7ba1503..b952f3eeca 100644 --- a/apps/code-examples/src/app/code-examples/progress-indicator/wizard/basic/modal.component.html +++ b/apps/code-examples/src/app/code-examples/progress-indicator/wizard/basic/modal.component.html @@ -1,7 +1,4 @@ - - - {{ title }} - +
-
- - -
+ + +
- - Select to continue - +
diff --git a/apps/code-examples/src/app/code-examples/progress-indicator/wizard/basic/modal.component.ts b/apps/code-examples/src/app/code-examples/progress-indicator/wizard/basic/modal.component.ts index e25415df68..1e7e1774ce 100644 --- a/apps/code-examples/src/app/code-examples/progress-indicator/wizard/basic/modal.component.ts +++ b/apps/code-examples/src/app/code-examples/progress-indicator/wizard/basic/modal.component.ts @@ -1,6 +1,6 @@ import { Component, inject } from '@angular/core'; import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms'; -import { SkyCheckboxModule } from '@skyux/forms'; +import { SkyCheckboxModule, SkyInputBoxModule } from '@skyux/forms'; import { SkyModalInstance, SkyModalModule } from '@skyux/modals'; import { SkyProgressIndicatorActionClickArgs, @@ -16,6 +16,7 @@ import { imports: [ ReactiveFormsModule, SkyCheckboxModule, + SkyInputBoxModule, SkyModalModule, SkyProgressIndicatorModule, ], diff --git a/apps/code-examples/src/app/code-examples/split-view/split-view/basic/demo.component.html b/apps/code-examples/src/app/code-examples/split-view/split-view/basic/demo.component.html index 74cafb257e..175f57e953 100644 --- a/apps/code-examples/src/app/code-examples/split-view/split-view/basic/demo.component.html +++ b/apps/code-examples/src/app/code-examples/split-view/split-view/basic/demo.component.html @@ -59,7 +59,7 @@ - + Approve expense diff --git a/apps/code-examples/src/app/code-examples/split-view/split-view/page-bound/demo.component.html b/apps/code-examples/src/app/code-examples/split-view/split-view/page-bound/demo.component.html index 055a72332e..2285279706 100644 --- a/apps/code-examples/src/app/code-examples/split-view/split-view/page-bound/demo.component.html +++ b/apps/code-examples/src/app/code-examples/split-view/split-view/page-bound/demo.component.html @@ -82,7 +82,7 @@ - + - - Sectioned form — Index: {{ activeIndexDisplay }} - + diff --git a/apps/code-examples/src/app/code-examples/tabs/wizard/basic/modal.component.html b/apps/code-examples/src/app/code-examples/tabs/wizard/basic/modal.component.html index 0944a61e41..e6c50846c8 100644 --- a/apps/code-examples/src/app/code-examples/tabs/wizard/basic/modal.component.html +++ b/apps/code-examples/src/app/code-examples/tabs/wizard/basic/modal.component.html @@ -1,8 +1,5 @@
- - - {{ title }} - + - - - Accept terms and conditions - - + - - - Sign up for our email newsletter - - + diff --git a/apps/code-examples/src/main.ts b/apps/code-examples/src/main.ts index cd9cbc4fad..a7dd5227c3 100644 --- a/apps/code-examples/src/main.ts +++ b/apps/code-examples/src/main.ts @@ -11,6 +11,5 @@ if (environment.production) { platformBrowserDynamic() .bootstrapModule(AppModule) .catch((err) => { - // eslint-disable-next-line no-console console.error(err); }); diff --git a/libs/sdk/eslint-config/package.json b/libs/sdk/eslint-config/package.json index 2f277e64a0..4188a73d7e 100644 --- a/libs/sdk/eslint-config/package.json +++ b/libs/sdk/eslint-config/package.json @@ -32,7 +32,6 @@ "dependencies": { "comment-json": "4.2.4", "fs-extra": "11.2.0", - "jsonc-parser": "3.3.1", - "package-json": "7.0.0" + "jsonc-parser": "3.3.1" } } diff --git a/libs/sdk/eslint-config/src/schematics/ng-add/ng-add.schematic.spec.ts b/libs/sdk/eslint-config/src/schematics/ng-add/ng-add.schematic.spec.ts index e169323279..d04ba1fbaa 100644 --- a/libs/sdk/eslint-config/src/schematics/ng-add/ng-add.schematic.spec.ts +++ b/libs/sdk/eslint-config/src/schematics/ng-add/ng-add.schematic.spec.ts @@ -10,12 +10,6 @@ import { readJsonFile } from '../shared/utility/tree'; const COLLECTION_PATH = path.resolve(__dirname, '../../../collection.json'); const ESLINT_CONFIG_PATH = './.eslintrc.json'; -jest.mock('../shared/utility/get-latest-version', () => ({ - getLatestVersion: jest.fn((_, version) => - Promise.resolve(`LATEST_${version}`), - ), -})); - describe('ng-add.schematic', () => { const runner = new SchematicTestRunner('schematics', COLLECTION_PATH); const defaultProjectName = 'my-app'; diff --git a/libs/sdk/eslint-config/src/schematics/shared/utility/get-latest-version.ts b/libs/sdk/eslint-config/src/schematics/shared/utility/get-latest-version.ts deleted file mode 100644 index bf54aa4a95..0000000000 --- a/libs/sdk/eslint-config/src/schematics/shared/utility/get-latest-version.ts +++ /dev/null @@ -1,12 +0,0 @@ -import packageJson from 'package-json'; - -export async function getLatestVersion( - packageName: string, - versionRange: string, -): Promise { - const result = (await packageJson(packageName, { - version: versionRange, - })) as unknown as { version: string }; - - return result.version; -} diff --git a/libs/sdk/skyux-eslint/README.md b/libs/sdk/skyux-eslint/README.md new file mode 100644 index 0000000000..094a8f9fe8 --- /dev/null +++ b/libs/sdk/skyux-eslint/README.md @@ -0,0 +1,51 @@ +# skyux-eslint (Developer Preview) + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test skyux-eslint` to execute the unit tests via [Jest](https://jestjs.io). + +## Implement in eslint.config.js + +``` +// @ts-check +const eslint = require('@eslint/js'); +const angular = require('angular-eslint'); +const skyux = require('skyux-eslint'); +const tseslint = require('typescript-eslint'); + +module.exports = tseslint.config( + { + files: ['**/*.ts'], + extends: [ + eslint.configs.recommended, + ...tseslint.configs.recommended, + ...tseslint.configs.stylistic, + ...angular.configs.tsRecommended, + ...skyux.configs.tsRecommended, + ], + processor: angular.processInlineTemplates, + rules: { + // ... + }, + }, + { + files: ['**/*.html'], + extends: [ + ...angular.configs.templateRecommended, + ...angular.configs.templateAccessibility, + ...skyux.configs.templateRecommended, + ], + rules: {}, + }, +); +``` + +## Refresh deprecations summary for `skyux-eslint-template/no-deprecated-directives` rule + +Note: Only do this for prerelease versions since updating the deprecations summary could result in a breaking change for our consumers. + +``` +npm run dev:refresh-skyux-eslint-deprecations-summary +``` diff --git a/libs/sdk/skyux-eslint/collection.json b/libs/sdk/skyux-eslint/collection.json new file mode 100644 index 0000000000..21a4c1dee0 --- /dev/null +++ b/libs/sdk/skyux-eslint/collection.json @@ -0,0 +1,9 @@ +{ + "$schema": "./node_modules/@angular-devkit/schematics/collection-schema.json", + "schematics": { + "ng-add": { + "description": "Add skyux-eslint to your project.", + "factory": "./src/schematics/ng-add/ng-add.schematic#ngAdd" + } + } +} diff --git a/libs/sdk/skyux-eslint/dev-transpiler.cjs b/libs/sdk/skyux-eslint/dev-transpiler.cjs new file mode 100644 index 0000000000..e51ad91b1f --- /dev/null +++ b/libs/sdk/skyux-eslint/dev-transpiler.cjs @@ -0,0 +1,15 @@ +/* eslint-disable @typescript-eslint/no-require-imports */ +const path = require('node:path'); + +/** + * Transpile the 'skyux-eslint' project so it can be consumed by an + * eslint.config.js file. + */ +require('ts-node').register({ + project: path.join(__dirname, './tsconfig.json'), + swc: true, +}); + +const skyuxEslint = require('./src/index.ts'); + +module.exports = skyuxEslint.default; diff --git a/libs/sdk/skyux-eslint/docs/rules/no-lambda-imports.md b/libs/sdk/skyux-eslint/docs/rules/no-lambda-imports.md new file mode 100644 index 0000000000..65b247902f --- /dev/null +++ b/libs/sdk/skyux-eslint/docs/rules/no-lambda-imports.md @@ -0,0 +1,34 @@ +# skyux-eslint/no-lambda-imports + +Prevents importing components from SKY UX packages that start with the "λ" lambda character. These imports are not included in the public API and should not be used. + +- Type: problem + +
+ +## Rule Options + +The rule does not have any configuration options. + +
+ +## Usage Examples + +#### Default Config + +```json +{ + "rules": { + "skyux-eslint/no-lambda-imports": ["error"] + } +} +``` + +
+ +#### ❌ Invalid Code + +```ts +import { λ3 } from '@skyux/indicators'; + ~~ +``` diff --git a/libs/sdk/skyux-eslint/docs/rules/template/no-deprecated-directives.md b/libs/sdk/skyux-eslint/docs/rules/template/no-deprecated-directives.md new file mode 100644 index 0000000000..e201e03321 --- /dev/null +++ b/libs/sdk/skyux-eslint/docs/rules/template/no-deprecated-directives.md @@ -0,0 +1,37 @@ +# `skyux-eslint-template/no-deprecated-directives` + +Prevents usage of deprecated directives and components in HTML templates. + +- Type: problem + +
+ +## Rule Options + +The rule does not have any configuration options. + +
+ +## Usage Examples + +#### Default Config + +```json +{ + "rules": { + "skyux-eslint-template/no-deprecated-directives": ["error"] + } +} +``` + +#### ❌ Invalid Code + +```html + +~~~~~~~~~~~~~~~~~~~~~ +``` + +```html + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` diff --git a/libs/sdk/skyux-eslint/docs/rules/template/no-unbound-id.md b/libs/sdk/skyux-eslint/docs/rules/template/no-unbound-id.md new file mode 100644 index 0000000000..fb0e7cbf0c --- /dev/null +++ b/libs/sdk/skyux-eslint/docs/rules/template/no-unbound-id.md @@ -0,0 +1,50 @@ +# skyux-eslint-template/no-unbound-id + +Prevents usage of static IDs on HTML elements. For accessibility reasons, all IDs on the page must be unique; to guarantee this, we recommend using the [`skyId`](https://developer.blackbaud.com/skyux/components/id) directive. + +- Type: problem + +
+ +## Rule Options + +The rule does not have any configuration options. + +
+ +## Usage Examples + +#### Default Config + +```json +{ + "rules": { + "skyux-eslint-template/no-unbound-id": ["error"] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html +
+~~~~~~~~~~~~~~ +``` + +
+ +#### ✅ Valid Code + +```html +
+``` + +```html +
+``` + +```html +
+``` diff --git a/libs/sdk/skyux-eslint/docs/rules/template/prefer-label-text.md b/libs/sdk/skyux-eslint/docs/rules/template/prefer-label-text.md new file mode 100644 index 0000000000..2f64617aae --- /dev/null +++ b/libs/sdk/skyux-eslint/docs/rules/template/prefer-label-text.md @@ -0,0 +1,51 @@ +# skyux-eslint-template/prefer-label-text + +Ensures form components set the `labelText` (or `headingText`) attribute, which automatically activates key usability and accessibility features. + +- Type: problem +- 🔧 Supports autofix (`--fix`) + +
+ +## Rule Options + +The rule does not have any configuration options. + +
+ +## Usage Examples + +#### Default Config + +```json +{ + "rules": { + "skyux-eslint-template/prefer-label-text": ["error"] + } +} +``` + +
+ +#### ❌ Invalid Code + +```html + +~~~~~~~~~~~~~~ + + ~~~~~~~~~~~~~~~~~~~~ + {{ 'first_name' | skyAppResources }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + ~~~~~~~~~~~~~~~~~~~~~ + +~~~~~~~~~~~~~~~ +``` + +
+ +#### ✅ Valid Code + +```html + +``` diff --git a/libs/sdk/skyux-eslint/eslint.config.js b/libs/sdk/skyux-eslint/eslint.config.js new file mode 100644 index 0000000000..ec2a3d0b5f --- /dev/null +++ b/libs/sdk/skyux-eslint/eslint.config.js @@ -0,0 +1,5 @@ +const prettier = require('eslint-config-prettier'); +const baseConfig = require('../../../eslint-base.config'); +const overrides = require('../../../eslint-overrides.config'); + +module.exports = [...baseConfig, ...overrides, prettier]; diff --git a/libs/sdk/skyux-eslint/jest.config.ts b/libs/sdk/skyux-eslint/jest.config.ts new file mode 100644 index 0000000000..92eefaff5c --- /dev/null +++ b/libs/sdk/skyux-eslint/jest.config.ts @@ -0,0 +1,26 @@ +export default { + displayName: 'skyux-eslint', + globals: {}, + testEnvironment: 'node', + transform: { + '^.+\\.[tj]sx?$': [ + 'ts-jest', + { + tsconfig: '/tsconfig.spec.json', + }, + ], + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], + coverageDirectory: '../../../coverage/libs/sdk/skyux-eslint', + coverageThreshold: { + global: { + branches: 100, + functions: 100, + lines: 100, + statements: 100, + }, + }, + coveragePathIgnorePatterns: ['/src/schematics/testing'], + preset: '../../../jest.preset.js', + maxWorkers: 2, +}; diff --git a/libs/sdk/skyux-eslint/package.json b/libs/sdk/skyux-eslint/package.json new file mode 100644 index 0000000000..0b70363832 --- /dev/null +++ b/libs/sdk/skyux-eslint/package.json @@ -0,0 +1,35 @@ +{ + "name": "skyux-eslint", + "version": "0.0.0-PLACEHOLDER", + "author": "Blackbaud, Inc.", + "description": "Recommended ESLint configuration for SKY UX projects", + "keywords": [ + "blackbaud", + "skyux" + ], + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/blackbaud/skyux.git" + }, + "bugs": { + "url": "https://github.com/blackbaud/skyux/issues" + }, + "homepage": "https://github.com/blackbaud/skyux#readme", + "schematics": "./collection.json", + "ng-add": { + "save": "devDependencies" + }, + "peerDependencies": { + "@angular-eslint/bundled-angular-compiler": "^18.3.1", + "@angular-eslint/eslint-plugin-template": "^18.3.1", + "@angular-eslint/template-parser": "^18.3.1", + "@angular-eslint/test-utils": "^18.3.1", + "@angular-eslint/utils": "^18.3.1", + "@angular/cli": "^18.2.8", + "@typescript-eslint/utils": "^8.8.0" + }, + "dependencies": { + "tslib": "^2.6.3" + } +} diff --git a/libs/sdk/skyux-eslint/project.json b/libs/sdk/skyux-eslint/project.json new file mode 100644 index 0000000000..fee1ad9a06 --- /dev/null +++ b/libs/sdk/skyux-eslint/project.json @@ -0,0 +1,36 @@ +{ + "name": "skyux-eslint", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/sdk/skyux-eslint/src", + "projectType": "library", + "tags": ["sdk", "npm"], + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/libs/sdk/skyux-eslint", + "tsConfig": "libs/sdk/skyux-eslint/tsconfig.lib.json", + "packageJson": "libs/sdk/skyux-eslint/package.json", + "main": "libs/sdk/skyux-eslint/src/index.ts", + "assets": [ + "libs/sdk/skyux-eslint/*.md", + "libs/sdk/skyux-eslint/collection.json" + ] + } + }, + "lint": { + "executor": "@nx/eslint:lint", + "options": { + "lintFilePatterns": ["{projectRoot}/**/*.ts"] + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/libs/sdk/skyux-eslint"], + "options": { + "jestConfig": "libs/sdk/skyux-eslint/jest.config.ts" + } + } + } +} diff --git a/libs/sdk/skyux-eslint/src/__deprecations.json b/libs/sdk/skyux-eslint/src/__deprecations.json new file mode 100644 index 0000000000..e7e6907106 --- /dev/null +++ b/libs/sdk/skyux-eslint/src/__deprecations.json @@ -0,0 +1 @@ +{"components":{"sky-tile":{"deprecated":false,"properties":{"helpClick":{"reason":"Set the `helpKey` or `helpPopoverContent` inputs instead."},"showHelp":{"reason":"Set the `helpKey` or `helpPopoverContent` inputs instead."}}},"sky-tab":{"deprecated":false,"properties":{"tabHeaderCount":{"reason":"SKY UX no longer recommends adding counts to tabs."}}},"sky-vertical-tab":{"deprecated":false,"properties":{"ariaControls":{"reason":"Now that the vertical tabs provide aria labels automatically, this input is no longer necessary."},"ariaRole":{"reason":"Any other value than `tab` could lead to a poor user experience for users with assistive technology. In the next major version, this property will be automatically set to `tab`."},"tabId":{"reason":"Now that the vertical tabs provide aria labels automatically, this input is no longer necessary."}}},"sky-vertical-tabset":{"deprecated":false,"properties":{"ariaRole":{"reason":"Any other value than `tablist` could lead to a poor user experience for users with assistive technology. In the next major version, this property will be automatically set to `tablist`."}}},"sky-split-view":{"deprecated":false,"properties":{"bindHeightToWindow":{"reason":"We recommend using the `dock` input instead. An example of this can be found in the developer code examples."}}},"sky-select-field":{"deprecated":true,"reason":"`SkySelectFieldComponent` is deprecated. Use `SkyLookupComponent` instead."},"sky-progress-indicator":{"deprecated":false,"properties":{"displayMode":{"reason":"The property was designed to create wizards by setting `displayMode=\"horizontal\"` on progress indicators in modals, but this wizard implementation was replaced by the\n[Wizard (Tabs) component](https://developer.blackbaud.com/skyux/components/progress-indicator)."}}},"sky-dropdown":{"deprecated":false,"properties":{"trigger":{"reason":"We recommend against using this property. If you choose to use the deprecated `hover` value anyway, we recommend that you not use it in combination with the `title` property."}}},"sky-autocomplete":{"deprecated":false,"properties":{"propertiesToSearch":{"reason":"We recommend against using this property. To search specific properties, use the `searchAsync` event instead."},"search":{"reason":"We recommend against using this property. To call a remote data source, use the `searchAsync` event instead."},"searchFilters":{"reason":"We recommend against using this property. To filter results, use the `searchAsync` event instead."}}},"sky-country-field":{"deprecated":false,"properties":{"autocompleteAttribute":{"reason":"SKY UX only supports browser autofill on components where the direct input matches the return value. This input may not behave as expected due to the dropdown selection interaction."}}},"sky-lookup":{"deprecated":false,"properties":{"ariaLabel":{"reason":"Use the input box `labelText` input instead."},"ariaLabelledBy":{"reason":"Use the input box `labelText` input instead."},"autocompleteAttribute":{"reason":"SKY UX only supports browser autofill on components where the direct input matches the return value. This input may not behave as expected due to the dropdown selection interaction."},"data":{"reason":"Use the `searchAsync` event emitter and callback instead to provide data to the lookup component."},"propertiesToSearch":{"reason":"Use the `searchAsync` event emitter and callback instead to provide data to the lookup component."},"search":{"reason":"Use the `searchAsync` event emitter and callback instead to provide searched data to the lookup component."},"searchFilters":{"reason":"Use the `searchAsync` event emitter and callback instead to provide searched data to the lookup component."}}},"sky-list-view-grid":{"deprecated":true,"reason":"List builder view grid and its features are deprecated. Use data entry grid instead. For more information, see https://developer.blackbaud.com/skyux/components/data-entry-grid."},"sky-list-view-checklist":{"deprecated":true,"reason":"List builder view checklist and its features are deprecated. Use repeater instead. For more information, see https://developer.blackbaud.com/skyux/components/repeater."},"sky-list-view-checklist-item":{"deprecated":true},"sky-list":{"deprecated":true,"reason":"List builder and its features are deprecated. Use data manager instead. For more information, see https://developer.blackbaud.com/skyux/components/data-manager."},"sky-list-secondary-actions":{"deprecated":true},"sky-list-toolbar":{"deprecated":true},"sky-list-filter-button":{"deprecated":true},"sky-list-toolbar-view-actions":{"deprecated":true},"sky-list-toolbar-search-actions":{"deprecated":true},"sky-list-filter-summary":{"deprecated":true},"sky-list-filter-inline-item":{"deprecated":true},"sky-list-filter-inline":{"deprecated":true},"sky-list-paging":{"deprecated":true},"sky-list-secondary-action":{"deprecated":true},"sky-list-toolbar-item":{"deprecated":true},"sky-list-toolbar-sort":{"deprecated":true},"sky-card-actions":{"deprecated":true},"sky-card-content":{"deprecated":true},"sky-card-title":{"deprecated":true},"sky-page-summary":{"deprecated":true,"reason":"`SkyPageSummaryComponent` is deprecated. For page templates and techniques to summarize page content, see the page design guidelines. For more information, see https://developer.blackbaud.com/skyux/design/guidelines/page-layouts."},"sky-page-summary-alert":{"deprecated":true},"sky-page-summary-content":{"deprecated":true},"sky-page-summary-image":{"deprecated":true},"sky-page-summary-key-info":{"deprecated":true},"sky-page-summary-status":{"deprecated":true},"sky-page-summary-subtitle":{"deprecated":true},"sky-page-summary-title":{"deprecated":true},"sky-box":{"deprecated":false,"properties":{"ariaLabel":{"reason":"Use `headingText` instead."},"ariaLabelledBy":{"reason":"Use `headingText` instead."}}},"sky-box-header":{"deprecated":true,"reason":"Use `headingText` input on the `sky-box` component instead."},"sky-card":{"deprecated":true,"reason":"`SkyCardComponent` is deprecated. For other SKY UX components that group and list content, see the content containers guidelines. For more information, see https://developer.blackbaud.com/skyux/design/guidelines/content-containers."},"sky-icon":{"deprecated":false,"properties":{"iconType":{"reason":"The icon component now automatically infers which type of icon to use based on the current theme. This input will be removed in a future version."}}},"sky-grid-column":{"deprecated":true,"reason":"`SkyGridComponent` and its features are deprecated. We recommend using the data grid instead. For more information, see https://developer.blackbaud.com/skyux/components/data-grid"},"sky-grid":{"deprecated":true,"reason":"`SkyGridComponent` and its features are deprecated. We recommend using the data grid instead. For more information, see https://developer.blackbaud.com/skyux/components/data-grid"},"sky-radio-group":{"deprecated":false,"properties":{"ariaLabel":{"reason":"Use `headingText` instead."},"ariaLabelledBy":{"reason":"Use `headingText` instead."}}},"sky-radio-label":{"deprecated":true,"reason":"Use `labelText` input on `sky-radio-component` instead."},"sky-radio":{"deprecated":false,"properties":{"label":{"reason":"Use `labelText` instead."},"labelledBy":{"reason":"Use `labelText` instead."},"name":{},"radioType":{"reason":"radioType is no longer supported"},"tabindex":{}}},"sky-toggle-switch-label":{"deprecated":true,"reason":"Use the `labelText` input on the toggle switch component instead."},"sky-toggle-switch":{"deprecated":false,"properties":{"ariaLabel":{"reason":"Use the `labelText` input instead."}}},"sky-checkbox":{"deprecated":false,"properties":{"checkboxType":{"reason":"checkboxType is no longer supported"},"label":{"reason":"Use `labelText` instead."},"labelledBy":{"reason":"Use `labelText` instead."}}},"sky-checkbox-label":{"deprecated":true,"reason":"Use `labelText` input on `sky-checkbox-component` instead."},"sky-file-attachment-label":{"deprecated":true,"reason":"Use the `labelText` input on the single file attachment component instead."},"sky-file-attachment":{"deprecated":false,"properties":{"fileChange":{"reason":"Subscribe to the form control's `valueChanges` event instead."},"validateFn":{"reason":"Add a custom Angular `Validator` function to the `FormControl` instead."}}},"sky-date-range-picker":{"deprecated":false,"properties":{"label":{"reason":"Use the `labelText` input instead."}}}},"directives":{"skyPopover":{"deprecated":false,"properties":{"skyPopoverTrigger":{"reason":"To ensure usability on touch devices, trigger user-invoked popovers on `click` actions rather than `mouseenter` actions."}}},"skyAutocomplete":{"deprecated":false,"properties":{"autocompleteAttribute":{"reason":"SKY UX only supports browser autofill on components where the direct input matches the return value. This input may not behave as expected due to the dropdown selection interaction."}}},"skyColorpickerInput":{"deprecated":false,"properties":{"returnFormat":{},"initialColor":{}}}}} diff --git a/libs/sdk/skyux-eslint/src/configs/README.md b/libs/sdk/skyux-eslint/src/configs/README.md new file mode 100644 index 0000000000..667982143b --- /dev/null +++ b/libs/sdk/skyux-eslint/src/configs/README.md @@ -0,0 +1,9 @@ +# Pre-made flat configs + +## `ts-all` and `template-all` + +Includes all possible rules from `skyux-eslint`. Use this ruleset with caution since new rules can be added between major versions of SKY UX. + +## `ts-recommended` and `template-recommended` + +Includes a recommended set of rules from `skyux-eslint`. We will not add/remove/change rules in this ruleset outside of a new major version release of SKY UX. diff --git a/libs/sdk/skyux-eslint/src/configs/template-all.ts b/libs/sdk/skyux-eslint/src/configs/template-all.ts new file mode 100644 index 0000000000..1e2db75b6c --- /dev/null +++ b/libs/sdk/skyux-eslint/src/configs/template-all.ts @@ -0,0 +1,15 @@ +import type { TSESLint } from '@typescript-eslint/utils'; + +import templateBaseConfig from './template-base'; + +export default [ + templateBaseConfig, + { + name: 'skyux-eslint-template-all', + rules: { + 'skyux-eslint-template/no-deprecated-directives': 'error', + 'skyux-eslint-template/no-unbound-id': 'error', + 'skyux-eslint-template/prefer-label-text': 'error', + }, + }, +] satisfies TSESLint.FlatConfig.ConfigArray; diff --git a/libs/sdk/skyux-eslint/src/configs/template-base.ts b/libs/sdk/skyux-eslint/src/configs/template-base.ts new file mode 100644 index 0000000000..21c27f7de8 --- /dev/null +++ b/libs/sdk/skyux-eslint/src/configs/template-base.ts @@ -0,0 +1,9 @@ +import type { TSESLint } from '@typescript-eslint/utils'; + +import templatePlugin from '../plugins/template-plugin'; + +export default { + plugins: { + 'skyux-eslint-template': templatePlugin, + }, +} satisfies TSESLint.FlatConfig.Config; diff --git a/libs/sdk/skyux-eslint/src/configs/template-recommended.ts b/libs/sdk/skyux-eslint/src/configs/template-recommended.ts new file mode 100644 index 0000000000..1e2db75b6c --- /dev/null +++ b/libs/sdk/skyux-eslint/src/configs/template-recommended.ts @@ -0,0 +1,15 @@ +import type { TSESLint } from '@typescript-eslint/utils'; + +import templateBaseConfig from './template-base'; + +export default [ + templateBaseConfig, + { + name: 'skyux-eslint-template-all', + rules: { + 'skyux-eslint-template/no-deprecated-directives': 'error', + 'skyux-eslint-template/no-unbound-id': 'error', + 'skyux-eslint-template/prefer-label-text': 'error', + }, + }, +] satisfies TSESLint.FlatConfig.ConfigArray; diff --git a/libs/sdk/skyux-eslint/src/configs/ts-all.ts b/libs/sdk/skyux-eslint/src/configs/ts-all.ts new file mode 100644 index 0000000000..ef1b7b4b32 --- /dev/null +++ b/libs/sdk/skyux-eslint/src/configs/ts-all.ts @@ -0,0 +1,15 @@ +import type { TSESLint } from '@typescript-eslint/utils'; + +import tsBaseConfig from './ts-base'; +import tsRecommendedTypeChecked from './ts-base-type-checked'; + +export default [ + tsBaseConfig, + tsRecommendedTypeChecked, + { + name: 'skyux-eslint/ts-all', + rules: { + 'skyux-eslint/no-lambda-imports': 'error', + }, + }, +] satisfies TSESLint.FlatConfig.ConfigArray; diff --git a/libs/sdk/skyux-eslint/src/configs/ts-base-type-checked.ts b/libs/sdk/skyux-eslint/src/configs/ts-base-type-checked.ts new file mode 100644 index 0000000000..f78bf93a81 --- /dev/null +++ b/libs/sdk/skyux-eslint/src/configs/ts-base-type-checked.ts @@ -0,0 +1,29 @@ +import type { TSESLint } from '@typescript-eslint/utils'; + +export default { + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: '.', + }, + }, + name: 'skyux-eslint/ts-base-type-checked', + rules: { + 'dot-notation': 'off', + '@typescript-eslint/dot-notation': 'error', + '@typescript-eslint/no-base-to-string': 'error', + '@typescript-eslint/no-confusing-void-expression': 'error', + '@typescript-eslint/no-deprecated': 'error', + '@typescript-eslint/no-mixed-enums': 'error', + '@typescript-eslint/no-redundant-type-constituents': 'error', + '@typescript-eslint/non-nullable-type-assertion-style': 'error', + '@typescript-eslint/prefer-includes': 'error', + '@typescript-eslint/prefer-nullish-coalescing': 'error', + '@typescript-eslint/prefer-optional-chain': 'error', + '@typescript-eslint/prefer-reduce-type-parameter': 'error', + '@typescript-eslint/prefer-return-this-type': 'error', + '@typescript-eslint/prefer-string-starts-ends-with': 'error', + '@typescript-eslint/switch-exhaustiveness-check': 'error', + '@typescript-eslint/unbound-method': ['error', { ignoreStatic: true }], + }, +} satisfies TSESLint.FlatConfig.Config; diff --git a/libs/sdk/skyux-eslint/src/configs/ts-base.ts b/libs/sdk/skyux-eslint/src/configs/ts-base.ts new file mode 100644 index 0000000000..dc28e17fe1 --- /dev/null +++ b/libs/sdk/skyux-eslint/src/configs/ts-base.ts @@ -0,0 +1,87 @@ +import type { TSESLint } from '@typescript-eslint/utils'; + +import tsPlugin from '../plugins/ts-plugin'; + +export default { + linterOptions: { + reportUnusedDisableDirectives: true, + }, + name: 'skyux-eslint/ts-base', + plugins: { + 'skyux-eslint': tsPlugin, + }, + rules: { + curly: 'error', + 'default-case': 'error', + 'default-case-last': 'error', + eqeqeq: ['error', 'always'], + 'guard-for-in': 'error', + 'id-denylist': [ + 'error', + 'any', + 'boolean', + 'Boolean', + 'number', + 'Number', + 'object', + 'Object', + 'string', + 'String', + 'undefined', + 'Undefined', + ], + 'no-alert': 'error', + 'no-caller': 'error', + 'no-console': 'error', + 'no-constant-binary-expression': 'error', + 'no-constructor-return': 'error', + 'no-duplicate-imports': ['error', { includeExports: true }], + 'no-eval': 'error', + 'no-lonely-if': 'error', + 'no-mixed-operators': 'error', + 'no-new-wrappers': 'error', + 'no-self-compare': 'error', + 'no-template-curly-in-string': 'error', + 'no-unmodified-loop-condition': 'error', + 'no-unreachable-loop': 'error', + 'no-unused-private-class-members': 'error', + 'no-useless-return': 'error', + 'prefer-arrow-callback': 'error', + 'prefer-regex-literals': 'error', + radix: 'error', + 'require-atomic-updates': 'error', + '@angular-eslint/no-lifecycle-call': 'error', + '@angular-eslint/sort-ngmodule-metadata-arrays': 'error', + '@typescript-eslint/array-type': 'error', + '@typescript-eslint/ban-tslint-comment': 'error', + '@typescript-eslint/consistent-generic-constructors': 'error', + 'default-param-last': 'off', + '@typescript-eslint/default-param-last': 'error', + '@typescript-eslint/explicit-member-accessibility': [ + 'error', + { overrides: { constructors: 'no-public' } }, + ], + '@typescript-eslint/explicit-module-boundary-types': 'error', + '@typescript-eslint/no-confusing-non-null-assertion': 'error', + '@typescript-eslint/no-duplicate-enum-values': 'error', + '@typescript-eslint/no-non-null-asserted-nullish-coalescing': 'error', + 'no-shadow': 'off', + '@typescript-eslint/no-shadow': 'error', + '@typescript-eslint/no-unsafe-declaration-merging': 'error', + 'no-unused-expressions': 'off', + '@typescript-eslint/no-unused-expressions': 'error', + 'no-use-before-define': 'off', + '@typescript-eslint/no-use-before-define': [ + 'error', + { + functions: false, + classes: true, + variables: true, + allowNamedExports: false, + }, + ], + '@typescript-eslint/prefer-for-of': 'error', + '@typescript-eslint/prefer-function-type': 'error', + '@typescript-eslint/prefer-literal-enum-member': 'error', + }, +} satisfies TSESLint.FlatConfig.Config; diff --git a/libs/sdk/skyux-eslint/src/configs/ts-recommended.ts b/libs/sdk/skyux-eslint/src/configs/ts-recommended.ts new file mode 100644 index 0000000000..0f768484b5 --- /dev/null +++ b/libs/sdk/skyux-eslint/src/configs/ts-recommended.ts @@ -0,0 +1,15 @@ +import type { TSESLint } from '@typescript-eslint/utils'; + +import tsBaseConfig from './ts-base'; +import tsBaseConfigTypeChecked from './ts-base-type-checked'; + +export default [ + tsBaseConfig, + tsBaseConfigTypeChecked, + { + name: 'skyux-eslint/ts-all', + rules: { + 'skyux-eslint/no-lambda-imports': 'error', + }, + }, +] satisfies TSESLint.FlatConfig.ConfigArray; diff --git a/libs/sdk/skyux-eslint/src/index.ts b/libs/sdk/skyux-eslint/src/index.ts new file mode 100644 index 0000000000..a7a516dc39 --- /dev/null +++ b/libs/sdk/skyux-eslint/src/index.ts @@ -0,0 +1,21 @@ +import templateAll from './configs/template-all'; +import templateRecommended from './configs/template-recommended'; +import tsAll from './configs/ts-all'; +import tsRecommended from './configs/ts-recommended'; + +const configs = { + templateAll, + templateRecommended, + tsAll, + tsRecommended, +}; + +// ESM +export default { + configs, +}; + +// CommonJS +export { configs }; + +export { ngAdd } from './schematics/ng-add/ng-add.schematic'; diff --git a/libs/sdk/skyux-eslint/src/plugins/template-plugin.ts b/libs/sdk/skyux-eslint/src/plugins/template-plugin.ts new file mode 100644 index 0000000000..dfaae0da0c --- /dev/null +++ b/libs/sdk/skyux-eslint/src/plugins/template-plugin.ts @@ -0,0 +1,27 @@ +import { processors } from '@angular-eslint/eslint-plugin-template'; +import type { TSESLint } from '@typescript-eslint/utils'; + +import { + rule as noDeprecatedDirectives, + RULE_NAME as noDeprecatedDirectivesRuleName, +} from '../rules/template/no-deprecated-directives'; +import { + rule as noUnboundId, + RULE_NAME as noUnboundIdRuleName, +} from '../rules/template/no-unbound-id'; +import { + rule as preferLabelText, + RULE_NAME as preferLabelTextRuleName, +} from '../rules/template/prefer-label-text'; + +export default { + meta: { + name: 'skyux-eslint-template', + }, + processors, + rules: { + [noDeprecatedDirectivesRuleName]: noDeprecatedDirectives, + [noUnboundIdRuleName]: noUnboundId, + [preferLabelTextRuleName]: preferLabelText, + }, +} satisfies TSESLint.FlatConfig.Plugin; diff --git a/libs/sdk/skyux-eslint/src/plugins/ts-plugin.ts b/libs/sdk/skyux-eslint/src/plugins/ts-plugin.ts new file mode 100644 index 0000000000..6c86851f48 --- /dev/null +++ b/libs/sdk/skyux-eslint/src/plugins/ts-plugin.ts @@ -0,0 +1,17 @@ +import type { TSESLint } from '@typescript-eslint/utils'; + +import { + rule as noLambdaImports, + RULE_NAME as noLambdaImportsRuleName, +} from '../rules/no-lambda-imports'; + +const tsPlugin: TSESLint.FlatConfig.Plugin = { + meta: { + name: 'skyux-eslint', + }, + rules: { + [noLambdaImportsRuleName]: noLambdaImports, + }, +}; + +export default tsPlugin; diff --git a/libs/sdk/skyux-eslint/src/rules/no-lambda-imports.spec.ts b/libs/sdk/skyux-eslint/src/rules/no-lambda-imports.spec.ts new file mode 100644 index 0000000000..014852834c --- /dev/null +++ b/libs/sdk/skyux-eslint/src/rules/no-lambda-imports.spec.ts @@ -0,0 +1,52 @@ +import { + RuleTester, + convertAnnotatedSourceToFailureCase, +} from '@angular-eslint/test-utils'; + +import { RULE_NAME, messageId, rule } from './no-lambda-imports'; + +const ruleTester = new RuleTester(); + +ruleTester.run(RULE_NAME, rule, { + valid: [ + `import { foo } from '@skyux/foo';`, + `import '@skyux/foo';`, + `import { Lλ } from 'foo';`, + ], + invalid: [ + convertAnnotatedSourceToFailureCase({ + description: 'it should fail when importing a lambda file', + annotatedSource: ` + import { λ1999 } from '@skyux/foo'; + ~~~~~ + `, + messageId, + data: { + importName: 'λ1999', + }, + }), + convertAnnotatedSourceToFailureCase({ + description: 'it should fail when importing multiple lambda files', + annotatedSource: ` + import { SkySummaryActionBarModule, λ3, λ5 } from '@skyux/foo'; + ~~ ^^ + `, + messages: [ + { + char: '~', + messageId, + data: { + importName: 'λ3', + }, + }, + { + char: '^', + messageId, + data: { + importName: 'λ5', + }, + }, + ], + }), + ], +}); diff --git a/libs/sdk/skyux-eslint/src/rules/no-lambda-imports.ts b/libs/sdk/skyux-eslint/src/rules/no-lambda-imports.ts new file mode 100644 index 0000000000..333e7b9bdc --- /dev/null +++ b/libs/sdk/skyux-eslint/src/rules/no-lambda-imports.ts @@ -0,0 +1,45 @@ +import type { TSESTree } from '@typescript-eslint/utils'; + +import { createESLintRule } from './utils/create-eslint-rule'; + +export const RULE_NAME = 'no-lambda-imports'; +export const messageId = 'noLambdaImports'; + +export const rule = createESLintRule({ + create(context) { + return { + ['ImportDeclaration'](node: TSESTree.ImportDeclaration): void { + const lambdaImports = node.specifiers.filter((specifier) => { + return specifier.local.name.startsWith('λ'); + }); + + if (lambdaImports.length > 0) { + for (const lambdaImport of lambdaImports) { + const data = { + importName: lambdaImport.local.name, + }; + + context.report({ + loc: lambdaImport.loc, + messageId, + data, + }); + } + } + }, + }; + }, + defaultOptions: [], + meta: { + docs: { + description: + 'Prevents importing components from SKY UX packages that start with the "λ" lambda character.', + }, + messages: { + [messageId]: '{{importName}} is not included in the SKY UX public API', + }, + schema: [], + type: 'problem', + }, + name: RULE_NAME, +}); diff --git a/libs/sdk/skyux-eslint/src/rules/template/no-deprecated-directives.spec.ts b/libs/sdk/skyux-eslint/src/rules/template/no-deprecated-directives.spec.ts new file mode 100644 index 0000000000..7a08cf0672 --- /dev/null +++ b/libs/sdk/skyux-eslint/src/rules/template/no-deprecated-directives.spec.ts @@ -0,0 +1,149 @@ +import { convertAnnotatedSourceToFailureCase } from '@angular-eslint/test-utils'; + +import { createTemplateRuleTester } from '../testing/create-template-rule-tester'; + +import { RULE_NAME, rule } from './no-deprecated-directives'; + +const ruleTester = createTemplateRuleTester(); + +jest.mock('../../__deprecations.json', () => { + return { + components: { + 'sky-card': { + deprecated: true, + reason: 'Do not use the card component.', + }, + 'sky-file-attachment': { + deprecated: false, + properties: { + fileChange: { + reason: + "Subscribe to the form control's `valueChanges` event instead.", + }, + validateFn: { + reason: + 'Add a custom Angular `Validator` function to the `FormControl` instead.', + }, + }, + }, + }, + directives: { + skyDeprecatedThing: { + deprecated: true, + }, + skyFoo: { + properties: { + noReason: { + deprecated: true, + }, + }, + }, + skyAutocomplete: { + deprecated: false, + properties: { + autocompleteAttribute: { + reason: 'Do not use it.', + }, + }, + }, + }, + }; +}); + +ruleTester.run(RULE_NAME, rule, { + valid: [], + invalid: [ + convertAnnotatedSourceToFailureCase({ + description: 'should fail when using deprecated directives', + annotatedSource: ` + + ~~~~~~~~~~~~~~~~~~ + `, + messageId: 'noDeprecatedDirectives', + data: { + reason: '', + selector: 'skyDeprecatedThing', + }, + }), + convertAnnotatedSourceToFailureCase({ + description: 'should fail when using deprecated features of directives', + annotatedSource: ` + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + `, + messageId: 'noDeprecatedDirectiveProperties', + data: { + reason: 'Do not use it.', + selector: 'input', + property: 'autocompleteAttribute', + }, + }), + convertAnnotatedSourceToFailureCase({ + description: + 'should work if a deprecated property does not have a reason', + annotatedSource: ` + + ~~~~~~~~ + `, + messageId: 'noDeprecatedDirectiveProperties', + data: { + property: 'noReason', + reason: '', + selector: 'input', + }, + }), + convertAnnotatedSourceToFailureCase({ + description: 'should fail when using deprecated components', + annotatedSource: ` + + ~~~~~~~~~~~~~~~~~~~~~ + `, + messageId: 'noDeprecatedDirectives', + data: { + reason: 'Do not use the card component.', + selector: 'sky-card', + }, + }), + convertAnnotatedSourceToFailureCase({ + description: 'should fail when using bound deprecated input', + annotatedSource: ` + + ~~~~~~~~~~~~~~~~~~ + `, + messageId: 'noDeprecatedDirectiveProperties', + data: { + property: 'validateFn', + reason: + 'Add a custom Angular `Validator` function to the `FormControl` instead.', + selector: 'sky-file-attachment', + }, + }), + convertAnnotatedSourceToFailureCase({ + description: 'should fail when using unbound deprecated input', + annotatedSource: ` + + ~~~~~~~~~~~~~~~~~~~~~~ + `, + messageId: 'noDeprecatedDirectiveProperties', + data: { + property: 'validateFn', + reason: + 'Add a custom Angular `Validator` function to the `FormControl` instead.', + selector: 'sky-file-attachment', + }, + }), + convertAnnotatedSourceToFailureCase({ + description: 'should fail when using deprecated output', + annotatedSource: ` + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + `, + messageId: 'noDeprecatedDirectiveProperties', + data: { + property: 'fileChange', + reason: "Subscribe to the form control's `valueChanges` event instead.", + selector: 'sky-file-attachment', + }, + }), + ], +}); diff --git a/libs/sdk/skyux-eslint/src/rules/template/no-deprecated-directives.ts b/libs/sdk/skyux-eslint/src/rules/template/no-deprecated-directives.ts new file mode 100644 index 0000000000..522abd6b9d --- /dev/null +++ b/libs/sdk/skyux-eslint/src/rules/template/no-deprecated-directives.ts @@ -0,0 +1,137 @@ +import { + type TmplAstBoundAttribute, + type TmplAstElement, + type TmplAstTextAttribute, +} from '@angular-eslint/bundled-angular-compiler'; +import { getTemplateParserServices } from '@angular-eslint/utils'; +import { RuleListener } from '@typescript-eslint/utils/ts-eslint'; + +import deprecationsJson from '../../__deprecations.json'; +import { createESLintTemplateRule } from '../utils/create-eslint-template-rule'; + +const DEPRECATIONS = deprecationsJson as Deprecations; + +interface DeprecatedProperty { + reason?: string; +} + +type DeprecatedProperties = Record; + +interface DeprecatedDirective { + deprecated: boolean; + reason?: string; + properties?: DeprecatedProperties; +} + +interface Deprecations { + components?: Record; + directives?: Record; +} + +export const RULE_NAME = 'no-deprecated-directives'; + +export const rule = createESLintTemplateRule({ + create(context) { + const parserServices = getTemplateParserServices(context); + + const reportDeprecatedDirective = ( + el: TmplAstElement | TmplAstBoundAttribute | TmplAstTextAttribute, + docs: DeprecatedDirective, + ): void => { + context.report({ + loc: parserServices.convertNodeSourceSpanToLoc(el.sourceSpan), + messageId: 'noDeprecatedDirectives', + data: { + reason: docs?.reason ?? '', + selector: el.name, + }, + }); + }; + + const reportDeprecatedInputsOutputs = ( + el: TmplAstElement, + docs: DeprecatedDirective, + ): void => { + if (docs.properties) { + for (const [propertyName, propertyDetails] of Object.entries( + docs.properties, + )) { + const attr = + el.inputs.find((input) => input.name === propertyName) || + el.outputs.find((output) => output.name === propertyName) || + el.attributes.find((attr) => attr.name === propertyName); + + if (attr) { + context.report({ + loc: parserServices.convertNodeSourceSpanToLoc(attr.sourceSpan), + messageId: 'noDeprecatedDirectiveProperties', + data: { + property: propertyName, + reason: propertyDetails.reason ?? '', + selector: el.name, + }, + }); + } + } + } + }; + + const rules: RuleListener = {}; + + if (DEPRECATIONS.components !== undefined) { + const components = DEPRECATIONS.components; + const selectors = Object.keys(components).join('|'); + + rules[`Element$1[name=/^(${selectors})$/]`] = ( + el: TmplAstElement, + ): void => { + const docs = components[el.name]; + + if (docs.deprecated) { + reportDeprecatedDirective(el, docs); + } else { + reportDeprecatedInputsOutputs(el, docs); + } + }; + } + + if (DEPRECATIONS.directives !== undefined) { + const directives = DEPRECATIONS.directives; + const selectors = Object.keys(directives).join('|'); + + rules[ + `:matches(BoundAttribute, TextAttribute)[name=/^(${selectors})$/]` + ] = ( + el: (TmplAstBoundAttribute | TmplAstTextAttribute) & { + parent: TmplAstElement; + }, + ): void => { + const docs = directives[el.name]; + + if (docs.deprecated) { + reportDeprecatedDirective(el, docs); + } else { + reportDeprecatedInputsOutputs(el.parent, docs); + } + }; + } + + return rules; + }, + defaultOptions: [], + meta: { + docs: { + description: + 'Prevents usage of deprecated directives and components in consumer templates.', + }, + messages: { + noDeprecatedDirectives: + '<{{selector}}> element is deprecated. {{reason}}', + noDeprecatedDirectiveProperties: + 'The attribute `{{property}}` on the <{{selector}}> element is deprecated. {{reason}}', + }, + schema: [], + type: 'problem', + }, + name: RULE_NAME, +}); diff --git a/libs/sdk/skyux-eslint/src/rules/template/no-unbound-id.spec.ts b/libs/sdk/skyux-eslint/src/rules/template/no-unbound-id.spec.ts new file mode 100644 index 0000000000..2d6659dcf9 --- /dev/null +++ b/libs/sdk/skyux-eslint/src/rules/template/no-unbound-id.spec.ts @@ -0,0 +1,26 @@ +import { convertAnnotatedSourceToFailureCase } from '@angular-eslint/test-utils'; + +import { createTemplateRuleTester } from '../testing/create-template-rule-tester'; + +import { RULE_NAME, messageId, rule } from './no-unbound-id'; + +const ruleTester = createTemplateRuleTester(); + +ruleTester.run(RULE_NAME, rule, { + valid: [ + '', + '', + '

', + ], + invalid: [ + convertAnnotatedSourceToFailureCase({ + description: 'should fail if id attribute statically set', + annotatedSource: ` + + ~~~~~~~~~~~ + `, + messageId, + data: { selector: 'span' }, + }), + ], +}); diff --git a/libs/sdk/skyux-eslint/src/rules/template/no-unbound-id.ts b/libs/sdk/skyux-eslint/src/rules/template/no-unbound-id.ts new file mode 100644 index 0000000000..4dc3dc0cfb --- /dev/null +++ b/libs/sdk/skyux-eslint/src/rules/template/no-unbound-id.ts @@ -0,0 +1,44 @@ +import { type TmplAstElement } from '@angular-eslint/bundled-angular-compiler'; +import { getTemplateParserServices } from '@angular-eslint/utils'; + +import { createESLintTemplateRule } from '../utils/create-eslint-template-rule'; + +export const RULE_NAME = 'no-unbound-id'; +export const messageId = 'noUnboundId'; + +export const rule = createESLintTemplateRule({ + create(context) { + const parserServices = getTemplateParserServices(context); + + return { + ['Element$1'](el: TmplAstElement): void { + const idAttr = el.attributes.find((attribute) => { + return attribute.name === 'id'; + }); + + if (idAttr) { + context.report({ + loc: parserServices.convertNodeSourceSpanToLoc(idAttr.sourceSpan), + messageId, + data: { + selector: el.name, + }, + }); + } + }, + }; + }, + defaultOptions: [], + meta: { + docs: { + description: 'Prevents usage of static IDs on HTML elements.', + }, + messages: { + [messageId]: + '<{{selector}}> element must not have a static ID. Use the `skyId` directive instead.', + }, + schema: [], + type: 'problem', + }, + name: RULE_NAME, +}); diff --git a/libs/sdk/skyux-eslint/src/rules/template/prefer-label-text.spec.ts b/libs/sdk/skyux-eslint/src/rules/template/prefer-label-text.spec.ts new file mode 100644 index 0000000000..48498865d5 --- /dev/null +++ b/libs/sdk/skyux-eslint/src/rules/template/prefer-label-text.spec.ts @@ -0,0 +1,124 @@ +import { convertAnnotatedSourceToFailureCase } from '@angular-eslint/test-utils'; + +import { createTemplateRuleTester } from '../testing/create-template-rule-tester'; + +import { RULE_NAME, messageId, rule } from './prefer-label-text'; + +const ruleTester = createTemplateRuleTester(); + +ruleTester.run(RULE_NAME, rule, { + valid: [ + ``, + ``, + ``, + ``, + ], + invalid: [ + convertAnnotatedSourceToFailureCase({ + description: + 'should fail if labelText not set and has label element with bound text', + annotatedSource: ` + + ~~~~~~~~~~~~~~ + + ~~~~~~~~~~~~~~~~~~~~ + {{ 'first_name' | skyAppResources }} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + ~~~~~~~~~~~~~~~~~~~~~ + + ~~~~~~~~~~~~~~~ + `, + annotatedOutput: ` + + ~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~~ + + ~~~~~~~~~~~~~~~ + `, + messageId, + data: { + selector: 'sky-checkbox', + labelInputName: 'labelText', + labelSelector: 'sky-checkbox-label', + }, + }), + convertAnnotatedSourceToFailureCase({ + description: 'should fail if labelText not set and has label element', + annotatedSource: ` + + ~~~~~~~~~~~~~~ + + ~~~~~~~~~~~~~~~~~~~~ + Foo + ~~~ + + ~~~~~~~~~~~~~~~~~~~~~ + + ~~~~~~~~~~~~~~~ + `, + annotatedOutput: ` + + ~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~~ + + ~~~~~~~~~~~~~~~ + `, + messageId, + data: { + selector: 'sky-checkbox', + labelInputName: 'labelText', + labelSelector: 'sky-checkbox-label', + }, + }), + convertAnnotatedSourceToFailureCase({ + description: 'should fail if labelText set but label element remains', + annotatedSource: ` + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + `, + annotatedOutput: ` + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + `, + messageId, + data: { + selector: 'sky-input-box', + labelInputName: 'labelText', + labelSelector: 'label', + }, + }), + convertAnnotatedSourceToFailureCase({ + description: + 'should fail if labelText not set and has child elements within label', + annotatedSource: ` + + ~~~~~~~~~~~~~~ + + ~~~~~~~~~~~~~~~~~~~~ +

Foo

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +
+ ~~~~~~~~~~~~~~~~~~~~~ +
+ ~~~~~~~~~~~~~~~ + `, + annotatedOutput: ` + + ~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~~ + + ~~~~~~~~~~~~~~~ + `, + messageId, + data: { + selector: 'sky-checkbox', + labelInputName: 'labelText', + labelSelector: 'sky-checkbox-label', + }, + }), + ], +}); diff --git a/libs/sdk/skyux-eslint/src/rules/template/prefer-label-text.ts b/libs/sdk/skyux-eslint/src/rules/template/prefer-label-text.ts new file mode 100644 index 0000000000..f8c173a22b --- /dev/null +++ b/libs/sdk/skyux-eslint/src/rules/template/prefer-label-text.ts @@ -0,0 +1,133 @@ +import { TmplAstElement } from '@angular-eslint/bundled-angular-compiler'; +import { getTemplateParserServices } from '@angular-eslint/utils'; + +import { createESLintTemplateRule } from '../utils/create-eslint-template-rule'; +import { getChildNodeOf } from '../utils/get-child-node-of'; +import { getTextContent } from '../utils/get-text-content'; + +export const RULE_NAME = 'prefer-label-text'; +export const messageId = 'preferLabelText'; + +const COMPONENTS_WITH_LABEL_TEXT: { + selector: string; + labelInputName: string; + labelSelector: string; +}[] = [ + { + selector: 'sky-box', + labelInputName: 'headingText', + labelSelector: 'sky-box-header', + }, + { + selector: 'sky-checkbox', + labelInputName: 'labelText', + labelSelector: 'sky-checkbox-label', + }, + { + selector: 'sky-file-attachment', + labelInputName: 'labelText', + labelSelector: 'sky-file-attachment-label', + }, + { + selector: 'sky-input-box', + labelInputName: 'labelText', + labelSelector: 'label', + }, + { + selector: 'sky-modal', + labelInputName: 'headingText', + labelSelector: 'sky-modal-header', + }, + { + selector: 'sky-radio', + labelInputName: 'labelText', + labelSelector: 'sky-radio-label', + }, + { + selector: 'sky-toggle-switch', + labelInputName: 'labelText', + labelSelector: 'sky-toggle-switch-label', + }, +]; + +const SELECTORS_WITH_LABEL_COMPONENTS = COMPONENTS_WITH_LABEL_TEXT.map( + (c) => c.selector, +).join('|'); + +export const rule = createESLintTemplateRule({ + create(context) { + const parserServices = getTemplateParserServices(context); + + return { + [`Element$1[name=/^(${SELECTORS_WITH_LABEL_COMPONENTS})$/]`]( + el: TmplAstElement, + ): void { + const config = COMPONENTS_WITH_LABEL_TEXT.find( + (c) => c.selector === el.name, + ); + + /* istanbul ignore if: safety check */ + if (!config) { + return; + } + + const { labelInputName, labelSelector } = config; + + const hasLabelText = + el.inputs.some((i) => i.name === labelInputName) || + el.attributes.some((i) => i.name === labelInputName); + + const labelEl = getChildNodeOf(el, labelSelector); + + if (labelEl) { + context.report({ + loc: parserServices.convertNodeSourceSpanToLoc(el.sourceSpan), + messageId, + data: { + selector: el.name, + labelInputName, + labelSelector, + }, + fix: (fixer) => { + const textContent = getTextContent(labelEl); + const textReplacement = ` ${labelInputName}="${textContent}"`; + const range = [ + el.startSourceSpan.end.offset - 1, + el.startSourceSpan.end.offset, + ] as const; + + const fixers = [ + fixer.removeRange([ + labelEl.sourceSpan.start.offset, + labelEl.sourceSpan.end.offset, + ]), + ]; + + if (!hasLabelText) { + fixers.push( + fixer.insertTextBeforeRange(range, textReplacement), + ); + } + + return fixers; + }, + }); + } + }, + }; + }, + defaultOptions: [], + meta: { + docs: { + description: 'Use label text.', + }, + messages: { + [messageId]: + 'Use of <{{labelSelector}}> element is not recommended. Set `{{labelInputName}}` on the <{{selector}}> element instead.', + }, + schema: [], + type: 'problem', + fixable: 'code', + }, + name: RULE_NAME, +}); diff --git a/libs/sdk/skyux-eslint/src/rules/testing/create-template-rule-tester.ts b/libs/sdk/skyux-eslint/src/rules/testing/create-template-rule-tester.ts new file mode 100644 index 0000000000..73ce84fa86 --- /dev/null +++ b/libs/sdk/skyux-eslint/src/rules/testing/create-template-rule-tester.ts @@ -0,0 +1,12 @@ +import { RuleTester } from '@angular-eslint/test-utils'; + +// eslint-disable-next-line @typescript-eslint/no-require-imports +const parser = require('@angular-eslint/template-parser'); + +export function createTemplateRuleTester(): RuleTester { + return new RuleTester({ + languageOptions: { + parser, + }, + }); +} diff --git a/libs/sdk/skyux-eslint/src/rules/utils/create-eslint-rule.ts b/libs/sdk/skyux-eslint/src/rules/utils/create-eslint-rule.ts new file mode 100644 index 0000000000..dfb9d3a640 --- /dev/null +++ b/libs/sdk/skyux-eslint/src/rules/utils/create-eslint-rule.ts @@ -0,0 +1,18 @@ +import { ESLintUtils } from '@typescript-eslint/utils'; + +export function createESLintRule( + config: Readonly< + ESLintUtils.RuleWithMetaAndName + >, +): ESLintUtils.RuleModule< + string, + readonly unknown[], + unknown, + ESLintUtils.RuleListener +> { + const ruleCreator = ESLintUtils.RuleCreator((ruleName) => { + return `https://github.com/blackbaud/skyux/blob/main/libs/cdk/skyux-eslint/docs/rules/${ruleName}.md`; + }); + + return ruleCreator(config); +} diff --git a/libs/sdk/skyux-eslint/src/rules/utils/create-eslint-template-rule.ts b/libs/sdk/skyux-eslint/src/rules/utils/create-eslint-template-rule.ts new file mode 100644 index 0000000000..abfc39b157 --- /dev/null +++ b/libs/sdk/skyux-eslint/src/rules/utils/create-eslint-template-rule.ts @@ -0,0 +1,18 @@ +import { ESLintUtils } from '@typescript-eslint/utils'; + +export function createESLintTemplateRule( + config: Readonly< + ESLintUtils.RuleWithMetaAndName + >, +): ESLintUtils.RuleModule< + string, + readonly unknown[], + unknown, + ESLintUtils.RuleListener +> { + const ruleCreator = ESLintUtils.RuleCreator((ruleName) => { + return `https://github.com/blackbaud/skyux/blob/main/libs/cdk/skyux-eslint/docs/rules/template/${ruleName}.md`; + }); + + return ruleCreator(config); +} diff --git a/libs/sdk/skyux-eslint/src/rules/utils/get-child-node-of.ts b/libs/sdk/skyux-eslint/src/rules/utils/get-child-node-of.ts new file mode 100644 index 0000000000..2f9ba23016 --- /dev/null +++ b/libs/sdk/skyux-eslint/src/rules/utils/get-child-node-of.ts @@ -0,0 +1,19 @@ +/* istanbul ignore file */ +import { TmplAstElement } from '@angular-eslint/bundled-angular-compiler'; + +export function getChildNodeOf( + el: TmplAstElement, + childNodeName: string, +): TmplAstElement | undefined { + return el.children.find((child) => { + if (child instanceof TmplAstElement) { + if (child.name === childNodeName) { + return true; + } + + return getChildNodeOf(child, childNodeName); + } + + return false; + }) as TmplAstElement | undefined; +} diff --git a/libs/sdk/skyux-eslint/src/rules/utils/get-text-content.ts b/libs/sdk/skyux-eslint/src/rules/utils/get-text-content.ts new file mode 100644 index 0000000000..1226d1c67c --- /dev/null +++ b/libs/sdk/skyux-eslint/src/rules/utils/get-text-content.ts @@ -0,0 +1,21 @@ +import { + TmplAstBoundText, + TmplAstElement, + TmplAstText, +} from '@angular-eslint/bundled-angular-compiler'; + +export function getTextContent(el: TmplAstElement): string { + let text = ''; + + el.children.forEach((child) => { + if (child instanceof TmplAstText) { + text += child.value.trim(); + } else if (child instanceof TmplAstBoundText) { + text += child.sourceSpan.toString().trim(); + } else if (child instanceof TmplAstElement) { + text += getTextContent(child); + } + }); + + return text; +} diff --git a/libs/sdk/skyux-eslint/src/schematics/ng-add/ng-add.schematic.spec.ts b/libs/sdk/skyux-eslint/src/schematics/ng-add/ng-add.schematic.spec.ts new file mode 100644 index 0000000000..ae768ed3d0 --- /dev/null +++ b/libs/sdk/skyux-eslint/src/schematics/ng-add/ng-add.schematic.spec.ts @@ -0,0 +1,104 @@ +import { + SchematicTestRunner, + UnitTestTree, +} from '@angular-devkit/schematics/testing'; + +import path from 'node:path'; + +import { createTestApp } from '../testing/scaffold'; + +interface PackageJson { + dependencies?: Record; + devDependencies?: Record; +} + +const COLLECTION_PATH = path.resolve(__dirname, '../../../collection.json'); + +describe('ng-add.schematic', () => { + const runner = new SchematicTestRunner('schematics', COLLECTION_PATH); + const projectName = 'my-app'; + + function readPackageJson(tree: UnitTestTree): PackageJson { + return tree.readJson('/package.json') as PackageJson; + } + + async function setupTest(options: { packageJson?: PackageJson }): Promise<{ + runSchematic: (options?: { project?: string }) => Promise; + tree: UnitTestTree; + }> { + const tree = await createTestApp(runner, { + projectName, + }); + + let packageJson = options.packageJson; + + if (!options.packageJson) { + packageJson = readPackageJson(tree); + packageJson.devDependencies ??= {}; + packageJson.devDependencies['@angular-eslint/schematics'] = '*'; + } + + tree.overwrite('package.json', JSON.stringify(packageJson)); + + const runSchematic = ( + options: { project?: string } = {}, + ): Promise => { + return runner.runSchematic('ng-add', options, tree); + }; + + return { + runSchematic, + tree, + }; + } + + it("should abort if '@angular-eslint/schematics' is not installed", async () => { + const { runSchematic } = await setupTest({ + packageJson: { + devDependencies: {}, // <-- empty + }, + }); + + await expect(() => runSchematic()).rejects.toThrow( + new Error( + "The package 'angular-eslint' is not installed. " + + "Run 'ng add @angular-eslint/schematics' and try this command again.\n" + + 'See: https://github.com/angular-eslint/angular-eslint#quick-start', + ), + ); + }); + + it("should not abort if 'angular-eslint' is installed", async () => { + const { runSchematic, tree } = await setupTest({ + packageJson: { + devDependencies: { + 'angular-eslint': '*', + }, + }, + }); + + await runSchematic(); + + const packageJson = readPackageJson(tree); + + expect(packageJson.devDependencies?.['skyux-eslint']).toBeDefined(); + }); + + it('should harden the version of the skyux-eslint package', async () => { + const { runSchematic, tree } = await setupTest({ + packageJson: { + devDependencies: { + '@angular-eslint/schematics': '*', + }, + }, + }); + + await runSchematic(); + + const packageJson = readPackageJson(tree); + + expect(packageJson.devDependencies?.['skyux-eslint']).toEqual( + '0.0.0-PLACEHOLDER', + ); + }); +}); diff --git a/libs/sdk/skyux-eslint/src/schematics/ng-add/ng-add.schematic.ts b/libs/sdk/skyux-eslint/src/schematics/ng-add/ng-add.schematic.ts new file mode 100644 index 0000000000..65d0bcdf9f --- /dev/null +++ b/libs/sdk/skyux-eslint/src/schematics/ng-add/ng-add.schematic.ts @@ -0,0 +1,46 @@ +import { Rule, chain } from '@angular-devkit/schematics'; +import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks'; +import { + NodeDependencyType, + addPackageJsonDependency, + getPackageJsonDependency, +} from '@schematics/angular/utility/dependencies'; + +import fsPromises from 'node:fs/promises'; +import path from 'node:path'; + +function hardenPackageVersion(): Rule { + return async (tree) => { + const thisPackageJson = JSON.parse( + await fsPromises.readFile( + path.resolve(__dirname, '../../../package.json'), + { encoding: 'utf-8' }, + ), + ); + + addPackageJsonDependency(tree, { + name: thisPackageJson.name, + version: thisPackageJson.version, + type: NodeDependencyType.Dev, + }); + }; +} + +export function ngAdd(): Rule { + return (tree, context) => { + if ( + !getPackageJsonDependency(tree, '@angular-eslint/schematics') && + !getPackageJsonDependency(tree, 'angular-eslint') + ) { + throw new Error( + "The package 'angular-eslint' is not installed. " + + "Run 'ng add @angular-eslint/schematics' and try this command again.\n" + + 'See: https://github.com/angular-eslint/angular-eslint#quick-start', + ); + } + + context.addTask(new NodePackageInstallTask()); + + return chain([hardenPackageVersion()]); + }; +} diff --git a/libs/sdk/skyux-eslint/src/schematics/testing/scaffold.ts b/libs/sdk/skyux-eslint/src/schematics/testing/scaffold.ts new file mode 100644 index 0000000000..047cca668f --- /dev/null +++ b/libs/sdk/skyux-eslint/src/schematics/testing/scaffold.ts @@ -0,0 +1,72 @@ +import { + SchematicTestRunner, + UnitTestTree, +} from '@angular-devkit/schematics/testing'; +import { VERSION } from '@angular/cli'; +import { Schema } from '@schematics/angular/ng-new/schema'; + +/** + * Creates a new Angular CLI application. + */ +export async function createTestApp( + runner: SchematicTestRunner, + appOptions: { + projectName: string; + options?: Partial; + }, +): Promise { + return await runner.runExternalSchematic('@schematics/angular', 'ng-new', { + directory: '/', + name: appOptions.projectName, + routing: true, + strict: true, + style: 'scss', + version: VERSION.major, + ...appOptions.options, + }); +} + +/** + * Create a test workspace with a library as the default project. + */ +export async function createTestLibrary( + runner: SchematicTestRunner, + libOptions: { + projectName: string; + options?: Partial; + }, +): Promise { + const workspaceTree = await runner.runExternalSchematic( + '@schematics/angular', + 'ng-new', + { + directory: '/', + name: `${libOptions.projectName}-workspace`, + createApplication: false, + strict: true, + version: VERSION.major, + ...libOptions.options, + }, + ); + + await runner.runExternalSchematic( + '@schematics/angular', + 'library', + { + name: libOptions.projectName, + }, + workspaceTree, + ); + + // Create a "showcase" application for library projects. + await runner.runExternalSchematic( + '@schematics/angular', + 'application', + { + name: `${libOptions.projectName}-showcase`, + }, + workspaceTree, + ); + + return workspaceTree; +} diff --git a/libs/sdk/skyux-eslint/tsconfig.json b/libs/sdk/skyux-eslint/tsconfig.json new file mode 100644 index 0000000000..32551a69b9 --- /dev/null +++ b/libs/sdk/skyux-eslint/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "module": "Node16", + "moduleResolution": "Node16", + "resolveJsonModule": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/sdk/skyux-eslint/tsconfig.lib.json b/libs/sdk/skyux-eslint/tsconfig.lib.json new file mode 100644 index 0000000000..5c108b8429 --- /dev/null +++ b/libs/sdk/skyux-eslint/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "declaration": true, + "types": ["node"] + }, + "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], + "include": ["**/*.ts"] +} diff --git a/libs/sdk/skyux-eslint/tsconfig.spec.json b/libs/sdk/skyux-eslint/tsconfig.spec.json new file mode 100644 index 0000000000..81738e4978 --- /dev/null +++ b/libs/sdk/skyux-eslint/tsconfig.spec.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": ["jest", "node"] + }, + "include": [ + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx", + "**/*.d.ts", + "jest.config.ts" + ] +} diff --git a/nx.json b/nx.json index f8915530ab..ae30ef4072 100644 --- a/nx.json +++ b/nx.json @@ -81,7 +81,7 @@ "!{projectRoot}/**/*.stories.@(js|ts)", "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)", "!{projectRoot}/**/fixtures/**/*", - "!{projectRoot}/.eslintrc.json", + "!{projectRoot}/eslint.config.js", "!{projectRoot}/.storybook/**/*", "!{projectRoot}/jest.config.[jt]s", "!{projectRoot}/karma.conf.js", @@ -93,18 +93,14 @@ "{workspaceRoot}/.github/workflows/e2e.yml", "{workspaceRoot}/.percy.json" ], - "lintInputs": [ - "{projectRoot}/**/*", - "{workspaceRoot}/.eslintrc-overrides.json", - "{workspaceRoot}/.eslintrc.json" - ], + "lintInputs": ["{projectRoot}/**/*", "{workspaceRoot}/eslint-*"], "storybookInputs": [ "{projectRoot}/**/*", "{workspaceRoot}/.babelrc", "{workspaceRoot}/.storybook/**/*", "!{projectRoot}/**/*.spec.[jt]s", "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)", - "!{projectRoot}/.eslintrc.json", + "!{projectRoot}/eslint.config.js", "!{projectRoot}/jest.config.[jt]s", "!{projectRoot}/karma.conf.js", "!{projectRoot}/src/test-setup.[jt]s", @@ -119,7 +115,7 @@ "{workspaceRoot}/scripts/posttest-{projectName}.ts", "{workspaceRoot}/scripts/utils/**", "!{projectRoot}/**/*.stories.@(js|ts)", - "!{projectRoot}/.eslintrc.json", + "!{projectRoot}/eslint.config.js", "!{projectRoot}/.storybook/**/*", "!{projectRoot}/tsconfig.storybook.json" ] diff --git a/package-lock.json b/package-lock.json index 0f898ad7e9..72468ee3c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,7 +40,6 @@ "moment": "2.30.1", "ng2-dragula": "5.1.0", "normalize-scss": "8.0.0", - "package-json": "7.0.0", "rxjs": "7.8.1", "storybook": "8.3.5", "tslib": "2.6.3", @@ -51,13 +50,16 @@ "@angular-devkit/build-angular": "18.2.8", "@angular-devkit/core": "18.2.8", "@angular-devkit/schematics": "18.2.8", + "@angular-eslint/bundled-angular-compiler": "18.3.1", "@angular-eslint/eslint-plugin": "18.3.1", "@angular-eslint/eslint-plugin-template": "18.3.1", "@angular-eslint/template-parser": "18.3.1", + "@angular-eslint/test-utils": "18.3.1", + "@angular-eslint/utils": "18.3.1", "@angular/cli": "18.2.8", "@angular/compiler-cli": "18.2.8", "@angular/language-service": "18.2.8", - "@cspell/eslint-plugin": "8.14.4", + "@cspell/eslint-plugin": "8.15.4", "@istanbuljs/nyc-config-typescript": "1.0.2", "@nx/cypress": "20.0.0", "@nx/devkit": "20.0.0", @@ -100,22 +102,25 @@ "@types/dragula": "2.1.36", "@types/fontfaceobserver": "2.1.3", "@types/fs-extra": "11.0.4", + "@types/glob": "8.1.0", "@types/google-libphonenumber": "7.4.30", "@types/he": "1.2.3", "@types/jasmine": "5.1.4", "@types/jest": "29.5.13", "@types/node": "20.14.12", "@types/validator": "13.12.0", - "@typescript-eslint/eslint-plugin": "8.8.1", - "@typescript-eslint/parser": "8.8.1", + "@typescript-eslint/eslint-plugin": "8.8.0", + "@typescript-eslint/parser": "8.8.0", + "@typescript-eslint/utils": "8.8.0", "angular-eslint": "18.3.1", "cross-spawn": "7.0.3", "cypress": "13.15.0", "eslint": "9.12.0", "eslint-config-prettier": "9.1.0", - "eslint-plugin-cypress": "3.5.0", - "eslint-plugin-storybook": "0.9.0", + "eslint-plugin-cypress": "4.0.0", + "eslint-plugin-storybook": "0.10.1", "fs-extra": "11.2.0", + "glob": "11.0.0", "jasmine": "5.3.0", "jasmine-core": "5.3.0", "jest": "29.7.0", @@ -823,6 +828,28 @@ "typescript": "*" } }, + "node_modules/@angular-eslint/test-utils": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/test-utils/-/test-utils-18.3.1.tgz", + "integrity": "sha512-DWodswrIwSIIFKvDgtUk67M/9poss4Q1QPSRzvIQTnneEapKXfWIyRjKl41OLM9TofVNRhPvUoPqIH1lQrnOgQ==", + "dev": true, + "peerDependencies": { + "@angular-eslint/template-parser": "18.3.1", + "@typescript-eslint/parser": "^7.11.0 || ^8.0.0", + "@typescript-eslint/rule-tester": "^7.11.0 || ^8.0.0", + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + }, + "peerDependenciesMeta": { + "@angular-eslint/template-parser": { + "optional": true + }, + "@typescript-eslint/parser": { + "optional": true + } + } + }, "node_modules/@angular-eslint/utils": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-18.3.1.tgz", @@ -3128,82 +3155,82 @@ } }, "node_modules/@cspell/cspell-bundled-dicts": { - "version": "8.14.4", - "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-8.14.4.tgz", - "integrity": "sha512-JHZOpCJzN6fPBapBOvoeMxZbr0ZA11ZAkwcqM4w0lKoacbi6TwK8GIYf66hHvwLmMeav75TNXWE6aPTvBLMMqA==", - "dev": true, - "dependencies": { - "@cspell/dict-ada": "^4.0.2", - "@cspell/dict-aws": "^4.0.4", - "@cspell/dict-bash": "^4.1.4", - "@cspell/dict-companies": "^3.1.4", - "@cspell/dict-cpp": "^5.1.16", - "@cspell/dict-cryptocurrencies": "^5.0.0", - "@cspell/dict-csharp": "^4.0.2", - "@cspell/dict-css": "^4.0.13", - "@cspell/dict-dart": "^2.2.1", - "@cspell/dict-django": "^4.1.0", - "@cspell/dict-docker": "^1.1.7", - "@cspell/dict-dotnet": "^5.0.5", - "@cspell/dict-elixir": "^4.0.3", - "@cspell/dict-en_us": "^4.3.23", - "@cspell/dict-en-common-misspellings": "^2.0.4", + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-8.15.4.tgz", + "integrity": "sha512-t5b2JwGeUmzmjl319mCuaeKGxTvmzLLRmrpdHr+ZZGRO4nf7L48Lbe9A6uwNUvsZe0cXohiNXsrrsuzRVXswVA==", + "dev": true, + "dependencies": { + "@cspell/dict-ada": "^4.0.5", + "@cspell/dict-aws": "^4.0.7", + "@cspell/dict-bash": "^4.1.8", + "@cspell/dict-companies": "^3.1.7", + "@cspell/dict-cpp": "^5.1.22", + "@cspell/dict-cryptocurrencies": "^5.0.3", + "@cspell/dict-csharp": "^4.0.5", + "@cspell/dict-css": "^4.0.16", + "@cspell/dict-dart": "^2.2.4", + "@cspell/dict-django": "^4.1.3", + "@cspell/dict-docker": "^1.1.11", + "@cspell/dict-dotnet": "^5.0.8", + "@cspell/dict-elixir": "^4.0.6", + "@cspell/dict-en_us": "^4.3.26", + "@cspell/dict-en-common-misspellings": "^2.0.7", "@cspell/dict-en-gb": "1.1.33", - "@cspell/dict-filetypes": "^3.0.4", - "@cspell/dict-flutter": "^1.0.0", - "@cspell/dict-fonts": "^4.0.0", - "@cspell/dict-fsharp": "^1.0.1", - "@cspell/dict-fullstack": "^3.2.0", - "@cspell/dict-gaming-terms": "^1.0.5", - "@cspell/dict-git": "^3.0.0", - "@cspell/dict-golang": "^6.0.12", - "@cspell/dict-google": "^1.0.1", - "@cspell/dict-haskell": "^4.0.1", - "@cspell/dict-html": "^4.0.5", - "@cspell/dict-html-symbol-entities": "^4.0.0", - "@cspell/dict-java": "^5.0.7", - "@cspell/dict-julia": "^1.0.1", - "@cspell/dict-k8s": "^1.0.6", - "@cspell/dict-latex": "^4.0.0", - "@cspell/dict-lorem-ipsum": "^4.0.0", - "@cspell/dict-lua": "^4.0.3", - "@cspell/dict-makefile": "^1.0.0", - "@cspell/dict-monkeyc": "^1.0.6", - "@cspell/dict-node": "^5.0.1", - "@cspell/dict-npm": "^5.1.4", - "@cspell/dict-php": "^4.0.10", - "@cspell/dict-powershell": "^5.0.8", - "@cspell/dict-public-licenses": "^2.0.8", - "@cspell/dict-python": "^4.2.6", - "@cspell/dict-r": "^2.0.1", - "@cspell/dict-ruby": "^5.0.3", - "@cspell/dict-rust": "^4.0.5", - "@cspell/dict-scala": "^5.0.3", - "@cspell/dict-software-terms": "^4.1.3", - "@cspell/dict-sql": "^2.1.5", - "@cspell/dict-svelte": "^1.0.2", - "@cspell/dict-swift": "^2.0.1", - "@cspell/dict-terraform": "^1.0.1", - "@cspell/dict-typescript": "^3.1.6", - "@cspell/dict-vue": "^3.0.0" + "@cspell/dict-filetypes": "^3.0.7", + "@cspell/dict-flutter": "^1.0.3", + "@cspell/dict-fonts": "^4.0.3", + "@cspell/dict-fsharp": "^1.0.4", + "@cspell/dict-fullstack": "^3.2.3", + "@cspell/dict-gaming-terms": "^1.0.8", + "@cspell/dict-git": "^3.0.3", + "@cspell/dict-golang": "^6.0.16", + "@cspell/dict-google": "^1.0.4", + "@cspell/dict-haskell": "^4.0.4", + "@cspell/dict-html": "^4.0.9", + "@cspell/dict-html-symbol-entities": "^4.0.3", + "@cspell/dict-java": "^5.0.10", + "@cspell/dict-julia": "^1.0.4", + "@cspell/dict-k8s": "^1.0.9", + "@cspell/dict-latex": "^4.0.3", + "@cspell/dict-lorem-ipsum": "^4.0.3", + "@cspell/dict-lua": "^4.0.6", + "@cspell/dict-makefile": "^1.0.3", + "@cspell/dict-monkeyc": "^1.0.9", + "@cspell/dict-node": "^5.0.4", + "@cspell/dict-npm": "^5.1.8", + "@cspell/dict-php": "^4.0.13", + "@cspell/dict-powershell": "^5.0.13", + "@cspell/dict-public-licenses": "^2.0.11", + "@cspell/dict-python": "^4.2.12", + "@cspell/dict-r": "^2.0.4", + "@cspell/dict-ruby": "^5.0.7", + "@cspell/dict-rust": "^4.0.9", + "@cspell/dict-scala": "^5.0.6", + "@cspell/dict-software-terms": "^4.1.11", + "@cspell/dict-sql": "^2.1.8", + "@cspell/dict-svelte": "^1.0.5", + "@cspell/dict-swift": "^2.0.4", + "@cspell/dict-terraform": "^1.0.5", + "@cspell/dict-typescript": "^3.1.10", + "@cspell/dict-vue": "^3.0.3" }, "engines": { "node": ">=18" } }, "node_modules/@cspell/cspell-pipe": { - "version": "8.14.4", - "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-8.14.4.tgz", - "integrity": "sha512-CLLdouqfrQ4rqdQdPu0Oo+HHCU/oLYoEsK1nNPb28cZTFxnn0cuSPKB6AMPBJmMwdfJ6fMD0BCKNbEe1UNLHcw==", + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-8.15.4.tgz", + "integrity": "sha512-WfCmZVFC6mX6vYlf02hWwelcSBTbDQgc5YqY+1miuMk+OHSUAHSACjZId6/a4IAID94xScvFfj7jgrdejUVvIQ==", "dev": true, "engines": { "node": ">=18" } }, "node_modules/@cspell/cspell-resolver": { - "version": "8.14.4", - "resolved": "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-8.14.4.tgz", - "integrity": "sha512-s3uZyymJ04yn8+zlTp7Pt1WRSlAel6XVo+iZRxls3LSvIP819KK64DoyjCD2Uon0Vg9P/K7aAPt8GcxDcnJtgA==", + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-8.15.4.tgz", + "integrity": "sha512-Zr428o+uUTqywrdKyjluJVnDPVAJEqZ1chQLKIrHggUah1cgs5aQ7rZ+0Rv5euYMlC2idZnP7IL6TDaIib80oA==", "dev": true, "dependencies": { "global-directory": "^4.0.1" @@ -3213,18 +3240,18 @@ } }, "node_modules/@cspell/cspell-service-bus": { - "version": "8.14.4", - "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-8.14.4.tgz", - "integrity": "sha512-i3UG+ep63akNsDXZrtGgICNF3MLBHtvKe/VOIH6+L+NYaAaVHqqQvOY9MdUwt1HXh8ElzfwfoRp36wc5aAvt6g==", + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-8.15.4.tgz", + "integrity": "sha512-pXYofnV/V9Y3LZdfFGbmhdxPX/ABjiD3wFjGHt5YhIU9hjVVuvjFlgY7pH2AvRjs4F8xKXv1ReWl44BJOL9gLA==", "dev": true, "engines": { "node": ">=18" } }, "node_modules/@cspell/cspell-types": { - "version": "8.14.4", - "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-8.14.4.tgz", - "integrity": "sha512-VXwikqdHgjOVperVVCn2DOe8W3rPIswwZtMHfRYnagpzZo/TOntIjkXPJSfTtl/cFyx5DnCBsDH8ytKGlMeHkw==", + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-8.15.4.tgz", + "integrity": "sha512-1hDtgYDQVW11zgtrr12EmGW45Deoi7IjZOhzPFLb+3WkhZ46ggWdbrRalWwBolQPDDo6+B2Q6WXz5hdND+Tpwg==", "dev": true, "engines": { "node": ">=18" @@ -3558,9 +3585,9 @@ "dev": true }, "node_modules/@cspell/dynamic-import": { - "version": "8.14.4", - "resolved": "https://registry.npmjs.org/@cspell/dynamic-import/-/dynamic-import-8.14.4.tgz", - "integrity": "sha512-GjKsBJvPXp4dYRqsMn7n1zpnKbnpfJnlKLOVeoFBh8fi4n06G50xYr+G25CWX1WT3WFaALAavvVICEUPrVsuqg==", + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/@cspell/dynamic-import/-/dynamic-import-8.15.4.tgz", + "integrity": "sha512-tr0F6EYN6qtniNvt1Uib+PgYQHeo4dQHXE2Optap+hYTOoQ2VoQ+SwBVjZ+Q2bmSAB0fmOyf0AvgsUtnWIpavw==", "dev": true, "dependencies": { "import-meta-resolve": "^4.1.0" @@ -3570,15 +3597,15 @@ } }, "node_modules/@cspell/eslint-plugin": { - "version": "8.14.4", - "resolved": "https://registry.npmjs.org/@cspell/eslint-plugin/-/eslint-plugin-8.14.4.tgz", - "integrity": "sha512-Wv6Jkttp/rsEm1nadLFQrUrYg9nTWQFwJu47KO2cfWP39TeH0zXQpmyas1xNlcDx5QJ9JJw9urTT/iw2tsHeRA==", + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/@cspell/eslint-plugin/-/eslint-plugin-8.15.4.tgz", + "integrity": "sha512-KySdPTi1of8FiSvGG6cC1nN9GF9xad/2AgDthHv2DJ0UTMTpX7fqccVpWdQ0Yo4qt32XUQgO4EmvwWSNgo1d3w==", "dev": true, "dependencies": { - "@cspell/cspell-types": "8.14.4", - "@cspell/url": "8.14.4", - "cspell-lib": "8.14.4", - "synckit": "^0.9.1" + "@cspell/cspell-types": "8.15.4", + "@cspell/url": "8.15.4", + "cspell-lib": "8.15.4", + "synckit": "^0.9.2" }, "engines": { "node": ">=18" @@ -3588,27 +3615,27 @@ } }, "node_modules/@cspell/filetypes": { - "version": "8.14.4", - "resolved": "https://registry.npmjs.org/@cspell/filetypes/-/filetypes-8.14.4.tgz", - "integrity": "sha512-qd68dD7xTA4Mnf/wjIKYz2SkiTBshIM+yszOUtLa06YJm0aocoNQ25FHXyYEQYm9NQXCYnRWWA02sFMGs8Sv/w==", + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/@cspell/filetypes/-/filetypes-8.15.4.tgz", + "integrity": "sha512-sNl6jr3ym/4151EY76qlI/00HHsiLZBqW7Vb1tqCzsgSg3EpL30ddjr74So6Sg2PN26Yf09hvxGTJzXn1R4aYw==", "dev": true, "engines": { "node": ">=18" } }, "node_modules/@cspell/strong-weak-map": { - "version": "8.14.4", - "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-8.14.4.tgz", - "integrity": "sha512-Uyfck64TfVU24wAP3BLGQ5EsAfzIZiLfN90NhttpEM7GlOBmbGrEJd4hNOwfpYsE/TT80eGWQVPRTLr5SDbXFA==", + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-8.15.4.tgz", + "integrity": "sha512-m5DeQksbhJFqcSYF8Q0Af/WXmXCMAJocCUShkzOXK+uZNXnvhBZN7VyQ9hL+GRzX8JTPEPdVcz2lFyVE5p+LzQ==", "dev": true, "engines": { "node": ">=18" } }, "node_modules/@cspell/url": { - "version": "8.14.4", - "resolved": "https://registry.npmjs.org/@cspell/url/-/url-8.14.4.tgz", - "integrity": "sha512-htHhNF8WrM/NfaLSWuTYw0NqVgFRVHYSyHlRT3i/Yv5xvErld8Gw7C6ldm+0TLjoGlUe6X1VV72JSir7+yLp/Q==", + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/@cspell/url/-/url-8.15.4.tgz", + "integrity": "sha512-K2oZu/oLQPs5suRpLS8uu04O3YMUioSlEU1D66fRoOxzI5NzLt7i7yMg3HQHjChGa09N5bzqmrVdhmQrRZXwGg==", "dev": true, "engines": { "node": ">=18.0" @@ -4950,6 +4977,49 @@ } } }, + "node_modules/@jest/reporters/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "devOptional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@jest/reporters/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "devOptional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "devOptional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@jest/schemas": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", @@ -5790,22 +5860,6 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@npmcli/package-json/node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@npmcli/package-json/node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -5826,6 +5880,27 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@npmcli/package-json/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/@npmcli/package-json/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -5841,6 +5916,22 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@npmcli/package-json/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@npmcli/promise-spawn": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz", @@ -7586,6 +7677,16 @@ "node": ">= 12" } }, + "node_modules/@ryansonshine/commitizen/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@ryansonshine/commitizen/node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -7601,6 +7702,39 @@ "node": ">=10" } }, + "node_modules/@ryansonshine/commitizen/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@ryansonshine/commitizen/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@ryansonshine/cz-conventional-changelog": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/@ryansonshine/cz-conventional-changelog/-/cz-conventional-changelog-3.3.4.tgz", @@ -7786,17 +7920,6 @@ "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==" }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, "node_modules/@sindresorhus/merge-streams": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", @@ -7856,22 +7979,6 @@ "proxy-from-env": "^1.1.0" } }, - "node_modules/@skyux/dev-infra-private/node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@skyux/dev-infra-private/node_modules/glob": { "version": "10.3.10", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", @@ -7913,15 +8020,25 @@ } }, "node_modules/@skyux/dev-infra-private/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "node_modules/@skyux/dev-infra-private/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@skyux/dev-infra-private/node_modules/semver": { @@ -7939,6 +8056,18 @@ "node": ">=10" } }, + "node_modules/@skyux/dev-infra-private/node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@skyux/dev-infra-private/node_modules/typedoc": { "version": "0.25.7", "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.7.tgz", @@ -9106,17 +9235,6 @@ "@swc/counter": "^0.1.3" } }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@testing-library/dom": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", @@ -9449,17 +9567,6 @@ "@types/node": "*" } }, - "node_modules/@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, "node_modules/@types/connect": { "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", @@ -9568,6 +9675,16 @@ "@types/node": "*" } }, + "node_modules/@types/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", + "dev": true, + "dependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, "node_modules/@types/google-libphonenumber": { "version": "7.4.30", "resolved": "https://registry.npmjs.org/@types/google-libphonenumber/-/google-libphonenumber-7.4.30.tgz", @@ -9604,11 +9721,6 @@ "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", "devOptional": true }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", - "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==" - }, "node_modules/@types/http-errors": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", @@ -9716,14 +9828,6 @@ "@types/node": "*" } }, - "node_modules/@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/lodash": { "version": "4.17.12", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.12.tgz", @@ -9741,6 +9845,12 @@ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, "node_modules/@types/minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", @@ -9823,14 +9933,6 @@ "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", "devOptional": true }, - "node_modules/@types/responselike": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", - "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/retry": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", @@ -9967,16 +10069,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz", - "integrity": "sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.0.tgz", + "integrity": "sha512-wORFWjU30B2WJ/aXBfOm1LX9v9nyt9D3jsSOxC3cCaTQGCW5k4jNpmjFv3U7p/7s4yvdjHzwtv2Sd2dOyhjS0A==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.8.1", - "@typescript-eslint/type-utils": "8.8.1", - "@typescript-eslint/utils": "8.8.1", - "@typescript-eslint/visitor-keys": "8.8.1", + "@typescript-eslint/scope-manager": "8.8.0", + "@typescript-eslint/type-utils": "8.8.0", + "@typescript-eslint/utils": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -10000,13 +10102,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz", - "integrity": "sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.8.0.tgz", + "integrity": "sha512-IKwJSS7bCqyCeG4NVGxnOP6lLT9Okc3Zj8hLO96bpMkJab+10HIfJbMouLrlpyOr3yrQ1cA413YPFiGd1mW9/Q==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.8.1", - "@typescript-eslint/utils": "8.8.1", + "@typescript-eslint/typescript-estree": "8.8.0", + "@typescript-eslint/utils": "8.8.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -10023,39 +10125,17 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.1.tgz", - "integrity": "sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w==", + "node_modules/@typescript-eslint/parser": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.8.0.tgz", + "integrity": "sha512-uEFUsgR+tl8GmzmLjRqz+VrDv4eoaMqMXW7ruXfgThaAShO9JTciKpEsB+TvnfFfbg5IpujgMXVV36gOJRLtZg==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.8.1", - "@typescript-eslint/types": "8.8.1", - "@typescript-eslint/typescript-estree": "8.8.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.8.1.tgz", - "integrity": "sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "8.8.1", - "@typescript-eslint/types": "8.8.1", - "@typescript-eslint/typescript-estree": "8.8.1", - "@typescript-eslint/visitor-keys": "8.8.1", - "debug": "^4.3.4" + "@typescript-eslint/scope-manager": "8.8.0", + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/typescript-estree": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0", + "debug": "^4.3.4" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -10073,14 +10153,19 @@ } } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz", - "integrity": "sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA==", + "node_modules/@typescript-eslint/rule-tester": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/rule-tester/-/rule-tester-8.12.2.tgz", + "integrity": "sha512-aggjJT+aZj/LJVUx/qX+97tYGGqpML6vnuLwjmNrjpRP047cuSlYutG1zX8fr3ibr9tzHxiwc03dlKFsLMd12g==", "dev": true, + "peer": true, "dependencies": { - "@typescript-eslint/types": "8.8.1", - "@typescript-eslint/visitor-keys": "8.8.1" + "@typescript-eslint/typescript-estree": "8.12.2", + "@typescript-eslint/utils": "8.12.2", + "ajv": "^6.12.6", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "4.6.2", + "semver": "^7.6.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -10088,17 +10173,20 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" } }, - "node_modules/@typescript-eslint/type-utils": { + "node_modules/@typescript-eslint/rule-tester/node_modules/@typescript-eslint/scope-manager": { "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.12.2.tgz", - "integrity": "sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz", + "integrity": "sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==", + "dev": true, + "peer": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.12.2", - "@typescript-eslint/utils": "8.12.2", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -10106,17 +10194,14 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "node_modules/@typescript-eslint/rule-tester/node_modules/@typescript-eslint/types": { "version": "8.12.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz", "integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==", + "dev": true, + "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -10125,10 +10210,12 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "node_modules/@typescript-eslint/rule-tester/node_modules/@typescript-eslint/typescript-estree": { "version": "8.12.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz", "integrity": "sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==", + "dev": true, + "peer": true, "dependencies": { "@typescript-eslint/types": "8.12.2", "@typescript-eslint/visitor-keys": "8.12.2", @@ -10152,10 +10239,35 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "node_modules/@typescript-eslint/rule-tester/node_modules/@typescript-eslint/utils": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.12.2.tgz", + "integrity": "sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==", + "dev": true, + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.12.2", + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/typescript-estree": "8.12.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@typescript-eslint/rule-tester/node_modules/@typescript-eslint/visitor-keys": { "version": "8.12.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz", "integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==", + "dev": true, + "peer": true, "dependencies": { "@typescript-eslint/types": "8.12.2", "eslint-visitor-keys": "^3.4.3" @@ -10168,10 +10280,36 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { + "node_modules/@typescript-eslint/rule-tester/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@typescript-eslint/rule-tester/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "peer": true + }, + "node_modules/@typescript-eslint/rule-tester/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "peer": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -10182,11 +10320,15 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@typescript-eslint/types": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.1.tgz", - "integrity": "sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.0.tgz", + "integrity": "sha512-EL8eaGC6gx3jDd8GwEFEV091210U97J0jeEHrAYvIYosmEGet4wJ+g0SYmLu+oRiAwbSA5AVrt6DxLHfdd+bUg==", "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -10195,19 +10337,14 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz", - "integrity": "sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg==", - "dev": true, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.12.2.tgz", + "integrity": "sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==", "dependencies": { - "@typescript-eslint/types": "8.8.1", - "@typescript-eslint/visitor-keys": "8.8.1", + "@typescript-eslint/typescript-estree": "8.12.2", + "@typescript-eslint/utils": "8.12.2", "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", "ts-api-utils": "^1.3.0" }, "engines": { @@ -10223,22 +10360,62 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz", + "integrity": "sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==", "dependencies": { - "brace-expansion": "^2.0.1" + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/utils": { + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz", + "integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz", + "integrity": "sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==", + "dependencies": { + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { "version": "8.12.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.12.2.tgz", "integrity": "sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==", @@ -10259,13 +10436,13 @@ "eslint": "^8.57.0 || ^9.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz", - "integrity": "sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz", + "integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==", "dependencies": { "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -10275,10 +10452,25 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz", - "integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==", + "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.0.tgz", + "integrity": "sha512-QJwc50hRCgBd/k12sTykOJbESe1RrzmX6COk8Y525C9l7oweZ+1lw9JiU56im7Amm8swlz00DRIlxMYLizr2Vw==", + "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -10287,13 +10479,14 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz", - "integrity": "sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.0.tgz", + "integrity": "sha512-ZaMJwc/0ckLz5DaAZ+pNLmHv8AMVGtfWxZe/x2JVEkD5LnmhWiQMMcYT7IY7gkdJuzJ9P14fRy28lUrlDSWYdw==", + "dev": true, "dependencies": { - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2", + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/visitor-keys": "8.8.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -10314,43 +10507,50 @@ } } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz", - "integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, "dependencies": { - "@typescript-eslint/types": "8.12.2", - "eslint-visitor-keys": "^3.4.3" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=16 || 14 >=14.17" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@typescript-eslint/utils/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "node_modules/@typescript-eslint/utils": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.0.tgz", + "integrity": "sha512-QE2MgfOTem00qrlPgyByaCHay9yb1+9BjnMFnSFkUKQfu7adBXDTnCAivURnuPPAG/qiB+kzKkZKmKfaMT0zVg==", + "dev": true, "dependencies": { - "brace-expansion": "^2.0.1" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.8.0", + "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/typescript-estree": "8.8.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz", - "integrity": "sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.0.tgz", + "integrity": "sha512-8mq51Lx6Hpmd7HnA2fcHQo3YgfX1qbccxQOgZcb4tvasu//zXRaA1j5ZRFeCw/VRAdFi4mRM9DnZw0Nu0Q2d1g==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.8.1", + "@typescript-eslint/types": "8.8.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -12653,22 +12853,6 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/cacache/node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "devOptional": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/cacache/node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -12689,6 +12873,21 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/cacache/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "devOptional": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/cacache/node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", @@ -12710,6 +12909,22 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/cacache/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "devOptional": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/cache-content-type": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", @@ -12722,31 +12937,6 @@ "node": ">= 6.0.0" } }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", - "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/cachedir": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", @@ -12851,15 +13041,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/camelcase-keys/node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -13255,17 +13436,6 @@ "node": ">=6" } }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -14146,14 +14316,14 @@ } }, "node_modules/cspell-config-lib": { - "version": "8.14.4", - "resolved": "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-8.14.4.tgz", - "integrity": "sha512-cnUeJfniTiebqCaQmIUnbSrPrTH7xzKRQjJDHAEV0WYnOG2MhRXI13OzytdFdhkVBdStmgTzTCJKE7x+kmU2NA==", + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-8.15.4.tgz", + "integrity": "sha512-vUgikQTRkRMTdkZqSs7F2cTdPpX61cTjr/9L/VCkXkbW38ObCr4650ioiF1Wq3zDF3Gy2bc4ECTpD2PZUXX5SA==", "dev": true, "dependencies": { - "@cspell/cspell-types": "8.14.4", + "@cspell/cspell-types": "8.15.4", "comment-json": "^4.2.5", - "yaml": "^2.5.1" + "yaml": "^2.6.0" }, "engines": { "node": ">=18" @@ -14176,14 +14346,14 @@ } }, "node_modules/cspell-dictionary": { - "version": "8.14.4", - "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-8.14.4.tgz", - "integrity": "sha512-pZvQHxpAW5fZAnt3ZKKy3s7M+3CX2t8tCS3uJrpEHIynlCawpG0fPF78rVE5o+g0dON36Lguc/BUuSN4IWKLmQ==", + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-8.15.4.tgz", + "integrity": "sha512-8+p/l9Saac7qyCbqtELneDoT7CwHu9gYmnI8uXMu34/lPGjhVhy10ZeI0+t1djaO2YyASK400YFKq5uP/5KulA==", "dev": true, "dependencies": { - "@cspell/cspell-pipe": "8.14.4", - "@cspell/cspell-types": "8.14.4", - "cspell-trie-lib": "8.14.4", + "@cspell/cspell-pipe": "8.15.4", + "@cspell/cspell-types": "8.15.4", + "cspell-trie-lib": "8.15.4", "fast-equals": "^5.0.1" }, "engines": { @@ -14191,12 +14361,12 @@ } }, "node_modules/cspell-glob": { - "version": "8.14.4", - "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-8.14.4.tgz", - "integrity": "sha512-C/xTS5nujMRMuguibq92qMVP767mtxrur7DcVolCvpzcivm1RB5NtIN0OctQxTyMbnmKeQv1t4epRKQ9A8vWRg==", + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-8.15.4.tgz", + "integrity": "sha512-TTfRRHRAN+PN9drIz4MAEgKKYnPThBOlPMdFddyuisvU33Do1sPAnqkkOjTEFdi3jAA5KwnSva68SVH6IzzMBQ==", "dev": true, "dependencies": { - "@cspell/url": "8.14.4", + "@cspell/url": "8.15.4", "micromatch": "^4.0.8" }, "engines": { @@ -14204,13 +14374,13 @@ } }, "node_modules/cspell-grammar": { - "version": "8.14.4", - "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-8.14.4.tgz", - "integrity": "sha512-yaSKAAJDiamsw3FChbw4HXb2RvTQrDsLelh1+T4MavarOIcAxXrqAJ8ysqm++g+S/ooJz2YO8YWIyzJKxcMf8g==", + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-8.15.4.tgz", + "integrity": "sha512-MKiKyYi05mRtXOxPoTv3Ksi0GwYLiK84Uq0C+5PaMrnIjXeed0bsddSFXCT+7ywFJc7PdjhTtz0M/9WWK3UgbA==", "dev": true, "dependencies": { - "@cspell/cspell-pipe": "8.14.4", - "@cspell/cspell-types": "8.14.4" + "@cspell/cspell-pipe": "8.15.4", + "@cspell/cspell-types": "8.15.4" }, "bin": { "cspell-grammar": "bin.mjs" @@ -14220,40 +14390,40 @@ } }, "node_modules/cspell-io": { - "version": "8.14.4", - "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-8.14.4.tgz", - "integrity": "sha512-o6OTWRyx/Az+PFhr1B0wMAwqG070hFC9g73Fkxd8+rHX0rfRS69QZH7LgSmZytqbZIMxCTDGdsLl33MFGWCbZQ==", + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-8.15.4.tgz", + "integrity": "sha512-rXIEREPTFV9dwwg4EKfvzqlCNOvT6910AYED5YrSt8Y68usRJ9lbqdx0BrDndVCd33bp1o+9JBfHuRiFIQC81g==", "dev": true, "dependencies": { - "@cspell/cspell-service-bus": "8.14.4", - "@cspell/url": "8.14.4" + "@cspell/cspell-service-bus": "8.15.4", + "@cspell/url": "8.15.4" }, "engines": { "node": ">=18" } }, "node_modules/cspell-lib": { - "version": "8.14.4", - "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-8.14.4.tgz", - "integrity": "sha512-qdkUkKtm+nmgpA4jQbmQTuepDfjHBDWvs3zDuEwVIVFq/h8gnXrRr75gJ3RYdTy+vOOqHPoLLqgxyqkUUrUGXA==", - "dev": true, - "dependencies": { - "@cspell/cspell-bundled-dicts": "8.14.4", - "@cspell/cspell-pipe": "8.14.4", - "@cspell/cspell-resolver": "8.14.4", - "@cspell/cspell-types": "8.14.4", - "@cspell/dynamic-import": "8.14.4", - "@cspell/filetypes": "8.14.4", - "@cspell/strong-weak-map": "8.14.4", - "@cspell/url": "8.14.4", + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-8.15.4.tgz", + "integrity": "sha512-iLp/625fvCyFFxSyZYLMgqHIKcrhN4hT7Hw5+ySa38Bp/OfA81ANqWHpsDQ0bGsALTRn/DHBpQYj4xCW/aN9tw==", + "dev": true, + "dependencies": { + "@cspell/cspell-bundled-dicts": "8.15.4", + "@cspell/cspell-pipe": "8.15.4", + "@cspell/cspell-resolver": "8.15.4", + "@cspell/cspell-types": "8.15.4", + "@cspell/dynamic-import": "8.15.4", + "@cspell/filetypes": "8.15.4", + "@cspell/strong-weak-map": "8.15.4", + "@cspell/url": "8.15.4", "clear-module": "^4.1.2", "comment-json": "^4.2.5", - "cspell-config-lib": "8.14.4", - "cspell-dictionary": "8.14.4", - "cspell-glob": "8.14.4", - "cspell-grammar": "8.14.4", - "cspell-io": "8.14.4", - "cspell-trie-lib": "8.14.4", + "cspell-config-lib": "8.15.4", + "cspell-dictionary": "8.15.4", + "cspell-glob": "8.15.4", + "cspell-grammar": "8.15.4", + "cspell-io": "8.15.4", + "cspell-trie-lib": "8.15.4", "env-paths": "^3.0.0", "fast-equals": "^5.0.1", "gensequence": "^7.0.0", @@ -14284,13 +14454,13 @@ } }, "node_modules/cspell-trie-lib": { - "version": "8.14.4", - "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-8.14.4.tgz", - "integrity": "sha512-zu8EJ33CH+FA5lwTRGqS//Q6phO0qtgEmODMR1KPlD7WlrfTFMb3bWFsLo/tiv5hjpsn7CM6dYDAAgBOSkoyhQ==", + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-8.15.4.tgz", + "integrity": "sha512-sg9klsNHyrfos0Boiio+qy5d6fI9cCNjBqFYrNxvpKpwZ4gEzDzjgEKdZY1C76RD2KoBQ8I1NF5YcGc0+hhhCw==", "dev": true, "dependencies": { - "@cspell/cspell-pipe": "8.14.4", - "@cspell/cspell-types": "8.14.4", + "@cspell/cspell-pipe": "8.15.4", + "@cspell/cspell-types": "8.15.4", "gensequence": "^7.0.0" }, "engines": { @@ -14902,31 +15072,6 @@ "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", "devOptional": true }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -14946,14 +15091,6 @@ "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", "integrity": "sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==" }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -15076,14 +15213,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "engines": { - "node": ">=10" - } - }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -16064,53 +16193,37 @@ } }, "node_modules/eslint-plugin-cypress": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-3.5.0.tgz", - "integrity": "sha512-JZQ6XnBTNI8h1B9M7wJSFzc48SYbh7VMMKaNTQOFa3BQlnmXPrVc4PKen8R+fpv6VleiPeej6VxloGb42zdRvw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-4.0.0.tgz", + "integrity": "sha512-KRzI4zxoOKMhWKRxcikRu/Vjsomnx1vXJEY2CTG+4oluFbXxGuyRC1CLlhmBVOK5/iR17vY7rzuyRbpcx5zEPA==", "dev": true, "dependencies": { - "globals": "^13.20.0" + "globals": "^15.11.0" }, "peerDependencies": { - "eslint": ">=7" + "eslint": ">=9" } }, "node_modules/eslint-plugin-cypress/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-plugin-cypress/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "version": "15.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.11.0.tgz", + "integrity": "sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==", "dev": true, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint-plugin-storybook": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.9.0.tgz", - "integrity": "sha512-qOT/2vQBo0VqrG/BhZv8IdSsKQiyzJw+2Wqq+WFCiblI/PfxLSrGkF/buiXF+HumwfsCyBdaC94UhqhmYFmAvA==", + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.10.1.tgz", + "integrity": "sha512-YpxkdqyiKpMIrRquuvBaCinsqmZJ86JvXRX/gtRa4Qctpk0ipFt2cWqEjkB1HHWWG0DVRXlUBKHjRogC2Ig1fg==", "dev": true, "dependencies": { - "@storybook/csf": "^0.0.1", - "@typescript-eslint/utils": "^5.62.0", - "requireindex": "^1.2.0", + "@storybook/csf": "^0.1.11", + "@typescript-eslint/utils": "^8.8.1", "ts-dedent": "^2.2.0" }, "engines": { @@ -16120,26 +16233,17 @@ "eslint": ">=6" } }, - "node_modules/eslint-plugin-storybook/node_modules/@storybook/csf": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.1.tgz", - "integrity": "sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw==", - "dev": true, - "dependencies": { - "lodash": "^4.17.15" - } - }, "node_modules/eslint-plugin-storybook/node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz", + "integrity": "sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -16147,12 +16251,12 @@ } }, "node_modules/eslint-plugin-storybook/node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz", + "integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -16160,21 +16264,22 @@ } }, "node_modules/eslint-plugin-storybook/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz", + "integrity": "sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -16187,103 +16292,63 @@ } }, "node_modules/eslint-plugin-storybook/node_modules/@typescript-eslint/utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.12.2.tgz", + "integrity": "sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.12.2", + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/typescript-estree": "8.12.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0" } }, "node_modules/eslint-plugin-storybook/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz", + "integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "8.12.2", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/eslint-plugin-storybook/node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint-plugin-storybook/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-plugin-storybook/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint-plugin-storybook/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/eslint-plugin-storybook/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/eslint-scope": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", - "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -16331,9 +16396,9 @@ } }, "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", - "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -16358,13 +16423,13 @@ } }, "node_modules/espree": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", - "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dependencies": { - "acorn": "^8.12.0", + "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.1.0" + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -16374,9 +16439,9 @@ } }, "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", - "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -17042,24 +17107,20 @@ } }, "node_modules/foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dependencies": { "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" + "signal-exit": "^4.0.1" }, "engines": { - "node": ">=8.0.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -17544,6 +17605,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, "dependencies": { "pump": "^3.0.0" }, @@ -17651,20 +17713,23 @@ "dev": true }, "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", + "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", + "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -17686,24 +17751,19 @@ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/global-directory": { @@ -17866,30 +17926,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/got": { - "version": "11.8.6", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", - "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -18377,7 +18413,8 @@ "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true }, "node_modules/http-deceiver": { "version": "1.2.7", @@ -18505,18 +18542,6 @@ "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==", "devOptional": true }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, "node_modules/https-proxy-agent": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", @@ -19384,17 +19409,18 @@ } }, "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz", + "integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==", + "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, + "engines": { + "node": "20 || >=22" + }, "funding": { "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" } }, "node_modules/jake": { @@ -19453,22 +19479,6 @@ "integrity": "sha512-zsOmeBKESky4toybvWEikRiZ0jHoBEu79wNArLfMdSnlLMZx3Xcp6CSm2sUcYyoJC+Uyj8LBJap/MUbVSfJ27g==", "dev": true }, - "node_modules/jasmine/node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/jasmine/node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -19489,6 +19499,27 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/jasmine/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jasmine/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/jasmine/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -19504,6 +19535,22 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/jasmine/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/javascript-natural-sort": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", @@ -19813,6 +19860,49 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/jest-config/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "devOptional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jest-config/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "devOptional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "devOptional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/jest-config/node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -20383,6 +20473,49 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-runtime/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "devOptional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "devOptional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-runtime/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "devOptional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/jest-snapshot": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", @@ -21118,6 +21251,27 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/karma/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "devOptional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/karma/node_modules/mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -22086,14 +22240,6 @@ "tslib": "^2.0.3" } }, - "node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "engines": { - "node": ">=8" - } - }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -22593,14 +22739,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "engines": { - "node": ">=4" - } - }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -23292,22 +23430,6 @@ "node": ">=6" } }, - "node_modules/node-gyp/node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/node-gyp/node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -23337,6 +23459,27 @@ "node": ">=16" } }, + "node_modules/node-gyp/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/node-gyp/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/node-gyp/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -23352,6 +23495,22 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/node-gyp/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/node-gyp/node_modules/which": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", @@ -23458,17 +23617,6 @@ "resolved": "https://registry.npmjs.org/normalize-scss/-/normalize-scss-8.0.0.tgz", "integrity": "sha512-C6GXIxQ2LOYWrde27xWbONavmybobxp+V6TY8BiBJw5M+yMNEg2R0WjaeDtmP5JsunFYKvFOvgMAIC0/OxZuJQ==" }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/npm-bundled": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.1.tgz", @@ -23775,8 +23923,18 @@ "node": ">=8.9" } }, - "node_modules/nyc/node_modules/cliui": { - "version": "6.0.0", + "node_modules/nyc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/nyc/node_modules/cliui": { + "version": "6.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dev": true, @@ -23799,6 +23957,40 @@ "node": ">=8" } }, + "node_modules/nyc/node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/nyc/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/nyc/node_modules/istanbul-lib-instrument": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", @@ -23826,6 +24018,18 @@ "node": ">=8" } }, + "node_modules/nyc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/nyc/node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -24106,14 +24310,6 @@ "@oxc-resolver/binding-win32-x64-msvc": "1.12.0" } }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "engines": { - "node": ">=8" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -24204,23 +24400,6 @@ "node": ">=8" } }, - "node_modules/package-json": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-7.0.0.tgz", - "integrity": "sha512-CHJqc94AA8YfSLHGQT3DbvSIuE12NLFekpM4n7LRrAd3dOJtA911+4xe9q6nC3/jcKraq7nNS9VxgtT0KC+diA==", - "dependencies": { - "got": "^11.8.2", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -24417,24 +24596,29 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "dev": true, "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">=16 || 14 >=14.18" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.1.tgz", + "integrity": "sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==", + "dev": true, + "engines": { + "node": "20 || >=22" + } }, "node_modules/path-to-regexp": { "version": "6.3.0", @@ -25519,6 +25703,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "dev": true, "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -25648,14 +25833,12 @@ "devOptional": true }, "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/rambda": { @@ -25693,33 +25876,6 @@ "node": ">= 0.8" } }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -26042,28 +26198,6 @@ "node": ">=4" } }, - "node_modules/registry-auth-token": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", - "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", - "dependencies": { - "rc": "1.2.8" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/regjsgen": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", @@ -26286,15 +26420,6 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, - "node_modules/requireindex": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", - "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", - "dev": true, - "engines": { - "node": ">=0.10.5" - } - }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -26322,11 +26447,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" - }, "node_modules/resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", @@ -26405,17 +26525,6 @@ "node": ">=10" } }, - "node_modules/responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "dependencies": { - "lowercase-keys": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -26472,6 +26581,49 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "devOptional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "devOptional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "devOptional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/rollup": { "version": "4.24.3", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.3.tgz", @@ -27239,6 +27391,19 @@ "node": ">=8" } }, + "node_modules/spawn-wrap/node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/spawn-wrap/node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -27883,6 +28048,46 @@ "webpack": "^5.0.0" } }, + "node_modules/stylus/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/stylus/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/stylus/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/stylus/node_modules/sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", @@ -28224,6 +28429,27 @@ "concat-map": "0.0.1" } }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "devOptional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/test-exclude/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -28632,27 +28858,6 @@ "node": ">=0.6.x" } }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "node_modules/tuf-js": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.1.tgz", @@ -28797,203 +29002,6 @@ } } }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.0.tgz", - "integrity": "sha512-wORFWjU30B2WJ/aXBfOm1LX9v9nyt9D3jsSOxC3cCaTQGCW5k4jNpmjFv3U7p/7s4yvdjHzwtv2Sd2dOyhjS0A==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.8.0", - "@typescript-eslint/type-utils": "8.8.0", - "@typescript-eslint/utils": "8.8.0", - "@typescript-eslint/visitor-keys": "8.8.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.8.0.tgz", - "integrity": "sha512-uEFUsgR+tl8GmzmLjRqz+VrDv4eoaMqMXW7ruXfgThaAShO9JTciKpEsB+TvnfFfbg5IpujgMXVV36gOJRLtZg==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "8.8.0", - "@typescript-eslint/types": "8.8.0", - "@typescript-eslint/typescript-estree": "8.8.0", - "@typescript-eslint/visitor-keys": "8.8.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.0.tgz", - "integrity": "sha512-EL8eaGC6gx3jDd8GwEFEV091210U97J0jeEHrAYvIYosmEGet4wJ+g0SYmLu+oRiAwbSA5AVrt6DxLHfdd+bUg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.8.0", - "@typescript-eslint/visitor-keys": "8.8.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.8.0.tgz", - "integrity": "sha512-IKwJSS7bCqyCeG4NVGxnOP6lLT9Okc3Zj8hLO96bpMkJab+10HIfJbMouLrlpyOr3yrQ1cA413YPFiGd1mW9/Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "8.8.0", - "@typescript-eslint/utils": "8.8.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.0.tgz", - "integrity": "sha512-QJwc50hRCgBd/k12sTykOJbESe1RrzmX6COk8Y525C9l7oweZ+1lw9JiU56im7Amm8swlz00DRIlxMYLizr2Vw==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.0.tgz", - "integrity": "sha512-ZaMJwc/0ckLz5DaAZ+pNLmHv8AMVGtfWxZe/x2JVEkD5LnmhWiQMMcYT7IY7gkdJuzJ9P14fRy28lUrlDSWYdw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.8.0", - "@typescript-eslint/visitor-keys": "8.8.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.0.tgz", - "integrity": "sha512-QE2MgfOTem00qrlPgyByaCHay9yb1+9BjnMFnSFkUKQfu7adBXDTnCAivURnuPPAG/qiB+kzKkZKmKfaMT0zVg==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.8.0", - "@typescript-eslint/types": "8.8.0", - "@typescript-eslint/typescript-estree": "8.8.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.0.tgz", - "integrity": "sha512-8mq51Lx6Hpmd7HnA2fcHQo3YgfX1qbccxQOgZcb4tvasu//zXRaA1j5ZRFeCw/VRAdFi4mRM9DnZw0Nu0Q2d1g==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.8.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/ua-parser-js": { "version": "0.7.39", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.39.tgz", @@ -30595,21 +30603,6 @@ } } }, - "node_modules/webpack-dev-server/node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/webpack-dev-server/node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -30660,6 +30653,25 @@ "node": ">= 10" } }, + "node_modules/webpack-dev-server/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/webpack-dev-server/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + }, "node_modules/webpack-dev-server/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -30674,6 +30686,21 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/webpack-dev-server/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/webpack-dev-server/node_modules/rimraf": { "version": "5.0.10", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", diff --git a/package.json b/package.json index c048d0c5b6..57d09008bc 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "lint:affected": "nx affected:lint --quiet --silent --parallel=5", "format": "nx format:write", "format:check": "nx format:check", + "dev:refresh-skyux-eslint-deprecations-summary": "npm run dev:create-packages-dist -- --skipNxCache && ts-node ./scripts/refresh-skyux-eslint-deprecations-summary.ts", "dev:check-library-dependencies": "skyux-dev check-lib-dependencies", "dev:check-library-missing-peers": "skyux-dev check-lib-missing-peers --fix", "dev:update-library-dependencies": "nx g @skyux-sdk/tools:update-dependencies", @@ -118,7 +119,6 @@ "moment": "2.30.1", "ng2-dragula": "5.1.0", "normalize-scss": "8.0.0", - "package-json": "7.0.0", "rxjs": "7.8.1", "storybook": "8.3.5", "tslib": "2.6.3", @@ -129,13 +129,16 @@ "@angular-devkit/build-angular": "18.2.8", "@angular-devkit/core": "18.2.8", "@angular-devkit/schematics": "18.2.8", + "@angular-eslint/bundled-angular-compiler": "18.3.1", "@angular-eslint/eslint-plugin": "18.3.1", "@angular-eslint/eslint-plugin-template": "18.3.1", "@angular-eslint/template-parser": "18.3.1", + "@angular-eslint/test-utils": "18.3.1", + "@angular-eslint/utils": "18.3.1", "@angular/cli": "18.2.8", "@angular/compiler-cli": "18.2.8", "@angular/language-service": "18.2.8", - "@cspell/eslint-plugin": "8.14.4", + "@cspell/eslint-plugin": "8.15.4", "@istanbuljs/nyc-config-typescript": "1.0.2", "@nx/cypress": "20.0.0", "@nx/devkit": "20.0.0", @@ -178,22 +181,25 @@ "@types/dragula": "2.1.36", "@types/fontfaceobserver": "2.1.3", "@types/fs-extra": "11.0.4", + "@types/glob": "8.1.0", "@types/google-libphonenumber": "7.4.30", "@types/he": "1.2.3", "@types/jasmine": "5.1.4", "@types/jest": "29.5.13", "@types/node": "20.14.12", "@types/validator": "13.12.0", - "@typescript-eslint/eslint-plugin": "8.8.1", - "@typescript-eslint/parser": "8.8.1", + "@typescript-eslint/eslint-plugin": "8.8.0", + "@typescript-eslint/parser": "8.8.0", + "@typescript-eslint/utils": "8.8.0", "angular-eslint": "18.3.1", "cross-spawn": "7.0.3", "cypress": "13.15.0", "eslint": "9.12.0", "eslint-config-prettier": "9.1.0", - "eslint-plugin-cypress": "3.5.0", - "eslint-plugin-storybook": "0.9.0", + "eslint-plugin-cypress": "4.0.0", + "eslint-plugin-storybook": "0.10.1", "fs-extra": "11.2.0", + "glob": "11.0.0", "jasmine": "5.3.0", "jasmine-core": "5.3.0", "jest": "29.7.0", diff --git a/scripts/refresh-skyux-eslint-deprecations-summary.ts b/scripts/refresh-skyux-eslint-deprecations-summary.ts new file mode 100644 index 0000000000..6822e0051b --- /dev/null +++ b/scripts/refresh-skyux-eslint-deprecations-summary.ts @@ -0,0 +1,149 @@ +/* eslint-disable complexity, max-depth */ +import { glob } from 'glob'; +import { readFile, writeFile } from 'node:fs/promises'; +import path from 'node:path'; + +interface DeprecatedProperty { + reason?: string; +} + +type DeprecatedProperties = Record; + +interface DeprecatedDirective { + deprecated: boolean; + reason?: string; + properties?: DeprecatedProperties; +} + +interface Deprecations { + components?: Record; + directives?: Record; +} + +const DEPRECATIONS_FILE_PATH = path.normalize( + 'libs/sdk/skyux-eslint/src/__deprecations.json', +); + +/** + * These selectors are deprecated, but have a non-deprecated replacement. Since + * the selectors are the same, we won't be able to distinguish between the + * deprecated selector and the non-deprecated selector. + */ +const EXCLUDE_SELECTORS = ['sky-page']; + +/** + * Refreshes the __deprecations.json file used by the + * 'skyux-eslint-template/no-deprecated-directives' rule. + */ +async function refreshSkyuxEslintDeprecationsSummary(): Promise { + const deprecations: Deprecations = {}; + + const files = await glob('dist/libs/components/*/documentation.json'); + + if (files.length === 0) { + throw new Error( + 'No documentation.json files found. ' + + 'Did you run `npx skyux-dev create-packages-dist`?', + ); + } + + for (const file of files) { + const json = JSON.parse( + await readFile(path.normalize(file), { encoding: 'utf-8' }), + ); + + for (const docs of json.typedoc.children) { + const docsDecorator = docs.decorators?.[0]; + + if (!docsDecorator) { + continue; + } + + const isDirective = docsDecorator.name === 'Directive'; + + if (docsDecorator.name === 'Component' || isDirective) { + let selector: string = docsDecorator.arguments.obj + .split("selector: '")[1] + .split("'")[0]; + + if (EXCLUDE_SELECTORS.includes(selector)) { + continue; + } + + if (isDirective) { + selector = selector.split('[')[1].split(']')[0]; + } + + const category: keyof Deprecations = isDirective + ? 'directives' + : 'components'; + + if (docs.comment?.blockTags) { + for (const tag of docs.comment.blockTags) { + if (tag.tag === '@deprecated') { + deprecations[category] ??= {}; + deprecations[category][selector] = { + deprecated: true, + }; + + const reason = tag.content + .map((x: { text: string }) => x.text.replace('\n', ' ')) + .join('') + .trim(); + + if (reason) { + deprecations[category][selector].reason = reason; + } + } + } + } + + for (const property of docs.children) { + const propertyDecorator = property.decorators?.[0]; + + const isInput = + propertyDecorator?.name === 'Input' || + property.type?.name === 'InputSignal'; + + const isOutput = + propertyDecorator?.name === 'Output' || + property.type?.name === 'OutputEmitterRef'; + + if (isInput || isOutput) { + const tags = + property.comment?.blockTags ?? + property.setSignature?.comment?.blockTags ?? + property.getSignature?.comment?.blockTags; + + if (tags) { + for (const tag of tags) { + if (tag.tag === '@deprecated') { + const reason = tag.content + .map((x: { text: string }) => x.text.replace('\n', ' ')) + .join('') + .trim(); + + deprecations[category] ??= {}; + deprecations[category][selector] ??= { deprecated: false }; + + const directive = deprecations[category][selector]; + + directive.properties ??= {}; + directive.properties[property.name] = {}; + + if (reason) { + directive.properties[property.name].reason = reason; + } + } + } + } + } + } + } + } + } + + await writeFile(DEPRECATIONS_FILE_PATH, JSON.stringify(deprecations)); +} + +void refreshSkyuxEslintDeprecationsSummary(); diff --git a/tsconfig.base.json b/tsconfig.base.json index b470cb219e..7c12b34362 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -162,7 +162,8 @@ "@skyux/toast/testing": [ "libs/components/toast/testing/src/public-api.ts" ], - "@skyux/validation": ["libs/components/validation/src/index.ts"] + "@skyux/validation": ["libs/components/validation/src/index.ts"], + "skyux-eslint": ["libs/sdk/skyux-eslint/src/index.ts"] } }, "angularCompilerOptions": {