From d569dea1fb33353e99d8492ad41b64bd270bd0d1 Mon Sep 17 00:00:00 2001 From: Ante Budimir Date: Tue, 4 Mar 2025 20:16:50 +0200 Subject: [PATCH] =?UTF-8?q?feat=20=F0=9F=A5=81:=20initialize=20project=20w?= =?UTF-8?q?ith=20complete=20codebase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 32 + .nvmrc | 1 + .prettierrc | 17 + LICENSE | 21 + README.md | 242 ++ eslint-plugin-eslint-plugin.d.ts | 10 + eslint-plugin-import.d.ts | 1 + eslint.config.mjs | 126 + package.json | 75 + pnpm-lock.yaml | 2427 +++++++++++++++++ src/css-rules/alphabetical-order/index.ts | 3 + .../property-order-enforcer.ts | 84 + .../recipe-order-enforcer.ts | 28 + .../alphabetical-order/rule-definition.ts | 23 + .../style-object-processor.ts | 37 + .../concentric-order/concentric-groups.ts | 336 +++ src/css-rules/concentric-order/index.ts | 3 + .../property-order-enforcer.ts | 85 + .../concentric-order/recipe-order-enforcer.ts | 31 + .../concentric-order/rule-definition.ts | 23 + .../style-object-processor.ts | 72 + src/css-rules/concentric-order/types.ts | 9 + .../custom-order/property-order-enforcer.ts | 91 + .../custom-order/recipe-order-enforcer.ts | 42 + src/css-rules/custom-order/rule-definition.ts | 55 + .../custom-order/style-object-processor.ts | 79 + src/css-rules/shared-utils/css-order-fixer.ts | 55 + .../shared-utils/css-property-priority-map.ts | 60 + .../nested-selectors-processor.ts | 44 + .../order-strategy-visitor-creator.ts | 98 + .../shared-utils/property-separator.ts | 57 + .../shared-utils/recipe-property-processor.ts | 45 + .../shared-utils/style-node-processor.ts | 30 + src/index.ts | 39 + tsconfig.json | 32 + 35 files changed, 4413 insertions(+) create mode 100644 .gitignore create mode 100644 .nvmrc create mode 100644 .prettierrc create mode 100644 LICENSE create mode 100644 README.md create mode 100644 eslint-plugin-eslint-plugin.d.ts create mode 100644 eslint-plugin-import.d.ts create mode 100644 eslint.config.mjs create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 src/css-rules/alphabetical-order/index.ts create mode 100644 src/css-rules/alphabetical-order/property-order-enforcer.ts create mode 100644 src/css-rules/alphabetical-order/recipe-order-enforcer.ts create mode 100644 src/css-rules/alphabetical-order/rule-definition.ts create mode 100644 src/css-rules/alphabetical-order/style-object-processor.ts create mode 100644 src/css-rules/concentric-order/concentric-groups.ts create mode 100644 src/css-rules/concentric-order/index.ts create mode 100644 src/css-rules/concentric-order/property-order-enforcer.ts create mode 100644 src/css-rules/concentric-order/recipe-order-enforcer.ts create mode 100644 src/css-rules/concentric-order/rule-definition.ts create mode 100644 src/css-rules/concentric-order/style-object-processor.ts create mode 100644 src/css-rules/concentric-order/types.ts create mode 100644 src/css-rules/custom-order/property-order-enforcer.ts create mode 100644 src/css-rules/custom-order/recipe-order-enforcer.ts create mode 100644 src/css-rules/custom-order/rule-definition.ts create mode 100644 src/css-rules/custom-order/style-object-processor.ts create mode 100644 src/css-rules/shared-utils/css-order-fixer.ts create mode 100644 src/css-rules/shared-utils/css-property-priority-map.ts create mode 100644 src/css-rules/shared-utils/nested-selectors-processor.ts create mode 100644 src/css-rules/shared-utils/order-strategy-visitor-creator.ts create mode 100644 src/css-rules/shared-utils/property-separator.ts create mode 100644 src/css-rules/shared-utils/recipe-property-processor.ts create mode 100644 src/css-rules/shared-utils/style-node-processor.ts create mode 100644 src/index.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..581d8f6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz +.pnpm-store/ +.pnpm-debug.log* + +# testing +/coverage + +# production +/build +/dist + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# local env files +.env*.local + +# typescript +*.tsbuildinfo diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..209e3ef --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +20 diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..5429867 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,17 @@ +{ + "proseWrap": "always", + "printWidth": 120, + "tabWidth": 2, + "semi": true, + "singleQuote": true, + "trailingComma": "all", + "bracketSameLine": true, + "overrides": [ + { + "files": "*.jsonc", + "options": { + "trailingComma": "none" + } + } + ] +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..442f3cf --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Ante Budimir + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..5fe1827 --- /dev/null +++ b/README.md @@ -0,0 +1,242 @@ +# @antebudimir/eslint-plugin-vanilla-extract + +An ESLint plugin for enforcing CSS ordering in vanilla-extract css styles. Available presets are for alphabetical and +[concentric](https://rhodesmill.org/brandon/2011/concentric-css/) CSS ordering. The plugin also supports a custom group ordering option based on groups available in concentric CSS. + +## Features + +- Enforces CSS property ordering in vanilla-extract style objects with two available presets: + - Alphabetical ordering for clean, predictable style organization + - Concentric ordering for logical, outside-in property arrangement +- Custom group ordering option for more fine-grained control +- Built for ESLint 9 flat config system +- Provides auto-fix capability to automatically sort properties +- Handles multiple vanilla-extract APIs (style, styleVariants, recipe, globalStyle, etc.) +- Handles complex cases like nested objects, arrays of styles, and pseudo selectors +- Works with camelCase properties as used in vanilla-extract + + +## Requirements + +- ESLint 9.0.0 or higher +- Node.js 18.18.0 or higher + +## Installation + +```bash +# Using npm +npm install --save-dev @antebudimir/eslint-plugin-vanilla-extract + +# Using yarn +yarn add --dev @antebudimir/eslint-plugin-vanilla-extract + +# Using pnpm +pnpm add -D @antebudimir/eslint-plugin-vanilla-extract +``` + +## Usage + +### ESLint Flat Config (ESLint 9+) + +Create or update your `eslint.config.js` or `eslint.config.mjs` file: + +```typescript +import vanillaExtract from '@antebudimir/eslint-plugin-vanilla-extract'; + +export default [ + { + files: ['**/*.css.ts'], + ignores: ['src/**/theme-contract.css.ts'], + plugins: { + 'vanilla-extract': vanillaExtract, + }, + rules: { + // 'vanilla-extract/alphabetical-order': 'warn', + // OR + // 'vanilla-extract/concentric-order': 'warn', + // OR + 'vanilla-extract/custom-order': [ + 'warn', + { + groupOrder: ['font', 'dimensions', 'margin', 'padding', 'position', 'border'], // example group order + // optional + sortRemainingProperties: 'concentric', // 'alphabetical' is default + }, + ], + }, + }, +]; +``` + +## Rules + +### vanilla-extract/alphabetical-order + +This rule enforces that CSS properties in vanilla-extract style objects follow alphabetical ordering. + +```typescript +// ❌ Incorrect +import { style } from '@vanilla-extract/css'; + +export const myStyle = style({ + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + height: 19, + marginBottom: 1, + marginLeft: 2, +}); + +// ✅ Correct +import { style } from '@vanilla-extract/css'; + +export const myStyle = style({ + alignItems: 'center', + display: 'flex', + height: 19, + justifyContent: 'center', + marginBottom: 1, + marginLeft: 2, +}); +``` + +### vanilla-extract/concentric-order + +This rule enforces that CSS properties in vanilla-extract style objects follow the concentric CSS ordering pattern, +which organizes properties from outside to inside. + +```typescript +// ❌ Incorrect +import { style } from '@vanilla-extract/css'; + +export const myStyle = style({ + color: 'red', + display: 'flex', + position: 'relative', + padding: '10px', + margin: '20px', +}); + +// ✅ Correct +import { style } from '@vanilla-extract/css'; + +export const myStyle = style({ + position: 'relative', + display: 'flex', + margin: '20px', + padding: '10px', + color: 'red', +}); +``` + +### vanilla-extract/custom-order + +The `vanilla-extract/custom-order` rule allows you to enforce a custom ordering of CSS properties in your vanilla-extract styles. You can specify an array of property groups in the order you prefer, and the rule will ensure that properties within these groups are sorted according to their position in the concentric CSS model. All other groups that aren't included in the groups array will have their respective properties sorted after the last group in the array. You can choose to sort them either alphabetically or following the concentric CSS order (see list of concentric groups) by setting the `sortRemainingProperties` option to 'alphabetical' or 'concentric' respectively. If not set, `sortRemainingProperties` defaults to 'alphabetical'. + +To configure the rule, add it to your ESLint configuration file with your desired options. You can customize the `groups` array to include any number of available CSS property groups you want to enforce, but minimum of 1 is required. + +Example usage: + +```typescript +// ❌ Incorrect (Unordered) +import { style } from '@vanilla-extract/css'; + +export const myStyle = style({ + color: 'blue', + padding: '10px', + fontFamily: 'Arial, sans-serif', + margin: '20px', + width: '200px', + border: '1px solid black', + display: 'flex', +}); + +// ✅ Correct +import { style } from '@vanilla-extract/css'; + +export const myStyle = style({ + // font group + fontFamily: 'Arial, sans-serif', + color: 'blue', + + // dimensions group + width: '200px', + + // margin group + margin: '20px', + + // padding group + padding: '10px', + + // display group + display: 'flex', + + // border group + border: '1px solid black', +}); +``` + +## Concentric CSS Model + +Here's a list of all available groups from the provided concentricGroups array: + +1. boxSizing +2. position +3. display +4. flex +5. grid +6. alignment +7. columns +8. transform +9. transitions +10. visibility +11. shape +12. margin +13. outline +14. border +15. boxShadow +16. background +17. cursor +18. padding +19. dimensions +20. overflow +21. listStyle +22. tables +23. animation +24. text +25. textSpacing +26. font +27. content +28. counters +29. breaks + +These groups represent different categories of CSS properties, organized in a concentric order from outside to inside. Each group contains related CSS properties that affect specific aspects of an element's styling and layout. + +## Roadmap + +The roadmap outlines the project's current status and future plans: + +### Completed Milestones + +- Initial release with support for alphabetical, concentric, and custom group CSS ordering. +- Auto-fix capability integrated into ESLint. +- Support for multiple vanilla-extract APIs (e.g., `style`, `styleVariants`, `recipe`, `globalStyle` etc.). + +### Current Work + +- Compatibility testing to determine if the plugin works with ESLint v8. **Note**: There are no plans to ensure compatibility if issues arise. Upcoming features will be prioritized. + +### Upcoming Features + +- Begin work on test coverage. +- Support for additional vanilla-extract APIs, including `fontFace`, `globalFontFace`, `globalKeyframes`, and `keyframes`. +- Option to sort properties within user-defined concentric groups alphabetically instead of following the concentric order. **Note**: This feature will only be implemented if there's sufficient interest from the community. + +## Contributing + +All well-intentioned contributions are welcome, of course! Please feel free to submit a Pull Request or get in touch via +GitHub issues. + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. diff --git a/eslint-plugin-eslint-plugin.d.ts b/eslint-plugin-eslint-plugin.d.ts new file mode 100644 index 0000000..ca89b61 --- /dev/null +++ b/eslint-plugin-eslint-plugin.d.ts @@ -0,0 +1,10 @@ +declare module 'eslint-plugin-eslint-plugin' { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const configs: Record; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const rules: Record; + export { configs, rules }; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const _default: { configs: Record; rules: Record }; + export default _default; +} diff --git a/eslint-plugin-import.d.ts b/eslint-plugin-import.d.ts new file mode 100644 index 0000000..a8d8de7 --- /dev/null +++ b/eslint-plugin-import.d.ts @@ -0,0 +1 @@ +declare module 'eslint-plugin-import'; diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..e44a25a --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,126 @@ +import path from 'path'; +import { fileURLToPath } from 'url'; +import { FlatCompat } from '@eslint/eslintrc'; +import eslintPluginESLintPlugin from 'eslint-plugin-eslint-plugin'; +import importPlugin from 'eslint-plugin-import'; +import * as tseslint from 'typescript-eslint'; +import vanillaExtract from '@antebudimir/eslint-plugin-vanilla-extract'; + +// mimic CommonJS variables +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const compat = new FlatCompat({ + baseDirectory: __dirname, +}); + +export default [ + // mimic ESLintRC-style extends + // Prettier always must be last to override other style rules + ...compat.extends('prettier'), + { + files: ['**/*.js', '**/*.ts', '**/*.cjs', '**/*.mjs'], + plugins: { + 'eslint-plugin': eslintPluginESLintPlugin, + import: importPlugin, + }, + settings: { + 'import/parsers': { + '@typescript-eslint/parser': ['.ts'], + }, + 'import/resolver': { + typescript: { + alwaysTryTypes: true, + project: './tsconfig.json', + }, + node: { + extensions: ['.js', '.ts'], + }, + }, + }, + rules: { + ...eslintPluginESLintPlugin.configs.recommended.rules, + 'eslint-plugin/prefer-message-ids': 'error', + 'eslint-plugin/require-meta-type': 'error', + 'eslint-plugin/require-meta-docs-description': 'error', + 'eslint-plugin/consistent-output': 'error', + 'import/order': [ + 'error', + { + groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'type'], + pathGroups: [ + { + pattern: '{@eslint/**,eslint,eslint-plugin-*}', + group: 'external', + position: 'before', + }, + { + pattern: '@vanilla-extract/**', + group: 'external', + position: 'after', + }, + ], + pathGroupsExcludedImportTypes: ['builtin', 'object'], + 'newlines-between': 'never', + alphabetize: { + order: 'asc', + caseInsensitive: true, + }, + }, + ], + 'import/no-unresolved': 'error', + 'import/named': 'error', + 'import/namespace': 'error', + 'import/default': 'error', + 'import/export': 'error', + }, + }, + ...tseslint.configs.recommended, + + { + files: ['**/*.css.ts'], + plugins: { + 'vanilla-extract': vanillaExtract, + }, + rules: { + // 'vanilla-extract/alphabetical-order': 'warn', + // 'vanilla-extract/concentric-order': 'error', + 'vanilla-extract/custom-order': [ + 'error', + { + groupOrder: ['dimensions', 'margin', 'font', 'border', 'boxShadow'], + // Optional + sortRemainingProperties: 'concentric', // or 'alphabetical' (default) + }, + ], + }, + }, + + { + files: ['**/*.{js,ts}'], + languageOptions: { + parser: tseslint.parser, + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: './tsconfig.json', + }, + }, + rules: { + // TypeScript rules + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-unsafe-assignment': 'error', + '@typescript-eslint/no-unsafe-member-access': 'error', + '@typescript-eslint/no-empty-object-type': 'error', + '@typescript-eslint/no-unsafe-function-type': 'error', + '@typescript-eslint/no-unused-vars': 'warn', + '@typescript-eslint/no-wrapper-object-types': 'error', + + // General rules + curly: 'error', + eqeqeq: 'error', + 'no-console': 'warn', + 'no-unused-vars': 'off', + }, + }, +]; diff --git a/package.json b/package.json new file mode 100644 index 0000000..69d5874 --- /dev/null +++ b/package.json @@ -0,0 +1,75 @@ +{ + "name": "@antebudimir/eslint-plugin-vanilla-extract", + "version": "1.0.0", + "description": "ESLint plugin for enforcing CSS ordering in vanilla-extract styles", + "author": "Ante Budimir", + "license": "MIT", + "keywords": [ + "eslint", + "eslintplugin", + "eslint-plugin", + "vanilla-extract", + "css", + "css-in-js", + "concentric", + "alphabetical", + "typescript", + "style", + "ordering", + "zero-runtime" + ], + "repository": { + "type": "git", + "url": "https://github.com/antebudimir/eslint-plugin-vanilla-extract.git" + }, + "bugs": { + "url": "https://github.com/antebudimir/eslint-plugin-vanilla-extract/issues" + }, + "homepage": "https://github.com/antebudimir/eslint-plugin-vanilla-extract#readme", + "type": "module", + "main": "dist/index.js", + "exports": { + ".": { + "import": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsc", + "format": "prettier --write .", + "lint": "eslint src --ext .ts --fix --max-warnings 0", + "prepublishOnly": "pnpm run lint && pnpm run build", + "publish": "pnpm publish --access public", + "typecheck": "tsc --noEmit", + "version:major": "pnpm version major --no-git-tag-version", + "version:minor": "pnpm version minor --no-git-tag-version", + "version:patch": "pnpm version patch --no-git-tag-version" + }, + "engines": { + "node": ">=20.18.3" + }, + "packageManager": "pnpm@10.5.0", + "peerDependencies": { + "eslint": ">=9.0.0" + }, + "devDependencies": { + "@eslint/eslintrc": "^3.3.0", + "@types/node": "^20.17.19", + "@typescript-eslint/eslint-plugin": "^8.25.0", + "@typescript-eslint/parser": "^8.25.0", + "@typescript-eslint/utils": "^8.25.0", + "@vanilla-extract/css": "^1.17.1", + "@vanilla-extract/recipes": "^0.5.5", + "eslint": "^9.21.0", + "eslint-config-prettier": "^10.0.2", + "eslint-import-resolver-typescript": "^3.8.3", + "eslint-plugin-eslint-plugin": "^6.4.0", + "eslint-plugin-import": "^2.31.0", + "prettier": "^3.5.2", + "typescript": "^5.7.3", + "typescript-eslint": "^8.25.0" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..87e5bbb --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,2427 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@antebudimir/eslint-plugin-vanilla-extract': + specifier: ./antebudimir-eslint-plugin-vanilla-extract-2.10.83.tgz + version: file:antebudimir-eslint-plugin-vanilla-extract-2.10.83.tgz(eslint@9.21.0) + '@eslint/eslintrc': + specifier: ^3.3.0 + version: 3.3.0 + '@types/node': + specifier: ^20.17.19 + version: 20.17.19 + '@typescript-eslint/eslint-plugin': + specifier: ^8.25.0 + version: 8.25.0(@typescript-eslint/parser@8.25.0(eslint@9.21.0)(typescript@5.7.3))(eslint@9.21.0)(typescript@5.7.3) + '@typescript-eslint/parser': + specifier: ^8.25.0 + version: 8.25.0(eslint@9.21.0)(typescript@5.7.3) + '@typescript-eslint/utils': + specifier: ^8.25.0 + version: 8.25.0(eslint@9.21.0)(typescript@5.7.3) + '@vanilla-extract/css': + specifier: ^1.17.1 + version: 1.17.1 + '@vanilla-extract/recipes': + specifier: ^0.5.5 + version: 0.5.5(@vanilla-extract/css@1.17.1) + eslint: + specifier: ^9.21.0 + version: 9.21.0 + eslint-config-prettier: + specifier: ^10.0.2 + version: 10.0.2(eslint@9.21.0) + eslint-import-resolver-typescript: + specifier: ^3.8.3 + version: 3.8.3(eslint-plugin-import@2.31.0)(eslint@9.21.0) + eslint-plugin-eslint-plugin: + specifier: ^6.4.0 + version: 6.4.0(eslint@9.21.0) + eslint-plugin-import: + specifier: ^2.31.0 + version: 2.31.0(@typescript-eslint/parser@8.25.0(eslint@9.21.0)(typescript@5.7.3))(eslint-import-resolver-typescript@3.8.3)(eslint@9.21.0) + prettier: + specifier: ^3.5.2 + version: 3.5.2 + typescript: + specifier: ^5.7.3 + version: 5.7.3 + typescript-eslint: + specifier: ^8.25.0 + version: 8.25.0(eslint@9.21.0)(typescript@5.7.3) + +packages: + + '@antebudimir/eslint-plugin-vanilla-extract@file:antebudimir-eslint-plugin-vanilla-extract-2.10.83.tgz': + resolution: {integrity: sha512-4wbgC0r7Has3eZiN2P1RdvUhuC4zoGQmn85WUKy5OBDaW6FgT2NAuLNiYWU44oyK0WQmfVhMi6E8qhrFgpkVTA==, tarball: file:antebudimir-eslint-plugin-vanilla-extract-2.10.83.tgz} + version: 1.0.0 + engines: {node: '>=20.18.3'} + peerDependencies: + eslint: '>=9.0.0' + + '@babel/runtime@7.26.9': + resolution: {integrity: sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==} + engines: {node: '>=6.9.0'} + + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + + '@eslint-community/eslint-utils@4.4.1': + resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.19.2': + resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.12.0': + resolution: {integrity: sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.0': + resolution: {integrity: sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.21.0': + resolution: {integrity: sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.6': + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.2.7': + resolution: {integrity: sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.6': + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.3.1': + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} + + '@humanwhocodes/retry@0.4.2': + resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} + engines: {node: '>=18.18'} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nolyfill/is-core-module@1.0.39': + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/node@20.17.19': + resolution: {integrity: sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==} + + '@typescript-eslint/eslint-plugin@8.25.0': + resolution: {integrity: sha512-VM7bpzAe7JO/BFf40pIT1lJqS/z1F8OaSsUB3rpFJucQA4cOSuH2RVVVkFULN+En0Djgr29/jb4EQnedUo95KA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + + '@typescript-eslint/parser@8.25.0': + resolution: {integrity: sha512-4gbs64bnbSzu4FpgMiQ1A+D+urxkoJk/kqlDJ2W//5SygaEiAP2B4GoS7TEdxgwol2el03gckFV9lJ4QOMiiHg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + + '@typescript-eslint/scope-manager@8.25.0': + resolution: {integrity: sha512-6PPeiKIGbgStEyt4NNXa2ru5pMzQ8OYKO1hX1z53HMomrmiSB+R5FmChgQAP1ro8jMtNawz+TRQo/cSXrauTpg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/type-utils@8.25.0': + resolution: {integrity: sha512-d77dHgHWnxmXOPJuDWO4FDWADmGQkN5+tt6SFRZz/RtCWl4pHgFl3+WdYCn16+3teG09DY6XtEpf3gGD0a186g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + + '@typescript-eslint/types@8.25.0': + resolution: {integrity: sha512-+vUe0Zb4tkNgznQwicsvLUJgZIRs6ITeWSCclX1q85pR1iOiaj+4uZJIUp//Z27QWu5Cseiw3O3AR8hVpax7Aw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.25.0': + resolution: {integrity: sha512-ZPaiAKEZ6Blt/TPAx5Ot0EIB/yGtLI2EsGoY6F7XKklfMxYQyvtL+gT/UCqkMzO0BVFHLDlzvFqQzurYahxv9Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.8.0' + + '@typescript-eslint/utils@8.25.0': + resolution: {integrity: sha512-syqRbrEv0J1wywiLsK60XzHnQe/kRViI3zwFALrNEgnntn1l24Ra2KvOAWwWbWZ1lBZxZljPDGOq967dsl6fkA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + + '@typescript-eslint/visitor-keys@8.25.0': + resolution: {integrity: sha512-kCYXKAum9CecGVHGij7muybDfTS2sD3t0L4bJsEZLkyrXUImiCTq1M3LG2SRtOhiHFwMR9wAFplpT6XHYjTkwQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@vanilla-extract/css@1.17.1': + resolution: {integrity: sha512-tOHQXHm10FrJeXKFeWE09JfDGN/tvV6mbjwoNB9k03u930Vg021vTnbrCwVLkECj9Zvh/SHLBHJ4r2flGqfovw==} + + '@vanilla-extract/private@1.0.6': + resolution: {integrity: sha512-ytsG/JLweEjw7DBuZ/0JCN4WAQgM9erfSTdS1NQY778hFQSZ6cfCDEZZ0sgVm4k54uNz6ImKB33AYvSR//fjxw==} + + '@vanilla-extract/recipes@0.5.5': + resolution: {integrity: sha512-VadU7+IFUwLNLMgks29AHav/K5h7DOEfTU91RItn5vwdPfzduodNg317YbgWCcpm7FSXkuR3B3X8ZOi95UOozA==} + peerDependencies: + '@vanilla-extract/css': ^1.0.0 + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.5: + resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.3: + resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + css-what@6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + dedent@1.5.3: + resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deep-object-diff@1.1.9: + resolution: {integrity: sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + enhanced-resolve@5.18.1: + resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} + engines: {node: '>=10.13.0'} + + es-abstract@1.23.9: + resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-prettier@10.0.2: + resolution: {integrity: sha512-1105/17ZIMjmCOJOPNfVdbXafLCLj3hPmkmB7dLgt7XsQ/zkxSuDerE/xgO3RxoHysR1N1whmquY0lSn2O0VLg==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-import-resolver-typescript@3.8.3: + resolution: {integrity: sha512-A0bu4Ks2QqDWNpeEgTQMPTngaMhuDu4yv6xpftBMAf+1ziXnpx+eSR1WRfoPTe2BAiAjHFZ7kSNx1fvr5g5pmQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + + eslint-module-utils@2.12.0: + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-eslint-plugin@6.4.0: + resolution: {integrity: sha512-X94/hr7DnckX68wE6Qqeo3DsZndZSclfoewjwD249yG5z2EAOl3UGUohLIgOpmbUjcFv6AlfW3wxBnOiWkS1Iw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: '>=8.23.0' + + eslint-plugin-import@2.31.0: + resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-scope@8.2.0: + resolution: {integrity: sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.21.0: + resolution: {integrity: sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.19.0: + resolution: {integrity: sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==} + + fdir@6.4.3: + resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.10.0: + resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-bun-module@1.3.0: + resolution: {integrity: sha512-DgXeu5UWI0IsMQundYb5UAOzm6G2eVnarJ0byP6Tm55iZNKceD59LNPA2L4VvsScTtHcw0yEkVwSf7PC+QoLSA==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-generator-function@1.1.0: + resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + media-query-parser@2.0.2: + resolution: {integrity: sha512-1N4qp+jE0pL5Xv4uEcwVUhIkwdUO3S/9gML90nqKA7v7FcOS5vUtatfzok9S9U1EJU8dHWlcv95WLnKmmxZI9w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + modern-ahocorasick@1.1.0: + resolution: {integrity: sha512-sEKPVl2rM+MNVkGQt3ChdmD8YsigmXdn5NifZn6jiwn9LRJpWm8F3guhaqrJT/JOat6pwpbXEk6kv+b9DMIjsQ==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier@3.5.2: + resolution: {integrity: sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg==} + engines: {node: '>=14'} + hasBin: true + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.1: + resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} + engines: {node: '>=10'} + hasBin: true + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + stable-hash@0.0.4: + resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + + tinyglobby@0.2.12: + resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + ts-api-utils@2.0.1: + resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typescript-eslint@8.25.0: + resolution: {integrity: sha512-TxRdQQLH4g7JkoFlYG3caW5v1S6kEkz8rqt80iQJZUYPq1zD1Ra7HfQBJJ88ABRaMvHAXnwRvRB4V+6sQ9xN5Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + + typescript@5.7.3: + resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} + engines: {node: '>=14.17'} + hasBin: true + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.18: + resolution: {integrity: sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@antebudimir/eslint-plugin-vanilla-extract@file:antebudimir-eslint-plugin-vanilla-extract-2.10.83.tgz(eslint@9.21.0)': + dependencies: + eslint: 9.21.0 + + '@babel/runtime@7.26.9': + dependencies: + regenerator-runtime: 0.14.1 + + '@emotion/hash@0.9.2': {} + + '@eslint-community/eslint-utils@4.4.1(eslint@9.21.0)': + dependencies: + eslint: 9.21.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/config-array@0.19.2': + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.0 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/core@0.12.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.0': + dependencies: + ajv: 6.12.6 + debug: 4.4.0 + espree: 10.3.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.21.0': {} + + '@eslint/object-schema@2.1.6': {} + + '@eslint/plugin-kit@0.2.7': + dependencies: + '@eslint/core': 0.12.0 + levn: 0.4.1 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.6': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.3.1': {} + + '@humanwhocodes/retry@0.4.2': {} + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.0 + + '@nolyfill/is-core-module@1.0.39': {} + + '@rtsao/scc@1.1.0': {} + + '@types/estree@1.0.6': {} + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/node@20.17.19': + dependencies: + undici-types: 6.19.8 + + '@typescript-eslint/eslint-plugin@8.25.0(@typescript-eslint/parser@8.25.0(eslint@9.21.0)(typescript@5.7.3))(eslint@9.21.0)(typescript@5.7.3)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.25.0(eslint@9.21.0)(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.25.0 + '@typescript-eslint/type-utils': 8.25.0(eslint@9.21.0)(typescript@5.7.3) + '@typescript-eslint/utils': 8.25.0(eslint@9.21.0)(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.25.0 + eslint: 9.21.0 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + ts-api-utils: 2.0.1(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.25.0(eslint@9.21.0)(typescript@5.7.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.25.0 + '@typescript-eslint/types': 8.25.0 + '@typescript-eslint/typescript-estree': 8.25.0(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.25.0 + debug: 4.4.0 + eslint: 9.21.0 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.25.0': + dependencies: + '@typescript-eslint/types': 8.25.0 + '@typescript-eslint/visitor-keys': 8.25.0 + + '@typescript-eslint/type-utils@8.25.0(eslint@9.21.0)(typescript@5.7.3)': + dependencies: + '@typescript-eslint/typescript-estree': 8.25.0(typescript@5.7.3) + '@typescript-eslint/utils': 8.25.0(eslint@9.21.0)(typescript@5.7.3) + debug: 4.4.0 + eslint: 9.21.0 + ts-api-utils: 2.0.1(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.25.0': {} + + '@typescript-eslint/typescript-estree@8.25.0(typescript@5.7.3)': + dependencies: + '@typescript-eslint/types': 8.25.0 + '@typescript-eslint/visitor-keys': 8.25.0 + debug: 4.4.0 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.1 + ts-api-utils: 2.0.1(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.25.0(eslint@9.21.0)(typescript@5.7.3)': + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@9.21.0) + '@typescript-eslint/scope-manager': 8.25.0 + '@typescript-eslint/types': 8.25.0 + '@typescript-eslint/typescript-estree': 8.25.0(typescript@5.7.3) + eslint: 9.21.0 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.25.0': + dependencies: + '@typescript-eslint/types': 8.25.0 + eslint-visitor-keys: 4.2.0 + + '@vanilla-extract/css@1.17.1': + dependencies: + '@emotion/hash': 0.9.2 + '@vanilla-extract/private': 1.0.6 + css-what: 6.1.0 + cssesc: 3.0.0 + csstype: 3.1.3 + dedent: 1.5.3 + deep-object-diff: 1.1.9 + deepmerge: 4.3.1 + lru-cache: 10.4.3 + media-query-parser: 2.0.2 + modern-ahocorasick: 1.1.0 + picocolors: 1.1.1 + transitivePeerDependencies: + - babel-plugin-macros + + '@vanilla-extract/private@1.0.6': {} + + '@vanilla-extract/recipes@0.5.5(@vanilla-extract/css@1.17.1)': + dependencies: + '@vanilla-extract/css': 1.17.1 + + acorn-jsx@5.3.2(acorn@8.14.0): + dependencies: + acorn: 8.14.0 + + acorn@8.14.0: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + argparse@2.0.1: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.3 + is-array-buffer: 3.0.5 + + array-includes@3.1.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + + array.prototype.findlastindex@1.2.5: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + async-function@1.0.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + balanced-match@1.0.2: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.3: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + concat-map@0.0.1: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + css-what@6.1.0: {} + + cssesc@3.0.0: {} + + csstype@3.1.3: {} + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.4.0: + dependencies: + ms: 2.1.3 + + dedent@1.5.3: {} + + deep-is@0.1.4: {} + + deep-object-diff@1.1.9: {} + + deepmerge@4.3.1: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + enhanced-resolve@5.18.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + + es-abstract@1.23.9: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-regex: 1.2.1 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.18 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + escape-string-regexp@4.0.0: {} + + eslint-config-prettier@10.0.2(eslint@9.21.0): + dependencies: + eslint: 9.21.0 + + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.1 + resolve: 1.22.10 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0)(eslint@9.21.0): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.4.0 + enhanced-resolve: 5.18.1 + eslint: 9.21.0 + get-tsconfig: 4.10.0 + is-bun-module: 1.3.0 + stable-hash: 0.0.4 + tinyglobby: 0.2.12 + optionalDependencies: + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.25.0(eslint@9.21.0)(typescript@5.7.3))(eslint-import-resolver-typescript@3.8.3)(eslint@9.21.0) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.25.0(eslint@9.21.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3)(eslint@9.21.0): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.25.0(eslint@9.21.0)(typescript@5.7.3) + eslint: 9.21.0 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.8.3(eslint-plugin-import@2.31.0)(eslint@9.21.0) + transitivePeerDependencies: + - supports-color + + eslint-plugin-eslint-plugin@6.4.0(eslint@9.21.0): + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@9.21.0) + eslint: 9.21.0 + estraverse: 5.3.0 + + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.25.0(eslint@9.21.0)(typescript@5.7.3))(eslint-import-resolver-typescript@3.8.3)(eslint@9.21.0): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.21.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.25.0(eslint@9.21.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3)(eslint@9.21.0) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.25.0(eslint@9.21.0)(typescript@5.7.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-scope@8.2.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.0: {} + + eslint@9.21.0: + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@9.21.0) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.19.2 + '@eslint/core': 0.12.0 + '@eslint/eslintrc': 3.3.0 + '@eslint/js': 9.21.0 + '@eslint/plugin-kit': 0.2.7 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.2 + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0 + escape-string-regexp: 4.0.0 + eslint-scope: 8.2.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + espree@10.3.0: + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 4.2.0 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.19.0: + dependencies: + reusify: 1.1.0 + + fdir@6.4.3(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + get-tsconfig@4.10.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + has-bigints@1.1.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + ignore@5.3.2: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + get-intrinsic: 1.3.0 + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.3 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + + is-bun-module@1.3.0: + dependencies: + semver: 7.7.1 + + is-callable@1.2.7: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.3 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.3 + + is-generator-function@1.1.0: + dependencies: + call-bound: 1.0.3 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-map@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.3 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.3 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.3 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.18 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.3 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.3 + get-intrinsic: 1.3.0 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lru-cache@10.4.3: {} + + math-intrinsics@1.1.0: {} + + media-query-parser@2.0.2: + dependencies: + '@babel/runtime': 7.26.9 + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + modern-ahocorasick@1.1.0: {} + + ms@2.1.3: {} + + natural-compare@1.4.0: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-object-atoms: 1.1.1 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.2: {} + + possible-typed-array-names@1.1.0: {} + + prelude-ls@1.2.1: {} + + prettier@3.5.2: {} + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regenerator-runtime@0.14.1: {} + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-regex: 1.2.1 + + semver@6.3.1: {} + + semver@7.7.1: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + stable-hash@0.0.4: {} + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + strip-bom@3.0.0: {} + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tapable@2.2.1: {} + + tinyglobby@0.2.12: + dependencies: + fdir: 6.4.3(picomatch@4.0.2) + picomatch: 4.0.2 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-api-utils@2.0.1(typescript@5.7.3): + dependencies: + typescript: 5.7.3 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript-eslint@8.25.0(eslint@9.21.0)(typescript@5.7.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.25.0(@typescript-eslint/parser@8.25.0(eslint@9.21.0)(typescript@5.7.3))(eslint@9.21.0)(typescript@5.7.3) + '@typescript-eslint/parser': 8.25.0(eslint@9.21.0)(typescript@5.7.3) + '@typescript-eslint/utils': 8.25.0(eslint@9.21.0)(typescript@5.7.3) + eslint: 9.21.0 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + typescript@5.7.3: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.3 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@6.19.8: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.3 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.0 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.18 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.18: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 + for-each: 0.3.5 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + yocto-queue@0.1.0: {} diff --git a/src/css-rules/alphabetical-order/index.ts b/src/css-rules/alphabetical-order/index.ts new file mode 100644 index 0000000..7821a4c --- /dev/null +++ b/src/css-rules/alphabetical-order/index.ts @@ -0,0 +1,3 @@ +import alphabeticalOrderRule from './rule-definition.js'; + +export default alphabeticalOrderRule; diff --git a/src/css-rules/alphabetical-order/property-order-enforcer.ts b/src/css-rules/alphabetical-order/property-order-enforcer.ts new file mode 100644 index 0000000..15dffd5 --- /dev/null +++ b/src/css-rules/alphabetical-order/property-order-enforcer.ts @@ -0,0 +1,84 @@ +import type { Rule } from 'eslint'; +import { TSESTree } from '@typescript-eslint/utils'; +import { generateFixesForCSSOrder } from '../shared-utils/css-order-fixer.js'; +import { getPropertyName } from '../shared-utils/property-separator.js'; + +/** + * Compares two CSS properties alphabetically. + * @param firstProperty The first property to compare. + * @param secondProperty The second property to compare. + * @returns A number indicating the relative order of the properties (-1, 0, or 1). + */ +const comparePropertiesAlphabetically = ( + firstProperty: TSESTree.Property, + secondProperty: TSESTree.Property, +): number => { + const firstName = getPropertyName(firstProperty); + const secondName = getPropertyName(secondProperty); + return firstName.localeCompare(secondName); +}; + +/** + * Reports an ordering issue to ESLint and generates fixes. + * @param ruleContext The ESLint rule context. + * @param currentProperty The current property in the order. + * @param nextProperty The next property that is out of order. + * @param regularProperties The full list of regular properties to be reordered. + */ +const reportOrderingIssue = ( + ruleContext: Rule.RuleContext, + currentProperty: TSESTree.Property, + nextProperty: TSESTree.Property, + regularProperties: TSESTree.Property[], +): void => { + ruleContext.report({ + node: nextProperty as Rule.Node, + messageId: 'alphabeticalOrder', + data: { + nextProperty: getPropertyName(nextProperty), + currentProperty: getPropertyName(currentProperty), + }, + fix: (fixer) => + generateFixesForCSSOrder( + fixer, + ruleContext, + regularProperties, + comparePropertiesAlphabetically, + (property) => property as Rule.Node, + ), + }); +}; + +/** + * Enforces alphabetical ordering of CSS properties. + * @param ruleContext The ESLint rule context. + * @param regularProperties An array of regular CSS properties to be checked. + * + * This function does the following: + * 1. Checks if there are enough properties to compare (more than 1). + * 2. Creates pairs of consecutive properties for comparison. + * 3. Finds the first pair that violates alphabetical order. + * 4. If a violation is found, reports the issue and generates fixes. + */ +export const enforceAlphabeticalCSSOrder = ( + ruleContext: Rule.RuleContext, + regularProperties: TSESTree.Property[], +): void => { + if (regularProperties.length <= 1) { + return; + } + + // Create pairs of consecutive properties + const propertyPairs = regularProperties.slice(0, -1).map((currentProperty, index) => ({ + currentProperty, + nextProperty: regularProperties[index + 1] as TSESTree.Property, + })); + + const violatingPair = propertyPairs.find( + ({ currentProperty, nextProperty }) => comparePropertiesAlphabetically(currentProperty, nextProperty) > 0, + ); + + if (violatingPair) { + reportOrderingIssue(ruleContext, violatingPair.currentProperty, violatingPair.nextProperty, regularProperties); + } +}; diff --git a/src/css-rules/alphabetical-order/recipe-order-enforcer.ts b/src/css-rules/alphabetical-order/recipe-order-enforcer.ts new file mode 100644 index 0000000..242e4f8 --- /dev/null +++ b/src/css-rules/alphabetical-order/recipe-order-enforcer.ts @@ -0,0 +1,28 @@ +import type { Rule } from 'eslint'; +import { TSESTree } from '@typescript-eslint/utils'; +import { processRecipeProperties } from '../shared-utils/recipe-property-processor.js'; +import { processStyleNode } from '../shared-utils/style-node-processor.js'; +import { enforceAlphabeticalCSSOrderInStyleObject } from './style-object-processor.js'; + +/** + * Enforces alphabetical ordering of CSS properties within a recipe function call. + * + * @param node The CallExpression node representing the recipe function call. + * @param context The ESLint rule context. + * + * This function does the following: + * 1. Checks if the first argument of the recipe function is an ObjectExpression. + * 2. If valid, processes the recipe object's properties. + * 3. For each relevant property (e.g., 'base', 'variants'), it applies alphabetical ordering to the CSS properties. + */ +export const enforceAlphabeticalCSSOrderInRecipe = (node: TSESTree.CallExpression, context: Rule.RuleContext): void => { + if (!node.arguments[0] || node.arguments[0].type !== 'ObjectExpression') { + return; + } + + const recipeObject = node.arguments[0]; + + processRecipeProperties(context, recipeObject, (context, object) => + processStyleNode(context, object, enforceAlphabeticalCSSOrderInStyleObject), + ); +}; diff --git a/src/css-rules/alphabetical-order/rule-definition.ts b/src/css-rules/alphabetical-order/rule-definition.ts new file mode 100644 index 0000000..a24ce8c --- /dev/null +++ b/src/css-rules/alphabetical-order/rule-definition.ts @@ -0,0 +1,23 @@ +import type { Rule } from 'eslint'; +import { createNodeVisitors } from '../shared-utils/order-strategy-visitor-creator.js'; + +const alphabeticalOrderRule: Rule.RuleModule = { + meta: { + type: 'suggestion', + docs: { + description: 'enforce alphabetical CSS property ordering in vanilla-extract styles', + category: 'Stylistic Issues', + recommended: true, + }, + fixable: 'code', + schema: [], + messages: { + alphabeticalOrder: "Property '{{next}}' should come before '{{current}}' in alphabetical order.", + }, + }, + create(context) { + return createNodeVisitors(context, 'alphabetical'); + }, +}; + +export default alphabeticalOrderRule; diff --git a/src/css-rules/alphabetical-order/style-object-processor.ts b/src/css-rules/alphabetical-order/style-object-processor.ts new file mode 100644 index 0000000..a59e63e --- /dev/null +++ b/src/css-rules/alphabetical-order/style-object-processor.ts @@ -0,0 +1,37 @@ +import type { Rule } from 'eslint'; +import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils'; +import { isSelectorsObject, processNestedSelectors } from '../shared-utils/nested-selectors-processor.js'; +import { separateProperties } from '../shared-utils/property-separator.js'; +import { enforceAlphabeticalCSSOrder } from './property-order-enforcer.js'; + +/** + * Processes a style object to enforce alphabetical ordering of CSS properties. + * + * This function handles different types of style objects: + * 1. If the object is invalid or not an ObjectExpression, it returns immediately. + * 2. For 'selectors' objects, it processes nested selectors recursively. + * 3. For regular style objects, it separates and enforces alphabetical order on properties. + * 4. It always processes nested objects recursively, regardless of type. + * + * @param ruleContext - The ESLint rule context for reporting and fixing issues. + * @param styleObject - The object expression representing the style object to be processed. + */ +export const enforceAlphabeticalCSSOrderInStyleObject = ( + ruleContext: Rule.RuleContext, + styleObject: TSESTree.ObjectExpression, +): void => { + if (!styleObject || styleObject.type !== AST_NODE_TYPES.ObjectExpression) { + return; + } + + if (isSelectorsObject(styleObject)) { + processNestedSelectors(ruleContext, styleObject, enforceAlphabeticalCSSOrderInStyleObject); + return; + } + + const { regularProperties } = separateProperties(styleObject.properties); + + enforceAlphabeticalCSSOrder(ruleContext, regularProperties); + + processNestedSelectors(ruleContext, styleObject, enforceAlphabeticalCSSOrderInStyleObject); +}; diff --git a/src/css-rules/concentric-order/concentric-groups.ts b/src/css-rules/concentric-order/concentric-groups.ts new file mode 100644 index 0000000..3b9b05f --- /dev/null +++ b/src/css-rules/concentric-order/concentric-groups.ts @@ -0,0 +1,336 @@ +// CSS property groups in order of importance (outside -> inside) +export const concentricGroups: { [key: string]: string[] } = { + boxSizing: ['all', 'box-sizing', 'aspect-ratio', 'contain'], + + position: [ + 'position', + 'z-index', + 'top', + 'right', + 'bottom', + 'left', + 'offset', + 'offset-path', + 'offset-distance', + 'offset-rotate', + 'inset', + 'inset-block', + 'inset-block-start', + 'inset-block-end', + 'inset-inline', + 'inset-inline-start', + 'inset-inline-end', + ], + + display: ['display', 'float', 'clear', 'isolation', 'appearance'], + + flex: ['flex', 'flex-basis', 'flex-direction', 'flex-flow', 'flex-grow', 'flex-shrink', 'flex-wrap'], + + grid: [ + 'grid', + 'grid-area', + 'grid-template', + 'grid-template-areas', + 'grid-template-rows', + 'grid-template-columns', + 'grid-row', + 'grid-row-start', + 'grid-row-end', + 'grid-column', + 'grid-column-start', + 'grid-column-end', + 'grid-auto-rows', + 'grid-auto-columns', + 'grid-auto-flow', + 'grid-gap', + 'grid-row-gap', + 'grid-column-gap', + ], + + alignment: [ + 'align-content', + 'align-items', + 'align-self', + 'justify-content', + 'justify-items', + 'justify-self', + 'place-content', + 'place-items', + 'place-self', + 'order', + 'gap', + 'row-gap', + 'column-gap', + ], + + columns: [ + 'columns', + 'column-fill', + 'column-rule', + 'column-rule-width', + 'column-rule-style', + 'column-rule-color', + 'column-span', + 'column-count', + 'column-width', + ], + + transform: [ + 'backface-visibility', + 'perspective', + 'perspective-origin', + 'transform', + 'transform-origin', + 'transform-style', + 'transform-box', + ], + + transitions: [ + 'transition', + 'transition-delay', + 'transition-duration', + 'transition-property', + 'transition-timing-function', + 'transition-behavior', + ], + + visibility: [ + 'visibility', + 'opacity', + 'backdrop-filter', + 'content-visibility', + 'filter', + 'mix-blend-mode', + 'will-change', + ], + + shape: ['clip-path', 'shape-outside', 'shape-image-threshold', 'shape-margin'], + + margin: [ + 'margin', + 'margin-top', + 'margin-right', + 'margin-bottom', + 'margin-left', + 'margin-block', + 'margin-block-start', + 'margin-block-end', + 'margin-inline', + 'margin-inline-start', + 'margin-inline-end', + 'margin-trim', + ], + + outline: ['outline', 'outline-offset', 'outline-width', 'outline-style', 'outline-color'], + + border: [ + 'border', + 'border-top', + 'border-right', + 'border-bottom', + 'border-left', + 'border-width', + 'border-top-width', + 'border-right-width', + 'border-bottom-width', + 'border-left-width', + 'border-style', + 'border-top-style', + 'border-right-style', + 'border-bottom-style', + 'border-left-style', + 'border-radius', + 'border-top-left-radius', + 'border-top-right-radius', + 'border-bottom-left-radius', + 'border-bottom-right-radius', + 'border-start-start-radius', + 'border-start-end-radius', + 'border-end-start-radius', + 'border-end-end-radius', + 'border-color', + 'border-top-color', + 'border-right-color', + 'border-bottom-color', + 'border-left-color', + 'border-image', + 'border-image-source', + 'border-image-width', + 'border-image-outset', + 'border-image-repeat', + 'border-image-slice', + 'border-block', + 'border-block-start', + 'border-block-end', + 'border-block-width', + 'border-block-style', + 'border-block-color', + 'border-inline', + 'border-inline-start', + 'border-inline-end', + 'border-inline-width', + 'border-inline-style', + 'border-inline-color', + ], + + boxShadow: ['box-shadow'], + + background: [ + 'background', + 'background-attachment', + 'background-clip', + 'background-color', + 'background-image', + 'background-origin', + 'background-position', + 'background-repeat', + 'background-size', + 'background-blend-mode', + 'object-fit', + 'object-position', + 'image-orientation', + 'image-rendering', + ], + + cursor: ['cursor', 'pointer-events', 'touch-action'], + + padding: [ + 'padding', + 'padding-top', + 'padding-right', + 'padding-bottom', + 'padding-left', + 'padding-block', + 'padding-block-start', + 'padding-block-end', + 'padding-inline', + 'padding-inline-start', + 'padding-inline-end', + ], + + dimensions: [ + 'width', + 'min-width', + 'max-width', + 'height', + 'min-height', + 'max-height', + 'block-size', + 'min-block-size', + 'max-block-size', + 'inline-size', + 'min-inline-size', + 'max-inline-size', + ], + + overflow: [ + 'overflow', + 'overflow-x', + 'overflow-y', + 'overflow-block', + 'overflow-inline', + 'overflow-clip-margin', + 'overflow-anchor', + 'overflow-wrap', + 'overscroll-behavior', + 'overscroll-behavior-x', + 'overscroll-behavior-y', + 'resize', + 'scrollbar-width', + 'scrollbar-color', + 'scrollbar-gutter', + 'scroll-behavior', + 'scroll-margin', + 'scroll-padding', + 'scroll-snap-align', + 'scroll-snap-stop', + 'scroll-snap-type', + ], + + listStyle: ['list-style', 'list-style-type', 'list-style-position', 'list-style-image', 'caption-side'], + + tables: ['table-layout', 'border-collapse', 'border-spacing', 'empty-cells'], + + animation: [ + 'animation', + 'animation-name', + 'animation-duration', + 'animation-timing-function', + 'animation-delay', + 'animation-iteration-count', + 'animation-direction', + 'animation-fill-mode', + 'animation-play-state', + ], + + text: [ + 'vertical-align', + 'direction', + 'writing-mode', + 'text-orientation', + 'unicode-bidi', + 'tab-size', + 'text-align', + 'text-align-last', + 'text-justify', + 'text-indent', + 'text-transform', + 'text-decoration', + 'text-decoration-color', + 'text-decoration-line', + 'text-decoration-style', + 'text-decoration-thickness', + 'text-decoration-skip-ink', + 'text-underline-position', + 'text-rendering', + 'text-shadow', + 'text-overflow', + 'text-wrap', + 'text-size-adjust', + 'text-combine-upright', + 'hyphens', + 'line-break', + 'ruby-position', + 'caret-color', + 'user-select', + ], + + textSpacing: [ + 'line-height', + 'word-spacing', + 'letter-spacing', + 'white-space', + 'word-break', + 'word-wrap', + 'orphans', + 'widows', + 'color', + ], + + font: [ + 'font', + 'font-family', + 'font-size', + 'font-size-adjust', + 'font-stretch', + 'font-weight', + 'font-smoothing', + 'osx-font-smoothing', + 'font-variant', + 'font-style', + 'font-feature-settings', + 'font-kerning', + 'font-optical-sizing', + ], + + content: ['content', 'quotes'], + + counters: ['counter-reset', 'counter-increment', 'counter-set'], + + breaks: ['page-break-before', 'page-break-after', 'page-break-inside', 'break-before', 'break-after', 'break-inside'], +}; + +/** + * Export all available groups for use in custom groups rule + */ +export const availableGroups = Object.keys(concentricGroups); diff --git a/src/css-rules/concentric-order/index.ts b/src/css-rules/concentric-order/index.ts new file mode 100644 index 0000000..7c6ca1d --- /dev/null +++ b/src/css-rules/concentric-order/index.ts @@ -0,0 +1,3 @@ +import concentricOrderRule from './rule-definition.js'; + +export default concentricOrderRule; diff --git a/src/css-rules/concentric-order/property-order-enforcer.ts b/src/css-rules/concentric-order/property-order-enforcer.ts new file mode 100644 index 0000000..2105116 --- /dev/null +++ b/src/css-rules/concentric-order/property-order-enforcer.ts @@ -0,0 +1,85 @@ +import type { Rule } from 'eslint'; +import { generateFixesForCSSOrder } from '../shared-utils/css-order-fixer.js'; +import type { CSSPropertyInfo } from './types.js'; + +/** + * Reports a violation of the concentric CSS ordering rule and generates fixes. + * + * @param ruleContext The ESLint rule context used for reporting and fixing. + * @param currentProperty The current property in the order. + * @param nextProperty The next property that is out of order. + * @param cssPropertyInfoList The full list of CSS properties to be reordered. + */ +const reportOrderingIssue = ( + ruleContext: Rule.RuleContext, + currentProperty: CSSPropertyInfo, + nextProperty: CSSPropertyInfo, + cssPropertyInfoList: CSSPropertyInfo[], +): void => { + ruleContext.report({ + node: nextProperty.node as Rule.Node, + messageId: 'incorrectOrder', + data: { + next: nextProperty.name, + current: currentProperty.name, + }, + fix: (fixer) => + generateFixesForCSSOrder( + fixer, + ruleContext, + cssPropertyInfoList, + compareProperties, + (propertyInfo) => propertyInfo.node as Rule.Node, + ), + }); +}; + +/** + * Compares two CSS properties based on their priority and position within their group. + * + * @param firstProperty The first property to compare. + * @param secondProperty The second property to compare. + * @returns A number indicating the relative order of the properties (-1, 0, or 1). + */ +const compareProperties = (firstProperty: CSSPropertyInfo, secondProperty: CSSPropertyInfo): number => { + if (firstProperty.priority !== secondProperty.priority) { + return firstProperty.priority - secondProperty.priority; + } + return firstProperty.positionInGroup - secondProperty.positionInGroup; +}; + +/** + * Enforces concentric ordering of CSS properties. + * + * This function checks the order of CSS properties to ensure they follow a concentric order + * based on their priority and position within their group. It performs the following steps: + * 1. Validates if there are enough properties to compare. + * 2. Creates pairs of consecutive properties for comparison. + * 3. Identifies the first pair that violates the concentric order. + * 4. If a violation is detected, reports the issue and suggests fixes using ESLint. + * + * @param ruleContext - The ESLint rule context used for reporting and fixing. + * @param cssPropertyInfoList - An array of CSS property information objects to be checked. + */ +export const enforceConcentricCSSOrder = ( + ruleContext: Rule.RuleContext, + cssPropertyInfoList: CSSPropertyInfo[], +): void => { + if (cssPropertyInfoList.length <= 1) { + return; + } + + // Create pairs of consecutive properties + const propertyPairs = cssPropertyInfoList.slice(0, -1).map((currentProperty, index) => ({ + currentProperty, + nextProperty: cssPropertyInfoList[index + 1] as CSSPropertyInfo, + })); + + const violatingPair = propertyPairs.find( + ({ currentProperty, nextProperty }) => compareProperties(currentProperty, nextProperty) > 0, + ); + + if (violatingPair) { + reportOrderingIssue(ruleContext, violatingPair.currentProperty, violatingPair.nextProperty, cssPropertyInfoList); + } +}; diff --git a/src/css-rules/concentric-order/recipe-order-enforcer.ts b/src/css-rules/concentric-order/recipe-order-enforcer.ts new file mode 100644 index 0000000..9d21ccd --- /dev/null +++ b/src/css-rules/concentric-order/recipe-order-enforcer.ts @@ -0,0 +1,31 @@ +import type { Rule } from 'eslint'; +import { TSESTree } from '@typescript-eslint/utils'; +import { processRecipeProperties } from '../shared-utils/recipe-property-processor.js'; +import { processStyleNode } from '../shared-utils/style-node-processor.js'; +import { enforceConcentricCSSOrderInStyleObject } from './style-object-processor.js'; + +/** + * Enforces concentric ordering of CSS properties within a recipe function call. + * + * @param ruleContext The ESLint rule context for reporting and fixing issues. + * @param callExpression The CallExpression node representing the recipe function call. + * + * This function does the following: + * 1. Checks if the first argument of the recipe function is an ObjectExpression. + * 2. If valid, processes the recipe object's properties. + * 3. For each relevant property (e.g., 'base', 'variants'), it applies concentric ordering to the CSS properties. + */ +export const enforceConcentricCSSOrderInRecipe = ( + ruleContext: Rule.RuleContext, + callExpression: TSESTree.CallExpression, +): void => { + if (!callExpression.arguments[0] || callExpression.arguments[0].type !== 'ObjectExpression') { + return; + } + + const recipeObjectExpression = callExpression.arguments[0]; + + processRecipeProperties(ruleContext, recipeObjectExpression, (currentContext, styleObject) => + processStyleNode(currentContext, styleObject, enforceConcentricCSSOrderInStyleObject), + ); +}; diff --git a/src/css-rules/concentric-order/rule-definition.ts b/src/css-rules/concentric-order/rule-definition.ts new file mode 100644 index 0000000..88de724 --- /dev/null +++ b/src/css-rules/concentric-order/rule-definition.ts @@ -0,0 +1,23 @@ +import type { Rule } from 'eslint'; +import { createNodeVisitors } from '../shared-utils/order-strategy-visitor-creator.js'; + +const concentricOrderRule: Rule.RuleModule = { + meta: { + type: 'suggestion', + docs: { + description: 'enforce concentric CSS property ordering in vanilla-extract styles', + category: 'Stylistic Issues', + recommended: true, + }, + fixable: 'code', + schema: [], + messages: { + incorrectOrder: "Property '{{next}}' should come before '{{current}}' according to concentric CSS ordering.", + }, + }, + create(context) { + return createNodeVisitors(context, 'concentric'); + }, +}; + +export default concentricOrderRule; diff --git a/src/css-rules/concentric-order/style-object-processor.ts b/src/css-rules/concentric-order/style-object-processor.ts new file mode 100644 index 0000000..4b9e69b --- /dev/null +++ b/src/css-rules/concentric-order/style-object-processor.ts @@ -0,0 +1,72 @@ +import type { Rule } from 'eslint'; +import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils'; +import { createCSSPropertyPriorityMap } from '../shared-utils/css-property-priority-map.js'; +import { isSelectorsObject, processNestedSelectors } from '../shared-utils/nested-selectors-processor.js'; +import { getPropertyName, separateProperties } from '../shared-utils/property-separator.js'; +import { enforceConcentricCSSOrder } from './property-order-enforcer.js'; +import type { CSSPropertyInfo } from './types.js'; + +const cssPropertyPriorityMap = createCSSPropertyPriorityMap(); + +/** + * Builds a list of CSS properties with their priority information in the concentric order of their groups. + * + * @param regularStyleProperties An array of regular style properties. + * @returns An array of CSSPropertyInfo objects containing name, node, priority, and position information. + */ +const buildCSSPropertyInfoList = (regularStyleProperties: TSESTree.Property[]): CSSPropertyInfo[] => { + return regularStyleProperties.map((styleProperty) => { + const propertyName = getPropertyName(styleProperty); + const propertyInfo = cssPropertyPriorityMap.get(propertyName); + + return { + name: propertyName, + node: styleProperty, + priority: propertyInfo?.groupIndex ?? Number.MAX_SAFE_INTEGER, + positionInGroup: propertyInfo?.positionInGroup ?? Number.MAX_SAFE_INTEGER, + }; + }); +}; + +/** + * Enforces concentric ordering of CSS properties within a style object. + * + * This function processes the given style object to ensure that CSS properties + * follow a concentric order based on predefined priority groups. It handles + * different types of style objects by: + * 1. Validating that the input is an ObjectExpression. + * 2. Processing 'selectors' objects separately and recursively applying the + * concentric order enforcement. + * 3. Separating regular properties and building a list of CSSPropertyInfo + * objects with priority details. + * 4. Enforcing concentric order on the properties using their priority + * information. + * 5. Recursively processing nested selectors and style objects. + * + * @param ruleContext - The ESLint rule context for reporting and fixing issues. + * @param styleObject - The object expression representing the style object to be processed. + */ +export const enforceConcentricCSSOrderInStyleObject = ( + ruleContext: Rule.RuleContext, + styleObject: TSESTree.ObjectExpression, +): void => { + if (!styleObject || styleObject.type !== AST_NODE_TYPES.ObjectExpression) { + return; + } + + if (isSelectorsObject(styleObject)) { + styleObject.properties.forEach((property) => { + if (property.type === AST_NODE_TYPES.Property && property.value.type === AST_NODE_TYPES.ObjectExpression) { + enforceConcentricCSSOrderInStyleObject(ruleContext, property.value); + } + }); + return; + } + + const { regularProperties } = separateProperties(styleObject.properties); + const cssPropertyInfoList = buildCSSPropertyInfoList(regularProperties); + + enforceConcentricCSSOrder(ruleContext, cssPropertyInfoList); + + processNestedSelectors(ruleContext, styleObject, enforceConcentricCSSOrderInStyleObject); +}; diff --git a/src/css-rules/concentric-order/types.ts b/src/css-rules/concentric-order/types.ts new file mode 100644 index 0000000..2424f9a --- /dev/null +++ b/src/css-rules/concentric-order/types.ts @@ -0,0 +1,9 @@ +import { TSESTree } from '@typescript-eslint/utils'; + +export interface CSSPropertyInfo { + name: string; + node: TSESTree.Property; + priority: number; + positionInGroup: number; + group?: string; +} diff --git a/src/css-rules/custom-order/property-order-enforcer.ts b/src/css-rules/custom-order/property-order-enforcer.ts new file mode 100644 index 0000000..52e636a --- /dev/null +++ b/src/css-rules/custom-order/property-order-enforcer.ts @@ -0,0 +1,91 @@ +import type { Rule } from 'eslint'; +import { generateFixesForCSSOrder } from '../shared-utils/css-order-fixer.js'; +import { createCSSPropertyPriorityMap } from '../shared-utils/css-property-priority-map.js'; +import type { CSSPropertyInfo } from '../concentric-order/types.js'; + +/** + * Enforces a custom ordering of CSS properties based on user-defined groups. + * + * @param ruleContext The ESLint rule context used for reporting and fixing. + * @param cssPropertyInfoList An array of CSS property information objects to be ordered. + * @param userDefinedGroups Array of user-defined property groups for custom ordering. + * @param sortRemainingProperties Strategy for sorting properties not in user-defined groups + * ('alphabetical' or 'concentric'). Defaults to 'concentric'. + * + * This function compares CSS properties based on their group priority and position within + * those groups. Properties not part of user-defined groups are sorted according to the + * specified strategy. If an ordering violation is detected, an ESLint report is generated + * with a suggested fix. + */ +export const enforceCustomGroupOrder = ( + ruleContext: Rule.RuleContext, + cssPropertyInfoList: CSSPropertyInfo[], + userDefinedGroups: string[] = [], + sortRemainingProperties?: 'alphabetical' | 'concentric', +): void => { + if (cssPropertyInfoList.length <= 1) { + return; + } + + const cssPropertyPriorityMap = createCSSPropertyPriorityMap(userDefinedGroups); + + const compareProperties = (firstProperty: CSSPropertyInfo, secondProperty: CSSPropertyInfo) => { + const firstPropertyInfo = cssPropertyPriorityMap.get(firstProperty.name) || { + groupIndex: Infinity, + positionInGroup: Infinity, + inUserGroup: false, + }; + const secondPropertyInfo = cssPropertyPriorityMap.get(secondProperty.name) || { + groupIndex: Infinity, + positionInGroup: Infinity, + inUserGroup: false, + }; + + if (firstPropertyInfo.inUserGroup !== secondPropertyInfo.inUserGroup) { + return firstPropertyInfo.inUserGroup ? -1 : 1; + } + + if (firstPropertyInfo.inUserGroup) { + if (firstPropertyInfo.groupIndex !== secondPropertyInfo.groupIndex) { + return firstPropertyInfo.groupIndex - secondPropertyInfo.groupIndex; + } + return firstPropertyInfo.positionInGroup - secondPropertyInfo.positionInGroup; + } + + // For properties not in user-defined groups + if (sortRemainingProperties === 'alphabetical') { + return firstProperty.name.localeCompare(secondProperty.name); + } else { + return ( + firstPropertyInfo.groupIndex - secondPropertyInfo.groupIndex || + firstPropertyInfo.positionInGroup - secondPropertyInfo.positionInGroup + ); + } + }; + + const sortedPropertyList = [...cssPropertyInfoList].sort(compareProperties); + + // Find the first pair that violates the new ordering + const violatingProperty = cssPropertyInfoList + .slice(0, -1) + .find((currentProperty, index) => currentProperty.name !== sortedPropertyList[index]?.name); + + if (violatingProperty) { + ruleContext.report({ + node: violatingProperty.node as Rule.Node, + messageId: 'incorrectOrder', + data: { + currentProperty: violatingProperty.name, + nextProperty: sortedPropertyList[cssPropertyInfoList.indexOf(violatingProperty)]?.name || '', + }, + fix: (fixer) => + generateFixesForCSSOrder( + fixer, + ruleContext, + cssPropertyInfoList, + compareProperties, + (propertyInfo) => propertyInfo.node as Rule.Node, + ), + }); + } +}; diff --git a/src/css-rules/custom-order/recipe-order-enforcer.ts b/src/css-rules/custom-order/recipe-order-enforcer.ts new file mode 100644 index 0000000..c34c7c9 --- /dev/null +++ b/src/css-rules/custom-order/recipe-order-enforcer.ts @@ -0,0 +1,42 @@ +import type { Rule } from 'eslint'; +import { TSESTree } from '@typescript-eslint/utils'; +import { processRecipeProperties } from '../shared-utils/recipe-property-processor.js'; +import { processStyleNode } from '../shared-utils/style-node-processor.js'; +import { enforceUserDefinedGroupOrderInStyleObject } from './style-object-processor.js'; + +/** + * Enforces custom group ordering of CSS properties within a recipe function call. + * + * @param ruleContext The ESLint rule context for reporting and fixing issues. + * @param callExpression The CallExpression node representing the recipe function call. + * @param userDefinedGroups An array of property groups in the desired order. + * + * This function does the following: + * 1. Validates that the first argument of the recipe function is an ObjectExpression. + * 2. Processes the recipe object's properties if valid. + * 3. Applies custom group ordering to CSS properties in relevant properties (e.g., 'base', 'variants'). + * 4. Processes nested selectors and style objects recursively. + */ +export const enforceUserDefinedGroupOrderInRecipe = ( + ruleContext: Rule.RuleContext, + callExpression: TSESTree.CallExpression, + userDefinedGroups: string[], + sortRemainingPropertiesMethod?: 'alphabetical' | 'concentric', +): void => { + if (!callExpression.arguments[0] || callExpression.arguments[0].type !== 'ObjectExpression') { + return; + } + + const recipeObjectExpression = callExpression.arguments[0]; + + processRecipeProperties(ruleContext, recipeObjectExpression, (currentContext, styleObject) => + processStyleNode(currentContext, styleObject, (styleContext, styleObjectNode) => + enforceUserDefinedGroupOrderInStyleObject( + styleContext, + styleObjectNode, + userDefinedGroups, + sortRemainingPropertiesMethod, + ), + ), + ); +}; diff --git a/src/css-rules/custom-order/rule-definition.ts b/src/css-rules/custom-order/rule-definition.ts new file mode 100644 index 0000000..5fac6e2 --- /dev/null +++ b/src/css-rules/custom-order/rule-definition.ts @@ -0,0 +1,55 @@ +import type { Rule } from 'eslint'; +import { availableGroups } from '../concentric-order/concentric-groups.js'; +import { createNodeVisitors } from '../shared-utils/order-strategy-visitor-creator.js'; + +interface CustomGroupRuleConfiguration { + groupOrder?: string[]; + sortRemainingProperties: 'alphabetical' | 'concentric'; +} + +const customGroupOrderRule: Rule.RuleModule = { + meta: { + type: 'suggestion', + docs: { + description: 'enforce custom group CSS property ordering in vanilla-extract styles', + category: 'Stylistic Issues', + recommended: true, + }, + fixable: 'code', + schema: [ + { + type: 'object', + properties: { + groupOrder: { + type: 'array', + items: { + enum: availableGroups, + }, + }, + sortRemainingProperties: { + enum: ['alphabetical', 'concentric'], + }, + }, + additionalProperties: false, + }, + ], + messages: { + incorrectOrder: + "Property '{{nextProperty}}' should come before '{{currentProperty}}' according to custom CSS group ordering.", + }, + }, + create(ruleContext: Rule.RuleContext) { + const ruleConfiguration = ruleContext.options[0] as CustomGroupRuleConfiguration; + const userDefinedGroupOrder = ruleConfiguration?.groupOrder ?? []; + const sortRemainingPropertiesMethod = ruleConfiguration?.sortRemainingProperties ?? 'alphabetical'; + + return createNodeVisitors( + ruleContext, + 'userDefinedGroupOrder', + userDefinedGroupOrder, + sortRemainingPropertiesMethod, + ); + }, +}; + +export default customGroupOrderRule; diff --git a/src/css-rules/custom-order/style-object-processor.ts b/src/css-rules/custom-order/style-object-processor.ts new file mode 100644 index 0000000..25884a4 --- /dev/null +++ b/src/css-rules/custom-order/style-object-processor.ts @@ -0,0 +1,79 @@ +import type { Rule } from 'eslint'; +import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils'; +import { concentricGroups } from '../concentric-order/concentric-groups.js'; +import { createCSSPropertyPriorityMap } from '../shared-utils/css-property-priority-map.js'; +import { isSelectorsObject, processNestedSelectors } from '../shared-utils/nested-selectors-processor.js'; +import { getPropertyName, separateProperties } from '../shared-utils/property-separator.js'; +import { enforceCustomGroupOrder } from './property-order-enforcer.js'; +import type { CSSPropertyInfo } from '../concentric-order/types.js'; + +/** + * Enforces a custom ordering of CSS properties based on user-defined groups in a given style object. + * + * @param context The ESLint rule context for reporting and fixing issues. + * @param styleObject The ObjectExpression node representing the style object to be processed. + * @param userDefinedGroups An array of property groups in the desired order. + * @param sortRemainingPropertiesMethod Strategy for sorting properties not in user-defined groups ('alphabetical' or 'concentric'). Defaults to 'concentric'. + * + * This function: + * 1. Validates the input styleObject. + * 2. Handles 'selectors' objects separately, processing their nested style objects. + * 3. Creates a priority map based on user-defined groups. + * 4. Processes regular properties, creating a list of CSSPropertyInfo objects. + * 5. Enforces custom group ordering on the properties. + * 6. Recursively processes nested selectors and style objects. + */ +export const enforceUserDefinedGroupOrderInStyleObject = ( + ruleContext: Rule.RuleContext, + styleObject: TSESTree.ObjectExpression, + userDefinedGroups: string[], + sortRemainingPropertiesMethod: 'alphabetical' | 'concentric' = 'concentric', +): void => { + if (!styleObject || styleObject.type !== AST_NODE_TYPES.ObjectExpression) { + return; + } + + if (isSelectorsObject(styleObject)) { + styleObject.properties.forEach((property) => { + if (property.type === AST_NODE_TYPES.Property && property.value.type === AST_NODE_TYPES.ObjectExpression) { + enforceUserDefinedGroupOrderInStyleObject( + ruleContext, + property.value, + userDefinedGroups, + sortRemainingPropertiesMethod, + ); + } + }); + return; + } + + const cssPropertyPriorityMap = createCSSPropertyPriorityMap(userDefinedGroups); + + const { regularProperties } = separateProperties(styleObject.properties); + const cssPropertyInfoList: CSSPropertyInfo[] = regularProperties.map((property) => { + const propertyName = getPropertyName(property); + const propertyInfo = cssPropertyPriorityMap.get(propertyName); + const group = + userDefinedGroups.find((groupName) => concentricGroups[groupName]?.includes(propertyName)) || 'remaining'; + + return { + name: propertyName, + node: property, + priority: propertyInfo?.groupIndex ?? Number.MAX_SAFE_INTEGER, + positionInGroup: propertyInfo?.positionInGroup ?? Number.MAX_SAFE_INTEGER, + group, + inUserGroup: propertyInfo?.inUserGroup ?? false, + }; + }); + + enforceCustomGroupOrder(ruleContext, cssPropertyInfoList, userDefinedGroups, sortRemainingPropertiesMethod); + + processNestedSelectors(ruleContext, styleObject, (nestedContext, nestedNode) => + enforceUserDefinedGroupOrderInStyleObject( + nestedContext, + nestedNode, + userDefinedGroups, + sortRemainingPropertiesMethod, + ), + ); +}; diff --git a/src/css-rules/shared-utils/css-order-fixer.ts b/src/css-rules/shared-utils/css-order-fixer.ts new file mode 100644 index 0000000..aea6f72 --- /dev/null +++ b/src/css-rules/shared-utils/css-order-fixer.ts @@ -0,0 +1,55 @@ +import type { Rule, SourceCode } from 'eslint'; + +/** + * Generates ESLint fixes for CSS property ordering violations. + * @param eslintFixer The ESLint fixer instance used to create fix objects. + * @param ruleContext The ESLint rule context, providing access to the source code. + * @param cssProperties The list of CSS properties to sort (can be TSESTree.Property[] or CSSPropertyInfo[]). + * @param compareProperties A comparison function that defines the sorting logic for the properties. + * @param extractNode A function that extracts the AST node from each property (used for text replacement). + * @returns An array of ESLint Fix objects to correct the property order. + * + * This function performs the following steps: + * 1. Sorts the input properties using the provided comparison function. + * 2. Maps the original and sorted properties to their text ranges. + * 3. Creates fix objects for properties whose positions have changed after sorting. + * 4. Returns an array of fixes that, when applied, will reorder the properties correctly. + */ +export const generateFixesForCSSOrder = ( + eslintFixer: Rule.RuleFixer, + ruleContext: Rule.RuleContext, + cssProperties: T[], + compareProperties: (firstProperty: T, secondProperty: T) => number, + extractNode: (property: T) => Rule.Node, +): Rule.Fix[] => { + const sourceCode: SourceCode = ruleContext.sourceCode; + + // Sort properties using the provided comparison function + const sortedProperties = [...cssProperties].sort(compareProperties); + + // Map each original property to its text range + const originalPropertyRanges = cssProperties.map((property) => ({ + property, + range: extractNode(property).range, + })); + + // Map sorted properties back to their original range information + const sortedPropertyRanges = sortedProperties.map((property) => + originalPropertyRanges.find((rangeInfo) => rangeInfo.property === property), + ); + + // Generate fixes for properties that have changed position + return originalPropertyRanges + .map((originalRangeInfo, index) => { + const sortedRangeInfo = sortedPropertyRanges[index]; + + // Create a fix only if the property's position has changed + if (originalRangeInfo && sortedRangeInfo && originalRangeInfo !== sortedRangeInfo) { + const sortedPropertyText = sourceCode.getText(extractNode(sortedRangeInfo.property)); + return eslintFixer.replaceText(extractNode(originalRangeInfo.property), sortedPropertyText); + } + + return null; + }) + .filter((fix): fix is Rule.Fix => fix !== null); +}; diff --git a/src/css-rules/shared-utils/css-property-priority-map.ts b/src/css-rules/shared-utils/css-property-priority-map.ts new file mode 100644 index 0000000..83ff471 --- /dev/null +++ b/src/css-rules/shared-utils/css-property-priority-map.ts @@ -0,0 +1,60 @@ +import { concentricGroups } from '../concentric-order/concentric-groups.js'; + +/** + * Creates a map of CSS properties to their priority information. + * + * This function generates a Map where each key is a CSS property (in camelCase), + * and each value is an object containing: + * - groupIndex: The index of the property's group + * - positionInGroup: The position of the property within its group + * - inUserGroup: Whether the property is in a user-specified group + * + * The function prioritizes user-specified groups over default concentric groups. + * If user groups are provided, they are processed first. Any remaining concentric + * groups are then processed to ensure complete coverage of CSS properties. + * + * @param userGroups - An optional array of user-specified group names to prioritize + * @returns A Map of CSS properties to their priority information + * + * @example + * const priorityMap = createCSSPropertyPriorityMap(['layout', 'typography']); + * console.log(priorityMap.get('display')); // { groupIndex: 0, positionInGroup: 0, inUserGroup: true } + */ +export const createCSSPropertyPriorityMap = (userGroups: string[] = []) => { + const cssPropertyPriorityMap = new Map< + string, + { + groupIndex: number; + positionInGroup: number; + inUserGroup: boolean; + } + >(); + + const processGroup = (groupName: string, groupIndex: number, inUserGroup: boolean) => { + const properties = concentricGroups[groupName] || []; + properties.forEach((property, positionInGroup) => { + const camelCaseProperty = property.replace(/-([a-z])/g, (_, letter: string) => letter.toUpperCase()); + if (!cssPropertyPriorityMap.has(camelCaseProperty)) { + cssPropertyPriorityMap.set(camelCaseProperty, { + groupIndex, + positionInGroup, + inUserGroup, + }); + } + }); + }; + + // Process user-specified groups first + userGroups.forEach((groupName, index) => processGroup(groupName, index, true)); + + // Process remaining groups if needed (for concentric order or as fallback) + if (userGroups.length === 0 || userGroups.length < Object.keys(concentricGroups).length) { + Object.keys(concentricGroups).forEach((groupName, index) => { + if (!userGroups.includes(groupName)) { + processGroup(groupName, userGroups.length + index, false); + } + }); + } + + return cssPropertyPriorityMap; +}; diff --git a/src/css-rules/shared-utils/nested-selectors-processor.ts b/src/css-rules/shared-utils/nested-selectors-processor.ts new file mode 100644 index 0000000..0ac07a0 --- /dev/null +++ b/src/css-rules/shared-utils/nested-selectors-processor.ts @@ -0,0 +1,44 @@ +import type { Rule } from 'eslint'; +import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils'; + +/** + * Determines if the given object node is a 'selectors' object within a style definition. + * @param objectNode The object expression node to check. + * @returns True if the node is a 'selectors' object, false otherwise. + * + * This function checks if: + * 1. The node has a parent + * 2. The parent is a Property node + * 3. The parent's key is an Identifier + * 4. The parent's key name is 'selectors' + */ +export const isSelectorsObject = (objectNode: TSESTree.ObjectExpression): boolean => { + return ( + objectNode.parent && + objectNode.parent.type === AST_NODE_TYPES.Property && + objectNode.parent.key.type === 'Identifier' && + objectNode.parent.key.name === 'selectors' + ); +}; + +/** + * Processes nested selectors within a 'selectors' object by recursively validating their value objects. + * @param context The ESLint rule context. + * @param objectNode The object expression node representing the 'selectors' object. + * @param validateFn A function to validate each nested selector's value object. + * + * This function iterates through each property of the 'selectors' object: + * - If a property's value is an ObjectExpression, it applies the validateFn to that object. + * - This allows for validation of nested style objects within selectors. + */ +export const processNestedSelectors = ( + context: Rule.RuleContext, + objectNode: TSESTree.ObjectExpression, + validateFn: (context: Rule.RuleContext, objectNode: TSESTree.ObjectExpression) => void, +): void => { + objectNode.properties.forEach((property) => { + if (property.type === AST_NODE_TYPES.Property && property.value.type === AST_NODE_TYPES.ObjectExpression) { + validateFn(context, property.value); + } + }); +}; diff --git a/src/css-rules/shared-utils/order-strategy-visitor-creator.ts b/src/css-rules/shared-utils/order-strategy-visitor-creator.ts new file mode 100644 index 0000000..781ecfd --- /dev/null +++ b/src/css-rules/shared-utils/order-strategy-visitor-creator.ts @@ -0,0 +1,98 @@ +import type { Rule } from 'eslint'; +import { TSESTree } from '@typescript-eslint/utils'; +import { enforceAlphabeticalCSSOrderInRecipe } from '../alphabetical-order/recipe-order-enforcer.js'; +import { enforceAlphabeticalCSSOrderInStyleObject } from '../alphabetical-order/style-object-processor.js'; +import { enforceConcentricCSSOrderInRecipe } from '../concentric-order/recipe-order-enforcer.js'; +import { enforceConcentricCSSOrderInStyleObject } from '../concentric-order/style-object-processor.js'; +import { enforceUserDefinedGroupOrderInRecipe } from '../custom-order/recipe-order-enforcer.js'; +import { enforceUserDefinedGroupOrderInStyleObject } from '../custom-order/style-object-processor.js'; +import { processStyleNode } from './style-node-processor.js'; + +/** + * Creates an ESLint rule listener with visitors for style-related function calls. + * @param ruleContext The ESLint rule context. + * @param orderingStrategy The strategy to use for ordering CSS properties ('alphabetical', 'concentric', or 'userDefinedGroupOrder'). + * @param userDefinedGroupOrder An optional array of property groups for the 'userDefinedGroupOrder' strategy. + * @param sortRemainingProperties An optional strategy for sorting properties not in user-defined groups. + * @returns An object with visitor functions for the ESLint rule. + * + * This function sets up visitors for the following cases: + * 1. Style-related functions: 'style', 'styleVariants', 'createVar', 'createTheme', 'createThemeContract' + * 2. The 'globalStyle' function + * 3. The 'recipe' function + * + * Each visitor applies the appropriate ordering strategy to the style objects in these function calls. + */ +export const createNodeVisitors = ( + ruleContext: Rule.RuleContext, + orderingStrategy: 'alphabetical' | 'concentric' | 'userDefinedGroupOrder', + userDefinedGroupOrder?: string[], + sortRemainingProperties?: 'alphabetical' | 'concentric', +): Rule.RuleListener => { + // Select the appropriate property processing function based on the ordering strategy + const processProperty = (() => { + switch (orderingStrategy) { + case 'alphabetical': + return enforceAlphabeticalCSSOrderInStyleObject; + case 'concentric': + return enforceConcentricCSSOrderInStyleObject; + case 'userDefinedGroupOrder': + if (!userDefinedGroupOrder || userDefinedGroupOrder.length === 0) { + throw new Error('💥 👿 User-defined group order must be provided for userDefinedGroupOrder strategy'); + } + return (ruleContext: Rule.RuleContext, node: TSESTree.Node) => + enforceUserDefinedGroupOrderInStyleObject( + ruleContext, + node as TSESTree.ObjectExpression, + userDefinedGroupOrder, + sortRemainingProperties, + ); + default: + return enforceAlphabeticalCSSOrderInStyleObject; + } + })(); + + return { + CallExpression(node) { + if (node.callee.type !== 'Identifier') { + return; + } + + // Handle style-related functions + if (['style', 'styleVariants', 'createVar', 'createTheme', 'createThemeContract'].includes(node.callee.name)) { + if (node.arguments.length > 0) { + const styleArg = node.arguments[0]; + processStyleNode(ruleContext, styleArg as TSESTree.Node, processProperty); + } + } + + // Handle globalStyle function + if (node.callee.name === 'globalStyle' && node.arguments.length >= 2) { + const styleArg = node.arguments[1]; + processStyleNode(ruleContext, styleArg as TSESTree.Node, processProperty); + } + + // Handle recipe function + if (node.callee.name === 'recipe') { + switch (orderingStrategy) { + case 'alphabetical': + enforceAlphabeticalCSSOrderInRecipe(node as TSESTree.CallExpression, ruleContext); + break; + case 'concentric': + enforceConcentricCSSOrderInRecipe(ruleContext, node as TSESTree.CallExpression); + break; + case 'userDefinedGroupOrder': + if (userDefinedGroupOrder) { + enforceUserDefinedGroupOrderInRecipe( + ruleContext, + node as TSESTree.CallExpression, + userDefinedGroupOrder, + sortRemainingProperties, + ); + } + break; + } + } + }, + }; +}; diff --git a/src/css-rules/shared-utils/property-separator.ts b/src/css-rules/shared-utils/property-separator.ts new file mode 100644 index 0000000..8259080 --- /dev/null +++ b/src/css-rules/shared-utils/property-separator.ts @@ -0,0 +1,57 @@ +import { TSESTree } from '@typescript-eslint/utils'; + +/** + * Extracts the name of a property from a TSESTree.Property node. + * @param property The property node to extract the name from. + * @returns The name of the property as a string, or an empty string if the name cannot be determined. + * + * This function handles two types of property keys: + * - Identifier: Returns the name directly. + * - Literal (string): Returns the string value. + * For any other type of key, it returns an empty string. + */ +export const getPropertyName = (property: TSESTree.Property): string => { + if (property.key.type === 'Identifier') { + return property.key.name; + } else if (property.key.type === 'Literal' && typeof property.key.value === 'string') { + return property.key.value; + } + return ''; +}; + +/** + * Separates object properties into regular and special categories. + * @param properties An array of object literal elements to be categorized. + * @returns An object containing two arrays: regularProperties and specialProperties. + * + * This function categorizes properties as follows: + * - Regular properties: Standard CSS properties. + * - Special properties: Properties that start with ':' (pseudo-selectors), + * '@' (at-rules), or are named 'selectors'. + * + * Non-Property type elements in the input array are ignored. + */ +export const separateProperties = ( + properties: TSESTree.ObjectLiteralElement[], +): { + regularProperties: TSESTree.Property[]; + specialProperties: TSESTree.Property[]; +} => { + const regularProperties: TSESTree.Property[] = []; + const specialProperties: TSESTree.Property[] = []; + + // Separate regular CSS properties from special ones (pseudo selectors, etc.) + properties.forEach((property) => { + if (property.type === 'Property') { + const propName = getPropertyName(property); + + if (propName.startsWith(':') || propName.startsWith('@') || propName === 'selectors') { + specialProperties.push(property); + } else { + regularProperties.push(property); + } + } + }); + + return { regularProperties, specialProperties }; +}; diff --git a/src/css-rules/shared-utils/recipe-property-processor.ts b/src/css-rules/shared-utils/recipe-property-processor.ts new file mode 100644 index 0000000..79ae722 --- /dev/null +++ b/src/css-rules/shared-utils/recipe-property-processor.ts @@ -0,0 +1,45 @@ +import type { Rule } from 'eslint'; +import { TSESTree } from '@typescript-eslint/utils'; + +/** + * Processes the `base` and `variants` properties of a recipe object. + * @param ruleContext The ESLint rule context. + * @param recipeNode The recipe object node to process. + * @param processProperty A callback function to process each property object (e.g., for alphabetical or concentric ordering). + * + * This function iterates through the properties of the recipe object: + * - For the `base` property, it directly processes the object. + * - For the `variants` property, it processes each variant's options individually. + * + * The function skips any non-Property nodes or nodes without an Identifier key. + * It only processes ObjectExpression values to ensure type safety. + */ +export const processRecipeProperties = ( + ruleContext: Rule.RuleContext, + recipeNode: TSESTree.ObjectExpression, + processProperty: (ruleContext: Rule.RuleContext, value: TSESTree.ObjectExpression) => void, +): void => { + recipeNode.properties.forEach((property: TSESTree.Property | TSESTree.SpreadElement) => { + if (property.type !== 'Property' || property.key.type !== 'Identifier') { + return; // Skip non-property nodes or nodes without an identifier key + } + + // Process the `base` property + if (property.key.name === 'base' && property.value.type === 'ObjectExpression') { + processProperty(ruleContext, property.value); + } + + // Process the `variants` property + if (property.key.name === 'variants' && property.value.type === 'ObjectExpression') { + property.value.properties.forEach((variantProperty) => { + if (variantProperty.type === 'Property' && variantProperty.value.type === 'ObjectExpression') { + variantProperty.value.properties.forEach((optionProperty) => { + if (optionProperty.type === 'Property' && optionProperty.value.type === 'ObjectExpression') { + processProperty(ruleContext, optionProperty.value); + } + }); + } + }); + } + }); +}; diff --git a/src/css-rules/shared-utils/style-node-processor.ts b/src/css-rules/shared-utils/style-node-processor.ts new file mode 100644 index 0000000..92b3d79 --- /dev/null +++ b/src/css-rules/shared-utils/style-node-processor.ts @@ -0,0 +1,30 @@ +import type { Rule } from 'eslint'; +import { TSESTree } from '@typescript-eslint/utils'; + +/** + * Recursively processes a style node, which can be an object or an array of objects. + * @param ruleContext The ESLint rule context. + * @param node The node to process. + * @param processProperty A function to process each object expression. + */ +export const processStyleNode = ( + ruleContext: Rule.RuleContext, + node: TSESTree.Node | undefined, + processProperty: (ruleContext: Rule.RuleContext, value: TSESTree.ObjectExpression) => void, +): void => { + if (!node) { + return; + } + + if (node.type === 'ObjectExpression') { + processProperty(ruleContext, node); + } + + if (node.type === 'ArrayExpression') { + node.elements.forEach((element) => { + if (element && element.type === 'ObjectExpression') { + processProperty(ruleContext, element); + } + }); + } +}; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..0421ee4 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,39 @@ +import alphabeticalOrderRule from './css-rules/alphabetical-order/index.js'; +import concentricOrderRule from './css-rules/concentric-order/index.js'; +import customOrderRule from './css-rules/custom-order/rule-definition.js'; + +export const vanillaExtract = { + meta: { + name: '@antebudimir/eslint-plugin-vanilla-extract', + version: '1.0.0', + }, + rules: { + 'alphabetical-order': alphabeticalOrderRule, + 'concentric-order': concentricOrderRule, + 'custom-order': customOrderRule, + }, + configs: { + recommended: [ + { + plugins: { + 'vanilla-extract': { + rules: { 'concentric-order': concentricOrderRule }, + }, + }, + rules: { 'vanilla-extract/concentric-order': 'warn' }, + }, + ], + alphabetical: [ + { + plugins: { + 'vanilla-extract': { + rules: { 'alphabetical-order': alphabeticalOrderRule }, + }, + }, + rules: { 'vanilla-extract/alphabetical-order': 'warn' }, + }, + ], + }, +}; + +export default vanillaExtract; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..9d18e4e --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + // Target and Module Settings + "target": "es2020", + "module": "NodeNext", + "moduleResolution": "NodeNext", + + // Output Settings + "declaration": true, + "outDir": "./dist", + + // Type Checking Options + "strict": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + "useUnknownInCatchVariables": true, + + // Interop Options + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + + // Other Options + "resolveJsonModule": true, + "isolatedModules": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "verbatimModuleSyntax": true + }, + "include": ["src/**/*", "*.d.ts"], + "exclude": ["node_modules", "**/*.test.ts", "dist"], + "typeRoots": ["./node_modules/@types", "./"] +}