From a308d9515a6dd74b313e8fdb4b64a3bfb2506c41 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Fri, 12 Dec 2025 19:44:14 +0200 Subject: [PATCH 01/38] init: create a plan for building an MCP server --- .github/workflows/node.js.yml | 2 +- .github/workflows/npm-publish.yml | 6 +- .stylelintrc.json | 2 +- package-lock.json | 18302 ++++++---------- package.json | 41 +- .../components/button/_button-theme.scss | 3 +- .../icon-button/_icon-button-theme.scss | 3 +- .../components/light/_input-group.scss | 6 +- .../schemas/components/light/_stepper.scss | 18 +- scripts/parser.mjs | 7 +- src/mcp/IMPROVEMENTS.md | 148 + src/mcp/PLAN.md | 908 + src/mcp/README.md | 363 + src/mcp/__tests__/generators/sass.test.ts | 518 + src/mcp/__tests__/knowledge/angular.test.ts | 309 + .../knowledge/platform-detection.test.ts | 488 + src/mcp/__tests__/knowledge/sass-api.test.ts | 316 + .../__tests__/knowledge/webcomponents.test.ts | 358 + .../__tests__/tools/handlers/handlers.test.ts | 336 + src/mcp/__tests__/tools/schemas.test.ts | 290 + src/mcp/__tests__/utils/color.test.ts | 262 + src/mcp/__tests__/utils/result.test.ts | 412 + src/mcp/__tests__/utils/sass.test.ts | 176 + .../validators/custom-palette.test.ts | 337 + src/mcp/generators/sass.ts | 322 + src/mcp/index.ts | 239 + src/mcp/knowledge/color-usage.ts | 711 + src/mcp/knowledge/colors.ts | 148 + src/mcp/knowledge/custom-palettes.ts | 208 + src/mcp/knowledge/elevations.ts | 46 + src/mcp/knowledge/index.ts | 130 + src/mcp/knowledge/multipliers.ts | 27 + src/mcp/knowledge/palettes.ts | 119 + src/mcp/knowledge/platforms/angular.ts | 333 + src/mcp/knowledge/platforms/blazor.ts | 170 + src/mcp/knowledge/platforms/common.ts | 94 + src/mcp/knowledge/platforms/index.ts | 415 + src/mcp/knowledge/platforms/react.ts | 158 + src/mcp/knowledge/platforms/webcomponents.ts | 565 + src/mcp/knowledge/sass-api.ts | 430 + src/mcp/knowledge/typography.ts | 66 + src/mcp/resources/index.ts | 10 + src/mcp/resources/presets.ts | 417 + src/mcp/tools/descriptions.ts | 616 + src/mcp/tools/handlers/custom-palette.ts | 151 + src/mcp/tools/handlers/elevations.ts | 40 + src/mcp/tools/handlers/index.ts | 10 + src/mcp/tools/handlers/palette.ts | 81 + src/mcp/tools/handlers/platform.ts | 219 + src/mcp/tools/handlers/theme.ts | 130 + src/mcp/tools/handlers/typography.ts | 42 + src/mcp/tools/index.ts | 29 + src/mcp/tools/schemas.ts | 238 + src/mcp/utils/color.ts | 536 + src/mcp/utils/result.ts | 375 + src/mcp/utils/sass.ts | 380 + src/mcp/utils/types.ts | 315 + src/mcp/validators/custom-palette.ts | 402 + src/mcp/validators/index.ts | 40 + src/mcp/validators/palette.ts | 435 + test/sass.test.ts | 13 + test/test.js | 10 - tsconfig.json | 17 + vitest.config.ts | 16 + 64 files changed, 20438 insertions(+), 11876 deletions(-) create mode 100644 src/mcp/IMPROVEMENTS.md create mode 100644 src/mcp/PLAN.md create mode 100644 src/mcp/README.md create mode 100644 src/mcp/__tests__/generators/sass.test.ts create mode 100644 src/mcp/__tests__/knowledge/angular.test.ts create mode 100644 src/mcp/__tests__/knowledge/platform-detection.test.ts create mode 100644 src/mcp/__tests__/knowledge/sass-api.test.ts create mode 100644 src/mcp/__tests__/knowledge/webcomponents.test.ts create mode 100644 src/mcp/__tests__/tools/handlers/handlers.test.ts create mode 100644 src/mcp/__tests__/tools/schemas.test.ts create mode 100644 src/mcp/__tests__/utils/color.test.ts create mode 100644 src/mcp/__tests__/utils/result.test.ts create mode 100644 src/mcp/__tests__/utils/sass.test.ts create mode 100644 src/mcp/__tests__/validators/custom-palette.test.ts create mode 100644 src/mcp/generators/sass.ts create mode 100644 src/mcp/index.ts create mode 100644 src/mcp/knowledge/color-usage.ts create mode 100644 src/mcp/knowledge/colors.ts create mode 100644 src/mcp/knowledge/custom-palettes.ts create mode 100644 src/mcp/knowledge/elevations.ts create mode 100644 src/mcp/knowledge/index.ts create mode 100644 src/mcp/knowledge/multipliers.ts create mode 100644 src/mcp/knowledge/palettes.ts create mode 100644 src/mcp/knowledge/platforms/angular.ts create mode 100644 src/mcp/knowledge/platforms/blazor.ts create mode 100644 src/mcp/knowledge/platforms/common.ts create mode 100644 src/mcp/knowledge/platforms/index.ts create mode 100644 src/mcp/knowledge/platforms/react.ts create mode 100644 src/mcp/knowledge/platforms/webcomponents.ts create mode 100644 src/mcp/knowledge/sass-api.ts create mode 100644 src/mcp/knowledge/typography.ts create mode 100644 src/mcp/resources/index.ts create mode 100644 src/mcp/resources/presets.ts create mode 100644 src/mcp/tools/descriptions.ts create mode 100644 src/mcp/tools/handlers/custom-palette.ts create mode 100644 src/mcp/tools/handlers/elevations.ts create mode 100644 src/mcp/tools/handlers/index.ts create mode 100644 src/mcp/tools/handlers/palette.ts create mode 100644 src/mcp/tools/handlers/platform.ts create mode 100644 src/mcp/tools/handlers/theme.ts create mode 100644 src/mcp/tools/handlers/typography.ts create mode 100644 src/mcp/tools/index.ts create mode 100644 src/mcp/tools/schemas.ts create mode 100644 src/mcp/utils/color.ts create mode 100644 src/mcp/utils/result.ts create mode 100644 src/mcp/utils/sass.ts create mode 100644 src/mcp/utils/types.ts create mode 100644 src/mcp/validators/custom-palette.ts create mode 100644 src/mcp/validators/index.ts create mode 100644 src/mcp/validators/palette.ts create mode 100644 test/sass.test.ts delete mode 100644 test/test.js create mode 100644 tsconfig.json create mode 100644 vitest.config.ts diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index f6e0cd9b..560f3392 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -26,5 +26,5 @@ jobs: node-version: ${{ matrix.node-version }} - run: npm ci - run: npm run lint - - run: npm run test - run: npm run build + - run: npm run test diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 8b830171..49eece4b 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -27,12 +27,12 @@ jobs: - name: Lint package run: npm run lint - - name: Test package - run: npm test - - name: Build package run: npm run build + - name: Test package + run: npm test + - name: Define NPM tag run: | if [[ ${VERSION} == *"alpha"* || ${VERSION} == *"beta"* || ${VERSION} == *"rc"* ]]; then diff --git a/.stylelintrc.json b/.stylelintrc.json index 0befd3bd..d46376c7 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -70,7 +70,7 @@ "shorthand-property-no-redundant-values": true, "alpha-value-notation": "number", "value-keyword-case": "lower", - "value-no-vendor-prefix": true, + "value-no-vendor-prefix": null, "scss/at-mixin-pattern": null, "scss/at-function-pattern": null, "scss/dollar-variable-pattern": null, diff --git a/package-lock.json b/package-lock.json index cabb638b..da246492 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,24 @@ { "name": "igniteui-theming", "version": "1.0.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "igniteui-theming", "version": "1.0.0", "license": "MIT", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.25.0", + "sass-embedded": "~1.92.1", + "zod": "^3.25.76" + }, + "bin": { + "igniteui-theming-mcp": "dist/mcp/index.js" + }, "devDependencies": { + "@types/node": "^22.0.0", + "@vitest/coverage-v8": "^4.0.16", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.29.1", @@ -16,28 +26,19 @@ "globby": "^13.1.4", "husky": "^8.0.3", "igniteui-sassdoc-theme": "^1.1.6", - "jest": "^29.5.0", - "jest-environment-node-single-context": "^29.0.0", "lunr": "^2.3.9", "postcss": "^8.4.35", "postcss-safe-parser": "^7.0.0", "prettier": "^3.2.5", - "sass-embedded": "^1.92.1", "sass-true": "^9.0.0", "sassdoc-plugin-localization": "^2.0.0", "shx": "^0.3.4", "stylelint": "^15.6.2", "stylelint-config-standard-scss": "^7.0.1", - "stylelint-scss": "^4.7.0" - } - }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "stylelint-scss": "^4.7.0", + "tsx": "^4.0.0", + "typescript": "^5.7.0", + "vitest": "^4.0.15" } }, "node_modules/@adobe/css-tools": { @@ -47,1343 +48,1230 @@ "dev": true, "license": "MIT" }, - "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@babel/code-frame/node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } + "license": "MIT" }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, + "license": "MIT", "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" + "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.8.0" + "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, "engines": { - "node": ">=4" + "node": ">=6.0.0" } }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" } }, - "node_modules/@babel/compat-data": { - "version": "7.21.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.7.tgz", - "integrity": "sha512-KYMqFYTaenzMK4yUtf4EW9wc4N9ef80FsbMtkwool5zpwl4YrT1SdWYSTRcT94KO4hannogdS+LxY7L+arP3gA==", + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/core": { - "version": "7.21.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.8.tgz", - "integrity": "sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ==", + "node_modules/@bufbuild/protobuf": { + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.10.2.tgz", + "integrity": "sha512-uFsRXwIGyu+r6AMdz+XijIIZJYpoWeYzILt5yZ2d3mCjQrWUTVpVD9WL/jZAbvp+Ed04rOhrsk7FiTcEDseB5A==", + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.7.1.tgz", + "integrity": "sha512-2SJS42gxmACHgikc1WGesXLIT8d/q2l0UFM7TaEeIzdFCE/FPMtTiizcPGGJtlPo2xuQzY09OhrLTzRxqJqwGw==", "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.5", - "@babel/helper-compilation-targets": "^7.21.5", - "@babel/helper-module-transforms": "^7.21.5", - "@babel/helpers": "^7.21.5", - "@babel/parser": "^7.21.8", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, "engines": { - "node": ">=6.9.0" + "node": "^14 || ^16 || >=18" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" + "peerDependencies": { + "@csstools/css-tokenizer": "^2.4.1" } }, - "node_modules/@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "node_modules/@csstools/css-tokenizer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.4.1.tgz", + "integrity": "sha512-eQ9DIktFJBhGjioABJRtUucoWR2mwllurfnM8LuNGAqX3ViZXaUchqk+1s7jjtkFiT9ySdACsFEA3etErkALUg==", "dev": true, - "dependencies": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, "engines": { - "node": ">=6.9.0" + "node": "^14 || ^16 || >=18" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.5.tgz", - "integrity": "sha512-1RkbFGUKex4lvsB9yhIfWltJM5cZKUftB2eNajaDv3dCMEp49iBG0K14uH8NnX9IPux2+mK7JGEOB0jn48/J6w==", + "node_modules/@csstools/media-query-list-parser": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.13.tgz", + "integrity": "sha512-XaHr+16KRU9Gf8XLi3q8kDlI18d5vzKSKCY510Vrtc9iNR0NJzbY9hhTmwhzYZj/ZwGL4VmB3TA9hJW0Um2qFA==", "dev": true, - "dependencies": { - "@babel/compat-data": "^7.21.5", - "@babel/helper-validator-option": "^7.21.0", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@csstools/css-parser-algorithms": "^2.7.1", + "@csstools/css-tokenizer": "^2.4.1" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "node_modules/@csstools/selector-specificity": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.1.1.tgz", + "integrity": "sha512-a7cxGcJ2wIlMFLlh8z2ONm+715QkPHiyJcxwQlKOz/03GPw1COpfhcmC9wm4xlZfp//jWHNNMwzjtqHXVWU9KA==", "dev": true, - "dependencies": { - "yallist": "^3.0.2" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^6.0.13" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-module-imports": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", - "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@babel/types": "^7.21.4" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.5.tgz", - "integrity": "sha512-bI2Z9zBGY2q5yMHoBvJ2a9iX3ZOAzJPm7Q8Yz6YeoUjU/Cvhmi2G4QyTNyPBqqXSgTjUxRg3L0xV45HvkNWWBw==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.21.5", - "@babel/helper-module-imports": "^7.21.4", - "@babel/helper-simple-access": "^7.21.5", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5" - }, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz", - "integrity": "sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.21.5.tgz", - "integrity": "sha512-ENPDAMC1wAjR0uaCUwliBdiSl1KBJAVnMTzXqi64c2MG8MPR6ii4qf7bSXDqSFbr4W6W028/rf5ivoHop5/mkg==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@babel/types": "^7.21.5" - }, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helpers": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.5.tgz", - "integrity": "sha512-BSY+JSlHxOmGsPTydUkPf1MdMQ3M81x5xGCOVgWM3G8XH77sJ292Y2oqcp0CbbgxhqBuI46iUz1tT7hqP7EfgA==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], "dev": true, - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], "dev": true, - "dependencies": { - "color-name": "1.1.3" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=0.8.0" + "node": ">=18" } }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/@babel/parser": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz", - "integrity": "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=6.0.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz", - "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": ">=6.9.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } + "license": "MIT" }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "node_modules/@hono/node-server": { + "version": "1.19.7", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.7.tgz", + "integrity": "sha512-vUcD0uauS7EU2caukW8z5lJKtoGMokxNbJtBiwHgpqxEXokaHCBkQUmCHhjFB1VUTWdqj25QoMkMKzgjq+uhrw==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "hono": "^4" } }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=10.10.0" } }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", - "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" - }, + "license": "Apache-2.0", "engines": { - "node": ">=6.9.0" + "node": ">=12.22" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@babel/template": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", - "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", "dev": true, - "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - } + "license": "BSD-3-Clause" }, - "node_modules/@babel/traverse": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.0.tgz", - "integrity": "sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==", + "node_modules/@jest/diff-sequences": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", "dev": true, - "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, + "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, + "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@bufbuild/protobuf": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.7.0.tgz", - "integrity": "sha512-qn6tAIZEw5i/wiESBF4nQxZkl86aY4KoO0IkUa2Lh+rya64oTOdJQFlZuMwI1Qz9VBJQrQC4QlSA2DNek5gCOA==", - "dev": true, - "license": "(Apache-2.0 AND BSD-3-Clause)" - }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.1.1.tgz", - "integrity": "sha512-viRnRh02AgO4mwIQb2xQNJju0i+Fh9roNgmbR5xEuG7J3TGgxjnE95HnBLgsFJOJOksvcfxOUCgODcft6Y07cA==", + "node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", "dev": true, - "engines": { - "node": "^14 || ^16 || >=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" }, - "peerDependencies": { - "@csstools/css-tokenizer": "^2.1.1" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@csstools/css-tokenizer": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.1.1.tgz", - "integrity": "sha512-GbrTj2Z8MCTUv+52GE0RbFGM527xuXZ0Xa5g0Z+YN573uveS4G0qi6WNOMyz3yrFM/jaILTTwJ0+umx81EzqfA==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, + "license": "MIT", "engines": { - "node": "^14 || ^16 || >=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "node": ">=6.0.0" } }, - "node_modules/@csstools/media-query-list-parser": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.0.4.tgz", - "integrity": "sha512-GyYot6jHgcSDZZ+tLSnrzkR7aJhF2ZW6d+CXH66mjy5WpAQhZD4HDke2OQ36SivGRWlZJpAz7TzbW6OKlEpxAA==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true, - "engines": { - "node": "^14 || ^16 || >=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^2.1.1", - "@csstools/css-tokenizer": "^2.1.1" - } + "license": "MIT" }, - "node_modules/@csstools/selector-specificity": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", - "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, - "engines": { - "node": "^14 || ^16 || >=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss-selector-parser": "^6.0.10" + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.1.tgz", + "integrity": "sha512-yO28oVFFC7EBoiKdAn+VqRm+plcfv4v0xp6osG/VsCB0NlPZWi87ajbCZZ8f/RvOFLEu7//rSRmuZZ7lMoe3gQ==", + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "@hono/node-server": "^1.19.7", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.0.1", + "express-rate-limit": "^7.5.0", + "jose": "^6.1.1", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.0" + }, + "engines": { + "node": ">=18" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } } }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">= 8" } }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "license": "MIT", + "engines": { + "node": ">= 8" } }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { - "type-fest": "^0.20.2" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 8" } }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, "dependencies": { - "argparse": "^2.0.1" + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, "engines": { - "node": ">=10" + "node": ">= 10.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" } }, - "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "node": ">= 10.0.0" }, - "engines": { - "node": ">=10.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=12.22" + "node": ">= 10.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", - "dev": true - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", - "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0" + "node": ">= 10.0.0" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/core": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", - "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/reporters": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.5.0", - "jest-config": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-resolve-dependencies": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "jest-watcher": "^29.5.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/diff-sequences": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", - "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", - "dev": true, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/environment": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", - "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0" + "node": ">= 10.0.0" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", - "dev": true, - "dependencies": { - "expect": "^29.5.0", - "jest-snapshot": "^29.5.0" - }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/expect-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", - "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.4.3" - }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/fake-timers": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", - "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/get-type": { - "version": "30.1.0", - "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", - "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", - "dev": true, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/globals": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", - "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/types": "^29.5.0", - "jest-mock": "^29.5.0" - }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/reporters": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", - "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "node": ">= 10.0.0" }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.25.16" - }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jest/source-map": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", - "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, + "license": "MIT", "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" } }, - "node_modules/@jest/test-result": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", - "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", - "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@parcel/watcher": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", - "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.5.tgz", + "integrity": "sha512-iDGS/h7D8t7tvZ1t6+WPK04KD0MwzLZrG0se1hzBjSi5fyxlsiggoJHwh18PCFNn7tG43OWb6pdZ6Y+rMlmyNQ==", + "cpu": [ + "arm" + ], "dev": true, - "hasInstallScript": true, "license": "MIT", "optional": true, - "dependencies": { - "detect-libc": "^1.0.3", - "is-glob": "^4.0.3", - "micromatch": "^4.0.5", - "node-addon-api": "^7.0.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.1", - "@parcel/watcher-darwin-arm64": "2.5.1", - "@parcel/watcher-darwin-x64": "2.5.1", - "@parcel/watcher-freebsd-x64": "2.5.1", - "@parcel/watcher-linux-arm-glibc": "2.5.1", - "@parcel/watcher-linux-arm-musl": "2.5.1", - "@parcel/watcher-linux-arm64-glibc": "2.5.1", - "@parcel/watcher-linux-arm64-musl": "2.5.1", - "@parcel/watcher-linux-x64-glibc": "2.5.1", - "@parcel/watcher-linux-x64-musl": "2.5.1", - "@parcel/watcher-win32-arm64": "2.5.1", - "@parcel/watcher-win32-ia32": "2.5.1", - "@parcel/watcher-win32-x64": "2.5.1" - } + "os": [ + "android" + ] }, - "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", - "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.5.tgz", + "integrity": "sha512-wrSAViWvZHBMMlWk6EJhvg8/rjxzyEhEdgfMMjREHEq11EtJ6IP6yfcCH57YAEca2Oe3FNCE9DSTgU70EIGmVw==", "cpu": [ "arm64" ], @@ -1392,19 +1280,12 @@ "optional": true, "os": [ "android" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + ] }, - "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", - "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.5.tgz", + "integrity": "sha512-S87zZPBmRO6u1YXQLwpveZm4JfPpAa6oHBX7/ghSiGH3rz/KDgAu1rKdGutV+WUI6tKDMbaBJomhnT30Y2t4VQ==", "cpu": [ "arm64" ], @@ -1413,19 +1294,12 @@ "optional": true, "os": [ "darwin" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + ] }, - "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", - "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.5.tgz", + "integrity": "sha512-YTbnsAaHo6VrAczISxgpTva8EkfQus0VPEVJCEaboHtZRIb6h6j0BNxRBOwnDciFTZLDPW5r+ZBmhL/+YpTZgA==", "cpu": [ "x64" ], @@ -1434,19 +1308,26 @@ "optional": true, "os": [ "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.5.tgz", + "integrity": "sha512-1T8eY2J8rKJWzaznV7zedfdhD1BqVs1iqILhmHDq/bqCUZsrMt+j8VCTHhP0vdfbHK3e1IQ7VYx3jlKqwlf+vw==", + "cpu": [ + "arm64" ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", - "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.5.tgz", + "integrity": "sha512-sHTiuXyBJApxRn+VFMaw1U+Qsz4kcNlxQ742snICYPrY+DDL8/ZbaC4DVIB7vgZmp3jiDaKA0WpBdP0aqPJoBQ==", "cpu": [ "x64" ], @@ -1455,19 +1336,12 @@ "optional": true, "os": [ "freebsd" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + ] }, - "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", - "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.5.tgz", + "integrity": "sha512-dV3T9MyAf0w8zPVLVBptVlzaXxka6xg1f16VAQmjg+4KMSTWDvhimI/Y6mp8oHwNrmnmVl9XxJ/w/mO4uIQONA==", "cpu": [ "arm" ], @@ -1476,19 +1350,12 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + ] }, - "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", - "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.5.tgz", + "integrity": "sha512-wIGYC1x/hyjP+KAu9+ewDI+fi5XSNiUi9Bvg6KGAh2TsNMA3tSEs+Sh6jJ/r4BV/bx/CyWu2ue9kDnIdRyafcQ==", "cpu": [ "arm" ], @@ -1497,19 +1364,12 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + ] }, - "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", - "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.5.tgz", + "integrity": "sha512-Y+qVA0D9d0y2FRNiG9oM3Hut/DgODZbU9I8pLLPwAsU0tUKZ49cyV1tzmB/qRbSzGvY8lpgGkJuMyuhH7Ma+Vg==", "cpu": [ "arm64" ], @@ -1518,19 +1378,12 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + ] }, - "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", - "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.5.tgz", + "integrity": "sha512-juaC4bEgJsyFVfqhtGLz8mbopaWD+WeSOYr5E16y+1of6KQjc0BpwZLuxkClqY1i8sco+MdyoXPNiCkQou09+g==", "cpu": [ "arm64" ], @@ -1539,8750 +1392,1620 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + ] }, - "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", - "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.5.tgz", + "integrity": "sha512-rIEC0hZ17A42iXtHX+EPJVL/CakHo+tT7W0pbzdAGuWOt2jxDFh7A/lRhsNHBcqL4T36+UiAgwO8pbmn3dE8wA==", "cpu": [ - "x64" + "loong64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", - "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", - "cpu": [ - "x64" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.5.tgz", + "integrity": "sha512-T7l409NhUE552RcAOcmJHj3xyZ2h7vMWzcwQI0hvn5tqHh3oSoclf9WgTl+0QqffWFG8MEVZZP1/OBglKZx52Q==", + "cpu": [ + "ppc64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + ] }, - "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", - "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.5.tgz", + "integrity": "sha512-7OK5/GhxbnrMcxIFoYfhV/TkknarkYC1hqUw1wU2xUN3TVRLNT5FmBv4KkheSG2xZ6IEbRAhTooTV2+R5Tk0lQ==", "cpu": [ - "arm64" + "riscv64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + "linux" + ] }, - "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", - "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.5.tgz", + "integrity": "sha512-GwuDBE/PsXaTa76lO5eLJTyr2k8QkPipAyOrs4V/KJufHCZBJ495VCGJol35grx9xryk4V+2zd3Ri+3v7NPh+w==", "cpu": [ - "ia32" + "riscv64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + "linux" + ] }, - "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", - "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.5.tgz", + "integrity": "sha512-IAE1Ziyr1qNfnmiQLHBURAD+eh/zH1pIeJjeShleII7Vj8kyEm2PF77o+lf3WTHDpNJcu4IXJxNO0Zluro8bOw==", "cpu": [ - "x64" + "s390x" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/@simeonoff/themeleon": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@simeonoff/themeleon/-/themeleon-3.0.3.tgz", - "integrity": "sha512-HflceRGqppzL5D96PjSzo7p6yjsjkNTAVX2q3iRma1QvP4Wd5OKzQDd0NSmPcQ2FBTrbkERKxE8RclFBpxtArg==", - "dev": true, - "dependencies": { - "ap": "^0.2.0", - "consolidate": "^0.13.0", - "fs-extra": "^0.13.0", - "glob": "^4.3.1", - "merge": "^2.1.1", - "q": "^1.1.2" - } - }, - "node_modules/@simeonoff/themeleon/node_modules/glob": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", - "integrity": "sha512-I0rTWUKSZKxPSIAIaqhSXTM/DiII6wame+rEC3cFA5Lqmr9YmdL7z6Hj9+bdWtTvoY1Su4/OiMLmb37Y7JzvJQ==", - "dev": true, - "dependencies": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^2.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@simeonoff/themeleon/node_modules/minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha512-jQo6o1qSVLEWaw3l+bwYA2X0uLuK2KjNh2wjgO7Q/9UJnXr1Q3yQKR8BI0/Bt/rPg75e6SMW4hW/6cBHVTZUjA==", - "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", - "dev": true, - "dependencies": { - "brace-expansion": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", - "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.1.0.tgz", - "integrity": "sha512-w1qd368vtrwttm1PRJWPW1QHlbmHrVDGs1eBH/jZvRPUFS4MNXV9Q33EQdjOdeAxZ7O8+3wM7zxztm2nfUSyKw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", - "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.18.5", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.5.tgz", - "integrity": "sha512-enCvTL8m/EHS/zIvJno9nE+ndYPh1/oNFzRYRmtUqJICG2VnCSBzMLW5VN2KCQU91f23tsNKR8v7VJJQMatl7Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "node_modules/@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.14.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", - "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==", - "dev": true - }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", - "dev": true - }, - "node_modules/@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", - "dev": true - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/ap": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/ap/-/ap-0.2.0.tgz", - "integrity": "sha512-ImdvquIuBSVpWRWhB441UjvTcZqic1RL+lTQaUKGdGEp1aiTvt/phAvY8Vvs32qya5FJBI8U+tzNBYzFDQY/lQ==", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.filter": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz", - "integrity": "sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz", - "integrity": "sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/babel-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", - "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", - "dev": true, - "dependencies": { - "@jest/transform": "^29.5.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.5.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", - "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", - "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^29.5.0", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/bluebird": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", - "integrity": "sha512-UfFSr22dmHPQqPP9XWHRhq+gWnHCYguQGkXQlbyPtW5qTnhFWA8/iXg765tH0cAjy7l/zPJ1aBTO0g5XgA7kvQ==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-builder": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/buffer-builder/-/buffer-builder-0.2.0.tgz", - "integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==", - "dev": true, - "license": "MIT/X11" - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001488", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001488.tgz", - "integrity": "sha512-NORIQuuL4xGpIy6iCCQGN4iFjlBXtfKWIenlUuyZJumLRIindLb7wXM+GO8erEhb7vXfcnf4BAg2PrSDN5TNLQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", - "dev": true - }, - "node_modules/colorjs.io": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz", - "integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/consolidate": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.13.1.tgz", - "integrity": "sha512-027d1hT0huixz578MzXlB30ipJaF0131zmQJhiL49fwjDj+I45MwgL3/TQHEgeuZfcJus69vBlHcIPd+h2UNCw==", - "deprecated": "Please upgrade to consolidate v1.0.0+ as it has been modernized with several long-awaited fixes implemented. Maintenance is supported by Forward Email at https://forwardemail.net ; follow/watch https://github.com/ladjs/consolidate for updates and release changelog", - "dev": true, - "dependencies": { - "bluebird": "^2.9.26" - } - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/cosmiconfig": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", - "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", - "dev": true, - "dependencies": { - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - } - }, - "node_modules/cosmiconfig/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/cosmiconfig/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-functions-list": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.1.0.tgz", - "integrity": "sha512-/9lCvYZaUbBGvYUgYGFJ4dcYiyqdhSjG7IPVluoV8A1ILjkF7ilmhp1OGUz8n+nmBcu0RNrQAzgD8B6FJbrt2w==", - "dev": true, - "engines": { - "node": ">=12.22" - } - }, - "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", - "integrity": "sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==", - "dev": true, - "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.399", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.399.tgz", - "integrity": "sha512-+V1aNvVgoWNWYIbMOiQ1n5fRIaY4SlQ/uRlrsCjLrUwr/3OvQgiX2f5vdav4oArVT9TnttJKcPCqjwPNyZqw/A==", - "dev": true - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.22.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.5.tgz", - "integrity": "sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "hasown": "^2.0.1", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.0", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.5", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "dev": true - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", - "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", - "semver": "^6.3.1", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", - "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": "*", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/eslint/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true, - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flatted": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", - "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", - "dev": true - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/fs-extra": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.13.0.tgz", - "integrity": "sha512-JiEPAzy0hZ0EN25pkXkgmzxn/ThqTbDrTqGnEO9eFMR33mfG72A2YFjQ23+zTsnDtcOesBKUtRXWTh6V4bQUVg==", - "dev": true, - "dependencies": { - "jsonfile": "^2.0.0", - "ncp": "^1.0.1", - "rimraf": "^2.2.8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "dev": true, - "dependencies": { - "global-prefix": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "dev": true, - "dependencies": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", - "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", - "dev": true, - "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globjoin": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", - "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", - "dev": true - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/html-tags": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", - "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/husky": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", - "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", - "dev": true, - "bin": { - "husky": "lib/bin.js" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" - } - }, - "node_modules/igniteui-sassdoc-theme": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/igniteui-sassdoc-theme/-/igniteui-sassdoc-theme-1.2.3.tgz", - "integrity": "sha512-8ptCZ/fJmuAxrrZMMnKu3rL/VfOk5XwShPgbaxCL02uSzYpiBSkU0gblc5lQIiwBeci8JU+I3rwJJSo77Kpt1A==", - "dev": true, - "dependencies": { - "@simeonoff/themeleon": "^3.0.3", - "extend": ">=2.0.2", - "handlebars": "^4.7.8", - "minimist": "^1.2.8", - "sassdoc-extras": "^2.5.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/immutable": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", - "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", - "dev": true, - "license": "MIT" - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", - "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", - "dev": true, - "dependencies": { - "@jest/core": "^29.5.0", - "@jest/types": "^29.5.0", - "import-local": "^3.0.2", - "jest-cli": "^29.5.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", - "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-changed-files/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-circus": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", - "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.5.0", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.5.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-cli": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", - "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", - "dev": true, - "dependencies": { - "@jest/core": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", - "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.5.0", - "@jest/types": "^29.5.0", - "babel-jest": "^29.5.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.5.0", - "jest-environment-node": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-diff": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", - "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.4.3", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", - "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", - "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "jest-util": "^29.5.0", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", - "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node-single-context": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-environment-node-single-context/-/jest-environment-node-single-context-29.0.0.tgz", - "integrity": "sha512-/XB09Hje38Kl5k9ISUpXNom3M4DQo5ifEsnELPFP5r3yrJDRyNQCEjL/9ScUN6z6UeF4FCNZUsiJIX/tGtTXNw==", - "dev": true, - "dependencies": { - "jest-environment-node": "^29.0.1" - }, - "funding": { - "url": "https://github.com/kayahr/jest-environment-node-single-context?sponsor=1" - } - }, - "node_modules/jest-get-type": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", - "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", - "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", - "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", - "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.5.0", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", - "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", - "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", - "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", - "dev": true, - "dependencies": { - "jest-regex-util": "^29.4.3", - "jest-snapshot": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", - "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/environment": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.4.3", - "jest-environment-node": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-leak-detector": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-resolve": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-util": "^29.5.0", - "jest-watcher": "^29.5.0", - "jest-worker": "^29.5.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-runtime": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", - "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/globals": "^29.5.0", - "@jest/source-map": "^29.4.3", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", - "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.5.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", - "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "leven": "^3.1.0", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", - "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.5.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", - "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "jest-util": "^29.5.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/known-css-properties": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.27.0.tgz", - "integrity": "sha512-uMCj6+hZYDoffuvAJjFAPz56E9uoowFHmTkqRtRq5WyC5Q6Cu/fTZKNQpX/RbzChBYLLl3lo8CjFZBAZXq9qFg==", - "dev": true - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "dev": true - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/marked": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.6.3.tgz", - "integrity": "sha512-Fqa7eq+UaxfMriqzYLayfqAE40WN03jf+zHjT18/uXNuzjq3TY0XTbrAoPeqSJrAmPz11VuUA+kBPYOhHt9oOQ==", - "dev": true, - "bin": { - "marked": "bin/marked" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mathml-tag-names": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", - "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true - }, - "node_modules/meow": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", - "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", - "dev": true, - "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize": "^1.2.0", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/merge": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", - "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", - "dev": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "dev": true, - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/ncp": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-1.0.1.tgz", - "integrity": "sha512-akBX7I5X9KQDDWmYYgQlLbVbjkveTje2mioZjhLLrVt09akSZcoqXWE5LEn1E2fu8T7th1PZYGfewQsTkTLTmQ==", - "dev": true, - "bin": { - "ncp": "bin/ncp" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.2.tgz", - "integrity": "sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw==", - "dev": true, - "dependencies": { - "array.prototype.filter": "^1.0.3", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.0.0" - } - }, - "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-media-query-parser": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", - "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", - "dev": true - }, - "node_modules/postcss-resolve-nested-selector": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz", - "integrity": "sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==", - "dev": true - }, - "node_modules/postcss-safe-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.0.tgz", - "integrity": "sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "engines": { - "node": ">=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/postcss-scss": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.6.tgz", - "integrity": "sha512-rLDPhJY4z/i4nVFZ27j9GqLxj1pwxE80eAzUNRMXtcpipFYIeowerzBgG3yJhMtObGEXidtIgbUpQ3eLDsf5OQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss-scss" - } - ], - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.4.19" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pure-rand": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", - "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ] - }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "dev": true, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dev": true, - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-array-concat/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-regex": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/sass": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.92.1.tgz", - "integrity": "sha512-ffmsdbwqb3XeyR8jJR6KelIXARM9bFQe8A6Q3W4Klmwy5Ckd5gz7jgUNHo4UOqutU5Sk1DtKLbpDP0nLCg1xqQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "chokidar": "^4.0.0", - "immutable": "^5.0.2", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=14.0.0" - }, - "optionalDependencies": { - "@parcel/watcher": "^2.4.1" - } - }, - "node_modules/sass-embedded": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.92.1.tgz", - "integrity": "sha512-28YwLnF5atAhogt3E4hXzz/NB9dwKffyw08a7DEasLh94P7+aELkG3ENSHYCWB9QFN14hYNLfwr9ozUsPDhcDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@bufbuild/protobuf": "^2.5.0", - "buffer-builder": "^0.2.0", - "colorjs.io": "^0.5.0", - "immutable": "^5.0.2", - "rxjs": "^7.4.0", - "supports-color": "^8.1.1", - "sync-child-process": "^1.0.2", - "varint": "^6.0.0" - }, - "bin": { - "sass": "dist/bin/sass.js" - }, - "engines": { - "node": ">=16.0.0" - }, - "optionalDependencies": { - "sass-embedded-all-unknown": "1.92.1", - "sass-embedded-android-arm": "1.92.1", - "sass-embedded-android-arm64": "1.92.1", - "sass-embedded-android-riscv64": "1.92.1", - "sass-embedded-android-x64": "1.92.1", - "sass-embedded-darwin-arm64": "1.92.1", - "sass-embedded-darwin-x64": "1.92.1", - "sass-embedded-linux-arm": "1.92.1", - "sass-embedded-linux-arm64": "1.92.1", - "sass-embedded-linux-musl-arm": "1.92.1", - "sass-embedded-linux-musl-arm64": "1.92.1", - "sass-embedded-linux-musl-riscv64": "1.92.1", - "sass-embedded-linux-musl-x64": "1.92.1", - "sass-embedded-linux-riscv64": "1.92.1", - "sass-embedded-linux-x64": "1.92.1", - "sass-embedded-unknown-all": "1.92.1", - "sass-embedded-win32-arm64": "1.92.1", - "sass-embedded-win32-x64": "1.92.1" - } - }, - "node_modules/sass-embedded-all-unknown": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.92.1.tgz", - "integrity": "sha512-5t6/YZf+vhO3OY/49h8RCL6Cwo78luva0M+TnTM9gu9ASffRXAuOVLNKciSXa3loptyemDDS6IU5/dVH5w0KmA==", - "cpu": [ - "!arm", - "!arm64", - "!riscv64", - "!x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "sass": "1.92.1" - } - }, - "node_modules/sass-embedded-android-arm": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.92.1.tgz", - "integrity": "sha512-4EjpVVzuksERdgAd4BqeSXFnWtWN3DSRyEIUPJ7BhcS9sfDh2Gf6miI2kNTvIQLJ2XIJynDDcEQ8a1U9KwKUTQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-android-arm64": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.92.1.tgz", - "integrity": "sha512-Q+UruGb7yKawHagVmVDRRKsnc4mJZvWMBnuRCu2coJo2FofyqBmXohVGXbxko97sYceA9TJTrUEx3WVKQUNCbQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-android-riscv64": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.92.1.tgz", - "integrity": "sha512-nCY5btLlX7W7Jc6cCL6D2Yklpiu540EJ2G08YVGu12DrAMCBzqM347CSRf2ojp1H8jyhvmLkaFwnrJWzh+6S+w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-android-x64": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.92.1.tgz", - "integrity": "sha512-qYWR3bftJ77aLYwYDFuzDI4dcwVVixxqQxlIQWNGkHRCexj614qGSSHemr18C2eVj3mjXAQxTQxU68U7pkGPAA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-darwin-arm64": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.92.1.tgz", - "integrity": "sha512-g2yQ3txjMYLKMjL2cW1xRO9nnV3ijf95NbX/QShtV6tiVUETZNWDsRMDEwBNGYY6PTE/UZerjJL1R/2xpQg6WA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-darwin-x64": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.92.1.tgz", - "integrity": "sha512-eH+fgxLQhTEPjZPCgPAVuX5e514Qp/4DMAUMtlNShv4cr4TD5qOp1XlsPYR/b7uE7p2cKFkUpUn/bHNqJ2ay4A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-linux-arm": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.92.1.tgz", - "integrity": "sha512-cT3w8yoQTqrtZvWLJeutEGmawITDTY4J6oSVQjeDcPnnoPt0gOFxem8YMznraACXvahw/2+KJDH33BTNgiPo0A==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-linux-arm64": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.92.1.tgz", - "integrity": "sha512-dNmlpGeZkry1BofhAdGFBXrpM69y9LlYuNnncf+HfsOOUtj8j0q1RwS+zb5asknhKFUOAG8GCGRY1df7Rwu35g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-linux-musl-arm": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.92.1.tgz", - "integrity": "sha512-nPBos6lI31ef2zQhqTZhFOU7ar4impJbLIax0XsqS269YsiCwjhk11VmUloJTpFlJuKMiVXNo7dPx+katxhD/Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-linux-musl-arm64": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.92.1.tgz", - "integrity": "sha512-TfiEBkCyNzVoOhjHXUT+vZ6+p0ueDbvRw6f4jHdkvljZzXdXMby4wh7BU1odl69rgRTkSvYKhgbErRLDR/F7pQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-linux-musl-riscv64": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.92.1.tgz", - "integrity": "sha512-R+RcJA4EYpJDE9JM1GgPYgZo7x94FlxZ6jPodOQkEaZ1S9kvXVCuP5X/0PXRPhu08KJOfeMsAElzfdAjUf7KJg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-linux-musl-x64": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.92.1.tgz", - "integrity": "sha512-/HolYRGXJjx8nLw6oj5ZrkR7PFM7X/5kE4MYZaFMpDIPIcw3bqB2fUXLo/MYlRLsw7gBAT6hJAMBrNdKuTphfw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-linux-riscv64": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.92.1.tgz", - "integrity": "sha512-b9bxe0CMsbSsLx3nrR0cq8xpIkoAC6X36o4DGMITF3m2v3KsojC7ru9X0Gz+zUFr6rwpq/0lTNzFLNu6sPNo3w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-linux-x64": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.92.1.tgz", - "integrity": "sha512-xuiK5Jp5NldW4bvlC7AuX1Wf7o0gLZ3md/hNg+bkTvxtCDgnUHtfdo8Q+xWP11bD9QX31xXFWpmUB8UDLi6XQQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-unknown-all": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.92.1.tgz", - "integrity": "sha512-AT9oXvtNY4N+Nd0wvoWqq9A5HjdH/X3aUH4boQUtXyaJ/9DUwnQmBpP5Gtn028ZS8exOGBdobmmWAuigv0k/OA==", - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "!android", - "!darwin", - "!linux", - "!win32" - ], - "dependencies": { - "sass": "1.92.1" - } - }, - "node_modules/sass-embedded-win32-arm64": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.92.1.tgz", - "integrity": "sha512-KvmpQjY9yTBMtTYz4WBqetlv9bGaDW1aStcu7MSTbH7YiSybX/9fnxlCAEQv1WlIidQhcJAiyk0Eae+LGK7cIQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded-win32-x64": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.92.1.tgz", - "integrity": "sha512-B6Nz/GbH7Vkpb2TkQHsGcczWM5t+70VWopWF1x5V5yxLpA8ZzVQ7NTKKi+jDoVY2Efu6ZyzgT9n5KgG2kWliXA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/sass-embedded/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/sass-true": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/sass-true/-/sass-true-9.0.0.tgz", - "integrity": "sha512-p+ReCwIrk2/m85uQ3w1hGqiTFhqiY4Pc7juHcvDYvrVWy4DvVmCyLbkypdHWOFnT2OV5DpgqyNk2JN+zm4GUig==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@adobe/css-tools": "^4.4.3", - "jest-diff": "^30.0.2", - "lodash": "^4.17.21" - }, - "engines": { - "node": ">=20" - }, - "peerDependencies": { - "sass": ">=1.45.0", - "sass-embedded": ">=1.45.0" - }, - "peerDependenciesMeta": { - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - } - } - }, - "node_modules/sass-true/node_modules/@jest/schemas": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", - "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.34.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/sass-true/node_modules/@sinclair/typebox": { - "version": "0.34.41", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", - "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", - "dev": true, - "license": "MIT" - }, - "node_modules/sass-true/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/sass-true/node_modules/jest-diff": { - "version": "30.1.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.1.2.tgz", - "integrity": "sha512-4+prq+9J61mOVXCa4Qp8ZjavdxzrWQXrI80GNxP8f4tkI2syPuPrJgdRPZRrfUTRvIoUwcmNLbqEJy9W800+NQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/diff-sequences": "30.0.1", - "@jest/get-type": "30.1.0", - "chalk": "^4.1.2", - "pretty-format": "30.0.5" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/sass-true/node_modules/pretty-format": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz", - "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "30.0.5", - "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/sassdoc-extras": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/sassdoc-extras/-/sassdoc-extras-2.5.1.tgz", - "integrity": "sha512-/+ilEnk1H1hG9nympL1GIFWhAczzoclyDzgzfphIg46nsT/dWJuzWYHyzIpduc/nTVwKeQfmTz0ZVvy12QMkrQ==", - "dev": true, - "dependencies": { - "marked": "^0.6.2" - } - }, - "node_modules/sassdoc-plugin-localization": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sassdoc-plugin-localization/-/sassdoc-plugin-localization-2.0.0.tgz", - "integrity": "sha512-jC/Mi8jYaux1SIt+eH9gj1g4UgzfBxm00oHxfqOXQSGrSEGkM+YfPe8iOcZzflEiXRPgR6ckLoHCdSM1YkSGTg==", - "dev": true, - "dependencies": { - "fs-extra": "^7.0.1" - } - }, - "node_modules/sassdoc-plugin-localization/node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/sassdoc-plugin-localization/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dev": true, - "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/shx": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", - "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", - "dev": true, - "dependencies": { - "minimist": "^1.2.3", - "shelljs": "^0.8.5" - }, - "bin": { - "shx": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", - "dev": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/style-search": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", - "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==", - "dev": true - }, - "node_modules/stylelint": { - "version": "15.6.2", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-15.6.2.tgz", - "integrity": "sha512-fjQWwcdUye4DU+0oIxNGwawIPC5DvG5kdObY5Sg4rc87untze3gC/5g/ikePqVjrAsBUZjwMN+pZsAYbDO6ArQ==", - "dev": true, - "dependencies": { - "@csstools/css-parser-algorithms": "^2.1.1", - "@csstools/css-tokenizer": "^2.1.1", - "@csstools/media-query-list-parser": "^2.0.4", - "@csstools/selector-specificity": "^2.2.0", - "balanced-match": "^2.0.0", - "colord": "^2.9.3", - "cosmiconfig": "^8.1.3", - "css-functions-list": "^3.1.0", - "css-tree": "^2.3.1", - "debug": "^4.3.4", - "fast-glob": "^3.2.12", - "fastest-levenshtein": "^1.0.16", - "file-entry-cache": "^6.0.1", - "global-modules": "^2.0.0", - "globby": "^11.1.0", - "globjoin": "^0.1.4", - "html-tags": "^3.3.1", - "ignore": "^5.2.4", - "import-lazy": "^4.0.0", - "imurmurhash": "^0.1.4", - "is-plain-object": "^5.0.0", - "known-css-properties": "^0.27.0", - "mathml-tag-names": "^2.1.3", - "meow": "^9.0.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", - "postcss-media-query-parser": "^0.2.3", - "postcss-resolve-nested-selector": "^0.1.1", - "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.12", - "postcss-value-parser": "^4.2.0", - "resolve-from": "^5.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "style-search": "^0.1.0", - "supports-hyperlinks": "^3.0.0", - "svg-tags": "^1.0.0", - "table": "^6.8.1", - "v8-compile-cache": "^2.3.0", - "write-file-atomic": "^5.0.1" - }, - "bin": { - "stylelint": "bin/stylelint.js" - }, - "engines": { - "node": "^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/stylelint" - } - }, - "node_modules/stylelint-config-recommended": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-10.0.1.tgz", - "integrity": "sha512-TQ4xQ48tW4QSlODcti7pgSRqBZcUaBzuh0jPpfiMhwJKBPkqzTIAU+IrSWL/7BgXlOM90DjB7YaNgFpx8QWhuA==", - "dev": true, - "peerDependencies": { - "stylelint": "^15.0.0" - } - }, - "node_modules/stylelint-config-recommended-scss": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-9.0.1.tgz", - "integrity": "sha512-qAmz/TdrqslwiMTuLM3QXeISUkfEDUXGMfRBCHm/xrkCJNnQefv+mzG2mWTsWkqcVk8HAyUkug10dwAcYp2fCQ==", - "dev": true, - "dependencies": { - "postcss-scss": "^4.0.2", - "stylelint-config-recommended": "^10.0.1", - "stylelint-scss": "^4.4.0" - }, - "peerDependencies": { - "postcss": "^8.3.3", - "stylelint": "^15.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - } - } - }, - "node_modules/stylelint-config-standard": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-30.0.1.tgz", - "integrity": "sha512-NbeHOmpRQhjZh5XB1B/S4MLRWvz4xxAxeDBjzl0tY2xEcayNhLbaRGF0ZQzq+DQZLCcPpOHeS2Ru1ydbkhkmLg==", - "dev": true, - "dependencies": { - "stylelint-config-recommended": "^10.0.1" - }, - "peerDependencies": { - "stylelint": "^15.0.0" - } - }, - "node_modules/stylelint-config-standard-scss": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/stylelint-config-standard-scss/-/stylelint-config-standard-scss-7.0.1.tgz", - "integrity": "sha512-m5sRdtsB1F5fnC1Ozla7ryftU47wVpO+HWd+JQTqeoG0g/oPh5EfbWfcVHbNCEtuoHfALIySiUWS20pz2hX6jA==", - "dev": true, - "dependencies": { - "stylelint-config-recommended-scss": "^9.0.0", - "stylelint-config-standard": "^30.0.1" - }, - "peerDependencies": { - "postcss": "^8.3.3", - "stylelint": "^15.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - } - } - }, - "node_modules/stylelint-scss": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-4.7.0.tgz", - "integrity": "sha512-TSUgIeS0H3jqDZnby1UO1Qv3poi1N8wUYIJY6D1tuUq2MN3lwp/rITVo0wD+1SWTmRm0tNmGO0b7nKInnqF6Hg==", - "dev": true, - "dependencies": { - "postcss-media-query-parser": "^0.2.3", - "postcss-resolve-nested-selector": "^0.1.1", - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0" - }, - "peerDependencies": { - "stylelint": "^14.5.1 || ^15.0.0" - } - }, - "node_modules/stylelint/node_modules/balanced-match": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", - "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", - "dev": true - }, - "node_modules/stylelint/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/stylelint/node_modules/postcss-safe-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", - "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", - "dev": true, - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.3.3" - } - }, - "node_modules/stylelint/node_modules/signal-exit": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz", - "integrity": "sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/stylelint/node_modules/write-file-atomic": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", - "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz", - "integrity": "sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=14.18" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/svg-tags": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", - "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", - "dev": true - }, - "node_modules/sync-child-process": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz", - "integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "sync-message-port": "^1.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/sync-message-port": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.1.3.tgz", - "integrity": "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/synckit": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", - "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", - "dev": true, - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.5.tgz", - "integrity": "sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", - "dev": true, - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/v8-to-istanbul": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", - "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/varint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", - "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==", - "dev": true, - "license": "MIT" - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true - }, - "@adobe/css-tools": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", - "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", - "dev": true - }, - "@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/compat-data": { - "version": "7.21.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.7.tgz", - "integrity": "sha512-KYMqFYTaenzMK4yUtf4EW9wc4N9ef80FsbMtkwool5zpwl4YrT1SdWYSTRcT94KO4hannogdS+LxY7L+arP3gA==", - "dev": true - }, - "@babel/core": { - "version": "7.21.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.8.tgz", - "integrity": "sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.5", - "@babel/helper-compilation-targets": "^7.21.5", - "@babel/helper-module-transforms": "^7.21.5", - "@babel/helpers": "^7.21.5", - "@babel/parser": "^7.21.8", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - } - }, - "@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", - "dev": true, - "requires": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.5.tgz", - "integrity": "sha512-1RkbFGUKex4lvsB9yhIfWltJM5cZKUftB2eNajaDv3dCMEp49iBG0K14uH8NnX9IPux2+mK7JGEOB0jn48/J6w==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.21.5", - "@babel/helper-validator-option": "^7.21.0", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "dependencies": { - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true - }, - "@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, - "requires": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-module-imports": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", - "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", - "dev": true, - "requires": { - "@babel/types": "^7.21.4" - } - }, - "@babel/helper-module-transforms": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.5.tgz", - "integrity": "sha512-bI2Z9zBGY2q5yMHoBvJ2a9iX3ZOAzJPm7Q8Yz6YeoUjU/Cvhmi2G4QyTNyPBqqXSgTjUxRg3L0xV45HvkNWWBw==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.21.5", - "@babel/helper-module-imports": "^7.21.4", - "@babel/helper-simple-access": "^7.21.5", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz", - "integrity": "sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg==", - "dev": true - }, - "@babel/helper-simple-access": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.21.5.tgz", - "integrity": "sha512-ENPDAMC1wAjR0uaCUwliBdiSl1KBJAVnMTzXqi64c2MG8MPR6ii4qf7bSXDqSFbr4W6W028/rf5ivoHop5/mkg==", - "dev": true, - "requires": { - "@babel/types": "^7.21.5" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", - "dev": true - }, - "@babel/helpers": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.5.tgz", - "integrity": "sha512-BSY+JSlHxOmGsPTydUkPf1MdMQ3M81x5xGCOVgWM3G8XH77sJ292Y2oqcp0CbbgxhqBuI46iUz1tT7hqP7EfgA==", - "dev": true, - "requires": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5" - } - }, - "@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz", - "integrity": "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==", - "dev": true - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz", - "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", - "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/template": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", - "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0" - } - }, - "@babel/traverse": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.0.tgz", - "integrity": "sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0", - "debug": "^4.3.1", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@bufbuild/protobuf": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.7.0.tgz", - "integrity": "sha512-qn6tAIZEw5i/wiESBF4nQxZkl86aY4KoO0IkUa2Lh+rya64oTOdJQFlZuMwI1Qz9VBJQrQC4QlSA2DNek5gCOA==", - "dev": true - }, - "@csstools/css-parser-algorithms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.1.1.tgz", - "integrity": "sha512-viRnRh02AgO4mwIQb2xQNJju0i+Fh9roNgmbR5xEuG7J3TGgxjnE95HnBLgsFJOJOksvcfxOUCgODcft6Y07cA==", - "dev": true, - "requires": {} - }, - "@csstools/css-tokenizer": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.1.1.tgz", - "integrity": "sha512-GbrTj2Z8MCTUv+52GE0RbFGM527xuXZ0Xa5g0Z+YN573uveS4G0qi6WNOMyz3yrFM/jaILTTwJ0+umx81EzqfA==", - "dev": true - }, - "@csstools/media-query-list-parser": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.0.4.tgz", - "integrity": "sha512-GyYot6jHgcSDZZ+tLSnrzkR7aJhF2ZW6d+CXH66mjy5WpAQhZD4HDke2OQ36SivGRWlZJpAz7TzbW6OKlEpxAA==", - "dev": true, - "requires": {} - }, - "@csstools/selector-specificity": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", - "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", - "dev": true, - "requires": {} - }, - "@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^3.3.0" - } - }, - "@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - } - } - }, - "@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true - }, - "@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", - "dev": true - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/console": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", - "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0" - } - }, - "@jest/core": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", - "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", - "dev": true, - "requires": { - "@jest/console": "^29.5.0", - "@jest/reporters": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.5.0", - "jest-config": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-resolve-dependencies": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "jest-watcher": "^29.5.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "@jest/diff-sequences": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", - "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", - "dev": true - }, - "@jest/environment": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", - "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", - "dev": true, - "requires": { - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0" - } - }, - "@jest/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", - "dev": true, - "requires": { - "expect": "^29.5.0", - "jest-snapshot": "^29.5.0" - } - }, - "@jest/expect-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", - "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", - "dev": true, - "requires": { - "jest-get-type": "^29.4.3" - } - }, - "@jest/fake-timers": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", - "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - } - }, - "@jest/get-type": { - "version": "30.1.0", - "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", - "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", - "dev": true - }, - "@jest/globals": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", - "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/types": "^29.5.0", - "jest-mock": "^29.5.0" - } - }, - "@jest/reporters": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", - "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - } - }, - "@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.25.16" - } - }, - "@jest/source-map": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", - "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - } - }, - "@jest/test-result": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", - "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", - "dev": true, - "requires": { - "@jest/console": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/test-sequencer": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", - "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", - "dev": true, - "requires": { - "@jest/test-result": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "slash": "^3.0.0" - } - }, - "@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "dependencies": { - "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - } - } - }, - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - }, - "dependencies": { - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - } - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@parcel/watcher": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", - "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", - "dev": true, - "optional": true, - "requires": { - "@parcel/watcher-android-arm64": "2.5.1", - "@parcel/watcher-darwin-arm64": "2.5.1", - "@parcel/watcher-darwin-x64": "2.5.1", - "@parcel/watcher-freebsd-x64": "2.5.1", - "@parcel/watcher-linux-arm-glibc": "2.5.1", - "@parcel/watcher-linux-arm-musl": "2.5.1", - "@parcel/watcher-linux-arm64-glibc": "2.5.1", - "@parcel/watcher-linux-arm64-musl": "2.5.1", - "@parcel/watcher-linux-x64-glibc": "2.5.1", - "@parcel/watcher-linux-x64-musl": "2.5.1", - "@parcel/watcher-win32-arm64": "2.5.1", - "@parcel/watcher-win32-ia32": "2.5.1", - "@parcel/watcher-win32-x64": "2.5.1", - "detect-libc": "^1.0.3", - "is-glob": "^4.0.3", - "micromatch": "^4.0.5", - "node-addon-api": "^7.0.0" - } - }, - "@parcel/watcher-android-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", - "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", - "dev": true, - "optional": true - }, - "@parcel/watcher-darwin-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", - "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", - "dev": true, - "optional": true - }, - "@parcel/watcher-darwin-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", - "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", - "dev": true, - "optional": true - }, - "@parcel/watcher-freebsd-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", - "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", - "dev": true, - "optional": true - }, - "@parcel/watcher-linux-arm-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", - "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", - "dev": true, - "optional": true - }, - "@parcel/watcher-linux-arm-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", - "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", - "dev": true, - "optional": true + "linux" + ] }, - "@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", - "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.5.tgz", + "integrity": "sha512-Pg6E+oP7GvZ4XwgRJBuSXZjcqpIW3yCBhK4BcsANvb47qMvAbCjR6E+1a/U2WXz1JJxp9/4Dno3/iSJLcm5auw==", + "cpu": [ + "x64" + ], "dev": true, - "optional": true + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "@parcel/watcher-linux-arm64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", - "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.5.tgz", + "integrity": "sha512-txGtluxDKTxaMDzUduGP0wdfng24y1rygUMnmlUJ88fzCCULCLn7oE5kb2+tRB+MWq1QDZT6ObT5RrR8HFRKqg==", + "cpu": [ + "x64" + ], "dev": true, - "optional": true + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "@parcel/watcher-linux-x64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", - "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.5.tgz", + "integrity": "sha512-3DFiLPnTxiOQV993fMc+KO8zXHTcIjgaInrqlG8zDp1TlhYl6WgrOHuJkJQ6M8zHEcntSJsUp1XFZSY8C1DYbg==", + "cpu": [ + "arm64" + ], "dev": true, - "optional": true + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] }, - "@parcel/watcher-linux-x64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", - "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.5.tgz", + "integrity": "sha512-nggc/wPpNTgjGg75hu+Q/3i32R00Lq1B6N1DO7MCU340MRKL3WZJMjA9U4K4gzy3dkZPXm9E1Nc81FItBVGRlA==", + "cpu": [ + "arm64" + ], "dev": true, - "optional": true + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "@parcel/watcher-win32-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", - "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.5.tgz", + "integrity": "sha512-U/54pTbdQpPLBdEzCT6NBCFAfSZMvmjr0twhnD9f4EIvlm9wy3jjQ38yQj1AGznrNO65EWQMgm/QUjuIVrYF9w==", + "cpu": [ + "ia32" + ], "dev": true, - "optional": true + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "@parcel/watcher-win32-ia32": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", - "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.5.tgz", + "integrity": "sha512-2NqKgZSuLH9SXBBV2dWNRCZmocgSOx8OJSdpRaEcRlIfX8YrKxUT6z0F1NpvDVhOsl190UFTRh2F2WDWWCYp3A==", + "cpu": [ + "x64" + ], "dev": true, - "optional": true + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "@parcel/watcher-win32-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", - "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.5.tgz", + "integrity": "sha512-JRpZUhCfhZ4keB5v0fe02gQJy05GqboPOaxvjugW04RLSYYoB/9t2lx2u/tMs/Na/1NXfY8QYjgRljRpN+MjTQ==", + "cpu": [ + "x64" + ], "dev": true, - "optional": true + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" }, - "@simeonoff/themeleon": { + "node_modules/@simeonoff/themeleon": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@simeonoff/themeleon/-/themeleon-3.0.3.tgz", "integrity": "sha512-HflceRGqppzL5D96PjSzo7p6yjsjkNTAVX2q3iRma1QvP4Wd5OKzQDd0NSmPcQ2FBTrbkERKxE8RclFBpxtArg==", "dev": true, - "requires": { + "license": "Unlicense", + "dependencies": { "ap": "^0.2.0", "consolidate": "^0.13.0", "fs-extra": "^0.13.0", "glob": "^4.3.1", "merge": "^2.1.1", "q": "^1.1.2" - }, - "dependencies": { - "glob": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", - "integrity": "sha512-I0rTWUKSZKxPSIAIaqhSXTM/DiII6wame+rEC3cFA5Lqmr9YmdL7z6Hj9+bdWtTvoY1Su4/OiMLmb37Y7JzvJQ==", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^2.0.1", - "once": "^1.3.0" - } - }, - "minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha512-jQo6o1qSVLEWaw3l+bwYA2X0uLuK2KjNh2wjgO7Q/9UJnXr1Q3yQKR8BI0/Bt/rPg75e6SMW4hW/6cBHVTZUjA==", - "dev": true, - "requires": { - "brace-expansion": "^1.0.0" - } - } } }, - "@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", - "dev": true + "node_modules/@sinclair/typebox": { + "version": "0.34.41", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "dev": true, + "license": "MIT" }, - "@sinonjs/commons": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", - "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "dev": true, - "requires": { - "type-detect": "4.0.8" - } + "license": "MIT" }, - "@sinonjs/fake-timers": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.1.0.tgz", - "integrity": "sha512-w1qd368vtrwttm1PRJWPW1QHlbmHrVDGs1eBH/jZvRPUFS4MNXV9Q33EQdjOdeAxZ7O8+3wM7zxztm2nfUSyKw==", + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", "dev": true, - "requires": { - "@sinonjs/commons": "^3.0.0" + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" } }, - "@types/babel__core": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", - "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", "dev": true, - "requires": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } + "license": "MIT" }, - "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } + "license": "MIT" }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } + "license": "MIT" }, - "@types/babel__traverse": { - "version": "7.18.5", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.5.tgz", - "integrity": "sha512-enCvTL8m/EHS/zIvJno9nE+ndYPh1/oNFzRYRmtUqJICG2VnCSBzMLW5VN2KCQU91f23tsNKR8v7VJJQMatl7Q==", + "node_modules/@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } + "license": "MIT" }, - "@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "node_modules/@types/node": { + "version": "22.19.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.3.tgz", + "integrity": "sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==", "dev": true, - "requires": { - "@types/node": "*" + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~6.21.0" } }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } + "license": "ISC" }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "node_modules/@vitest/coverage-v8": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.16.tgz", + "integrity": "sha512-2rNdjEIsPRzsdu6/9Eq0AYAzYdpP6Bx9cje9tL3FE5XzXRQF1fNU9pe/1yE8fCrS0HD+fBtt6gLPh6LI57tX7A==", "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.0.16", + "ast-v8-to-istanbul": "^0.3.8", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.1", + "obug": "^2.1.1", + "std-env": "^3.10.0", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.0.16", + "vitest": "4.0.16" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } } }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", - "dev": true + "node_modules/@vitest/expect": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.16.tgz", + "integrity": "sha512-eshqULT2It7McaJkQGLkPjPjNph+uevROGuIMJdG3V+0BSR2w9u6J9Lwu+E8cK5TETlfou8GRijhafIMhXsimA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.16", + "@vitest/utils": "4.0.16", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } }, - "@types/node": { - "version": "18.14.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", - "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==", - "dev": true + "node_modules/@vitest/mocker": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.16.tgz", + "integrity": "sha512-yb6k4AZxJTB+q9ycAvsoxGn+j/po0UaPgajllBgt1PzoMAAmJGYFdDk0uCcRcxb3BrME34I6u8gHZTQlkqSZpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.0.16", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } }, - "@types/normalize-package-data": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", - "dev": true + "node_modules/@vitest/pretty-format": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.16.tgz", + "integrity": "sha512-eNCYNsSty9xJKi/UdVD8Ou16alu7AYiS2fCPRs0b1OdhJiV89buAXQLpTbe+X8V9L6qrs9CqyvU7OaAopJYPsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } }, - "@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", - "dev": true + "node_modules/@vitest/runner": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.16.tgz", + "integrity": "sha512-VWEDm5Wv9xEo80ctjORcTQRJ539EGPB3Pb9ApvVRAY1U/WkHXmmYISqU5E79uCwcW7xYUV38gwZD+RV755fu3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.16", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true + "node_modules/@vitest/snapshot": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.16.tgz", + "integrity": "sha512-sf6NcrYhYBsSYefxnry+DR8n3UV4xWZwWxYbCJUt2YdvtqzSPR7VfGrY0zsv090DAbjFZsi7ZaMi1KnSRyK1XA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.16", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } }, - "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "node_modules/@vitest/spy": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.16.tgz", + "integrity": "sha512-4jIOWjKP0ZUaEmJm00E0cOBLU+5WE0BpeNr3XN6TEF05ltro6NJqHWxXD0kA8/Zc8Nh23AT8WQxwNG+WeROupw==", "dev": true, - "requires": { - "@types/yargs-parser": "*" + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" } }, - "@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true + "node_modules/@vitest/utils": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.16.tgz", + "integrity": "sha512-h8z9yYhV3e1LEfaQ3zdypIrnAg/9hguReGZoS7Gl0aBG5xgA410zBqECqmaF/+RkTggRsfnzc1XaAHA6bmUufA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.16", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } }, - "@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } }, - "acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } }, - "acorn-jsx": { + "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, - "requires": {} + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } }, - "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, - "ansi-regex": { + "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "ansi-styles": { + "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "ap": { + "node_modules/ap": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/ap/-/ap-0.2.0.tgz", "integrity": "sha512-ImdvquIuBSVpWRWhB441UjvTcZqic1RL+lTQaUKGdGEp1aiTvt/phAvY8Vvs32qya5FJBI8U+tzNBYzFDQY/lQ==", - "dev": true + "dev": true, + "license": "MIT/X11" }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } + "license": "Python-2.0" }, - "array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "dev": true, - "requires": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-string": "^1.0.7" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "array-union": { + "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "array.prototype.filter": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz", - "integrity": "sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "array.prototype.findlastindex": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz", - "integrity": "sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ==", + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", "dev": true, - "requires": { - "call-bind": "^1.0.5", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", + "es-abstract": "^1.23.9", "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "arrify": { + "node_modules/arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } }, - "available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "node_modules/ast-v8-to-istanbul": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.9.tgz", + "integrity": "sha512-dSC6tJeOJxbZrPzPbv5mMd6CMiQ1ugaVXXPRad2fXUSsy1kstFn9XQWemV9VW7Y7kpxgQ/4WMoZfwdH8XSU48w==", "dev": true, - "requires": { - "possible-typed-array-names": "^1.0.0" + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^9.0.1" } }, - "babel-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", - "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, - "requires": { - "@jest/transform": "^29.5.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.5.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, - "babel-plugin-jest-hoist": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", - "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", - "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^29.5.0", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "balanced-match": { + "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, - "bluebird": { + "node_modules/bluebird": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", "integrity": "sha512-UfFSr22dmHPQqPP9XWHRhq+gWnHCYguQGkXQlbyPtW5qTnhFWA8/iXg765tH0cAjy7l/zPJ1aBTO0g5XgA7kvQ==", - "dev": true + "dev": true, + "license": "MIT" }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/body-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", + "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "braces": { + "node_modules/braces": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "requires": { + "devOptional": true, + "license": "MIT", + "dependencies": { "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-builder": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/buffer-builder/-/buffer-builder-0.2.0.tgz", + "integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==", + "license": "MIT/X11" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz", + "integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==", "dev": true, - "requires": { - "node-int64": "^0.4.0" + "license": "MIT", + "dependencies": { + "camelcase": "^6.3.0", + "map-obj": "^4.1.0", + "quick-lru": "^5.1.1", + "type-fest": "^1.2.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "buffer-builder": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/buffer-builder/-/buffer-builder-0.2.0.tgz", - "integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==", - "dev": true - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "node_modules/camelcase-keys/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", "dev": true, - "requires": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "node_modules/chai": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.1.tgz", + "integrity": "sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==", "dev": true, - "requires": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" + "license": "MIT", + "engines": { + "node": ">=18" } }, - "caniuse-lite": { - "version": "1.0.30001488", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001488.tgz", - "integrity": "sha512-NORIQuuL4xGpIy6iCCQGN4iFjlBXtfKWIenlUuyZJumLRIindLb7wXM+GO8erEhb7vXfcnf4BAg2PrSDN5TNLQ==", - "dev": true - }, - "chalk": { + "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "chokidar": { + "node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, + "license": "MIT", "optional": true, - "requires": { + "dependencies": { "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true - }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "color-convert": { + "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "color-name": { + "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, - "colord": { + "node_modules/colord": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", - "dev": true + "dev": true, + "license": "MIT" }, - "colorjs.io": { + "node_modules/colorjs.io": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz", "integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==", - "dev": true + "license": "MIT" }, - "concat-map": { + "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, - "consolidate": { + "node_modules/consolidate": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.13.1.tgz", "integrity": "sha512-027d1hT0huixz578MzXlB30ipJaF0131zmQJhiL49fwjDj+I45MwgL3/TQHEgeuZfcJus69vBlHcIPd+h2UNCw==", + "deprecated": "Please upgrade to consolidate v1.0.0+ as it has been modernized with several long-awaited fixes implemented. Maintenance is supported by Forward Email at https://forwardemail.net ; follow/watch https://github.com/ladjs/consolidate for updates and release changelog", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "bluebird": "^2.9.26" } }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" + "node_modules/content-disposition": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" } }, - "cosmiconfig": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", - "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dev": true, - "requires": { - "import-fresh": "^3.2.1", + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", + "parse-json": "^5.2.0", "path-type": "^4.0.0" }, - "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true } } }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" } }, - "css-functions-list": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.1.0.tgz", - "integrity": "sha512-/9lCvYZaUbBGvYUgYGFJ4dcYiyqdhSjG7IPVluoV8A1ILjkF7ilmhp1OGUz8n+nmBcu0RNrQAzgD8B6FJbrt2w==", - "dev": true + "node_modules/css-functions-list": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.3.tgz", + "integrity": "sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12 || >=16" + } }, - "css-tree": { + "node_modules/css-tree": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, - "cssesc": { + "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "dev": true, - "requires": { - "ms": "2.1.2" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } }, - "decamelize-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", - "integrity": "sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==", + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "dev": true, - "requires": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", "dependencies": { - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "deep-is": { + "node_modules/decamelize": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz", + "integrity": "sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true + "dev": true, + "license": "MIT" }, - "define-data-property": { + "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "define-properties": { + "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "detect-libc": { + "node_modules/detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "dev": true, - "optional": true - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", - "dev": true + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } }, - "dir-glob": { + "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "doctrine": { + "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, - "requires": { + "license": "Apache-2.0", + "dependencies": { "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" } }, - "electron-to-chromium": { - "version": "1.4.399", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.399.tgz", - "integrity": "sha512-+V1aNvVgoWNWYIbMOiQ1n5fRIaY4SlQ/uRlrsCjLrUwr/3OvQgiX2f5vdav4oArVT9TnttJKcPCqjwPNyZqw/A==", - "dev": true + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } }, - "emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" }, - "emoji-regex": { + "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "is-arrayish": "^0.2.1" } }, - "es-abstract": { - "version": "1.22.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.5.tgz", - "integrity": "sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==", + "node_modules/es-abstract": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", + "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "es-define-property": "^1.0.0", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", + "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.0.3", - "has-symbols": "^1.0.3", - "hasown": "^2.0.1", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.0", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.5", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.14" - } - }, - "es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "dev": true + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.2.4" + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, - "es-errors": { + "node_modules/es-errors": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", "dev": true, - "requires": { - "get-intrinsic": "^1.2.4", + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", "dev": true, - "requires": { - "hasown": "^2.0.0" + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true + "node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, - "requires": { + "license": "MIT", + "peer": true, + "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -10317,2537 +3040,3512 @@ "strip-ansi": "^6.0.1", "text-table": "^0.2.0" }, - "dependencies": { - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - } + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "node_modules/eslint-config-prettier": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz", + "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", "dev": true, - "requires": {} + "license": "MIT", + "peer": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } }, - "eslint-import-resolver-node": { + "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", "resolve": "^1.22.4" - }, + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } + "ms": "^2.1.1" } }, - "eslint-module-utils": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", - "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "debug": "^3.2.7" }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true } } }, - "eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, - "requires": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", + "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" }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - } + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "eslint-plugin-prettier": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", - "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "node_modules/eslint-plugin-prettier": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz", + "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" + "synckit": "^0.11.7" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } } }, - "eslint-scope": { + "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, - "requires": { + "license": "BSD-2-Clause", + "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "eslint-visitor-keys": { + "node_modules/eslint-visitor-keys": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } }, - "espree": { + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, - "requires": { + "license": "BSD-2-Clause", + "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, - "requires": { + "license": "BSD-3-Clause", + "dependencies": { "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" } }, - "esrecurse": { + "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "requires": { + "license": "BSD-2-Clause", + "dependencies": { "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" } }, - "estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } }, - "esutils": { + "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } }, - "expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", "dev": true, - "requires": { - "@jest/expect-utils": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0" + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "peer": true, + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", + "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" } }, - "extend": { + "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true + "dev": true, + "license": "MIT" }, - "fast-deep-equal": { + "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "license": "MIT" }, - "fast-diff": { + "node_modules/fast-diff": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, - "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, - "fast-json-stable-stringify": { + "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, - "fast-levenshtein": { + "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" }, - "fastest-levenshtein": { + "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "dev": true, - "requires": { + "license": "ISC", + "dependencies": { "reusify": "^1.0.4" } }, - "fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, - "requires": { - "bser": "2.1.1" + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, - "requires": { - "flat-cache": "^3.0.4" + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, - "requires": { - "to-regex-range": "^5.0.1" + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" } }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } + "license": "ISC" }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, + "license": "MIT", "dependencies": { - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "flatted": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", - "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", - "dev": true + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "requires": { - "is-callable": "^1.1.3" + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "fs-extra": { + "node_modules/fs-extra": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.13.0.tgz", "integrity": "sha512-JiEPAzy0hZ0EN25pkXkgmzxn/ThqTbDrTqGnEO9eFMR33mfG72A2YFjQ23+zTsnDtcOesBKUtRXWTh6V4bQUVg==", "dev": true, - "requires": { + "dependencies": { "jsonfile": "^2.0.0", "ncp": "^1.0.1", "rimraf": "^2.2.8" } }, - "fs.realpath": { + "node_modules/fs-extra/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fs-extra/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "dev": true, + "license": "ISC" }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, - "optional": true + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, - "function-bind": { + "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "functions-have-names": { + "node_modules/functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", "dev": true, - "requires": { + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "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", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } }, - "get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, - "requires": { - "call-bind": "^1.0.5", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", "dev": true, - "requires": { - "fs.realpath": "^1.0.0", + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", + "integrity": "sha512-I0rTWUKSZKxPSIAIaqhSXTM/DiII6wame+rEC3cFA5Lqmr9YmdL7z6Hj9+bdWtTvoY1Su4/OiMLmb37Y7JzvJQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^2.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": "*" } }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, - "requires": { - "is-glob": "^4.0.1" + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" } }, - "global-modules": { + "node_modules/glob/node_modules/minimatch": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "integrity": "sha512-jQo6o1qSVLEWaw3l+bwYA2X0uLuK2KjNh2wjgO7Q/9UJnXr1Q3yQKR8BI0/Bt/rPg75e6SMW4hW/6cBHVTZUjA==", + "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/global-modules": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "global-prefix": { + "node_modules/global-prefix": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "ini": "^1.3.5", "kind-of": "^6.0.2", "which": "^1.3.1" }, - "dependencies": { - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, - "requires": { - "define-properties": "^1.1.3" + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "globby": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", - "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", + "node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", "merge2": "^1.4.1", "slash": "^4.0.0" }, - "dependencies": { - "slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true - } + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "globjoin": { + "node_modules/globjoin": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", - "dev": true - }, - "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, - "requires": { - "get-intrinsic": "^1.1.3" + "license": "MIT" + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" }, - "graphemer": { + "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, - "handlebars": { + "node_modules/handlebars": { "version": "4.7.8", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", - "uglify-js": "^3.1.4", "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" } }, - "hard-rejection": { + "node_modules/hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "has-flag": { + "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "has-property-descriptors": { + "node_modules/has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "dev": true + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "has-tostringtag": { + "node_modules/has-tostringtag": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "hasown": { + "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hono": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.1.tgz", + "integrity": "sha512-KsFcH0xxHes0J4zaQgWbYwmz3UPOOskdqZmItstUG93+Wk1ePBLkLGwbP9zlmh1BFUiL8Qp+Xfu9P7feJWpGNg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=16.9.0" } }, - "hosted-git-info": { + "node_modules/hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", "dev": true, - "requires": { + "license": "ISC", + "dependencies": { "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" } }, - "html-escaper": { + "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "dev": true, + "license": "MIT" }, - "html-tags": { + "node_modules/html-tags": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } }, - "husky": { + "node_modules/husky": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", - "dev": true + "dev": true, + "license": "MIT", + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", + "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } }, - "igniteui-sassdoc-theme": { + "node_modules/igniteui-sassdoc-theme": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/igniteui-sassdoc-theme/-/igniteui-sassdoc-theme-1.2.3.tgz", "integrity": "sha512-8ptCZ/fJmuAxrrZMMnKu3rL/VfOk5XwShPgbaxCL02uSzYpiBSkU0gblc5lQIiwBeci8JU+I3rwJJSo77Kpt1A==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "@simeonoff/themeleon": "^3.0.3", "extend": ">=2.0.2", "handlebars": "^4.7.8", "minimist": "^1.2.8", "sassdoc-extras": "^2.5.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } }, - "immutable": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", - "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", - "dev": true + "node_modules/immutable": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz", + "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==", + "license": "MIT" }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" }, - "dependencies": { - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - } + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "import-lazy": { + "node_modules/import-lazy": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", - "dev": true - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "imurmurhash": { + "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "inflight": { + "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, - "requires": { + "license": "ISC", + "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, - "inherits": { + "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "license": "ISC" }, - "ini": { + "node_modules/ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "dev": true, + "license": "ISC" }, - "internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" } }, - "interpret": { + "node_modules/interpret": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } }, - "is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-arrayish": { + "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "dev": true, + "license": "MIT" }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "dev": true, - "requires": { - "has-bigints": "^1.0.1" + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true - }, - "is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, - "requires": { - "hasown": "^2.0.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, - "requires": { - "is-extglob": "^2.1.1" + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "is-plain-obj": { + "node_modules/is-date-object": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true - }, - "is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", - "dev": true, - "requires": { - "call-bind": "^1.0.7" + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "requires": { - "has-symbols": "^1.0.2" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", "dev": true, - "requires": { - "which-typed-array": "^1.1.14" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" } }, - "istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", - "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, - "requires": { - "@jest/core": "^29.5.0", - "@jest/types": "^29.5.0", - "import-local": "^3.0.2", - "jest-cli": "^29.5.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "jest-changed-files": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", - "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", "dev": true, - "requires": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - }, - "dependencies": { - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - } + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "jest-circus": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", - "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.5.0", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.5.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "dependencies": { - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - } + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "jest-cli": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", - "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, - "requires": { - "@jest/core": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - } - }, - "jest-config": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", - "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.5.0", - "@jest/types": "^29.5.0", - "babel-jest": "^29.5.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.5.0", - "jest-environment-node": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-diff": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", - "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^29.4.3", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-docblock": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", - "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, - "requires": { - "detect-newline": "^3.0.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-each": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", - "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "jest-util": "^29.5.0", - "pretty-format": "^29.5.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-environment-node": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", - "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-environment-node-single-context": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-environment-node-single-context/-/jest-environment-node-single-context-29.0.0.tgz", - "integrity": "sha512-/XB09Hje38Kl5k9ISUpXNom3M4DQo5ifEsnELPFP5r3yrJDRyNQCEjL/9ScUN6z6UeF4FCNZUsiJIX/tGtTXNw==", + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, - "requires": { - "jest-environment-node": "^29.0.1" + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-get-type": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", - "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", - "dev": true - }, - "jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "jest-leak-detector": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", - "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", - "dev": true, - "requires": { - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - } - }, - "jest-matcher-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", - "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-message-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", - "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.5.0", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-mock": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", - "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-util": "^29.5.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true, - "requires": {} + "license": "MIT" }, - "jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" }, - "jest-resolve": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", - "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, - "requires": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" } }, - "jest-resolve-dependencies": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", - "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, - "requires": { - "jest-regex-util": "^29.4.3", - "jest-snapshot": "^29.5.0" + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" } }, - "jest-runner": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", - "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", "dev": true, - "requires": { - "@jest/console": "^29.5.0", - "@jest/environment": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.4.3", - "jest-environment-node": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-leak-detector": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-resolve": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-util": "^29.5.0", - "jest-watcher": "^29.5.0", - "jest-worker": "^29.5.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "dependencies": { - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - } - } - }, - "jest-runtime": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", - "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/globals": "^29.5.0", - "@jest/source-map": "^29.4.3", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - } - }, - "jest-snapshot": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", - "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.5.0", - "semver": "^7.3.5" - }, - "dependencies": { - "semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" } }, - "jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "jest-validate": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", - "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", + "node_modules/jest-diff": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "leven": "^3.1.0", - "pretty-format": "^29.5.0" - }, + "license": "MIT", "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - } + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "jest-watcher": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", - "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", - "dev": true, - "requires": { - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.5.0", - "string-length": "^4.0.1" + "node_modules/jose": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", + "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" } }, - "jest-worker": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", - "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", "dev": true, - "requires": { - "@types/node": "*", - "jest-util": "^29.5.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "license": "MIT" }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" }, - "json-parse-even-better-errors": { + "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "dev": true, + "license": "MIT" }, - "json-schema-traverse": { + "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" }, - "json-stable-stringify-without-jsonify": { + "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } }, - "jsonfile": { + "node_modules/jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", "dev": true, - "requires": { + "license": "MIT", + "optionalDependencies": { "graceful-fs": "^4.1.6" } }, - "kind-of": { + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "known-css-properties": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.27.0.tgz", - "integrity": "sha512-uMCj6+hZYDoffuvAJjFAPz56E9uoowFHmTkqRtRq5WyC5Q6Cu/fTZKNQpX/RbzChBYLLl3lo8CjFZBAZXq9qFg==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true + "node_modules/known-css-properties": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.29.0.tgz", + "integrity": "sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==", + "dev": true, + "license": "MIT" }, - "levn": { + "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "lines-and-columns": { + "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "dev": true, + "license": "MIT" }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, - "requires": { - "p-locate": "^4.1.0" + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "lodash": { + "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "dev": true, + "license": "MIT" }, - "lodash.merge": { + "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, - "lodash.truncate": { + "node_modules/lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true + "dev": true, + "license": "MIT" }, - "lru-cache": { + "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "requires": { + "license": "ISC", + "dependencies": { "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" } }, - "lunr": { + "node_modules/lunr": { "version": "2.3.9", "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "dev": true + "dev": true, + "license": "MIT" }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magicast": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.1.tgz", + "integrity": "sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "source-map-js": "^1.2.1" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, - "requires": { - "semver": "^6.0.0" + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "node_modules/make-dir/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, - "requires": { - "tmpl": "1.0.5" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "map-obj": { + "node_modules/map-obj": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "marked": { + "node_modules/marked": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/marked/-/marked-0.6.3.tgz", "integrity": "sha512-Fqa7eq+UaxfMriqzYLayfqAE40WN03jf+zHjT18/uXNuzjq3TY0XTbrAoPeqSJrAmPz11VuUA+kBPYOhHt9oOQ==", - "dev": true + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "mathml-tag-names": { + "node_modules/mathml-tag-names": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==", - "dev": true + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "mdn-data": { + "node_modules/mdn-data": { "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true + "dev": true, + "license": "CC0-1.0" }, - "meow": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", - "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/meow": { + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/meow/-/meow-10.1.5.tgz", + "integrity": "sha512-/d+PQ4GKmGvM9Bee/DPa8z3mXs/pkvJE2KEThngVNOqtmljC6K7NMPxtc2JeZYTmpWb9k/TmxjeL18ez3h7vCw==", "dev": true, - "requires": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize": "^1.2.0", + "license": "MIT", + "dependencies": { + "@types/minimist": "^1.2.2", + "camelcase-keys": "^7.0.0", + "decamelize": "^5.0.0", "decamelize-keys": "^1.1.0", "hard-rejection": "^2.1.0", "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, - "dependencies": { - "type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", - "dev": true - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true - } + "normalize-package-data": "^3.0.2", + "read-pkg-up": "^8.0.0", + "redent": "^4.0.0", + "trim-newlines": "^4.0.2", + "type-fest": "^1.2.2", + "yargs-parser": "^20.2.9" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "merge": { + "node_modules/merge": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", - "dev": true + "dev": true, + "license": "MIT" }, - "merge-stream": { + "node_modules/merge-descriptors": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "merge2": { + "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, - "requires": { - "braces": "^3.0.2", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" } }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, - "min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } }, - "minimatch": { + "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "requires": { + "license": "ISC", + "dependencies": { "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "minimist": { + "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "minimist-options": { + "node_modules/minimist-options": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "arrify": "^1.0.1", "is-plain-obj": "^1.1.0", "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, - "nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } }, - "natural-compare": { + "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, - "ncp": { + "node_modules/ncp": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ncp/-/ncp-1.0.1.tgz", "integrity": "sha512-akBX7I5X9KQDDWmYYgQlLbVbjkveTje2mioZjhLLrVt09akSZcoqXWE5LEn1E2fu8T7th1PZYGfewQsTkTLTmQ==", - "dev": true + "dev": true, + "license": "MIT", + "bin": { + "ncp": "bin/ncp" + } + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, - "neo-async": { + "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "dev": true, - "optional": true - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true + "license": "MIT" }, - "node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", - "dev": true + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT", + "optional": true }, - "normalize-package-data": { + "node_modules/normalize-package-data": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", "dev": true, - "requires": { + "license": "BSD-2-Clause", + "dependencies": { "hosted-git-info": "^4.0.1", "is-core-module": "^2.5.0", "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" }, - "dependencies": { - "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "normalize-path": { + "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, - "requires": { - "path-key": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "object-keys": { + "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "dev": true, - "requires": { - "call-bind": "^1.0.5", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" } }, - "object.groupby": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.2.tgz", - "integrity": "sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw==", + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", "dev": true, - "requires": { - "array.prototype.filter": "^1.0.3", - "call-bind": "^1.0.5", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.0.0" + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" } }, - "once": { + "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { + "license": "ISC", + "dependencies": { "wrappy": "1" } }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, - "requires": { - "@aashutoshrathi/word-wrap": "^1.2.3", + "license": "MIT", + "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" } }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", "dev": true, - "requires": { - "p-try": "^2.0.0" + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, - "requires": { - "p-limit": "^2.2.0" + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "parent-module": { + "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "parse-json": { + "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "path-exists": { + "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "path-is-absolute": { + "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "path-key": { + "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "path-parse": { + "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } }, - "path-type": { + "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" }, - "picomatch": { + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, - "pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", "dev": true, - "requires": { - "find-up": "^4.0.0" + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, - "possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "dev": true - }, - "postcss": { - "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, - "requires": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" } }, - "postcss-media-query-parser": { + "node_modules/postcss-media-query-parser": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", - "dev": true + "dev": true, + "license": "MIT" }, - "postcss-resolve-nested-selector": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz", - "integrity": "sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==", - "dev": true + "node_modules/postcss-resolve-nested-selector": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz", + "integrity": "sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==", + "dev": true, + "license": "MIT" }, - "postcss-safe-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.0.tgz", - "integrity": "sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg==", + "node_modules/postcss-safe-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", + "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", "dev": true, - "requires": {} + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } }, - "postcss-scss": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.6.tgz", - "integrity": "sha512-rLDPhJY4z/i4nVFZ27j9GqLxj1pwxE80eAzUNRMXtcpipFYIeowerzBgG3yJhMtObGEXidtIgbUpQ3eLDsf5OQ==", + "node_modules/postcss-scss": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", + "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", "dev": true, - "requires": {} + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-scss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.4.29" + } }, - "postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, - "requires": { + "license": "MIT", + "peer": true, + "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" } }, - "postcss-value-parser": { + "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "dev": true, + "license": "MIT" }, - "prelude-ls": { + "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } }, - "prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", - "dev": true + "node_modules/prettier": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", + "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } }, - "prettier-linter-helpers": { + "node_modules/prettier-linter-helpers": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" } }, - "pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "node_modules/pretty-format": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, + "license": "MIT", "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } }, - "pure-rand": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", - "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==", - "dev": true + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "q": { + "node_modules/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "dev": true + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "queue-microtask": { + "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, - "quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } }, - "react-is": { + "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true + "dev": true, + "license": "MIT" }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "node_modules/read-pkg": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-6.0.0.tgz", + "integrity": "sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "normalize-package-data": "^3.0.2", + "parse-json": "^5.2.0", + "type-fest": "^1.0.1" }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-8.0.0.tgz", + "integrity": "sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ==", + "dev": true, + "license": "MIT", "dependencies": { - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } + "find-up": "^5.0.0", + "read-pkg": "^6.0.0", + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" }, - "dependencies": { - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "optional": true - }, - "rechoir": { + "node_modules/rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", "dev": true, - "requires": { + "dependencies": { "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" } }, - "redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "node_modules/redent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-4.0.0.tgz", + "integrity": "sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==", "dev": true, - "requires": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" + "license": "MIT", + "dependencies": { + "indent-string": "^5.0.0", + "strip-indent": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", "dev": true, - "requires": { - "call-bind": "^1.0.6", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "require-from-string": { + "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, - "requires": { - "is-core-module": "^2.13.0", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, - "requires": { - "resolve-from": "^5.0.0" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", - "dev": true + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, - "requires": { + "license": "ISC", + "dependencies": { "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.5.tgz", + "integrity": "sha512-iTNAbFSlRpcHeeWu73ywU/8KuU/LZmNCSxp6fjQkJBD3ivUb8tpDrXhIxEzA05HlYMEwmtaUnb3RP+YNv162OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.53.5", + "@rollup/rollup-android-arm64": "4.53.5", + "@rollup/rollup-darwin-arm64": "4.53.5", + "@rollup/rollup-darwin-x64": "4.53.5", + "@rollup/rollup-freebsd-arm64": "4.53.5", + "@rollup/rollup-freebsd-x64": "4.53.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.53.5", + "@rollup/rollup-linux-arm-musleabihf": "4.53.5", + "@rollup/rollup-linux-arm64-gnu": "4.53.5", + "@rollup/rollup-linux-arm64-musl": "4.53.5", + "@rollup/rollup-linux-loong64-gnu": "4.53.5", + "@rollup/rollup-linux-ppc64-gnu": "4.53.5", + "@rollup/rollup-linux-riscv64-gnu": "4.53.5", + "@rollup/rollup-linux-riscv64-musl": "4.53.5", + "@rollup/rollup-linux-s390x-gnu": "4.53.5", + "@rollup/rollup-linux-x64-gnu": "4.53.5", + "@rollup/rollup-linux-x64-musl": "4.53.5", + "@rollup/rollup-openharmony-arm64": "4.53.5", + "@rollup/rollup-win32-arm64-msvc": "4.53.5", + "@rollup/rollup-win32-ia32-msvc": "4.53.5", + "@rollup/rollup-win32-x64-gnu": "4.53.5", + "@rollup/rollup-win32-x64-msvc": "4.53.5", + "fsevents": "~2.3.2" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" } }, - "run-parallel": { + "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, - "requires": { + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { "queue-microtask": "^1.2.2" } }, - "rxjs": { + "node_modules/rxjs": { "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "dev": true, - "requires": { + "license": "Apache-2.0", + "dependencies": { "tslib": "^2.1.0" } }, - "safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "dev": true, - "requires": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", "isarray": "^2.0.5" }, - "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - } + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, - "requires": { - "call-bind": "^1.0.6", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", "es-errors": "^1.3.0", - "is-regex": "^1.1.4" + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "sass": { + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sass": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass/-/sass-1.92.1.tgz", "integrity": "sha512-ffmsdbwqb3XeyR8jJR6KelIXARM9bFQe8A6Q3W4Klmwy5Ckd5gz7jgUNHo4UOqutU5Sk1DtKLbpDP0nLCg1xqQ==", - "dev": true, + "license": "MIT", "optional": true, - "requires": { - "@parcel/watcher": "^2.4.1", + "peer": true, + "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" } }, - "sass-embedded": { + "node_modules/sass-embedded": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.92.1.tgz", "integrity": "sha512-28YwLnF5atAhogt3E4hXzz/NB9dwKffyw08a7DEasLh94P7+aELkG3ENSHYCWB9QFN14hYNLfwr9ozUsPDhcDQ==", - "dev": true, - "requires": { + "license": "MIT", + "peer": true, + "dependencies": { "@bufbuild/protobuf": "^2.5.0", "buffer-builder": "^0.2.0", "colorjs.io": "^0.5.0", "immutable": "^5.0.2", "rxjs": "^7.4.0", + "supports-color": "^8.1.1", + "sync-child-process": "^1.0.2", + "varint": "^6.0.0" + }, + "bin": { + "sass": "dist/bin/sass.js" + }, + "engines": { + "node": ">=16.0.0" + }, + "optionalDependencies": { "sass-embedded-all-unknown": "1.92.1", "sass-embedded-android-arm": "1.92.1", "sass-embedded-android-arm64": "1.92.1", @@ -12865,545 +6563,939 @@ "sass-embedded-linux-x64": "1.92.1", "sass-embedded-unknown-all": "1.92.1", "sass-embedded-win32-arm64": "1.92.1", - "sass-embedded-win32-x64": "1.92.1", - "supports-color": "^8.1.1", - "sync-child-process": "^1.0.2", - "varint": "^6.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "sass-embedded-win32-x64": "1.92.1" } }, - "sass-embedded-all-unknown": { + "node_modules/sass-embedded-all-unknown": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.92.1.tgz", "integrity": "sha512-5t6/YZf+vhO3OY/49h8RCL6Cwo78luva0M+TnTM9gu9ASffRXAuOVLNKciSXa3loptyemDDS6IU5/dVH5w0KmA==", - "dev": true, + "cpu": [ + "!arm", + "!arm64", + "!riscv64", + "!x64" + ], + "license": "MIT", "optional": true, - "requires": { + "dependencies": { "sass": "1.92.1" } }, - "sass-embedded-android-arm": { + "node_modules/sass-embedded-android-arm": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.92.1.tgz", "integrity": "sha512-4EjpVVzuksERdgAd4BqeSXFnWtWN3DSRyEIUPJ7BhcS9sfDh2Gf6miI2kNTvIQLJ2XIJynDDcEQ8a1U9KwKUTQ==", - "dev": true, - "optional": true + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } }, - "sass-embedded-android-arm64": { + "node_modules/sass-embedded-android-arm64": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.92.1.tgz", "integrity": "sha512-Q+UruGb7yKawHagVmVDRRKsnc4mJZvWMBnuRCu2coJo2FofyqBmXohVGXbxko97sYceA9TJTrUEx3WVKQUNCbQ==", - "dev": true, - "optional": true + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } }, - "sass-embedded-android-riscv64": { + "node_modules/sass-embedded-android-riscv64": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.92.1.tgz", "integrity": "sha512-nCY5btLlX7W7Jc6cCL6D2Yklpiu540EJ2G08YVGu12DrAMCBzqM347CSRf2ojp1H8jyhvmLkaFwnrJWzh+6S+w==", - "dev": true, - "optional": true + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } }, - "sass-embedded-android-x64": { + "node_modules/sass-embedded-android-x64": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.92.1.tgz", "integrity": "sha512-qYWR3bftJ77aLYwYDFuzDI4dcwVVixxqQxlIQWNGkHRCexj614qGSSHemr18C2eVj3mjXAQxTQxU68U7pkGPAA==", - "dev": true, - "optional": true + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } }, - "sass-embedded-darwin-arm64": { + "node_modules/sass-embedded-darwin-arm64": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.92.1.tgz", "integrity": "sha512-g2yQ3txjMYLKMjL2cW1xRO9nnV3ijf95NbX/QShtV6tiVUETZNWDsRMDEwBNGYY6PTE/UZerjJL1R/2xpQg6WA==", - "dev": true, - "optional": true + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } }, - "sass-embedded-darwin-x64": { + "node_modules/sass-embedded-darwin-x64": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.92.1.tgz", "integrity": "sha512-eH+fgxLQhTEPjZPCgPAVuX5e514Qp/4DMAUMtlNShv4cr4TD5qOp1XlsPYR/b7uE7p2cKFkUpUn/bHNqJ2ay4A==", - "dev": true, - "optional": true + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } }, - "sass-embedded-linux-arm": { + "node_modules/sass-embedded-linux-arm": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.92.1.tgz", "integrity": "sha512-cT3w8yoQTqrtZvWLJeutEGmawITDTY4J6oSVQjeDcPnnoPt0gOFxem8YMznraACXvahw/2+KJDH33BTNgiPo0A==", - "dev": true, - "optional": true + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } }, - "sass-embedded-linux-arm64": { + "node_modules/sass-embedded-linux-arm64": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.92.1.tgz", "integrity": "sha512-dNmlpGeZkry1BofhAdGFBXrpM69y9LlYuNnncf+HfsOOUtj8j0q1RwS+zb5asknhKFUOAG8GCGRY1df7Rwu35g==", - "dev": true, - "optional": true + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } }, - "sass-embedded-linux-musl-arm": { + "node_modules/sass-embedded-linux-musl-arm": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.92.1.tgz", "integrity": "sha512-nPBos6lI31ef2zQhqTZhFOU7ar4impJbLIax0XsqS269YsiCwjhk11VmUloJTpFlJuKMiVXNo7dPx+katxhD/Q==", - "dev": true, - "optional": true + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } }, - "sass-embedded-linux-musl-arm64": { + "node_modules/sass-embedded-linux-musl-arm64": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.92.1.tgz", "integrity": "sha512-TfiEBkCyNzVoOhjHXUT+vZ6+p0ueDbvRw6f4jHdkvljZzXdXMby4wh7BU1odl69rgRTkSvYKhgbErRLDR/F7pQ==", - "dev": true, - "optional": true + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } }, - "sass-embedded-linux-musl-riscv64": { + "node_modules/sass-embedded-linux-musl-riscv64": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.92.1.tgz", "integrity": "sha512-R+RcJA4EYpJDE9JM1GgPYgZo7x94FlxZ6jPodOQkEaZ1S9kvXVCuP5X/0PXRPhu08KJOfeMsAElzfdAjUf7KJg==", - "dev": true, - "optional": true + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } }, - "sass-embedded-linux-musl-x64": { + "node_modules/sass-embedded-linux-musl-x64": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.92.1.tgz", "integrity": "sha512-/HolYRGXJjx8nLw6oj5ZrkR7PFM7X/5kE4MYZaFMpDIPIcw3bqB2fUXLo/MYlRLsw7gBAT6hJAMBrNdKuTphfw==", - "dev": true, - "optional": true + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } }, - "sass-embedded-linux-riscv64": { + "node_modules/sass-embedded-linux-riscv64": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.92.1.tgz", "integrity": "sha512-b9bxe0CMsbSsLx3nrR0cq8xpIkoAC6X36o4DGMITF3m2v3KsojC7ru9X0Gz+zUFr6rwpq/0lTNzFLNu6sPNo3w==", - "dev": true, - "optional": true + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } }, - "sass-embedded-linux-x64": { + "node_modules/sass-embedded-linux-x64": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.92.1.tgz", "integrity": "sha512-xuiK5Jp5NldW4bvlC7AuX1Wf7o0gLZ3md/hNg+bkTvxtCDgnUHtfdo8Q+xWP11bD9QX31xXFWpmUB8UDLi6XQQ==", - "dev": true, - "optional": true + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } }, - "sass-embedded-unknown-all": { + "node_modules/sass-embedded-unknown-all": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.92.1.tgz", "integrity": "sha512-AT9oXvtNY4N+Nd0wvoWqq9A5HjdH/X3aUH4boQUtXyaJ/9DUwnQmBpP5Gtn028ZS8exOGBdobmmWAuigv0k/OA==", - "dev": true, + "license": "MIT", "optional": true, - "requires": { + "os": [ + "!android", + "!darwin", + "!linux", + "!win32" + ], + "dependencies": { "sass": "1.92.1" } }, - "sass-embedded-win32-arm64": { + "node_modules/sass-embedded-win32-arm64": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.92.1.tgz", "integrity": "sha512-KvmpQjY9yTBMtTYz4WBqetlv9bGaDW1aStcu7MSTbH7YiSybX/9fnxlCAEQv1WlIidQhcJAiyk0Eae+LGK7cIQ==", - "dev": true, - "optional": true + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } }, - "sass-embedded-win32-x64": { + "node_modules/sass-embedded-win32-x64": { "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.92.1.tgz", "integrity": "sha512-B6Nz/GbH7Vkpb2TkQHsGcczWM5t+70VWopWF1x5V5yxLpA8ZzVQ7NTKKi+jDoVY2Efu6ZyzgT9n5KgG2kWliXA==", - "dev": true, - "optional": true + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } }, - "sass-true": { + "node_modules/sass-true": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/sass-true/-/sass-true-9.0.0.tgz", "integrity": "sha512-p+ReCwIrk2/m85uQ3w1hGqiTFhqiY4Pc7juHcvDYvrVWy4DvVmCyLbkypdHWOFnT2OV5DpgqyNk2JN+zm4GUig==", "dev": true, - "requires": { + "license": "BSD-3-Clause", + "dependencies": { "@adobe/css-tools": "^4.4.3", "jest-diff": "^30.0.2", "lodash": "^4.17.21" }, - "dependencies": { - "@jest/schemas": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", - "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.34.0" - } - }, - "@sinclair/typebox": { - "version": "0.34.41", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", - "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", - "dev": true - }, - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - }, - "jest-diff": { - "version": "30.1.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.1.2.tgz", - "integrity": "sha512-4+prq+9J61mOVXCa4Qp8ZjavdxzrWQXrI80GNxP8f4tkI2syPuPrJgdRPZRrfUTRvIoUwcmNLbqEJy9W800+NQ==", - "dev": true, - "requires": { - "@jest/diff-sequences": "30.0.1", - "@jest/get-type": "30.1.0", - "chalk": "^4.1.2", - "pretty-format": "30.0.5" - } + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "sass": ">=1.45.0", + "sass-embedded": ">=1.45.0" + }, + "peerDependenciesMeta": { + "sass": { + "optional": true }, - "pretty-format": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz", - "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==", - "dev": true, - "requires": { - "@jest/schemas": "30.0.5", - "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" - } + "sass-embedded": { + "optional": true } } }, - "sassdoc-extras": { + "node_modules/sassdoc-extras": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/sassdoc-extras/-/sassdoc-extras-2.5.1.tgz", "integrity": "sha512-/+ilEnk1H1hG9nympL1GIFWhAczzoclyDzgzfphIg46nsT/dWJuzWYHyzIpduc/nTVwKeQfmTz0ZVvy12QMkrQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "marked": "^0.6.2" } }, - "sassdoc-plugin-localization": { + "node_modules/sassdoc-plugin-localization": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/sassdoc-plugin-localization/-/sassdoc-plugin-localization-2.0.0.tgz", "integrity": "sha512-jC/Mi8jYaux1SIt+eH9gj1g4UgzfBxm00oHxfqOXQSGrSEGkM+YfPe8iOcZzflEiXRPgR6ckLoHCdSM1YkSGTg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "fs-extra": "^7.0.1" - }, + } + }, + "node_modules/sassdoc-plugin-localization/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "license": "MIT", "dependencies": { - "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - } + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/sassdoc-plugin-localization/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "semver": { + "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } }, - "set-function-length": { + "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "set-function-name": { + "node_modules/set-function-name": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" } }, - "shebang-command": { + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "shebang-regex": { + "node_modules/shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "shelljs": { + "node_modules/shelljs": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", "dev": true, - "requires": { + "license": "BSD-3-Clause", + "dependencies": { "glob": "^7.0.0", "interpret": "^1.0.0", "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/shelljs/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "shx": { + "node_modules/shx": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "minimist": "^1.2.3", "shelljs": "^0.8.5" + }, + "bin": { + "shx": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, - "side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dev": true, - "requires": { - "call-bind": "^1.0.7", + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "slice-ansi": { + "node_modules/slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "source-map": { + "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true - }, - "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" } }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, - "requires": { + "license": "Apache-2.0", + "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" }, - "spdx-expression-parse": { + "node_modules/spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, - "spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "node_modules/spdx-license-ids": { + "version": "3.0.22", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", + "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "dev": true, + "license": "CC0-1.0" }, - "stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" + "license": "MIT" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", "dev": true, - "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" } }, - "string-width": { + "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "strip-ansi": { + "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-indent": { + "node_modules/strip-bom": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-indent": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.1.1.tgz", + "integrity": "sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==", "dev": true, - "requires": { - "min-indent": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "strip-json-comments": { + "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "style-search": { + "node_modules/style-search": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==", - "dev": true + "dev": true, + "license": "ISC" }, - "stylelint": { - "version": "15.6.2", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-15.6.2.tgz", - "integrity": "sha512-fjQWwcdUye4DU+0oIxNGwawIPC5DvG5kdObY5Sg4rc87untze3gC/5g/ikePqVjrAsBUZjwMN+pZsAYbDO6ArQ==", + "node_modules/stylelint": { + "version": "15.11.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-15.11.0.tgz", + "integrity": "sha512-78O4c6IswZ9TzpcIiQJIN49K3qNoXTM8zEJzhaTE/xRTCZswaovSEVIa/uwbOltZrk16X4jAxjaOhzz/hTm1Kw==", "dev": true, - "requires": { - "@csstools/css-parser-algorithms": "^2.1.1", - "@csstools/css-tokenizer": "^2.1.1", - "@csstools/media-query-list-parser": "^2.0.4", - "@csstools/selector-specificity": "^2.2.0", + "license": "MIT", + "peer": true, + "dependencies": { + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0", + "@csstools/media-query-list-parser": "^2.1.4", + "@csstools/selector-specificity": "^3.0.0", "balanced-match": "^2.0.0", "colord": "^2.9.3", - "cosmiconfig": "^8.1.3", - "css-functions-list": "^3.1.0", + "cosmiconfig": "^8.2.0", + "css-functions-list": "^3.2.1", "css-tree": "^2.3.1", "debug": "^4.3.4", - "fast-glob": "^3.2.12", + "fast-glob": "^3.3.1", "fastest-levenshtein": "^1.0.16", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^7.0.0", "global-modules": "^2.0.0", "globby": "^11.1.0", "globjoin": "^0.1.4", @@ -13412,17 +7504,16 @@ "import-lazy": "^4.0.0", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.27.0", + "known-css-properties": "^0.29.0", "mathml-tag-names": "^2.1.3", - "meow": "^9.0.0", + "meow": "^10.1.5", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.23", - "postcss-media-query-parser": "^0.2.3", + "postcss": "^8.4.28", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.12", + "postcss-selector-parser": "^6.0.13", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", @@ -13431,523 +7522,1078 @@ "supports-hyperlinks": "^3.0.0", "svg-tags": "^1.0.0", "table": "^6.8.1", - "v8-compile-cache": "^2.3.0", "write-file-atomic": "^5.0.1" }, - "dependencies": { - "balanced-match": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", - "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", - "dev": true - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "postcss-safe-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", - "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", - "dev": true, - "requires": {} - }, - "signal-exit": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz", - "integrity": "sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==", - "dev": true - }, - "write-file-atomic": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", - "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "signal-exit": "^4.0.1" - } - } + "bin": { + "stylelint": "bin/stylelint.mjs" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" } }, - "stylelint-config-recommended": { + "node_modules/stylelint-config-recommended": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-10.0.1.tgz", "integrity": "sha512-TQ4xQ48tW4QSlODcti7pgSRqBZcUaBzuh0jPpfiMhwJKBPkqzTIAU+IrSWL/7BgXlOM90DjB7YaNgFpx8QWhuA==", "dev": true, - "requires": {} + "license": "MIT", + "peerDependencies": { + "stylelint": "^15.0.0" + } }, - "stylelint-config-recommended-scss": { + "node_modules/stylelint-config-recommended-scss": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-9.0.1.tgz", "integrity": "sha512-qAmz/TdrqslwiMTuLM3QXeISUkfEDUXGMfRBCHm/xrkCJNnQefv+mzG2mWTsWkqcVk8HAyUkug10dwAcYp2fCQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "postcss-scss": "^4.0.2", "stylelint-config-recommended": "^10.0.1", "stylelint-scss": "^4.4.0" + }, + "peerDependencies": { + "postcss": "^8.3.3", + "stylelint": "^15.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + } } }, - "stylelint-config-standard": { + "node_modules/stylelint-config-standard": { "version": "30.0.1", "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-30.0.1.tgz", "integrity": "sha512-NbeHOmpRQhjZh5XB1B/S4MLRWvz4xxAxeDBjzl0tY2xEcayNhLbaRGF0ZQzq+DQZLCcPpOHeS2Ru1ydbkhkmLg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "stylelint-config-recommended": "^10.0.1" + }, + "peerDependencies": { + "stylelint": "^15.0.0" } }, - "stylelint-config-standard-scss": { + "node_modules/stylelint-config-standard-scss": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/stylelint-config-standard-scss/-/stylelint-config-standard-scss-7.0.1.tgz", "integrity": "sha512-m5sRdtsB1F5fnC1Ozla7ryftU47wVpO+HWd+JQTqeoG0g/oPh5EfbWfcVHbNCEtuoHfALIySiUWS20pz2hX6jA==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "stylelint-config-recommended-scss": "^9.0.0", "stylelint-config-standard": "^30.0.1" + }, + "peerDependencies": { + "postcss": "^8.3.3", + "stylelint": "^15.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + } } }, - "stylelint-scss": { + "node_modules/stylelint-scss": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-4.7.0.tgz", "integrity": "sha512-TSUgIeS0H3jqDZnby1UO1Qv3poi1N8wUYIJY6D1tuUq2MN3lwp/rITVo0wD+1SWTmRm0tNmGO0b7nKInnqF6Hg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "stylelint": "^14.5.1 || ^15.0.0" + } + }, + "node_modules/stylelint/node_modules/balanced-match": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", + "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", + "dev": true, + "license": "MIT" + }, + "node_modules/stylelint/node_modules/file-entry-cache": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-7.0.2.tgz", + "integrity": "sha512-TfW7/1iI4Cy7Y8L6iqNdZQVvdXn0f8B4QcIXmkIbtTIe/Okm/nSlHb4IwGzRVOd3WfSieCgvf5cMzEfySAIl0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/stylelint/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylelint/node_modules/postcss-safe-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", + "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.3.3" + } + }, + "node_modules/stylelint/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/stylelint/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "supports-color": { + "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "supports-hyperlinks": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz", - "integrity": "sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==", + "node_modules/supports-hyperlinks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", + "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" } }, - "supports-preserve-symlinks-flag": { + "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "svg-tags": { + "node_modules/svg-tags": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", "dev": true }, - "sync-child-process": { + "node_modules/sync-child-process": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz", "integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==", - "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "sync-message-port": "^1.0.0" + }, + "engines": { + "node": ">=16.0.0" } }, - "sync-message-port": { + "node_modules/sync-message-port": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.1.3.tgz", "integrity": "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==", - "dev": true + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } }, - "synckit": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", - "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "node_modules/synckit": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", "dev": true, - "requires": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" } }, - "table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", "dev": true, - "requires": { + "license": "BSD-3-Clause", + "dependencies": { "ajv": "^8.0.1", "lodash.truncate": "^4.4.2", "slice-ansi": "^4.0.0", "string-width": "^4.2.3", "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" } }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "text-table": { + "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "dev": true, + "license": "MIT" }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } }, - "to-regex-range": { + "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { + "devOptional": true, + "license": "MIT", + "dependencies": { "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" } }, - "trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", - "dev": true + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/trim-newlines": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-4.1.1.tgz", + "integrity": "sha512-jRKj0n0jXWo6kh62nA5TEh3+4igKDXLvzBJcPpiizP7oOolUrYIxmVBG9TOtHYFHoddUk6YvAkGeGoSVTXfQXQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "tsconfig-paths": { + "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" - }, - "dependencies": { - "json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true - } } }, - "tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } }, - "type-check": { + "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } }, - "typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "dev": true, - "requires": { - "call-bind": "^1.0.7", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" } }, - "typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "dev": true, - "requires": { - "call-bind": "^1.0.7", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "typed-array-length": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.5.tgz", - "integrity": "sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==", + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-proto": "^1.0.3", "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, - "optional": true + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "dev": true, - "requires": { - "call-bind": "^1.0.2", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "universalify": { + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } }, - "update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", - "dev": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "uri-js": { + "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "requires": { + "license": "BSD-2-Clause", + "dependencies": { "punycode": "^2.1.0" } }, - "util-deprecate": { + "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "v8-to-istanbul": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", - "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - } + "license": "MIT" }, - "validate-npm-package-license": { + "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, - "requires": { + "license": "Apache-2.0", + "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, - "varint": { + "node_modules/varint": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==", - "dev": true + "license": "MIT" }, - "walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vite": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz", + "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vitest": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.16.tgz", + "integrity": "sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@vitest/expect": "4.0.16", + "@vitest/mocker": "4.0.16", + "@vitest/pretty-format": "4.0.16", + "@vitest/runner": "4.0.16", + "@vitest/snapshot": "4.0.16", + "@vitest/spy": "4.0.16", + "@vitest/utils": "4.0.16", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.16", + "@vitest/browser-preview": "4.0.16", + "@vitest/browser-webdriverio": "4.0.16", + "@vitest/ui": "4.0.16", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, - "requires": { - "makeerror": "1.0.12" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "which": { + "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { + "license": "ISC", + "dependencies": { "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "which-boxed-primitive": { + "node_modules/which-collection": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" } }, - "wordwrap": { + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } + "license": "MIT" }, - "wrappy": { + "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "license": "ISC" }, - "write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", "dev": true, - "requires": { + "license": "ISC", + "dependencies": { "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { + "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, - "yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, - "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "license": "ISC", + "engines": { + "node": ">=10" } }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - }, - "yocto-queue": { + "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.0.tgz", + "integrity": "sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25 || ^4" + } } } } diff --git a/package.json b/package.json index 9814efc1..3f51bc71 100644 --- a/package.json +++ b/package.json @@ -3,29 +3,35 @@ "version": "1.0.0", "description": "A set of Sass variables, mixins, and functions for generating palettes, typography, and elevations used by Ignite UI components.", "main": "index.js", + "type": "module", + "bin": { + "igniteui-theming-mcp": "./dist/mcp/index.js" + }, "scripts": { - "clean": "npm run clean:json && npm run clean:docs", + "clean": "npm run clean:json && npm run clean:mcp && npm run clean:docs", "clean:json": "shx rm -rf json", "clean:docs": "shx rm -rf docs", "clean:tailwind": "shx rm -rf tailwind", - "build": "npm run clean && npm run build:json && npm run build:tailwind && npm run build:e2e", + "clean:mcp": "shx rm -rf dist/mcp", + "build": "npm run clean && npm run build:tailwind && npm run build:e2e && npm run build:mcp", "build:docs": "npm run clean:docs && npm run build:docs:en:production", "build:docs:en:production": "set NODE_ENV=production && npx sassdoc ./sass -d docs", "build:docs:en:staging": "set NODE_ENV=staging && npx sassdoc ./sass -d docs", "build:e2e": "sass --quiet ./test/e2e/theme.scss ./test/e2e/theme.css", "build:json": "node scripts/buildJSON.mjs", "build:tailwind": "npm run clean:tailwind && node scripts/buildTailwind.mjs", + "build:mcp": "npm run build:json && tsc -p tsconfig.json && node -e \"require('fs').chmodSync('dist/mcp/index.js', '755')\"", "serve:docs": "npx http-server ./docs", "preview:palette": "node scripts/previewPalette.mjs", "lint": "npm run lint:styles && npm run lint:prettier", "lint:styles": "stylelint ./sass/**/*.scss --fix", "lint:prettier": "prettier \"./sass/**/*.scss\" --check --ignore-path .gitignore", - "test": "jest", "format": "stylelint \"./sass/**/*.{scss,css}\" --fix --allow-empty-input --ignore-path .gitignore && prettier \"./sass/**/*.{scss,css}\" --write --ignore-path .gitignore", - "prepare": "husky install" - }, - "jest": { - "testEnvironment": "jest-environment-node-single-context" + "prepare": "husky install", + "mcp:dev": "tsx src/mcp/index.ts", + "mcp:inspector": "npx @modelcontextprotocol/inspector dist/mcp/index.js", + "test": "vitest run", + "coverage": "vitest run --coverage" }, "lint-staged": { "sass/**/*.{scss,css}": [ @@ -36,6 +42,7 @@ "sass/", "json/", "tailwind/", + "dist/mcp/", "_index.scss" ], "repository": { @@ -77,9 +84,19 @@ "./json/colors/presets/palettes.json": "./json/colors/presets/palettes.json", "./json/elevations/indigo.json": "./json/elevations/indigo.json", "./json/elevations/material.json": "./json/elevations/material.json", - "./json/typography/presets/typescales.json": "./json/typography/presets/typescales.json" + "./json/typography/presets/typescales.json": "./json/typography/presets/typescales.json", + "./mcp": { + "import": "./dist/mcp/index.js" + } + }, + "dependencies": { + "@modelcontextprotocol/sdk": "^1.25.0", + "sass-embedded": "~1.92.1", + "zod": "^3.25.76" }, "devDependencies": { + "@types/node": "^22.0.0", + "@vitest/coverage-v8": "^4.0.16", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.29.1", @@ -87,18 +104,18 @@ "globby": "^13.1.4", "husky": "^8.0.3", "igniteui-sassdoc-theme": "^1.1.6", - "jest": "^29.5.0", - "jest-environment-node-single-context": "^29.0.0", "lunr": "^2.3.9", "postcss": "^8.4.35", "postcss-safe-parser": "^7.0.0", "prettier": "^3.2.5", - "sass-embedded": "^1.92.1", "sass-true": "^9.0.0", "sassdoc-plugin-localization": "^2.0.0", "shx": "^0.3.4", "stylelint": "^15.6.2", "stylelint-config-standard-scss": "^7.0.1", - "stylelint-scss": "^4.7.0" + "stylelint-scss": "^4.7.0", + "tsx": "^4.0.0", + "typescript": "^5.7.0", + "vitest": "^4.0.15" } } diff --git a/sass/themes/components/button/_button-theme.scss b/sass/themes/components/button/_button-theme.scss index a70b6e77..cb8cca68 100644 --- a/sass/themes/components/button/_button-theme.scss +++ b/sass/themes/components/button/_button-theme.scss @@ -187,8 +187,7 @@ $themes: map.merge( $themes, ( - $_name: - extend( + $_name: extend( digest-schema($_schema), ( name: $name, diff --git a/sass/themes/components/icon-button/_icon-button-theme.scss b/sass/themes/components/icon-button/_icon-button-theme.scss index 0f4aef3a..f171fb4a 100644 --- a/sass/themes/components/icon-button/_icon-button-theme.scss +++ b/sass/themes/components/icon-button/_icon-button-theme.scss @@ -103,8 +103,7 @@ $themes: map.merge( $themes, ( - $_name: - extend( + $_name: extend( digest-schema($_schema), ( name: $name, diff --git a/sass/themes/schemas/components/light/_input-group.scss b/sass/themes/schemas/components/light/_input-group.scss index 4abfd5e8..b2caa7b7 100644 --- a/sass/themes/schemas/components/light/_input-group.scss +++ b/sass/themes/schemas/components/light/_input-group.scss @@ -116,8 +116,7 @@ $light-input-group: extend( ), ), // Text colors - idle-text-color: - ( + idle-text-color: ( color: ( 'gray', 700, @@ -148,8 +147,7 @@ $light-input-group: extend( ), ), // State colors - idle-secondary-color: - ( + idle-secondary-color: ( color: ( 'gray', 700, diff --git a/sass/themes/schemas/components/light/_stepper.scss b/sass/themes/schemas/components/light/_stepper.scss index 99029586..cab0ef16 100644 --- a/sass/themes/schemas/components/light/_stepper.scss +++ b/sass/themes/schemas/components/light/_stepper.scss @@ -59,8 +59,7 @@ /// @prop {Map} content-foreground [color: ('gray', 900)] - The foreground of the step content. $light-stepper: ( // Step incomplete - content-foreground: - ( + content-foreground: ( color: ( 'gray', 900, @@ -264,8 +263,7 @@ $light-stepper: ( ), // Disabled - disabled-indicator-color: - ( + disabled-indicator-color: ( color: ( 'gray', 500, @@ -292,8 +290,7 @@ $light-stepper: ( ), // Separator - step-separator-color: - ( + step-separator-color: ( color: ( 'gray', 300, @@ -542,8 +539,7 @@ $fluent-stepper: extend( ), // Complete - complete-indicator-background: - ( + complete-indicator-background: ( color: ( 'gray', 300, @@ -763,8 +759,7 @@ $bootstrap-stepper: extend( ), ), // Complete - complete-indicator-background: - ( + complete-indicator-background: ( color: ( 'gray', 400, @@ -784,8 +779,7 @@ $bootstrap-stepper: extend( ), // Disabled - disabled-indicator-outline: - ( + disabled-indicator-outline: ( color: ( 'gray', 300, diff --git a/scripts/parser.mjs b/scripts/parser.mjs index 74bb4c5b..2bd12316 100644 --- a/scripts/parser.mjs +++ b/scripts/parser.mjs @@ -2,11 +2,16 @@ import postcss from 'postcss'; import safeParser from 'postcss-safe-parser'; import report from './report.mjs'; -// Remove surrounding quotes from a string +// Remove surrounding quotes from a string (both single and double quotes) function removeQuotes(string) { + // Remove double quotes if (string.startsWith('"') && string.endsWith('"')) { return string.substring(1, string.length - 1); } + // Remove single quotes + if (string.startsWith("'") && string.endsWith("'")) { + return string.substring(1, string.length - 1); + } return string; } diff --git a/src/mcp/IMPROVEMENTS.md b/src/mcp/IMPROVEMENTS.md new file mode 100644 index 00000000..50834897 --- /dev/null +++ b/src/mcp/IMPROVEMENTS.md @@ -0,0 +1,148 @@ +# MCP Server Code Quality & Maintainability Improvements + +## Goals + +1. **Improve maintainability** for when the Sass framework changes +2. **Prepare architecture** for upcoming component theming and additional tools +3. **Add comprehensive test coverage** with real, meaningful tests +4. **Reduce code duplication** and improve consistency + +--- + +## Phase 1: Foundation Cleanup (Low Risk, High Value) - COMPLETED + +### 1.1 Consolidate Duplicate Types and Constants - DONE + +**What:** Create a single source of truth for shared types and constants. + +**Changes made:** +- `src/mcp/utils/types.ts` - Added canonical constants: `PLATFORMS`, `DESIGN_SYSTEMS`, `VARIANTS`, `ELEVATION_PRESETS` +- `src/mcp/tools/schemas.ts` - Now imports constants from `utils/types.ts`, Zod schemas derive from them +- `src/mcp/knowledge/platforms/index.ts` - Now imports `Platform` from `utils/types.ts` +- `src/mcp/knowledge/typography.ts` - Now imports `DesignSystem` from `utils/types.ts` + +### 1.2 Centralize Utility Functions - DONE + +**What:** Move duplicated helper functions to a single location. + +**Changes made:** +- `src/mcp/utils/sass.ts` - Added `toVariableName()` and `generateHeader()` with proper validation +- `src/mcp/tools/handlers/custom-palette.ts` - Removed local duplicates, now imports from `utils/sass.ts` +- `src/mcp/generators/sass.ts` - Re-exports utilities for external use + +### 1.3 Fix Type Safety Issues - DONE + +**What:** Remove unsafe non-null assertions and add proper type guards. + +**Changes made:** +- `src/mcp/utils/color.ts` - Refactored `PaletteSuitabilityAnalysis` to use discriminated union: + - `PaletteSuitabilitySuitable` (suitable: true) + - `PaletteSuitabilityUnsuitable` (suitable: false, issue and description are guaranteed) +- `src/mcp/validators/palette.ts` - Removed `!` assertions, TypeScript now correctly narrows types + +--- + +## Phase 2: Test Infrastructure - COMPLETED + +### 2.1 Set Up Vitest Test Framework - DONE + +**Files created:** +- `vitest.config.mcp.ts` - Vitest configuration for MCP code + +### 2.2 Add Unit Tests for Utils - DONE + +**Test files created:** +- `src/mcp/__tests__/utils/sass.test.ts` - 24 tests for Sass utility functions +- `src/mcp/__tests__/utils/color.test.ts` - 30 tests for color analysis utilities + +### 2.3 Add Unit Tests for Validators - DONE + +**Test files created:** +- `src/mcp/__tests__/validators/custom-palette.test.ts` - 16 tests for custom palette validation + +### 2.4 Add Unit Tests for Generators - DONE + +**Test files created:** +- `src/mcp/__tests__/generators/sass.test.ts` - 28 tests for Sass code generators + +**Test approach:** +1. Test that generated code contains expected Sass constructs +2. Compile the generated code with sass-embedded to verify it's valid Sass +3. Test platform-specific output differences + +### 2.5 Add Unit Tests for Tool Handlers - DONE + +**Test files created:** +- `src/mcp/__tests__/tools/handlers/handlers.test.ts` - 25 tests for all tool handlers + +**Current test count: 123 tests, all passing** + +--- + +## Phase 3: Structural Improvements for Extensibility - COMPLETED + +### 3.1 Create Sass API Manifest - DONE + +**What:** Centralize Sass API knowledge for easier updates when framework changes. + +**Files created:** +- `src/mcp/knowledge/sass-api.ts` - Central manifest of all Sass API knowledge: + - `SASS_FUNCTIONS` - All Sass functions (palette, typography, elevations, spacing) + - `SASS_MIXINS` - All Sass mixins (palette, typography, elevations, etc.) + - `SASS_VARIABLE_PATTERNS` - Variable naming conventions for each module + - `CSS_CUSTOM_PROPERTIES` - CSS custom property patterns + - Helper functions: `getSassFunctionsByModule()`, `getSassMixinsByModule()`, etc. +- `src/mcp/__tests__/knowledge/sass-api.test.ts` - 52 tests + +### 3.2 Refactor Web Components Generator - DONE + +**What:** Break the 213-line function into smaller, testable pieces. + +**Changes made to `src/mcp/knowledge/platforms/webcomponents.ts`:** +- Extracted `generateWCHeader()` - file header comment +- Extracted `getWCElevationPreset()` - elevation variable lookup +- Extracted `generateWCImports()` - import statements +- Extracted `generateWCProgressProperties()` - CSS @property declarations +- Extracted `generateWCRootVariables()` - :root CSS variables +- Extracted `generateWCRtlSupport()` - RTL direction support +- Extracted `generateWCScrollbarCustomization()` - scrollbar styling +- Extracted `generateWCThemingMixins()` - palette/typography/elevations/spacing mixins +- Updated `src/mcp/knowledge/platforms/index.ts` - exports new helper functions +- `src/mcp/__tests__/knowledge/webcomponents.test.ts` - 26 tests + +### 3.3 Add Error Handling Consistency - DONE + +**What:** Standardize error handling across the codebase. + +**Files created:** +- `src/mcp/utils/result.ts` - Result type for explicit error handling: + - `Result` - discriminated union (Success | Failure) + - Helper functions: `success()`, `failure()`, `isSuccess()`, `isFailure()` + - `mapResult()`, `unwrap()`, `unwrapOr()` - utility functions + - `McpError` type with error codes: `INVALID_COLOR`, `INVALID_PARAMETER`, `SASS_COMPILATION_ERROR`, `VALIDATION_ERROR`, `NOT_FOUND`, `UNKNOWN_ERROR` + - `McpResult` - Result type using McpError for failures + - `ValidationResult` type with errors and warnings arrays + - Helper functions: `validationSuccess()`, `validationFailure()`, `combineValidationResults()`, `formatValidationMessages()` +- `src/mcp/__tests__/utils/result.test.ts` - 42 tests + +--- + +## Summary & Progress + +| Phase | Tasks | Status | Notes | +|-------|-------|--------|-------| +| 1.1 | Consolidate Types/Constants | DONE | Single source of truth in `utils/types.ts` | +| 1.2 | Centralize Utility Functions | DONE | `toVariableName`, `generateHeader` in `utils/sass.ts` | +| 1.3 | Fix Type Safety Issues | DONE | Discriminated union for `PaletteSuitabilityAnalysis` | +| 2.1 | Test Framework Setup | DONE | Vitest configured | +| 2.2 | Unit Tests for Utils | DONE | sass.test.ts (24), color.test.ts (30), result.test.ts (42) | +| 2.3 | Unit Tests for Validators | DONE | custom-palette.test.ts (16) | +| 2.4 | Unit Tests for Generators | DONE | sass.test.ts (28) | +| 2.5 | Unit Tests for Handlers | DONE | handlers.test.ts (25) | +| 3.1 | Sass API Manifest | DONE | sass-api.ts + 52 tests | +| 3.2 | Refactor WC Generator | DONE | 8 helper functions extracted + 26 tests | +| 3.3 | Error Handling | DONE | result.ts with Result + ValidationResult types | + +**Total tests: 243 passing** + +**Run tests:** `npm run test:mcp` diff --git a/src/mcp/PLAN.md b/src/mcp/PLAN.md new file mode 100644 index 00000000..217c8589 --- /dev/null +++ b/src/mcp/PLAN.md @@ -0,0 +1,908 @@ +# Ignite UI Theming MCP Server - Implementation Plan + +## Executive Summary + +This document outlines the architecture and implementation plan for a **goals-oriented Model Context Protocol (MCP) server** for the Ignite UI Theming framework. The server will enable AI coding assistants and design tools (including integrations with tools like the Figma MCP server) to generate professional, production-ready theming code in both Sass and CSS formats. + +### Goals-Oriented Philosophy + +Unlike API-based MCP servers that simply expose functions, this server is designed around **user goals**: + +| API-Based Approach | Goals-Oriented Approach | +| -------------------------------------------- | ---------------------------------------------------------- | +| `createPalette(primary, secondary, surface)` | "Create a dark theme for a fintech app with blue branding" | +| `setTypography(font, scale)` | "Set up modern, accessible typography for a mobile app" | +| `getElevation(level)` | "Make this card feel elevated and interactive" | + +The server should understand context, make smart defaults, and guide users toward best practices. + +--- + +## Platform Support + +The MCP server supports two target platforms for theme generation: + +| Platform | Package | Theming Module | Key Characteristics | +|----------|---------|----------------|---------------------| +| `angular` | `igniteui-angular` | `igniteui-angular/theming` | Uses `core()` + `theme()` mixins, forwards igniteui-theming with overrides | +| `webcomponents` | `igniteui-webcomponents` | `igniteui-theming` | Uses individual mixins (`palette()`, `typography()`, `elevations()`), supports runtime switching | + +### Platform Detection Strategy + +The server can detect the target platform through multiple methods: + +1. **Explicit Parameter**: User specifies `platform: 'angular'` or `platform: 'webcomponents'` +2. **Automatic Detection**: `detect_platform` tool reads `package.json` to infer platform from dependencies +3. **Fallback**: Generate platform-agnostic code when detection fails + +### Key Platform Differences + +#### Ignite UI for Angular + +```scss +// Uses igniteui-angular/theming module +@use "igniteui-angular/theming" as *; + +// Requires core() mixin first (Angular-specific) +@include core(); + +// Typography mixin (Angular overrides this) +@include typography( + $font-family: $material-typeface, + $type-scale: $material-type-scale +); + +// theme() mixin (Angular-specific, combines palette + schema + elevations) +@include theme( + $palette: $light-material-palette, + $schema: $light-material-schema +); +``` + +**Angular-specific features:** +- `core()` mixin with `$print-layout` and `$enhanced-accessibility` options +- `theme()` mixin with `$exclude`, `$roundness`, `$elevation` options +- Requires `ig-typography` CSS class on root element +- Typography module is overridden with Angular-specific implementation + +#### Ignite UI for Web Components + +```scss +// Uses igniteui-theming directly +@use 'igniteui-theming/sass/color/presets/light/material' as *; +@use 'igniteui-theming' as *; +@use 'igniteui-theming/sass/typography/presets/material' as *; +@use 'igniteui-theming/sass/elevations/presets' as *; + +// Individual mixin calls (no unified theme() mixin) +:root { + --ig-theme: material; + --ig-theme-variant: light; +} + +@include palette($palette); +@include elevations($material-elevations); +@include typography($font-family: $typeface, $type-scale: $type-scale); +@include spacing(); +``` + +**Web Components-specific features:** +- No `core()` or `theme()` mixins - uses igniteui-theming directly +- Ships precompiled CSS themes in `dist/themes/` +- Supports runtime theme switching via `configureTheme()` JavaScript API +- Components use `ThemingController` for dynamic CSS variable updates + +--- + +## Architecture Overview + +### Technology Stack + +``` +┌─────────────────────────────────────────────────────────────┐ +│ MCP Server (TypeScript) │ +├─────────────────────────────────────────────────────────────┤ +│ Transport: STDIO (local) / Streamable HTTP (remote) │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ +│ │ Tools │ │ Resources │ │ Prompts │ │ +│ │ │ │ │ │ │ │ +│ │ • Theme │ │ • Schemas │ │ • Theme Creation │ │ +│ │ Generator │ │ • Presets │ │ • Color Selection │ │ +│ │ • Palette │ │ • Component │ │ • Typography Setup │ │ +│ │ Creator │ │ Catalog │ │ • Troubleshooting │ │ +│ │ • Validator │ │ • Examples │ │ │ │ +│ └─────────────┘ └─────────────┘ └─────────────────────┘ │ +│ │ +├─────────────────────────────────────────────────────────────┤ +│ Core Services Layer │ +│ ┌──────────────────────────────────────────────────────┐ │ +│ │ • SassGenerator - Generates valid Sass code │ │ +│ │ • CssGenerator - Generates CSS custom properties │ │ +│ │ • Validator - Validates via dart-sass (optional) │ │ +│ │ • SchemaEngine - Processes theme schemas │ │ +│ └──────────────────────────────────────────────────────┘ │ +├─────────────────────────────────────────────────────────────┤ +│ Knowledge Base (Embedded) │ +│ • Color presets, multipliers, shade algorithms │ +│ • Typography scales (Material, Bootstrap, Fluent, Indigo) │ +│ • Elevation definitions │ +│ • Component theme schemas │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Build System + +- **Vite** for building the TypeScript MCP server +- **Output**: `mcp/` folder in the published package +- **Entry point**: `mcp/index.js` + +--- + +## MCP Primitives Design + +### 1. Tools (Model-Controlled Actions) + +Tools are the core of the MCP server - they perform actions and generate code. + +#### Tool Category 1: Theme Foundation + +| Tool Name | Description | Input Schema | Output | +| ------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------- | --------------------- | +| `create_theme` | Create a complete theme foundation | `{ platform?, designSystem?, primaryColor, secondaryColor?, surfaceColor?, variant?, name? }` | Sass/CSS theme code | +| `create_palette` | Generate a color palette | `{ platform?, primary, secondary?, surface?, gray?, info?, success?, warn?, error?, variant? }` | Palette definition | +| `create_typography` | Set up typography system | `{ platform?, fontFamily, designSystem?, baseFontSize?, customScale? }` | Typography setup code | +| `create_elevations` | Configure elevation/shadow system | `{ platform?, designSystem?, customColors? }` | Elevations setup code | +| `detect_platform` | Detect target platform from project| `{ packageJsonPath? }` | Platform detection | + +#### Tool Category 2: Color Operations + +| Tool Name | Description | Input Schema | Output | +| ----------------------- | ------------------------------------ | ----------------------------------- | ------------------------------- | +| `get_color` | Retrieve a color from a palette | `{ color, variant?, opacity? }` | CSS variable reference or value | +| `get_contrast_color` | Get accessible contrast color | `{ backgroundColor, wcagLevel? }` | Contrast color value | +| `generate_color_shades` | Generate all shades for a color | `{ baseColor, name }` | Complete shade map | +| `suggest_palette` | Suggest palette based on description | `{ description, mood?, industry? }` | Recommended colors | + +#### Tool Category 3: Typography Operations + +| Tool Name | Description | Input Schema | Output | +| ------------------------- | -------------------------- | ------------------------------------------------------------------------ | --------------------- | +| `create_type_style` | Create a custom type style | `{ fontSize, fontWeight?, lineHeight?, letterSpacing?, textTransform? }` | Type style definition | +| `get_type_scale_category` | Get styles for a category | `{ category, designSystem? }` | Category styles | +| `convert_units` | Convert between px/rem/em | `{ value, to, context? }` | Converted value | + +#### Tool Category 4: Spacing & Sizing + +| Tool Name | Description | Input Schema | Output | +| ----------------------- | ------------------------- | ----------------------------------------- | ------------------ | +| `create_spacing_system` | Define spacing scale | `{ baseUnit?, scale? }` | Spacing variables | +| `get_sizable_value` | Get responsive size value | `{ small, medium, large }` | Sizable expression | +| `get_padding` | Get contextual padding | `{ small?, medium?, large?, direction? }` | Padding expression | + +#### Tool Category 5: Component Theming (Extensible) + +| Tool Name | Description | Input Schema | Output | +| ------------------------ | -------------------------- | ----------------------------------- | -------------------- | +| `create_component_theme` | Create a component theme | `{ component, schema?, overrides }` | Component theme code | +| `list_component_themes` | List available components | `{ category? }` | Component catalog | +| `get_component_schema` | Get schema for a component | `{ component, designSystem? }` | Schema definition | + +#### Tool Category 6: Validation & Utilities + +| Tool Name | Description | Input Schema | Output | +| ------------------ | ----------------------------- | ------------------------------------ | ----------------- | +| `validate_theme` | Validate generated theme code | `{ code, format }` | Validation result | +| `check_contrast` | Check WCAG contrast ratio | `{ foreground, background, level? }` | Pass/fail + ratio | +| `explain_function` | Explain a theming function | `{ functionName }` | Documentation | + +### 2. Resources (Application-Controlled Data) + +Resources provide read-only context that AI applications can use. + +#### Resource Category 1: Platform Information (Direct Resources) + +| URI | Description | MIME Type | +| ------------------------------------ | ---------------------------------------- | ------------------ | +| `theming://platforms` | List of supported platforms | `application/json` | +| `theming://platforms/angular` | Angular platform configuration & usage | `application/json` | +| `theming://platforms/webcomponents` | Web Components platform config & usage | `application/json` | + +#### Resource Category 2: Presets (Direct Resources) + +| URI | Description | MIME Type | +| ---------------------------------- | ------------------------------------- | ------------------ | +| `theming://presets/palettes` | All predefined palette configurations | `application/json` | +| `theming://presets/palettes/light` | Light palette variants | `application/json` | +| `theming://presets/palettes/dark` | Dark palette variants | `application/json` | +| `theming://presets/typography` | All typography presets | `application/json` | +| `theming://presets/elevations` | Elevation definitions | `application/json` | +| `theming://presets/easings` | Animation easing functions | `application/json` | + +#### Resource Category 4: Schemas (Direct Resources) + +| URI | Description | MIME Type | +| ----------------------------------- | ---------------------- | ------------------ | +| `theming://schemas/light-material` | Light Material schema | `application/json` | +| `theming://schemas/dark-material` | Dark Material schema | `application/json` | +| `theming://schemas/light-bootstrap` | Light Bootstrap schema | `application/json` | +| `theming://schemas/dark-bootstrap` | Dark Bootstrap schema | `application/json` | +| `theming://schemas/light-fluent` | Light Fluent schema | `application/json` | +| `theming://schemas/dark-fluent` | Dark Fluent schema | `application/json` | +| `theming://schemas/light-indigo` | Light Indigo schema | `application/json` | +| `theming://schemas/dark-indigo` | Dark Indigo schema | `application/json` | + +#### Resource Category 5: Component Catalog (Resource Templates) + +| URI Template | Description | +| -------------------------------------- | ----------------------------------- | +| `theming://components` | List all themeable components | +| `theming://components/{name}` | Component theme schema & properties | +| `theming://components/{name}/examples` | Usage examples for a component | + +#### Resource Category 6: Documentation (Resource Templates) + +| URI Template | Description | +| --------------------------------- | ---------------------- | +| `theming://docs/functions/{name}` | Function documentation | +| `theming://docs/mixins/{name}` | Mixin documentation | +| `theming://docs/variables/{name}` | Variable documentation | + +### 3. Prompts (User-Controlled Templates) + +Pre-built interaction templates for common theming tasks. + +| Prompt Name | Description | Arguments | +| ------------------------- | ------------------------------------------ | --------------------------------------- | +| `create-app-theme` | Guided theme creation for an application | `appType`, `primaryColor?`, `variant?` | +| `brand-to-palette` | Convert brand colors to a full palette | `brandColors[]`, `style?` | +| `accessibility-audit` | Check theme for accessibility issues | `themeCode` | +| `migrate-theme` | Migrate from one design system to another | `fromSystem`, `toSystem`, `currentCode` | +| `dark-mode-variant` | Create dark mode variant of existing theme | `lightThemeCode` | +| `component-customization` | Guide through customizing a component | `componentName`, `goals` | + +--- + +## Implementation Phases + +### Phase 1: Foundation (MVP) + +**Goal**: Core palette, typography, and elevation generation + +**Deliverables**: + +- MCP server scaffolding with STDIO transport +- `create_theme` tool (basic) +- `create_palette` tool +- `create_typography` tool +- `create_elevations` tool +- Preset resources (palettes, typography, elevations) +- Basic Sass and CSS code generation + +**Data to Embed**: + +- Color multipliers (`$color`, `$grayscale` from `_multipliers.scss`) +- All 8 palette presets (light/dark x 4 design systems) +- All 4 typography presets with type scales +- Both elevation presets (material, indigo) +- Shade generation algorithms + +### Phase 2: Color Intelligence + +**Goal**: Smart color operations, validation, and suggestions + +**Deliverables**: + +- ✅ Color validation for surface/gray colors (validates against theme variant) +- ✅ Color guidance resource (`theming://guidance/colors`) +- `get_color` tool +- `get_contrast_color` tool +- `generate_color_shades` tool +- `suggest_palette` tool (AI-friendly descriptions) +- `check_contrast` tool +- Schema resources + +**Implemented: Surface/Gray Color Validation** + +The `create_palette` and `create_theme` tools now validate surface and gray colors against the theme variant: + +| Variant | Surface Requirement | Gray Requirement | +|---------|---------------------|------------------| +| `light` | Light color (luminance > 0.5) | Dark color (luminance ≤ 0.5) | +| `dark` | Dark color (luminance ≤ 0.5) | Light color (luminance > 0.5) | + +**Why is gray inverted?** The `palette()` function generates gray shades that need to contrast against the surface. Light themes need dark gray text, dark themes need light gray text. + +**Validation behavior:** +- Warnings are shown but code is still generated (non-blocking) +- Warning comments are added to generated Sass code +- Tips suggest omitting gray parameter to let it auto-calculate +- Uses Sass `luminance()` function via `sass-embedded` for accurate calculation + +**New files:** +- `src/mcp/utils/color.ts` - Sass-powered color analysis (luminance, contrast) +- `src/mcp/validators/palette.ts` - Validation logic +- `src/mcp/validators/index.ts` - Validators barrel export +- `src/mcp/knowledge/colors.ts` - Color rules documentation + +**New resource:** +- `theming://guidance/colors` - Markdown documentation about color rules + +**Data to Embed**: + +- WCAG contrast calculation algorithms +- Color shade generation logic +- Industry/mood color associations + +### Phase 3: Typography & Spacing + +**Goal**: Complete typography and spacing control + +**Deliverables**: + +- `create_type_style` tool +- `get_type_scale_category` tool +- `convert_units` tool +- `create_spacing_system` tool +- `get_sizable_value` tool +- `get_padding` tool +- Typography documentation resources + +### Phase 4: Validation & Intelligence + +**Goal**: Code validation and smart assistance + +**Deliverables**: + +- `validate_theme` tool (integrates dart-sass for validation) +- `explain_function` tool +- Documentation resources +- All prompts + +**Optional Enhancement**: + +- Sass compilation service for validation +- Error message interpretation + +### Phase 5: Component Themes (Extensible) + +**Goal**: Per-component theme generation + +**Deliverables**: + +- `create_component_theme` tool +- `list_component_themes` tool +- `get_component_schema` tool +- Component catalog resources +- Component examples resources + +**Strategy for Component Extensibility**: + +```typescript +// Component registry pattern +interface ComponentThemeDefinition { + name: string; + properties: PropertyDefinition[]; + schema: Record; + defaults: Record>; + generator: (options: ThemeOptions) => string; +} + +// Components can be added incrementally +const componentRegistry = new Map(); +``` + +--- + +## Data Extraction Strategy + +The MCP server needs embedded knowledge from the Sass source files. + +### Approach: Build-Time Extraction + +1. **Parse Sass files** during build to extract: + + - Color presets and multipliers -> JSON + - Typography presets -> JSON + - Elevation presets -> JSON + - Component schemas -> JSON + +2. **Embed as TypeScript constants**: + + ```typescript + // Generated from sass/color/presets/ + export const PALETTES = { + 'light-material': { primary: '#09f', secondary: '#df1b74', ... }, + // ... + } as const; + ``` + +3. **Existing JSON exports**: Leverage the existing `scripts/buildJSON.mjs` pipeline that already generates: + - `json/colors/presets/palettes.json` + - `json/colors/meta/multipliers.json` + - `json/typography/presets/typescales.json` + - `json/elevations/*.json` + +### Shade Generation Algorithm (To Embed) + +From `sass/color/_functions.scss`, the shade generation uses HSL manipulation with multipliers: + +```typescript +// Simplified shade generation logic +function generateShades(baseColor: string, multipliers: ShadeMultipliers): ShadeMap { + const hsl = parseToHSL(baseColor); + const shades: ShadeMap = {}; + + for (const [shade, factors] of Object.entries(multipliers)) { + shades[shade] = { + h: hsl.h, + s: clamp(hsl.s * factors.s, 0, 100), + l: clamp(hsl.l * factors.l, 0, 100), + }; + } + + return shades; +} +``` + +--- + +## Code Generation Templates + +The MCP server generates platform-specific Sass code based on the detected or specified platform. + +### Ignite UI for Angular + +```scss +// Generated by Ignite UI Theming MCP Server +// Platform: Angular + +@use "igniteui-angular/theming" as *; + +// Initialize core styles (required for Angular) +@include core(); + +// Custom palette +$my-palette: palette( + $primary: #2563eb, + $secondary: #7c3aed, + $surface: #ffffff, + $gray: #64748b, +); + +// Typography setup +@include typography( + $font-family: $material-typeface, + $type-scale: $material-type-scale +); + +// Apply complete theme (palette + schema + elevations) +@include theme( + $palette: $my-palette, + $schema: $light-material-schema +); +``` + +**Angular-specific notes:** +- Uses `igniteui-angular/theming` module (forwards igniteui-theming with overrides) +- Requires `core()` mixin to be called first +- Uses unified `theme()` mixin instead of individual `palette()`, `elevations()` calls +- Typography module is overridden with Angular-specific implementation +- Requires `ig-typography` CSS class on the root HTML element + +### Ignite UI for Web Components + +```scss +// Generated by Ignite UI Theming MCP Server +// Platform: Web Components + +@use "igniteui-theming/sass/color/presets/light/material" as light-preset; +@use "igniteui-theming" as *; +@use "igniteui-theming/sass/typography/presets/material" as typography-preset; +@use "igniteui-theming/sass/elevations/presets" as elevation-preset; + +// Theme identification variables +:root { + --ig-theme: material; + --ig-theme-variant: light; +} + +// Custom palette +$my-palette: palette( + $primary: #2563eb, + $secondary: #7c3aed, + $surface: #ffffff, + $gray: #64748b, +); + +// Apply palette (generates CSS custom properties) +@include palette($my-palette); + +// Typography setup +@include typography( + $font-family: typography-preset.$typeface, + $type-scale: typography-preset.$type-scale +); + +// Elevations +@include elevations(elevation-preset.$material-elevations); + +// Spacing (Web Components only) +@include spacing(); +``` + +**Web Components-specific notes:** +- Uses `igniteui-theming` directly (not via Angular forwarding) +- No `core()` or unified `theme()` mixins - uses individual mixins +- Supports runtime theme switching via `configureTheme()` JavaScript API +- Ships precompiled CSS themes in `dist/themes/` for zero-config usage +- Includes `spacing()` mixin for spacing CSS custom properties + +### CSS Output Example + +Both platforms generate similar CSS custom properties: + +```css +/* Generated by Ignite UI Theming MCP Server */ +:root { + /* Primary Color Shades */ + --ig-primary-50: hsl(217, 91%, 95%); + --ig-primary-100: hsl(217, 91%, 85%); + --ig-primary-200: hsl(217, 91%, 75%); + /* ... */ + --ig-primary-500: hsl(217, 91%, 59%); + /* ... */ + + /* Typography */ + --ig-font-family: 'Inter', system-ui, sans-serif; + --ig-h1-font-size: 6rem; + --ig-h1-font-weight: 300; + /* ... */ + + /* Elevations */ + --ig-elevation-1: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); + /* ... */ +} +``` + +--- + +## File Structure + +``` +src/mcp/ +├── index.ts # Entry point, server initialization +├── server.ts # MCP server configuration +├── transport/ +│ ├── stdio.ts # STDIO transport +│ └── http.ts # HTTP transport (future) +├── tools/ +│ ├── index.ts # Tool registry +│ ├── handlers/ # Tool handler implementations +│ │ ├── theme.ts # create_theme handler +│ │ ├── palette.ts # create_palette handler +│ │ ├── typography.ts # create_typography handler +│ │ ├── elevations.ts # create_elevations handler +│ │ └── platform.ts # detect_platform handler +│ └── schemas.ts # Zod schemas for tool inputs +├── resources/ +│ ├── index.ts # Resource registry +│ ├── presets.ts # Preset resources +│ ├── schemas.ts # Schema resources +│ ├── components.ts # Component catalog +│ └── docs.ts # Documentation resources +├── prompts/ +│ ├── index.ts # Prompt registry +│ └── templates.ts # Prompt definitions +├── generators/ +│ ├── sass.ts # Sass code generation (platform-aware) +│ ├── css.ts # CSS code generation +│ └── templates/ # Code templates +├── validators/ +│ ├── sass.ts # Sass validation (dart-sass) +│ └── contrast.ts # WCAG contrast validation +├── knowledge/ +│ ├── index.ts # Knowledge base exports +│ ├── palettes.ts # Embedded palette data +│ ├── typography.ts # Embedded typography data +│ ├── elevations.ts # Embedded elevation data +│ ├── multipliers.ts # Color multipliers +│ ├── platforms/ # Platform-specific knowledge +│ │ ├── index.ts # Platform exports, detection +│ │ ├── angular.ts # Angular platform config & generator +│ │ └── webcomponents.ts # Web Components platform config & generator +│ └── components/ # Component schemas +└── utils/ + ├── color.ts # Color manipulation utilities + ├── units.ts # Unit conversion + └── types.ts # TypeScript types +``` + +--- + +## Build Configuration + +### Vite Configuration + +```typescript +// vite.config.mcp.ts +import {defineConfig} from 'vite'; +import {resolve} from 'path'; + +export default defineConfig({ + build: { + lib: { + entry: resolve(__dirname, 'src/mcp/index.ts'), + formats: ['es'], + fileName: 'index', + }, + outDir: 'mcp', + rollupOptions: { + external: ['@modelcontextprotocol/sdk'], + }, + }, +}); +``` + +### Package.json Updates + +```json +{ + "bin": { + "igniteui-theming-mcp": "./mcp/index.js" + }, + "exports": { + "./mcp": { + "import": "./mcp/index.js" + } + }, + "files": ["mcp/"], + "scripts": { + "build:mcp": "vite build --config vite.config.mcp.ts", + "mcp:dev": "tsx src/mcp/index.ts" + } +} +``` + +--- + +## Dependencies + +### Runtime Dependencies + +```json +{ + "@modelcontextprotocol/sdk": "^1.0.0", + "zod": "^3.0.0" +} +``` + +### Optional Dependencies (for validation) + +```json +{ + "sass": "^1.92.0" +} +``` + +### Dev Dependencies + +```json +{ + "vite": "^5.0.0", + "typescript": "^5.0.0", + "tsx": "^4.0.0" +} +``` + +--- + +## Usage Examples + +### Claude Desktop Configuration + +```json +{ + "mcpServers": { + "igniteui-theming": { + "command": "npx", + "args": ["igniteui-theming/mcp"] + } + } +} +``` + +### Example Interaction + +**User**: "Create a dark theme for a healthcare app with a calming blue primary color" + +**AI uses `detect_platform` tool first** (optional, to auto-detect): + +```json +{ + "name": "detect_platform", + "arguments": { + "packageJsonPath": "./package.json" + } +} +``` + +**Response**: +```json +{ + "platform": "angular", + "confidence": "high", + "detectedPackage": "igniteui-angular", + "reason": "Found igniteui-angular in dependencies" +} +``` + +**AI uses `create_theme` tool**: + +```json +{ + "name": "create_theme", + "arguments": { + "platform": "angular", + "designSystem": "material", + "primaryColor": "#0891b2", + "variant": "dark", + "name": "healthcare-dark" + } +} +``` + +**Response**: Complete platform-specific Sass code with accessible color palette optimized for healthcare applications. + +### Example: Web Components Theme + +**User**: "I need a Material light theme for my web components project" + +**AI uses `create_theme` tool** (with explicit platform): + +```json +{ + "name": "create_theme", + "arguments": { + "platform": "webcomponents", + "designSystem": "material", + "primaryColor": "#3f51b5", + "variant": "light" + } +} +``` + +**Response**: Web Components-specific Sass code using `igniteui-theming` directly with individual `palette()`, `typography()`, and `elevations()` mixins. + +--- + +## Success Metrics + +1. **Functional**: All Phase 1 tools working correctly +2. **Quality**: Generated code compiles without errors +3. **Accessibility**: Generated themes pass WCAG AA by default +4. **Usability**: AI assistants can accomplish theming tasks in 1-2 tool calls +5. **Extensibility**: New components can be added without modifying core code + +--- + +## Open Questions + +1. **Sass Compilation for Validation**: Should we bundle dart-sass for runtime validation, or make it optional/lazy-loaded to reduce package size? + +2. **HTTP Transport**: Should Phase 1 include HTTP transport for remote hosting, or is STDIO sufficient for MVP? + +3. **Component Priority**: Which components should be prioritized for Phase 5? Suggest: button, card, input, grid (most commonly themed) + +4. **Caching**: Should validated themes be cached? What invalidation strategy? + +--- + +## Appendix: Theming Framework API Reference + +### Color Module (`sass/color/`) + +#### Public Functions + +- `palette($primary, $secondary, $surface, ...)` - Generate complete color palette +- `color($palette?, $color, $variant, $opacity?)` - Retrieve color from palette +- `contrast-color($palette?, $color, $variant, $opacity?)` - Get contrast color +- `adaptive-contrast($color)` - Runtime-calculated contrast color +- `luminance($color)` - Calculate relative luminance +- `contrast($background, $foreground)` - Calculate WCAG contrast ratio + +#### Public Mixins + +- `palette($palette, $contrast?, $contrast-level?)` - Generate CSS custom properties +- `adaptive-contrast($level?)` - Set up WCAG contrast variables +- `configure-colors($enhanced-accessibility?)` - Configure color module + +#### Presets + +- Light: `$light-material-palette`, `$light-bootstrap-palette`, `$light-fluent-palette`, `$light-indigo-palette` +- Dark: `$dark-material-palette`, `$dark-bootstrap-palette`, `$dark-fluent-palette`, `$dark-indigo-palette` + +### Typography Module (`sass/typography/`) + +#### Public Functions + +- `rem($pixels, $context?)` - Convert to rem units +- `em($pixels, $context?)` - Convert to em units +- `px($num, $context?)` - Convert to pixels +- `type-style(...)` - Create type style map +- `type-scale(...)` - Create complete type scale +- `type-scale-category($scale, $category)` - Get category from scale + +#### Public Mixins + +- `typography($font-family, $type-scale)` - Set up complete typography +- `type-style($category, $check?)` - Apply type style +- `type-style-vars($name, $type-style)` - Generate CSS variables + +#### Presets + +- `$material-typeface`, `$material-type-scale` +- `$bootstrap-typeface`, `$bootstrap-type-scale` +- `$fluent-typeface`, `$fluent-type-scale` +- `$indigo-typeface`, `$indigo-type-scale` + +### Elevations Module (`sass/elevations/`) + +#### Public Functions + +- `elevation($name)` - Get elevation CSS variable reference +- `box-shadow($shadows)` - Transform shadows with elevation factor + +#### Public Mixins + +- `elevations($elevations)` - Generate all elevation CSS variables +- `elevation($name)` - Apply elevation to element + +#### Presets + +- `$material-elevations` - 25 levels (0-24) +- `$indigo-elevations` - 25 levels (0-24) + +### Themes Module (`sass/themes/`) + +#### Public Functions + +- `sizable($sm, $md, $lg)` - Responsive sizing +- `pad($sm, $md, $lg, $dir?)` - Contextual padding +- `pad-inline($sm, $md, $lg)` - Inline padding +- `pad-block($sm, $md, $lg)` - Block padding + +#### Public Mixins + +- `css-vars-from-theme($theme)` - Output CSS custom properties from theme +- `sizable()` - Add size reactivity CSS properties +- `ellipsis()` - Text overflow ellipsis +- `line-clamp($lines, ...)` - Multi-line text truncation + +#### Design System Schemas + +- Light: `$light-material-schema`, `$light-bootstrap-schema`, `$light-fluent-schema`, `$light-indigo-schema` +- Dark: `$dark-material-schema`, `$dark-bootstrap-schema`, `$dark-fluent-schema`, `$dark-indigo-schema` + +### Animations Module (`sass/animations/`) + +#### Public Mixins + +- `keyframes($name)` - Register keyframe animation +- `animation($animate...)` - Apply animation + +#### Easing Variables + +- `$ease-in-quad`, `$ease-in-cubic`, `$ease-in-quart`, etc. +- `$ease-out-quad`, `$ease-out-cubic`, `$ease-out-quart`, etc. +- `$ease-in-out-quad`, `$ease-in-out-cubic`, etc. +--- + +## Next Steps + +1. Review and approve this plan +2. Set up project scaffolding with Vite +3. Implement Phase 1 tools +4. Test with Claude Desktop/Code and other AI assistants +5. Iterate based on feedback diff --git a/src/mcp/README.md b/src/mcp/README.md new file mode 100644 index 00000000..88bc3249 --- /dev/null +++ b/src/mcp/README.md @@ -0,0 +1,363 @@ +# Ignite UI Theming MCP Server + +A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that enables AI assistants to generate production-ready theming code for Ignite UI components. + +## Overview + +This MCP server helps you create custom themes for Ignite UI applications by generating Sass code for: + +- **Color Palettes** - Primary, secondary, surface, and semantic colors with automatic shade generation +- **Typography** - Font families and type scales following design system conventions +- **Elevations** - Shadow definitions for visual depth and hierarchy +- **Complete Themes** - All of the above combined into a ready-to-use theme + +### Supported Platforms + +| Platform | Package | Description | +|----------|---------|-------------| +| `angular` | `igniteui-angular` | Ignite UI for Angular applications | +| `webcomponents` | `igniteui-webcomponents` | Ignite UI for Web Components | + +### Supported Design Systems + +- **Material** - Google Material Design +- **Bootstrap** - Bootstrap design language +- **Fluent** - Microsoft Fluent Design +- **Indigo** - Infragistics Indigo Design + +--- + +## Quick Start + +### 1. Install the Package + +```bash +npm install igniteui-theming +``` + +### 2. Build the MCP Server + +```bash +npm run build:mcp +``` + +### 3. Configure Your AI Client + +#### Claude Desktop + +Add to your Claude Desktop configuration file: + +**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` +**Windows**: `%APPDATA%\Claude\claude_desktop_config.json` + +```json +{ + "mcpServers": { + "igniteui-theming": { + "command": "node", + "args": ["/path/to/igniteui-theming/dist/mcp/index.js"] + } + } +} +``` + +#### Using npx (after publishing) + +```json +{ + "mcpServers": { + "igniteui-theming": { + "command": "npx", + "args": ["igniteui-theming/mcp"] + } + } +} +``` + +--- + +## Tools Reference + +The MCP server provides 6 tools for theme generation. + +### `detect_platform` + +Automatically detects whether your project uses Ignite UI for Angular or Web Components by analyzing `package.json`. + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `packageJsonPath` | string | No | Path to package.json (default: `./package.json`) | + +**Example prompt:** +> "Detect which Ignite UI platform my project uses" + +--- + +### `create_palette` + +Generates a color palette with automatically calculated shade variations (50-900, A100-A700). + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `platform` | `"angular"` \| `"webcomponents"` | No | Target platform | +| `primary` | string | Yes | Primary brand color (hex, rgb, hsl, or named) | +| `secondary` | string | Yes | Secondary/accent color | +| `surface` | string | Yes | Background/surface color | +| `gray` | string | No | Gray/neutral color (auto-calculated if omitted) | +| `info` | string | No | Info state color | +| `success` | string | No | Success state color | +| `warn` | string | No | Warning state color | +| `error` | string | No | Error state color | +| `variant` | `"light"` \| `"dark"` | No | Theme variant (default: `"light"`) | +| `name` | string | No | Custom variable name | + +**Example prompts:** +> "Create a color palette with blue (#1976D2) as primary and orange (#FF9800) as secondary for a light theme" + +> "Generate a dark theme palette using my brand colors: primary #6366F1, secondary #EC4899, surface #1E1E1E" + +--- + +### `create_custom_palette` + +Creates a palette with fine-grained control over individual shade values. Use this when you have exact brand guidelines or when automatic shade generation produces suboptimal results. + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `platform` | `"angular"` \| `"webcomponents"` | No | Target platform | +| `variant` | `"light"` \| `"dark"` | No | Theme variant | +| `designSystem` | `"material"` \| `"bootstrap"` \| `"fluent"` \| `"indigo"` | No | Design system preset | +| `name` | string | No | Custom variable name | +| `primary` | ColorDefinition | Yes | Primary color definition | +| `secondary` | ColorDefinition | Yes | Secondary color definition | +| `surface` | ColorDefinition | Yes | Surface color definition | +| `gray` | ColorDefinition | No | Gray color definition | +| `info` | ColorDefinition | No | Info color definition | +| `success` | ColorDefinition | No | Success color definition | +| `warn` | ColorDefinition | No | Warning color definition | +| `error` | ColorDefinition | No | Error color definition | + +**ColorDefinition** can be: +- `{ mode: "shades", baseColor: "#hexcolor" }` - Auto-generate shades from base color +- `{ mode: "explicit", shades: { "50": "#...", "100": "#...", ... } }` - Specify all 14 shades manually + +**Example prompts:** +> "Create a custom palette where primary uses explicit shades from my brand guidelines, but secondary and surface are auto-generated" + +> "I have exact hex values for all 14 shades of my primary green color. Create a custom palette with these explicit values." + +--- + +### `create_typography` + +Sets up typography with your preferred font family. + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `platform` | `"angular"` \| `"webcomponents"` | No | Target platform | +| `fontFamily` | string | Yes | Font family with fallbacks | +| `designSystem` | `"material"` \| `"bootstrap"` \| `"fluent"` \| `"indigo"` | No | Design system for type scale | +| `name` | string | No | Custom variable name | + +**Example prompts:** +> "Set up typography using Inter font with Material Design type scale" + +> "Configure typography with 'Segoe UI', Arial, sans-serif for a Fluent design system" + +--- + +### `create_elevations` + +Configures elevation shadows for visual depth. + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `platform` | `"angular"` \| `"webcomponents"` | No | Target platform | +| `designSystem` | `"material"` \| `"indigo"` | No | Elevation preset | +| `name` | string | No | Custom variable name | + +**Example prompts:** +> "Set up Material Design elevations for my Angular app" + +> "Create Indigo-style shadows for my web components project" + +--- + +### `create_theme` + +Generates a complete, production-ready theme with palette, typography, and elevations combined. + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `platform` | `"angular"` \| `"webcomponents"` | No | Target platform | +| `designSystem` | `"material"` \| `"bootstrap"` \| `"fluent"` \| `"indigo"` | No | Design system | +| `primaryColor` | string | Yes | Primary brand color | +| `secondaryColor` | string | Yes | Secondary/accent color | +| `surfaceColor` | string | Yes | Background/surface color | +| `variant` | `"light"` \| `"dark"` | No | Theme variant | +| `name` | string | No | Custom theme name | +| `fontFamily` | string | No | Font family | +| `includeTypography` | boolean | No | Include typography (default: `true`) | +| `includeElevations` | boolean | No | Include elevations (default: `true`) | +| `includeSpacing` | boolean | No | Include spacing - Web Components only (default: `true`) | + +**Example prompts:** +> "Create a complete Material Design dark theme for my Angular app with primary #3F51B5, secondary #FF4081, and a dark surface" + +> "Generate a production-ready Bootstrap light theme using my brand colors: primary teal (#009688), secondary amber (#FFC107)" + +> "Create a Fluent theme for Web Components with Segoe UI font, blue primary, and orange accent colors" + +--- + +## Resources Reference + +The MCP server exposes read-only resources that provide reference data. + +### Platform Resources + +| URI | Description | +|-----|-------------| +| `theming://platforms` | List of supported platforms | +| `theming://platforms/angular` | Angular platform configuration and usage examples | +| `theming://platforms/webcomponents` | Web Components platform configuration and examples | + +### Preset Resources + +| URI | Description | +|-----|-------------| +| `theming://presets/palettes` | All predefined palette configurations | +| `theming://presets/palettes/light` | Light mode palette presets | +| `theming://presets/palettes/dark` | Dark mode palette presets | +| `theming://presets/typography` | Typography presets for all design systems | +| `theming://presets/elevations` | Elevation shadow presets | + +### Color Guidance Resources + +| URI | Description | +|-----|-------------| +| `theming://guidance/colors` | Overview of color guidance resources | +| `theming://guidance/colors/rules` | Light/dark theme color rules | +| `theming://guidance/colors/usage` | Which shades to use for different purposes | +| `theming://guidance/colors/roles` | Semantic meaning of each color family | +| `theming://guidance/colors/states` | Color changes for interaction states | +| `theming://guidance/colors/themes` | Design system-specific color patterns | + +--- + +## Example Usage Scenarios + +### Scenario 1: New Project Setup + +> "I'm starting a new Angular project with Ignite UI. Create a complete Material Design theme with: +> - Primary: our brand blue #2563EB +> - Secondary: coral accent #F97316 +> - Light theme +> - Roboto font" + +The AI will use `create_theme` to generate ready-to-use Sass code. + +### Scenario 2: Dark Mode Variant + +> "I need a dark mode version of my theme. Use the same primary blue #2563EB but with a dark surface color #121212" + +### Scenario 3: Brand Guidelines with Exact Colors + +> "Our design system specifies exact hex values for each shade of our primary green. I'll provide all 14 values - create a custom palette with these explicit shades." + +The AI will use `create_custom_palette` with `mode: "explicit"`. + +### Scenario 4: Typography Only + +> "I just need to change the font to Inter for my existing Material theme" + +The AI will use `create_typography` to generate only the typography setup. + +### Scenario 5: Platform Detection + +> "Check my package.json and tell me which Ignite UI platform I'm using, then create an appropriate theme" + +The AI will first use `detect_platform`, then use the detected platform for `create_theme`. + +--- + +## Platform Differences + +### Ignite UI for Angular + +- Uses `@use "igniteui-angular/theming"` module +- Requires `core()` mixin to be called first +- Uses unified `theme()` mixin +- Requires `ig-typography` CSS class on root element + +### Ignite UI for Web Components + +- Uses `@use "igniteui-theming"` directly +- Uses individual mixins (`palette()`, `typography()`, `elevations()`) +- Supports runtime theme switching via JavaScript API +- Includes optional `spacing()` mixin + +--- + +## Development + +### Running in Development Mode + +```bash +npm run mcp:dev +``` + +### Running Tests + +```bash +npm run test:mcp +``` + +### Building + +```bash +npm run build:mcp +``` + +### Debugging with MCP Inspector + +```bash +npm run mcp:inspector +``` + +--- + +## Troubleshooting + +### "Platform not detected" + +If `detect_platform` returns `null`, ensure: +- The `package.json` path is correct +- Your project has `igniteui-angular` or `igniteui-webcomponents` in dependencies + +You can always specify the `platform` parameter explicitly. + +### "Luminance warning" on colors + +If you see warnings about color luminance, it means your chosen color may produce suboptimal automatic shade generation. Options: +1. Choose a color with mid-range luminance (not too light or too dark) +2. Use `create_custom_palette` with explicit shade values + +### "Surface color doesn't match variant" + +For light themes, use light surface colors (high luminance like `#FAFAFA`). +For dark themes, use dark surface colors (low luminance like `#121212`). + +### Generated code doesn't compile + +Ensure you have the correct Ignite UI package installed: +- Angular: `npm install igniteui-angular` +- Web Components: `npm install igniteui-webcomponents` + +--- + +## Related Documentation + +- [Ignite UI for Angular Theming](https://www.infragistics.com/products/ignite-ui-angular/angular/components/themes/index) +- [Ignite UI for Web Components Theming](https://www.infragistics.com/products/ignite-ui-web-components/web-components/components/themes/overview) +- [Model Context Protocol](https://modelcontextprotocol.io/) diff --git a/src/mcp/__tests__/generators/sass.test.ts b/src/mcp/__tests__/generators/sass.test.ts new file mode 100644 index 00000000..5c6cfafb --- /dev/null +++ b/src/mcp/__tests__/generators/sass.test.ts @@ -0,0 +1,518 @@ +/** + * Tests for Sass code generators. + * + * These tests verify: + * 1. Generated code contains expected Sass constructs + * 2. Generated code structure is correct for each platform + * 3. Variables and descriptions are set correctly + * + * Note: Full Sass compilation tests are limited because generated code + * uses variables (like $material-type-scale) that are defined within + * the theming library's context. We focus on structural validation. + */ + +import {describe, it, expect} from 'vitest'; +import * as sass from 'sass-embedded'; +import * as path from 'path'; +import {fileURLToPath} from 'url'; +import {generatePalette, generateTypography, generateElevations, generateTheme} from '../../generators/sass.js'; + +// Get the package root directory (where sass/ folder is located) +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +// From src/mcp/__tests__/generators/ we need to go up 4 levels to package root +const PACKAGE_ROOT = path.resolve(__dirname, '..', '..', '..', '..'); + +/** + * Rewrites generated Sass code to use local paths for testing. + * Replaces package imports with local sass/ directory imports. + */ +function rewriteImportsForTesting(code: string): string { + return code + .replace(/@use ['"]igniteui-angular\/theming['"] as \*;/g, "@use 'sass' as *;") + .replace(/@use ['"]igniteui-theming['"] as \*;/g, "@use 'sass' as *;"); +} + +/** + * Helper to compile Sass code and verify it's valid. + * Returns the compiled CSS or throws on error. + */ +async function compileSass(code: string): Promise { + const testCode = rewriteImportsForTesting(code); + const result = await sass.compileStringAsync(testCode, { + loadPaths: [PACKAGE_ROOT], + }); + return result.css; +} + +/** + * Helper to check if Sass code compiles without errors. + */ +async function isValidSass(code: string): Promise { + try { + await compileSass(code); + return true; + } catch { + return false; + } +} + +describe('generatePalette', () => { + it('generates valid Sass code that compiles', async () => { + const result = generatePalette({ + primary: '#2ab759', + secondary: '#f7bd32', + surface: 'white', + }); + + expect(result.code).toContain('@use'); + expect(result.code).toContain('palette('); + expect(result.code).toContain('$primary: #2ab759'); + expect(result.code).toContain('$secondary: #f7bd32'); + expect(result.code).toContain('$surface: white'); + // This should compile because palette() has all required args + expect(await isValidSass(result.code)).toBe(true); + }); + + it('includes optional colors when provided', async () => { + const result = generatePalette({ + primary: '#2ab759', + secondary: '#f7bd32', + surface: 'white', + gray: '#333', + info: '#0288d1', + success: '#4caf50', + warn: '#ff9800', + error: '#f44336', + }); + + expect(result.code).toContain('$gray: #333'); + expect(result.code).toContain('$info: #0288d1'); + expect(result.code).toContain('$success: #4caf50'); + expect(result.code).toContain('$warn: #ff9800'); + expect(result.code).toContain('$error: #f44336'); + expect(await isValidSass(result.code)).toBe(true); + }); + + it('uses custom name for palette variable', () => { + const result = generatePalette({ + primary: '#2ab759', + secondary: '#f7bd32', + surface: 'white', + name: 'my-brand', + }); + + expect(result.variables).toContain('$my-brand-palette'); + expect(result.code).toContain('$my-brand-palette'); + }); + + it('uses variant in default variable name', () => { + const result = generatePalette({ + primary: '#2ab759', + secondary: '#f7bd32', + surface: '#121212', + variant: 'dark', + }); + + expect(result.variables).toContain('$custom-dark-palette'); + expect(result.description).toContain('dark'); + }); + + it('uses Angular import for angular platform', () => { + const result = generatePalette({ + platform: 'angular', + primary: '#2ab759', + secondary: '#f7bd32', + surface: 'white', + }); + + expect(result.code).toContain('igniteui-angular/theming'); + }); + + it('uses generic import for webcomponents platform', () => { + const result = generatePalette({ + platform: 'webcomponents', + primary: '#2ab759', + secondary: '#f7bd32', + surface: 'white', + }); + + expect(result.code).toContain('igniteui-theming'); + expect(result.code).not.toContain('igniteui-angular'); + }); +}); + +describe('generateTypography', () => { + it('generates code with correct structure', () => { + const result = generateTypography({ + fontFamily: 'Roboto', + }); + + expect(result.code).toContain('@use'); + expect(result.code).toContain('@include typography('); + expect(result.code).toContain('$font-family:'); + expect(result.code).toContain('$type-scale:'); + }); + + it('uses design system type scale variable', () => { + const result = generateTypography({ + fontFamily: 'Roboto', + designSystem: 'indigo', + }); + + expect(result.variables).toContain('$indigo-type-scale'); + expect(result.code).toContain('$indigo-type-scale'); + expect(result.description).toContain('indigo'); + }); + + it('quotes font family correctly', () => { + const result = generateTypography({ + fontFamily: 'Open Sans', + }); + + expect(result.code).toContain("'Open Sans'"); + }); + + it('handles font stacks with quotes', () => { + const result = generateTypography({ + fontFamily: "'Titillium Web', sans-serif", + }); + + // Font stack should be wrapped in quotes + expect(result.code).toContain('"\'Titillium Web\', sans-serif"'); + }); +}); + +describe('generateElevations', () => { + it('generates code with correct structure', () => { + const result = generateElevations({}); + + expect(result.code).toContain('@use'); + expect(result.code).toContain('@include elevations('); + }); + + it('uses material elevations by default', () => { + const result = generateElevations({}); + + expect(result.variables).toContain('$material-elevations'); + expect(result.code).toContain('$material-elevations'); + }); + + it('uses indigo elevations when specified', () => { + const result = generateElevations({ + designSystem: 'indigo', + }); + + expect(result.variables).toContain('$indigo-elevations'); + expect(result.code).toContain('$indigo-elevations'); + }); +}); + +describe('generateTheme', () => { + describe('platform-agnostic (no platform specified)', () => { + it('generates code with correct structure', () => { + const result = generateTheme({ + primaryColor: '#2ab759', + }); + + expect(result.code).toContain('@use'); + expect(result.code).toContain('palette('); + expect(result.code).toContain('@include palette('); + }); + + it('includes typography by default', () => { + const result = generateTheme({ + primaryColor: '#2ab759', + }); + + expect(result.code).toContain('@include typography('); + }); + + it('includes elevations by default', () => { + const result = generateTheme({ + primaryColor: '#2ab759', + }); + + expect(result.code).toContain('@include elevations('); + }); + + it('can exclude typography', () => { + const result = generateTheme({ + primaryColor: '#2ab759', + includeTypography: false, + }); + + expect(result.code).not.toContain('@include typography('); + }); + + it('can exclude elevations', () => { + const result = generateTheme({ + primaryColor: '#2ab759', + includeElevations: false, + }); + + expect(result.code).not.toContain('@include elevations('); + }); + + it('uses dark surface color for dark variant', () => { + const result = generateTheme({ + primaryColor: '#2ab759', + variant: 'dark', + }); + + expect(result.code).toContain('$surface: #222222'); + }); + }); + + describe('Angular platform', () => { + it('generates code with core() and theme() mixins', () => { + const result = generateTheme({ + platform: 'angular', + primaryColor: '#2ab759', + designSystem: 'material', + }); + + expect(result.code).toContain('igniteui-angular/theming'); + expect(result.code).toContain('@include core()'); + expect(result.code).toContain('@include theme('); + expect(result.description).toContain('Angular'); + }); + + it('uses design system schema', () => { + const result = generateTheme({ + platform: 'angular', + primaryColor: '#2ab759', + designSystem: 'indigo', + variant: 'dark', + }); + + expect(result.variables).toContain('$dark-indigo-schema'); + }); + }); + + describe('Web Components platform', () => { + it('generates code with individual mixins', () => { + const result = generateTheme({ + platform: 'webcomponents', + primaryColor: '#2ab759', + designSystem: 'material', + }); + + expect(result.code).toContain('igniteui-theming'); + expect(result.code).not.toContain('igniteui-angular'); + expect(result.code).toContain('@include palette('); + expect(result.description).toContain('Web Components'); + }); + + it('includes spacing by default', () => { + const result = generateTheme({ + platform: 'webcomponents', + primaryColor: '#2ab759', + }); + + expect(result.code).toContain('@include spacing('); + }); + + it('can exclude spacing', () => { + const result = generateTheme({ + platform: 'webcomponents', + primaryColor: '#2ab759', + includeSpacing: false, + }); + + expect(result.code).not.toContain('@include spacing('); + }); + + it('uses correct elevation preset for design system', () => { + const indigoResult = generateTheme({ + platform: 'webcomponents', + primaryColor: '#2ab759', + designSystem: 'indigo', + }); + + expect(indigoResult.variables).toContain('$indigo-elevations'); + + const materialResult = generateTheme({ + platform: 'webcomponents', + primaryColor: '#2ab759', + designSystem: 'material', + }); + + expect(materialResult.variables).toContain('$material-elevations'); + }); + }); + + describe('React platform', () => { + it('generates Web Components-style code (uses igniteui-theming)', () => { + const result = generateTheme({ + platform: 'react', + primaryColor: '#2ab759', + designSystem: 'material', + }); + + expect(result.code).toContain('igniteui-theming'); + expect(result.code).not.toContain('igniteui-angular'); + }); + + it('generates individual mixins, not Angular core()/theme() pattern', () => { + const result = generateTheme({ + platform: 'react', + primaryColor: '#2ab759', + designSystem: 'material', + }); + + expect(result.code).toContain('@include palette('); + expect(result.code).toContain('@include elevations('); + expect(result.code).toContain('@include typography('); + // Angular-specific: core() mixin is never used in Web Components/React/Blazor + expect(result.code).not.toContain('@include core('); + // Note: WC generator creates a @mixin theme() wrapper, but does NOT use Angular's theme() mixin + // The key difference is: no $schema parameter and no igniteui-angular/theming import + expect(result.code).not.toContain('$schema:'); + }); + + it('includes spacing by default', () => { + const result = generateTheme({ + platform: 'react', + primaryColor: '#2ab759', + }); + + expect(result.code).toContain('@include spacing('); + }); + + it('can exclude spacing', () => { + const result = generateTheme({ + platform: 'react', + primaryColor: '#2ab759', + includeSpacing: false, + }); + + expect(result.code).not.toContain('@include spacing('); + }); + + it('uses correct elevation preset for design system', () => { + const indigoResult = generateTheme({ + platform: 'react', + primaryColor: '#2ab759', + designSystem: 'indigo', + }); + + expect(indigoResult.variables).toContain('$indigo-elevations'); + + const materialResult = generateTheme({ + platform: 'react', + primaryColor: '#2ab759', + designSystem: 'material', + }); + + expect(materialResult.variables).toContain('$material-elevations'); + }); + + it('description mentions Web Components (shared generator)', () => { + const result = generateTheme({ + platform: 'react', + primaryColor: '#2ab759', + }); + + expect(result.description).toContain('Web Components'); + }); + }); + + describe('Blazor platform', () => { + it('generates Web Components-style code (uses igniteui-theming)', () => { + const result = generateTheme({ + platform: 'blazor', + primaryColor: '#2ab759', + designSystem: 'material', + }); + + expect(result.code).toContain('igniteui-theming'); + expect(result.code).not.toContain('igniteui-angular'); + }); + + it('generates individual mixins, not Angular core()/theme() pattern', () => { + const result = generateTheme({ + platform: 'blazor', + primaryColor: '#2ab759', + designSystem: 'material', + }); + + expect(result.code).toContain('@include palette('); + expect(result.code).toContain('@include elevations('); + expect(result.code).toContain('@include typography('); + // Angular-specific: core() mixin is never used in Web Components/React/Blazor + expect(result.code).not.toContain('@include core('); + // Note: WC generator creates a @mixin theme() wrapper, but does NOT use Angular's theme() mixin + // The key difference is: no $schema parameter and no igniteui-angular/theming import + expect(result.code).not.toContain('$schema:'); + }); + + it('includes spacing by default', () => { + const result = generateTheme({ + platform: 'blazor', + primaryColor: '#2ab759', + }); + + expect(result.code).toContain('@include spacing('); + }); + + it('uses correct elevation preset for design system', () => { + const indigoResult = generateTheme({ + platform: 'blazor', + primaryColor: '#2ab759', + designSystem: 'indigo', + }); + + expect(indigoResult.variables).toContain('$indigo-elevations'); + + const materialResult = generateTheme({ + platform: 'blazor', + primaryColor: '#2ab759', + designSystem: 'material', + }); + + expect(materialResult.variables).toContain('$material-elevations'); + }); + + it('description mentions Web Components (shared generator)', () => { + const result = generateTheme({ + platform: 'blazor', + primaryColor: '#2ab759', + }); + + expect(result.description).toContain('Web Components'); + }); + }); + + describe('custom naming', () => { + it('uses custom name for palette variable', () => { + const result = generateTheme({ + primaryColor: '#2ab759', + name: 'my-brand', + }); + + expect(result.variables).toContain('$my-brand-palette'); + expect(result.code).toContain('$my-brand-palette'); + }); + + it('uses custom name in Angular theme', () => { + const result = generateTheme({ + platform: 'angular', + primaryColor: '#2ab759', + name: 'corporate', + }); + + expect(result.variables).toContain('$corporate-palette'); + }); + + it('uses custom name in Web Components theme', () => { + const result = generateTheme({ + platform: 'webcomponents', + primaryColor: '#2ab759', + name: 'app-theme', + }); + + expect(result.variables).toContain('$app-theme-palette'); + }); + }); +}); diff --git a/src/mcp/__tests__/knowledge/angular.test.ts b/src/mcp/__tests__/knowledge/angular.test.ts new file mode 100644 index 00000000..0898c672 --- /dev/null +++ b/src/mcp/__tests__/knowledge/angular.test.ts @@ -0,0 +1,309 @@ +/** + * Tests for Angular theme generation. + * + * Tests verify the generateAngularThemeSass function produces + * correct Sass code for Ignite UI for Angular applications. + */ + +import {describe, it, expect} from 'vitest'; +import {generateAngularThemeSass} from '../../knowledge/platforms/angular.js'; + +describe('generateAngularThemeSass', () => { + describe('basic theme generation', () => { + it('generates code with correct header and platform comment', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + }); + + expect(code).toContain('// Generated by Ignite UI Theming MCP Server'); + expect(code).toContain('// Platform: Ignite UI for Angular'); + }); + + it('imports igniteui-angular/theming module', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + }); + + expect(code).toContain('@use "igniteui-angular/theming" as *;'); + }); + + it('includes core() mixin', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + }); + + expect(code).toContain('@include core()'); + }); + + it('includes theme() mixin with palette and schema', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + }); + + expect(code).toContain('@include theme('); + expect(code).toContain('$palette:'); + expect(code).toContain('$schema:'); + }); + }); + + describe('typography handling', () => { + it('includes typography mixin by default', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + }); + + expect(code).toContain('@include typography('); + }); + + it('uses design system typeface variable', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + }); + + expect(code).toContain('$material-typeface'); + expect(code).toContain('$material-type-scale'); + }); + + it('uses indigo typeface for indigo design system', () => { + const code = generateAngularThemeSass({ + designSystem: 'indigo', + variant: 'light', + }); + + expect(code).toContain('$indigo-typeface'); + expect(code).toContain('$indigo-type-scale'); + }); + + it('uses custom font family when provided', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + fontFamily: 'Inter', + }); + + expect(code).toContain("'Inter'"); + // Should not use the preset typeface variable + expect(code).not.toContain('$material-typeface'); + }); + + it('excludes typography when includeTypography is false', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + includeTypography: false, + }); + + expect(code).not.toContain('@include typography('); + }); + }); + + describe('custom palette', () => { + it('generates custom palette when colors are provided', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + primaryColor: '#2ab759', + secondaryColor: '#f7bd32', + surfaceColor: '#ffffff', + }); + + expect(code).toContain('$primary-color: #2ab759'); + expect(code).toContain('$secondary-color: #f7bd32'); + expect(code).toContain('$surface-color: #ffffff'); + expect(code).toContain('palette('); + }); + + it('uses custom palette name when provided', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + primaryColor: '#2ab759', + customPaletteName: '$corporate-palette', + }); + + expect(code).toContain('$corporate-palette'); + }); + + it('uses preset palette when no custom colors', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + }); + + expect(code).toContain('$light-material-palette'); + // Should not have custom color variables + expect(code).not.toContain('$primary-color:'); + }); + + it('includes gray color when provided', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + primaryColor: '#2ab759', + grayColor: '#9e9e9e', + }); + + expect(code).toContain('$gray-color: #9e9e9e'); + }); + }); + + describe('design systems and variants', () => { + it('uses correct schema for light material', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + }); + + expect(code).toContain('$light-material-schema'); + }); + + it('uses correct schema for dark material', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'dark', + }); + + expect(code).toContain('$dark-material-schema'); + }); + + it('uses correct schema for dark indigo', () => { + const code = generateAngularThemeSass({ + designSystem: 'indigo', + variant: 'dark', + }); + + expect(code).toContain('$dark-indigo-schema'); + }); + + it('uses correct schema for light fluent', () => { + const code = generateAngularThemeSass({ + designSystem: 'fluent', + variant: 'light', + }); + + expect(code).toContain('$light-fluent-schema'); + }); + + it('uses correct schema for light bootstrap', () => { + const code = generateAngularThemeSass({ + designSystem: 'bootstrap', + variant: 'light', + }); + + expect(code).toContain('$light-bootstrap-schema'); + }); + + it('uses correct palette for dark indigo preset', () => { + const code = generateAngularThemeSass({ + designSystem: 'indigo', + variant: 'dark', + }); + + expect(code).toContain('$dark-indigo-palette'); + }); + }); + + describe('core mixin options', () => { + it('defaults to core() with no arguments', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + }); + + expect(code).toContain('@include core();'); + }); + + it('adds $print-layout: false when specified', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + coreOptions: { + printLayout: false, + }, + }); + + expect(code).toContain('@include core($print-layout: false)'); + }); + + it('adds $enhanced-accessibility: true when specified', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + coreOptions: { + enhancedAccessibility: true, + }, + }); + + expect(code).toContain('@include core($enhanced-accessibility: true)'); + }); + + it('combines multiple core options', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + coreOptions: { + printLayout: false, + enhancedAccessibility: true, + }, + }); + + expect(code).toContain('@include core($print-layout: false, $enhanced-accessibility: true)'); + }); + }); + + describe('theme mixin options', () => { + it('adds $roundness when specified', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + themeOptions: { + roundness: 0.5, + }, + }); + + expect(code).toContain('$roundness: 0.5'); + }); + + it('adds $elevation: false when specified', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + themeOptions: { + elevation: false, + }, + }); + + expect(code).toContain('$elevation: false'); + }); + + it('adds custom $elevations when specified', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + themeOptions: { + elevations: '$custom-elevations', + }, + }); + + expect(code).toContain('$elevations: $custom-elevations'); + }); + + it('adds $exclude list when specified', () => { + const code = generateAngularThemeSass({ + designSystem: 'material', + variant: 'light', + themeOptions: { + exclude: ['igx-avatar', 'igx-badge'], + }, + }); + + expect(code).toContain('$exclude: (igx-avatar, igx-badge)'); + }); + }); +}); diff --git a/src/mcp/__tests__/knowledge/platform-detection.test.ts b/src/mcp/__tests__/knowledge/platform-detection.test.ts new file mode 100644 index 00000000..ba6ddebf --- /dev/null +++ b/src/mcp/__tests__/knowledge/platform-detection.test.ts @@ -0,0 +1,488 @@ +/** + * Tests for platform detection functionality + * + * Tests cover: + * - Ignite UI package detection (Angular, Web Components, React) + * - Config file detection (angular.json, vite.config.*, next.config.*, .csproj) + * - Framework fallback detection + * - Ambiguous platform scenarios + * - Confidence scoring + */ + +import {describe, it, expect, vi, beforeEach, afterEach} from 'vitest'; +import {detectPlatformFromDependencies, detectConfigFiles} from '../../knowledge/platforms/index.js'; + +// Mock fs module +vi.mock('node:fs', async () => { + const actual = await vi.importActual('node:fs'); + return { + ...actual, + existsSync: vi.fn(), + readFileSync: vi.fn(), + readdirSync: vi.fn(), + }; +}); + +import {existsSync, readFileSync, readdirSync} from 'node:fs'; + +const mockExistsSync = vi.mocked(existsSync); +const mockReadFileSync = vi.mocked(readFileSync); +const mockReaddirSync = vi.mocked(readdirSync); + +describe('detectPlatformFromDependencies', () => { + beforeEach(() => { + vi.clearAllMocks(); + // Default: no config files exist + mockExistsSync.mockReturnValue(false); + mockReaddirSync.mockReturnValue([]); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + describe('Angular detection', () => { + it('detects igniteui-angular package with high confidence', () => { + const result = detectPlatformFromDependencies({'igniteui-angular': '^18.0.0'}, {}); + + expect(result.platform).toBe('angular'); + expect(result.confidence).toBe('high'); + expect(result.detectedPackage).toBe('igniteui-angular'); + expect(result.signals).toContainEqual({ + type: 'ignite_package', + package: 'igniteui-angular', + confidence: 100, + }); + }); + + it('detects @infragistics/igniteui-angular commercial package', () => { + const result = detectPlatformFromDependencies({'@infragistics/igniteui-angular': '^18.0.0'}, {}); + + expect(result.platform).toBe('angular'); + expect(result.confidence).toBe('high'); + expect(result.detectedPackage).toBe('@infragistics/igniteui-angular'); + }); + + it('detects Angular from devDependencies', () => { + const result = detectPlatformFromDependencies({}, {'igniteui-angular': '^18.0.0'}); + + expect(result.platform).toBe('angular'); + expect(result.confidence).toBe('high'); + }); + + it('detects Angular from angular.json config file', () => { + mockExistsSync.mockImplementation((path) => { + return String(path).includes('angular.json'); + }); + + const result = detectPlatformFromDependencies({}, {}, '/project'); + + expect(result.platform).toBe('angular'); + expect(result.confidence).toBe('high'); // 80 rounds to high + expect(result.signals).toContainEqual({ + type: 'config_file', + file: 'angular.json', + confidence: 80, + }); + }); + + it('uses @angular/core as fallback with low confidence', () => { + const result = detectPlatformFromDependencies({'@angular/core': '^18.0.0'}, {}); + + expect(result.platform).toBe('angular'); + expect(result.confidence).toBe('low'); + expect(result.signals).toContainEqual({ + type: 'framework_package', + package: '@angular/core', + confidence: 40, + }); + }); + }); + + describe('Web Components detection', () => { + it('detects igniteui-webcomponents package with high confidence', () => { + const result = detectPlatformFromDependencies({'igniteui-webcomponents': '^5.0.0'}, {}); + + expect(result.platform).toBe('webcomponents'); + expect(result.confidence).toBe('high'); + expect(result.detectedPackage).toBe('igniteui-webcomponents'); + }); + + it('detects @infragistics/igniteui-webcomponents commercial package', () => { + const result = detectPlatformFromDependencies({'@infragistics/igniteui-webcomponents': '^5.0.0'}, {}); + + expect(result.platform).toBe('webcomponents'); + expect(result.confidence).toBe('high'); + }); + + it('uses lit as fallback with low confidence', () => { + const result = detectPlatformFromDependencies({lit: '^3.0.0'}, {}); + + expect(result.platform).toBe('webcomponents'); + expect(result.confidence).toBe('low'); + expect(result.signals).toContainEqual({ + type: 'framework_package', + package: 'lit', + confidence: 40, + }); + }); + }); + + describe('React detection', () => { + it('detects igniteui-react package with high confidence', () => { + const result = detectPlatformFromDependencies({'igniteui-react': '^18.0.0'}, {}); + + expect(result.platform).toBe('react'); + expect(result.confidence).toBe('high'); + expect(result.detectedPackage).toBe('igniteui-react'); + }); + + it('detects @infragistics/igniteui-react commercial package', () => { + const result = detectPlatformFromDependencies({'@infragistics/igniteui-react': '^18.0.0'}, {}); + + expect(result.platform).toBe('react'); + expect(result.confidence).toBe('high'); + }); + + it('detects React from vite.config.ts with @vitejs/plugin-react', () => { + mockExistsSync.mockImplementation((path) => { + return String(path).includes('vite.config.ts'); + }); + mockReadFileSync.mockReturnValue(` + import { defineConfig } from 'vite'; + import react from '@vitejs/plugin-react'; + export default defineConfig({ plugins: [react()] }); + `); + + const result = detectPlatformFromDependencies({}, {}, '/project'); + + expect(result.platform).toBe('react'); + expect(result.confidence).toBe('high'); + expect(result.signals).toContainEqual({ + type: 'config_file', + file: 'vite.config.ts', + confidence: 80, + }); + }); + + it('detects React from next.config.js', () => { + mockExistsSync.mockImplementation((path) => { + return String(path).includes('next.config.js'); + }); + + const result = detectPlatformFromDependencies({}, {}, '/project'); + + expect(result.platform).toBe('react'); + expect(result.confidence).toBe('high'); + expect(result.signals).toContainEqual({ + type: 'config_file', + file: 'next.config.js', + confidence: 80, + }); + }); + + it('uses react package as fallback with low confidence', () => { + const result = detectPlatformFromDependencies({react: '^18.0.0', 'react-dom': '^18.0.0'}, {}); + + expect(result.platform).toBe('react'); + expect(result.confidence).toBe('low'); + expect(result.signals).toContainEqual({ + type: 'framework_package', + package: 'react', + confidence: 40, + }); + }); + }); + + describe('Blazor detection', () => { + it('detects Blazor from .csproj with IgniteUI.Blazor reference', () => { + mockExistsSync.mockReturnValue(false); + mockReaddirSync.mockReturnValue(['MyApp.csproj'] as unknown as ReturnType); + mockReadFileSync.mockReturnValue(` + + + + + + `); + + const result = detectPlatformFromDependencies({}, {}, '/project'); + + expect(result.platform).toBe('blazor'); + expect(result.confidence).toBe('high'); + expect(result.signals).toContainEqual({ + type: 'config_file', + file: 'MyApp.csproj', + confidence: 100, + }); + }); + + it('detects Blazor SDK without IgniteUI with low confidence', () => { + mockExistsSync.mockReturnValue(false); + mockReaddirSync.mockReturnValue(['MyApp.csproj'] as unknown as ReturnType); + mockReadFileSync.mockReturnValue(` + + + net8.0 + + + `); + + const result = detectPlatformFromDependencies({}, {}, '/project'); + + expect(result.platform).toBe('blazor'); + expect(result.confidence).toBe('low'); + expect(result.signals).toContainEqual({ + type: 'config_file', + file: 'MyApp.csproj', + confidence: 40, + }); + }); + }); + + describe('Ambiguous detection', () => { + it('returns ambiguous when Angular and React packages both present', () => { + const result = detectPlatformFromDependencies({ + 'igniteui-angular': '^18.0.0', + 'igniteui-react': '^18.0.0', + }, {}); + + expect(result.platform).toBeNull(); + expect(result.ambiguous).toBe(true); + expect(result.alternatives).toHaveLength(2); + expect(result.alternatives?.map((a: {platform: string}) => a.platform).sort()).toEqual(['angular', 'react']); + }); + + it('returns ambiguous when angular.json and next.config.js both exist', () => { + mockExistsSync.mockImplementation((path) => { + const pathStr = String(path); + return pathStr.includes('angular.json') || pathStr.includes('next.config.js'); + }); + + const result = detectPlatformFromDependencies({}, {}, '/project'); + + expect(result.platform).toBeNull(); + expect(result.ambiguous).toBe(true); + expect(result.alternatives).toHaveLength(2); + }); + + it('provides helpful reason message for ambiguous results', () => { + const result = detectPlatformFromDependencies({ + 'igniteui-angular': '^18.0.0', + 'igniteui-webcomponents': '^5.0.0', + }, {}); + + expect(result.reason).toContain('Multiple platforms detected'); + expect(result.reason).toContain('angular'); + expect(result.reason).toContain('webcomponents'); + }); + + it('includes signals for each alternative platform', () => { + const result = detectPlatformFromDependencies({ + 'igniteui-angular': '^18.0.0', + 'igniteui-react': '^18.0.0', + }, {}); + + expect(result.alternatives).toBeDefined(); + + const angularAlt = result.alternatives?.find((a: {platform: string}) => a.platform === 'angular'); + expect(angularAlt?.signals).toContainEqual({ + type: 'ignite_package', + package: 'igniteui-angular', + confidence: 100, + }); + + const reactAlt = result.alternatives?.find((a: {platform: string}) => a.platform === 'react'); + expect(reactAlt?.signals).toContainEqual({ + type: 'ignite_package', + package: 'igniteui-react', + confidence: 100, + }); + }); + }); + + describe('No platform detected', () => { + it('returns null platform with none confidence when no matches', () => { + const result = detectPlatformFromDependencies({lodash: '^4.17.0'}, {}); + + expect(result.platform).toBeNull(); + expect(result.confidence).toBe('none'); + expect(result.signals).toEqual([]); + expect(result.reason).toContain('No Ignite UI packages'); + }); + + it('returns null platform when dependencies are empty', () => { + const result = detectPlatformFromDependencies({}, {}); + + expect(result.platform).toBeNull(); + expect(result.confidence).toBe('none'); + }); + }); + + describe('Signal priority', () => { + it('prefers Ignite UI package over framework fallback', () => { + const result = detectPlatformFromDependencies({ + '@angular/core': '^18.0.0', + 'igniteui-angular': '^18.0.0', + }, {}); + + expect(result.platform).toBe('angular'); + expect(result.confidence).toBe('high'); + expect(result.detectedPackage).toBe('igniteui-angular'); + // Should not include framework fallback since we have high confidence + }); + + it('prefers config file over framework fallback', () => { + mockExistsSync.mockImplementation((path) => { + return String(path).includes('angular.json'); + }); + + const result = detectPlatformFromDependencies({'@angular/core': '^18.0.0'}, {}, '/project'); + + expect(result.platform).toBe('angular'); + expect(result.confidence).toBe('high'); + // Config file (80) should override framework fallback (40) + expect(result.signals).toContainEqual({ + type: 'config_file', + file: 'angular.json', + confidence: 80, + }); + }); + + it('combines multiple signals for same platform', () => { + mockExistsSync.mockImplementation((path) => { + return String(path).includes('angular.json'); + }); + + const result = detectPlatformFromDependencies({'igniteui-angular': '^18.0.0'}, {}, '/project'); + + expect(result.platform).toBe('angular'); + expect(result.confidence).toBe('high'); + // Should have both package and config file signals + expect(result.signals.length).toBeGreaterThanOrEqual(2); + }); + }); +}); + +describe('detectConfigFiles', () => { + beforeEach(() => { + vi.clearAllMocks(); + mockExistsSync.mockReturnValue(false); + mockReaddirSync.mockReturnValue([]); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('detects angular.json', () => { + mockExistsSync.mockImplementation((path) => { + return String(path).includes('angular.json'); + }); + + const signals = detectConfigFiles('/project'); + + expect(signals).toContainEqual({ + platform: 'angular', + file: 'angular.json', + confidence: 80, + }); + }); + + it('detects vite.config.ts with React plugin', () => { + mockExistsSync.mockImplementation((path) => { + return String(path).includes('vite.config.ts'); + }); + mockReadFileSync.mockReturnValue("import react from '@vitejs/plugin-react';"); + + const signals = detectConfigFiles('/project'); + + expect(signals).toContainEqual({ + platform: 'react', + file: 'vite.config.ts', + confidence: 80, + }); + }); + + it('ignores vite.config.ts without React plugin', () => { + mockExistsSync.mockImplementation((path) => { + return String(path).includes('vite.config.ts'); + }); + mockReadFileSync.mockReturnValue("import vue from '@vitejs/plugin-vue';"); + + const signals = detectConfigFiles('/project'); + + expect(signals).not.toContainEqual(expect.objectContaining({platform: 'react'})); + }); + + it('detects next.config.js', () => { + mockExistsSync.mockImplementation((path) => { + return String(path).includes('next.config.js'); + }); + + const signals = detectConfigFiles('/project'); + + expect(signals).toContainEqual({ + platform: 'react', + file: 'next.config.js', + confidence: 80, + }); + }); + + it('detects .csproj with IgniteUI.Blazor', () => { + mockReaddirSync.mockReturnValue(['App.csproj'] as unknown as ReturnType); + mockReadFileSync.mockReturnValue(''); + + const signals = detectConfigFiles('/project'); + + expect(signals).toContainEqual({ + platform: 'blazor', + file: 'App.csproj', + confidence: 100, + }); + }); + + it('limits .csproj scanning to first 5 files', () => { + mockReaddirSync.mockReturnValue([ + 'a.csproj', + 'b.csproj', + 'c.csproj', + 'd.csproj', + 'e.csproj', + 'f.csproj', + 'g.csproj', + ] as unknown as ReturnType); + mockReadFileSync.mockReturnValue(''); + + detectConfigFiles('/project'); + + // Should have called readFileSync at most 5 times for csproj files + const csprojReadCalls = mockReadFileSync.mock.calls.filter((call) => String(call[0]).endsWith('.csproj')); + expect(csprojReadCalls.length).toBeLessThanOrEqual(5); + }); + + it('handles file read errors gracefully', () => { + mockExistsSync.mockReturnValue(true); + mockReadFileSync.mockImplementation(() => { + throw new Error('Permission denied'); + }); + + // Should not throw + expect(() => detectConfigFiles('/project')).not.toThrow(); + }); + + it('handles directory read errors gracefully', () => { + mockReaddirSync.mockImplementation(() => { + throw new Error('Permission denied'); + }); + + // Should not throw + expect(() => detectConfigFiles('/project')).not.toThrow(); + }); + + it('returns empty array when no config files found', () => { + const signals = detectConfigFiles('/project'); + + expect(signals).toEqual([]); + }); +}); diff --git a/src/mcp/__tests__/knowledge/sass-api.test.ts b/src/mcp/__tests__/knowledge/sass-api.test.ts new file mode 100644 index 00000000..3b113cdc --- /dev/null +++ b/src/mcp/__tests__/knowledge/sass-api.test.ts @@ -0,0 +1,316 @@ +/** + * Tests for Sass API Manifest. + * + * These tests verify that the centralized Sass API knowledge is correct + * and that helper functions work as expected. + */ + +import {describe, it, expect} from 'vitest'; +import { + IMPORT_PATHS, + getImportPath, + PALETTE_FUNCTION, + SHADES_FUNCTION, + TYPOGRAPHY_MIXIN, + ELEVATIONS_MIXIN, + PALETTE_MIXIN, + SPACING_MIXIN, + CORE_MIXIN, + THEME_MIXIN, + CSS_VARIABLE_PATTERNS, + VARIABLE_PATTERNS, + getElevationsVariable, + isMixinSupported, + getPaletteColorGroups, +} from '../../knowledge/sass-api.js'; +import {generateUseStatement} from '../../utils/sass.js'; + +describe('IMPORT_PATHS', () => { + it('has correct path for Angular', () => { + expect(IMPORT_PATHS.angular).toBe('igniteui-angular/theming'); + }); + + it('has correct path for Web Components', () => { + expect(IMPORT_PATHS.webcomponents).toBe('igniteui-theming'); + }); + + it('has correct default path', () => { + expect(IMPORT_PATHS.default).toBe('igniteui-theming'); + }); +}); + +describe('getImportPath', () => { + it('returns Angular path for angular platform', () => { + expect(getImportPath('angular')).toBe('igniteui-angular/theming'); + }); + + it('returns default path for webcomponents platform', () => { + expect(getImportPath('webcomponents')).toBe('igniteui-theming'); + }); + + it('returns default path when platform is undefined', () => { + expect(getImportPath()).toBe('igniteui-theming'); + }); +}); + +describe('PALETTE_FUNCTION', () => { + it('has correct function name', () => { + expect(PALETTE_FUNCTION.name).toBe('palette'); + }); + + it('has all required parameters', () => { + expect(PALETTE_FUNCTION.requiredParams).toContain('primary'); + expect(PALETTE_FUNCTION.requiredParams).toContain('secondary'); + expect(PALETTE_FUNCTION.requiredParams).toContain('surface'); + expect(PALETTE_FUNCTION.requiredParams).toHaveLength(3); + }); + + it('has optional color parameters', () => { + expect(PALETTE_FUNCTION.optionalParams).toContain('gray'); + expect(PALETTE_FUNCTION.optionalParams).toContain('info'); + expect(PALETTE_FUNCTION.optionalParams).toContain('success'); + expect(PALETTE_FUNCTION.optionalParams).toContain('warn'); + expect(PALETTE_FUNCTION.optionalParams).toContain('error'); + }); +}); + +describe('SHADES_FUNCTION', () => { + it('has correct function name', () => { + expect(SHADES_FUNCTION.name).toBe('shades'); + }); + + it('has correct chromatic shade levels', () => { + expect(SHADES_FUNCTION.chromaticShadeLevels).toContain('50'); + expect(SHADES_FUNCTION.chromaticShadeLevels).toContain('500'); + expect(SHADES_FUNCTION.chromaticShadeLevels).toContain('900'); + expect(SHADES_FUNCTION.chromaticShadeLevels).toContain('A100'); + expect(SHADES_FUNCTION.chromaticShadeLevels).toContain('A700'); + expect(SHADES_FUNCTION.chromaticShadeLevels).toHaveLength(14); + }); + + it('has correct gray shade levels (no accent shades)', () => { + expect(SHADES_FUNCTION.grayShadeLevels).toContain('50'); + expect(SHADES_FUNCTION.grayShadeLevels).toContain('900'); + expect(SHADES_FUNCTION.grayShadeLevels).not.toContain('A100'); + expect(SHADES_FUNCTION.grayShadeLevels).toHaveLength(10); + }); +}); + +describe('TYPOGRAPHY_MIXIN', () => { + it('has correct mixin name', () => { + expect(TYPOGRAPHY_MIXIN.name).toBe('typography'); + }); + + it('has font-family and type-scale params', () => { + expect(TYPOGRAPHY_MIXIN.params).toContain('$font-family'); + expect(TYPOGRAPHY_MIXIN.params).toContain('$type-scale'); + }); + + it('has Angular root class defined', () => { + expect(TYPOGRAPHY_MIXIN.angularRootClass).toBe('ig-typography'); + }); +}); + +describe('ELEVATIONS_MIXIN', () => { + it('has correct mixin name', () => { + expect(ELEVATIONS_MIXIN.name).toBe('elevations'); + }); + + it('has 25 elevation levels (0-24)', () => { + expect(ELEVATIONS_MIXIN.levelCount).toBe(25); + }); +}); + +describe('PALETTE_MIXIN', () => { + it('has correct mixin name', () => { + expect(PALETTE_MIXIN.name).toBe('palette'); + }); +}); + +describe('SPACING_MIXIN', () => { + it('has correct mixin name', () => { + expect(SPACING_MIXIN.name).toBe('spacing'); + }); + + it('is supported only for webcomponents', () => { + expect(SPACING_MIXIN.supportedPlatforms).toContain('webcomponents'); + expect(SPACING_MIXIN.supportedPlatforms).not.toContain('angular'); + }); +}); + +describe('CORE_MIXIN', () => { + it('has correct mixin name', () => { + expect(CORE_MIXIN.name).toBe('core'); + }); + + it('is supported only for angular', () => { + expect(CORE_MIXIN.supportedPlatforms).toContain('angular'); + expect(CORE_MIXIN.supportedPlatforms).not.toContain('webcomponents'); + }); + + it('has correct default values for optional params', () => { + expect(CORE_MIXIN.optionalParams['$print-layout']).toBe(true); + expect(CORE_MIXIN.optionalParams['$enhanced-accessibility']).toBe(false); + }); +}); + +describe('THEME_MIXIN', () => { + it('has correct mixin name', () => { + expect(THEME_MIXIN.name).toBe('theme'); + }); + + it('is supported only for angular', () => { + expect(THEME_MIXIN.supportedPlatforms).toContain('angular'); + }); + + it('has palette and schema as required params', () => { + expect(THEME_MIXIN.requiredParams).toContain('$palette'); + expect(THEME_MIXIN.requiredParams).toContain('$schema'); + }); +}); + +describe('CSS_VARIABLE_PATTERNS', () => { + it('has correct theme variables', () => { + expect(CSS_VARIABLE_PATTERNS.theme).toBe('--ig-theme'); + expect(CSS_VARIABLE_PATTERNS.themeVariant).toBe('--ig-theme-variant'); + }); + + it('has correct size variables', () => { + expect(CSS_VARIABLE_PATTERNS.sizes.small).toBe('--ig-size-small'); + expect(CSS_VARIABLE_PATTERNS.sizes.medium).toBe('--ig-size-medium'); + expect(CSS_VARIABLE_PATTERNS.sizes.large).toBe('--ig-size-large'); + }); + + it('has correct scrollbar variables', () => { + expect(CSS_VARIABLE_PATTERNS.scrollbar.size).toBe('--ig-scrollbar-size'); + expect(CSS_VARIABLE_PATTERNS.scrollbar.thumbBackground).toBe('--ig-scrollbar-thumb-background'); + expect(CSS_VARIABLE_PATTERNS.scrollbar.trackBackground).toBe('--ig-scrollbar-track-background'); + }); + + it('has correct patterns for color and elevation', () => { + expect(CSS_VARIABLE_PATTERNS.colorPattern).toBe('--ig-{color}-{shade}'); + expect(CSS_VARIABLE_PATTERNS.elevationPattern).toBe('--ig-elevation-{level}'); + }); +}); + +describe('VARIABLE_PATTERNS', () => { + it('generates correct palette preset variable', () => { + expect(VARIABLE_PATTERNS.palettePreset('light', 'material')).toBe('$light-material-palette'); + expect(VARIABLE_PATTERNS.palettePreset('dark', 'indigo')).toBe('$dark-indigo-palette'); + }); + + it('generates correct schema variable', () => { + expect(VARIABLE_PATTERNS.schema('light', 'material')).toBe('$light-material-schema'); + expect(VARIABLE_PATTERNS.schema('dark', 'fluent')).toBe('$dark-fluent-schema'); + }); + + it('generates correct typeface variable', () => { + expect(VARIABLE_PATTERNS.typeface('material')).toBe('$material-typeface'); + expect(VARIABLE_PATTERNS.typeface('indigo')).toBe('$indigo-typeface'); + }); + + it('generates correct type scale variable', () => { + expect(VARIABLE_PATTERNS.typeScale('material')).toBe('$material-type-scale'); + expect(VARIABLE_PATTERNS.typeScale('bootstrap')).toBe('$bootstrap-type-scale'); + }); + + it('generates correct elevations variable', () => { + expect(VARIABLE_PATTERNS.elevations('material')).toBe('$material-elevations'); + expect(VARIABLE_PATTERNS.elevations('indigo')).toBe('$indigo-elevations'); + }); + + it('generates correct custom palette variable', () => { + expect(VARIABLE_PATTERNS.customPalette('brand', 'light')).toBe('$brand-light-palette'); + expect(VARIABLE_PATTERNS.customPalette('company', 'dark')).toBe('$company-dark-palette'); + }); +}); + +describe('generateUseStatement', () => { + it('generates Angular use statement with double quotes', () => { + const result = generateUseStatement('angular'); + expect(result).toBe('@use "igniteui-angular/theming" as *;'); + }); + + it('generates Web Components use statement with single quotes', () => { + const result = generateUseStatement('webcomponents'); + expect(result).toBe("@use 'igniteui-theming' as *;"); + }); + + it('generates default use statement when platform is undefined', () => { + const result = generateUseStatement(); + expect(result).toBe("@use 'igniteui-theming' as *;"); + }); +}); + +describe('getElevationsVariable', () => { + it('returns material elevations for material design system', () => { + expect(getElevationsVariable('material')).toBe('$material-elevations'); + }); + + it('returns indigo elevations for indigo design system', () => { + expect(getElevationsVariable('indigo')).toBe('$indigo-elevations'); + }); + + it('returns material elevations for bootstrap (fallback)', () => { + expect(getElevationsVariable('bootstrap')).toBe('$material-elevations'); + }); + + it('returns material elevations for fluent (fallback)', () => { + expect(getElevationsVariable('fluent')).toBe('$material-elevations'); + }); +}); + +describe('isMixinSupported', () => { + describe('core mixin', () => { + it('is supported for angular', () => { + expect(isMixinSupported('core', 'angular')).toBe(true); + }); + + it('is not supported for webcomponents', () => { + expect(isMixinSupported('core', 'webcomponents')).toBe(false); + }); + + it('is not supported when platform is undefined', () => { + expect(isMixinSupported('core')).toBe(false); + }); + }); + + describe('theme mixin', () => { + it('is supported for angular', () => { + expect(isMixinSupported('theme', 'angular')).toBe(true); + }); + + it('is not supported for webcomponents', () => { + expect(isMixinSupported('theme', 'webcomponents')).toBe(false); + }); + }); + + describe('spacing mixin', () => { + it('is supported for webcomponents', () => { + expect(isMixinSupported('spacing', 'webcomponents')).toBe(true); + }); + + it('is not supported for angular', () => { + expect(isMixinSupported('spacing', 'angular')).toBe(false); + }); + + it('is supported when platform is undefined (generic output)', () => { + expect(isMixinSupported('spacing')).toBe(true); + }); + }); +}); + +describe('getPaletteColorGroups', () => { + it('returns all palette color groups', () => { + const groups = getPaletteColorGroups(); + expect(groups).toContain('primary'); + expect(groups).toContain('secondary'); + expect(groups).toContain('gray'); + expect(groups).toContain('surface'); + expect(groups).toContain('info'); + expect(groups).toContain('success'); + expect(groups).toContain('warn'); + expect(groups).toContain('error'); + expect(groups).toHaveLength(8); + }); +}); diff --git a/src/mcp/__tests__/knowledge/webcomponents.test.ts b/src/mcp/__tests__/knowledge/webcomponents.test.ts new file mode 100644 index 00000000..553ccf64 --- /dev/null +++ b/src/mcp/__tests__/knowledge/webcomponents.test.ts @@ -0,0 +1,358 @@ +/** + * Tests for Web Components helper functions. + * + * These tests verify the smaller, focused helper functions extracted + * during the refactoring of generateWebComponentsThemeSass. + */ + +import {describe, it, expect} from 'vitest'; +import { + generateWCHeader, + getWCElevationPreset, + generateWCImports, + generateWCProgressProperties, + generateWCRootVariables, + generateWCRtlSupport, + generateWCScrollbarCustomization, + generateWCThemingMixins, + generateWebComponentsThemeSass, +} from '../../knowledge/platforms/webcomponents.js'; + +describe('generateWCHeader', () => { + it('returns correct header lines', () => { + const header = generateWCHeader(); + expect(header).toContain('// Generated by Ignite UI Theming MCP Server'); + expect(header).toContain('// Platform: Ignite UI for Web Components'); + expect(header).toHaveLength(3); // Two comment lines + empty line + }); +}); + +describe('getWCElevationPreset', () => { + it('returns indigo elevations for indigo design system', () => { + expect(getWCElevationPreset('indigo')).toBe('$indigo-elevations'); + }); + + it('returns material elevations for material design system', () => { + expect(getWCElevationPreset('material')).toBe('$material-elevations'); + }); + + it('returns material elevations for fluent design system', () => { + expect(getWCElevationPreset('fluent')).toBe('$material-elevations'); + }); + + it('returns material elevations for bootstrap design system', () => { + expect(getWCElevationPreset('bootstrap')).toBe('$material-elevations'); + }); +}); + +describe('generateWCImports', () => { + it('generates imports for custom colors', () => { + const imports = generateWCImports({ + designSystem: 'material', + variant: 'light', + hasCustomColors: true, + includeTypography: true, + includeElevations: true, + }); + + expect(imports.join('\n')).toContain("@use 'igniteui-theming' as *;"); + expect(imports.join('\n')).toContain("@use 'igniteui-theming/sass/typography/presets/material' as *;"); + expect(imports.join('\n')).toContain("@use 'igniteui-theming/sass/elevations/presets' as *;"); + }); + + it('generates imports for preset palette', () => { + const imports = generateWCImports({ + designSystem: 'indigo', + variant: 'dark', + hasCustomColors: false, + includeTypography: true, + includeElevations: true, + }); + + expect(imports.join('\n')).toContain("@use 'igniteui-theming/sass/color/presets/dark/indigo' as *;"); + expect(imports.join('\n')).toContain("@use 'igniteui-theming' as *;"); + expect(imports.join('\n')).toContain("@use 'igniteui-theming/sass/typography/presets/indigo' as *;"); + }); + + it('skips typography import when not included', () => { + const imports = generateWCImports({ + designSystem: 'material', + variant: 'light', + hasCustomColors: false, + includeTypography: false, + includeElevations: true, + }); + + expect(imports.join('\n')).not.toContain('typography/presets'); + }); + + it('skips elevations import when not included', () => { + const imports = generateWCImports({ + designSystem: 'material', + variant: 'light', + hasCustomColors: false, + includeTypography: true, + includeElevations: false, + }); + + expect(imports.join('\n')).not.toContain('elevations/presets'); + }); +}); + +describe('generateWCProgressProperties', () => { + it('generates progress property declarations', () => { + const props = generateWCProgressProperties(); + const output = props.join('\n'); + + expect(output).toContain('@property --_progress-integer'); + expect(output).toContain('@property --_progress-fraction'); + expect(output).toContain("syntax: ''"); + expect(output).toContain('initial-value: 0'); + expect(output).toContain('inherits: true'); + }); + + it('applies indent when specified', () => { + const props = generateWCProgressProperties(' '); + expect(props[0].startsWith(' @property')).toBe(true); + expect(props[1].startsWith(' syntax')).toBe(true); + }); +}); + +describe('generateWCRootVariables', () => { + it('generates root variables with literal values for preset palette', () => { + const vars = generateWCRootVariables({ + designSystem: 'material', + variant: 'light', + usePaletteMap: false, + }); + const output = vars.join('\n'); + + expect(output).toContain(':root {'); + expect(output).toContain('--ig-theme: material'); + expect(output).toContain('--ig-theme-variant: light'); + expect(output).toContain('--ig-size-small: 1'); + expect(output).toContain('--ig-size-medium: 2'); + expect(output).toContain('--ig-size-large: 3'); + expect(output).toContain('--ig-scrollbar-size: #{rem(16px)}'); + }); + + it('generates root variables with map.get for custom palette', () => { + const vars = generateWCRootVariables({ + designSystem: 'indigo', + variant: 'dark', + usePaletteMap: true, + }); + const output = vars.join('\n'); + + expect(output).toContain("--ig-theme: #{map.get($palette, '_meta', 'variant')}"); + expect(output).toContain('--ig-theme-variant: #{$variant}'); + }); + + it('applies indent when specified', () => { + const vars = generateWCRootVariables({ + designSystem: 'material', + variant: 'light', + indent: ' ', + }); + expect(vars[0]).toBe(' :root {'); + }); +}); + +describe('generateWCRtlSupport', () => { + it('generates RTL direction support', () => { + const rtl = generateWCRtlSupport(); + const output = rtl.join('\n'); + + expect(output).toContain("body[dir='rtl']"); + expect(output).toContain('--ig-dir: -1'); + }); + + it('applies indent when specified', () => { + const rtl = generateWCRtlSupport(' '); + expect(rtl[0]).toBe(" body[dir='rtl'] {"); + }); +}); + +describe('generateWCScrollbarCustomization', () => { + it('generates scrollbar customization using color function', () => { + const scrollbar = generateWCScrollbarCustomization(); + const output = scrollbar.join('\n'); + + expect(output).toContain('// Scrollbar customization'); + expect(output).toContain(':root {'); + expect(output).toContain('--ig-scrollbar-thumb-background'); + expect(output).toContain('--ig-scrollbar-track-background'); + expect(output).toContain('color($color: gray, $variant: 400)'); + expect(output).toContain('color($color: gray, $variant: 100)'); + }); +}); + +describe('generateWCThemingMixins', () => { + it('generates all theming mixins', () => { + const mixins = generateWCThemingMixins({ + paletteVar: '$my-palette', + typefaceValue: '$typeface', + elevationsVar: '$material-elevations', + includeTypography: true, + includeElevations: true, + includeSpacing: true, + }); + const output = mixins.join('\n'); + + expect(output).toContain('@include palette($my-palette)'); + expect(output).toContain('@include elevations($material-elevations)'); + expect(output).toContain('@include typography('); + expect(output).toContain("$font-family: '$typeface'"); // quoteFontFamily adds quotes + expect(output).toContain('@include spacing()'); + }); + + it('skips mixins when not included', () => { + const mixins = generateWCThemingMixins({ + paletteVar: '$palette', + typefaceValue: '$typeface', + elevationsVar: '$material-elevations', + includeTypography: false, + includeElevations: false, + includeSpacing: false, + }); + const output = mixins.join('\n'); + + expect(output).toContain('@include palette($palette)'); + expect(output).not.toContain('@include elevations'); + expect(output).not.toContain('@include typography'); + expect(output).not.toContain('@include spacing'); + }); + + it('adds comments when requested', () => { + const mixins = generateWCThemingMixins({ + paletteVar: '$palette', + typefaceValue: '$typeface', + elevationsVar: '$material-elevations', + includeTypography: true, + includeElevations: true, + includeSpacing: true, + addComments: true, + }); + const output = mixins.join('\n'); + + expect(output).toContain('// Apply palette CSS variables'); + expect(output).toContain('// Apply elevation CSS variables'); + expect(output).toContain('// Apply typography CSS variables'); + expect(output).toContain('// Apply spacing CSS variables'); + }); + + it('applies indent when specified', () => { + const mixins = generateWCThemingMixins({ + paletteVar: '$palette', + typefaceValue: '$typeface', + elevationsVar: '$material-elevations', + includeTypography: true, + includeElevations: true, + includeSpacing: true, + indent: ' ', + }); + + expect(mixins[0]).toBe(' @include palette($palette);'); + }); +}); + +describe('generateWebComponentsThemeSass (integration)', () => { + it('generates complete theme for preset palette', () => { + const code = generateWebComponentsThemeSass({ + designSystem: 'material', + variant: 'light', + }); + + // Header + expect(code).toContain('// Generated by Ignite UI Theming MCP Server'); + expect(code).toContain('// Platform: Ignite UI for Web Components'); + + // Imports + expect(code).toContain("@use 'igniteui-theming/sass/color/presets/light/material' as *;"); + expect(code).toContain("@use 'igniteui-theming' as *;"); + + // Root variables + expect(code).toContain('--ig-theme: material'); + expect(code).toContain('--ig-theme-variant: light'); + + // Mixins + expect(code).toContain('@include palette($palette)'); + expect(code).toContain('@include elevations($material-elevations)'); + expect(code).toContain('@include typography('); + expect(code).toContain('@include spacing()'); + }); + + it('generates complete theme for custom palette', () => { + const code = generateWebComponentsThemeSass({ + designSystem: 'indigo', + variant: 'dark', + primaryColor: '#2ab759', + secondaryColor: '#f7bd32', + surfaceColor: '#1a1a1a', + }); + + // Header + expect(code).toContain('// Platform: Ignite UI for Web Components'); + + // Custom palette + expect(code).toContain('$primary-color: #2ab759'); + expect(code).toContain('$secondary-color: #f7bd32'); + expect(code).toContain('$surface-color: #1a1a1a'); + expect(code).toContain('$my-palette: palette('); + + // Theme mixin wrapper + expect(code).toContain('@mixin theme($palette, $variant)'); + expect(code).toContain("@include theme($my-palette, 'dark')"); + }); + + it('respects includeTypography option', () => { + const codeWithTypography = generateWebComponentsThemeSass({ + designSystem: 'material', + variant: 'light', + includeTypography: true, + }); + + const codeWithoutTypography = generateWebComponentsThemeSass({ + designSystem: 'material', + variant: 'light', + includeTypography: false, + }); + + expect(codeWithTypography).toContain('@include typography('); + expect(codeWithoutTypography).not.toContain('@include typography('); + }); + + it('respects includeElevations option', () => { + const codeWithElevations = generateWebComponentsThemeSass({ + designSystem: 'material', + variant: 'light', + includeElevations: true, + }); + + const codeWithoutElevations = generateWebComponentsThemeSass({ + designSystem: 'material', + variant: 'light', + includeElevations: false, + }); + + expect(codeWithElevations).toContain('@include elevations('); + expect(codeWithoutElevations).not.toContain('@include elevations('); + }); + + it('respects includeSpacing option', () => { + const codeWithSpacing = generateWebComponentsThemeSass({ + designSystem: 'material', + variant: 'light', + includeSpacing: true, + }); + + const codeWithoutSpacing = generateWebComponentsThemeSass({ + designSystem: 'material', + variant: 'light', + includeSpacing: false, + }); + + expect(codeWithSpacing).toContain('@include spacing()'); + expect(codeWithoutSpacing).not.toContain('@include spacing()'); + }); +}); diff --git a/src/mcp/__tests__/tools/handlers/handlers.test.ts b/src/mcp/__tests__/tools/handlers/handlers.test.ts new file mode 100644 index 00000000..0d030eb9 --- /dev/null +++ b/src/mcp/__tests__/tools/handlers/handlers.test.ts @@ -0,0 +1,336 @@ +/** + * Tests for tool handler functions. + * + * These tests verify that handlers: + * 1. Return the correct MCP response format + * 2. Include expected content in responses + * 3. Handle validation and warnings correctly + */ + +import {describe, it, expect} from 'vitest'; +import {handleCreatePalette} from '../../../tools/handlers/palette.js'; +import {handleCreateTheme} from '../../../tools/handlers/theme.js'; +import {handleCreateTypography} from '../../../tools/handlers/typography.js'; +import {handleCreateElevations} from '../../../tools/handlers/elevations.js'; +import {handleCreateCustomPalette} from '../../../tools/handlers/custom-palette.js'; + +describe('handleCreatePalette', () => { + it('returns MCP response format', async () => { + const result = await handleCreatePalette({ + primary: '#2ab759', + secondary: '#f7bd32', + surface: 'white', + }); + + expect(result).toHaveProperty('content'); + expect(result.content).toBeInstanceOf(Array); + expect(result.content[0]).toHaveProperty('type', 'text'); + expect(result.content[0]).toHaveProperty('text'); + }); + + it('includes generated Sass code', async () => { + const result = await handleCreatePalette({ + primary: '#2ab759', + secondary: '#f7bd32', + surface: 'white', + }); + + const text = result.content[0].text; + expect(text).toContain('```scss'); + expect(text).toContain('palette('); + expect(text).toContain('$primary: #2ab759'); + }); + + it('shows platform info when specified', async () => { + const result = await handleCreatePalette({ + platform: 'angular', + primary: '#2ab759', + secondary: '#f7bd32', + surface: 'white', + }); + + const text = result.content[0].text; + expect(text).toContain('Ignite UI for Angular'); + }); + + it('shows platform hint when not specified', async () => { + const result = await handleCreatePalette({ + primary: '#2ab759', + secondary: '#f7bd32', + surface: 'white', + }); + + const text = result.content[0].text; + expect(text).toContain('Platform: Not specified'); + expect(text).toContain('Specify `platform`'); + }); + + it('includes validation warnings for incorrect surface/variant', async () => { + const result = await handleCreatePalette({ + primary: '#2ab759', + secondary: '#f7bd32', + surface: '#121212', // dark surface for light variant + variant: 'light', + }); + + const text = result.content[0].text; + expect(text).toContain('Warning'); + expect(text).toContain('surface'); + }); + + it('includes variable names in response', async () => { + const result = await handleCreatePalette({ + primary: '#2ab759', + secondary: '#f7bd32', + surface: 'white', + name: 'my-brand', + }); + + const text = result.content[0].text; + expect(text).toContain('$my-brand-palette'); + }); +}); + +describe('handleCreateTheme', () => { + const baseThemeParams = { + primaryColor: '#2ab759', + secondaryColor: '#f7bd32', + surfaceColor: 'white', + includeTypography: true, + includeElevations: true, + includeSpacing: true, + }; + + it('returns MCP response format', async () => { + const result = await handleCreateTheme(baseThemeParams); + + expect(result).toHaveProperty('content'); + expect(result.content).toBeInstanceOf(Array); + expect(result.content[0]).toHaveProperty('type', 'text'); + expect(result.content[0]).toHaveProperty('text'); + }); + + it('includes generated Sass code', async () => { + const result = await handleCreateTheme(baseThemeParams); + + const text = result.content[0].text; + expect(text).toContain('```scss'); + expect(text).toContain('palette'); + }); + + it('includes typography when not explicitly excluded', async () => { + const result = await handleCreateTheme(baseThemeParams); + + const text = result.content[0].text; + expect(text).toContain('typography'); + }); + + it('excludes typography when requested', async () => { + const result = await handleCreateTheme({ + ...baseThemeParams, + includeTypography: false, + }); + + const text = result.content[0].text; + expect(text).not.toContain('@include typography('); + }); + + it('warns about color suitability issues', async () => { + const result = await handleCreateTheme({ + ...baseThemeParams, + primaryColor: '#fafafa', // very light color + }); + + const text = result.content[0].text; + // Should warn about luminance issues - check for warning indicators + const hasWarning = text.includes('luminance') || text.toLowerCase().includes('warning'); + expect(hasWarning).toBe(true); + }); + + it('shows Angular-specific content for angular platform', async () => { + const result = await handleCreateTheme({ + ...baseThemeParams, + platform: 'angular', + }); + + const text = result.content[0].text; + expect(text).toContain('Angular'); + expect(text).toContain('core()'); + expect(text).toContain('theme('); + }); + + it('shows Web Components-specific content for webcomponents platform', async () => { + const result = await handleCreateTheme({ + ...baseThemeParams, + platform: 'webcomponents', + }); + + const text = result.content[0].text; + expect(text).toContain('Web Components'); + }); + + it('shows React-specific platform name for react platform', async () => { + const result = await handleCreateTheme({ + ...baseThemeParams, + platform: 'react', + }); + + const text = result.content[0].text; + expect(text).toContain('Platform: Ignite UI for React'); + }); + + it('shows Blazor-specific platform name for blazor platform', async () => { + const result = await handleCreateTheme({ + ...baseThemeParams, + platform: 'blazor', + }); + + const text = result.content[0].text; + expect(text).toContain('Platform: Ignite UI for Blazor'); + }); +}); + +describe('handleCreateTypography', () => { + it('returns MCP response format', () => { + const result = handleCreateTypography({ + fontFamily: 'Roboto', + }); + + expect(result).toHaveProperty('content'); + expect(result.content).toBeInstanceOf(Array); + expect(result.content[0]).toHaveProperty('type', 'text'); + }); + + it('includes typography mixin in code', () => { + const result = handleCreateTypography({ + fontFamily: 'Roboto', + }); + + const text = result.content[0].text; + expect(text).toContain('```scss'); + expect(text).toContain('@include typography('); + expect(text).toContain('Roboto'); + }); + + it('uses specified design system type scale', () => { + const result = handleCreateTypography({ + fontFamily: 'Inter', + designSystem: 'indigo', + }); + + const text = result.content[0].text; + expect(text).toContain('$indigo-type-scale'); + }); +}); + +describe('handleCreateElevations', () => { + it('returns MCP response format', () => { + const result = handleCreateElevations({}); + + expect(result).toHaveProperty('content'); + expect(result.content).toBeInstanceOf(Array); + expect(result.content[0]).toHaveProperty('type', 'text'); + }); + + it('includes elevations mixin in code', () => { + const result = handleCreateElevations({}); + + const text = result.content[0].text; + expect(text).toContain('```scss'); + expect(text).toContain('@include elevations('); + }); + + it('uses material elevations by default', () => { + const result = handleCreateElevations({}); + + const text = result.content[0].text; + expect(text).toContain('$material-elevations'); + }); + + it('uses indigo elevations when specified', () => { + const result = handleCreateElevations({ + designSystem: 'indigo', + }); + + const text = result.content[0].text; + expect(text).toContain('$indigo-elevations'); + }); +}); + +describe('handleCreateCustomPalette', () => { + it('returns MCP response format', async () => { + const result = await handleCreateCustomPalette({ + primary: {mode: 'shades', baseColor: '#2ab759'}, + secondary: {mode: 'shades', baseColor: '#f7bd32'}, + surface: {mode: 'shades', baseColor: 'white'}, + }); + + expect(result).toHaveProperty('content'); + expect(result.content).toBeInstanceOf(Array); + expect(result.content[0]).toHaveProperty('type', 'text'); + }); + + it('generates palette with shades mode', async () => { + const result = await handleCreateCustomPalette({ + primary: {mode: 'shades', baseColor: '#2ab759'}, + secondary: {mode: 'shades', baseColor: '#f7bd32'}, + surface: {mode: 'shades', baseColor: 'white'}, + }); + + const text = result.content[0].text; + expect(text).toContain('```scss'); + expect(text).toContain('shades('); + }); + + it('shows validation errors for invalid colors', async () => { + const result = await handleCreateCustomPalette({ + primary: {mode: 'shades', baseColor: 'not-a-color'}, + secondary: {mode: 'shades', baseColor: '#f7bd32'}, + surface: {mode: 'shades', baseColor: 'white'}, + }); + + const text = result.content[0].text; + expect(text).toContain('Validation Failed'); + expect(text).toContain('Invalid'); + }); + + it('shows which colors use shades mode', async () => { + const result = await handleCreateCustomPalette({ + primary: {mode: 'shades', baseColor: '#2ab759'}, + secondary: {mode: 'shades', baseColor: '#f7bd32'}, + surface: {mode: 'shades', baseColor: 'white'}, + }); + + const text = result.content[0].text; + expect(text).toContain('shades() function'); + }); + + it('supports explicit shade definitions', async () => { + const result = await handleCreateCustomPalette({ + primary: { + mode: 'explicit', + shades: { + '50': '#e8f5e9', + '100': '#c8e6c9', + '200': '#a5d6a7', + '300': '#81c784', + '400': '#66bb6a', + '500': '#4caf50', + '600': '#43a047', + '700': '#388e3c', + '800': '#2e7d32', + '900': '#1b5e20', + A100: '#b9f6ca', + A200: '#69f0ae', + A400: '#00e676', + A700: '#00c853', + }, + }, + secondary: {mode: 'shades', baseColor: '#f7bd32'}, + surface: {mode: 'shades', baseColor: 'white'}, + }); + + const text = result.content[0].text; + expect(text).toContain('explicit shades'); + }); +}); diff --git a/src/mcp/__tests__/tools/schemas.test.ts b/src/mcp/__tests__/tools/schemas.test.ts new file mode 100644 index 00000000..6d295dfd --- /dev/null +++ b/src/mcp/__tests__/tools/schemas.test.ts @@ -0,0 +1,290 @@ +/** + * Tests for Zod schemas in tools/schemas.ts. + * + * These tests verify that the colorSchema correctly validates + * CSS Color Level 4 color formats at the schema level. + * + * Note: The schema performs permissive pattern matching. Full validation + * of actual color values happens at Sass compile time. + */ + +import {describe, it, expect} from 'vitest'; +import {colorSchema} from '../../tools/schemas.js'; + +describe('colorSchema', () => { + describe('hex colors', () => { + it('accepts 3-digit hex', () => { + expect(colorSchema.safeParse('#fff').success).toBe(true); + expect(colorSchema.safeParse('#F00').success).toBe(true); + expect(colorSchema.safeParse('#abc').success).toBe(true); + }); + + it('accepts 4-digit hex (with alpha)', () => { + expect(colorSchema.safeParse('#ffff').success).toBe(true); + expect(colorSchema.safeParse('#F00F').success).toBe(true); + expect(colorSchema.safeParse('#abcd').success).toBe(true); + }); + + it('accepts 6-digit hex', () => { + expect(colorSchema.safeParse('#ffffff').success).toBe(true); + expect(colorSchema.safeParse('#FF0000').success).toBe(true); + expect(colorSchema.safeParse('#abcdef').success).toBe(true); + }); + + it('accepts 8-digit hex (with alpha)', () => { + expect(colorSchema.safeParse('#ffffffff').success).toBe(true); + expect(colorSchema.safeParse('#FF0000FF').success).toBe(true); + expect(colorSchema.safeParse('#abcdef80').success).toBe(true); + }); + + it('rejects invalid hex lengths', () => { + expect(colorSchema.safeParse('#ff').success).toBe(false); + expect(colorSchema.safeParse('#fffff').success).toBe(false); + expect(colorSchema.safeParse('#fffffff').success).toBe(false); + }); + + it('hex without hash matches as named color (permissive for Sass validation)', () => { + // 'ffffff' without hash matches the named color pattern [a-z]+ + // This is intentional - the schema is permissive and Sass will catch + // invalid color names at compile time + expect(colorSchema.safeParse('ffffff').success).toBe(true); + }); + }); + + describe('RGB/RGBA colors', () => { + it('accepts legacy comma-separated rgb()', () => { + expect(colorSchema.safeParse('rgb(255, 0, 0)').success).toBe(true); + expect(colorSchema.safeParse('rgb(0, 128, 255)').success).toBe(true); + }); + + it('accepts legacy comma-separated rgba()', () => { + expect(colorSchema.safeParse('rgba(255, 0, 0, 0.5)').success).toBe(true); + expect(colorSchema.safeParse('rgba(0, 128, 255, 1)').success).toBe(true); + }); + + it('accepts modern space-separated rgb()', () => { + expect(colorSchema.safeParse('rgb(255 0 0)').success).toBe(true); + expect(colorSchema.safeParse('rgb(0 128 255)').success).toBe(true); + }); + + it('accepts modern rgb() with slash alpha', () => { + expect(colorSchema.safeParse('rgb(255 0 0 / 0.5)').success).toBe(true); + expect(colorSchema.safeParse('rgb(255 0 0 / 50%)').success).toBe(true); + }); + + it('accepts percentage values', () => { + expect(colorSchema.safeParse('rgb(100%, 0%, 0%)').success).toBe(true); + expect(colorSchema.safeParse('rgb(100% 0% 0% / 50%)').success).toBe(true); + }); + }); + + describe('HSL/HSLA colors', () => { + it('accepts legacy comma-separated hsl()', () => { + expect(colorSchema.safeParse('hsl(180, 50%, 50%)').success).toBe(true); + expect(colorSchema.safeParse('hsl(0, 100%, 50%)').success).toBe(true); + }); + + it('accepts legacy comma-separated hsla()', () => { + expect(colorSchema.safeParse('hsla(180, 50%, 50%, 0.5)').success).toBe(true); + expect(colorSchema.safeParse('hsla(0, 100%, 50%, 1)').success).toBe(true); + }); + + it('accepts modern space-separated hsl()', () => { + expect(colorSchema.safeParse('hsl(180 50% 50%)').success).toBe(true); + expect(colorSchema.safeParse('hsl(0 100% 50%)').success).toBe(true); + }); + + it('accepts modern hsl() with slash alpha', () => { + expect(colorSchema.safeParse('hsl(180 50% 50% / 0.5)').success).toBe(true); + expect(colorSchema.safeParse('hsl(180 50% 50% / 50%)').success).toBe(true); + }); + + it('accepts hue angle units', () => { + expect(colorSchema.safeParse('hsl(180deg 50% 50%)').success).toBe(true); + expect(colorSchema.safeParse('hsl(0.5turn 50% 50%)').success).toBe(true); + expect(colorSchema.safeParse('hsl(3.14rad 50% 50%)').success).toBe(true); + expect(colorSchema.safeParse('hsl(200grad 50% 50%)').success).toBe(true); + }); + }); + + describe('HWB colors (CSS Color Level 4)', () => { + it('accepts hwb() syntax', () => { + expect(colorSchema.safeParse('hwb(180 20% 30%)').success).toBe(true); + expect(colorSchema.safeParse('hwb(0 0% 0%)').success).toBe(true); + }); + + it('accepts hwb() with alpha', () => { + expect(colorSchema.safeParse('hwb(180 20% 30% / 0.5)').success).toBe(true); + expect(colorSchema.safeParse('hwb(180 20% 30% / 50%)').success).toBe(true); + }); + + it('accepts hwb() with hue angle units', () => { + expect(colorSchema.safeParse('hwb(180deg 20% 30%)').success).toBe(true); + expect(colorSchema.safeParse('hwb(0.5turn 20% 30%)').success).toBe(true); + }); + }); + + describe('LAB colors (CSS Color Level 4)', () => { + it('accepts lab() syntax', () => { + expect(colorSchema.safeParse('lab(50% 40 59.5)').success).toBe(true); + expect(colorSchema.safeParse('lab(100 0 0)').success).toBe(true); + }); + + it('accepts lab() with alpha', () => { + expect(colorSchema.safeParse('lab(50% 40 59.5 / 0.5)').success).toBe(true); + expect(colorSchema.safeParse('lab(50% 40 59.5 / 50%)').success).toBe(true); + }); + + it('accepts lab() with negative values', () => { + expect(colorSchema.safeParse('lab(50% -40 -59.5)').success).toBe(true); + }); + }); + + describe('LCH colors (CSS Color Level 4)', () => { + it('accepts lch() syntax', () => { + expect(colorSchema.safeParse('lch(50% 80 30)').success).toBe(true); + expect(colorSchema.safeParse('lch(100 0 0)').success).toBe(true); + }); + + it('accepts lch() with alpha', () => { + expect(colorSchema.safeParse('lch(50% 80 30 / 0.5)').success).toBe(true); + expect(colorSchema.safeParse('lch(50% 80 30 / 50%)').success).toBe(true); + }); + + it('accepts lch() with hue angle units', () => { + expect(colorSchema.safeParse('lch(50% 80 30deg)').success).toBe(true); + expect(colorSchema.safeParse('lch(50% 80 0.5turn)').success).toBe(true); + }); + }); + + describe('OKLAB colors (CSS Color Level 4)', () => { + it('accepts oklab() syntax', () => { + expect(colorSchema.safeParse('oklab(59% 0.1 0.1)').success).toBe(true); + expect(colorSchema.safeParse('oklab(1 0 0)').success).toBe(true); + }); + + it('accepts oklab() with alpha', () => { + expect(colorSchema.safeParse('oklab(59% 0.1 0.1 / 0.5)').success).toBe(true); + expect(colorSchema.safeParse('oklab(59% 0.1 0.1 / 50%)').success).toBe(true); + }); + + it('accepts oklab() with negative values', () => { + expect(colorSchema.safeParse('oklab(59% -0.1 -0.1)').success).toBe(true); + }); + }); + + describe('OKLCH colors (CSS Color Level 4)', () => { + it('accepts oklch() syntax', () => { + expect(colorSchema.safeParse('oklch(60% 0.15 50)').success).toBe(true); + expect(colorSchema.safeParse('oklch(1 0 0)').success).toBe(true); + }); + + it('accepts oklch() with alpha', () => { + expect(colorSchema.safeParse('oklch(60% 0.15 50 / 0.5)').success).toBe(true); + expect(colorSchema.safeParse('oklch(60% 0.15 50 / 50%)').success).toBe(true); + }); + + it('accepts oklch() with hue angle units', () => { + expect(colorSchema.safeParse('oklch(60% 0.15 50deg)').success).toBe(true); + expect(colorSchema.safeParse('oklch(60% 0.15 0.14turn)').success).toBe(true); + }); + }); + + describe('color() function (CSS Color Level 4)', () => { + it('accepts color() with display-p3', () => { + expect(colorSchema.safeParse('color(display-p3 1 0.5 0)').success).toBe(true); + expect(colorSchema.safeParse('color(display-p3 0 1 0)').success).toBe(true); + }); + + it('accepts color() with srgb', () => { + expect(colorSchema.safeParse('color(srgb 1 0 0)').success).toBe(true); + expect(colorSchema.safeParse('color(srgb 0.5 0.5 0.5)').success).toBe(true); + }); + + it('accepts color() with alpha', () => { + expect(colorSchema.safeParse('color(display-p3 1 0.5 0 / 0.5)').success).toBe(true); + expect(colorSchema.safeParse('color(srgb 1 0 0 / 50%)').success).toBe(true); + }); + + it('accepts color() with other color spaces', () => { + expect(colorSchema.safeParse('color(srgb-linear 1 0 0)').success).toBe(true); + expect(colorSchema.safeParse('color(a98-rgb 1 0 0)').success).toBe(true); + expect(colorSchema.safeParse('color(prophoto-rgb 1 0 0)').success).toBe(true); + expect(colorSchema.safeParse('color(rec2020 1 0 0)').success).toBe(true); + expect(colorSchema.safeParse('color(xyz 0.5 0.5 0.5)').success).toBe(true); + expect(colorSchema.safeParse('color(xyz-d50 0.5 0.5 0.5)').success).toBe(true); + expect(colorSchema.safeParse('color(xyz-d65 0.5 0.5 0.5)').success).toBe(true); + }); + }); + + describe('named colors', () => { + it('accepts standard CSS named colors', () => { + expect(colorSchema.safeParse('red').success).toBe(true); + expect(colorSchema.safeParse('blue').success).toBe(true); + expect(colorSchema.safeParse('green').success).toBe(true); + expect(colorSchema.safeParse('white').success).toBe(true); + expect(colorSchema.safeParse('black').success).toBe(true); + }); + + it('accepts extended CSS named colors', () => { + expect(colorSchema.safeParse('rebeccapurple').success).toBe(true); + expect(colorSchema.safeParse('cornflowerblue').success).toBe(true); + expect(colorSchema.safeParse('papayawhip').success).toBe(true); + }); + + it('accepts transparent keyword', () => { + expect(colorSchema.safeParse('transparent').success).toBe(true); + }); + + it('accepts currentColor keyword', () => { + expect(colorSchema.safeParse('currentColor').success).toBe(true); + expect(colorSchema.safeParse('currentcolor').success).toBe(true); + }); + + it('is case-insensitive for named colors', () => { + expect(colorSchema.safeParse('RED').success).toBe(true); + expect(colorSchema.safeParse('Red').success).toBe(true); + expect(colorSchema.safeParse('RebeccaPurple').success).toBe(true); + }); + }); + + describe('invalid colors', () => { + it('rejects empty string', () => { + expect(colorSchema.safeParse('').success).toBe(false); + }); + + it('rejects strings with spaces only', () => { + expect(colorSchema.safeParse(' ').success).toBe(false); + }); + + it('rejects numbers as strings', () => { + // Numbers alone are not valid colors + expect(colorSchema.safeParse('123').success).toBe(false); + expect(colorSchema.safeParse('0').success).toBe(false); + }); + + it('rejects arbitrary strings with non-alpha characters', () => { + expect(colorSchema.safeParse('not-a-color').success).toBe(false); + expect(colorSchema.safeParse('hello_world').success).toBe(false); + expect(colorSchema.safeParse('color.name').success).toBe(false); + }); + + it('rejects unknown function names', () => { + expect(colorSchema.safeParse('cmyk(0, 100, 100, 0)').success).toBe(false); + expect(colorSchema.safeParse('custom(1, 2, 3)').success).toBe(false); + }); + }); + + describe('edge cases', () => { + it('accepts colors with none keyword for missing components', () => { + // CSS Color Level 4 allows 'none' for missing components + expect(colorSchema.safeParse('hsl(none 50% 50%)').success).toBe(true); + expect(colorSchema.safeParse('oklch(60% 0.15 none)').success).toBe(true); + }); + + it('accepts calc() expressions inside color functions', () => { + // While unusual, calc() can be used inside color functions + expect(colorSchema.safeParse('rgb(calc(255 * 0.5) 0 0)').success).toBe(true); + }); + }); +}); diff --git a/src/mcp/__tests__/utils/color.test.ts b/src/mcp/__tests__/utils/color.test.ts new file mode 100644 index 00000000..c6c107fb --- /dev/null +++ b/src/mcp/__tests__/utils/color.test.ts @@ -0,0 +1,262 @@ +/** + * Tests for color analysis utilities. + * + * These tests use real Sass compilation to verify color analysis. + */ + +import { describe, it, expect } from 'vitest'; +import { + analyzeColor, + calculateContrast, + analyzeSurfaceGrayColors, + isValidColor, + validateColorsInBatch, + extractHue, + huesAreClose, + analyzeColorForPalette, + LUMINANCE_THRESHOLD, + PALETTE_LUMINANCE_THRESHOLDS, +} from '../../utils/color.js'; + +describe('analyzeColor', () => { + it('analyzes white as a light color', async () => { + const result = await analyzeColor('white'); + expect(result.color).toBe('white'); + expect(result.luminance).toBeCloseTo(1, 1); + expect(result.isLight).toBe(true); + }); + + it('analyzes black as a dark color', async () => { + const result = await analyzeColor('black'); + expect(result.color).toBe('black'); + expect(result.luminance).toBeCloseTo(0, 1); + expect(result.isLight).toBe(false); + }); + + it('analyzes hex colors correctly', async () => { + const result = await analyzeColor('#808080'); // 50% gray + expect(result.luminance).toBeGreaterThan(0.1); + expect(result.luminance).toBeLessThan(0.5); + }); + + it('throws error for invalid colors', async () => { + await expect(analyzeColor('not-a-color')).rejects.toThrow(); + }); +}); + +describe('calculateContrast', () => { + it('calculates maximum contrast between black and white', async () => { + const ratio = await calculateContrast('white', 'black'); + expect(ratio).toBeCloseTo(21, 0); + }); + + it('calculates no contrast between same colors', async () => { + const ratio = await calculateContrast('#808080', '#808080'); + expect(ratio).toBeCloseTo(1, 0); + }); + + it('calculates reasonable contrast for mid-tones', async () => { + const ratio = await calculateContrast('white', '#808080'); + expect(ratio).toBeGreaterThan(3); + expect(ratio).toBeLessThan(10); + }); +}); + +describe('analyzeSurfaceGrayColors', () => { + it('returns empty object when no colors provided', async () => { + const result = await analyzeSurfaceGrayColors({}); + expect(result).toEqual({}); + }); + + it('analyzes surface only', async () => { + const result = await analyzeSurfaceGrayColors({ surface: 'white' }); + expect(result.surface).toBeDefined(); + expect(result.surface?.isLight).toBe(true); + expect(result.gray).toBeUndefined(); + expect(result.contrastRatio).toBeUndefined(); + }); + + it('analyzes gray only', async () => { + const result = await analyzeSurfaceGrayColors({ gray: 'black' }); + expect(result.gray).toBeDefined(); + expect(result.gray?.isLight).toBe(false); + expect(result.surface).toBeUndefined(); + }); + + it('analyzes both surface and gray with contrast', async () => { + const result = await analyzeSurfaceGrayColors({ + surface: 'white', + gray: 'black', + }); + expect(result.surface?.isLight).toBe(true); + expect(result.gray?.isLight).toBe(false); + expect(result.contrastRatio).toBeCloseTo(21, 0); + }); +}); + +describe('isValidColor', () => { + it('returns true for valid hex color', async () => { + expect(await isValidColor('#ff0000')).toBe(true); + }); + + it('returns true for valid named color', async () => { + expect(await isValidColor('rebeccapurple')).toBe(true); + }); + + it('returns true for rgb() color', async () => { + expect(await isValidColor('rgb(255, 0, 0)')).toBe(true); + }); + + it('returns false for invalid color', async () => { + expect(await isValidColor('not-a-color')).toBe(false); + }); + + it('returns false for empty string', async () => { + expect(await isValidColor('')).toBe(false); + }); +}); + +describe('extractHue', () => { + it('extracts hue from red', async () => { + const hue = await extractHue('red'); + expect(hue).toBeCloseTo(0, 0); + }); + + it('extracts hue from blue', async () => { + const hue = await extractHue('blue'); + expect(hue).toBeCloseTo(240, 0); + }); + + it('extracts hue from green', async () => { + const hue = await extractHue('lime'); // lime is pure green + expect(hue).toBeCloseTo(120, 0); + }); +}); + +describe('huesAreClose', () => { + it('returns true for identical hues', () => { + expect(huesAreClose(180, 180)).toBe(true); + }); + + it('returns true for hues within tolerance', () => { + expect(huesAreClose(180, 190, 30)).toBe(true); + }); + + it('returns false for hues outside tolerance', () => { + expect(huesAreClose(180, 220, 30)).toBe(false); + }); + + it('handles circular hue (0 and 360 are the same)', () => { + expect(huesAreClose(10, 350, 30)).toBe(true); + }); + + it('handles crossing the 360/0 boundary', () => { + expect(huesAreClose(355, 5, 15)).toBe(true); + }); +}); + +describe('analyzeColorForPalette', () => { + it('marks mid-tone colors as suitable', async () => { + const result = await analyzeColorForPalette('#2ab759'); // Medium green + expect(result.suitable).toBe(true); + // TypeScript correctly narrows: issue/description don't exist on suitable results + if (!result.suitable) { + throw new Error('Expected suitable result'); + } + }); + + it('marks very light colors as unsuitable (too light)', async () => { + const result = await analyzeColorForPalette('#f8f8f8'); // Very light gray + expect(result.suitable).toBe(false); + if (result.suitable) { + throw new Error('Expected unsuitable result'); + } + expect(result.issue).toBe('too-light'); + expect(result.description).toBeDefined(); + }); + + it('marks very dark colors as unsuitable (too dark)', async () => { + const result = await analyzeColorForPalette('#0a0a0a'); // Very dark gray + expect(result.suitable).toBe(false); + if (result.suitable) { + throw new Error('Expected unsuitable result'); + } + expect(result.issue).toBe('too-dark'); + expect(result.description).toBeDefined(); + }); + + it('uses correct threshold for too light', async () => { + const result = await analyzeColorForPalette('white'); + expect(result.luminance).toBeGreaterThan(PALETTE_LUMINANCE_THRESHOLDS.TOO_LIGHT); + expect(result.suitable).toBe(false); + }); + + it('uses correct threshold for too dark', async () => { + const result = await analyzeColorForPalette('black'); + expect(result.luminance).toBeLessThan(PALETTE_LUMINANCE_THRESHOLDS.TOO_DARK); + expect(result.suitable).toBe(false); + }); +}); + +describe('LUMINANCE_THRESHOLD', () => { + it('is set to 0.5 for light/dark determination', () => { + expect(LUMINANCE_THRESHOLD).toBe(0.5); + }); +}); + +describe('validateColorsInBatch', () => { + it('returns empty object for empty input', async () => { + const result = await validateColorsInBatch({}); + expect(result).toEqual({}); + }); + + it('validates multiple valid colors in single batch', async () => { + const result = await validateColorsInBatch({ + primary: '#ff0000', + secondary: 'blue', + surface: 'rgb(255, 255, 255)', + }); + expect(result.primary).toBe(true); + expect(result.secondary).toBe(true); + expect(result.surface).toBe(true); + }); + + it('identifies invalid colors in batch', async () => { + const result = await validateColorsInBatch({ + valid1: '#ff0000', + invalid1: 'not-a-color', + valid2: 'blue', + invalid2: 'also-invalid', + }); + expect(result.valid1).toBe(true); + expect(result.invalid1).toBe(false); + expect(result.valid2).toBe(true); + expect(result.invalid2).toBe(false); + }); + + it('handles large batches efficiently (14+ colors)', async () => { + const colors: Record = {}; + const shades = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', 'A100', 'A200', 'A400', 'A700']; + + // Generate 14 valid hex colors + for (const shade of shades) { + colors[`shade-${shade}`] = `#${Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0')}`; + } + + const result = await validateColorsInBatch(colors); + + // All should be valid + for (const shade of shades) { + expect(result[`shade-${shade}`]).toBe(true); + } + }); + + it('handles keys with special characters', async () => { + const result = await validateColorsInBatch({ + 'primary.500': '#ff0000', + 'contrast.A100': 'white', + }); + expect(result['primary.500']).toBe(true); + expect(result['contrast.A100']).toBe(true); + }); +}); diff --git a/src/mcp/__tests__/utils/result.test.ts b/src/mcp/__tests__/utils/result.test.ts new file mode 100644 index 00000000..8ae5b4f5 --- /dev/null +++ b/src/mcp/__tests__/utils/result.test.ts @@ -0,0 +1,412 @@ +import {describe, it, expect} from 'vitest'; +import { + success, + failure, + isSuccess, + isFailure, + mapResult, + unwrap, + unwrapOr, + mcpError, + validationSuccess, + validationFailure, + combineValidationResults, + formatValidationMessages, + type Result, + type McpResult, + type ValidationResult, + type ValidationError, + type ValidationWarning, +} from '../../utils/result'; + +describe('Result Type', () => { + describe('success()', () => { + it('creates a successful result with a value', () => { + const result = success(42); + expect(result.ok).toBe(true); + expect(result.value).toBe(42); + }); + + it('creates a successful result with an object value', () => { + const value = {code: 'test', lines: 10}; + const result = success(value); + expect(result.ok).toBe(true); + expect(result.value).toEqual(value); + }); + + it('creates a successful result with null value', () => { + const result = success(null); + expect(result.ok).toBe(true); + expect(result.value).toBeNull(); + }); + + it('creates a successful result with undefined value', () => { + const result = success(undefined); + expect(result.ok).toBe(true); + expect(result.value).toBeUndefined(); + }); + }); + + describe('failure()', () => { + it('creates a failed result with an error', () => { + const error = new Error('Something went wrong'); + const result = failure(error); + expect(result.ok).toBe(false); + expect(result.error).toBe(error); + }); + + it('creates a failed result with a string error', () => { + const result = failure('Invalid input'); + expect(result.ok).toBe(false); + expect(result.error).toBe('Invalid input'); + }); + + it('creates a failed result with an object error', () => { + const error = {code: 'ERR_001', message: 'Failed'}; + const result = failure(error); + expect(result.ok).toBe(false); + expect(result.error).toEqual(error); + }); + }); + + describe('isSuccess()', () => { + it('returns true for success results', () => { + const result = success('value'); + expect(isSuccess(result)).toBe(true); + }); + + it('returns false for failure results', () => { + const result = failure(new Error('error')); + expect(isSuccess(result)).toBe(false); + }); + + it('narrows type correctly', () => { + const result: Result = success(42); + if (isSuccess(result)) { + // TypeScript should allow accessing value here + expect(result.value).toBe(42); + } + }); + }); + + describe('isFailure()', () => { + it('returns true for failure results', () => { + const result = failure(new Error('error')); + expect(isFailure(result)).toBe(true); + }); + + it('returns false for success results', () => { + const result = success('value'); + expect(isFailure(result)).toBe(false); + }); + + it('narrows type correctly', () => { + const result: Result = failure(new Error('test error')); + if (isFailure(result)) { + // TypeScript should allow accessing error here + expect(result.error.message).toBe('test error'); + } + }); + }); + + describe('mapResult()', () => { + it('transforms the value of a success result', () => { + const result = success(5); + const mapped = mapResult(result, (x) => x * 2); + expect(isSuccess(mapped)).toBe(true); + if (isSuccess(mapped)) { + expect(mapped.value).toBe(10); + } + }); + + it('returns failure unchanged', () => { + const error = new Error('original error'); + const result: Result = failure(error); + const mapped = mapResult(result, (x: number) => x * 2); + expect(isFailure(mapped)).toBe(true); + if (isFailure(mapped)) { + expect(mapped.error).toBe(error); + } + }); + + it('can change the type of the value', () => { + const result = success(42); + const mapped = mapResult(result, (x) => x.toString()); + expect(isSuccess(mapped)).toBe(true); + if (isSuccess(mapped)) { + expect(mapped.value).toBe('42'); + } + }); + }); + + describe('unwrap()', () => { + it('returns the value for a success result', () => { + const result = success(42); + expect(unwrap(result)).toBe(42); + }); + + it('throws the error for a failure result', () => { + const error = new Error('test error'); + const result: Result = failure(error); + expect(() => unwrap(result)).toThrow('test error'); + }); + }); + + describe('unwrapOr()', () => { + it('returns the value for a success result', () => { + const result = success(42); + expect(unwrapOr(result, 0)).toBe(42); + }); + + it('returns the default value for a failure result', () => { + const result: Result = failure(new Error('error')); + expect(unwrapOr(result, 0)).toBe(0); + }); + + it('works with null as default', () => { + const result: Result = failure(new Error('error')); + expect(unwrapOr(result, null)).toBeNull(); + }); + }); +}); + +describe('McpError', () => { + describe('mcpError()', () => { + it('creates an error with code and message', () => { + const error = mcpError('INVALID_COLOR', 'Invalid hex color'); + expect(error.code).toBe('INVALID_COLOR'); + expect(error.message).toBe('Invalid hex color'); + expect(error.context).toBeUndefined(); + }); + + it('creates an error with context', () => { + const error = mcpError('VALIDATION_ERROR', 'Missing field', {field: 'primary'}); + expect(error.code).toBe('VALIDATION_ERROR'); + expect(error.message).toBe('Missing field'); + expect(error.context).toEqual({field: 'primary'}); + }); + + it('supports all error codes', () => { + const codes = [ + 'INVALID_COLOR', + 'INVALID_PARAMETER', + 'SASS_COMPILATION_ERROR', + 'VALIDATION_ERROR', + 'NOT_FOUND', + 'UNKNOWN_ERROR', + ] as const; + + for (const code of codes) { + const error = mcpError(code, 'test'); + expect(error.code).toBe(code); + } + }); + }); + + describe('McpResult type', () => { + it('can be used as Result with McpError', () => { + const successResult: McpResult = success('generated code'); + const failureResult: McpResult = failure(mcpError('INVALID_COLOR', 'Bad color')); + + expect(isSuccess(successResult)).toBe(true); + expect(isFailure(failureResult)).toBe(true); + }); + }); +}); + +describe('ValidationResult', () => { + describe('validationSuccess()', () => { + it('creates a valid result with no warnings', () => { + const result = validationSuccess(); + expect(result.isValid).toBe(true); + expect(result.errors).toEqual([]); + expect(result.warnings).toEqual([]); + }); + + it('creates a valid result with warnings', () => { + const warnings: ValidationWarning[] = [{message: 'Consider using a lighter shade'}]; + const result = validationSuccess(warnings); + expect(result.isValid).toBe(true); + expect(result.errors).toEqual([]); + expect(result.warnings).toEqual(warnings); + }); + }); + + describe('validationFailure()', () => { + it('creates an invalid result with errors', () => { + const errors: ValidationError[] = [{message: 'Invalid color', field: 'primary'}]; + const result = validationFailure(errors); + expect(result.isValid).toBe(false); + expect(result.errors).toEqual(errors); + expect(result.warnings).toEqual([]); + }); + + it('creates an invalid result with errors and warnings', () => { + const errors: ValidationError[] = [{message: 'Invalid color'}]; + const warnings: ValidationWarning[] = [{message: 'Consider accessibility'}]; + const result = validationFailure(errors, warnings); + expect(result.isValid).toBe(false); + expect(result.errors).toEqual(errors); + expect(result.warnings).toEqual(warnings); + }); + }); + + describe('combineValidationResults()', () => { + it('combines multiple valid results', () => { + const result1 = validationSuccess(); + const result2 = validationSuccess(); + const combined = combineValidationResults(result1, result2); + expect(combined.isValid).toBe(true); + expect(combined.errors).toEqual([]); + }); + + it('combines valid results with warnings', () => { + const result1 = validationSuccess([{message: 'warning 1'}]); + const result2 = validationSuccess([{message: 'warning 2'}]); + const combined = combineValidationResults(result1, result2); + expect(combined.isValid).toBe(true); + expect(combined.warnings).toHaveLength(2); + expect(combined.warnings[0].message).toBe('warning 1'); + expect(combined.warnings[1].message).toBe('warning 2'); + }); + + it('returns invalid if any result is invalid', () => { + const valid = validationSuccess(); + const invalid = validationFailure([{message: 'error'}]); + const combined = combineValidationResults(valid, invalid); + expect(combined.isValid).toBe(false); + expect(combined.errors).toHaveLength(1); + }); + + it('combines all errors from multiple invalid results', () => { + const result1 = validationFailure([{message: 'error 1'}]); + const result2 = validationFailure([{message: 'error 2'}]); + const combined = combineValidationResults(result1, result2); + expect(combined.isValid).toBe(false); + expect(combined.errors).toHaveLength(2); + }); + + it('handles empty array', () => { + const combined = combineValidationResults(); + expect(combined.isValid).toBe(true); + expect(combined.errors).toEqual([]); + expect(combined.warnings).toEqual([]); + }); + + it('preserves error and warning details', () => { + const result1 = validationFailure( + [{message: 'error', field: 'primary', suggestion: 'use hex'}], + [{message: 'warning', field: 'secondary'}], + ); + const result2 = validationSuccess([{message: 'info', suggestion: 'consider contrast'}]); + const combined = combineValidationResults(result1, result2); + + expect(combined.errors[0].field).toBe('primary'); + expect(combined.errors[0].suggestion).toBe('use hex'); + expect(combined.warnings[0].field).toBe('secondary'); + expect(combined.warnings[1].suggestion).toBe('consider contrast'); + }); + }); + + describe('formatValidationMessages()', () => { + it('formats errors only', () => { + const result = validationFailure([{message: 'Invalid color'}, {message: 'Missing shade'}]); + const formatted = formatValidationMessages(result); + expect(formatted).toContain('**Errors:**'); + expect(formatted).toContain('Invalid color'); + expect(formatted).toContain('Missing shade'); + expect(formatted).not.toContain('**Warnings:**'); + }); + + it('formats warnings only', () => { + const result = validationSuccess([{message: 'Consider accessibility'}]); + const formatted = formatValidationMessages(result); + expect(formatted).toContain('**Warnings:**'); + expect(formatted).toContain('Consider accessibility'); + expect(formatted).not.toContain('**Errors:**'); + }); + + it('formats both errors and warnings', () => { + const result = validationFailure([{message: 'Invalid'}], [{message: 'Warning'}]); + const formatted = formatValidationMessages(result); + expect(formatted).toContain('**Errors:**'); + expect(formatted).toContain('**Warnings:**'); + }); + + it('includes field prefix when present', () => { + const result = validationFailure([{message: 'Invalid color', field: 'primary'}]); + const formatted = formatValidationMessages(result); + expect(formatted).toContain('`primary`'); + expect(formatted).toContain('Invalid color'); + }); + + it('includes suggestions when present', () => { + const result = validationFailure([{message: 'Invalid', suggestion: 'Try using hex format'}]); + const formatted = formatValidationMessages(result); + expect(formatted).toContain('Suggestion: Try using hex format'); + }); + + it('returns empty string for valid result without warnings', () => { + const result = validationSuccess(); + const formatted = formatValidationMessages(result); + expect(formatted).toBe(''); + }); + + it('formats complex validation result correctly', () => { + const result: ValidationResult = { + isValid: false, + errors: [ + {field: 'primary', message: 'Invalid hex color', suggestion: 'Use format #RRGGBB'}, + {message: 'Missing required shade 500'}, + ], + warnings: [ + {field: 'contrast', message: 'Low contrast ratio', suggestion: 'Consider WCAG guidelines'}, + ], + }; + const formatted = formatValidationMessages(result); + + expect(formatted).toContain('**Errors:**'); + expect(formatted).toContain('`primary`'); + expect(formatted).toContain('Invalid hex color'); + expect(formatted).toContain('Suggestion: Use format #RRGGBB'); + expect(formatted).toContain('Missing required shade 500'); + expect(formatted).toContain('**Warnings:**'); + expect(formatted).toContain('`contrast`'); + expect(formatted).toContain('Low contrast ratio'); + expect(formatted).toContain('Suggestion: Consider WCAG guidelines'); + }); + + it('formats tips when present', () => { + const result: ValidationResult = { + isValid: false, + errors: [{message: 'Error'}], + warnings: [], + tips: ['Use lighter colors', 'Consider contrast ratio'], + }; + const formatted = formatValidationMessages(result); + + expect(formatted).toContain('**Tips:**'); + expect(formatted).toContain('Use lighter colors'); + expect(formatted).toContain('Consider contrast ratio'); + }); + + it('respects includeIcons option', () => { + const result = validationFailure([{message: 'Error'}], [{message: 'Warning'}]); + const formatted = formatValidationMessages(result, {includeIcons: false}); + expect(formatted).not.toContain('❌'); + expect(formatted).not.toContain('⚠️'); + }); + + it('shows info icon for info severity warnings', () => { + const result = validationSuccess([{message: 'Info message', severity: 'info'}]); + const formatted = formatValidationMessages(result); + expect(formatted).toContain('ℹ️'); + }); + + it('includes suggestedValues when present', () => { + const result = validationSuccess([{message: 'Warning', suggestedValues: ['#fff', '#000']}]); + const formatted = formatValidationMessages(result); + expect(formatted).toContain('Suggested: #fff, #000'); + }); + }); +}); diff --git a/src/mcp/__tests__/utils/sass.test.ts b/src/mcp/__tests__/utils/sass.test.ts new file mode 100644 index 00000000..6759e04e --- /dev/null +++ b/src/mcp/__tests__/utils/sass.test.ts @@ -0,0 +1,176 @@ +/** + * Tests for Sass utility functions. + */ + +import { describe, it, expect } from 'vitest'; +import { + toVariableName, + generateHeader, + quoteFontFamily, + generateUseStatement, + generatePaletteCode, +} from '../../utils/sass.js'; + +describe('toVariableName', () => { + it('converts spaces to hyphens', () => { + expect(toVariableName('My Theme')).toBe('my-theme'); + }); + + it('converts to lowercase', () => { + expect(toVariableName('DARK_THEME')).toBe('dark-theme'); + }); + + it('handles mixed case with numbers', () => { + expect(toVariableName('Theme_v2_Test')).toBe('theme-v2-test'); + }); + + it('removes invalid characters', () => { + expect(toVariableName('Theme@#$%')).toBe('theme'); + }); + + it('collapses multiple hyphens', () => { + expect(toVariableName('my---theme')).toBe('my-theme'); + }); + + it('removes leading and trailing hyphens', () => { + expect(toVariableName('-my-theme-')).toBe('my-theme'); + }); + + it('throws on empty input', () => { + expect(() => toVariableName('')).toThrow('Variable name cannot be empty'); + }); + + it('throws on whitespace-only input', () => { + expect(() => toVariableName(' ')).toThrow('Variable name cannot be empty'); + }); + + it('throws when result would be empty', () => { + expect(() => toVariableName('@#$%')).toThrow('Cannot create valid Sass variable name'); + }); +}); + +describe('generateHeader', () => { + it('generates a comment header with description', () => { + const result = generateHeader('Custom palette'); + expect(result).toContain('Generated by Ignite UI Theming MCP Server'); + expect(result).toContain('Custom palette'); + }); + + it('produces valid Sass comments', () => { + const result = generateHeader('Test'); + const lines = result.split('\n'); + expect(lines.every((line) => line.startsWith('//'))).toBe(true); + }); +}); + +describe('quoteFontFamily', () => { + it('quotes unquoted single font names', () => { + expect(quoteFontFamily('Roboto')).toBe("'Roboto'"); + }); + + it('leaves already single-quoted fonts unchanged', () => { + expect(quoteFontFamily("'Roboto'")).toBe("'Roboto'"); + }); + + it('leaves already double-quoted fonts unchanged', () => { + expect(quoteFontFamily('"Roboto"')).toBe('"Roboto"'); + }); + + it('wraps font stacks with double quotes when they contain single quotes', () => { + const input = "'Titillium Web', sans-serif"; + expect(quoteFontFamily(input)).toBe(`"'Titillium Web', sans-serif"`); + }); + + it('wraps font stacks with single quotes when they contain double quotes', () => { + const input = '"Titillium Web", sans-serif'; + expect(quoteFontFamily(input)).toBe(`'"Titillium Web", sans-serif'`); + }); +}); + +describe('generateUseStatement', () => { + it('generates Angular import for angular platform', () => { + const result = generateUseStatement('angular'); + expect(result).toBe('@use "igniteui-angular/theming" as *;'); + }); + + it('generates generic import for webcomponents platform', () => { + const result = generateUseStatement('webcomponents'); + expect(result).toBe("@use 'igniteui-theming' as *;"); + }); + + it('generates generic import when platform is undefined', () => { + const result = generateUseStatement(); + expect(result).toBe("@use 'igniteui-theming' as *;"); + }); +}); + +describe('generatePaletteCode', () => { + it('generates palette code with required parameters', () => { + const result = generatePaletteCode({ + primary: '#2ab759', + secondary: '#f7bd32', + surface: 'white', + }); + + expect(result.variableName).toBe('$custom-light-palette'); + expect(result.paletteDefinition.join('\n')).toContain('$primary: #2ab759'); + expect(result.paletteDefinition.join('\n')).toContain('$secondary: #f7bd32'); + expect(result.paletteDefinition.join('\n')).toContain('$surface: white'); + }); + + it('uses custom variable name when provided', () => { + const result = generatePaletteCode({ + primary: '#2ab759', + secondary: '#f7bd32', + surface: 'white', + variableName: 'my-brand', + }); + + expect(result.variableName).toBe('$my-brand'); + }); + + it('uses dark variant in variable name', () => { + const result = generatePaletteCode({ + primary: '#2ab759', + secondary: '#f7bd32', + surface: '#121212', + variant: 'dark', + }); + + expect(result.variableName).toBe('$custom-dark-palette'); + }); + + it('includes optional colors when provided', () => { + const result = generatePaletteCode({ + primary: '#2ab759', + secondary: '#f7bd32', + surface: 'white', + gray: '#333', + info: '#0288d1', + success: '#4caf50', + warn: '#ff9800', + error: '#f44336', + }); + + const code = result.paletteDefinition.join('\n'); + expect(code).toContain('$gray: #333'); + expect(code).toContain('$info: #0288d1'); + expect(code).toContain('$success: #4caf50'); + expect(code).toContain('$warn: #ff9800'); + expect(code).toContain('$error: #f44336'); + }); + + it('generates variable references when useVariableReferences is true', () => { + const result = generatePaletteCode({ + primary: '#2ab759', + secondary: '#f7bd32', + surface: 'white', + useVariableReferences: true, + }); + + expect(result.colorVariables).toContain('$primary-color: #2ab759;'); + expect(result.colorVariables).toContain('$secondary-color: #f7bd32;'); + expect(result.colorVariables).toContain('$surface-color: white;'); + expect(result.paletteDefinition.join('\n')).toContain('$primary: $primary-color'); + }); +}); diff --git a/src/mcp/__tests__/validators/custom-palette.test.ts b/src/mcp/__tests__/validators/custom-palette.test.ts new file mode 100644 index 00000000..e969f717 --- /dev/null +++ b/src/mcp/__tests__/validators/custom-palette.test.ts @@ -0,0 +1,337 @@ +/** + * Tests for custom palette validation. + */ + +import { describe, it, expect } from 'vitest'; +import { + validateCustomPalette, + formatCustomPaletteValidation, + type CustomPaletteValidationResult, +} from '../../validators/custom-palette.js'; +import type { CreateCustomPaletteInput, ShadesBasedColor, ExplicitColorShades } from '../../utils/types.js'; + +// Helper to create a minimal valid shades-based palette +function createShadesBasedPalette(overrides?: Partial): CreateCustomPaletteInput { + const shadesColor = (baseColor: string): ShadesBasedColor => ({ + mode: 'shades', + baseColor, + }); + + return { + platform: 'angular', + variant: 'light', + designSystem: 'material', + name: 'test-palette', + primary: shadesColor('#2ab759'), + secondary: shadesColor('#f7bd32'), + surface: shadesColor('#fafafa'), + ...overrides, + }; +} + +// Helper to create explicit shade maps +function createExplicitShades(): ExplicitColorShades['shades'] { + return { + '50': '#e8f5e9', + '100': '#c8e6c9', + '200': '#a5d6a7', + '300': '#81c784', + '400': '#66bb6a', + '500': '#4caf50', + '600': '#43a047', + '700': '#388e3c', + '800': '#2e7d32', + '900': '#1b5e20', + 'A100': '#b9f6ca', + 'A200': '#69f0ae', + 'A400': '#00e676', + 'A700': '#00c853', + }; +} + +describe('validateCustomPalette', () => { + describe('shades mode validation', () => { + it('validates a minimal shades-based palette', async () => { + const input = createShadesBasedPalette(); + const result = await validateCustomPalette(input, 'light'); + + expect(result.isValid).toBe(true); + expect(result.errors).toHaveLength(0); + }); + + it('reports error for invalid base color', async () => { + const input = createShadesBasedPalette({ + primary: { mode: 'shades', baseColor: 'not-a-color' }, + }); + const result = await validateCustomPalette(input, 'light'); + + expect(result.isValid).toBe(false); + expect(result.errors).toContainEqual( + expect.objectContaining({ + field: 'primary', + message: expect.stringContaining('Invalid base color'), + }) + ); + }); + + it('validates all color groups with shades mode', async () => { + const input = createShadesBasedPalette({ + gray: { mode: 'shades', baseColor: '#333333' }, + info: { mode: 'shades', baseColor: '#0288d1' }, + success: { mode: 'shades', baseColor: '#4caf50' }, + warn: { mode: 'shades', baseColor: '#ff9800' }, + error: { mode: 'shades', baseColor: '#f44336' }, + }); + const result = await validateCustomPalette(input, 'light'); + + expect(result.isValid).toBe(true); + }); + }); + + describe('explicit mode validation', () => { + it('validates explicit shades with all required shades', async () => { + const input = createShadesBasedPalette({ + primary: { + mode: 'explicit', + shades: createExplicitShades(), + }, + }); + const result = await validateCustomPalette(input, 'light'); + + expect(result.isValid).toBe(true); + }); + + it('reports error for missing required shade', async () => { + const shades = createExplicitShades(); + // Remove a required shade + delete (shades as Record)['500']; + + const input = createShadesBasedPalette({ + primary: { + mode: 'explicit', + shades: shades as ExplicitColorShades['shades'], + }, + }); + const result = await validateCustomPalette(input, 'light'); + + expect(result.isValid).toBe(false); + expect(result.errors).toContainEqual( + expect.objectContaining({ + field: 'primary.500', + message: expect.stringContaining('Missing required shade'), + }) + ); + }); + + it('reports error for invalid color value in shade', async () => { + const shades = createExplicitShades(); + (shades as Record)['500'] = 'invalid-color'; + + const input = createShadesBasedPalette({ + primary: { + mode: 'explicit', + shades: shades as ExplicitColorShades['shades'], + }, + }); + const result = await validateCustomPalette(input, 'light'); + + expect(result.isValid).toBe(false); + expect(result.errors).toContainEqual( + expect.objectContaining({ + field: 'primary.500', + message: expect.stringContaining('Invalid color value'), + }) + ); + }); + }); + + describe('contrast overrides validation', () => { + it('validates valid contrast overrides', async () => { + const input = createShadesBasedPalette({ + primary: { + mode: 'explicit', + shades: createExplicitShades(), + contrastOverrides: { + '500': 'white', + '900': '#ffffff', + }, + }, + }); + const result = await validateCustomPalette(input, 'light'); + + expect(result.isValid).toBe(true); + }); + + it('reports error for invalid contrast override key', async () => { + const input = createShadesBasedPalette({ + primary: { + mode: 'explicit', + shades: createExplicitShades(), + contrastOverrides: { + 'invalid-shade': 'white', + } as ExplicitColorShades['contrastOverrides'], + }, + }); + const result = await validateCustomPalette(input, 'light'); + + expect(result.isValid).toBe(false); + expect(result.errors).toContainEqual( + expect.objectContaining({ + field: 'primary.invalid-shade', + message: expect.stringContaining('Invalid contrast override key'), + }) + ); + }); + + it('reports error for invalid contrast color value', async () => { + const input = createShadesBasedPalette({ + primary: { + mode: 'explicit', + shades: createExplicitShades(), + contrastOverrides: { + '500': 'not-a-color', + }, + }, + }); + const result = await validateCustomPalette(input, 'light'); + + expect(result.isValid).toBe(false); + expect(result.errors).toContainEqual( + expect.objectContaining({ + field: 'primary.contrast.500', + message: expect.stringContaining('Invalid contrast color'), + }) + ); + }); + }); + + describe('shade progression validation', () => { + it('warns when shade 50 is darker than shade 900 for chromatic colors', async () => { + const shades = createExplicitShades(); + // Invert 50 and 900 + (shades as Record)['50'] = '#1b5e20'; // dark + (shades as Record)['900'] = '#e8f5e9'; // light + + const input = createShadesBasedPalette({ + primary: { + mode: 'explicit', + shades: shades as ExplicitColorShades['shades'], + }, + }); + const result = await validateCustomPalette(input, 'light'); + + // Should still be valid but have warnings + expect(result.isValid).toBe(true); + expect(result.warnings).toContainEqual( + expect.objectContaining({ + field: 'primary', + message: expect.stringContaining('shade 50 should be lighter than shade 900'), + }) + ); + }); + + it('warns for incorrect gray progression in dark themes', async () => { + // For dark themes, gray 50 should be DARKER than 900 (inverted) + const grayShades = { + '50': '#fafafa', // light - wrong for dark theme + '100': '#f5f5f5', + '200': '#eeeeee', + '300': '#e0e0e0', + '400': '#bdbdbd', + '500': '#9e9e9e', + '600': '#757575', + '700': '#616161', + '800': '#424242', + '900': '#212121', // dark - wrong for dark theme + }; + + const input = createShadesBasedPalette({ + variant: 'dark', + gray: { + mode: 'explicit', + shades: grayShades, + }, + }); + const result = await validateCustomPalette(input, 'dark'); + + expect(result.warnings).toContainEqual( + expect.objectContaining({ + field: 'gray', + message: expect.stringContaining('dark themes'), + }) + ); + }); + }); + + describe('monochromatic hue validation', () => { + it('warns when shades have different hues', async () => { + const shades = createExplicitShades(); + // Change 500 to a completely different hue (blue instead of green) + (shades as Record)['500'] = '#2196f3'; + + const input = createShadesBasedPalette({ + primary: { + mode: 'explicit', + shades: shades as ExplicitColorShades['shades'], + }, + }); + const result = await validateCustomPalette(input, 'light'); + + expect(result.warnings).toContainEqual( + expect.objectContaining({ + field: 'primary', + message: expect.stringContaining('monochromatic'), + }) + ); + }); + }); +}); + +describe('formatCustomPaletteValidation', () => { + it('returns empty string for valid result with no warnings', () => { + const result: CustomPaletteValidationResult = { + isValid: true, + errors: [], + warnings: [], + }; + expect(formatCustomPaletteValidation(result)).toBe(''); + }); + + it('formats errors', () => { + const result: CustomPaletteValidationResult = { + isValid: false, + errors: [{field: 'primary.500', message: 'Invalid color'}], + warnings: [], + }; + const formatted = formatCustomPaletteValidation(result); + + expect(formatted).toContain('**Errors:**'); + expect(formatted).toContain('primary.500'); + expect(formatted).toContain('Invalid color'); + }); + + it('formats warnings', () => { + const result: CustomPaletteValidationResult = { + isValid: true, + errors: [], + warnings: [{field: 'gray', message: 'Consider adjusting', severity: 'warning'}], + }; + const formatted = formatCustomPaletteValidation(result); + + expect(formatted).toContain('**Warnings:**'); + expect(formatted).toContain('gray'); + expect(formatted).toContain('Consider adjusting'); + }); + + it('formats both errors and warnings', () => { + const result: CustomPaletteValidationResult = { + isValid: false, + errors: [{field: 'primary', message: 'Error message'}], + warnings: [{field: 'gray', message: 'Warning message', severity: 'warning'}], + }; + const formatted = formatCustomPaletteValidation(result); + + expect(formatted).toContain('**Errors:**'); + expect(formatted).toContain('**Warnings:**'); + }); +}); diff --git a/src/mcp/generators/sass.ts b/src/mcp/generators/sass.ts new file mode 100644 index 00000000..7c6e4d1a --- /dev/null +++ b/src/mcp/generators/sass.ts @@ -0,0 +1,322 @@ +/** + * Sass code generator for Ignite UI Theming. + * Generates valid Sass code that uses the igniteui-theming library. + * + * Supports two platforms: + * - Angular: Uses `igniteui-angular/theming` with `core()` and `theme()` mixins + * - Web Components: Uses `igniteui-theming` directly with individual mixins + */ + +import type { + CreatePaletteInput, + CreateTypographyInput, + CreateElevationsInput, + CreateThemeInput, + GeneratedCode, + DesignSystem, + ThemeVariant, +} from '../utils/types.js'; +import { + quoteFontFamily, + generateUseStatement, + toVariableName, + generateHeader, +} from '../utils/sass.js'; +import { + TYPOGRAPHY_PRESETS, + generateAngularThemeSass, + generateWebComponentsThemeSass, +} from '../knowledge/index.js'; + +// Re-export utilities for external use +export { + quoteFontFamily, + generateUseStatement, + generatePaletteCode, + generateTypographyCode, + generateElevationsCode, + toVariableName, + generateHeader, +} from '../utils/sass.js'; +export type { + PaletteCodeOptions, + PaletteCodeResult, + TypographyCodeOptions, + ElevationsCodeOptions, +} from '../utils/sass.js'; + +/** + * Generate a palette definition. + */ +export function generatePalette(input: CreatePaletteInput): GeneratedCode { + const variant = input.variant ?? 'light'; + const name = input.name ? toVariableName(input.name) : `custom-${variant}`; + const varName = `$${name}-palette`; + + // Primary, secondary, and surface are required by the Sass palette() function + const paletteArgs: string[] = [ + `$primary: ${input.primary}`, + `$secondary: ${input.secondary}`, + `$surface: ${input.surface}`, + ]; + + // Optional colors + if (input.gray) paletteArgs.push(`$gray: ${input.gray}`); + if (input.info) paletteArgs.push(`$info: ${input.info}`); + if (input.success) paletteArgs.push(`$success: ${input.success}`); + if (input.warn) paletteArgs.push(`$warn: ${input.warn}`); + if (input.error) paletteArgs.push(`$error: ${input.error}`); + + const code = `${generateHeader(`${variant} palette with primary color ${input.primary}`)} +${generateUseStatement(input.platform)} + +// Custom ${variant} palette +${varName}: palette( + ${paletteArgs.join(',\n ')} +); + +// Apply the palette (generates CSS custom properties) +@include palette(${varName}); +`; + + return { + code, + description: `Generated a ${variant} color palette with primary color ${input.primary}`, + variables: [varName], + }; +} + +/** + * Generate typography setup. + */ +export function generateTypography(input: CreateTypographyInput): GeneratedCode { + const designSystem: DesignSystem = input.designSystem ?? 'material'; + const typeScaleVar = `$${designSystem}-type-scale`; + + // Get the typeface from preset + const preset = TYPOGRAPHY_PRESETS[designSystem]; + const typeface = input.fontFamily || preset.typeface; + + const code = `${generateHeader(`Typography setup using ${designSystem} type scale`)} +${generateUseStatement(input.platform)} + +// Typography setup with ${designSystem} type scale +@include typography( + $font-family: ${quoteFontFamily(typeface)}, + $type-scale: ${typeScaleVar} +); +`; + + return { + code, + description: `Generated typography setup using ${designSystem} design system with font family ${typeface}`, + variables: [typeScaleVar], + }; +} + +/** + * Generate elevations setup. + */ +export function generateElevations(input: CreateElevationsInput): GeneratedCode { + const preset = input.designSystem ?? 'material'; + const elevationsVar = `$${preset}-elevations`; + + const code = `${generateHeader(`Elevations setup using ${preset} preset`)} +${generateUseStatement(input.platform)} + +// Elevations setup with ${preset} shadows +@include elevations(${elevationsVar}); +`; + + return { + code, + description: `Generated elevations setup using ${preset} preset (25 elevation levels)`, + variables: [elevationsVar], + }; +} + +/** + * Generate a complete theme (palette + typography + elevations). + * + * Supports two platforms: + * - `angular`: Uses `igniteui-angular/theming` with `core()` and `theme()` mixins + * - `webcomponents`: Uses `igniteui-theming` directly with individual mixins + * + * If no platform is specified, defaults to generating platform-agnostic code + * using igniteui-theming directly (similar to webcomponents but simpler). + */ +export function generateTheme(input: CreateThemeInput): GeneratedCode { + const platform = input.platform; + const designSystem: DesignSystem = input.designSystem ?? 'material'; + const variant = input.variant ?? 'light'; + + // Use platform-specific generators if platform is specified + switch (platform) { + case 'angular': + return generateAngularTheme(input, designSystem, variant); + case 'webcomponents': + case 'react': + case 'blazor': + return generateWebComponentsTheme(input, designSystem, variant); + default: + return generateGenericTheme(input, designSystem, variant); + } +} + +/** + * Generate Angular-specific theme using core() and theme() mixins. + */ +function generateAngularTheme( + input: CreateThemeInput, + designSystem: DesignSystem, + variant: ThemeVariant +): GeneratedCode { + const code = generateAngularThemeSass({ + designSystem, + variant, + primaryColor: input.primaryColor, + secondaryColor: input.secondaryColor, + surfaceColor: input.surfaceColor, + customPaletteName: input.name ? `$${toVariableName(input.name)}-palette` : undefined, + fontFamily: input.fontFamily, + includeTypography: input.includeTypography !== false, + }); + + const variables: string[] = []; + if (input.name) { + variables.push(`$${toVariableName(input.name)}-palette`); + } + variables.push(`$${variant}-${designSystem}-schema`); + if (input.includeTypography !== false) { + // If custom font family provided, we're not using the preset variable + if (!input.fontFamily) { + variables.push(`$${designSystem}-typeface`); + } + variables.push(`$${designSystem}-type-scale`); + } + + return { + code, + description: `Generated Angular ${variant} theme based on ${designSystem} design system`, + variables, + }; +} + +/** + * Generate Web Components-specific theme using individual mixins. + */ +function generateWebComponentsTheme( + input: CreateThemeInput, + designSystem: DesignSystem, + variant: ThemeVariant +): GeneratedCode { + const code = generateWebComponentsThemeSass({ + designSystem, + variant, + primaryColor: input.primaryColor, + secondaryColor: input.secondaryColor, + surfaceColor: input.surfaceColor, + customPaletteName: input.name ? `$${toVariableName(input.name)}-palette` : undefined, + fontFamily: input.fontFamily, + includeTypography: input.includeTypography !== false, + includeElevations: input.includeElevations !== false, + includeSpacing: input.includeSpacing !== false, + }); + + const variables: string[] = []; + if (input.name) { + variables.push(`$${toVariableName(input.name)}-palette`); + } else { + variables.push('$palette'); + } + if (input.includeTypography !== false) { + // If custom font family provided, we're not using the preset $typeface variable + if (!input.fontFamily) { + variables.push('$typeface'); + } + variables.push('$type-scale'); + } + if (input.includeElevations !== false) { + variables.push(designSystem === 'indigo' ? '$indigo-elevations' : '$material-elevations'); + } + + return { + code, + description: `Generated Web Components ${variant} theme based on ${designSystem} design system`, + variables, + }; +} + +/** + * Generate platform-agnostic theme (legacy behavior). + * Uses igniteui-theming directly without platform-specific optimizations. + */ +function generateGenericTheme( + input: CreateThemeInput, + designSystem: DesignSystem, + variant: ThemeVariant +): GeneratedCode { + const themeName = input.name ? toVariableName(input.name) : `${variant}-${designSystem}`; + const paletteVar = `$${themeName}-palette`; + const includeTypography = input.includeTypography !== false; + const includeElevations = input.includeElevations !== false; + + const variables: string[] = [paletteVar]; + + // Build palette arguments + const paletteArgs: string[] = [`$primary: ${input.primaryColor}`]; + if (input.secondaryColor) paletteArgs.push(`$secondary: ${input.secondaryColor}`); + if (input.surfaceColor) { + paletteArgs.push(`$surface: ${input.surfaceColor}`); + } else { + paletteArgs.push(`$surface: ${variant === 'dark' ? '#222222' : 'white'}`); + } + + // Build the code sections + const sections: string[] = [ + generateHeader(`Complete ${variant} theme based on ${designSystem} design system`), + '// NOTE: Specify platform ("angular" or "webcomponents") for optimized output', + generateUseStatement(), + '', + `// ${themeName} palette`, + `${paletteVar}: palette(`, + ` ${paletteArgs.join(',\n ')}`, + ');', + '', + '// Apply the palette', + `@include palette(${paletteVar});`, + ]; + + if (includeTypography) { + const preset = TYPOGRAPHY_PRESETS[designSystem]; + const typeface = input.fontFamily || preset.typeface; + const typeScaleVar = `$${designSystem}-type-scale`; + variables.push(typeScaleVar); + + sections.push( + '', + '// Typography setup', + '@include typography(', + ` $font-family: ${quoteFontFamily(typeface)},`, + ` $type-scale: ${typeScaleVar}`, + ');', + ); + } + + if (includeElevations) { + // Use material elevations for material/bootstrap, indigo for indigo/fluent + const elevationPreset = designSystem === 'indigo' ? 'indigo' : 'material'; + const elevationsVar = `$${elevationPreset}-elevations`; + variables.push(elevationsVar); + + sections.push('', '// Elevations setup', `@include elevations(${elevationsVar});`); + } + + const code = sections.join('\n') + '\n'; + + return { + code, + description: `Generated complete ${variant} theme based on ${designSystem} design system (platform-agnostic)`, + variables, + }; +} diff --git a/src/mcp/index.ts b/src/mcp/index.ts new file mode 100644 index 00000000..8c9a1e4e --- /dev/null +++ b/src/mcp/index.ts @@ -0,0 +1,239 @@ +#!/usr/bin/env node +/** + * Ignite UI Theming MCP Server + * + * A Model Context Protocol server for generating Ignite UI theming code. + * Provides tools for creating palettes, typography, elevations, and complete themes. + */ + +import {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js'; +import {StdioServerTransport} from '@modelcontextprotocol/sdk/server/stdio.js'; + +import { + detectPlatformSchema, + createPaletteSchema, + createCustomPaletteSchema, + createTypographySchema, + createElevationsSchema, + createThemeSchema, + handleDetectPlatform, + handleCreatePalette, + handleCreateCustomPalette, + handleCreateTypography, + handleCreateElevations, + handleCreateTheme, +} from './tools/index.js'; +import {TOOL_DESCRIPTIONS} from './tools/descriptions.js'; + +import {RESOURCE_DEFINITIONS, getResourceContent} from './resources/index.js'; + +/** + * Create and configure the MCP server. + */ +function createServer(): McpServer { + const server = new McpServer({ + name: 'igniteui-theming', + version: '1.0.0', + }); + + // Register tools + registerTools(server); + + // Register resources + registerResources(server); + + return server; +} + +/** + * Register all theming tools. + */ +function registerTools(server: McpServer): void { + // detect_platform tool + server.registerTool( + 'detect_platform', + { + title: 'Detect Target Platform', + description: TOOL_DESCRIPTIONS.detect_platform, + inputSchema: { + packageJsonPath: detectPlatformSchema.shape.packageJsonPath, + }, + }, + async (params) => { + const validated = detectPlatformSchema.parse(params); + return handleDetectPlatform(validated); + }, + ); + + // create_palette tool + server.registerTool( + 'create_palette', + { + title: 'Create Color Palette', + description: TOOL_DESCRIPTIONS.create_palette, + inputSchema: { + platform: createPaletteSchema.shape.platform, + primary: createPaletteSchema.shape.primary, + secondary: createPaletteSchema.shape.secondary, + surface: createPaletteSchema.shape.surface, + gray: createPaletteSchema.shape.gray, + info: createPaletteSchema.shape.info, + success: createPaletteSchema.shape.success, + warn: createPaletteSchema.shape.warn, + error: createPaletteSchema.shape.error, + variant: createPaletteSchema.shape.variant, + name: createPaletteSchema.shape.name, + }, + }, + async (params) => { + const validated = createPaletteSchema.parse(params); + return await handleCreatePalette(validated); + }, + ); + + // create_custom_palette tool + server.registerTool( + 'create_custom_palette', + { + title: 'Create Custom Handmade Palette', + description: TOOL_DESCRIPTIONS.create_custom_palette, + inputSchema: { + platform: createCustomPaletteSchema.shape.platform, + variant: createCustomPaletteSchema.shape.variant, + designSystem: createCustomPaletteSchema.shape.designSystem, + name: createCustomPaletteSchema.shape.name, + primary: createCustomPaletteSchema.shape.primary, + secondary: createCustomPaletteSchema.shape.secondary, + surface: createCustomPaletteSchema.shape.surface, + gray: createCustomPaletteSchema.shape.gray, + info: createCustomPaletteSchema.shape.info, + success: createCustomPaletteSchema.shape.success, + warn: createCustomPaletteSchema.shape.warn, + error: createCustomPaletteSchema.shape.error, + }, + }, + async (params) => { + const validated = createCustomPaletteSchema.parse(params); + return await handleCreateCustomPalette(validated); + }, + ); + + // create_typography tool + server.registerTool( + 'create_typography', + { + title: 'Create Typography', + description: TOOL_DESCRIPTIONS.create_typography, + inputSchema: { + platform: createTypographySchema.shape.platform, + fontFamily: createTypographySchema.shape.fontFamily, + designSystem: createTypographySchema.shape.designSystem, + name: createTypographySchema.shape.name, + }, + }, + async (params) => { + const validated = createTypographySchema.parse(params); + return handleCreateTypography(validated); + }, + ); + + // create_elevations tool + server.registerTool( + 'create_elevations', + { + title: 'Create Elevations', + description: TOOL_DESCRIPTIONS.create_elevations, + inputSchema: { + platform: createElevationsSchema.shape.platform, + designSystem: createElevationsSchema.shape.designSystem, + name: createElevationsSchema.shape.name, + }, + }, + async (params) => { + const validated = createElevationsSchema.parse(params); + return handleCreateElevations(validated); + }, + ); + + // create_theme tool + server.registerTool( + 'create_theme', + { + title: 'Create Complete Theme', + description: TOOL_DESCRIPTIONS.create_theme, + inputSchema: { + platform: createThemeSchema.shape.platform, + designSystem: createThemeSchema.shape.designSystem, + primaryColor: createThemeSchema.shape.primaryColor, + secondaryColor: createThemeSchema.shape.secondaryColor, + surfaceColor: createThemeSchema.shape.surfaceColor, + variant: createThemeSchema.shape.variant, + name: createThemeSchema.shape.name, + fontFamily: createThemeSchema.shape.fontFamily, + includeTypography: createThemeSchema.shape.includeTypography, + includeElevations: createThemeSchema.shape.includeElevations, + includeSpacing: createThemeSchema.shape.includeSpacing, + }, + }, + async (params) => { + const validated = createThemeSchema.parse(params); + return await handleCreateTheme(validated); + }, + ); +} + +/** + * Register all theming resources. + */ +function registerResources(server: McpServer): void { + for (const resource of RESOURCE_DEFINITIONS) { + server.registerResource( + resource.name.toLowerCase().replace(/\s+/g, '-'), + resource.uri, + { + title: resource.name, + description: resource.description, + mimeType: resource.mimeType, + }, + async (uri) => { + const content = getResourceContent(uri.href); + if (!content) { + throw new Error(`Resource not found: ${uri.href}`); + } + return { + contents: [ + { + uri: uri.href, + mimeType: content.mimeType, + text: content.content, + }, + ], + }; + }, + ); + } +} + +/** + * Main entry point - start the MCP server with STDIO transport. + */ +async function main(): Promise { + const server = createServer(); + const transport = new StdioServerTransport(); + + await server.connect(transport); + + // Handle graceful shutdown + const shutdown = async () => { + await server.close(); + process.exit(0); + }; + process.on('SIGINT', shutdown); + process.on('SIGTERM', shutdown); +} + +// Run the server +main().catch((error) => { + console.error('Failed to start MCP server:', error); + process.exit(1); +}); diff --git a/src/mcp/knowledge/color-usage.ts b/src/mcp/knowledge/color-usage.ts new file mode 100644 index 00000000..79dc78ee --- /dev/null +++ b/src/mcp/knowledge/color-usage.ts @@ -0,0 +1,711 @@ +/** + * Color usage documentation and semantic roles. + * Describes how colors are used across Ignite UI components. + */ + +import type { ShadeLevel } from './multipliers.js'; + +/** + * Shade range description. + */ +export interface ShadeRange { + /** Shade levels included in this range */ + shades: ShadeLevel[]; + /** Description of what this range is used for */ + purpose: string; + /** Example use cases */ + examples: string[]; +} + +/** + * Color family semantic role definition. + */ +export interface ColorSemanticRole { + /** Brief role description */ + role: string; + /** Detailed description of the color's purpose */ + description: string; + /** General usage patterns */ + usage: string[]; + /** Components that commonly use this color */ + components: string[]; + /** Shade-specific guidance */ + shadeGuidance: ShadeRange[]; +} + +/** + * Semantic roles for each color family. + * Derived from analysis of component schemas across Material, Fluent, Bootstrap, and Indigo themes. + */ +export const COLOR_SEMANTIC_ROLES: Record = { + primary: { + role: 'Brand identity and primary actions', + description: + 'The primary color represents your brand and is the most prominent color in your UI. It draws attention to key interactive elements and indicates the primary action a user can take.', + usage: [ + 'Primary action buttons (contained/filled style)', + 'Links and navigation highlights', + 'Active/selected states (tabs, list items, tree nodes)', + 'Form controls when checked/selected (checkbox, radio, switch)', + 'Progress indicators and sliders', + 'Focus rings and outlines', + 'Calendar date selection', + 'Grid row selection and highlights', + ], + components: [ + 'button', + 'checkbox', + 'radio', + 'switch', + 'slider', + 'tabs', + 'progress', + 'calendar', + 'grid', + 'tree', + 'list', + 'nav-drawer', + 'stepper', + ], + shadeGuidance: [ + { + shades: ['50', '100'], + purpose: 'Subtle backgrounds and disabled states', + examples: ['Focus backgrounds', 'Disabled button fills', 'Very light tints for hover'], + }, + { + shades: ['200', '300'], + purpose: 'Focus outlines, selection backgrounds with opacity', + examples: [ + 'Focus ring color (often with 0.5 opacity)', + 'Selected item backgrounds in Indigo theme (300 with 0.3 opacity)', + 'Light hover states', + ], + }, + { + shades: ['400'], + purpose: 'Intermediate states and secondary emphasis', + examples: ['Hover states in some themes', 'Border colors', 'Secondary interactive elements'], + }, + { + shades: ['500'], + purpose: 'Default/main usage - THE primary color', + examples: [ + 'Button backgrounds', + 'Link text color', + 'Checkbox/radio fill when checked', + 'Tab indicators', + 'Progress bar fill', + ], + }, + { + shades: ['600', '700'], + purpose: 'Hover and active states', + examples: ['Button hover background (Bootstrap)', 'Active/pressed states', 'Stronger emphasis'], + }, + { + shades: ['800', '900'], + purpose: 'Dark mode adaptations and maximum emphasis', + examples: ['Active text in dark contexts', 'Selected backgrounds in dark mode', 'High contrast needs'], + }, + ], + }, + + secondary: { + role: 'Accent color and secondary emphasis', + description: + 'The secondary color provides accent and emphasis for elements that need to stand out but are not the primary action. Most prominent in Material Design themes.', + usage: [ + 'Flat and outlined button text (Material)', + 'List and dropdown headers', + 'Selected item backgrounds (alternative to primary)', + 'Accent highlights and decorative elements', + 'Secondary action buttons', + ], + components: ['button', 'list', 'drop-down', 'tree', 'grid', 'radio', 'checkbox'], + shadeGuidance: [ + { + shades: ['100', '200'], + purpose: 'Selected backgrounds and light accents', + examples: ['Selected row backgrounds', 'Light accent fills', 'Hover backgrounds'], + }, + { + shades: ['300'], + purpose: 'Hover states in dark mode', + examples: ['Dark mode hover backgrounds', 'Medium accent'], + }, + { + shades: ['500'], + purpose: 'Default accent color', + examples: ['Accent text', 'Secondary action color', 'Header text'], + }, + { + shades: ['600', '700'], + purpose: 'Stronger accents and header text', + examples: ['Header text (Fluent)', 'Strong accent color', 'Hover states'], + }, + ], + }, + + gray: { + role: 'Neutral UI foundation - text, borders, and backgrounds', + description: + 'Gray is the most extensively used color family, providing the foundation for text hierarchy, borders, backgrounds, and disabled states. It creates visual structure without competing with brand colors.', + usage: [ + 'Text at all hierarchy levels (primary, secondary, disabled)', + 'Borders and dividers', + 'Backgrounds (hover, selected, disabled)', + 'Icons and decorative elements', + 'Placeholder text', + 'Disabled state indicators', + 'Tooltips and overlays', + ], + components: [ + 'All components use gray', + 'input-group', + 'card', + 'list', + 'expansion-panel', + 'grid', + 'drop-down', + 'tooltip', + 'dialog', + ], + shadeGuidance: [ + { + shades: ['50'], + purpose: 'Lightest backgrounds (becomes dark in dark mode)', + examples: ['Dark mode backgrounds', 'Group areas', 'Prefix/suffix backgrounds in inputs'], + }, + { + shades: ['100'], + purpose: 'Hover and focus backgrounds', + examples: ['Item hover backgrounds', 'Focus backgrounds', 'Light borders', 'Card outlines in dark mode'], + }, + { + shades: ['200'], + purpose: 'Selected backgrounds and borders', + examples: ['Selected item backgrounds (Fluent)', 'Hover backgrounds', 'Row borders', 'Default borders'], + }, + { + shades: ['300'], + purpose: 'Borders and light disabled states', + examples: ['Border colors', 'Disabled borders', 'Dividers', 'Light disabled fills'], + }, + { + shades: ['400'], + purpose: 'Disabled text/borders and placeholders', + examples: ['Disabled text color', 'Placeholder text', 'Empty state icons', 'Secondary borders'], + }, + { + shades: ['500'], + purpose: 'Secondary text and icons', + examples: ['Disabled text', 'Secondary text', 'Icon colors', 'Border colors'], + }, + { + shades: ['600'], + purpose: 'Secondary text and labels', + examples: ['Header text (Indigo)', 'Secondary text', 'Label text', 'Icon colors'], + }, + { + shades: ['700'], + purpose: 'Descriptions and tooltips', + examples: ['Description text', 'Tooltip backgrounds', 'Subtitle text', 'Icon colors'], + }, + { + shades: ['800'], + purpose: 'Primary text and strong emphasis', + examples: ['Primary text', 'Titles', 'Strong text', 'Icon colors'], + }, + { + shades: ['900'], + purpose: 'Maximum contrast text', + examples: ['Highest contrast text', 'Main headings', 'Maximum emphasis content'], + }, + ], + }, + + surface: { + role: 'Component background foundation', + description: + 'The surface color is the base background color for components. It defines the "canvas" on which UI elements are painted. In light themes, surface is typically white; in dark themes, it\'s a dark gray.', + usage: [ + 'Card backgrounds', + 'Dialog backgrounds', + 'Input field backgrounds', + 'List backgrounds', + 'Dropdown menu backgrounds', + 'Navigation drawer backgrounds', + 'Panel and expansion panel backgrounds', + ], + components: [ + 'card', + 'dialog', + 'input-group', + 'list', + 'drop-down', + 'nav-drawer', + 'expansion-panel', + 'calendar', + 'grid', + 'tree', + ], + shadeGuidance: [ + { + shades: ['500'], + purpose: 'Default surface - typically the only shade used', + examples: [ + 'Component backgrounds', + 'Base layer for contrast calculations', + 'Light theme: white or near-white', + 'Dark theme: dark gray (#222, #1a1a1a)', + ], + }, + ], + }, + + error: { + role: 'Validation errors and destructive actions', + description: + 'The error color communicates problems, validation failures, and destructive actions. It should be used sparingly to maintain its impact and urgency.', + usage: [ + 'Form validation error borders and text', + 'Error messages and icons', + 'Invalid state indicators (checkbox, radio)', + 'Destructive action buttons', + 'Progress bar error state', + 'Stepper invalid step indicator', + ], + components: ['input-group', 'checkbox', 'radio', 'stepper', 'progress', 'button'], + shadeGuidance: [ + { + shades: ['200'], + purpose: 'Focus outlines with opacity', + examples: ['Error focus rings (Bootstrap)', 'Light error backgrounds'], + }, + { + shades: ['400'], + purpose: 'Focus outlines and hover states', + examples: ['Error focus outlines (Indigo)', 'Error hover states'], + }, + { + shades: ['500'], + purpose: 'Default error color', + examples: ['Error borders', 'Error text', 'Error icons', 'Invalid state fills'], + }, + { + shades: ['600', '700'], + purpose: 'Hover and active states', + examples: ['Error button hover (Bootstrap/Fluent)', 'Stronger error emphasis'], + }, + { + shades: ['800'], + purpose: 'Material theme error states', + examples: ['Material Design error color', 'Dark error emphasis'], + }, + ], + }, + + success: { + role: 'Positive feedback and completion', + description: + 'The success color indicates successful operations, completed states, and positive feedback. Use it to confirm that actions have been completed successfully.', + usage: [ + 'Success messages and notifications', + 'Completed step indicators', + 'Progress completion state', + 'Positive validation feedback', + 'Success action buttons', + ], + components: ['progress', 'stepper', 'snackbar', 'button'], + shadeGuidance: [ + { + shades: ['500'], + purpose: 'Default success color', + examples: ['Success indicators', 'Completed state fills', 'Success text and icons'], + }, + ], + }, + + warn: { + role: 'Warnings and cautionary states', + description: + 'The warn color alerts users to potential issues or asks for caution. It\'s less severe than error but still requires attention.', + usage: [ + 'Warning messages and notifications', + 'Caution indicators', + 'Progress warning state', + 'Stepper warning indicator', + ], + components: ['progress', 'stepper', 'snackbar'], + shadeGuidance: [ + { + shades: ['500'], + purpose: 'Default warning color', + examples: ['Warning indicators', 'Caution state fills', 'Warning text and icons'], + }, + ], + }, + + info: { + role: 'Informational states', + description: + 'The info color provides neutral informational feedback. It\'s less prominent than primary but indicates helpful information.', + usage: ['Informational messages', 'Info progress state', 'Helper text and tooltips'], + components: ['progress', 'snackbar'], + shadeGuidance: [ + { + shades: ['500'], + purpose: 'Default info color', + examples: ['Info indicators', 'Informational state fills', 'Info icons'], + }, + ], + }, +}; + +/** + * Common opacity values and their purposes. + */ +export const OPACITY_USAGE = { + '0.05-0.1': 'Very subtle hover overlays, light backgrounds', + '0.12-0.15': 'Subtle active states, disabled backgrounds', + '0.2': 'Disabled text/elements', + '0.3': 'Selected backgrounds (Indigo theme), medium overlays', + '0.38': 'Material Design disabled opacity (standard)', + '0.5': 'Focus outlines, semi-transparent overlays', + '0.6': 'Border colors, secondary elements', + '0.8': 'Strong overlays, near-opaque states', + '0.9': 'Tooltip backgrounds, near-solid overlays', +} as const; + +/** + * State progression patterns showing how colors change across interaction states. + */ +export const STATE_PATTERNS = { + button: { + description: 'Button state progression', + states: { + idle: 'primary-500 background', + hover: 'primary-600 or primary-500 with overlay', + focus: 'primary-500 with focus ring (primary-200 or 300)', + active: 'primary-700 or darker', + disabled: 'gray-300 background, gray-500 text', + }, + }, + listItem: { + description: 'List item state progression', + states: { + idle: 'surface background, gray-800 text', + hover: 'gray-100 or 200 background', + focus: 'gray-100 background with focus outline', + selected: 'primary-100 or 200 background (or primary-300 with opacity)', + disabled: 'gray-400 text, no interaction', + }, + }, + input: { + description: 'Input field state progression', + states: { + idle: 'surface background, gray-300 or 400 border', + hover: 'gray-400 or 500 border', + focus: 'primary-500 border, focus ring', + filled: 'gray-800 text', + error: 'error-500 border and text', + disabled: 'gray-100 background, gray-400 text', + }, + }, +} as const; + +/** + * Design system specific patterns. + */ +export const THEME_PATTERNS = { + material: { + name: 'Material Design', + characteristics: [ + 'Uses secondary color prominently for accents', + 'Ripple effects on interaction', + 'Shade 500 as baseline', + 'Elevation through shadows', + 'A100-A700 accent shades for selection', + ], + }, + fluent: { + name: 'Fluent Design', + characteristics: [ + 'More gray-based, subtle interactions', + 'Hover states use 100-200 shades', + 'Border-focused component styling', + 'Less saturated colors overall', + ], + }, + bootstrap: { + name: 'Bootstrap', + characteristics: [ + 'Uses primary color for most accents', + 'Shade 600 commonly used for hover', + 'Strong border patterns', + 'More traditional web styling', + ], + }, + indigo: { + name: 'Indigo Design', + characteristics: [ + 'Transparent backgrounds with opacity', + 'Primary 300 with 0.3 opacity for selections', + 'Strong emphasis on gray scale', + 'Clean, modern aesthetic', + 'Subtle interactive states', + ], + }, +} as const; + +/** + * Full markdown documentation for color usage. + * This is the comprehensive guide for AI models to understand color semantics. + */ +export const COLOR_USAGE_MARKDOWN = `# Ignite UI Color Usage Guide + +## Overview + +The Ignite UI theming system uses **8 color families**, each with **10 shade levels** (50-900). Understanding how these colors interact with components helps you create cohesive, accessible themes. + +## Color Families + +### Primary Color +**Role:** Brand identity and primary actions + +The primary color is your brand's signature color. It draws attention to the most important interactive elements. + +**Used For:** +- Primary action buttons (filled/contained style) +- Links and navigation highlights +- Active/selected states (tabs, list items, checkboxes, radios, switches) +- Progress indicators and sliders +- Focus rings and outlines +- Calendar date selection +- Grid row selection + +**Shade Usage:** +| Shades | Purpose | Examples | +|--------|---------|----------| +| 50-100 | Subtle backgrounds, disabled | Focus backgrounds, disabled button fills | +| 200-300 | Focus outlines, selections with opacity | Focus rings, selected backgrounds (Indigo) | +| **500** | **Default/main color** | Button backgrounds, link text, checkbox fills | +| 600-700 | Hover and active states | Button hover, pressed states | +| 800-900 | Dark mode, maximum emphasis | Dark theme selections | + +--- + +### Secondary Color +**Role:** Accent and secondary emphasis + +Most prominent in Material Design. Provides accent without competing with primary. + +**Used For:** +- Flat/outlined button text (Material) +- List and dropdown headers +- Alternative selection backgrounds +- Secondary action buttons + +**Shade Usage:** +| Shades | Purpose | +|--------|---------| +| 100-200 | Selected backgrounds, light accents | +| **500** | Default accent | +| 600-700 | Headers (Fluent), strong accents | + +--- + +### Gray Color +**Role:** Neutral UI foundation + +The most used color family. Creates text hierarchy, borders, and backgrounds. + +**Used For:** +- All text (primary, secondary, disabled, placeholder) +- Borders and dividers +- Backgrounds (hover, selected, disabled) +- Icons +- Tooltips + +**Shade Usage:** +| Shade | Purpose | Examples | +|-------|---------|----------| +| 50 | Lightest backgrounds | Dark mode bg, group areas | +| 100 | Hover/focus backgrounds | Item hover, light borders | +| 200 | Selected backgrounds, borders | Selected items (Fluent), borders | +| 300 | Borders, dividers | Default borders, dividers | +| 400 | Disabled elements, placeholders | Disabled text, placeholder | +| 500 | Secondary text, icons | Disabled text, secondary content | +| 600 | Labels, secondary text | Header text (Indigo), labels | +| 700 | Descriptions, tooltips | Tooltip bg, descriptions | +| 800 | Primary text | Main text, titles | +| **900** | **Maximum contrast text** | Headings, emphasis | + +--- + +### Surface Color +**Role:** Component background foundation + +The "canvas" color. Typically white (light) or dark gray (dark themes). + +**Used For:** +- Card, dialog, dropdown backgrounds +- Input field backgrounds +- List and panel backgrounds +- Navigation backgrounds + +**Note:** Usually only shade 500 is used. The surface determines whether gray shades appear light or dark. + +--- + +### Error Color +**Role:** Validation errors and destructive actions + +Communicates problems. Use sparingly for maximum impact. + +**Used For:** +- Form validation errors (borders, text) +- Invalid state indicators +- Destructive action buttons +- Error progress state + +**Shade Usage:** +| Shades | Purpose | +|--------|---------| +| 200-400 | Focus rings, light errors | +| **500** | Default error | +| 600-800 | Hover states, Material errors | + +--- + +### Success, Warn, Info Colors +**Role:** Feedback states + +| Color | Purpose | +|-------|---------| +| **Success** | Completion, positive feedback | +| **Warn** | Caution, potential issues | +| **Info** | Neutral information | + +These primarily use shade **500** for their default state. + +--- + +## Interaction State Patterns + +### Button States +\`\`\` +idle → primary-500 background +hover → primary-600 (or 500 + overlay) +focus → primary-500 + focus ring (200-300) +active → primary-700 +disabled → gray-300 bg, gray-500 text +\`\`\` + +### List Item States +\`\`\` +idle → surface bg, gray-800 text +hover → gray-100 or 200 bg +focus → gray-100 bg + outline +selected → primary-100/200 bg (or 300 @ 0.3 opacity) +disabled → gray-400 text +\`\`\` + +### Input States +\`\`\` +idle → surface bg, gray-300/400 border +hover → gray-400/500 border +focus → primary-500 border + ring +error → error-500 border/text +disabled → gray-100 bg, gray-400 text +\`\`\` + +--- + +## Opacity Usage + +Opacity modifiers adjust color intensity while maintaining relationships: + +| Opacity | Use Case | +|---------|----------| +| 0.05-0.1 | Subtle hover overlays | +| 0.12-0.15 | Active states, disabled bg | +| 0.2 | Disabled elements | +| 0.3 | Selected backgrounds (Indigo) | +| **0.38** | Material disabled (standard) | +| 0.5 | Focus outlines | +| 0.8-0.9 | Strong overlays, tooltips | + +--- + +## Contrast Colors + +Always use \`contrast-color\` for text on colored backgrounds: + +\`\`\`scss +// Text on primary button +color: contrast-color('primary', 500); + +// Text with opacity +color: contrast-color('gray', 50, 0.8); +\`\`\` + +--- + +## Theme Variations + +### Material Design +- Secondary color for accents +- Ripple effects +- A100-A700 accent shades +- Elevation through shadows + +### Fluent Design +- Gray-based, subtle +- 100-200 for hovers +- Border-focused styling + +### Bootstrap +- Primary for accents +- 600 for hover states +- Strong borders + +### Indigo Design +- Transparent backgrounds +- Primary 300 @ 0.3 opacity for selections +- Clean, modern aesthetic + +--- + +## Dark Mode Guidelines + +IMPORTANT: Chromatic color shades (primary, secondary, etc.) are NEVER inverted. +The shade order is always 50=lightest, 900=darkest regardless of theme variant. +Only GRAY inverts its shade progression for dark themes. + +1. **Gray shades invert**: Lower numbers become darker (50=darkest in dark mode) +2. **Use lighter primary shades**: In dark mode UI, reference lighter shades (100-300) + instead of darker ones (500-700) for better visibility. The palette itself is NOT + inverted - you just USE different shades from the same palette. +3. **Surface becomes dark**: #222, #1a1a1a, etc. +4. **Contrast still works**: \`contrast-color\` adapts automatically + +--- + +## Quick Reference + +| Need | Color | Shade | +|------|-------|-------| +| Primary button bg | primary | 500 | +| Link text | primary | 500 | +| Main body text | gray | 800-900 | +| Secondary text | gray | 600-700 | +| Disabled text | gray | 400-500 | +| Component bg | surface | 500 | +| Hover bg | gray | 100-200 | +| Border | gray | 200-400 | +| Error state | error | 500 | +| Success state | success | 500 | +| Focus ring | primary | 200-300 | +`; diff --git a/src/mcp/knowledge/colors.ts b/src/mcp/knowledge/colors.ts new file mode 100644 index 00000000..0d563461 --- /dev/null +++ b/src/mcp/knowledge/colors.ts @@ -0,0 +1,148 @@ +/** + * Color rules and guidance documentation for AI context. + * This knowledge helps AI models understand the relationship between + * theme variants and color choices. + */ + +import { LUMINANCE_THRESHOLD, SUGGESTED_COLORS, DEFAULT_MINIMUM_CONTRAST_RATIO } from '../utils/color.js'; + +/** + * Color variant rules for surface and gray colors. + */ +export const COLOR_VARIANT_RULES = { + light: { + description: 'Light theme variant with light backgrounds and dark text', + surface: { + requirement: 'light', + luminanceRule: `luminance > ${LUMINANCE_THRESHOLD}`, + explanation: 'Light themes use bright backgrounds (white, off-white, light gray)', + examples: SUGGESTED_COLORS.light.surface, + }, + gray: { + requirement: 'dark', + luminanceRule: `luminance <= ${LUMINANCE_THRESHOLD}`, + explanation: + 'Gray base should be dark so the generated gray shades contrast well against light surfaces', + examples: SUGGESTED_COLORS.light.gray, + }, + }, + dark: { + description: 'Dark theme variant with dark backgrounds and light text', + surface: { + requirement: 'dark', + luminanceRule: `luminance <= ${LUMINANCE_THRESHOLD}`, + explanation: 'Dark themes use dark backgrounds (near-black, dark gray)', + examples: SUGGESTED_COLORS.dark.surface, + }, + gray: { + requirement: 'light', + luminanceRule: `luminance > ${LUMINANCE_THRESHOLD}`, + explanation: + 'Gray base should be light so the generated gray shades contrast well against dark surfaces', + examples: SUGGESTED_COLORS.dark.gray, + }, + }, +} as const; + +/** + * Full documentation about color rules in markdown format. + * This is intended to be provided as context to AI models. + */ +export const COLOR_GUIDANCE_MARKDOWN = `# Ignite UI Theming - Color Guidance + +## Understanding Theme Variants + +Ignite UI themes support two variants: **light** and **dark**. The variant affects how colors are chosen and how the palette generates shades. + +## Surface Color Rules + +The **surface** color is the main background color used throughout your application. + +| Variant | Surface Requirement | Luminance | Examples | +|---------|---------------------|-----------|----------| +| light | Light color | > ${LUMINANCE_THRESHOLD} | ${SUGGESTED_COLORS.light.surface.join(', ')} | +| dark | Dark color | ≤ ${LUMINANCE_THRESHOLD} | ${SUGGESTED_COLORS.dark.surface.join(', ')} | + +## Gray Color Rules + +The **gray** parameter sets the base color used to generate the grayscale palette. This is INVERTED from the surface because the grayscale shades need to contrast against the surface. + +| Variant | Gray Base Requirement | Luminance | Examples | +|---------|----------------------|-----------|----------| +| light | Dark color | ≤ ${LUMINANCE_THRESHOLD} | ${SUGGESTED_COLORS.light.gray.join(', ')} | +| dark | Light color | > ${LUMINANCE_THRESHOLD} | ${SUGGESTED_COLORS.dark.gray.join(', ')} | + +### Why is Gray Inverted? + +The \`palette()\` function generates grayscale shades that are used for text, borders, and UI elements. These shades need to be readable against the surface: + +- **Light theme**: Light surface needs dark gray shades for readable text → use dark gray base +- **Dark theme**: Dark surface needs light gray shades for readable text → use light gray base + +## Luminance Calculation + +Luminance is calculated using the WCAG 2.0 formula: +- 0 = pure black +- 1 = pure white +- ${LUMINANCE_THRESHOLD} = threshold between "light" and "dark" colors + +## Contrast Ratio + +When both surface and gray are provided, the system checks their contrast ratio. A minimum of ${DEFAULT_MINIMUM_CONTRAST_RATIO}:1 is recommended for good readability. + +## Best Practices + +1. **Let the system auto-calculate gray**: If you're unsure, omit the \`gray\` parameter. The palette() function will automatically derive an appropriate gray base from the surface color. + +2. **Match surface to variant**: Always use a light surface for light themes and a dark surface for dark themes. + +3. **Test contrast**: Ensure your color combinations meet accessibility standards (WCAG 2.0). + +## Common Mistakes + +❌ **Light theme with dark surface**: Creates visual confusion +❌ **Dark theme with light surface**: Defeats the purpose of dark mode +❌ **Light theme with light gray base**: Produces unreadable gray shades +❌ **Dark theme with dark gray base**: Produces unreadable gray shades + +## Examples + +### Correct Light Theme +\`\`\`scss +$palette: palette( + $primary: #0066cc, + $secondary: #ff6600, + $surface: white, // ✅ Light surface for light theme + $gray: #333333 // ✅ Dark gray base (optional) +); +\`\`\` + +### Correct Dark Theme +\`\`\`scss +$palette: palette( + $primary: #3399ff, + $secondary: #ff9933, + $surface: #1a1a1a, // ✅ Dark surface for dark theme + $gray: #f5f5f5 // ✅ Light gray base (optional) +); +\`\`\` +`; + +/** + * Compact rules for quick reference. + */ +export const COLOR_RULES_SUMMARY = { + luminanceThreshold: LUMINANCE_THRESHOLD, + minimumContrastRatio: DEFAULT_MINIMUM_CONTRAST_RATIO, + rules: { + light: { + surface: `luminance > ${LUMINANCE_THRESHOLD} (light color)`, + gray: `luminance <= ${LUMINANCE_THRESHOLD} (dark color)`, + }, + dark: { + surface: `luminance <= ${LUMINANCE_THRESHOLD} (dark color)`, + gray: `luminance > ${LUMINANCE_THRESHOLD} (light color)`, + }, + }, + suggestedColors: SUGGESTED_COLORS, +} as const; diff --git a/src/mcp/knowledge/custom-palettes.ts b/src/mcp/knowledge/custom-palettes.ts new file mode 100644 index 00000000..cd2e5373 --- /dev/null +++ b/src/mcp/knowledge/custom-palettes.ts @@ -0,0 +1,208 @@ +/** + * Knowledge about custom palette creation for model guidance. + */ + +import {SHADE_LEVELS, ACCENT_SHADE_LEVELS} from './multipliers.js'; + +/** + * Guidance documentation for custom palette creation. + */ +export const CUSTOM_PALETTE_GUIDANCE = ` +# Custom Palette Creation Guide + +## When to Use create_custom_palette vs create_palette + +### Use create_palette (standard) when: +- Brand colors work well as base colors for automatic shade generation +- The base color has medium lightness (not too light, not too dark) +- Quick, consistent shade generation is desired +- Material Design shade conventions are acceptable + +### Use create_custom_palette when: +- The base color is very light (produces washed-out dark shades) +- The base color is very dark (produces muddy light shades) +- Precise control over specific shade values is required +- Brand guidelines specify exact colors for different shades +- Accessibility requirements need specific contrast ratios at certain shades +- You want to mix auto-generated and hand-picked colors in one palette + +## Color Definition Modes + +### mode: 'shades' +Uses the Sass shades() function to auto-generate all shade variants from a single base color. + +\`\`\`json +{ + "mode": "shades", + "baseColor": "#6797de" +} +\`\`\` + +### mode: 'explicit' +Manually specify all shade values for complete control. + +**Important:** Unlike the palette() function where 500 is always the base, with explicit +shades you can define any shade as your "anchor" and build other shades around it. + +\`\`\`json +{ + "mode": "explicit", + "shades": { + "50": "#e6eff8", + "100": "#bfd7f2", + ...all 14 shades... + }, + "contrastOverrides": { + "50": "black", + "500": "white" + } +} +\`\`\` + +## Shade Conventions + +| Shade | Typical Usage | +|-------|---------------| +| 50-100 | Very light tints, backgrounds, hover states | +| 200-300 | Light tints, borders, disabled states | +| 400 | Light accent, secondary text | +| 500 | Base/primary usage | +| 600-700 | Darker shades, active states, headers | +| 800-900 | Very dark shades, high contrast text | +| A100-A700 | Accent variants (vibrant alternatives) | + +## Gray and Surface Relationship + +The gray color should contrast with the surface color: +- **Light themes**: light surface (luminance > 0.5), dark gray base +- **Dark themes**: dark surface (luminance <= 0.5), light gray base + +When gray uses mode:'shades', the surface color is passed to ensure proper contrast. + +## Contrast Colors (Auto-Generated - Do Not Provide) + +**DO NOT provide contrast colors** - they are automatically generated. + +When you use explicit mode, the system automatically generates contrast colors for each shade: +\`\`\`scss +'500': #4CAF50, +'500-contrast': adaptive-contrast(#4CAF50), // AUTO-GENERATED +'500-raw': #4CAF50, +\`\`\` + +The \`adaptive-contrast()\` function automatically selects black or white based on the +background color's luminance, ensuring WCAG-compliant text contrast. + +**Only provide \`contrastOverrides\` if:** +- You have a specific accessibility audit requiring exact contrast values +- The auto-generated contrast doesn't meet specific brand requirements + +This is rare - in 99% of cases, just omit \`contrastOverrides\` entirely. + +## Shade Progression Rules + +**⚠️ CRITICAL: Only GRAY inverts for dark themes. Chromatic colors NEVER invert.** + +### Chromatic Colors (primary, secondary, surface, info, success, warn, error) + +Chromatic shades should **always** follow light-to-dark progression **regardless of theme variant**: +- **Shade 50**: Lightest (highest luminance) - SAME for light AND dark themes +- **Shade 900**: Darkest (lowest luminance) - SAME for light AND dark themes +- **Accent shades (A100 → A700)**: Also light-to-dark, more vibrant alternatives + +**DO NOT invert primary, secondary, or other chromatic colors for dark themes.** +The shade order is always 50=lightest to 900=darkest. This matches Material Design +conventions and how the built-in \`shades()\` function works. + +### ⚠️ CRITICAL: Monochromatic Requirement + +**All shades within a color group MUST be the same color (same hue), just at different lightness levels.** + +A shade palette is NOT a collection of different colors - it's ONE color at varying intensities. +Think of it like mixing paint with white (lighter shades) or black (darker shades). + +**✅ CORRECT - Blue primary palette (all shades are BLUE):** +\`\`\` +primary: + 50: "#E3F2FD" ← very light blue + 100: "#BBDEFB" ← light blue + 200: "#90CAF9" ← light blue + 300: "#64B5F6" ← medium-light blue + 400: "#42A5F5" ← medium blue + 500: "#2196F3" ← blue (base) + 600: "#1E88E5" ← medium-dark blue + 700: "#1976D2" ← dark blue + 800: "#1565C0" ← darker blue + 900: "#0D47A1" ← very dark blue +\`\`\` +All shades have the same blue hue (~210°), only lightness varies. + +**❌ WRONG - Rainbow palette (different colors - DO NOT DO THIS):** +\`\`\` +primary: + 50: "#FFEBEE" ← pink (hue ~350°) + 100: "#FFE0B2" ← orange (hue ~30°) + 200: "#FFF9C4" ← yellow (hue ~55°) + 500: "#4CAF50" ← green (hue ~122°) + 700: "#1976D2" ← blue (hue ~210°) + 900: "#9C27B0" ← purple (hue ~291°) +\`\`\` +This is WRONG! Each shade has a completely different hue. + +**Why this matters:** +- Components use specific shades for states (hover uses 600, active uses 700, etc.) +- If shades are different colors, hover/active states will look broken +- The \`contrast-color()\` function expects consistent hue across shades +- Visual coherence requires related colors, not random ones + +**Tolerance:** The validator allows ±30° hue variance to accommodate natural saturation shifts, +but intentionally different hues will trigger warnings. + +### Gray Color (THE ONLY COLOR THAT INVERTS) + +Gray is the **only** color family that changes shade progression based on theme variant. +This is because gray shades are used for text and UI elements that must contrast against +the surface color. + +**Light themes:** +- Shade 50: Lightest (e.g., near-white, #f5f5f5) +- Shade 900: Darkest (e.g., near-black, #212121) + +**Dark themes (inverted progression):** +- Shade 50: Darkest (e.g., near-black, #1a1a1a) +- Shade 900: Lightest (e.g., near-white, #f5f5f5) + +This inversion ensures text remains readable: dark text on light backgrounds (light theme) +and light text on dark backgrounds (dark theme). + +### Why This Matters + +Consistent shade progression ensures: +1. Component styles that use hardcoded shade references work correctly +2. Hover/active states (often darker shades) behave as expected +3. Text contrast calculations remain valid +4. Theming utilities like \`color()\` and \`contrast-color()\` produce correct results + +The validator issues **warnings** (not errors) for progression issues, allowing override +when intentional deviation is needed. +`; + +/** + * Required shade counts for validation. + */ +export const REQUIRED_SHADES = { + /** Number of shades required for chromatic colors (primary, secondary, etc.) */ + chromatic: [...SHADE_LEVELS, ...ACCENT_SHADE_LEVELS].length, // 14 + /** Number of shades required for gray */ + gray: SHADE_LEVELS.length, // 10 +}; + +/** + * All chromatic shades combined. + */ +export const ALL_CHROMATIC_SHADES = [...SHADE_LEVELS, ...ACCENT_SHADE_LEVELS]; + +/** + * All gray shades. + */ +export const ALL_GRAY_SHADES = [...SHADE_LEVELS]; diff --git a/src/mcp/knowledge/elevations.ts b/src/mcp/knowledge/elevations.ts new file mode 100644 index 00000000..16e688c0 --- /dev/null +++ b/src/mcp/knowledge/elevations.ts @@ -0,0 +1,46 @@ +/** + * Elevation presets for Material and Indigo design systems. + * These are loaded from the JSON files generated by buildJSON.mjs + * which is the single source of truth from the Sass code. + */ + +import materialElevationsData from '../../../json/elevations/material.json' with { type: 'json' }; +import indigoElevationsData from '../../../json/elevations/indigo.json' with { type: 'json' }; + +export type ElevationLevel = + | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 + | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 + | 21 | 22 | 23 | 24; + +export type ElevationPreset = 'material' | 'indigo'; + +type ElevationMap = Record; + +/** + * Material Design elevation definitions loaded from JSON. + * Based on the Material Design elevation system with 25 levels (0-24). + */ +export const MATERIAL_ELEVATIONS: ElevationMap = materialElevationsData.elevations as ElevationMap; + +/** + * Indigo Design System elevation definitions loaded from JSON. + * A custom elevation system with unique shadow definitions. + */ +export const INDIGO_ELEVATIONS: ElevationMap = indigoElevationsData.elevations as ElevationMap; + +/** + * All elevation presets indexed by design system name. + */ +export const ELEVATION_PRESETS: Record = { + material: MATERIAL_ELEVATIONS, + indigo: INDIGO_ELEVATIONS, +}; + +/** + * Valid elevation levels. + */ +export const ELEVATION_LEVELS: ElevationLevel[] = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, +]; diff --git a/src/mcp/knowledge/index.ts b/src/mcp/knowledge/index.ts new file mode 100644 index 00000000..91accd16 --- /dev/null +++ b/src/mcp/knowledge/index.ts @@ -0,0 +1,130 @@ +/** + * Knowledge base index - re-exports all embedded theming data. + */ + +// Sass API Manifest (centralized API knowledge) +export { + IMPORT_PATHS, + PALETTE_FUNCTION, + SHADES_FUNCTION, + TYPOGRAPHY_MIXIN, + ELEVATIONS_MIXIN, + PALETTE_MIXIN, + SPACING_MIXIN, + CORE_MIXIN, + THEME_MIXIN, + CSS_VARIABLE_PATTERNS, + VARIABLE_PATTERNS, + getImportPath, + getElevationsVariable, + isMixinSupported, + getPaletteColorGroups, + type PaletteFunctionParams, + type ShadesFunctionParams, + type TypographyMixinParams, + type ElevationsMixinParams, + type PaletteMixinParams, + type CoreMixinParams, + type ThemeMixinParams, +} from './sass-api.js'; + +// Color guidance +export {COLOR_VARIANT_RULES, COLOR_GUIDANCE_MARKDOWN, COLOR_RULES_SUMMARY} from './colors.js'; + +// Color usage +export { + COLOR_SEMANTIC_ROLES, + COLOR_USAGE_MARKDOWN, + OPACITY_USAGE, + STATE_PATTERNS, + THEME_PATTERNS, + type ColorSemanticRole, + type ShadeRange, +} from './color-usage.js'; + +// Palettes +export { + type PaletteColors, + type PalettePresetName, + PALETTE_PRESETS, + LIGHT_PALETTE_PRESETS, + DARK_PALETTE_PRESETS, +} from './palettes.js'; + +// Custom Palettes +export {CUSTOM_PALETTE_GUIDANCE, REQUIRED_SHADES, ALL_CHROMATIC_SHADES, ALL_GRAY_SHADES} from './custom-palettes.js'; + +// Multipliers +export { + type ShadeMultipliers, + COLOR_MULTIPLIERS, + GRAYSCALE_MULTIPLIERS, + SHADE_LEVELS, + ACCENT_SHADE_LEVELS, + type ShadeLevel, + type AccentShadeLevel, +} from './multipliers.js'; + +// Typography +export { + type TypeStyle, + type TypeScale, + type DesignSystem, + TYPOGRAPHY_PRESETS, + TYPE_SCALE_CATEGORIES, + type TypeScaleCategory, +} from './typography.js'; + +// Elevations +export { + type ElevationLevel, + type ElevationPreset, + MATERIAL_ELEVATIONS, + INDIGO_ELEVATIONS, + ELEVATION_PRESETS, + ELEVATION_LEVELS, +} from './elevations.js'; + +// Platforms +export { + // Angular + ANGULAR_PLATFORM, + ANGULAR_USAGE_EXAMPLES, + generateAngularThemeSass, + type CoreMixinOptions, + type ThemeMixinOptions, + type AngularThemeTemplate, + // Web Components + WEBCOMPONENTS_PLATFORM, + WEBCOMPONENTS_USAGE_EXAMPLES, + WEBCOMPONENTS_RUNTIME_CONFIG, + generateWebComponentsThemeSass, + type WebComponentsThemeTemplate, + // React + REACT_PLATFORM, + REACT_USAGE_EXAMPLES, + // Blazor + BLAZOR_PLATFORM, + BLAZOR_USAGE_EXAMPLES, + // Platform utilities + type Platform, + type PlatformDetectionResult, + type DetectionSignal, + type PackageDetectionSignal, + type ConfigFileDetectionSignal, + type FrameworkDetectionSignal, + type PlatformAlternative, + detectPlatformFromDependencies, + detectConfigFiles, + PLATFORM_METADATA, +} from './platforms/index.js'; + +export { + PALETTE_PRESETS_PATHS, + TYPOGRAPHY_PRESETS_PATHS, + SCHEMAS as SCHEMA_PRESETS, + TYPEFACES as TYPEFACE_PRESETS, + TYPE_SCALES as TYPE_SCALE_PRESETS, + PALETTES as PALETTES_PRESETS, + ELEVATIONS as ELEVATIONS_PRESETS +} from './platforms/common.js'; diff --git a/src/mcp/knowledge/multipliers.ts b/src/mcp/knowledge/multipliers.ts new file mode 100644 index 00000000..fbc2ce91 --- /dev/null +++ b/src/mcp/knowledge/multipliers.ts @@ -0,0 +1,27 @@ +/** + * Color shade multipliers used for generating color shades. + * These are loaded from the JSON files generated by buildJSON.mjs + * which is the single source of truth from the Sass code. + */ + +import multipliersData from '../../../json/colors/meta/multipliers.json' with { type: 'json' }; + +// Re-export shade level constants and types from the canonical source +export {SHADE_LEVELS, ACCENT_SHADE_LEVELS, type ShadeLevel, type AccentShadeLevel} from '../utils/types.js'; + +export interface ShadeMultipliers { + s?: Record; + l: Record; +} + +/** + * Multipliers for chromatic colors (primary, secondary, info, success, warn, error). + * Contains saturation (s) and lightness (l) multipliers for each shade level. + */ +export const COLOR_MULTIPLIERS: ShadeMultipliers = multipliersData.color as ShadeMultipliers; + +/** + * Multipliers for grayscale colors. + * Only contains lightness (l) multipliers as grayscale has no saturation. + */ +export const GRAYSCALE_MULTIPLIERS: Pick = multipliersData.grayscale as Pick; diff --git a/src/mcp/knowledge/palettes.ts b/src/mcp/knowledge/palettes.ts new file mode 100644 index 00000000..924d5c98 --- /dev/null +++ b/src/mcp/knowledge/palettes.ts @@ -0,0 +1,119 @@ +/** + * Embedded palette presets from the Ignite UI Theming framework. + * These are loaded from the JSON files generated by buildJSON.mjs + * which is the single source of truth from the Sass code. + */ + +import palettesData from '../../../json/colors/presets/palettes.json' with { type: 'json' }; + +export interface PaletteColors { + primary: string; + secondary: string; + gray: string; + surface: string; + info: string; + success: string; + warn: string; + error: string; +} + +export type PalettePresetName = + | 'light-bootstrap-palette' + | 'dark-bootstrap-palette' + | 'light-material-palette' + | 'dark-material-palette' + | 'light-fluent-palette' + | 'dark-fluent-palette' + | 'light-indigo-palette' + | 'dark-indigo-palette'; + +/** + * All palette presets loaded from JSON. + */ +export const PALETTE_PRESETS = palettesData as Record; + +/** + * Get light palette presets only. + */ +export const LIGHT_PALETTE_PRESETS = { + 'light-bootstrap-palette': PALETTE_PRESETS['light-bootstrap-palette'], + 'light-material-palette': PALETTE_PRESETS['light-material-palette'], + 'light-fluent-palette': PALETTE_PRESETS['light-fluent-palette'], + 'light-indigo-palette': PALETTE_PRESETS['light-indigo-palette'], +} as const; + +/** + * Get dark palette presets only. + */ +export const DARK_PALETTE_PRESETS = { + 'dark-bootstrap-palette': PALETTE_PRESETS['dark-bootstrap-palette'], + 'dark-material-palette': PALETTE_PRESETS['dark-material-palette'], + 'dark-fluent-palette': PALETTE_PRESETS['dark-fluent-palette'], + 'dark-indigo-palette': PALETTE_PRESETS['dark-indigo-palette'], +} as const; + +// ============================================================================ +// Palette Luminance Guidance +// ============================================================================ + +/** + * Documentation about color luminance and shade generation suitability. + * + * The theming system uses two different luminance concepts: + * + * 1. **LUMINANCE_THRESHOLD (0.5)** - Determines if a color is "light" or "dark" + * for variant matching. Used to validate that surface/gray colors match + * the theme variant (light themes need light surfaces, dark themes need + * dark surfaces). + * + * 2. **PALETTE_LUMINANCE_THRESHOLDS** - Determines if a color is suitable for + * automatic shade generation with the palette() function: + * - TOO_DARK (< 0.05): Lighter shades (50-200) will lack contrast range + * - TOO_LIGHT (> 0.45): Darker shades (600-900) will appear washed out + * - Ideal range: 0.05 - 0.45 luminance + * + * When a color falls outside the ideal range for shade generation, the + * create_theme tool will warn and recommend using create_custom_palette + * with explicit shade values instead. + */ +export const PALETTE_LUMINANCE_GUIDANCE = ` +## Color Luminance and Shade Generation + +### Why Luminance Matters + +The palette() function generates 10 shades (50-900) from a base color by +adjusting lightness. This works well when the base color has moderate +luminance, but produces poor results for extreme values: + +- **Very light colors (luminance > 0.45)**: The darker shades (600-900) + will appear washed out because there's limited "darkening room" +- **Very dark colors (luminance < 0.05)**: The lighter shades (50-200) + will lack contrast range because there's limited "lightening room" + +### Ideal Base Color Range + +For best results with automatic shade generation: +- **Luminance**: 0.05 - 0.45 +- **CIELAB L***: 25 - 73 (approximately) +- **Examples**: Medium blues, greens, purples, oranges work well +- **Problematic**: Near-white (#f5f5f5), near-black (#1a1a1a), pastels + +### When to Use create_custom_palette + +Use create_custom_palette with explicit shade values when: +1. Base color luminance is outside 0.05-0.45 range +2. Brand guidelines specify exact shades +3. Accessibility requirements need specific contrast ratios +4. You need precise control over the shade progression + +### Example: Problematic vs. Ideal Colors + +| Color | Luminance | Suitability | +|-------|-----------|-------------| +| #2196F3 | 0.28 | ✅ Ideal - good shade range | +| #4CAF50 | 0.30 | ✅ Ideal - good shade range | +| #FF5722 | 0.18 | ✅ Ideal - good shade range | +| #f5f5f5 | 0.91 | ❌ Too light - use explicit shades | +| #1a1a1a | 0.02 | ❌ Too dark - use explicit shades | +| #e3f2fd | 0.88 | ❌ Too light - use explicit shades | +`; diff --git a/src/mcp/knowledge/platforms/angular.ts b/src/mcp/knowledge/platforms/angular.ts new file mode 100644 index 00000000..cb33d03a --- /dev/null +++ b/src/mcp/knowledge/platforms/angular.ts @@ -0,0 +1,333 @@ +/** + * Ignite UI for Angular Platform Knowledge + * + * This module contains platform-specific information for generating + * valid Sass theme code for Ignite UI for Angular applications. + * + * Key differences from igniteui-theming: + * - Uses `igniteui-angular/theming` module (forwards igniteui-theming with overrides) + * - Exposes `core()` and `theme()` mixins (Angular-specific, not in igniteui-theming) + * - Typography is overridden with Angular-specific implementation + * - Requires `ig-typography` CSS class on root element + */ + +import {quoteFontFamily, generateUseStatement, generatePaletteCode, generateTypographyCode} from '../../utils/sass.js'; +import {PALETTE_PRESETS, type PalettePresetName} from '../palettes.js'; +import {DesignSystem, ThemeVariant} from '../../utils/types.js'; +import { PALETTES, SCHEMAS, TYPE_SCALES, TYPEFACES } from './common.js'; + +export const ANGULAR_PLATFORM = { + id: 'angular', + name: 'Ignite UI for Angular', + packageName: 'igniteui-angular', + + /** + * The Sass module to import for theming + */ + themingModule: 'igniteui-angular/theming', + + /** + * Detection patterns in package.json dependencies + */ + detectionPatterns: ['igniteui-angular', '@infragistics/igniteui-angular'], + + /** + * Required CSS class on root element for typography + */ + rootClass: 'ig-typography', +} as const; + +/** + * Core mixin configuration for Angular + * + * The `core` mixin must be included before `theme` mixin. + * It provides base definitions needed for theming to work correctly. + */ +export interface CoreMixinOptions { + /** + * Include/exclude styles for printing + * @default true + */ + printLayout?: boolean; + + /** + * Switches component colors to more accessible values + * (suitable for color blind users) + * @default false + */ + enhancedAccessibility?: boolean; +} + +/** + * Theme mixin configuration for Angular + * + * The `theme` mixin generates styles for all components. + */ +export interface ThemeMixinOptions { + /** + * The palette map to be used by default themes of all components + */ + palette?: string; + + /** + * The schema used as basis for styling components + * @default '$light-material-schema' + */ + schema?: string; + + /** + * List of component themes to exclude from global theme + */ + exclude?: string[]; + + /** + * Global roundness factor (0 to 1) + */ + roundness?: number; + + /** + * Enable/disable elevations for all components + * @default true + */ + elevation?: boolean; + + /** + * The elevation map to use + * @default '$material-elevations' + */ + elevations?: string; +} + +/** + * Template for generating a complete Angular theme + */ +export interface AngularThemeTemplate { + designSystem: DesignSystem; + variant: ThemeVariant; + primaryColor?: string; + secondaryColor?: string; + surfaceColor?: string; + grayColor?: string; + customPaletteName?: string; + fontFamily?: string; + includeTypography?: boolean; + coreOptions?: CoreMixinOptions; + themeOptions?: Partial; +} + +/** + * Generate Sass code for an Angular theme + * + * Uses shared code generation helpers from utils/sass.ts for: + * - @use statement (generateUseStatement) + * - Palette code (generatePaletteCode) + * - Typography code (generateTypographyCode) + */ +export function generateAngularThemeSass(template: AngularThemeTemplate): string { + const { + designSystem, + variant, + primaryColor, + secondaryColor, + surfaceColor, + grayColor, + customPaletteName = '$my-palette', + fontFamily, + includeTypography = true, + coreOptions = {}, + themeOptions = {}, + } = template; + + const lines: string[] = [ + '// Generated by Ignite UI Theming MCP Server', + '// Platform: Ignite UI for Angular', + '', + '// Import the theming module', + generateUseStatement('angular'), + '', + ]; + + // Custom palette generation (if custom colors provided) + const hasCustomColors = primaryColor || secondaryColor || surfaceColor; + let paletteVariable: string; + + if (hasCustomColors) { + // Get default colors from the preset for this design system and variant + const presetName = `${variant}-${designSystem}-palette` as PalettePresetName; + const presetColors = PALETTE_PRESETS[presetName]; + + // Use provided colors or fall back to preset defaults + // primary is required when hasCustomColors is true + const effectivePrimary = primaryColor || presetColors.primary; + const effectiveSecondary = secondaryColor || presetColors.secondary; + const effectiveSurface = surfaceColor || presetColors.surface; + + // Use shared palette code generator + const paletteResult = generatePaletteCode({ + primary: effectivePrimary, + secondary: effectiveSecondary, + surface: effectiveSurface, + gray: grayColor, + variableName: customPaletteName.replace(/^\$/, ''), // Remove $ prefix + useVariableReferences: true, + }); + + lines.push('// Custom color palette'); + lines.push(...paletteResult.colorVariables); + lines.push(''); + lines.push(...paletteResult.paletteDefinition); + lines.push(''); + + paletteVariable = paletteResult.variableName; + } else { + // Use predefined palette + paletteVariable = PALETTES[variant][designSystem as keyof (typeof PALETTES)['light']]; + } + + // Core mixin + lines.push('// IMPORTANT: Always include core first!'); + const coreArgs: string[] = []; + if (coreOptions.printLayout === false) { + coreArgs.push('$print-layout: false'); + } + if (coreOptions.enhancedAccessibility) { + coreArgs.push('$enhanced-accessibility: true'); + } + + if (coreArgs.length > 0) { + lines.push(`@include core(${coreArgs.join(', ')});`); + } else { + lines.push('@include core();'); + } + + // Typography mixin + if (includeTypography) { + // Use custom font family if provided, otherwise use preset variable + const typefaceValue = fontFamily ? quoteFontFamily(fontFamily) : TYPEFACES[designSystem]; + const typeScale = TYPE_SCALES[designSystem]; + + // Use shared typography code generator + const typographyLines = generateTypographyCode({ + fontFamily: typefaceValue, + typeScaleVar: typeScale, + }); + lines.push(...typographyLines); + } + + // Theme mixin + const schema = SCHEMAS[variant][designSystem]; + const themeArgs: string[] = []; + + themeArgs.push(` $palette: ${paletteVariable}`); + themeArgs.push(` $schema: ${schema}`); + + if (themeOptions.roundness !== undefined) { + themeArgs.push(` $roundness: ${themeOptions.roundness}`); + } + if (themeOptions.elevation === false) { + themeArgs.push(' $elevation: false'); + } + if (themeOptions.elevations) { + themeArgs.push(` $elevations: ${themeOptions.elevations}`); + } + if (themeOptions.exclude && themeOptions.exclude.length > 0) { + themeArgs.push(` $exclude: (${themeOptions.exclude.join(', ')})`); + } + + lines.push(''); + lines.push('// Apply the theme'); + lines.push('@include theme('); + lines.push(themeArgs.join(',\n')); + lines.push(');'); + + return lines.join('\n'); +} + +/** + * Example usage documentation + */ +export const ANGULAR_USAGE_EXAMPLES = { + basic: ` +// Basic Material Light Theme +@use "igniteui-angular/theming" as *; + +@include core(); +@include typography( + $font-family: $material-typeface, + $type-scale: $material-type-scale +); +@include theme( + $palette: $light-material-palette, + $schema: $light-material-schema +); +`, + + customPalette: ` +// Custom Palette Theme +@use "igniteui-angular/theming" as *; + +$my-palette: palette( + $primary: #2ab759, + $secondary: #f96a88, + $surface: #ffffff +); + +@include core(); +@include typography( + $font-family: $material-typeface, + $type-scale: $material-type-scale +); +@include theme( + $palette: $my-palette, + $schema: $light-material-schema +); +`, + + darkTheme: ` +// Dark Indigo Theme +@use "igniteui-angular/theming" as *; + +@include core(); +@include typography( + $font-family: $indigo-typeface, + $type-scale: $indigo-type-scale +); +@include theme( + $palette: $dark-indigo-palette, + $schema: $dark-indigo-schema +); +`, + + excludeComponents: ` +// Theme with excluded components +@use "igniteui-angular/theming" as *; + +$excluded-components: (igx-avatar, igx-badge); + +@include core(); +@include typography( + $font-family: $material-typeface, + $type-scale: $material-type-scale +); +@include theme( + $palette: $light-material-palette, + $schema: $light-material-schema, + $exclude: $excluded-components +); +`, + + enhancedAccessibility: ` +// Theme with enhanced accessibility +@use "igniteui-angular/theming" as *; + +@include core($enhanced-accessibility: true); +@include typography( + $font-family: $material-typeface, + $type-scale: $material-type-scale +); +@include theme( + $palette: $light-material-palette, + $schema: $light-material-schema +); +`, +} as const; diff --git a/src/mcp/knowledge/platforms/blazor.ts b/src/mcp/knowledge/platforms/blazor.ts new file mode 100644 index 00000000..7604149a --- /dev/null +++ b/src/mcp/knowledge/platforms/blazor.ts @@ -0,0 +1,170 @@ +/** + * Ignite UI for Blazor Platform Knowledge + * + * This module contains platform-specific information for generating + * valid Sass theme code for Ignite UI for Blazor applications. + * + * Key characteristics: + * - .NET/C# project using Blazor framework (Server or WebAssembly) + * - Uses NuGet package `IgniteUI.Blazor` (not npm) + * - Uses `igniteui-theming` npm package for Sass compilation + * - Sass files are compiled to CSS and referenced in Blazor components + * - Components use CSS variables for theming (--ig-* naming convention) + * - Theming approach is similar to Web Components/React + */ + +export const BLAZOR_PLATFORM = { + id: 'blazor', + name: 'Ignite UI for Blazor', + packageName: 'IgniteUI.Blazor', + + /** + * The Sass module to import for theming + * Note: Blazor projects need to install igniteui-theming via npm + * even though the main package is NuGet-based + */ + themingModule: 'igniteui-theming', + + /** + * Detection patterns - Blazor uses NuGet packages, not npm + * Detection is done via .csproj file analysis + */ + detectionPatterns: ['IgniteUI.Blazor'], + + /** + * Config files that indicate a Blazor project + * .csproj files with IgniteUI.Blazor package reference + */ + configFiles: ['.csproj'], + + /** + * No required root class (themes apply via CSS variables on :root) + */ + rootClass: null, +} as const; + +/** + * Example usage documentation for Blazor + */ +export const BLAZOR_USAGE_EXAMPLES = { + basic: ` +// Basic Material Light Theme for Blazor +// In your wwwroot/css/theme.scss file: + +@use 'igniteui-theming/sass/color/presets/light/material' as *; +@use 'igniteui-theming' as *; +@use 'igniteui-theming/sass/typography/presets/material' as *; +@use 'igniteui-theming/sass/elevations/presets' as *; + +:root { + --ig-theme: material; + --ig-theme-variant: light; + --ig-size-small: 1; + --ig-size-medium: 2; + --ig-size-large: 3; + --ig-scrollbar-size: #{rem(16px)}; +} + +@include palette($palette); +@include elevations($material-elevations); +@include typography( + $font-family: $typeface, + $type-scale: $type-scale +); +@include spacing(); +`, + + projectSetup: ` +// Blazor project setup for custom theming: + +// 1. Install NuGet package in your .csproj: + + +// 2. Install npm packages for Sass theming: +npm init -y +npm install igniteui-theming sass + +// 3. Create theme file (wwwroot/css/theme.scss) + +// 4. Add npm script to package.json: +{ + "scripts": { + "build:theme": "sass wwwroot/css/theme.scss wwwroot/css/theme.css" + } +} + +// 5. Reference compiled CSS in _Host.cshtml or index.html: + +`, + + csprojExample: ` + + + + net8.0 + + + + + +`, + + customPalette: ` +// Custom Palette Theme +@use 'igniteui-theming' as *; +@use 'igniteui-theming/sass/typography/presets/material' as *; +@use 'igniteui-theming/sass/elevations/presets' as *; + +$my-palette: palette( + $primary: #2ab759, + $secondary: #f96a88, + $surface: #ffffff +); + +:root { + --ig-theme: material; + --ig-theme-variant: light; + --ig-size-small: 1; + --ig-size-medium: 2; + --ig-size-large: 3; +} + +@include palette($my-palette); +@include elevations($material-elevations); +@include typography( + $font-family: $typeface, + $type-scale: $type-scale +); +@include spacing(); +`, + + darkTheme: ` +// Dark Indigo Theme for Blazor +@use 'igniteui-theming' as *; +@use 'igniteui-theming/sass/color/presets/dark/indigo' as *; +@use 'igniteui-theming/sass/typography/presets/indigo' as *; +@use 'igniteui-theming/sass/elevations/presets' as *; + +:root { + --ig-theme: indigo; + --ig-theme-variant: dark; + --ig-size-small: 1; + --ig-size-medium: 2; + --ig-size-large: 3; +} + +@include palette($dark-indigo-palette); +@include elevations($indigo-elevations); +@include typography( + $font-family: $indigo-typeface, + $type-scale: $indigo-type-scale +); +@include spacing(); +`, +} as const; + +/** + * Note: Blazor uses the same Sass code generation as Web Components/React. + * The generateWebComponentsThemeSass function from webcomponents.ts can be reused for Blazor. + * The main difference is in the build pipeline (npm + sass CLI vs Angular CLI). + */ diff --git a/src/mcp/knowledge/platforms/common.ts b/src/mcp/knowledge/platforms/common.ts new file mode 100644 index 00000000..d48e43af --- /dev/null +++ b/src/mcp/knowledge/platforms/common.ts @@ -0,0 +1,94 @@ +/** + * Available palettes preset paths + */ +export const PALETTE_PRESETS_PATHS = { + light: { + material: 'igniteui-theming/sass/color/presets/light/material', + fluent: 'igniteui-theming/sass/color/presets/light/fluent', + bootstrap: 'igniteui-theming/sass/color/presets/light/bootstrap', + indigo: 'igniteui-theming/sass/color/presets/light/indigo', + }, + dark: { + material: 'igniteui-theming/sass/color/presets/dark/material', + fluent: 'igniteui-theming/sass/color/presets/dark/fluent', + bootstrap: 'igniteui-theming/sass/color/presets/dark/bootstrap', + indigo: 'igniteui-theming/sass/color/presets/dark/indigo', + }, +} as const; + + +/** + * Available typography preset paths + */ +export const TYPOGRAPHY_PRESETS_PATHS = { + material: 'igniteui-theming/sass/typography/presets/material', + fluent: 'igniteui-theming/sass/typography/presets/fluent', + bootstrap: 'igniteui-theming/sass/typography/presets/bootstrap', + indigo: 'igniteui-theming/sass/typography/presets/indigo', +} as const; + +/** + * Available schema presets + */ +export const SCHEMAS = { + light: { + material: '$light-material-schema', + fluent: '$light-fluent-schema', + bootstrap: '$light-bootstrap-schema', + indigo: '$light-indigo-schema', + }, + dark: { + material: '$dark-material-schema', + fluent: '$dark-fluent-schema', + bootstrap: '$dark-bootstrap-schema', + indigo: '$dark-indigo-schema', + }, +} as const; + +/** + * Available palettes presets + */ +export const PALETTES = { + light: { + material: '$light-material-palette', + fluent: '$light-fluent-palette', + bootstrap: '$light-bootstrap-palette', + indigo: '$light-indigo-palette', + }, + dark: { + material: '$dark-material-palette', + fluent: '$dark-fluent-palette', + bootstrap: '$dark-bootstrap-palette', + indigo: '$dark-indigo-palette', + }, +} as const; + +/** + * Available typefaces + */ +export const TYPEFACES = { + material: '$material-typeface', + fluent: '$fluent-typeface', + bootstrap: '$bootstrap-typeface', + indigo: '$indigo-typeface', +} as const; + +/** + * Available type scales + */ +export const TYPE_SCALES = { + material: '$material-type-scale', + fluent: '$fluent-type-scale', + bootstrap: '$bootstrap-type-scale', + indigo: '$indigo-type-scale', +} as const; + +/** + * Available elevation presets + */ +export const ELEVATIONS = { + material: '$material-elevations', + bootstrap: '$material-elevations', + fluent: '$material-elevations', + indigo: '$indigo-elevations', +} as const; diff --git a/src/mcp/knowledge/platforms/index.ts b/src/mcp/knowledge/platforms/index.ts new file mode 100644 index 00000000..2cfc2d1d --- /dev/null +++ b/src/mcp/knowledge/platforms/index.ts @@ -0,0 +1,415 @@ +/** + * Platform-specific knowledge for theme generation + * + * This module exports platform-specific configurations and generators + * for all supported Ignite UI platforms: + * - Ignite UI for Angular + * - Ignite UI for Web Components + * - Ignite UI for React + * - Ignite UI for Blazor + * + * It also provides platform detection functionality with multi-signal analysis + * for automatic platform identification from project files. + */ + +import {existsSync, readFileSync, readdirSync} from 'node:fs'; +import {resolve} from 'node:path'; +import type {Platform} from '../../utils/types.js'; + +// Angular platform +export { + ANGULAR_PLATFORM, + ANGULAR_USAGE_EXAMPLES, + generateAngularThemeSass, + type CoreMixinOptions, + type ThemeMixinOptions, + type AngularThemeTemplate, +} from './angular.js'; + +// Web Components platform +export { + WEBCOMPONENTS_PLATFORM, + WEBCOMPONENTS_USAGE_EXAMPLES, + WEBCOMPONENTS_RUNTIME_CONFIG, + generateWebComponentsThemeSass, + // Helper functions for testability and reuse + generateWCHeader, + getWCElevationPreset, + generateWCImports, + generateWCProgressProperties, + generateWCRootVariables, + generateWCRtlSupport, + generateWCScrollbarCustomization, + generateWCThemingMixins, + type WebComponentsThemeTemplate, +} from './webcomponents.js'; + +// React platform +export { + REACT_PLATFORM, + REACT_USAGE_EXAMPLES, +} from './react.js'; + +// Blazor platform +export { + BLAZOR_PLATFORM, + BLAZOR_USAGE_EXAMPLES, +} from './blazor.js'; + +// Re-export Platform type from canonical source +export type {Platform} from '../../utils/types.js'; + +// ============================================================================ +// PLATFORM DETECTION TYPES +// ============================================================================ + +/** + * Detection signal from package analysis + */ +export interface PackageDetectionSignal { + type: 'ignite_package'; + package: string; + confidence: number; +} + +/** + * Detection signal from config file analysis + */ +export interface ConfigFileDetectionSignal { + type: 'config_file'; + file: string; + confidence: number; +} + +/** + * Detection signal from framework package (fallback) + */ +export interface FrameworkDetectionSignal { + type: 'framework_package'; + package: string; + confidence: number; +} + +/** + * Union type for all detection signals + */ +export type DetectionSignal = PackageDetectionSignal | ConfigFileDetectionSignal | FrameworkDetectionSignal; + +/** + * Alternative platform detected during ambiguous detection + */ +export interface PlatformAlternative { + platform: Platform; + confidence: number; + signals: DetectionSignal[]; +} + +/** + * Platform detection result with enhanced ambiguity handling + */ +export interface PlatformDetectionResult { + /** Detected platform (null if ambiguous or not detected) */ + platform: Platform | null; + /** Overall confidence level */ + confidence: 'high' | 'medium' | 'low' | 'none'; + /** True when multiple platforms detected with similar confidence */ + ambiguous?: boolean; + /** Alternative platforms when ambiguous */ + alternatives?: PlatformAlternative[]; + /** All detection signals found */ + signals: DetectionSignal[]; + /** Human-readable reason for the detection result */ + reason: string; + /** Primary detected package (for backward compatibility) */ + detectedPackage?: string; +} + +// ============================================================================ +// PACKAGE DETECTION PATTERNS +// ============================================================================ + +/** + * Ignite UI package patterns for each platform. + * These are HIGH confidence indicators (100). + */ +const IGNITE_PACKAGE_PATTERNS: Record = { + angular: ['igniteui-angular', '@infragistics/igniteui-angular'], + webcomponents: ['igniteui-webcomponents', '@infragistics/igniteui-webcomponents'], + react: ['igniteui-react', '@infragistics/igniteui-react'], + blazor: [], // Blazor uses NuGet, not npm - detected via .csproj +}; + +/** + * Framework package patterns for fallback detection. + * These are LOW confidence indicators (40) - only used when no Ignite UI package found. + */ +const FRAMEWORK_PACKAGE_PATTERNS: Record = { + '@angular/core': 'angular', + lit: 'webcomponents', + react: 'react', + 'react-dom': 'react', +}; + +// ============================================================================ +// CONFIG FILE DETECTION +// ============================================================================ + +/** + * Internal interface for config file detection results + */ +interface ConfigFileSignal { + platform: Platform; + file: string; + confidence: number; +} + +/** + * Detect platform from config files in the project root. + * Fast detection that only checks root directory, no deep scanning. + * + * @param projectRoot - Path to the project root directory + * @returns Array of detected config file signals + */ +export function detectConfigFiles(projectRoot: string = '.'): ConfigFileSignal[] { + const signals: ConfigFileSignal[] = []; + const root = resolve(projectRoot); + + // Angular: angular.json (HIGH-MEDIUM confidence) + if (existsSync(resolve(root, 'angular.json'))) { + signals.push({platform: 'angular', file: 'angular.json', confidence: 80}); + } + + // React: vite.config.* with React plugin + for (const viteConfig of ['vite.config.ts', 'vite.config.js', 'vite.config.mts', 'vite.config.mjs']) { + const configPath = resolve(root, viteConfig); + if (existsSync(configPath)) { + try { + const content = readFileSync(configPath, 'utf-8'); + // Check for React plugin in Vite config + if (content.includes('@vitejs/plugin-react') || content.includes('plugin-react')) { + signals.push({platform: 'react', file: viteConfig, confidence: 80}); + break; + } + } catch { + // Ignore read errors, continue with other checks + } + } + } + + // React: next.config.* (Next.js is React-specific) + for (const nextConfig of ['next.config.js', 'next.config.mjs', 'next.config.ts']) { + if (existsSync(resolve(root, nextConfig))) { + signals.push({platform: 'react', file: nextConfig, confidence: 80}); + break; + } + } + + // Blazor: *.csproj with IgniteUI.Blazor reference (HIGH confidence) + try { + const files = readdirSync(root); + const csprojFiles = files.filter((f) => f.endsWith('.csproj')).slice(0, 5); // Limit to first 5 + + for (const csproj of csprojFiles) { + try { + const content = readFileSync(resolve(root, csproj), 'utf-8'); + if (content.includes('IgniteUI.Blazor')) { + signals.push({platform: 'blazor', file: csproj, confidence: 100}); + break; + } + // Also check for Blazor SDK without Ignite UI (lower confidence) + if (content.includes('Microsoft.NET.Sdk.BlazorWebAssembly') || content.includes('Microsoft.NET.Sdk.Razor')) { + signals.push({platform: 'blazor', file: csproj, confidence: 40}); + break; + } + } catch { + // Ignore read errors for individual files + } + } + } catch { + // Ignore directory read errors + } + + return signals; +} + +// ============================================================================ +// MAIN DETECTION FUNCTION +// ============================================================================ + +/** + * Detect platform from package.json dependencies and project config files. + * + * Uses a multi-signal approach with confidence scoring: + * 1. Ignite UI packages (HIGH - 100): Definitive platform match + * 2. Config files (MEDIUM-HIGH - 80): Strong platform indicator + * 3. Framework packages (LOW - 40): Fallback when no Ignite UI found + * + * When multiple platforms are detected with significant confidence (≥60), + * returns an ambiguous result asking the user to specify explicitly. + * + * @param dependencies - package.json dependencies + * @param devDependencies - package.json devDependencies + * @param projectRoot - Project root directory for config file detection + * @returns Platform detection result with signals and confidence + */ +export function detectPlatformFromDependencies( + dependencies: Record = {}, + devDependencies: Record = {}, + projectRoot: string = '.' +): PlatformDetectionResult { + const allDeps = {...dependencies, ...devDependencies}; + const signals: DetectionSignal[] = []; + const platformScores = new Map(); + + // STEP 1: Check for Ignite UI packages (HIGH confidence - 100) + for (const [platform, patterns] of Object.entries(IGNITE_PACKAGE_PATTERNS) as [Platform, string[]][]) { + for (const pattern of patterns) { + if (pattern in allDeps) { + signals.push({type: 'ignite_package', package: pattern, confidence: 100}); + const current = platformScores.get(platform) || 0; + platformScores.set(platform, Math.max(current, 100)); + } + } + } + + // STEP 2: Check config files (MEDIUM-HIGH confidence - 80, or 100 for Blazor with IgniteUI) + const configSignals = detectConfigFiles(projectRoot); + for (const signal of configSignals) { + signals.push({type: 'config_file', file: signal.file, confidence: signal.confidence}); + const current = platformScores.get(signal.platform) || 0; + platformScores.set(signal.platform, Math.max(current, signal.confidence)); + } + + // STEP 3: Check framework packages (LOW confidence - 40) + // Only add if we don't already have a high-confidence signal for this platform + for (const [pkg, platform] of Object.entries(FRAMEWORK_PACKAGE_PATTERNS)) { + if (pkg in allDeps) { + const currentScore = platformScores.get(platform) || 0; + if (currentScore < 60) { + // Only use framework fallback if no better signal exists + signals.push({type: 'framework_package', package: pkg, confidence: 40}); + platformScores.set(platform, Math.max(currentScore, 40)); + } + } + } + + // STEP 4: Analyze results + if (platformScores.size === 0) { + return { + platform: null, + confidence: 'none', + signals: [], + reason: 'No Ignite UI packages, framework packages, or config files detected', + }; + } + + // Sort platforms by score (highest first) + const sorted = Array.from(platformScores.entries()).sort((a, b) => b[1] - a[1]); + const [topPlatform, topScore] = sorted[0]; + + // Check for ambiguous case (multiple platforms with significant scores) + const ambiguousThreshold = 60; + const significantPlatforms = sorted.filter(([, score]) => score >= ambiguousThreshold); + + if (significantPlatforms.length > 1) { + // Build alternatives array with their signals + const alternatives: PlatformAlternative[] = significantPlatforms.map(([platform, score]) => { + const platformSignals = signals.filter((s) => { + if (s.type === 'ignite_package') { + return IGNITE_PACKAGE_PATTERNS[platform]?.includes(s.package); + } + if (s.type === 'config_file') { + return configSignals.some((cs) => cs.platform === platform && cs.file === s.file); + } + if (s.type === 'framework_package') { + return FRAMEWORK_PACKAGE_PATTERNS[s.package] === platform; + } + return false; + }); + + return { + platform, + confidence: score, + signals: platformSignals, + }; + }); + + return { + platform: null, + confidence: 'none', + ambiguous: true, + alternatives, + signals, + reason: `Multiple platforms detected: ${alternatives.map((a) => a.platform).join(', ')}. Please specify platform explicitly.`, + }; + } + + // Single platform detected - determine confidence level + let confidenceLevel: 'high' | 'medium' | 'low'; + if (topScore >= 80) { + confidenceLevel = 'high'; + } else if (topScore >= 60) { + confidenceLevel = 'medium'; + } else { + confidenceLevel = 'low'; + } + + // Find the detected package for backward compatibility + const detectedPackageSignal = signals.find( + (s) => s.type === 'ignite_package' && IGNITE_PACKAGE_PATTERNS[topPlatform]?.includes(s.package) + ) as PackageDetectionSignal | undefined; + + return { + platform: topPlatform, + confidence: confidenceLevel, + signals, + detectedPackage: detectedPackageSignal?.package, + reason: `Detected ${topPlatform} with ${confidenceLevel} confidence (score: ${topScore})`, + }; +} + +// ============================================================================ +// PLATFORM METADATA +// ============================================================================ + +/** + * Platform metadata for display purposes + */ +export const PLATFORM_METADATA = { + angular: { + id: 'angular', + name: 'Ignite UI for Angular', + shortName: 'Angular', + packageName: 'igniteui-angular', + themingModule: 'igniteui-angular/theming', + description: + 'Uses core() and theme() mixins from igniteui-angular/theming module. Requires ig-typography CSS class on root element.', + }, + webcomponents: { + id: 'webcomponents', + name: 'Ignite UI for Web Components', + shortName: 'Web Components', + packageName: 'igniteui-webcomponents', + themingModule: 'igniteui-theming', + description: + 'Uses igniteui-theming directly with palette(), typography(), and elevations() mixins. Supports runtime theme switching via configureTheme().', + }, + react: { + id: 'react', + name: 'Ignite UI for React', + shortName: 'React', + packageName: 'igniteui-react', + themingModule: 'igniteui-theming', + description: + 'Uses igniteui-theming directly with palette(), typography(), and elevations() mixins. Common with Vite or Next.js projects.', + }, + blazor: { + id: 'blazor', + name: 'Ignite UI for Blazor', + shortName: 'Blazor', + packageName: 'IgniteUI.Blazor', + themingModule: 'igniteui-theming', + description: + 'Uses igniteui-theming for Sass compilation in .NET Blazor projects. Theme styles are compiled to CSS and referenced in Blazor components.', + }, +} as const; diff --git a/src/mcp/knowledge/platforms/react.ts b/src/mcp/knowledge/platforms/react.ts new file mode 100644 index 00000000..7e63233d --- /dev/null +++ b/src/mcp/knowledge/platforms/react.ts @@ -0,0 +1,158 @@ +/** + * Ignite UI for React Platform Knowledge + * + * This module contains platform-specific information for generating + * valid Sass theme code for Ignite UI for React applications. + * + * Key characteristics: + * - Uses `igniteui-theming` directly (same as Web Components) + * - No `core()` or `theme()` mixins - uses individual mixins: `palette()`, `typography()`, `elevations()` + * - Commonly used with Vite, Next.js, or Create React App + * - Components use CSS variables for theming (--ig-* naming convention) + * - Theming approach is identical to Web Components + */ + +export const REACT_PLATFORM = { + id: 'react', + name: 'Ignite UI for React', + packageName: 'igniteui-react', + + /** + * The Sass module to import for theming + */ + themingModule: 'igniteui-theming', + + /** + * Detection patterns in package.json dependencies + */ + detectionPatterns: ['igniteui-react', '@infragistics/igniteui-react'], + + /** + * Config files that indicate a React project + */ + configFiles: ['vite.config.ts', 'vite.config.js', 'next.config.js', 'next.config.mjs'], + + /** + * No required root class (themes apply via CSS variables on :root) + */ + rootClass: null, +} as const; + +/** + * Example usage documentation for React + */ +export const REACT_USAGE_EXAMPLES = { + basic: ` +// Basic Material Light Theme for React (Vite) +// In your styles.scss or theme.scss file: + +@use 'igniteui-theming/sass/color/presets/light/material' as *; +@use 'igniteui-theming' as *; +@use 'igniteui-theming/sass/typography/presets/material' as *; +@use 'igniteui-theming/sass/elevations/presets' as *; + +:root { + --ig-theme: material; + --ig-theme-variant: light; + --ig-size-small: 1; + --ig-size-medium: 2; + --ig-size-large: 3; + --ig-scrollbar-size: #{rem(16px)}; +} + +@include palette($palette); +@include elevations($material-elevations); +@include typography( + $font-family: $typeface, + $type-scale: $type-scale +); +@include spacing(); +`, + + viteConfig: ` +// vite.config.ts - Sass configuration for Ignite UI theming +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + css: { + preprocessorOptions: { + scss: { + // Add node_modules to include paths for @use statements + includePaths: ['node_modules'], + }, + }, + }, +}); +`, + + nextjsConfig: ` +// next.config.js - Sass configuration for Next.js +const path = require('path'); + +module.exports = { + sassOptions: { + includePaths: [path.join(__dirname, 'node_modules')], + }, +}; +`, + + customPalette: ` +// Custom Palette Theme for React +@use 'igniteui-theming' as *; +@use 'igniteui-theming/sass/typography/presets/material' as *; +@use 'igniteui-theming/sass/elevations/presets' as *; + +$my-palette: palette( + $primary: #2ab759, + $secondary: #f96a88, + $surface: #ffffff +); + +:root { + --ig-theme: material; + --ig-theme-variant: light; + --ig-size-small: 1; + --ig-size-medium: 2; + --ig-size-large: 3; +} + +@include palette($my-palette); +@include elevations($material-elevations); +@include typography( + $font-family: $typeface, + $type-scale: $type-scale +); +@include spacing(); +`, + + darkTheme: ` +// Dark Indigo Theme for React +@use 'igniteui-theming' as *; +@use 'igniteui-theming/sass/typography/presets/indigo' as *; +@use 'igniteui-theming/sass/elevations/presets' as *; + +:root { + --ig-theme: indigo; + --ig-theme-variant: dark; + --ig-size-small: 1; + --ig-size-medium: 2; + --ig-size-large: 3; +} + +@include palette($palette); +@include elevations($indigo-elevations); +@include typography( + $font-family: $typeface, + $type-scale: $type-scale +); +@include spacing(); +`, +} as const; + +/** + * Note: React uses the same Sass code generation as Web Components. + * The generateWebComponentsThemeSass function from webcomponents.ts can be reused for React. + * The only difference is in how the Sass files are imported and bundled (Vite vs Angular CLI). + */ diff --git a/src/mcp/knowledge/platforms/webcomponents.ts b/src/mcp/knowledge/platforms/webcomponents.ts new file mode 100644 index 00000000..cf86f9cf --- /dev/null +++ b/src/mcp/knowledge/platforms/webcomponents.ts @@ -0,0 +1,565 @@ +/** + * Ignite UI for Web Components Platform Knowledge + * + * This module contains platform-specific information for generating + * valid Sass theme code for Ignite UI for Web Components applications. + * + * Key differences from Angular: + * - Uses `igniteui-theming` directly (not forwarded through another module) + * - No `core()` or `theme()` mixins - uses individual mixins: `palette()`, `typography()`, `elevations()` + * - Ships precompiled CSS themes, but users can install igniteui-theming for custom Sass themes + * - Components use ThemingController for runtime theme switching via CSS variables + * - Generated CSS variables follow --ig-* naming convention + */ + +import { + quoteFontFamily, + generateUseStatement, + generatePaletteCode, + generateTypographyCode, + generateElevationsCode, +} from '../../utils/sass.js'; +import { DesignSystem, ThemeVariant } from '../../utils/types.js'; +import {PALETTE_PRESETS, type PalettePresetName} from '../palettes.js'; +import { ELEVATIONS, PALETTE_PRESETS_PATHS, TYPOGRAPHY_PRESETS_PATHS } from './common.js'; + +export const WEBCOMPONENTS_PLATFORM = { + id: 'webcomponents', + name: 'Ignite UI for Web Components', + packageName: 'igniteui-webcomponents', + + /** + * The Sass module to import for theming + */ + themingModule: 'igniteui-theming', + + /** + * Detection patterns in package.json dependencies + */ + detectionPatterns: ['igniteui-webcomponents', '@infragistics/igniteui-webcomponents'], + + /** + * No required root class (themes apply via CSS variables on :root) + */ + rootClass: null, +} as const; + +/** + * Template for generating a complete Web Components theme + */ +export interface WebComponentsThemeTemplate { + designSystem: DesignSystem; + variant: ThemeVariant; + primaryColor?: string; + secondaryColor?: string; + surfaceColor?: string; + grayColor?: string; + customPaletteName?: string; + /** Custom font family (e.g., "'Inter', sans-serif") */ + fontFamily?: string; + includeTypography?: boolean; + includeElevations?: boolean; + includeSpacing?: boolean; +} + +// ============================================================================ +// HELPER FUNCTIONS FOR CODE GENERATION +// These smaller functions make the code more testable and maintainable +// ============================================================================ + +/** + * Generate the file header comment for Web Components themes. + */ +export function generateWCHeader(): string[] { + return ['// Generated by Ignite UI Theming MCP Server', '// Platform: Ignite UI for Web Components', '']; +} + +/** + * Get the elevation preset variable for a design system. + */ +export function getWCElevationPreset(designSystem: DesignSystem): string { + return ELEVATIONS[designSystem]; +} + +/** + * Generate import statements for a Web Components theme. + */ +export function generateWCImports(options: { + designSystem: DesignSystem; + variant: ThemeVariant; + hasCustomColors: boolean; + includeTypography: boolean; + includeElevations: boolean; +}): string[] { + const {designSystem, variant, hasCustomColors, includeTypography, includeElevations} = options; + const lines: string[] = []; + + if (hasCustomColors) { + // Custom palette: import main module first + lines.push('// Import the theming module'); + lines.push(generateUseStatement('webcomponents')); + + if (includeTypography) { + const typographyModule = TYPOGRAPHY_PRESETS_PATHS[designSystem]; + lines.push(`@use '${typographyModule}' as *;`); + } + + if (includeElevations) { + lines.push("@use 'igniteui-theming/sass/elevations/presets' as *;"); + } + } else { + // Preset palette: import palette first, then theming module + const paletteModule = PALETTE_PRESETS_PATHS[variant][designSystem]; + lines.push('// Import palette preset'); + lines.push(`@use '${paletteModule}' as *;`); + lines.push(''); + lines.push('// Import base theme configuration'); + lines.push(generateUseStatement('webcomponents')); + + if (includeTypography) { + const typographyModule = TYPOGRAPHY_PRESETS_PATHS[designSystem]; + lines.push(`@use '${typographyModule}' as *;`); + } + + if (includeElevations) { + lines.push("@use 'igniteui-theming/sass/elevations/presets' as *;"); + } + } + + return lines; +} + +/** + * Generate CSS @property declarations for progress tracking. + * These are required by some components. + */ +export function generateWCProgressProperties(indent = ''): string[] { + return [ + `${indent}@property --_progress-integer {`, + `${indent} syntax: '';`, + `${indent} initial-value: 0;`, + `${indent} inherits: true;`, + `${indent}}`, + '', + `${indent}@property --_progress-fraction {`, + `${indent} syntax: '';`, + `${indent} initial-value: 0;`, + `${indent} inherits: true;`, + `${indent}}`, + ]; +} + +/** + * Generate :root CSS variables for theme configuration. + */ +export function generateWCRootVariables(options: { + designSystem: DesignSystem; + variant: ThemeVariant; + usePaletteMap?: boolean; + indent?: string; +}): string[] { + const {designSystem, variant, usePaletteMap = false, indent = ''} = options; + const lines: string[] = []; + + lines.push(`${indent}:root {`); + + if (usePaletteMap) { + // When using a palette variable, get theme from the palette's metadata + lines.push(`${indent} --ig-theme: #{map.get($palette, '_meta', 'variant')};`); + lines.push(`${indent} --ig-theme-variant: #{$variant};`); + } else { + // When using preset palette, use literal values + lines.push(`${indent} --ig-theme: ${designSystem};`); + lines.push(`${indent} --ig-theme-variant: ${variant};`); + } + + lines.push(`${indent} --ig-size-small: 1;`); + lines.push(`${indent} --ig-size-medium: 2;`); + lines.push(`${indent} --ig-size-large: 3;`); + lines.push(`${indent} --ig-scrollbar-size: #{rem(16px)};`); + lines.push(`${indent}}`); + + return lines; +} + +/** + * Generate RTL direction support. + */ +export function generateWCRtlSupport(indent = ''): string[] { + return [`${indent}body[dir='rtl'] {`, `${indent} --ig-dir: -1;`, `${indent}}`]; +} + +/** + * Generate scrollbar customization using palette colors. + */ +export function generateWCScrollbarCustomization(): string[] { + return [ + '// Scrollbar customization', + ':root {', + ' --ig-scrollbar-thumb-background: #{color($color: gray, $variant: 400)};', + ' --ig-scrollbar-track-background: #{color($color: gray, $variant: 100)};', + '}', + ]; +} + +/** + * Generate theming mixin calls (palette, elevations, typography, spacing). + */ +export function generateWCThemingMixins(options: { + paletteVar: string; + typefaceValue: string; + elevationsVar: string; + includeTypography: boolean; + includeElevations: boolean; + includeSpacing: boolean; + indent?: string; + addComments?: boolean; +}): string[] { + const { + paletteVar, + typefaceValue, + elevationsVar, + includeTypography, + includeElevations, + includeSpacing, + indent = '', + addComments = false, + } = options; + + const lines: string[] = []; + + // Palette mixin + if (addComments) lines.push(`${indent}// Apply palette CSS variables`); + lines.push(`${indent}@include palette(${paletteVar});`); + if (addComments) lines.push(''); + + // Elevations mixin + if (includeElevations) { + if (addComments) lines.push(`${indent}// Apply elevation CSS variables`); + lines.push(...generateElevationsCode({elevationsVar, indent})); + if (addComments) lines.push(''); + } + + // Typography mixin + if (includeTypography) { + if (addComments) lines.push(`${indent}// Apply typography CSS variables`); + lines.push( + ...generateTypographyCode({ + fontFamily: typefaceValue, + typeScaleVar: '$type-scale', + indent, + }), + ); + if (addComments) lines.push(''); + } + + // Spacing mixin + if (includeSpacing) { + if (addComments) lines.push(`${indent}// Apply spacing CSS variables`); + lines.push(`${indent}@include spacing();`); + } + + return lines; +} + +/** + * Generate a custom palette theme with a theme() mixin wrapper. + */ +function generateCustomPaletteTheme( + template: WebComponentsThemeTemplate, + typefaceValue: string, +): string[] { + const { + designSystem, + variant, + primaryColor, + secondaryColor, + surfaceColor, + grayColor, + customPaletteName = '$my-palette', + includeTypography = true, + includeElevations = true, + includeSpacing = true, + } = template; + + const lines: string[] = []; + + // Get default colors from the preset + const presetName = `${variant}-${designSystem}-palette` as PalettePresetName; + const presetColors = PALETTE_PRESETS[presetName]; + + const effectivePrimary = primaryColor || presetColors.primary; + const effectiveSecondary = secondaryColor || presetColors.secondary; + const effectiveSurface = surfaceColor || presetColors.surface; + + // Generate palette code + const paletteResult = generatePaletteCode({ + primary: effectivePrimary, + secondary: effectiveSecondary, + surface: effectiveSurface, + gray: grayColor, + variableName: customPaletteName.replace(/^\$/, ''), + useVariableReferences: true, + }); + + lines.push('// Custom color palette'); + lines.push(...paletteResult.colorVariables); + lines.push(''); + lines.push(...paletteResult.paletteDefinition); + lines.push(''); + + // Generate theme() mixin wrapper + lines.push('// Theme configuration'); + lines.push('@mixin theme($palette, $variant) {'); + lines.push(' // Root-level CSS custom properties'); + lines.push(...generateWCProgressProperties(' ')); + lines.push(''); + lines.push(...generateWCRootVariables({designSystem, variant, usePaletteMap: true, indent: ' '})); + lines.push(''); + lines.push(...generateWCRtlSupport(' ')); + lines.push(''); + lines.push( + ...generateWCThemingMixins({ + paletteVar: '$palette', + typefaceValue, + elevationsVar: getWCElevationPreset(designSystem), + includeTypography, + includeElevations, + includeSpacing, + indent: ' ', + }), + ); + lines.push('}'); + lines.push(''); + lines.push('// Apply the theme'); + lines.push(`@include theme(${paletteResult.variableName}, '${variant}');`); + + return lines; +} + +/** + * Generate a preset palette theme (uses predefined palette from design system). + */ +function generatePresetPaletteTheme( + template: WebComponentsThemeTemplate, + typefaceValue: string, +): string[] { + const {designSystem, variant, includeTypography = true, includeElevations = true, includeSpacing = true} = template; + + const lines: string[] = []; + + // Scrollbar customization (uses color() function from palette preset) + lines.push(...generateWCScrollbarCustomization()); + lines.push(''); + + // Progress properties at root level + lines.push(...generateWCProgressProperties()); + lines.push(''); + + // Root variables + lines.push(...generateWCRootVariables({designSystem, variant})); + lines.push(''); + + // RTL support + lines.push(...generateWCRtlSupport()); + lines.push(''); + + // Theming mixins with comments + lines.push( + ...generateWCThemingMixins({ + paletteVar: '$palette', + typefaceValue, + elevationsVar: getWCElevationPreset(designSystem), + includeTypography, + includeElevations, + includeSpacing, + addComments: true, + }), + ); + + return lines; +} + +/** + * Generate Sass code for a Web Components theme + * + * Web Components themes use igniteui-theming directly and call individual + * mixins (palette, typography, elevations) rather than a unified theme() mixin. + * + * This function orchestrates smaller helper functions for: + * - Header generation (generateWCHeader) + * - Import statements (generateWCImports) + * - Custom or preset palette themes + */ +export function generateWebComponentsThemeSass(template: WebComponentsThemeTemplate): string { + const { + designSystem, + variant, + primaryColor, + secondaryColor, + surfaceColor, + fontFamily, + includeTypography = true, + includeElevations = true, + } = template; + + // Determine the font-family value to use + const typefaceValue = fontFamily ? quoteFontFamily(fontFamily) : '$typeface'; + + // Determine if using custom or preset palette + const hasCustomColors = !!(primaryColor || secondaryColor || surfaceColor); + + // Build the output + const lines: string[] = []; + + // Header + lines.push(...generateWCHeader()); + + // Import statements + lines.push( + ...generateWCImports({ + designSystem, + variant, + hasCustomColors, + includeTypography, + includeElevations, + }), + ); + lines.push(''); + + // Theme body (custom or preset) + if (hasCustomColors) { + lines.push(...generateCustomPaletteTheme(template, typefaceValue)); + } else { + lines.push(...generatePresetPaletteTheme(template, typefaceValue)); + } + + return lines.join('\n'); +} + +/** + * Example usage documentation + */ +export const WEBCOMPONENTS_USAGE_EXAMPLES = { + basic: ` +// Basic Material Light Theme for Web Components +@use 'igniteui-theming/sass/color/presets/light/material' as *; +@use 'igniteui-theming' as *; +@use 'igniteui-theming/sass/typography/presets/material' as *; +@use 'igniteui-theming/sass/elevations/presets' as *; + +:root { + --ig-theme: material; + --ig-theme-variant: light; + --ig-size-small: 1; + --ig-size-medium: 2; + --ig-size-large: 3; + --ig-scrollbar-size: #{rem(16px)}; +} + +@include palette($palette); +@include elevations($material-elevations); +@include typography( + $font-family: $typeface, + $type-scale: $type-scale +); +@include spacing(); +`, + + customPalette: ` +// Custom Palette Theme for Web Components +@use 'igniteui-theming' as *; +@use 'igniteui-theming/sass/typography/presets/material' as *; +@use 'igniteui-theming/sass/elevations/presets' as *; + +$my-palette: palette( + $primary: #2ab759, + $secondary: #f96a88, + $surface: #ffffff +); + +:root { + --ig-theme: material; + --ig-theme-variant: light; + --ig-size-small: 1; + --ig-size-medium: 2; + --ig-size-large: 3; +} + +@include palette($my-palette); +@include elevations($material-elevations); +@include typography( + $font-family: $typeface, + $type-scale: $type-scale +); +@include spacing(); +`, + + darkTheme: ` +// Dark Indigo Theme for Web Components +@use 'igniteui-theming/sass/color/presets/dark/indigo' as *; +@use 'igniteui-theming' as *; +@use 'igniteui-theming/sass/typography/presets/indigo' as *; +@use 'igniteui-theming/sass/elevations/presets' as *; + +:root { + --ig-theme: indigo; + --ig-theme-variant: dark; + --ig-size-small: 1; + --ig-size-medium: 2; + --ig-size-large: 3; +} + +@include palette($palette); +@include elevations($indigo-elevations); +@include typography( + $font-family: $typeface, + $type-scale: $type-scale +); +@include spacing(); +`, + + minimalConfig: ` +// Minimal theme (palette only, no typography/elevations) +@use 'igniteui-theming/sass/color/presets/light/bootstrap' as *; +@use 'igniteui-theming' as *; + +:root { + --ig-theme: bootstrap; + --ig-theme-variant: light; +} + +@include palette($palette); +`, +} as const; + +/** + * Runtime theme configuration for Web Components + * + * Web Components support runtime theme switching via the configureTheme() function + * and CSS variables. This is different from Angular which requires Sass recompilation. + */ +export const WEBCOMPONENTS_RUNTIME_CONFIG = { + /** + * JavaScript API for runtime theme switching + */ + configureThemeAPI: ` +import { configureTheme } from 'igniteui-webcomponents'; + +// Switch to dark material theme at runtime +configureTheme('material', 'dark'); + +// Switch to light indigo theme +configureTheme('indigo', 'light'); +`, + + /** + * CSS variables that control the theme at runtime + */ + runtimeVariables: ['--ig-theme', '--ig-theme-variant'], + + /** + * Events dispatched during theme changes + */ + themeChangeEvents: ['igc-change-theme', 'igc-changed-theme'], +} as const; diff --git a/src/mcp/knowledge/sass-api.ts b/src/mcp/knowledge/sass-api.ts new file mode 100644 index 00000000..64e89a51 --- /dev/null +++ b/src/mcp/knowledge/sass-api.ts @@ -0,0 +1,430 @@ +/** + * Sass API Manifest + * + * This module centralizes all knowledge about the igniteui-theming Sass API. + * When the Sass framework changes, update this file to propagate changes + * throughout the MCP server codebase. + * + * This manifest defines: + * - Function signatures and parameters + * - Mixin signatures and parameters + * - Variable naming conventions + * - CSS custom property patterns + * - Import paths for different platforms + */ + +import { + PALETTE_COLOR_GROUPS, + type Platform, + type DesignSystem, + type ThemeVariant, + type ElevationPreset, +} from '../utils/types.js'; + +// ============================================================================ +// IMPORT PATHS +// ============================================================================ + +/** + * Import paths for the theming library by platform. + */ +export const IMPORT_PATHS = { + /** Ignite UI for Angular theming module (forwards igniteui-theming with overrides) */ + angular: 'igniteui-angular/theming', + + /** Direct igniteui-theming module for Web Components */ + webcomponents: 'igniteui-theming', + + /** Direct igniteui-theming module for React */ + react: 'igniteui-theming', + + /** Direct igniteui-theming module for Blazor */ + blazor: 'igniteui-theming', + + /** Default for platform-agnostic code */ + default: 'igniteui-theming', +} as const; + +/** + * Get the appropriate import path for a platform. + */ +export function getImportPath(platform?: Platform): string { + switch (platform) { + case 'webcomponents': + return IMPORT_PATHS.webcomponents; + case 'react': + return IMPORT_PATHS.react; + case 'blazor': + return IMPORT_PATHS.blazor; + case 'angular': + return IMPORT_PATHS.angular; + default: + return IMPORT_PATHS.default; + } +} + +// ============================================================================ +// PALETTE FUNCTION +// ============================================================================ + +/** + * Parameters for the palette() Sass function. + */ +export interface PaletteFunctionParams { + /** Primary brand color (required) */ + primary: string; + /** Secondary/accent color (required) */ + secondary: string; + /** Surface/background color (required) */ + surface: string; + /** Gray base color (optional - auto-generated from surface if not provided) */ + gray?: string; + /** Info state color (optional) */ + info?: string; + /** Success state color (optional) */ + success?: string; + /** Warning state color (optional) */ + warn?: string; + /** Error state color (optional) */ + error?: string; +} + +/** + * Metadata about the palette() function. + */ +export const PALETTE_FUNCTION = { + name: 'palette', + + /** Required parameters (must always be provided) */ + requiredParams: ['primary', 'secondary', 'surface'] as const, + + /** Optional parameters */ + optionalParams: ['gray', 'info', 'success', 'warn', 'error'] as const, + + /** Default variable name pattern */ + defaultVariablePattern: '$custom-{variant}-palette', + + /** Description for documentation */ + description: + 'Creates a color palette map from base colors. Automatically generates shade variants (50-900, A100-A700) for each color using internal algorithms.', +} as const; + +// ============================================================================ +// SHADES FUNCTION +// ============================================================================ + +/** + * Parameters for the shades() Sass function. + * Used for generating shade variants from a single base color. + */ +export interface ShadesFunctionParams { + /** Color group name (e.g., 'primary', 'secondary') */ + colorName: string; + /** Base color to generate shades from */ + baseColor: string; + /** List of shade levels to generate */ + shadeLevels: readonly string[]; + /** Surface color (required for gray shades to calculate proper contrast) */ + surface?: string; +} + +/** + * Metadata about the shades() function. + */ +export const SHADES_FUNCTION = { + name: 'shades', + + /** Description for documentation */ + description: 'Generates a shade map from a base color. Creates contrast-accessible shade variants automatically.', + + /** Chromatic shade levels (for primary, secondary, etc.) */ + chromaticShadeLevels: [ + '50', + '100', + '200', + '300', + '400', + '500', + '600', + '700', + '800', + '900', + 'A100', + 'A200', + 'A400', + 'A700', + ] as const, + + /** Gray shade levels (no accent shades) */ + grayShadeLevels: ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900'] as const, +} as const; + +// ============================================================================ +// TYPOGRAPHY MIXIN +// ============================================================================ + +/** + * Parameters for the typography() mixin. + */ +export interface TypographyMixinParams { + /** Font family string (e.g., "'Inter', sans-serif") */ + fontFamily: string; + /** Type scale variable reference (e.g., '$material-type-scale') */ + typeScale: string; +} + +/** + * Metadata about the typography() mixin. + */ +export const TYPOGRAPHY_MIXIN = { + name: 'typography', + + /** Parameter names in order */ + params: ['$font-family', '$type-scale'] as const, + + /** Description for documentation */ + description: 'Applies typography CSS custom properties for font sizes, weights, line heights, and letter spacing.', + + /** CSS class required on root element (Angular only) */ + angularRootClass: 'ig-typography', +} as const; + +// ============================================================================ +// ELEVATIONS MIXIN +// ============================================================================ + +/** + * Parameters for the elevations() mixin. + */ +export interface ElevationsMixinParams { + /** Elevations variable reference (e.g., '$material-elevations') */ + elevations: string; +} + +/** + * Metadata about the elevations() mixin. + */ +export const ELEVATIONS_MIXIN = { + name: 'elevations', + + /** Parameter names */ + params: ['$elevations'] as const, + + /** Number of elevation levels (0-24) */ + levelCount: 25, + + /** Description for documentation */ + description: 'Applies elevation CSS custom properties for box-shadow values at 25 levels (0-24).', +} as const; + +// ============================================================================ +// PALETTE MIXIN +// ============================================================================ + +/** + * Parameters for the palette() mixin (applies palette to CSS variables). + */ +export interface PaletteMixinParams { + /** Palette variable reference (e.g., '$my-palette') */ + palette: string; +} + +/** + * Metadata about the palette() mixin. + */ +export const PALETTE_MIXIN = { + name: 'palette', + + /** Description for documentation */ + description: 'Applies a palette map as CSS custom properties (--ig-* variables).', +} as const; + +// ============================================================================ +// SPACING MIXIN (Web Components only) +// ============================================================================ + +/** + * Metadata about the spacing() mixin. + */ +export const SPACING_MIXIN = { + name: 'spacing', + + /** Platforms that support this mixin */ + supportedPlatforms: ['webcomponents', 'react', 'blazor'] as const, + + /** Description for documentation */ + description: 'Applies spacing CSS custom properties for consistent margins and paddings.', +} as const; + +// ============================================================================ +// ANGULAR-SPECIFIC MIXINS +// ============================================================================ + +/** + * Parameters for the core() mixin (Angular only). + */ +export interface CoreMixinParams { + /** Include/exclude styles for printing */ + printLayout?: boolean; + /** Enable enhanced accessibility colors */ + enhancedAccessibility?: boolean; +} + +/** + * Metadata about the core() mixin. + */ +export const CORE_MIXIN = { + name: 'core', + + /** Platforms that support this mixin */ + supportedPlatforms: ['angular'] as const, + + /** Description for documentation */ + description: 'Provides base definitions for theming. Must be included before theme() mixin.', + + /** Optional parameters with defaults */ + optionalParams: { + '$print-layout': true, + '$enhanced-accessibility': false, + }, +} as const; + +/** + * Parameters for the theme() mixin (Angular only). + */ +export interface ThemeMixinParams { + /** Palette map to use */ + palette: string; + /** Schema to use for component styling */ + schema: string; + /** Global roundness factor (0 to 1) */ + roundness?: number; + /** Enable/disable elevations */ + elevation?: boolean; + /** Custom elevations map */ + elevations?: string; + /** Components to exclude from theming */ + exclude?: string[]; +} + +/** + * Metadata about the theme() mixin. + */ +export const THEME_MIXIN = { + name: 'theme', + + /** Platforms that support this mixin */ + supportedPlatforms: ['angular'] as const, + + /** Required parameters */ + requiredParams: ['$palette', '$schema'] as const, + + /** Optional parameters */ + optionalParams: ['$roundness', '$elevation', '$elevations', '$exclude'] as const, + + /** Description for documentation */ + description: 'Generates styles for all components using the specified palette and schema.', +} as const; + +// ============================================================================ +// CSS CUSTOM PROPERTY PATTERNS +// ============================================================================ + +/** + * CSS custom property naming patterns used by the theming library. + */ +export const CSS_VARIABLE_PATTERNS = { + /** Theme identifier */ + theme: '--ig-theme', + /** Theme variant (light/dark) */ + themeVariant: '--ig-theme-variant', + /** Component size levels */ + sizes: { + small: '--ig-size-small', + medium: '--ig-size-medium', + large: '--ig-size-large', + }, + /** Scrollbar customization */ + scrollbar: { + size: '--ig-scrollbar-size', + thumbBackground: '--ig-scrollbar-thumb-background', + trackBackground: '--ig-scrollbar-track-background', + }, + /** RTL direction multiplier */ + direction: '--ig-dir', + /** Color function pattern: --ig-{color}-{shade} */ + colorPattern: '--ig-{color}-{shade}', + /** Elevation pattern: --ig-elevation-{level} */ + elevationPattern: '--ig-elevation-{level}', + /** Typography patterns */ + typography: { + fontFamily: '--ig-font-family', + fontSize: '--ig-font-size-{category}', + fontWeight: '--ig-font-weight-{category}', + lineHeight: '--ig-line-height-{category}', + letterSpacing: '--ig-letter-spacing-{category}', + }, +} as const; + +// ============================================================================ +// VARIABLE NAMING CONVENTIONS +// ============================================================================ + +/** + * Variable naming patterns for the theming library. + */ +export const VARIABLE_PATTERNS = { + /** Palette variable: ${variant}-${designSystem}-palette */ + palettePreset: (variant: ThemeVariant, designSystem: DesignSystem) => `$${variant}-${designSystem}-palette`, + + /** Schema variable: ${variant}-${designSystem}-schema */ + schema: (variant: ThemeVariant, designSystem: DesignSystem) => `$${variant}-${designSystem}-schema`, + + /** Typeface variable: ${designSystem}-typeface */ + typeface: (designSystem: DesignSystem) => `$${designSystem}-typeface`, + + /** Type scale variable: ${designSystem}-type-scale */ + typeScale: (designSystem: DesignSystem) => `$${designSystem}-type-scale`, + + /** Elevations variable: ${preset}-elevations */ + elevations: (preset: ElevationPreset) => `$${preset}-elevations`, + + /** Custom palette variable */ + customPalette: (name: string, variant: ThemeVariant) => `$${name}-${variant}-palette`, +} as const; + +// ============================================================================ +// HELPER FUNCTIONS +// ============================================================================ + +/** + * Get the appropriate elevations variable for a design system. + */ +export function getElevationsVariable(designSystem: DesignSystem): string { + // Only material and indigo have elevation presets; others use material + const preset: ElevationPreset = designSystem === 'indigo' ? 'indigo' : 'material'; + return VARIABLE_PATTERNS.elevations(preset); +} + +/** + * Check if a mixin is supported on a given platform. + */ +export function isMixinSupported(mixin: 'core' | 'theme' | 'spacing', platform?: Platform): boolean { + switch (mixin) { + case 'core': + case 'theme': + return platform === 'angular'; + case 'spacing': + return platform !== 'angular'; + default: + return true; + } +} + +/** + * Get all color groups that should be in a palette. + * Returns the canonical list from types.ts. + */ +export function getPaletteColorGroups(): readonly string[] { + return PALETTE_COLOR_GROUPS; +} diff --git a/src/mcp/knowledge/typography.ts b/src/mcp/knowledge/typography.ts new file mode 100644 index 00000000..a16b7b85 --- /dev/null +++ b/src/mcp/knowledge/typography.ts @@ -0,0 +1,66 @@ +/** + * Typography presets for each design system. + * These are loaded from the JSON files generated by buildJSON.mjs + * which is the single source of truth from the Sass code. + */ + +import typescalesData from '../../../json/typography/presets/typescales.json' with {type: 'json'}; +import type {DesignSystem} from '../utils/types.js'; + +// Re-export DesignSystem for backwards compatibility +export type {DesignSystem} from '../utils/types.js'; + +export interface TypeStyle { + 'font-family': string; + 'font-size': string; + 'font-weight': string; + 'font-style': string; + 'line-height': string; + 'letter-spacing': string; + 'text-transform': string; + 'margin-top'?: string; + 'margin-bottom'?: string; +} + +export interface TypeScale { + typeface: string; + h1: TypeStyle; + h2: TypeStyle; + h3: TypeStyle; + h4: TypeStyle; + h5: TypeStyle; + h6: TypeStyle; + 'subtitle-1': TypeStyle; + 'subtitle-2': TypeStyle; + 'body-1': TypeStyle; + 'body-2': TypeStyle; + button: TypeStyle; + caption: TypeStyle; + overline: TypeStyle; +} + +/** + * Typography presets loaded from JSON. + */ +export const TYPOGRAPHY_PRESETS = typescalesData as Record; + +/** + * Type scale category names. + */ +export const TYPE_SCALE_CATEGORIES = [ + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'subtitle-1', + 'subtitle-2', + 'body-1', + 'body-2', + 'button', + 'caption', + 'overline', +] as const; + +export type TypeScaleCategory = (typeof TYPE_SCALE_CATEGORIES)[number]; diff --git a/src/mcp/resources/index.ts b/src/mcp/resources/index.ts new file mode 100644 index 00000000..bec77d82 --- /dev/null +++ b/src/mcp/resources/index.ts @@ -0,0 +1,10 @@ +/** + * Resources index - exports all resource handlers. + */ + +export { + RESOURCE_SCHEME, + RESOURCE_URIS, + RESOURCE_DEFINITIONS, + getResourceContent, +} from './presets.js'; diff --git a/src/mcp/resources/presets.ts b/src/mcp/resources/presets.ts new file mode 100644 index 00000000..2fb6bf9a --- /dev/null +++ b/src/mcp/resources/presets.ts @@ -0,0 +1,417 @@ +/** + * Resource handlers for preset data. + * Provides access to palette, typography, elevation presets, and platform information. + */ + +import { + PALETTE_PRESETS, + LIGHT_PALETTE_PRESETS, + DARK_PALETTE_PRESETS, + TYPOGRAPHY_PRESETS, + ELEVATION_PRESETS, + PLATFORM_METADATA, + ANGULAR_PLATFORM, + ANGULAR_USAGE_EXAMPLES, + WEBCOMPONENTS_PLATFORM, + WEBCOMPONENTS_USAGE_EXAMPLES, + WEBCOMPONENTS_RUNTIME_CONFIG, + COLOR_VARIANT_RULES, + COLOR_GUIDANCE_MARKDOWN, + COLOR_RULES_SUMMARY, + COLOR_SEMANTIC_ROLES, + COLOR_USAGE_MARKDOWN, + OPACITY_USAGE, + STATE_PATTERNS, + THEME_PATTERNS, + TYPEFACE_PRESETS, + TYPE_SCALE_PRESETS, + ELEVATIONS_PRESETS, + SCHEMA_PRESETS, + REACT_PLATFORM, + REACT_USAGE_EXAMPLES, + BLAZOR_PLATFORM, + BLAZOR_USAGE_EXAMPLES, +} from '../knowledge/index.js'; + +/** + * Resource URI scheme. + */ +export const RESOURCE_SCHEME = 'theming'; + +/** + * Available resource URIs. + */ +export const RESOURCE_URIS = { + // Platform resources + PLATFORMS: `${RESOURCE_SCHEME}://platforms`, + PLATFORM_ANGULAR: `${RESOURCE_SCHEME}://platforms/angular`, + PLATFORM_WEBCOMPONENTS: `${RESOURCE_SCHEME}://platforms/webcomponents`, + PLATFORM_REACT: `${RESOURCE_SCHEME}://platforms/react`, + PLATFORM_BLAZOR: `${RESOURCE_SCHEME}://platforms/blazor`, + // Preset resources + PALETTES: `${RESOURCE_SCHEME}://presets/palettes`, + PALETTES_LIGHT: `${RESOURCE_SCHEME}://presets/palettes/light`, + PALETTES_DARK: `${RESOURCE_SCHEME}://presets/palettes/dark`, + TYPOGRAPHY: `${RESOURCE_SCHEME}://presets/typography`, + ELEVATIONS: `${RESOURCE_SCHEME}://presets/elevations`, + // Color guidance resources (organized under colors/ parent) + GUIDANCE_COLORS: `${RESOURCE_SCHEME}://guidance/colors`, + GUIDANCE_COLORS_RULES: `${RESOURCE_SCHEME}://guidance/colors/rules`, + GUIDANCE_COLORS_USAGE: `${RESOURCE_SCHEME}://guidance/colors/usage`, + GUIDANCE_COLORS_ROLES: `${RESOURCE_SCHEME}://guidance/colors/roles`, + GUIDANCE_COLORS_STATES: `${RESOURCE_SCHEME}://guidance/colors/states`, + GUIDANCE_COLORS_THEMES: `${RESOURCE_SCHEME}://guidance/colors/themes`, +} as const; + +/** + * Resource definitions for MCP server. + */ +export const RESOURCE_DEFINITIONS = [ + // Platform resources + { + uri: RESOURCE_URIS.PLATFORMS, + name: 'Supported Platforms', + description: 'List of supported target platforms with their configurations', + mimeType: 'application/json', + }, + { + uri: RESOURCE_URIS.PLATFORM_ANGULAR, + name: 'Angular Platform', + description: 'Ignite UI for Angular platform configuration, schemas, palettes, and usage examples', + mimeType: 'application/json', + }, + { + uri: RESOURCE_URIS.PLATFORM_WEBCOMPONENTS, + name: 'Web Components Platform', + description: 'Ignite UI for Web Components platform configuration, presets, and usage examples', + mimeType: 'application/json', + }, + { + uri: RESOURCE_URIS.PLATFORM_REACT, + name: 'React Platform', + description: 'Ignite UI for React platform configuration, schemas, palettes, and usage examples', + mimeType: 'application/json', + }, + { + uri: RESOURCE_URIS.PLATFORM_BLAZOR, + name: 'Blazor Platform', + description: 'Ignite UI for Blazor platform configuration, schemas, palettes, and usage examples', + mimeType: 'application/json', + }, + // Preset resources + { + uri: RESOURCE_URIS.PALETTES, + name: 'All Palette Presets', + description: 'All predefined color palette configurations (light and dark variants for each design system)', + mimeType: 'application/json', + }, + { + uri: RESOURCE_URIS.PALETTES_LIGHT, + name: 'Light Palette Presets', + description: 'Light mode color palette configurations', + mimeType: 'application/json', + }, + { + uri: RESOURCE_URIS.PALETTES_DARK, + name: 'Dark Palette Presets', + description: 'Dark mode color palette configurations', + mimeType: 'application/json', + }, + { + uri: RESOURCE_URIS.TYPOGRAPHY, + name: 'Typography Presets', + description: 'Typography presets for all design systems (Material, Bootstrap, Fluent, Indigo)', + mimeType: 'application/json', + }, + { + uri: RESOURCE_URIS.ELEVATIONS, + name: 'Elevation Presets', + description: 'Elevation/shadow presets (Material and Indigo)', + mimeType: 'application/json', + }, + // Color guidance resources (organized under colors/ parent) + { + uri: RESOURCE_URIS.GUIDANCE_COLORS, + name: 'Color Guidance', + description: + 'Overview of all color guidance resources. Lists available sub-resources for theme rules, shade reference, semantic roles, interaction states, and design system patterns.', + mimeType: 'application/json', + }, + { + uri: RESOURCE_URIS.GUIDANCE_COLORS_RULES, + name: 'Light & Dark Theme Rules', + description: + 'Guidelines for choosing surface and gray colors based on theme variant (light/dark). Explains luminance requirements and contrast considerations.', + mimeType: 'text/markdown', + }, + { + uri: RESOURCE_URIS.GUIDANCE_COLORS_USAGE, + name: 'Shade Reference', + description: + 'Comprehensive guide explaining which shades (50-900) to use for different purposes across Ignite UI components. Includes shade-level guidance for all color families.', + mimeType: 'text/markdown', + }, + { + uri: RESOURCE_URIS.GUIDANCE_COLORS_ROLES, + name: 'Color Roles', + description: + 'Structured data defining the semantic meaning of each color family (primary, secondary, gray, surface, error, success, warn, info). Includes component mappings and opacity usage.', + mimeType: 'application/json', + }, + { + uri: RESOURCE_URIS.GUIDANCE_COLORS_STATES, + name: 'Interaction States', + description: + 'Patterns showing how colors change across interaction states (idle, hover, focus, active, disabled) for common UI elements like buttons, list items, and inputs.', + mimeType: 'application/json', + }, + { + uri: RESOURCE_URIS.GUIDANCE_COLORS_THEMES, + name: 'Design System Patterns', + description: + 'Color usage characteristics specific to Material, Fluent, Bootstrap, and Indigo design systems.', + mimeType: 'application/json', + }, +]; + +// ============================================================================ +// RESOURCE CONTENT HANDLERS +// Using a Map for better maintainability and easier extension +// ============================================================================ + +type ResourceHandler = () => {content: string; mimeType: string}; + +/** + * Map of URI to content handler function. + * Lazily evaluates content to avoid unnecessary JSON serialization. + */ +const RESOURCE_HANDLERS: Map = new Map([ + // Platform resources + [ + RESOURCE_URIS.PLATFORMS, + () => ({ + content: JSON.stringify( + { + platforms: ['angular', 'webcomponents', 'react', 'blazor'], + metadata: PLATFORM_METADATA, + }, + null, + 2, + ), + mimeType: 'application/json', + }), + ], + [ + RESOURCE_URIS.PLATFORM_ANGULAR, + () => ({ + content: JSON.stringify( + { + platform: ANGULAR_PLATFORM, + schemas: SCHEMA_PRESETS, + palettes: PALETTE_PRESETS, + typefaces: TYPEFACE_PRESETS, + typeScales: TYPE_SCALE_PRESETS, + elevations: ELEVATIONS_PRESETS, + usageExamples: ANGULAR_USAGE_EXAMPLES, + }, + null, + 2, + ), + mimeType: 'application/json', + }), + ], + [ + RESOURCE_URIS.PLATFORM_WEBCOMPONENTS, + () => ({ + content: JSON.stringify( + { + platform: WEBCOMPONENTS_PLATFORM, + schemas: SCHEMA_PRESETS, + palettes: PALETTE_PRESETS, + typefaces: TYPEFACE_PRESETS, + typography: TYPOGRAPHY_PRESETS, + elevations: ELEVATION_PRESETS, + usageExamples: WEBCOMPONENTS_USAGE_EXAMPLES, + runtimeConfig: WEBCOMPONENTS_RUNTIME_CONFIG, + }, + null, + 2, + ), + mimeType: 'application/json', + }), + ], + [ + RESOURCE_URIS.PLATFORM_REACT, + () => ({ + content: JSON.stringify( + { + platform: REACT_PLATFORM, + schemas: SCHEMA_PRESETS, + palettes: PALETTE_PRESETS, + typefaces: TYPEFACE_PRESETS, + typography: TYPOGRAPHY_PRESETS, + elevations: ELEVATION_PRESETS, + usageExamples: REACT_USAGE_EXAMPLES, + }, + null, + 2, + ), + mimeType: 'application/json', + }), + ], + [ + RESOURCE_URIS.PLATFORM_BLAZOR, + () => ({ + content: JSON.stringify( + { + platform: BLAZOR_PLATFORM, + schemas: SCHEMA_PRESETS, + palettes: PALETTE_PRESETS, + typefaces: TYPEFACE_PRESETS, + typography: TYPOGRAPHY_PRESETS, + elevations: ELEVATION_PRESETS, + usageExamples: BLAZOR_USAGE_EXAMPLES, + }, + null, + 2, + ), + mimeType: 'application/json', + }), + ], + + // Preset resources + [ + RESOURCE_URIS.PALETTES, + () => ({ + content: JSON.stringify(PALETTE_PRESETS, null, 2), + mimeType: 'application/json', + }), + ], + [ + RESOURCE_URIS.PALETTES_LIGHT, + () => ({ + content: JSON.stringify(LIGHT_PALETTE_PRESETS, null, 2), + mimeType: 'application/json', + }), + ], + [ + RESOURCE_URIS.PALETTES_DARK, + () => ({ + content: JSON.stringify(DARK_PALETTE_PRESETS, null, 2), + mimeType: 'application/json', + }), + ], + [ + RESOURCE_URIS.TYPOGRAPHY, + () => ({ + content: JSON.stringify(TYPOGRAPHY_PRESETS, null, 2), + mimeType: 'application/json', + }), + ], + [ + RESOURCE_URIS.ELEVATIONS, + () => ({ + content: JSON.stringify(ELEVATION_PRESETS, null, 2), + mimeType: 'application/json', + }), + ], + + // Color guidance resources + [ + RESOURCE_URIS.GUIDANCE_COLORS, + () => ({ + content: JSON.stringify( + { + description: 'Color guidance resources for Ignite UI Theming', + resources: [ + { + uri: RESOURCE_URIS.GUIDANCE_COLORS_RULES, + name: 'Light & Dark Theme Rules', + description: 'Guidelines for surface/gray colors based on theme variant', + mimeType: 'text/markdown', + }, + { + uri: RESOURCE_URIS.GUIDANCE_COLORS_USAGE, + name: 'Shade Reference', + description: 'Which shades (50-900) to use for different purposes', + mimeType: 'text/markdown', + }, + { + uri: RESOURCE_URIS.GUIDANCE_COLORS_ROLES, + name: 'Color Roles', + description: 'Semantic meaning of each color family', + mimeType: 'application/json', + }, + { + uri: RESOURCE_URIS.GUIDANCE_COLORS_STATES, + name: 'Interaction States', + description: 'Color changes across hover/focus/active/disabled', + mimeType: 'application/json', + }, + { + uri: RESOURCE_URIS.GUIDANCE_COLORS_THEMES, + name: 'Design System Patterns', + description: 'Material/Fluent/Bootstrap/Indigo characteristics', + mimeType: 'application/json', + }, + ], + }, + null, + 2, + ), + mimeType: 'application/json', + }), + ], + [ + RESOURCE_URIS.GUIDANCE_COLORS_RULES, + () => ({ + content: COLOR_GUIDANCE_MARKDOWN, + mimeType: 'text/markdown', + }), + ], + [ + RESOURCE_URIS.GUIDANCE_COLORS_USAGE, + () => ({ + content: COLOR_USAGE_MARKDOWN, + mimeType: 'text/markdown', + }), + ], + [ + RESOURCE_URIS.GUIDANCE_COLORS_ROLES, + () => ({ + content: JSON.stringify( + { + semanticRoles: COLOR_SEMANTIC_ROLES, + variantRules: COLOR_VARIANT_RULES, + rulesSummary: COLOR_RULES_SUMMARY, + opacityUsage: OPACITY_USAGE, + }, + null, + 2, + ), + mimeType: 'application/json', + }), + ], + [ + RESOURCE_URIS.GUIDANCE_COLORS_STATES, + () => ({ + content: JSON.stringify(STATE_PATTERNS, null, 2), + mimeType: 'application/json', + }), + ], + [ + RESOURCE_URIS.GUIDANCE_COLORS_THEMES, + () => ({ + content: JSON.stringify(THEME_PATTERNS, null, 2), + mimeType: 'application/json', + }), + ], +]); + +/** + * Get resource content by URI. + */ +export function getResourceContent(uri: string): {content: string; mimeType: string} | null { + const handler = RESOURCE_HANDLERS.get(uri); + return handler ? handler() : null; +} diff --git a/src/mcp/tools/descriptions.ts b/src/mcp/tools/descriptions.ts new file mode 100644 index 00000000..22ca0adb --- /dev/null +++ b/src/mcp/tools/descriptions.ts @@ -0,0 +1,616 @@ +/** + * Centralized descriptions for MCP tools and their parameters. + * + * Uses XML-like tags for structured content that helps AI models + * understand tool purpose, workflows, and constraints. + * + * Structure: + * - FRAGMENTS: Reusable text snippets for common concepts + * - TOOL_DESCRIPTIONS: Full tool descriptions with XML sections + * - PARAM_DESCRIPTIONS: Individual parameter descriptions + */ + +// ============================================================================ +// REUSABLE FRAGMENTS +// ============================================================================ + +/** + * Reusable text fragments for common concepts. + * Used to maintain consistency across descriptions. + */ +export const FRAGMENTS = { + /** Platform parameter description */ + PLATFORM: `Target platform: "angular" for Ignite UI for Angular, "webcomponents" for Ignite UI for Web Components, "react" for Ignite UI for React, or "blazor" for Ignite UI for Blazor. If omitted, generates generic code. Use detect_platform tool first to auto-detect from project files.`, + + /** Color format examples - CSS Color Level 4 */ + COLOR_FORMAT: `Valid CSS color formats: hex ("#3F51B5", "#3F51B5AA"), rgb/rgba ("rgb(63, 81, 181)", "rgb(63 81 181 / 0.5)"), hsl/hsla ("hsl(231, 48%, 48%)", "hsl(231 48% 48% / 0.5)"), hwb ("hwb(231 20% 30%)"), lab/lch ("lab(50% 40 59)", "lch(50% 80 30)"), oklab/oklch ("oklab(59% 0.1 0.1)", "oklch(60% 0.15 50)"), color() for wide-gamut ("color(display-p3 1 0.5 0)"), or CSS named colors ("indigo", "rebeccapurple").`, + + /** Variant parameter description */ + VARIANT: `Theme variant: "light" (light backgrounds, dark text) or "dark" (dark backgrounds, light text). Defaults to "light".`, + + /** Design system parameter description */ + DESIGN_SYSTEM: `Design system preset: "material" (Material Design), "bootstrap" (Bootstrap), "fluent" (Microsoft Fluent), or "indigo" (Infragistics Indigo). Defaults to "material".`, + + /** Chromatic shade levels */ + CHROMATIC_SHADES: `14 shades required: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, A100, A200, A400, A700`, + + /** Gray shade levels */ + GRAY_SHADES: `10 shades required: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900`, + + /** Luminance warning */ + LUMINANCE_WARNING: `Colors with extreme luminance (< 0.05 or > 0.45) may produce suboptimal automatic shade generation.`, + + /** Monochromatic requirement for chromatic colors */ + MONOCHROMATIC_RULE: `MONOCHROMATIC REQUIREMENT: All shades in a color group (e.g., primary) must be the SAME HUE. Shades are lighter/darker versions of ONE color, NOT different colors. Example: primary shades should all be blue (#E3F2FD → #0D47A1), not blue→green→purple. Vary only lightness and saturation, keep hue constant (±30° tolerance).`, + + /** Resource scheme */ + RESOURCE_SCHEME: 'theming://', +} as const; + +// ============================================================================ +// TOOL DESCRIPTIONS +// ============================================================================ + +/** + * Comprehensive tool descriptions with XML-structured sections. + * These are shown to AI models when listing available tools. + */ +export const TOOL_DESCRIPTIONS = { + // --------------------------------------------------------------------------- + // detect_platform - Simple tool + // --------------------------------------------------------------------------- + detect_platform: `Detect the target Ignite UI platform by analyzing package.json dependencies and project config files. + + + Use this tool FIRST before generating any theme code to ensure platform-optimized output. + The detected platform determines the correct Sass module paths and syntax. + + + + Uses multi-signal detection with confidence scoring: + 1. Ignite UI packages (HIGH - 100): igniteui-angular, igniteui-webcomponents, igniteui-react, IgniteUI.Blazor + 2. Config files (MEDIUM-HIGH - 80): angular.json, vite.config.*, next.config.*, .csproj + 3. Framework packages (LOW - 40): @angular/core, react, lit (fallback only) + + + + Returns: + - platform: "angular" | "webcomponents" | "react" | "blazor" | null + - confidence: "high" | "medium" | "low" | "none" + - ambiguous: true if multiple platforms detected (requires user to specify explicitly) + - alternatives: Array of detected platforms when ambiguous + - signals: Array of detection signals found + - detectedPackage: The primary package that triggered detection + - platformInfo: Name, theming module path, and description + + + + When multiple platforms are detected with significant confidence (≥60), returns: + - platform: null + - ambiguous: true + - alternatives: List of possible platforms with their signals + - Action: User must specify platform explicitly in subsequent tool calls + + + + After detection, use the platform value with: + - create_palette: Generate color palette + - create_theme: Generate complete theme + - create_typography: Set up typography + - create_elevations: Configure shadows +`, + + // --------------------------------------------------------------------------- + // create_palette - Medium complexity + // --------------------------------------------------------------------------- + create_palette: `Generate a color palette for Ignite UI themes using the palette() Sass function. + + + Use this tool when you have base colors and want to auto-generate a complete palette + with all shade variations (50-900, A100-A700). Best for colors with mid-range luminance + that will produce good automatic shade distribution. + + + + 1. Validates input colors against the theme variant + 2. Analyzes color luminance for shade generation suitability + 3. Generates Sass code using the palette() function + 4. Adds warning comments to code if issues detected + 5. Returns validation warnings and tips in response + + + + - Requires primary, secondary, and surface colors (matches Sass palette() API) + - Gray, info, success, warn, error are optional (use design system defaults) + - Surface color should match variant: light colors for "light", dark for "dark" + - ${FRAGMENTS.LUMINANCE_WARNING} + + SHADE PROGRESSION (important): + - Primary, secondary, and all chromatic colors: shades are NEVER inverted. + The palette() function always generates 50=lightest to 900=darkest. + - Only gray shades behave differently based on variant (for text contrast). + - DO NOT manually invert primary/secondary colors for dark themes. + + + + Returns: + - Generated Sass code with palette() function call + - Platform-specific module imports + - Validation warnings (if any colors have issues) + - Variable name created (e.g., $my-palette) + + + + - Invalid color format: Returns error with format examples + - Variant mismatch: Warns if surface color doesn't match theme variant + - Luminance issues: Warns with recommendation to use create_custom_palette + + + + Blue brand with orange accent on light theme: + { + "primary": "#1976D2", + "secondary": "#FF9800", + "surface": "#FAFAFA", + "variant": "light" + } + + + + - detect_platform: Run first to get correct platform value + - create_custom_palette: Use if this tool warns about luminance issues + - create_theme: Use instead if you want palette + typography + elevations together + + + + - theming://presets/palettes: View available preset palette colors + - theming://guidance/colors: Color guidance overview + - theming://guidance/colors/rules: Light/dark theme color rules +`, + + // --------------------------------------------------------------------------- + // create_custom_palette - Complex tool + // --------------------------------------------------------------------------- + create_custom_palette: `Generate a custom color palette with fine-grained control over individual shade values. + +⚠️ CRITICAL RULES - READ BEFORE GENERATING SHADES: +1. MONOCHROMATIC: Each color (primary, secondary, etc.) must use ONE HUE only. + All 14 shades are lighter/darker versions of the SAME color. + Example: primary blue → all shades must be blue (#E3F2FD light → #0D47A1 dark). + WRONG: mixing blue, green, purple in one color's shades. +2. NEVER INVERT: Chromatic colors always go 50=lightest → 900=darkest. + This applies to BOTH light and dark themes. Only gray inverts for dark themes. + + + Use this tool when: + - The standard palette() function produces suboptimal shade distribution + - You have brand guidelines specifying exact color values for each shade + - Base colors are too light (luminance > 0.45) or too dark (< 0.05) + - You have specific accessibility audit requirements with exact contrast color values (rare - auto-generated contrast is usually sufficient) + - You want to mix auto-generated and manually specified color groups + + + + 1. For each color group, choose a mode: + - mode:"shades" → Auto-generate all shades from baseColor using shades() function + - mode:"explicit" → Manually specify every shade value + 2. Validates all explicit shades for: + - Completeness: All required shades present + - Color format: Valid CSS color values + - Luminance progression: 50 lightest → 900 darkest (chromatic colors) + - Hue consistency: All shades within ±30° hue tolerance (monochromatic) + 3. Generates Sass code with color() map structure + 4. Returns any validation warnings + + + + CRITICAL - SHADE PROGRESSION RULES: + - CHROMATIC colors (primary, secondary, surface, info, success, warn, error): + Shade 50 = ALWAYS lightest, shade 900 = ALWAYS darkest. + This is TRUE FOR BOTH light AND dark themes. NEVER invert chromatic colors. + - GRAY color ONLY: Inverts for dark themes (50=darkest, 900=lightest). + - DO NOT confuse these rules. Only gray inverts, never primary/secondary/etc. + + ⚠️ CRITICAL - MONOCHROMATIC REQUIREMENT: + Each color group (primary, secondary, etc.) must contain shades of ONE COLOR ONLY. + Shades are lighter/darker variations of the SAME hue - NOT different colors! + + CORRECT example for primary blue: + 50: "#E3F2FD" (very light blue) + 500: "#2196F3" (medium blue) + 900: "#0D47A1" (dark blue) + → All shades are BLUE, just different lightness levels + + WRONG example (DO NOT DO THIS): + 50: "#E3F2FD" (light blue) + 500: "#4CAF50" (green) ← WRONG! Different hue + 900: "#9C27B0" (purple) ← WRONG! Different hue + → This creates a rainbow, not a shade palette + + Rule: Keep hue constant (±30° tolerance), vary only lightness and saturation. + + CHROMATIC COLORS (primary, secondary, surface, info, success, warn, error): + - Explicit mode requires ${FRAGMENTS.CHROMATIC_SHADES} + - Shade 50 = lightest, shade 900 = darkest (SAME for light AND dark themes) + - ALL shades must be the SAME HUE (monochromatic) - see requirement above + - A100-A700 are accent shades (same hue, typically more saturated) + + GRAY COLOR (the ONLY color that inverts): + - Explicit mode requires ${FRAGMENTS.GRAY_SHADES} + - LIGHT themes: 50 = lightest (near white), 900 = darkest (near black) + - DARK themes: 50 = darkest, 900 = lightest (INVERTED progression) + - Gray inverts because text/UI elements need to contrast against the surface + + CONTRAST COLORS (AUTO-GENERATED - DO NOT PROVIDE): + - DO NOT include contrastOverrides in your input - OMIT THIS FIELD ENTIRELY + - The system AUTOMATICALLY generates contrast colors using adaptive-contrast() + - For each shade, the generated Sass output will include: + '500': #4CAF50, + '500-contrast': adaptive-contrast(#4CAF50), ← AUTO-GENERATED + '500-raw': #4CAF50, + - The adaptive-contrast() function auto-selects black or white for readability + - Only provide contrastOverrides if you have a specific accessibility audit + requiring exact contrast color values (this is extremely rare) + + MIXING MODES: + - You can use "shades" mode for some colors and "explicit" for others + - Example: explicit primary, shades-based secondary and surface + + + + Returns: + - Generated Sass code with color() map definitions + - Summary of which colors use shades() vs explicit values + - Variable name created (e.g., $custom-light-palette) + - Validation warnings (if any) + + + + Validation FAILS (returns error, no code generated) if: + - Missing required shades in explicit mode + - Invalid CSS color format in any shade + + Validation WARNS (generates code with warnings) if: + - Luminance progression incorrect (50 darker than 900) + - Hue inconsistency detected (shades not monochromatic) + - Gray progression doesn't match variant (light vs dark) + + + + Brand green with exact shades (NOTE: ALL shades are GREEN - same hue, different lightness): + + INPUT (what you provide - NO contrastOverrides needed): + { + "variant": "light", + "primary": { + "mode": "explicit", + "shades": { + "50": "#E8F5E9", + "100": "#C8E6C9", + "200": "#A5D6A7", + "300": "#81C784", + "400": "#66BB6A", + "500": "#4CAF50", + "600": "#43A047", + "700": "#388E3C", + "800": "#2E7D32", + "900": "#1B5E20", + "A100": "#B9F6CA", + "A200": "#69F0AE", + "A400": "#00E676", + "A700": "#00C853" + } + // ↑ Only provide shades - contrast colors are AUTO-GENERATED + }, + "secondary": { "mode": "shades", "baseColor": "#FF9800" }, + "surface": { "mode": "shades", "baseColor": "#FAFAFA" } + } + + GENERATED OUTPUT (contrast colors added automatically): + 'primary': ( + '500': #4CAF50, + '500-contrast': adaptive-contrast(#4CAF50), // ← AUTO-GENERATED + '500-raw': #4CAF50, // ← AUTO-GENERATED + // ... same pattern for all 14 shades + ) + + + + - detect_platform: Run first to get correct platform value + - create_palette: Use for simpler cases with mid-range luminance colors + - create_theme: Does not support custom palettes; use this tool + manual theme assembly + + + + ❌ WRONG - DO NOT create shades like this (different hues = broken palette): + { + "primary": { + "mode": "explicit", + "shades": { + "50": "#E3F2FD", // blue + "100": "#DCEDC8", // green ← WRONG HUE + "200": "#FFF9C4", // yellow ← WRONG HUE + "500": "#9C27B0", // purple ← WRONG HUE + "900": "#BF360C" // red-brown ← WRONG HUE + } + } + } + This creates a rainbow, not a shade palette. Components will look broken. + + + + - theming://presets/palettes: View preset palette colors for reference + - theming://guidance/colors/usage: Which shades to use for different purposes + - theming://guidance/colors/roles: Semantic meaning of each color family +`, + + // --------------------------------------------------------------------------- + // create_typography - Medium complexity + // --------------------------------------------------------------------------- + create_typography: `Set up typography for Ignite UI themes with custom font families and type scales. + + + Use this tool to configure fonts that match your brand identity while maintaining + consistent sizing, line heights, and letter spacing based on design system conventions. + + + + 1. Takes font family string and optional design system preset + 2. Generates Sass code using the typography() mixin + 3. Applies the type scale from the selected design system + 4. Optionally applies custom scale overrides + + + + - Font family string should include fallbacks for cross-platform compatibility + - Quote font names that contain spaces: '"Segoe UI"' not 'Segoe UI' + - Design system affects: font sizes, line heights, letter spacing, font weights + - Type styles include: h1-h6, subtitle-1/2, body-1/2, button, caption, overline + + + + Returns: + - Generated Sass code with typography() mixin call + - Platform-specific module imports + - Variable name used (e.g., $my-typography) + + + + - Empty font family: Returns error requesting valid font family string + + + + Modern sans-serif typography for Material Design: + { + "fontFamily": "'Inter', 'Segoe UI', 'Helvetica Neue', sans-serif", + "designSystem": "material" + } + + + + - detect_platform: Run first to get correct platform value + - create_theme: Use instead if you want typography + palette + elevations together + + + + - theming://presets/typography: View typography presets for all design systems +`, + + // --------------------------------------------------------------------------- + // create_elevations - Simple tool + // --------------------------------------------------------------------------- + create_elevations: `Set up elevation shadows for Ignite UI themes. + + + Use this tool to configure box-shadow values that provide visual depth and hierarchy. + Elevations follow Material Design or Indigo design specifications. + + + + 1. Selects elevation preset based on design system parameter + 2. Generates Sass code using the elevations() mixin + 3. Creates 24 elevation levels (0-24) with corresponding shadow values + + + + - "material" preset: Material Design 3 shadow specifications + - "indigo" preset: Infragistics Indigo shadow specifications + - Elevation 0 = no shadow, elevation 24 = maximum shadow depth + - Components use elevation() function to apply specific levels + + + + Returns: + - Generated Sass code with elevations() mixin call + - Platform-specific module imports + - Variable name used (e.g., $my-elevations) + + + + - detect_platform: Run first to get correct platform value + - create_theme: Use instead if you want elevations + palette + typography together + + + + - theming://presets/elevations: View elevation presets for Material and Indigo +`, + + // --------------------------------------------------------------------------- + // create_theme - Complex tool + // --------------------------------------------------------------------------- + create_theme: `Generate a complete, production-ready Ignite UI theme with palette, typography, and elevations. + + + Use this tool as the starting point for new projects. It generates everything needed + for a working theme in a single operation: color palette, typography setup, elevation + shadows, and the theme application mixin. + + + + 1. Analyzes input colors for palette shade generation suitability + 2. Creates color palette using palette() function + 3. Sets up typography with specified font family (if includeTypography: true) + 4. Configures elevations based on design system (if includeElevations: true) + 5. Configures spacing utilities for Web Components (if includeSpacing: true) + 6. Applies the theme using the theme() mixin + 7. Returns luminance warnings if any colors may produce poor shades + + + + REQUIRED COLORS: + - primaryColor: Main brand color + - secondaryColor: Accent/highlight color + - surfaceColor: Background color (should match variant) + + SHADE PROGRESSION (important): + - Primary and secondary colors are NEVER inverted between light/dark themes. + - The palette() function generates shades 50=lightest to 900=darkest for ALL + chromatic colors regardless of theme variant. + - Only gray shades behave differently (for text contrast against surface). + - DO NOT provide inverted primary/secondary colors for dark themes. + + LUMINANCE ANALYSIS: + - ${FRAGMENTS.LUMINANCE_WARNING} + - If warnings appear, consider using create_custom_palette for those colors + + PLATFORM DIFFERENCES: + - Angular: Uses igniteui-angular/theming with core() and theme() mixins + - Web Components: Uses igniteui-theming directly with palette(), typography(), elevations() mixins + - React: Uses igniteui-theming directly (same as Web Components), common with Vite/Next.js + - Blazor: Uses igniteui-theming for Sass compilation, theme CSS referenced in Blazor components + + + + Returns: + - Complete Sass code with all theme components + - Luminance analysis warnings (if applicable) + - List of variables created/used + - Platform-specific guidance + + + + - Invalid color format: Returns error with format examples + - Luminance issues: Warns but still generates code (may produce suboptimal shades) + - Variant mismatch: Warns if surface color doesn't match theme variant + + + + Complete Material Design blue theme: + { + "platform": "angular", + "designSystem": "material", + "primaryColor": "#1976D2", + "secondaryColor": "#FF9800", + "surfaceColor": "#FAFAFA", + "variant": "light", + "fontFamily": "'Roboto', sans-serif", + "includeTypography": true, + "includeElevations": true + } + + + + After generating a theme: + 1. Review any luminance warnings in the output + 2. If warnings suggest shade generation issues: + - Use create_custom_palette for problematic colors + - Manually assemble theme with custom palette + 3. Import the generated Sass file in your application's main styles + 4. Customize individual component themes as needed using component schema overrides + + + + - detect_platform: Run first to auto-detect platform from package.json + - create_custom_palette: Use for colors that produce luminance warnings + - create_palette: Use if you only need a palette without full theme + - create_typography: Use if you only need typography setup + - create_elevations: Use if you only need elevation shadows + + + + - theming://presets/palettes: View available preset palette colors + - theming://guidance/colors: Color guidance overview + - theming://guidance/colors/rules: Light/dark theme color rules + - theming://platforms/angular: Angular platform configuration + - theming://platforms/webcomponents: Web Components platform configuration + - theming://platforms/react: React platform configuration + - theming://platforms/blazor: Blazor platform configuration +`, +} as const; + +// ============================================================================ +// PARAMETER DESCRIPTIONS +// ============================================================================ + +/** + * Individual parameter descriptions for schema fields. + * Include valid values, defaults, formats, and constraints. + */ +export const PARAM_DESCRIPTIONS = { + // --------------------------------------------------------------------------- + // Common parameters (used across multiple tools) + // --------------------------------------------------------------------------- + platform: FRAGMENTS.PLATFORM, + variant: FRAGMENTS.VARIANT, + designSystem: FRAGMENTS.DESIGN_SYSTEM, + name: `Custom variable name (without $ prefix). If omitted, auto-generates based on tool and variant (e.g., "custom-light", "my-theme").`, + + // --------------------------------------------------------------------------- + // detect_platform parameters + // --------------------------------------------------------------------------- + packageJsonPath: `Path to package.json file, relative to current working directory. Defaults to "./package.json".`, + + // --------------------------------------------------------------------------- + // Color parameters (for create_palette) + // --------------------------------------------------------------------------- + primary: `Primary brand color - used for main actions, active states, and emphasis. ${FRAGMENTS.COLOR_FORMAT}`, + secondary: `Secondary/accent color - used for FABs, selection controls, highlights. ${FRAGMENTS.COLOR_FORMAT}`, + surface: `Surface/background color - should be light for "light" variant, dark for "dark" variant. ${FRAGMENTS.COLOR_FORMAT}`, + gray: `Gray/neutral base color for text, borders, disabled states. Optional - defaults from design system preset. ${FRAGMENTS.COLOR_FORMAT}`, + info: `Info state color (typically blue) for informational messages. Optional - defaults from design system. ${FRAGMENTS.COLOR_FORMAT}`, + success: `Success state color (typically green) for success messages and positive actions. Optional - defaults from design system. ${FRAGMENTS.COLOR_FORMAT}`, + warn: `Warning state color (typically orange/amber) for warning messages. Optional - defaults from design system. ${FRAGMENTS.COLOR_FORMAT}`, + error: `Error state color (typically red) for error messages and destructive actions. Optional - defaults from design system. ${FRAGMENTS.COLOR_FORMAT}`, + + // --------------------------------------------------------------------------- + // Typography parameters + // --------------------------------------------------------------------------- + fontFamily: `Font family string with fallbacks. Quote names with spaces. Example: '"Inter", "Helvetica Neue", sans-serif'`, + customScale: `Custom type scale overrides. Object with type style names as keys (h1, h2, body-1, button, etc.) and style objects as values containing fontSize, fontWeight, lineHeight, letterSpacing, textTransform.`, + + // --------------------------------------------------------------------------- + // Elevations parameters + // --------------------------------------------------------------------------- + elevationPreset: `Elevation shadow preset: "material" (Material Design shadows) or "indigo" (Infragistics Indigo shadows). Defaults to "material".`, + + // --------------------------------------------------------------------------- + // Theme-specific parameters (for create_theme) + // --------------------------------------------------------------------------- + primaryColor: `Primary brand color for the theme - used for main actions and emphasis. ${FRAGMENTS.COLOR_FORMAT}`, + secondaryColor: `Secondary/accent color for the theme - used for highlights and selection. ${FRAGMENTS.COLOR_FORMAT}`, + surfaceColor: `Surface/background color for the theme. Use light colors (#FAFAFA) for "light" variant, dark colors (#121212) for "dark" variant. ${FRAGMENTS.COLOR_FORMAT}`, + includeTypography: `Include typography setup in the generated theme. Set to false if you want to configure typography separately. Defaults to true.`, + includeElevations: `Include elevation shadows in the generated theme. Set to false if you want to configure elevations separately. Defaults to true.`, + includeSpacing: `Include spacing CSS custom properties (Web Components platform only). Defaults to true. Has no effect on Angular platform.`, + + // --------------------------------------------------------------------------- + // Custom palette parameters (for create_custom_palette) + // --------------------------------------------------------------------------- + colorDefinition: `Color definition object with mode selection: +• mode: "shades" + baseColor: Auto-generates all shades from one color +• mode: "explicit" + shades: Manually specify all ${FRAGMENTS.CHROMATIC_SHADES} +IMPORTANT: All shades must be MONOCHROMATIC (same hue). Shades are lighter/darker versions of ONE color, not different colors.`, + + grayDefinition: `Gray color definition object with mode selection: +• mode: "shades" + baseColor: Auto-generates all shades from one color +• mode: "explicit" + shades: Manually specify all ${FRAGMENTS.GRAY_SHADES} +Important: Gray progression is INVERTED for dark themes (50=darkest, 900=lightest).`, + + baseColor: `Base color for automatic shade generation using shades() function. Choose a mid-luminance color (0.1-0.4) for best results. ${FRAGMENTS.COLOR_FORMAT}`, + + shades: `Object with all shade values. ${FRAGMENTS.CHROMATIC_SHADES}. Luminance should decrease from 50 (lightest) to 900 (darkest). CRITICAL: All shades must be the SAME COLOR (same hue) at different lightness levels - do NOT use different colors for different shades.`, + + grayShades: `Object with all gray shade values. ${FRAGMENTS.GRAY_SHADES}. For light themes: 50=lightest, 900=darkest. For dark themes: 50=darkest, 900=lightest.`, + + contrastOverrides: `USUALLY OMIT THIS FIELD. Contrast colors are auto-generated using adaptive-contrast(). Only provide this if you have specific accessibility requirements with exact contrast values (rare). When omitted (recommended), the generated Sass code automatically includes adaptive-contrast(#shadeColor) for each shade, which auto-selects black or white for optimal readability.`, +} as const; diff --git a/src/mcp/tools/handlers/custom-palette.ts b/src/mcp/tools/handlers/custom-palette.ts new file mode 100644 index 00000000..acb8991d --- /dev/null +++ b/src/mcp/tools/handlers/custom-palette.ts @@ -0,0 +1,151 @@ +/** + * Handler for create_custom_palette tool. + */ + +import {generateCustomPaletteCode, generateUseStatement, toVariableName, generateHeader} from '../../utils/sass.js'; +import {PALETTE_PRESETS, type PalettePresetName} from '../../knowledge/palettes.js'; +import {validateCustomPalette, formatCustomPaletteValidation} from '../../validators/index.js'; +import type {CreateCustomPaletteParams} from '../schemas.js'; +import type {ShadesBasedColor, ColorDefinition, GrayDefinition} from '../../utils/types.js'; + +export async function handleCreateCustomPalette(params: CreateCustomPaletteParams) { + const variant = params.variant ?? 'light'; + const designSystem = params.designSystem ?? 'material'; + const presetName = `${variant}-${designSystem}-palette` as PalettePresetName; + const preset = PALETTE_PRESETS[presetName]; + + // Determine surface color for gray generation + // If surface is explicit, extract a representative color (500 shade) + // If surface is shades-based, use the baseColor + let surfaceColorForGray: string; + if (params.surface.mode === 'shades') { + surfaceColorForGray = params.surface.baseColor; + } else { + surfaceColorForGray = params.surface.shades['500']; + } + + // Fill in missing colors with defaults from preset (using shades mode) + // Cast to our internal types since Zod schema generates slightly different types + const colors: { + primary: ColorDefinition; + secondary: ColorDefinition; + surface: ColorDefinition; + gray: GrayDefinition; + info: ColorDefinition; + success: ColorDefinition; + warn: ColorDefinition; + error: ColorDefinition; + } = { + primary: params.primary as ColorDefinition, + secondary: params.secondary as ColorDefinition, + surface: params.surface as ColorDefinition, + gray: (params.gray as GrayDefinition) ?? ({mode: 'shades', baseColor: preset.gray} as ShadesBasedColor), + info: (params.info as ColorDefinition) ?? ({mode: 'shades', baseColor: preset.info} as ShadesBasedColor), + success: (params.success as ColorDefinition) ?? ({mode: 'shades', baseColor: preset.success} as ShadesBasedColor), + warn: (params.warn as ColorDefinition) ?? ({mode: 'shades', baseColor: preset.warn} as ShadesBasedColor), + error: (params.error as ColorDefinition) ?? ({mode: 'shades', baseColor: preset.error} as ShadesBasedColor), + }; + + // Validate the custom palette structure (passing variant for gray progression validation) + const validation = await validateCustomPalette( + { + platform: params.platform, + variant, + designSystem, + name: params.name, + primary: colors.primary, + secondary: colors.secondary, + surface: colors.surface, + gray: colors.gray, + info: colors.info, + success: colors.success, + warn: colors.warn, + error: colors.error, + }, + variant, + ); + + if (!validation.isValid) { + const errorText = formatCustomPaletteValidation(validation); + return { + content: [ + { + type: 'text' as const, + text: `**Validation Failed**\n\n${errorText}\n\nPlease fix the errors and try again.`, + }, + ], + }; + } + + // Generate the Sass code + const paletteName = params.name ? toVariableName(params.name) : `custom-${variant}`; + const paletteLines = generateCustomPaletteCode({ + platform: params.platform, + variant, + variableName: paletteName, + surfaceColor: surfaceColorForGray, + colors, + }); + + const varName = `$${paletteName}-palette`; + + const code = `${generateHeader(`Custom ${variant} palette with explicit shade control`)} +${generateUseStatement(params.platform)} + +${paletteLines.join('\n')} + +// Apply the palette (generates CSS custom properties) +@include palette(${varName}); +`; + + // Build response + const responseParts: string[] = [`**Custom Palette Generated**`]; + responseParts.push(''); + responseParts.push(`Created a custom ${variant} color palette based on ${designSystem} defaults.`); + + // Add platform hint + const platformNote = params.platform + ? `Platform: ${params.platform === 'angular' ? 'Ignite UI for Angular' : 'Ignite UI for Web Components'}` + : 'Platform: Not specified (generic output). Specify `platform` for optimized code.'; + responseParts.push(''); + responseParts.push(platformNote); + + // Show which colors use which mode + const shadesMode = Object.entries(colors) + .filter(([_, def]) => def.mode === 'shades') + .map(([name]) => name); + const explicitMode = Object.entries(colors) + .filter(([_, def]) => def.mode === 'explicit') + .map(([name]) => name); + + responseParts.push(''); + if (shadesMode.length > 0) { + responseParts.push(`**Using shades() function:** ${shadesMode.join(', ')}`); + } + if (explicitMode.length > 0) { + responseParts.push(`**Using explicit shades:** ${explicitMode.join(', ')}`); + } + + responseParts.push(''); + responseParts.push(`**Variable:** \`${varName}\``); + + // Add warnings if any + if (validation.warnings.length > 0) { + responseParts.push(''); + responseParts.push(formatCustomPaletteValidation(validation)); + } + + responseParts.push(''); + responseParts.push('```scss'); + responseParts.push(code.trimEnd()); + responseParts.push('```'); + + return { + content: [ + { + type: 'text' as const, + text: responseParts.join('\n'), + }, + ], + }; +} diff --git a/src/mcp/tools/handlers/elevations.ts b/src/mcp/tools/handlers/elevations.ts new file mode 100644 index 00000000..518717a3 --- /dev/null +++ b/src/mcp/tools/handlers/elevations.ts @@ -0,0 +1,40 @@ +/** + * Handler for create_elevations tool. + */ + +import {generateElevations} from '../../generators/sass.js'; +import type {CreateElevationsParams} from '../schemas.js'; + +export function handleCreateElevations(params: CreateElevationsParams) { + const result = generateElevations({ + platform: params.platform, + designSystem: params.designSystem, + name: params.name, + }); + + // Build response text + const responseParts: string[] = [result.description]; + + // Add platform hint if not specified + const platformNote = params.platform + ? `Platform: ${params.platform === 'angular' ? 'Ignite UI for Angular' : 'Ignite UI for Web Components'}` + : 'Platform: Not specified (generic output). Specify `platform` for optimized code.'; + responseParts.push(''); + responseParts.push(platformNote); + + responseParts.push(''); + responseParts.push(`Variables used: ${result.variables.join(', ')}`); + responseParts.push(''); + responseParts.push('```scss'); + responseParts.push(result.code.trimEnd()); + responseParts.push('```'); + + return { + content: [ + { + type: 'text' as const, + text: responseParts.join('\n'), + }, + ], + }; +} diff --git a/src/mcp/tools/handlers/index.ts b/src/mcp/tools/handlers/index.ts new file mode 100644 index 00000000..048ca9ef --- /dev/null +++ b/src/mcp/tools/handlers/index.ts @@ -0,0 +1,10 @@ +/** + * Tool handlers index - re-exports all tool handlers. + */ + +export {handleDetectPlatform} from './platform.js'; +export {handleCreatePalette} from './palette.js'; +export {handleCreateCustomPalette} from './custom-palette.js'; +export {handleCreateTypography} from './typography.js'; +export {handleCreateElevations} from './elevations.js'; +export {handleCreateTheme} from './theme.js'; diff --git a/src/mcp/tools/handlers/palette.ts b/src/mcp/tools/handlers/palette.ts new file mode 100644 index 00000000..64f05f66 --- /dev/null +++ b/src/mcp/tools/handlers/palette.ts @@ -0,0 +1,81 @@ +/** + * Handler for create_palette tool. + */ + +import {generatePalette} from '../../generators/sass.js'; +import type {CreatePaletteParams} from '../schemas.js'; +import {validatePaletteColors, formatValidationResult, generateWarningComments} from '../../validators/index.js'; + +export async function handleCreatePalette(params: CreatePaletteParams) { + const variant = params.variant ?? 'light'; + + // Validate surface and gray colors against the variant + const validation = await validatePaletteColors({ + variant, + surface: params.surface, + gray: params.gray, + }); + + // Generate the palette code + const result = generatePalette({ + platform: params.platform, + primary: params.primary, + secondary: params.secondary, + surface: params.surface, + gray: params.gray, + info: params.info, + success: params.success, + warn: params.warn, + error: params.error, + variant: params.variant, + name: params.name, + }); + + // Add warning comments to the generated code if there are validation issues + let finalCode = result.code; + if (!validation.isValid) { + const warningComments = generateWarningComments(validation); + if (warningComments.length > 0) { + // Insert warning comments after the header but before the @use statement + const lines = finalCode.split('\n'); + const useIndex = lines.findIndex((line) => line.startsWith("@use '") || line.startsWith('@use "')); + if (useIndex > 0) { + lines.splice(useIndex, 0, ...warningComments, ''); + finalCode = lines.join('\n'); + } + } + } + + // Build response text + const responseParts: string[] = [result.description]; + + // Add platform hint if not specified + const platformNote = params.platform + ? `Platform: ${params.platform === 'angular' ? 'Ignite UI for Angular' : 'Ignite UI for Web Components'}` + : 'Platform: Not specified (generic output). Specify `platform` for optimized code.'; + responseParts.push(''); + responseParts.push(platformNote); + + // Add validation warnings and tips + const validationText = formatValidationResult(validation); + if (validationText) { + responseParts.push(''); + responseParts.push(validationText); + } + + responseParts.push(''); + responseParts.push(`Variables created: ${result.variables.join(', ')}`); + responseParts.push(''); + responseParts.push('```scss'); + responseParts.push(finalCode.trimEnd()); + responseParts.push('```'); + + return { + content: [ + { + type: 'text' as const, + text: responseParts.join('\n'), + }, + ], + }; +} diff --git a/src/mcp/tools/handlers/platform.ts b/src/mcp/tools/handlers/platform.ts new file mode 100644 index 00000000..a36b994c --- /dev/null +++ b/src/mcp/tools/handlers/platform.ts @@ -0,0 +1,219 @@ +/** + * Handler for detect_platform tool. + * + * Detects the target platform (Angular, Web Components, React, or Blazor) + * from package.json dependencies and project config files. + * + * Uses a multi-signal detection approach: + * 1. Ignite UI packages (HIGH confidence) + * 2. Config files like angular.json, vite.config.ts, etc. (MEDIUM-HIGH confidence) + * 3. Framework packages as fallback (LOW confidence) + * + * When multiple platforms are detected with significant confidence, + * returns an ambiguous result prompting user to specify explicitly. + */ + +import {readFile} from 'node:fs/promises'; +import {resolve, dirname} from 'node:path'; +import {z} from 'zod'; +import { + detectPlatformFromDependencies, + PLATFORM_METADATA, + type PlatformDetectionResult, + type DetectionSignal, +} from '../../knowledge/index.js'; +import type {DetectPlatformParams} from '../schemas.js'; + +/** + * Zod schema for validating package.json structure. + * Only validates the fields we need for platform detection. + */ +const packageJsonSchema = z.object({ + dependencies: z.record(z.string()).optional(), + devDependencies: z.record(z.string()).optional(), +}); + +/** + * Result structure for platform detection (public API). + */ +export interface DetectPlatformResult { + platform: string | null; + confidence: 'high' | 'medium' | 'low' | 'none'; + ambiguous?: boolean; + alternatives?: Array<{ + platform: string; + confidence: number; + signals: DetectionSignal[]; + }>; + detectedPackage?: string; + signals?: DetectionSignal[]; + reason: string; + platformInfo?: { + name: string; + packageName: string; + themingModule: string; + description: string; + }; +} + +/** + * Format a detection signal for human-readable output. + */ +function formatSignal(signal: DetectionSignal): string { + switch (signal.type) { + case 'ignite_package': + return `package: ${signal.package}`; + case 'config_file': + return `config: ${signal.file}`; + case 'framework_package': + return `framework: ${signal.package}`; + default: + return 'unknown'; + } +} + +/** + * Handle the detect_platform tool invocation. + */ +export async function handleDetectPlatform(params: DetectPlatformParams) { + const packageJsonPath = params.packageJsonPath ?? './package.json'; + const resolvedPath = resolve(process.cwd(), packageJsonPath); + const projectRoot = dirname(resolvedPath); + + let result: PlatformDetectionResult; + + try { + const packageJsonContent = await readFile(resolvedPath, 'utf-8'); + const parseResult = packageJsonSchema.safeParse(JSON.parse(packageJsonContent)); + + if (!parseResult.success) { + result = { + platform: null, + confidence: 'none', + signals: [], + reason: `Invalid package.json structure: ${parseResult.error.message}`, + }; + } else { + const packageJson = parseResult.data; + result = detectPlatformFromDependencies(packageJson.dependencies, packageJson.devDependencies, projectRoot); + } + } catch (error) { + // File not found or invalid JSON + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + result = { + platform: null, + confidence: 'none', + signals: [], + reason: `Could not read package.json: ${errorMessage}`, + }; + } + + // Build the response + const response: DetectPlatformResult = { + platform: result.platform, + confidence: result.confidence, + reason: result.reason, + signals: result.signals, + }; + + if (result.ambiguous && result.alternatives) { + response.ambiguous = true; + response.alternatives = result.alternatives; + } + + if (result.detectedPackage) { + response.detectedPackage = result.detectedPackage; + } + + // Add platform info if detected + if (result.platform) { + const metadata = PLATFORM_METADATA[result.platform]; + response.platformInfo = { + name: metadata.name, + packageName: metadata.packageName, + themingModule: metadata.themingModule, + description: metadata.description, + }; + } + + // Format the response text for MCP + let text: string; + + if (result.ambiguous && result.alternatives) { + // AMBIGUOUS CASE: Multiple platforms detected + text = `## Platform Detection Result\n\n`; + text += `**Status:** Ambiguous - Multiple platforms detected\n\n`; + text += `The project appears to contain dependencies for multiple Ignite UI platforms. `; + text += `This might be a monorepo or a project transitioning between frameworks.\n\n`; + text += `### Detected Platforms\n\n`; + + for (const alt of result.alternatives) { + const metadata = PLATFORM_METADATA[alt.platform as keyof typeof PLATFORM_METADATA]; + text += `#### ${metadata.name}\n`; + text += `- **Confidence:** ${alt.confidence}%\n`; + text += `- **Signals:** ${alt.signals.map(formatSignal).join(', ')}\n`; + text += `- **Theming module:** \`${metadata.themingModule}\`\n\n`; + } + + text += `### Action Required\n\n`; + text += `Please specify the platform explicitly when calling theme generation tools:\n\n`; + for (const alt of result.alternatives) { + const metadata = PLATFORM_METADATA[alt.platform as keyof typeof PLATFORM_METADATA]; + text += `- Use \`platform: '${alt.platform}'\` for ${metadata.name}\n`; + } + } else if (result.platform) { + // SINGLE PLATFORM DETECTED + const metadata = PLATFORM_METADATA[result.platform]; + text = `## Platform Detection Result\n\n`; + text += `**Detected Platform:** ${metadata.name}\n`; + text += `**Confidence:** ${result.confidence}\n`; + + if (result.detectedPackage) { + text += `**Detected Package:** ${result.detectedPackage}\n`; + } + + if (result.signals && result.signals.length > 0) { + text += `**Detection Signals:** ${result.signals.map(formatSignal).join(', ')}\n`; + } + + text += `**Theming Module:** \`${metadata.themingModule}\`\n\n`; + + text += `### Usage\n\n`; + text += `When generating theme code, use \`platform: '${result.platform}'\` to ensure `; + text += `the correct Sass syntax is generated for this platform.\n\n`; + text += `${metadata.description}`; + + // Add confidence-specific notes + if (result.confidence === 'low') { + text += `\n\n### Note\n\n`; + text += `Detection confidence is **low**. This means no Ignite UI package was found, `; + text += `only framework packages. Please verify this is the correct platform before generating themes.`; + } else if (result.confidence === 'medium') { + text += `\n\n### Note\n\n`; + text += `Detection confidence is **medium**. Consider verifying the platform if the generated `; + text += `code doesn't work as expected.`; + } + } else { + // NO PLATFORM DETECTED + text = `## Platform Detection Result\n\n`; + text += `**Platform:** Not detected\n`; + text += `**Reason:** ${result.reason}\n\n`; + text += `### Recommendation\n\n`; + text += `Please specify the platform explicitly when calling theme generation tools:\n\n`; + text += `- Use \`platform: 'angular'\` for Ignite UI for Angular\n`; + text += `- Use \`platform: 'webcomponents'\` for Ignite UI for Web Components\n`; + text += `- Use \`platform: 'react'\` for Ignite UI for React\n`; + text += `- Use \`platform: 'blazor'\` for Ignite UI for Blazor`; + } + + return { + content: [ + { + type: 'text' as const, + text, + }, + ], + // Also include structured data for programmatic access + structuredData: response, + }; +} diff --git a/src/mcp/tools/handlers/theme.ts b/src/mcp/tools/handlers/theme.ts new file mode 100644 index 00000000..213b5862 --- /dev/null +++ b/src/mcp/tools/handlers/theme.ts @@ -0,0 +1,130 @@ +/** + * Handler for create_theme tool. + */ + +import {generateTheme} from '../../generators/sass.js'; +import type {CreateThemeParams} from '../schemas.js'; +import { + validatePaletteColors, + formatValidationResult, + generateWarningComments, + analyzeThemeColorsForPalette, + formatPaletteSuitabilityWarnings, + generatePaletteSuitabilityComments, +} from '../../validators/index.js'; + +export async function handleCreateTheme(params: CreateThemeParams) { + const variant = params.variant ?? 'light'; + + // Validate surface color against the variant + // Note: For themes, we only validate surfaceColor (gray is not exposed in theme params) + const validation = await validatePaletteColors({ + variant, + surface: params.surfaceColor, + }); + + // Analyze colors for palette shade generation suitability + const suitabilityAnalysis = await analyzeThemeColorsForPalette({ + primary: params.primaryColor, + secondary: params.secondaryColor, + surface: params.surfaceColor, + }); + + // Generate the theme code + const result = generateTheme({ + platform: params.platform, + designSystem: params.designSystem, + primaryColor: params.primaryColor, + secondaryColor: params.secondaryColor, + surfaceColor: params.surfaceColor, + variant: params.variant, + name: params.name, + fontFamily: params.fontFamily, + includeTypography: params.includeTypography, + includeElevations: params.includeElevations, + includeSpacing: params.includeSpacing, + }); + + // Add warning comments to the generated code if there are validation issues + let finalCode = result.code; + + // Collect all warning comments to insert + const allWarningComments: string[] = []; + + // Add variant validation warnings (single-line comments) + if (!validation.isValid) { + allWarningComments.push(...generateWarningComments(validation)); + } + + // Add suitability warnings (block comment) + if (!suitabilityAnalysis.allSuitable) { + allWarningComments.push(...generatePaletteSuitabilityComments(suitabilityAnalysis)); + } + + // Insert all warning comments after the header but before the @use statement + if (allWarningComments.length > 0) { + const lines = finalCode.split('\n'); + const useIndex = lines.findIndex((line) => line.startsWith("@use '") || line.startsWith('@use "')); + if (useIndex > 0) { + lines.splice(useIndex, 0, ...allWarningComments, ''); + finalCode = lines.join('\n'); + } + } + + // Build response text + const responseParts: string[] = [result.description]; + + // Add platform hint if not specified + let platformNote = '' + + switch (params.platform) { + case 'angular': + platformNote = 'Platform: Ignite UI for Angular'; + break; + case 'webcomponents': + platformNote = 'Platform: Ignite UI for Web Components'; + break; + case 'react': + platformNote = 'Platform: Ignite UI for React'; + break; + case 'blazor': + platformNote = 'Platform: Ignite UI for Blazor'; + break; + default: + platformNote = + 'Platform: Not specified (generic output). Specify `platform` for optimized code.'; + break; + } + + responseParts.push(''); + responseParts.push(platformNote); + + // Add validation warnings and tips (variant mismatch) + const validationText = formatValidationResult(validation); + if (validationText) { + responseParts.push(''); + responseParts.push(validationText); + } + + // Add suitability warnings (luminance issues) + if (!suitabilityAnalysis.allSuitable) { + responseParts.push(''); + responseParts.push(formatPaletteSuitabilityWarnings(suitabilityAnalysis)); + } + + responseParts.push(''); + responseParts.push(`Variables created/used: ${result.variables.join(', ')}`); + responseParts.push(''); + responseParts.push('```scss'); + responseParts.push(finalCode.trimEnd()); + responseParts.push('```'); + + return { + content: [ + { + type: 'text' as const, + text: responseParts.join('\n'), + }, + ], + }; +} diff --git a/src/mcp/tools/handlers/typography.ts b/src/mcp/tools/handlers/typography.ts new file mode 100644 index 00000000..9df14884 --- /dev/null +++ b/src/mcp/tools/handlers/typography.ts @@ -0,0 +1,42 @@ +/** + * Handler for create_typography tool. + */ + +import {generateTypography} from '../../generators/sass.js'; +import type {CreateTypographyParams} from '../schemas.js'; + +export function handleCreateTypography(params: CreateTypographyParams) { + const result = generateTypography({ + platform: params.platform, + fontFamily: params.fontFamily, + designSystem: params.designSystem, + customScale: params.customScale, + name: params.name, + }); + + // Build response text + const responseParts: string[] = [result.description]; + + // Add platform hint if not specified + const platformNote = params.platform + ? `Platform: ${params.platform === 'angular' ? 'Ignite UI for Angular' : 'Ignite UI for Web Components'}` + : 'Platform: Not specified (generic output). Specify `platform` for optimized code.'; + responseParts.push(''); + responseParts.push(platformNote); + + responseParts.push(''); + responseParts.push(`Variables used: ${result.variables.join(', ')}`); + responseParts.push(''); + responseParts.push('```scss'); + responseParts.push(result.code.trimEnd()); + responseParts.push('```'); + + return { + content: [ + { + type: 'text' as const, + text: responseParts.join('\n'), + }, + ], + }; +} diff --git a/src/mcp/tools/index.ts b/src/mcp/tools/index.ts new file mode 100644 index 00000000..7b511c49 --- /dev/null +++ b/src/mcp/tools/index.ts @@ -0,0 +1,29 @@ +/** + * Tools index - exports schemas and handlers for all MCP tools. + */ + +export { + detectPlatformSchema, + createPaletteSchema, + createCustomPaletteSchema, + createTypographySchema, + createElevationsSchema, + createThemeSchema, + platformSchema, + type DetectPlatformParams, + type CreatePaletteParams, + type CreateCustomPaletteParams, + type CreateTypographyParams, + type CreateElevationsParams, + type CreateThemeParams, + type Platform, +} from './schemas.js'; + +export { + handleDetectPlatform, + handleCreatePalette, + handleCreateCustomPalette, + handleCreateTypography, + handleCreateElevations, + handleCreateTheme, +} from './handlers/index.js'; diff --git a/src/mcp/tools/schemas.ts b/src/mcp/tools/schemas.ts new file mode 100644 index 00000000..4d9412a5 --- /dev/null +++ b/src/mcp/tools/schemas.ts @@ -0,0 +1,238 @@ +/** + * Zod schemas for tool input validation. + * + * Schemas are derived from constants in utils/types.ts to maintain + * a single source of truth. When adding new enums, add the constant + * array to utils/types.ts first, then derive the Zod schema here. + * + * Parameter descriptions are imported from descriptions.ts to maintain + * consistent, comprehensive documentation across the MCP server. + */ + +import {z} from 'zod'; +import {SHADE_LEVELS} from '../knowledge/index.js'; +import {PLATFORMS, DESIGN_SYSTEMS, VARIANTS, ELEVATION_PRESETS, ALL_COLOR_SHADES} from '../utils/types.js'; +import {PARAM_DESCRIPTIONS} from './descriptions.js'; + +/** + * Regex for validating CSS color values. + * + * This is a permissive pattern matcher for CSS Color Level 4 syntax. + * It validates the general structure of color values but does NOT validate + * the actual color values (e.g., that RGB values are 0-255). Full validation + * happens at Sass compile time via the isValidColor() utility. + * + * Supported formats: + * - Hex colors: #RGB, #RGBA, #RRGGBB, #RRGGBBAA (3, 4, 6, or 8 hex digits) + * - Legacy RGB/RGBA: rgb(r, g, b) or rgba(r, g, b, a) + * - Modern RGB: rgb(r g b) or rgb(r g b / alpha) + * - Legacy HSL/HSLA: hsl(h, s%, l%) or hsla(h, s%, l%, a) + * - Modern HSL: hsl(h s% l%) or hsl(h s% l% / alpha) + * - HWB (CSS Color Level 4): hwb(h w% b%) or hwb(h w% b% / alpha) + * - LAB (CSS Color Level 4): lab(L a b) or lab(L a b / alpha) + * - LCH (CSS Color Level 4): lch(L C H) or lch(L C H / alpha) + * - OKLAB (CSS Color Level 4): oklab(L a b) or oklab(L a b / alpha) + * - OKLCH (CSS Color Level 4): oklch(L C H) or oklch(L C H / alpha) + * - color() function: color(colorspace values...) for wide-gamut colors + * e.g., color(display-p3 1 0.5 0), color(srgb 1 0 0 / 0.5) + * - Named colors: CSS named colors (e.g., red, blue, rebeccapurple, transparent) + * + * @see https://www.w3.org/TR/css-color-4/ for the full CSS Color Level 4 specification + */ +const colorRegex = + /^(#[0-9a-fA-F]{3,4}|#[0-9a-fA-F]{6}|#[0-9a-fA-F]{8}|rgba?\(.+\)|hsla?\(.+\)|hwb\(.+\)|lab\(.+\)|lch\(.+\)|oklab\(.+\)|oklch\(.+\)|color\(.+\)|[a-z]+)$/i; + +/** + * Schema for CSS color values. + * Supports CSS Color Level 4 formats including hex, rgb, hsl, hwb, lab, lch, oklab, oklch, color(), and named colors. + */ +export const colorSchema = z + .string() + .regex(colorRegex, 'Must be a valid CSS color (hex, rgb, hsl, hwb, lab, lch, oklab, oklch, color(), or named color)'); + +/** + * Theme variant schema - derived from VARIANTS constant. + */ +export const variantSchema = z.enum(VARIANTS).optional(); + +/** + * Design system schema - derived from DESIGN_SYSTEMS constant. + */ +export const designSystemSchema = z.enum(DESIGN_SYSTEMS).optional(); + +/** + * Elevation preset schema - derived from ELEVATION_PRESETS constant. + */ +export const elevationPresetSchema = z.enum(ELEVATION_PRESETS).optional(); + +/** + * Platform schema - derived from PLATFORMS constant. + */ +export const platformSchema = z.enum(PLATFORMS).optional().describe(PARAM_DESCRIPTIONS.platform); + +/** + * Schema for detect_platform tool. + */ +export const detectPlatformSchema = z.object({ + packageJsonPath: z.string().optional().describe(PARAM_DESCRIPTIONS.packageJsonPath), +}); + +/** + * Schema for create_palette tool. + */ +export const createPaletteSchema = z.object({ + platform: platformSchema, + primary: colorSchema.describe(PARAM_DESCRIPTIONS.primary), + secondary: colorSchema.describe(PARAM_DESCRIPTIONS.secondary), + surface: colorSchema.describe(PARAM_DESCRIPTIONS.surface), + gray: colorSchema.optional().describe(PARAM_DESCRIPTIONS.gray), + info: colorSchema.optional().describe(PARAM_DESCRIPTIONS.info), + success: colorSchema.optional().describe(PARAM_DESCRIPTIONS.success), + warn: colorSchema.optional().describe(PARAM_DESCRIPTIONS.warn), + error: colorSchema.optional().describe(PARAM_DESCRIPTIONS.error), + variant: variantSchema.describe(PARAM_DESCRIPTIONS.variant), + name: z.string().optional().describe(PARAM_DESCRIPTIONS.name), +}); + +/** + * Schema for type style customization. + */ +export const typeStyleSchema = z.object({ + fontSize: z.string().optional(), + fontWeight: z.union([z.string(), z.number()]).optional(), + fontStyle: z.string().optional(), + lineHeight: z.string().optional(), + letterSpacing: z.string().optional(), + textTransform: z.string().optional(), + marginTop: z.string().optional(), + marginBottom: z.string().optional(), +}); + +/** + * Schema for create_typography tool. + */ +export const createTypographySchema = z.object({ + platform: platformSchema, + fontFamily: z.string().describe(PARAM_DESCRIPTIONS.fontFamily), + designSystem: designSystemSchema.describe(PARAM_DESCRIPTIONS.designSystem), + customScale: z.record(typeStyleSchema).optional().describe(PARAM_DESCRIPTIONS.customScale), + name: z.string().optional().describe(PARAM_DESCRIPTIONS.name), +}); + +/** + * Schema for create_elevations tool. + */ +export const createElevationsSchema = z.object({ + platform: platformSchema, + designSystem: elevationPresetSchema.describe(PARAM_DESCRIPTIONS.elevationPreset), + name: z.string().optional().describe(PARAM_DESCRIPTIONS.name), +}); + +/** + * Schema for create_theme tool. + */ +export const createThemeSchema = z.object({ + platform: platformSchema, + designSystem: designSystemSchema.describe(PARAM_DESCRIPTIONS.designSystem), + primaryColor: colorSchema.describe(PARAM_DESCRIPTIONS.primaryColor), + secondaryColor: colorSchema.describe(PARAM_DESCRIPTIONS.secondaryColor), + surfaceColor: colorSchema.describe(PARAM_DESCRIPTIONS.surfaceColor), + variant: variantSchema.describe(PARAM_DESCRIPTIONS.variant), + name: z.string().optional().describe(PARAM_DESCRIPTIONS.name), + fontFamily: z.string().optional().describe(PARAM_DESCRIPTIONS.fontFamily), + includeTypography: z.boolean().optional().default(true).describe(PARAM_DESCRIPTIONS.includeTypography), + includeElevations: z.boolean().optional().default(true).describe(PARAM_DESCRIPTIONS.includeElevations), + includeSpacing: z.boolean().optional().default(true).describe(PARAM_DESCRIPTIONS.includeSpacing), +}); + +/** + * Type exports inferred from schemas. + */ +export type DetectPlatformParams = z.infer; +export type CreatePaletteParams = z.infer; +export type CreateTypographyParams = z.infer; +export type CreateElevationsParams = z.infer; +export type CreateThemeParams = z.infer; + +// Re-export canonical types from utils/types.ts for convenience +export type {Platform, DesignSystem, ThemeVariant, ElevationPreset} from '../utils/types.js'; + +// ============================================================================ +// Custom Palette Schemas +// ============================================================================ + +/** + * All chromatic shade levels combined for schema validation. + * Imported from types.ts - the single source of truth. + */ + +/** + * Schema for shades-based color generation (uses Sass shades() function). + */ +const shadesBasedColorSchema = z.object({ + mode: z.literal('shades'), + baseColor: colorSchema.describe(PARAM_DESCRIPTIONS.baseColor), +}); + +/** + * Schema for explicit chromatic shades (14 shades required). + * Dynamically builds the shades object from SHADE_LEVELS and ACCENT_SHADE_LEVELS. + */ +const explicitColorShadesSchema = z.object({ + mode: z.literal('explicit'), + shades: z + .object(Object.fromEntries(ALL_COLOR_SHADES.map((s) => [s, colorSchema])) as Record) + .describe(PARAM_DESCRIPTIONS.shades), + contrastOverrides: z + .record(z.enum(ALL_COLOR_SHADES as unknown as [string, ...string[]]), colorSchema) + .optional() + .describe(PARAM_DESCRIPTIONS.contrastOverrides), +}); + +/** + * Schema for explicit gray shades (10 shades required). + */ +const explicitGrayShadesSchema = z.object({ + mode: z.literal('explicit'), + shades: z + .object(Object.fromEntries(SHADE_LEVELS.map((s) => [s, colorSchema])) as Record) + .describe(PARAM_DESCRIPTIONS.grayShades), + contrastOverrides: z + .record(z.enum(SHADE_LEVELS as unknown as [string, ...string[]]), colorSchema) + .optional() + .describe(PARAM_DESCRIPTIONS.contrastOverrides), +}); + +/** + * Schema for color definition - either shades-based or explicit. + */ +const colorDefinitionSchema = z.union([shadesBasedColorSchema, explicitColorShadesSchema]); + +/** + * Schema for gray definition - either shades-based or explicit. + */ +const grayDefinitionSchema = z.union([shadesBasedColorSchema, explicitGrayShadesSchema]); + +/** + * Schema for create_custom_palette tool. + */ +export const createCustomPaletteSchema = z.object({ + platform: platformSchema, + variant: variantSchema.describe(PARAM_DESCRIPTIONS.variant), + designSystem: designSystemSchema.describe(PARAM_DESCRIPTIONS.designSystem), + name: z.string().optional().describe(PARAM_DESCRIPTIONS.name), + + // Required colors - use colorDefinition description for detailed guidance + primary: colorDefinitionSchema.describe(PARAM_DESCRIPTIONS.colorDefinition), + secondary: colorDefinitionSchema.describe(PARAM_DESCRIPTIONS.colorDefinition), + surface: colorDefinitionSchema.describe(PARAM_DESCRIPTIONS.colorDefinition), + + // Optional colors - defaults from design system preset if not provided + gray: grayDefinitionSchema.optional().describe(PARAM_DESCRIPTIONS.grayDefinition), + info: colorDefinitionSchema.optional().describe(PARAM_DESCRIPTIONS.colorDefinition), + success: colorDefinitionSchema.optional().describe(PARAM_DESCRIPTIONS.colorDefinition), + warn: colorDefinitionSchema.optional().describe(PARAM_DESCRIPTIONS.colorDefinition), + error: colorDefinitionSchema.optional().describe(PARAM_DESCRIPTIONS.colorDefinition), +}); + +export type CreateCustomPaletteParams = z.infer; diff --git a/src/mcp/utils/color.ts b/src/mcp/utils/color.ts new file mode 100644 index 00000000..1be32f10 --- /dev/null +++ b/src/mcp/utils/color.ts @@ -0,0 +1,536 @@ +/** + * Color analysis utilities using Sass-embedded. + * Calls the actual Sass luminance() and contrast() functions for accurate validation. + */ + +import * as sass from 'sass-embedded'; +import * as path from 'path'; +import {fileURLToPath} from 'url'; + +// Get the package root directory (where sass/ folder is located) +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +// From dist/mcp/utils/ we need to go up 3 levels to package root +const PACKAGE_ROOT = path.resolve(__dirname, '..', '..', '..'); + +/** + * Luminance threshold for determining light vs dark colors. + * Colors with luminance > 0.5 are considered "light". + * Colors with luminance <= 0.5 are considered "dark". + */ +export const LUMINANCE_THRESHOLD = 0.5; + +/** + * Minimum recommended contrast ratio for surface/gray combinations. + * This is the WCAG 2.0 AA standard for large text (3:1). + * Note: The actual contrast ratio can be configured via the palette mixin. + */ +export const DEFAULT_MINIMUM_CONTRAST_RATIO = 3; + +/** + * Result of analyzing a single color. + */ +export interface ColorAnalysis { + /** The original color value */ + color: string; + /** Calculated luminance (0-1) */ + luminance: number; + /** Whether the color is considered light (luminance > 0.5) */ + isLight: boolean; +} + +/** + * Result of analyzing surface and gray colors together. + */ +export interface SurfaceGrayAnalysis { + /** Analysis of the surface color */ + surface?: ColorAnalysis; + /** Analysis of the gray color */ + gray?: ColorAnalysis; + /** Contrast ratio between surface and gray (if both provided) */ + contrastRatio?: number; +} + +/** + * Suggested colors for different variants. + */ +export const SUGGESTED_COLORS = { + light: { + surface: ['white', '#ffffff', '#f8f9fa', '#fafafa', '#f5f5f5'], + gray: ['black', '#000000', '#333333', '#212121', '#424242'], + }, + dark: { + surface: ['#222222', '#1a1a1a', '#121212', '#181818', '#2d2d2d'], + gray: ['white', '#ffffff', '#e5e5e5', '#f5f5f5', '#eeeeee'], + }, +} as const; + +/** + * Analyze a single color using Sass luminance() function. + * + * @param color - CSS color value (hex, rgb, hsl, or named color) + * @returns Color analysis with luminance and isLight flag + * @throws Error if Sass compilation fails or color is invalid + */ +export async function analyzeColor(color: string): Promise { + const sassCode = ` +@use 'sass/color' as color; + +$lum: color.luminance(${color}); + +:root { + --luminance: #{$lum}; +} +`; + + try { + const result = await sass.compileStringAsync(sassCode, { + loadPaths: [PACKAGE_ROOT], + }); + + // Parse the luminance value from CSS output + const luminanceMatch = result.css.match(/--luminance:\s*([\d.]+)/); + if (!luminanceMatch) { + throw new Error(`Could not parse luminance from Sass output for color: ${color}`); + } + + const luminance = parseFloat(luminanceMatch[1]); + + return { + color, + luminance, + isLight: luminance > LUMINANCE_THRESHOLD, + }; + } catch (error) { + // Re-throw with more context + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Failed to analyze color "${color}": ${message}`); + } +} + +/** + * Calculate the contrast ratio between two colors using Sass contrast() function. + * + * @param color1 - First CSS color value + * @param color2 - Second CSS color value + * @returns Contrast ratio (1 to 21) + * @throws Error if Sass compilation fails or colors are invalid + */ +export async function calculateContrast(color1: string, color2: string): Promise { + const sassCode = ` +@use 'sass/color' as color; + +$ratio: color.contrast(${color1}, ${color2}); + +:root { + --contrast-ratio: #{$ratio}; +} +`; + + try { + const result = await sass.compileStringAsync(sassCode, { + loadPaths: [PACKAGE_ROOT], + }); + + // Parse the contrast ratio from CSS output + const contrastMatch = result.css.match(/--contrast-ratio:\s*([\d.]+)/); + if (!contrastMatch) { + throw new Error(`Could not parse contrast ratio from Sass output`); + } + + return parseFloat(contrastMatch[1]); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Failed to calculate contrast between "${color1}" and "${color2}": ${message}`); + } +} + +/** + * Analyze surface and gray colors together in a single Sass compilation. + * This is more efficient than calling analyzeColor twice. + * + * @param params - Object containing surface and/or gray colors + * @returns Combined analysis results + */ +export async function analyzeSurfaceGrayColors(params: { + surface?: string; + gray?: string; +}): Promise { + const {surface, gray} = params; + + // If neither color is provided, return empty result + if (!surface && !gray) { + return {}; + } + + // Build Sass code to analyze all provided colors in one compilation + const sassLines = [`@use 'sass/color' as color;`, '']; + + if (surface) { + sassLines.push(`$surface-lum: color.luminance(${surface});`); + } + if (gray) { + sassLines.push(`$gray-lum: color.luminance(${gray});`); + } + if (surface && gray) { + sassLines.push(`$contrast: color.contrast(${surface}, ${gray});`); + } + + sassLines.push('', ':root {'); + if (surface) { + sassLines.push(' --surface-luminance: #{$surface-lum};'); + } + if (gray) { + sassLines.push(' --gray-luminance: #{$gray-lum};'); + } + if (surface && gray) { + sassLines.push(' --contrast-ratio: #{$contrast};'); + } + sassLines.push('}'); + + const sassCode = sassLines.join('\n'); + + try { + const result = await sass.compileStringAsync(sassCode, { + loadPaths: [PACKAGE_ROOT], + }); + + const analysis: SurfaceGrayAnalysis = {}; + + if (surface) { + const surfaceMatch = result.css.match(/--surface-luminance:\s*([\d.]+)/); + if (surfaceMatch) { + const luminance = parseFloat(surfaceMatch[1]); + analysis.surface = { + color: surface, + luminance, + isLight: luminance > LUMINANCE_THRESHOLD, + }; + } + } + + if (gray) { + const grayMatch = result.css.match(/--gray-luminance:\s*([\d.]+)/); + if (grayMatch) { + const luminance = parseFloat(grayMatch[1]); + analysis.gray = { + color: gray, + luminance, + isLight: luminance > LUMINANCE_THRESHOLD, + }; + } + } + + if (surface && gray) { + const contrastMatch = result.css.match(/--contrast-ratio:\s*([\d.]+)/); + if (contrastMatch) { + analysis.contrastRatio = parseFloat(contrastMatch[1]); + } + } + + return analysis; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Failed to analyze surface/gray colors: ${message}`); + } +} + +/** + * Check if a color is valid by attempting to analyze it. + * + * @param color - CSS color value to validate + * @returns true if the color is valid, false otherwise + */ +export async function isValidColor(color: string): Promise { + try { + await analyzeColor(color); + return true; + } catch { + return false; + } +} + +/** + * Validate multiple colors in a single Sass compilation for efficiency. + * This is much faster than calling isValidColor() for each color individually. + * + * @param colors - Map of key names to color values + * @returns Map of key names to validation results (true = valid, false = invalid) + */ +export async function validateColorsInBatch(colors: Record): Promise> { + const entries = Object.entries(colors); + if (entries.length === 0) { + return {}; + } + + // Build Sass code that attempts to use each color + // Invalid colors will cause Sass compilation errors, but we catch them per-color + // by using a try/catch pattern in Sass itself (via color.is-color()) + const sassLines = [`@use 'sass:color';`, `@use 'sass:meta';`, '']; + + // For each color, we check if it's a valid color using meta.type-of() + // A valid color will have type "color", invalid will cause an error or have different type + for (const [key, colorValue] of entries) { + const safeKey = key.replace(/[^a-zA-Z0-9]/g, '-'); + // Use a variable assignment to test if the color parses correctly + // If it's not a valid color, Sass will error, but we can catch this + sassLines.push(`$${safeKey}-valid: meta.type-of(${colorValue}) == 'color';`); + } + + sassLines.push('', ':root {'); + for (const [key] of entries) { + const safeKey = key.replace(/[^a-zA-Z0-9]/g, '-'); + sassLines.push(` --${safeKey}-valid: #{$${safeKey}-valid};`); + } + sassLines.push('}'); + + const sassCode = sassLines.join('\n'); + + try { + const result = await sass.compileStringAsync(sassCode, { + loadPaths: [PACKAGE_ROOT], + }); + + const validationResults: Record = {}; + + for (const [key] of entries) { + const safeKey = key.replace(/[^a-zA-Z0-9]/g, '-'); + const validMatch = result.css.match(new RegExp(`--${safeKey}-valid:\\s*(true|false)`)); + validationResults[key] = validMatch ? validMatch[1] === 'true' : false; + } + + return validationResults; + } catch { + // If the entire compilation fails, it means at least one color is invalid + // Fall back to individual validation to identify which ones + const validationResults: Record = {}; + for (const [key, colorValue] of entries) { + validationResults[key] = await isValidColor(colorValue); + } + return validationResults; + } +} + +/** + * Default hue tolerance in degrees for monochromatic validation. + * Allows for slight hue variation within a color family. + */ +export const DEFAULT_HUE_TOLERANCE = 30; + +/** + * Extract the hue value (0-360) from a color using Sass color.channel() function. + * + * @param color - CSS color value (hex, rgb, hsl, or named color) + * @returns Hue value in degrees (0-360) + * @throws Error if Sass compilation fails or color is invalid + */ +export async function extractHue(color: string): Promise { + const sassCode = ` +@use 'sass:color'; + +$hue: color.channel(${color}, "hue", $space: hsl); + +:root { + --hue: #{$hue}; +} +`; + + try { + const result = await sass.compileStringAsync(sassCode, { + loadPaths: [PACKAGE_ROOT], + }); + + // Parse the hue value from CSS output (e.g., "210deg" or "210") + const hueMatch = result.css.match(/--hue:\s*([\d.]+)/); + if (!hueMatch) { + throw new Error(`Could not parse hue from Sass output for color: ${color}`); + } + + return parseFloat(hueMatch[1]); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Failed to extract hue from color "${color}": ${message}`); + } +} + +/** + * Check if two hue values are within tolerance of each other, + * accounting for the circular nature of hue (0° = 360°). + * + * @param hue1 - First hue value (0-360) + * @param hue2 - Second hue value (0-360) + * @param tolerance - Maximum allowed difference in degrees (default: 30) + * @returns true if hues are within tolerance + */ +export function huesAreClose(hue1: number, hue2: number, tolerance: number = DEFAULT_HUE_TOLERANCE): boolean { + // Calculate the minimum angular distance between two hues + // accounting for the circular nature (e.g., 350° and 10° are 20° apart) + const diff = Math.abs(hue1 - hue2); + const circularDiff = Math.min(diff, 360 - diff); + return circularDiff <= tolerance; +} + +/** + * Analyze multiple colors in a single Sass compilation for efficiency. + * Returns luminance and hue for each color. + * + * @param colors - Map of key names to color values + * @returns Map of key names to analysis results + */ +export async function analyzeColorsWithHue( + colors: Record, +): Promise> { + const entries = Object.entries(colors); + if (entries.length === 0) { + return {}; + } + + // Build Sass code to analyze all colors in one compilation + const sassLines = [`@use 'sass/color' as igColor;`, `@use 'sass:color';`, '']; + + for (const [key, color] of entries) { + const safeKey = key.replace(/[^a-zA-Z0-9]/g, '-'); + sassLines.push(`$${safeKey}-lum: igColor.luminance(${color});`); + sassLines.push(`$${safeKey}-hue: color.channel(${color}, "hue", $space: hsl);`); + } + + sassLines.push('', ':root {'); + for (const [key] of entries) { + const safeKey = key.replace(/[^a-zA-Z0-9]/g, '-'); + sassLines.push(` --${safeKey}-luminance: #{$${safeKey}-lum};`); + sassLines.push(` --${safeKey}-hue: #{$${safeKey}-hue};`); + } + sassLines.push('}'); + + const sassCode = sassLines.join('\n'); + + try { + const result = await sass.compileStringAsync(sassCode, { + loadPaths: [PACKAGE_ROOT], + }); + + const analysis: Record = {}; + + for (const [key] of entries) { + const safeKey = key.replace(/[^a-zA-Z0-9]/g, '-'); + const lumMatch = result.css.match(new RegExp(`--${safeKey}-luminance:\\s*([\\d.]+)`)); + const hueMatch = result.css.match(new RegExp(`--${safeKey}-hue:\\s*([\\d.]+)`)); + + if (lumMatch && hueMatch) { + analysis[key] = { + luminance: parseFloat(lumMatch[1]), + hue: parseFloat(hueMatch[1]), + }; + } + } + + return analysis; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Failed to analyze colors: ${message}`); + } +} + +// ============================================================================ +// Palette Shade Generation Suitability +// ============================================================================ + +/** + * Luminance thresholds for palette shade generation suitability. + * Colors outside this range may produce poor automatic shade generation results. + * + * Note: This is different from LUMINANCE_THRESHOLD (0.5) which determines + * if a color is "light" or "dark" for variant matching. These thresholds + * determine if a color can produce a good range of shades when used with + * the palette() function. + * + * Based on color theory research: + * - Optimal base color tone: 35-65 L* (CIELAB) + * - Too light (L* > 70-75): darker shades compress together + * - Too dark (L* < 25-30): lighter shades compress together + */ +export const PALETTE_LUMINANCE_THRESHOLDS = { + /** Below this luminance, lighter shades (50-200) will lack contrast range */ + TOO_DARK: 0.05, + /** Above this luminance, darker shades (600-900) will appear washed out */ + TOO_LIGHT: 0.45, +} as const; + +/** + * Base fields for palette suitability analysis. + */ +interface PaletteSuitabilityBase { + /** The original color value */ + color: string; + /** Calculated luminance (0-1) */ + luminance: number; +} + +/** + * Result when a color is suitable for automatic shade generation. + */ +interface PaletteSuitabilitySuitable extends PaletteSuitabilityBase { + /** The color is suitable for automatic shade generation */ + suitable: true; +} + +/** + * Result when a color is NOT suitable for automatic shade generation. + */ +interface PaletteSuitabilityUnsuitable extends PaletteSuitabilityBase { + /** The color is not suitable for automatic shade generation */ + suitable: false; + /** Issue type - always present when not suitable */ + issue: 'too-light' | 'too-dark'; + /** Human-readable description of the issue - always present when not suitable */ + description: string; +} + +/** + * Result of analyzing a color for palette shade generation suitability. + * Uses a discriminated union: when `suitable` is false, `issue` and `description` + * are guaranteed to be present. + */ +export type PaletteSuitabilityAnalysis = PaletteSuitabilitySuitable | PaletteSuitabilityUnsuitable; + +/** + * Analyze whether a color is suitable for automatic shade generation. + * Colors with extreme luminance (very light or very dark) may produce + * poor results when using the palette() function's automatic shade generation. + * + * @param color - CSS color value (hex, rgb, hsl, or named color) + * @returns Analysis result indicating suitability and any issues + */ +export async function analyzeColorForPalette(color: string): Promise { + const analysis = await analyzeColor(color); + + if (analysis.luminance > PALETTE_LUMINANCE_THRESHOLDS.TOO_LIGHT) { + return { + color, + luminance: analysis.luminance, + suitable: false, + issue: 'too-light', + description: + `Luminance ${analysis.luminance.toFixed(2)} exceeds ${PALETTE_LUMINANCE_THRESHOLDS.TOO_LIGHT} - ` + + `darker shades (600-900) will appear washed out`, + }; + } + + if (analysis.luminance < PALETTE_LUMINANCE_THRESHOLDS.TOO_DARK) { + return { + color, + luminance: analysis.luminance, + suitable: false, + issue: 'too-dark', + description: + `Luminance ${analysis.luminance.toFixed(2)} is below ${PALETTE_LUMINANCE_THRESHOLDS.TOO_DARK} - ` + + `lighter shades (50-200) will lack contrast range`, + }; + } + + return { + color, + luminance: analysis.luminance, + suitable: true, + }; +} diff --git a/src/mcp/utils/result.ts b/src/mcp/utils/result.ts new file mode 100644 index 00000000..836ff38b --- /dev/null +++ b/src/mcp/utils/result.ts @@ -0,0 +1,375 @@ +/** + * Result Type for Error Handling + * + * This module provides a standardized Result type for operations that can fail. + * Using a Result type instead of exceptions makes error handling explicit and + * composable, following functional programming patterns. + * + * Use this pattern for: + * - Operations that can fail due to external input (user input, file I/O, etc.) + * - Validation that should return errors instead of throwing + * - Operations where you want to accumulate multiple errors + * + * Use exceptions (throw) for: + * - Programming errors (assertions, invalid state) + * - Unrecoverable errors + */ + +/** + * A successful result containing a value. + */ +export interface Success { + readonly ok: true; + readonly value: T; +} + +/** + * A failed result containing an error. + */ +export interface Failure { + readonly ok: false; + readonly error: E; +} + +/** + * A Result is either a Success with a value or a Failure with an error. + * This provides type-safe error handling without exceptions. + */ +export type Result = Success | Failure; + +/** + * Create a successful result. + * + * @example + * const result = success({ code: '...', variables: ['$my-palette'] }); + */ +export function success(value: T): Success { + return {ok: true, value}; +} + +/** + * Create a failed result. + * + * @example + * const result = failure(new Error('Invalid color')); + * const result = failure({ code: 'INVALID_COLOR', message: 'Invalid color' }); + */ +export function failure(error: E): Failure { + return {ok: false, error}; +} + +/** + * Check if a result is successful. + * TypeScript will narrow the type after this check. + * + * @example + * if (isSuccess(result)) { + * // result.value is available here + * } + */ +export function isSuccess(result: Result): result is Success { + return result.ok; +} + +/** + * Check if a result is a failure. + * TypeScript will narrow the type after this check. + * + * @example + * if (isFailure(result)) { + * // result.error is available here + * } + */ +export function isFailure(result: Result): result is Failure { + return !result.ok; +} + +/** + * Map over a successful result. + * If the result is a failure, returns the failure unchanged. + * + * @example + * const result = success(5); + * const doubled = mapResult(result, x => x * 2); // success(10) + */ +export function mapResult(result: Result, fn: (value: T) => U): Result { + if (result.ok) { + return success(fn(result.value)); + } + return result; +} + +/** + * Unwrap a result, throwing an error if it's a failure. + * Use this when you want to convert a Result back to a throwing operation. + * + * @example + * const value = unwrap(result); // throws if result is a failure + */ +export function unwrap(result: Result): T { + if (result.ok) { + return result.value; + } + throw result.error; +} + +/** + * Get the value from a result, or a default value if it's a failure. + * + * @example + * const value = unwrapOr(result, 'default'); + */ +export function unwrapOr(result: Result, defaultValue: T): T { + if (result.ok) { + return result.value; + } + return defaultValue; +} + +// ============================================================================ +// COMMON ERROR TYPES +// ============================================================================ + +/** + * Error codes for common error types in the MCP server. + */ +export type ErrorCode = + | 'INVALID_COLOR' + | 'INVALID_PARAMETER' + | 'SASS_COMPILATION_ERROR' + | 'VALIDATION_ERROR' + | 'NOT_FOUND' + | 'UNKNOWN_ERROR'; + +/** + * A structured error with code and message. + * More informative than a plain Error string. + */ +export interface McpError { + /** Error code for programmatic handling */ + code: ErrorCode; + /** Human-readable error message */ + message: string; + /** Additional context (e.g., which field failed validation) */ + context?: Record; +} + +/** + * Create an MCP error. + * + * @example + * const error = mcpError('INVALID_COLOR', 'Invalid hex color: #xyz'); + * const error = mcpError('VALIDATION_ERROR', 'Missing required field', { field: 'primary' }); + */ +export function mcpError(code: ErrorCode, message: string, context?: Record): McpError { + return {code, message, context}; +} + +/** + * Result type using McpError for failures. + * This is the preferred result type for MCP operations. + */ +export type McpResult = Result; + +// ============================================================================ +// VALIDATION RESULT HELPERS +// ============================================================================ + +/** + * Severity level for validation messages. + */ +export type ValidationSeverity = 'error' | 'warning' | 'info'; + +/** + * A validation error (fatal issue that prevents proceeding). + * + * Use for: + * - Missing required values + * - Invalid color/input formats + * - Structural problems that make generation impossible + */ +export interface ValidationError { + /** The field or path that failed validation (e.g., 'primary', 'primary.500') */ + field?: string; + /** Error message describing the issue */ + message: string; + /** Suggestion for how to fix the error */ + suggestion?: string; + /** Current value that caused the error */ + currentValue?: string; +} + +/** + * A validation warning (non-fatal issue that should be reported). + * + * Use for: + * - Suboptimal values that will still work + * - Best practice violations + * - Accessibility concerns + */ +export interface ValidationWarning { + /** The field or path with a warning (e.g., 'surface', 'gray.50') */ + field?: string; + /** Warning message describing the issue */ + message: string; + /** Severity: 'warning' for potential problems, 'info' for suggestions */ + severity?: 'warning' | 'info'; + /** Suggestion for improvement */ + suggestion?: string; + /** Current value that caused the warning */ + currentValue?: string; + /** Suggested alternative values */ + suggestedValues?: string[]; + /** Additional technical details for advanced users */ + details?: Record; +} + +/** + * Result of a validation operation. + * Can contain both errors (fatal) and warnings (non-fatal). + */ +export interface ValidationResult { + /** Whether validation passed (no errors) */ + isValid: boolean; + /** Validation errors (fatal issues that prevent proceeding) */ + errors: ValidationError[]; + /** Validation warnings (non-fatal issues that should be reported) */ + warnings: ValidationWarning[]; + /** Optional tips for the user (general guidance) */ + tips?: string[]; + /** Optional metadata from validation (e.g., analysis data) */ + metadata?: TMetadata; +} + +/** + * Create a successful validation result. + */ +export function validationSuccess( + warnings: ValidationWarning[] = [], + options?: {tips?: string[]; metadata?: TMetadata}, +): ValidationResult { + return { + isValid: true, + errors: [], + warnings, + tips: options?.tips, + metadata: options?.metadata, + }; +} + +/** + * Create a failed validation result. + */ +export function validationFailure( + errors: ValidationError[], + warnings: ValidationWarning[] = [], + options?: {tips?: string[]; metadata?: TMetadata}, +): ValidationResult { + return { + isValid: false, + errors, + warnings, + tips: options?.tips, + metadata: options?.metadata, + }; +} + +/** + * Combine multiple validation results. + * The combined result is invalid if any input result is invalid. + */ +export function combineValidationResults( + ...results: ValidationResult[] +): ValidationResult { + const combined: ValidationResult = { + isValid: true, + errors: [], + warnings: [], + tips: [], + }; + + for (const result of results) { + if (!result.isValid) { + combined.isValid = false; + } + combined.errors.push(...result.errors); + combined.warnings.push(...result.warnings); + if (result.tips) { + combined.tips!.push(...result.tips); + } + } + + // Remove tips array if empty + if (combined.tips!.length === 0) { + delete combined.tips; + } + + return combined; +} + +/** + * Options for formatting validation messages. + */ +export interface FormatValidationOptions { + /** Include severity icons (default: true) */ + includeIcons?: boolean; + /** Include suggested values (default: true) */ + includeSuggestions?: boolean; + /** Include tips section (default: true) */ + includeTips?: boolean; +} + +/** + * Format validation errors and warnings for display. + * + * @param result - Validation result to format + * @param options - Formatting options + * @returns Formatted markdown string + */ +export function formatValidationMessages( + result: ValidationResult, + options: FormatValidationOptions = {}, +): string { + const {includeIcons = true, includeSuggestions = true, includeTips = true} = options; + const lines: string[] = []; + + if (result.errors.length > 0) { + lines.push('**Errors:**'); + for (const error of result.errors) { + const icon = includeIcons ? '❌ ' : ''; + const prefix = error.field ? `\`${error.field}\`: ` : ''; + lines.push(`- ${icon}${prefix}${error.message}`); + if (includeSuggestions && error.suggestion) { + lines.push(` Suggestion: ${error.suggestion}`); + } + } + } + + if (result.warnings.length > 0) { + if (lines.length > 0) lines.push(''); + lines.push('**Warnings:**'); + for (const warning of result.warnings) { + const icon = includeIcons ? (warning.severity === 'info' ? 'ℹ️ ' : '⚠️ ') : ''; + const prefix = warning.field ? `\`${warning.field}\`: ` : ''; + lines.push(`- ${icon}${prefix}${warning.message}`); + if (includeSuggestions) { + if (warning.suggestedValues && warning.suggestedValues.length > 0) { + lines.push(` Suggested: ${warning.suggestedValues.join(', ')}`); + } else if (warning.suggestion) { + lines.push(` Suggestion: ${warning.suggestion}`); + } + } + } + } + + if (includeTips && result.tips && result.tips.length > 0) { + if (lines.length > 0) lines.push(''); + lines.push('**Tips:**'); + for (const tip of result.tips) { + const icon = includeIcons ? '💡 ' : ''; + lines.push(`- ${icon}${tip}`); + } + } + + return lines.join('\n'); +} diff --git a/src/mcp/utils/sass.ts b/src/mcp/utils/sass.ts new file mode 100644 index 00000000..168f9af6 --- /dev/null +++ b/src/mcp/utils/sass.ts @@ -0,0 +1,380 @@ +/** + * Sass code generation utilities. + * + * This module provides low-level helpers for generating Sass code snippets. + * These helpers are designed to be reusable across different code generators + * (standalone tools and platform-specific theme generators). + */ + +import {SHADE_LEVELS} from '../knowledge/index.js'; +import {ALL_COLOR_SHADES, type Platform, type ColorDefinition, type GrayDefinition, ThemeVariant} from './types.js'; + +/** + * Properly quote a font-family value for Sass. + * Font stacks (containing commas) need to be wrapped in quotes + * to preserve them as a single string value. + * + * Handles various input formats: + * - `Roboto` -> `'Roboto'` + * - `'Roboto'` -> `'Roboto'` (unchanged) + * - `'Titillium Web', sans-serif` -> `"'Titillium Web', sans-serif"` + * - `"Titillium Web", sans-serif` -> `'"Titillium Web", sans-serif'` + */ +export function quoteFontFamily(typeface: string): string { + if (typeface.includes(',')) { + // Font stack: wrap entire value in quotes to preserve as single string. + // Use opposite quote type to avoid escaping inner quotes. + const hasDoubleQuotes = typeface.includes('"'); + const hasSingleQuotes = typeface.includes("'"); + + if (hasDoubleQuotes && !hasSingleQuotes) { + // Inner double quotes -> wrap with single quotes + return `'${typeface}'`; + } + // Inner single quotes or no quotes -> wrap with double quotes + return `"${typeface}"`; + } + // Single font: add quotes if not already quoted + if (typeface.startsWith("'") || typeface.startsWith('"')) { + return typeface; + } + return `'${typeface}'`; +} + +/** + * Convert a name to a valid Sass variable name. + * + * Transforms input string to lowercase, replaces invalid characters with hyphens, + * collapses multiple hyphens, and removes leading/trailing hyphens. + * + * @param name - The name to convert + * @returns A valid Sass variable name (without $ prefix) + * @throws Error if the input results in an empty variable name + * + * @example + * toVariableName('My Theme') // 'my-theme' + * toVariableName('DARK_THEME_v2') // 'dark-theme-v2' + */ +export function toVariableName(name: string): string { + if (!name || !name.trim()) { + throw new Error('Variable name cannot be empty'); + } + + const result = name + .toLowerCase() + .replace(/[^a-z0-9-]/g, '-') + .replace(/-+/g, '-') + .replace(/^-|-$/g, ''); + + if (!result) { + throw new Error(`Cannot create valid Sass variable name from: "${name}"`); + } + + return result; +} + +/** + * Generate a comment header for generated Sass code. + * + * @param description - Description of what the code does + * @returns Formatted Sass comment header + */ +export function generateHeader(description: string): string { + return `// Generated by Ignite UI Theming MCP Server\n// ${description}`; +} + +// ============================================================================ +// LOW-LEVEL CODE GENERATION HELPERS +// These helpers generate reusable code snippets that can be composed by both +// standalone tools and platform-specific theme generators. +// ============================================================================ + +/** + * Generate the Sass @use statement for the theming library. + * Uses platform-specific import paths when platform is specified. + * + * @param platform - Target platform (angular or webcomponents) + * @returns The appropriate @use statement for the platform + */ +export function generateUseStatement(platform?: Platform): string { + if (platform === 'angular') { + return '@use "igniteui-angular/theming" as *;'; + } + // Web Components or unspecified (default to igniteui-theming) + return "@use 'igniteui-theming' as *;"; +} + +/** + * Options for generating a palette function call. + */ +export interface PaletteCodeOptions { + /** Primary brand color */ + primary: string; + /** Secondary/accent color (required by Sass palette function) */ + secondary: string; + /** Surface/background color (required by Sass palette function) */ + surface: string; + /** Gray base color */ + gray?: string; + /** Info state color */ + info?: string; + /** Success state color */ + success?: string; + /** Warning state color */ + warn?: string; + /** Error state color */ + error?: string; + /** Theme variant (affects surface default) */ + variant?: ThemeVariant + /** Variable name for the palette (without $) */ + variableName?: string; + /** Whether to use inline color values or reference Sass variables */ + useVariableReferences?: boolean; +} + +/** + * Result from generating palette code. + */ +export interface PaletteCodeResult { + /** Lines for color variable declarations (if useVariableReferences is true) */ + colorVariables: string[]; + /** Lines for the palette() function call */ + paletteDefinition: string[]; + /** The full variable name (with $) */ + variableName: string; +} + +/** + * Generate the palette() function call code. + * Returns an object with code lines that can be joined or embedded in other code. + * + * @example + * // Basic usage - returns lines for palette definition + * const result = generatePaletteCode({ primary: '#2ab759' }); + * // result.paletteDefinition: ['$custom-light-palette: palette(', ' $primary: #2ab759,', ' $surface: white', ');'] + * + * @example + * // With variable references (for use in theme generators) + * const result = generatePaletteCode({ + * primary: '#2ab759', + * useVariableReferences: true, + * variableName: 'my-palette' + * }); + * // Uses $primary-color, $secondary-color references + */ +export function generatePaletteCode(options: PaletteCodeOptions): PaletteCodeResult { + const variant = options.variant ?? 'light'; + const varName = options.variableName ? `$${options.variableName}` : `$custom-${variant}-palette`; + + const colorVariables: string[] = []; + const paletteArgs: string[] = []; + + // Primary, secondary, and surface are required by the Sass palette() function + if (options.useVariableReferences) { + // Generate color variable declarations and reference them in palette + colorVariables.push(`$primary-color: ${options.primary};`); + paletteArgs.push('$primary: $primary-color'); + + colorVariables.push(`$secondary-color: ${options.secondary};`); + paletteArgs.push('$secondary: $secondary-color'); + + colorVariables.push(`$surface-color: ${options.surface};`); + paletteArgs.push('$surface: $surface-color'); + + if (options.gray) { + colorVariables.push(`$gray-color: ${options.gray};`); + paletteArgs.push('$gray: $gray-color'); + } + } else { + // Use inline color values - all three required + paletteArgs.push(`$primary: ${options.primary}`); + paletteArgs.push(`$secondary: ${options.secondary}`); + paletteArgs.push(`$surface: ${options.surface}`); + if (options.gray) paletteArgs.push(`$gray: ${options.gray}`); + } + + // Additional color options (always inline) + if (options.info) paletteArgs.push(`$info: ${options.info}`); + if (options.success) paletteArgs.push(`$success: ${options.success}`); + if (options.warn) paletteArgs.push(`$warn: ${options.warn}`); + if (options.error) paletteArgs.push(`$error: ${options.error}`); + + const paletteDefinition = [ + `${varName}: palette(`, + ...paletteArgs.map((arg, i) => ` ${arg}${i < paletteArgs.length - 1 ? ',' : ''}`), + ');', + ]; + + return { + colorVariables, + paletteDefinition, + variableName: varName, + }; +} + +/** + * Options for generating a typography mixin call. + */ +export interface TypographyCodeOptions { + /** Font family string */ + fontFamily: string; + /** Type scale variable name (with $) */ + typeScaleVar: string; + /** Indentation for the mixin call */ + indent?: string; +} + +/** + * Generate the typography() mixin call code. + * Returns an array of lines that can be joined or embedded in other code. + */ +export function generateTypographyCode(options: TypographyCodeOptions): string[] { + const indent = options.indent ?? ''; + return [ + `${indent}@include typography(`, + `${indent} $font-family: ${quoteFontFamily(options.fontFamily)},`, + `${indent} $type-scale: ${options.typeScaleVar}`, + `${indent});`, + ]; +} + +/** + * Options for generating an elevations mixin call. + */ +export interface ElevationsCodeOptions { + /** Elevations variable name (with $) */ + elevationsVar: string; + /** Indentation for the mixin call */ + indent?: string; +} + +/** + * Generate the elevations() mixin call code. + * Returns an array of lines that can be joined or embedded in other code. + */ +export function generateElevationsCode(options: ElevationsCodeOptions): string[] { + const indent = options.indent ?? ''; + return [`${indent}@include elevations(${options.elevationsVar});`]; +} + +// ============================================================================ +// CUSTOM PALETTE CODE GENERATION +// ============================================================================ + +/** + * Options for generating a custom handmade palette. + */ +export interface CustomPaletteCodeOptions { + /** Target platform (affects import statements) */ + platform?: Platform; + /** Theme variant (light or dark) */ + variant?: ThemeVariant; + /** Variable name for the palette (without $ prefix) */ + variableName?: string; + /** Surface color for gray shades generation */ + surfaceColor?: string; + /** Color definitions for all palette groups */ + colors: { + primary: ColorDefinition; + secondary: ColorDefinition; + surface: ColorDefinition; + gray: GrayDefinition; + info: ColorDefinition; + success: ColorDefinition; + warn: ColorDefinition; + error: ColorDefinition; + }; +} + +/** + * Generates Sass code for a custom handmade palette. + * + * This function creates a Sass map palette structure that can use either: + * - The `shades()` function for auto-generating shades from a base color + * - Explicit shade maps with manual control over each shade value + * + * @example + * // Generate palette with mixed modes + * const lines = generateCustomPaletteCode({ + * variant: 'light', + * variableName: 'my-brand', + * surfaceColor: '#fafafa', + * colors: { + * primary: { mode: 'explicit', shades: { '50': '#e6eff8', ... } }, + * secondary: { mode: 'shades', baseColor: '#f7bd32' }, + * // ... + * } + * }); + */ +export function generateCustomPaletteCode(options: CustomPaletteCodeOptions): string[] { + const variant = options.variant ?? 'light'; + const varName = options.variableName ?? `custom-${variant}`; + + const lines: string[] = []; + lines.push(`$${varName}-palette: (`); + + const colorGroups: Array<{ + name: string; + def: ColorDefinition | GrayDefinition; + shades: readonly string[]; + isGray: boolean; + }> = [ + {name: 'primary', def: options.colors.primary, shades: ALL_COLOR_SHADES, isGray: false}, + {name: 'secondary', def: options.colors.secondary, shades: ALL_COLOR_SHADES, isGray: false}, + {name: 'gray', def: options.colors.gray, shades: SHADE_LEVELS, isGray: true}, + {name: 'surface', def: options.colors.surface, shades: ALL_COLOR_SHADES, isGray: false}, + {name: 'info', def: options.colors.info, shades: ALL_COLOR_SHADES, isGray: false}, + {name: 'success', def: options.colors.success, shades: ALL_COLOR_SHADES, isGray: false}, + {name: 'warn', def: options.colors.warn, shades: ALL_COLOR_SHADES, isGray: false}, + {name: 'error', def: options.colors.error, shades: ALL_COLOR_SHADES, isGray: false}, + ]; + + for (let i = 0; i < colorGroups.length; i++) { + const {name, def, shades, isGray} = colorGroups[i]; + const isLast = i === colorGroups.length - 1; + + if (def.mode === 'shades') { + // Use shades() function + const shadesListStr = shades.map((s) => `'${s}'`).join(', '); + lines.push(` '${name}': shades(`); + lines.push(` '${name}',`); + lines.push(` ${def.baseColor},`); + // Add surface parameter for gray to ensure proper contrast + if (isGray && options.surfaceColor) { + lines.push(` (${shadesListStr}),`); + lines.push(` ${options.surfaceColor}`); + } else { + lines.push(` (${shadesListStr})`); + } + lines.push(` )${isLast ? '' : ','}`); + } else { + // Explicit shade map + lines.push(` '${name}': (`); + + for (let j = 0; j < shades.length; j++) { + const shade = shades[j]; + const color = def.shades[shade as keyof typeof def.shades]; + const contrast = def.contrastOverrides?.[shade as keyof typeof def.contrastOverrides]; + const isLastShade = j === shades.length - 1; + + // Shade value + lines.push(` '${shade}': ${color},`); + // Contrast (explicit or adaptive-contrast) + const contrastValue = contrast ?? `adaptive-contrast(${color})`; + lines.push(` '${shade}-contrast': ${contrastValue},`); + // Raw value (exact color, no wrapping) + lines.push(` '${shade}-raw': ${color}${isLastShade ? '' : ','}`); + } + + lines.push(` )${isLast ? '' : ','}`); + } + } + + // Add metadata + lines.push(` '_meta': (`); + lines.push(` 'variant': ${variant}`); + lines.push(` )`); + lines.push(`);`); + + return lines; +} diff --git a/src/mcp/utils/types.ts b/src/mcp/utils/types.ts new file mode 100644 index 00000000..38b7a51b --- /dev/null +++ b/src/mcp/utils/types.ts @@ -0,0 +1,315 @@ +/** + * Shared TypeScript types for the MCP server. + * + * This module is the SINGLE SOURCE OF TRUTH for shared types and constants. + * Other modules should import from here rather than redefining types. + * + * IMPORTANT: This module should have NO imports from knowledge/ to avoid + * circular dependencies. Knowledge modules may import from this module. + */ + +// ============================================================================ +// CANONICAL CONSTANTS +// These constants are the source of truth - Zod schemas derive from these. +// ============================================================================ + +/** + * Supported target platforms for code generation. + * + * - angular: Ignite UI for Angular (uses igniteui-angular/theming) + * - webcomponents: Ignite UI for Web Components (uses igniteui-theming directly) + * - react: Ignite UI for React (uses igniteui-theming directly) + * - blazor: Ignite UI for Blazor (uses igniteui-theming for Sass compilation) + */ +export const PLATFORMS = ['angular', 'webcomponents', 'react', 'blazor'] as const; + +/** + * Supported design systems. + */ +export const DESIGN_SYSTEMS = ['material', 'bootstrap', 'fluent', 'indigo'] as const; + +/** + * Supported theme variants. + */ +export const VARIANTS = ['light', 'dark'] as const; + +/** + * Supported elevation presets. + */ +export const ELEVATION_PRESETS = ['material', 'indigo'] as const; + +/** + * Standard shade levels used in the theming system. + */ +export const SHADE_LEVELS = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900'] as const; + +/** + * Accent shade levels (Material Design style). + */ +export const ACCENT_SHADE_LEVELS = ['A100', 'A200', 'A400', 'A700'] as const; + +// ============================================================================ +// CANONICAL TYPES (derived from constants) +// ============================================================================ + +/** + * Target platform for code generation. + */ +export type Platform = (typeof PLATFORMS)[number]; + +/** + * Design system for theming. + */ +export type DesignSystem = (typeof DESIGN_SYSTEMS)[number]; + +/** + * Theme variant - light or dark mode. + */ +export type ThemeVariant = (typeof VARIANTS)[number]; + +/** + * Elevation preset type. + */ +export type ElevationPreset = (typeof ELEVATION_PRESETS)[number]; + +/** + * Standard shade level type. + */ +export type ShadeLevel = (typeof SHADE_LEVELS)[number]; + +/** + * Accent shade level type. + */ +export type AccentShadeLevel = (typeof ACCENT_SHADE_LEVELS)[number]; + +/** + * Input parameters for palette creation. + */ +export interface CreatePaletteInput { + /** Target platform for code generation */ + platform?: Platform; + /** Primary brand color (hex, rgb, or hsl) */ + primary: string; + /** Secondary/accent color (required by Sass palette function) */ + secondary: string; + /** Surface/background color (required by Sass palette function) */ + surface: string; + /** Gray base color */ + gray?: string; + /** Info state color */ + info?: string; + /** Success state color */ + success?: string; + /** Warning state color */ + warn?: string; + /** Error state color */ + error?: string; + /** Theme variant (light or dark) - affects surface defaults */ + variant?: ThemeVariant; + /** Custom name for the palette variable */ + name?: string; +} + +/** + * Input parameters for typography creation. + */ +export interface CreateTypographyInput { + /** Target platform for code generation */ + platform?: Platform; + /** Font family string */ + fontFamily: string; + /** Design system preset to use for type scale */ + designSystem?: DesignSystem; + /** Custom type scale (overrides designSystem) */ + customScale?: Partial>; + /** Custom name for the typography variable */ + name?: string; +} + +/** + * Input for a single type style. + */ +export interface TypeStyleInput { + fontSize?: string; + fontWeight?: string | number; + fontStyle?: string; + lineHeight?: string; + letterSpacing?: string; + textTransform?: string; + marginTop?: string; + marginBottom?: string; +} + +/** + * Input parameters for elevations creation. + */ +export interface CreateElevationsInput { + /** Target platform for code generation */ + platform?: Platform; + /** Design system preset to use (material or indigo) */ + designSystem?: 'material' | 'indigo'; + /** Custom name for the elevations variable */ + name?: string; +} + +/** + * Input parameters for complete theme creation. + */ +export interface CreateThemeInput { + /** Target platform for code generation */ + platform?: Platform; + /** Design system to base the theme on */ + designSystem?: DesignSystem; + /** Primary brand color */ + primaryColor: string; + /** Secondary/accent color */ + secondaryColor?: string; + /** Surface/background color */ + surfaceColor?: string; + /** Theme variant */ + variant?: ThemeVariant; + /** Theme name (used for variable naming) */ + name?: string; + /** Font family for typography */ + fontFamily?: string; + /** Whether to include typography setup */ + includeTypography?: boolean; + /** Whether to include elevations setup */ + includeElevations?: boolean; + /** Whether to include spacing setup (Web Components only) */ + includeSpacing?: boolean; +} + +/** + * Result from code generation. + */ +export interface GeneratedCode { + /** The generated Sass code */ + code: string; + /** Description of what was generated */ + description: string; + /** Variable names created */ + variables: string[]; +} + +/** + * Color in HSL format. + */ +export interface HSLColor { + h: number; + s: number; + l: number; +} + +// ============================================================================ +// Custom Palette Types +// ============================================================================ + +/** + * All chromatic shade levels (standard + accent). + * Derived from SHADE_LEVELS and ACCENT_SHADE_LEVELS to maintain single source of truth. + */ +export const ALL_COLOR_SHADES = [...SHADE_LEVELS, ...ACCENT_SHADE_LEVELS] as const; + +/** + * All palette color groups. + * These are the color families that make up a complete palette. + */ +export const PALETTE_COLOR_GROUPS = ['primary', 'secondary', 'gray', 'surface', 'info', 'success', 'warn', 'error'] as const; + +/** + * Type for palette color group names. + */ +export type PaletteColorGroup = (typeof PALETTE_COLOR_GROUPS)[number]; + +/** + * Chromatic color groups (excludes gray which has different shade handling). + * These groups use 14 shades (50-900, A100-A700). + * Derived from PALETTE_COLOR_GROUPS to maintain single source of truth. + */ +export const CHROMATIC_COLOR_GROUPS = PALETTE_COLOR_GROUPS.filter((g): g is Exclude => g !== 'gray'); + +/** + * Type for chromatic color group names. + */ +export type ChromaticColorGroup = (typeof CHROMATIC_COLOR_GROUPS)[number]; + +/** + * Combined type for all chromatic shade levels. + */ +export type ColorShadeLevel = ShadeLevel | AccentShadeLevel; + +/** + * Color definition using the shades() function. + * Generates all shades from a single base color. + */ +export interface ShadesBasedColor { + mode: 'shades'; + baseColor: string; +} + +/** + * Explicit shade definition for chromatic colors. + * All 14 shades must be provided (50-900, A100-A700). + */ +export interface ExplicitColorShades { + mode: 'explicit'; + shades: Record; + /** Optional explicit contrast colors per shade (defaults to adaptive-contrast) */ + contrastOverrides?: Partial>; +} + +/** + * Explicit shade definition for gray. + * All 10 shades must be provided (50-900). + */ +export interface ExplicitGrayShades { + mode: 'explicit'; + shades: Record; + /** Optional explicit contrast colors per shade (defaults to adaptive-contrast) */ + contrastOverrides?: Partial>; +} + +/** + * Color definition - either shades-based or explicit. + */ +export type ColorDefinition = ShadesBasedColor | ExplicitColorShades; + +/** + * Gray definition - either shades-based or explicit. + */ +export type GrayDefinition = ShadesBasedColor | ExplicitGrayShades; + +/** + * Input parameters for custom palette creation. + */ +export interface CreateCustomPaletteInput { + /** Target platform for code generation */ + platform?: Platform; + /** Theme variant (light or dark) */ + variant?: ThemeVariant; + /** Design system to use for default color values */ + designSystem?: DesignSystem; + /** Custom name for the palette variable */ + name?: string; + + // Required colors + /** Primary brand color definition */ + primary: ColorDefinition; + /** Secondary/accent color definition */ + secondary: ColorDefinition; + /** Surface/background color definition */ + surface: ColorDefinition; + + // Optional colors (defaults from design system preset) + /** Gray/neutral color definition */ + gray?: GrayDefinition; + /** Info state color definition */ + info?: ColorDefinition; + /** Success state color definition */ + success?: ColorDefinition; + /** Warning state color definition */ + warn?: ColorDefinition; + /** Error state color definition */ + error?: ColorDefinition; +} diff --git a/src/mcp/validators/custom-palette.ts b/src/mcp/validators/custom-palette.ts new file mode 100644 index 00000000..edb6e567 --- /dev/null +++ b/src/mcp/validators/custom-palette.ts @@ -0,0 +1,402 @@ +/** + * Validation for custom palette structures. + * + * Uses the unified ValidationResult type from result.ts for consistent + * error/warning handling across the codebase. + * + * Performance optimization: Uses batch color validation to minimize Sass + * compilations. Instead of validating each color individually (which would + * spawn ~100+ Sass processes), we collect all colors and validate them in + * a single Sass compilation. + */ + +import {validateColorsInBatch, analyzeColorsWithHue, huesAreClose, DEFAULT_HUE_TOLERANCE} from '../utils/color.js'; +import {SHADE_LEVELS} from '../knowledge/index.js'; +import { + ALL_COLOR_SHADES, + CHROMATIC_COLOR_GROUPS, + type CreateCustomPaletteInput, + type ColorDefinition, + type GrayDefinition, + type ThemeVariant, +} from '../utils/types.js'; +import { + type ValidationResult, + type ValidationError, + type ValidationWarning, + formatValidationMessages, +} from '../utils/result.js'; + +/** + * Result of custom palette validation. + * Uses the standard ValidationResult interface. + */ +export type CustomPaletteValidationResult = ValidationResult; + +// Re-export types for external use +export type {ValidationError as CustomPaletteError, ValidationWarning as CustomPaletteWarning}; + +/** + * Helper to create a field path from color group and optional shade. + */ +function makeFieldPath(colorGroup: string, shade?: string): string { + return shade ? `${colorGroup}.${shade}` : colorGroup; +} + +/** + * Collected color for batch validation. + */ +interface CollectedColor { + key: string; + color: string; + groupName: string; + shade?: string; + isContrast?: boolean; +} + +/** + * Collects all colors from a palette input for batch validation. + */ +function collectAllColors( + input: CreateCustomPaletteInput, +): {colors: CollectedColor[]; missingShades: ValidationError[]} { + const colors: CollectedColor[] = []; + const missingShades: ValidationError[] = []; + + // Collect chromatic colors + for (const group of CHROMATIC_COLOR_GROUPS) { + const definition = input[group]; + if (definition) { + collectFromDefinition(group, definition, ALL_COLOR_SHADES, colors, missingShades); + } + } + + // Collect gray colors + if (input.gray) { + collectFromDefinition('gray', input.gray, [...SHADE_LEVELS], colors, missingShades); + } + + return {colors, missingShades}; +} + +/** + * Collects colors from a single color definition. + */ +function collectFromDefinition( + groupName: string, + definition: ColorDefinition | GrayDefinition, + expectedShades: readonly string[], + colors: CollectedColor[], + missingShades: ValidationError[], +): void { + if (definition.mode === 'shades') { + // Collect base color + colors.push({ + key: `${groupName}.baseColor`, + color: definition.baseColor, + groupName, + }); + } else { + // Collect explicit shades + for (const shade of expectedShades) { + const color = definition.shades[shade as keyof typeof definition.shades]; + if (!color) { + missingShades.push({ + field: makeFieldPath(groupName, shade), + message: `Missing required shade: ${shade}`, + }); + } else { + colors.push({ + key: `${groupName}.${shade}`, + color, + groupName, + shade, + }); + } + } + + // Collect contrast overrides + if (definition.contrastOverrides) { + for (const [shade, color] of Object.entries(definition.contrastOverrides)) { + // Check if the shade key is valid (will add error later if not) + if (expectedShades.includes(shade)) { + colors.push({ + key: `${groupName}.contrast.${shade}`, + color, + groupName, + shade, + isContrast: true, + }); + } + } + } + } +} + +/** + * Validates a custom palette input structure. + * + * @param input - The custom palette input to validate + * @param variant - Theme variant for gray shade progression validation (defaults to 'light') + */ +export async function validateCustomPalette( + input: CreateCustomPaletteInput, + variant: ThemeVariant = 'light', +): Promise { + const errors: ValidationError[] = []; + const warnings: ValidationWarning[] = []; + + // Phase 1: Collect all colors and check for missing shades + const {colors, missingShades} = collectAllColors(input); + errors.push(...missingShades); + + // Check for invalid contrast override keys (not part of expected shades) + // Cast to string[] for includes() check since we're validating user input + const chromaticShadeSet = ALL_COLOR_SHADES as readonly string[]; + const grayShadeSet = SHADE_LEVELS as readonly string[]; + + for (const group of CHROMATIC_COLOR_GROUPS) { + const definition = input[group]; + if (definition?.mode === 'explicit' && definition.contrastOverrides) { + for (const shade of Object.keys(definition.contrastOverrides)) { + if (!chromaticShadeSet.includes(shade)) { + errors.push({ + field: makeFieldPath(group, shade), + message: `Invalid contrast override key: ${shade}. Valid keys are: ${ALL_COLOR_SHADES.join(', ')}`, + }); + } + } + } + } + if (input.gray?.mode === 'explicit' && input.gray.contrastOverrides) { + for (const shade of Object.keys(input.gray.contrastOverrides)) { + if (!grayShadeSet.includes(shade)) { + errors.push({ + field: makeFieldPath('gray', shade), + message: `Invalid contrast override key: ${shade}. Valid keys are: ${SHADE_LEVELS.join(', ')}`, + }); + } + } + } + + // Phase 2: Batch validate all collected colors (single Sass compilation) + if (colors.length > 0) { + const colorMap: Record = {}; + for (const c of colors) { + colorMap[c.key] = c.color; + } + + const validationResults = await validateColorsInBatch(colorMap); + + // Generate errors for invalid colors + for (const c of colors) { + if (!validationResults[c.key]) { + if (c.isContrast) { + errors.push({ + field: makeFieldPath(c.groupName, `contrast.${c.shade}`), + message: `Invalid contrast color for shade ${c.shade}: ${c.color}`, + currentValue: c.color, + }); + } else if (c.shade) { + errors.push({ + field: makeFieldPath(c.groupName, c.shade), + message: `Invalid color value for shade ${c.shade}: ${c.color}`, + currentValue: c.color, + }); + } else { + errors.push({ + field: c.groupName, + message: `Invalid base color: ${c.color}`, + currentValue: c.color, + }); + } + } + } + } + + // Phase 3: Validate shade progression and monochromatic hue (only for explicit shades) + // These use analyzeColorsWithHue which already batches colors efficiently + for (const group of CHROMATIC_COLOR_GROUPS) { + const definition = input[group]; + if (definition?.mode === 'explicit') { + await validateShadeProgression(group, definition.shades, 'chromatic', variant, warnings); + await validateMonochromaticHue(group, definition.shades, warnings); + } + } + + if (input.gray?.mode === 'explicit') { + await validateShadeProgression('gray', input.gray.shades, 'gray', variant, warnings); + } + + return { + isValid: errors.length === 0, + errors, + warnings, + }; +} + +/** + * Format validation result as markdown. + * + * This is a thin wrapper around formatValidationMessages for backward compatibility. + * New code should use formatValidationMessages directly. + */ +export function formatCustomPaletteValidation(result: CustomPaletteValidationResult): string { + if (result.isValid && result.warnings.length === 0) return ''; + return formatValidationMessages(result); +} + +// ============================================================================ +// Shade Progression and Monochromatic Validation +// ============================================================================ + +/** + * Validates that shade progression follows expected luminance direction. + * + * - Chromatic colors: shade 50 should be lighter than shade 900 (always) + * - Gray (light themes): shade 50 should be lighter than shade 900 + * - Gray (dark themes): shade 50 should be darker than shade 900 (inverted) + * + * Only checks endpoints (50 vs 900), not full progression. + * Issues warnings, not errors. + */ +async function validateShadeProgression( + groupName: string, + shades: Record, + colorType: 'chromatic' | 'gray', + variant: ThemeVariant, + warnings: ValidationWarning[], +): Promise { + const shade50 = shades['50']; + const shade900 = shades['900']; + + // Skip if shades are missing (will be caught by other validation) + if (!shade50 || !shade900) { + return; + } + + try { + const analysis = await analyzeColorsWithHue({ + shade50: shade50, + shade900: shade900, + }); + + const lum50 = analysis['shade50']?.luminance; + const lum900 = analysis['shade900']?.luminance; + + if (lum50 === undefined || lum900 === undefined) { + return; + } + + // Determine expected direction + const isGrayDarkTheme = colorType === 'gray' && variant === 'dark'; + + if (isGrayDarkTheme) { + // Gray in dark themes: 50 should be darker (lower luminance) than 900 + if (lum50 >= lum900) { + warnings.push({ + field: groupName, + message: + `For dark themes, gray shade 50 should be darker than shade 900 (inverted progression). ` + + `Found: 50 (luminance: ${lum50.toFixed(3)}) vs 900 (luminance: ${lum900.toFixed(3)}).`, + severity: 'warning', + }); + } + } else { + // Chromatic or gray in light themes: 50 should be lighter (higher luminance) than 900 + if (lum50 <= lum900) { + const context = colorType === 'gray' ? 'For light themes, gray' : 'Chromatic'; + warnings.push({ + field: groupName, + message: + `${context} shade 50 should be lighter than shade 900. ` + + `Found: 50 (luminance: ${lum50.toFixed(3)}) vs 900 (luminance: ${lum900.toFixed(3)}).`, + severity: 'warning', + }); + } + } + } catch (error) { + // Color analysis failures are non-fatal - the color validity check will catch + // truly invalid colors. This can happen with edge-case color formats that Sass + // accepts but our analysis doesn't handle. Log for debugging if needed. + if (process.env.DEBUG) { + console.warn(`[custom-palette] Shade progression validation skipped for ${groupName}:`, error); + } + } +} + +/** + * Validates that a chromatic color family is monochromatic (same hue family). + * + * Checks hues at shades 50, 500, and 900. Warns if hue variation exceeds tolerance. + * Only applies to chromatic colors, not gray. + */ +async function validateMonochromaticHue( + groupName: string, + shades: Record, + warnings: ValidationWarning[], + tolerance: number = DEFAULT_HUE_TOLERANCE, +): Promise { + const shade50 = shades['50']; + const shade500 = shades['500']; + const shade900 = shades['900']; + + // Skip if shades are missing + if (!shade50 || !shade500 || !shade900) { + return; + } + + try { + const analysis = await analyzeColorsWithHue({ + shade50: shade50, + shade500: shade500, + shade900: shade900, + }); + + const hue50 = analysis['shade50']?.hue; + const hue500 = analysis['shade500']?.hue; + const hue900 = analysis['shade900']?.hue; + + if (hue50 === undefined || hue500 === undefined || hue900 === undefined) { + return; + } + + // Check if all hues are within tolerance of each other + const hues = [ + {shade: '50', hue: hue50}, + {shade: '500', hue: hue500}, + {shade: '900', hue: hue900}, + ]; + + const outliers: string[] = []; + + // Compare each pair + for (let i = 0; i < hues.length; i++) { + for (let j = i + 1; j < hues.length; j++) { + if (!huesAreClose(hues[i].hue, hues[j].hue, tolerance)) { + outliers.push( + `${hues[i].shade} (${Math.round(hues[i].hue)}°) vs ${hues[j].shade} (${Math.round(hues[j].hue)}°)`, + ); + } + } + } + + if (outliers.length > 0) { + warnings.push({ + field: groupName, + message: + `Color shades may not be monochromatic (hue varies by more than ±${tolerance}°). ` + + `Differences found: ${outliers.join(', ')}. ` + + `Consider using colors from the same hue family for visual consistency.`, + severity: 'warning', + }); + } + } catch (error) { + // Color analysis failures are non-fatal - the color validity check will catch + // truly invalid colors. This can happen with edge-case color formats that Sass + // accepts but our analysis doesn't handle. Log for debugging if needed. + if (process.env.DEBUG) { + console.warn(`[custom-palette] Hue validation skipped for ${groupName}:`, error); + } + } +} diff --git a/src/mcp/validators/index.ts b/src/mcp/validators/index.ts new file mode 100644 index 00000000..2dbf8137 --- /dev/null +++ b/src/mcp/validators/index.ts @@ -0,0 +1,40 @@ +/** + * Validators index - re-exports all validation utilities. + */ + +// Re-export common validation types from result.ts +export { + type ValidationResult, + type ValidationError, + type ValidationWarning, + type ValidationSeverity, + validationSuccess, + validationFailure, + combineValidationResults, + formatValidationMessages, +} from '../utils/result.js'; + +// Palette validation +export { + validatePaletteColors, + formatValidationResult, + generateWarningComments, + analyzeThemeColorsForPalette, + formatPaletteSuitabilityWarnings, + generatePaletteSuitabilityComments, + type PaletteWarning, + type PaletteValidationResult, + type PaletteValidationMetadata, + type ValidatePaletteColorsInput, + type WarningSeverity, + type ThemeColorsSuitabilityResult, +} from './palette.js'; + +// Custom palette validation +export { + validateCustomPalette, + formatCustomPaletteValidation, + type CustomPaletteError, + type CustomPaletteWarning, + type CustomPaletteValidationResult, +} from './custom-palette.js'; diff --git a/src/mcp/validators/palette.ts b/src/mcp/validators/palette.ts new file mode 100644 index 00000000..a7ba054e --- /dev/null +++ b/src/mcp/validators/palette.ts @@ -0,0 +1,435 @@ +/** + * Palette validation logic. + * Validates surface and gray colors against the theme variant. + * + * Uses the unified ValidationResult type from result.ts while maintaining + * specialized warning types for palette-specific validation. + */ + +import { + analyzeSurfaceGrayColors, + analyzeColorForPalette, + LUMINANCE_THRESHOLD, + DEFAULT_MINIMUM_CONTRAST_RATIO, + SUGGESTED_COLORS, + type ColorAnalysis, + type SurfaceGrayAnalysis, + type PaletteSuitabilityAnalysis, +} from '../utils/color.js'; +import type {ThemeVariant} from '../utils/types.js'; +import { + type ValidationResult, + type ValidationWarning, + formatValidationMessages, +} from '../utils/result.js'; + +// Re-export ValidationSeverity as WarningSeverity for backward compatibility +export type WarningSeverity = 'warning' | 'info'; + +/** + * A palette validation warning. + * Extends ValidationWarning with palette-specific fields. + */ +export interface PaletteWarning extends ValidationWarning { + /** Which parameter the warning is about (mapped to field for compatibility) */ + field: 'surface' | 'gray' | 'contrast'; +} + +/** + * Metadata for palette validation results. + */ +export interface PaletteValidationMetadata { + /** Raw analysis data from Sass */ + analysis: SurfaceGrayAnalysis; +} + +/** + * Result of palette color validation. + * Uses ValidationResult with palette-specific metadata. + */ +export interface PaletteValidationResult extends ValidationResult { + /** Override warnings to use PaletteWarning type */ + warnings: PaletteWarning[]; + /** Raw analysis data (alias for metadata.analysis for backward compatibility) */ + analysis: SurfaceGrayAnalysis; +} + +/** + * Input parameters for palette validation. + */ +export interface ValidatePaletteColorsInput { + /** Theme variant (light or dark) */ + variant: ThemeVariant; + /** Surface/background color */ + surface?: string; + /** Gray base color */ + gray?: string; + /** Minimum contrast ratio (default: 3) */ + minimumContrastRatio?: number; +} + +/** + * Validate surface and gray colors against the theme variant. + * + * Rules: + * - Light variant: surface should be light (luminance > 0.5), gray should be dark (luminance <= 0.5) + * - Dark variant: surface should be dark (luminance <= 0.5), gray should be light (luminance > 0.5) + * + * The gray logic is inverted because the Sass palette() function generates gray shades + * that contrast against the surface. + * + * @param input - Validation input parameters + * @returns Validation result with warnings and tips + */ +export async function validatePaletteColors(input: ValidatePaletteColorsInput): Promise { + const {variant, surface, gray, minimumContrastRatio = DEFAULT_MINIMUM_CONTRAST_RATIO} = input; + + const warnings: PaletteWarning[] = []; + const tips: string[] = []; + + // If neither surface nor gray is provided, no validation needed + if (!surface && !gray) { + return { + isValid: true, + errors: [], + warnings: [], + tips: [], + analysis: {}, + metadata: {analysis: {}}, + }; + } + + // Analyze colors using Sass + let analysis: SurfaceGrayAnalysis; + try { + analysis = await analyzeSurfaceGrayColors({surface, gray}); + } catch (error) { + // If analysis fails, return with an error warning + const message = error instanceof Error ? error.message : String(error); + return { + isValid: false, + errors: [], + warnings: [ + { + field: 'surface', + severity: 'warning', + message: `Failed to analyze colors: ${message}`, + }, + ], + tips: ['Ensure color values are valid CSS colors (hex, rgb, hsl, or named colors)'], + analysis: {}, + metadata: {analysis: {}}, + }; + } + + // Validate surface color + if (surface && analysis.surface) { + const surfaceWarning = validateSurfaceColor(analysis.surface, variant); + if (surfaceWarning) { + warnings.push(surfaceWarning); + } + } + + // Validate gray color + if (gray && analysis.gray) { + const grayWarning = validateGrayColor(analysis.gray, variant); + if (grayWarning) { + warnings.push(grayWarning); + } + } + + // Check contrast ratio if both colors are provided + if (surface && gray && analysis.contrastRatio !== undefined) { + if (analysis.contrastRatio < minimumContrastRatio) { + warnings.push({ + field: 'contrast', + severity: 'warning', + message: `Contrast ratio between surface and gray is ${analysis.contrastRatio.toFixed(2)}:1, which is below the recommended ${minimumContrastRatio}:1`, + details: { + contrastRatio: analysis.contrastRatio, + }, + }); + } + } + + // Add tips based on warnings + if (warnings.some((w) => w.field === 'gray')) { + tips.push( + 'Consider omitting the gray parameter to let the palette() function auto-calculate an appropriate gray base from the surface color', + ); + } + + if (warnings.some((w) => w.field === 'surface')) { + tips.push( + `For a ${variant} theme, use a ${variant === 'light' ? 'light' : 'dark'} surface color like ${SUGGESTED_COLORS[variant].surface.slice(0, 3).join(', ')}`, + ); + } + + return { + isValid: warnings.length === 0, + errors: [], + warnings, + tips, + analysis, + metadata: {analysis}, + }; +} + +/** + * Validate surface color against variant. + */ +function validateSurfaceColor(surface: ColorAnalysis, variant: ThemeVariant): PaletteWarning | null { + // Light variant expects light surface (high luminance) + // Dark variant expects dark surface (low luminance) + const expectLight = variant === 'light'; + const isCorrect = surface.isLight === expectLight; + + if (isCorrect) { + return null; + } + + const colorType = surface.isLight ? 'light' : 'dark'; + const expectedType = expectLight ? 'light' : 'dark'; + + return { + field: 'surface', + severity: 'warning', + message: `Surface color "${surface.color}" is a ${colorType} color (luminance: ${surface.luminance.toFixed(2)}), but variant is '${variant}'. Expected a ${expectedType} surface color (luminance ${expectLight ? `> ${LUMINANCE_THRESHOLD}` : `<= ${LUMINANCE_THRESHOLD}`}).`, + currentValue: surface.color, + suggestedValues: SUGGESTED_COLORS[variant].surface.slice(0, 3), + details: { + luminance: surface.luminance, + isLight: surface.isLight, + expectedLuminance: expectLight ? `> ${LUMINANCE_THRESHOLD}` : `<= ${LUMINANCE_THRESHOLD}`, + }, + }; +} + +/** + * Validate gray color against variant. + * + * Note: Gray logic is INVERTED from surface because the palette() function + * generates gray shades that need to contrast with the surface. + * - Light variant (light surface) needs dark gray base + * - Dark variant (dark surface) needs light gray base + */ +function validateGrayColor(gray: ColorAnalysis, variant: ThemeVariant): PaletteWarning | null { + // Gray is inverted: light variant needs dark gray, dark variant needs light gray + const expectLightGray = variant === 'dark'; + const isCorrect = gray.isLight === expectLightGray; + + if (isCorrect) { + return null; + } + + const colorType = gray.isLight ? 'light' : 'dark'; + const expectedType = expectLightGray ? 'light' : 'dark'; + + return { + field: 'gray', + severity: 'warning', + message: `Gray base "${gray.color}" is a ${colorType} color (luminance: ${gray.luminance.toFixed(2)}), but variant is '${variant}'. For ${variant} themes, the gray base should be ${expectedType} (luminance ${expectLightGray ? `> ${LUMINANCE_THRESHOLD}` : `<= ${LUMINANCE_THRESHOLD}`}) to ensure proper contrast with the ${variant} surface.`, + currentValue: gray.color, + suggestedValues: SUGGESTED_COLORS[variant].gray.slice(0, 3), + details: { + luminance: gray.luminance, + isLight: gray.isLight, + expectedLuminance: expectLightGray ? `> ${LUMINANCE_THRESHOLD}` : `<= ${LUMINANCE_THRESHOLD}`, + }, + }; +} + +/** + * Format validation result as markdown for display. + * + * @param result - Validation result to format + * @returns Markdown string with warnings and tips + */ +export function formatValidationResult(result: PaletteValidationResult): string { + if (result.isValid) { + return ''; + } + + // Use the unified formatter + return formatValidationMessages(result); +} + +/** + * Generate Sass comment warnings for code generation. + * + * @param result - Validation result + * @returns Array of Sass comment lines + */ +export function generateWarningComments(result: PaletteValidationResult): string[] { + if (result.isValid) { + return []; + } + + return result.warnings.map((warning) => { + const paramLabel = warning.field === 'contrast' ? 'Contrast' : `${capitalize(warning.field)} color`; + return `// ⚠️ Warning: ${paramLabel} may not be optimal for this variant`; + }); +} + +/** + * Capitalize the first letter of a string. + */ +function capitalize(str: string): string { + return str.charAt(0).toUpperCase() + str.slice(1); +} + +// ============================================================================ +// Palette Shade Generation Suitability Analysis +// ============================================================================ + +/** + * Result of analyzing theme colors for palette shade generation suitability. + */ +export interface ThemeColorsSuitabilityResult { + /** Whether all colors are suitable for standard palette() generation */ + allSuitable: boolean; + /** Analysis for each color */ + colors: Record; + /** Colors that have suitability issues */ + problematicColors: Array<{ + name: string; + color: string; + luminance: number; + issue: 'too-light' | 'too-dark'; + description: string; + }>; +} + +/** + * Analyze theme colors for palette shade generation suitability. + * Checks if colors have extreme luminance that would produce poor + * automatic shade generation results with the palette() function. + * + * @param params - Theme colors to analyze + * @returns Analysis result with suitability status and any problematic colors + */ +export async function analyzeThemeColorsForPalette(params: { + primary: string; + secondary?: string; + surface?: string; +}): Promise { + const colors: Record = {}; + const problematicColors: ThemeColorsSuitabilityResult['problematicColors'] = []; + + // Analyze primary (required) + colors.primary = await analyzeColorForPalette(params.primary); + if (!colors.primary.suitable) { + problematicColors.push({ + name: 'primary', + color: params.primary, + luminance: colors.primary.luminance, + issue: colors.primary.issue, + description: colors.primary.description, + }); + } + + // Analyze secondary (optional) + if (params.secondary) { + colors.secondary = await analyzeColorForPalette(params.secondary); + if (!colors.secondary.suitable) { + problematicColors.push({ + name: 'secondary', + color: params.secondary, + luminance: colors.secondary.luminance, + issue: colors.secondary.issue, + description: colors.secondary.description, + }); + } + } + + // Analyze surface (optional) + if (params.surface) { + colors.surface = await analyzeColorForPalette(params.surface); + if (!colors.surface.suitable) { + problematicColors.push({ + name: 'surface', + color: params.surface, + luminance: colors.surface.luminance, + issue: colors.surface.issue, + description: colors.surface.description, + }); + } + } + + return { + allSuitable: problematicColors.length === 0, + colors, + problematicColors, + }; +} + +/** + * Format palette suitability warnings as markdown table. + * + * @param result - Suitability analysis result + * @returns Formatted markdown string with warnings table and recommendations + */ +export function formatPaletteSuitabilityWarnings(result: ThemeColorsSuitabilityResult): string { + if (result.allSuitable) { + return ''; + } + + const lines: string[] = []; + + lines.push('**Color Luminance Warnings:**'); + lines.push(''); + lines.push('The following colors have extreme luminance values that may produce suboptimal shade generation:'); + lines.push(''); + lines.push('| Color | Value | Luminance | Issue |'); + lines.push('|-------|-------|-----------|-------|'); + + for (const pc of result.problematicColors) { + const issueText = + pc.issue === 'too-light' + ? 'Too light - darker shades (600-900) will appear washed out' + : 'Too dark - lighter shades (50-200) will lack contrast range'; + lines.push(`| ${pc.name} | \`${pc.color}\` | ${pc.luminance.toFixed(2)} | ${issueText} |`); + } + + lines.push(''); + lines.push( + '**Recommendation:** For production-quality results, use the `create_custom_palette` tool from the Ignite UI Theming MCP with explicit ' + + 'shade values for these colors. This gives you fine-grained control over each shade level (50-900, A100-A700).', + ); + lines.push(''); + lines.push( + 'The generated code below uses the standard `palette()` function, which may produce ' + + 'limited shade ranges for the flagged colors.', + ); + + return lines.join('\n'); +} + +/** + * Generate Sass block comment for palette suitability warnings. + * This comment is inserted into the generated Sass code to warn developers. + * + * @param result - Suitability analysis result + * @returns Array of Sass comment lines + */ +export function generatePaletteSuitabilityComments(result: ThemeColorsSuitabilityResult): string[] { + if (result.allSuitable) { + return []; + } + + const lines: string[] = []; + lines.push('/*'); + lines.push(' * ⚠️ PALETTE SUITABILITY WARNINGS'); + lines.push(' * The following colors have extreme luminance that may produce suboptimal shade generation:'); + + for (const pc of result.problematicColors) { + const issueText = + pc.issue === 'too-light' ? 'too light - darker shades may be washed out' : 'too dark - lighter shades may lack range'; + lines.push(` * - ${pc.name} (${pc.color}): luminance ${pc.luminance.toFixed(2)} - ${issueText}`); + } + + lines.push(' * Consider using the create_custom_palette tool of the Ignite UI Theming MCP server with explicit shade values for better results.'); + lines.push(' */'); + + return lines; +} diff --git a/test/sass.test.ts b/test/sass.test.ts new file mode 100644 index 00000000..50d7802f --- /dev/null +++ b/test/sass.test.ts @@ -0,0 +1,13 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import sassTrue from 'sass-true'; +import { describe, it } from 'vitest'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const sassFile = path.join(__dirname, '_index.scss'); + +sassTrue.runSass( + { describe, it }, + sassFile, + { loadPaths: ['node_modules'] } +); diff --git a/test/test.js b/test/test.js deleted file mode 100644 index be700144..00000000 --- a/test/test.js +++ /dev/null @@ -1,10 +0,0 @@ -const path = require('path'); -const sassTrue = require('sass-true'); - -const sassFile = path.join(__dirname, '_index.scss'); - -sassTrue.runSass( - { describe, it }, - sassFile, - { loadPaths: ['node_modules'] } -); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..d2a7c2da --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "rootDir": "./src/mcp", + "outDir": "./dist/mcp", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "resolveJsonModule": true + }, + "include": ["src/mcp/**/*"], + "exclude": ["node_modules", "**/__tests__/**"] +} diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 00000000..f84502bf --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + root: './', + include: ['**/*.{test,spec}.ts'], + environment: 'node', + globals: false, + testTimeout: 10000, // 10s for Sass compilation tests + coverage: { + provider: 'v8', + include: ['**/*.ts'], + exclude: ['dist', '**/*.test.ts', '**/*.spec.ts', 'index.ts'], + }, + }, +}); From 4669ffbb4174907e9e839a44c2de59ad0bfc7002 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Fri, 9 Jan 2026 15:28:38 +0200 Subject: [PATCH 02/38] feat(mcp): add component theming to server --- package-lock.json | 3268 ++++++++++++++++- package.json | 3 +- sass/json/components.scss | 52 + .../action-strip/_action-strip-theme.scss | 11 +- .../components/avatar/_avatar-theme.scss | 12 +- .../themes/components/badge/_badge-theme.scss | 14 +- .../components/banner/_banner-theme.scss | 16 +- .../bottom-nav/_bottom-nav-theme.scss | 26 +- .../button-group/_button-group-theme.scss | 75 +- .../components/button/_button-theme.scss | 33 +- .../button/_contained-button-theme.scss | 50 +- .../components/button/_fab-button-theme.scss | 51 +- .../components/button/_flat-button-theme.scss | 46 +- .../button/_outlined-button-theme.scss | 56 +- .../components/calendar/_calendar-theme.scss | 78 +- sass/themes/components/card/_card-theme.scss | 18 +- .../components/carousel/_carousel-theme.scss | 45 +- sass/themes/components/chat/_chat-theme.scss | 42 +- .../components/checkbox/_checkbox-theme.scss | 35 +- sass/themes/components/chip/_chip-theme.scss | 44 +- .../column-actions/_column-actions-theme.scss | 12 +- .../themes/components/combo/_combo-theme.scss | 34 +- .../_date-range-picker-theme.scss | 5 + .../components/dialog/_dialog-theme.scss | 14 +- .../components/divider/_divider-theme.scss | 4 + .../dock-manager/_dock-manager-theme.scss | 7 +- .../drop-down/_drop-down-theme.scss | 49 +- .../_expansion-panel-theme.scss | 28 +- .../components/grid/_grid-summary-theme.scss | 20 +- sass/themes/components/grid/_grid-theme.scss | 143 +- .../components/grid/_grid-toolbar-theme.scss | 27 +- .../grid/_pivot-data-selector-theme.scss | 5 + .../highlight/_highlight-theme.scss | 15 +- .../_contained-icon-button-theme.scss | 40 +- .../icon-button/_flat-icon-button-theme.scss | 35 +- .../icon-button/_icon-button-theme.scss | 27 +- .../_outlined-icon-button-theme.scss | 39 +- sass/themes/components/icon/_icon-theme.scss | 4 + .../components/input/_file-input-theme.scss | 42 +- .../themes/components/input/_input-theme.scss | 67 +- .../themes/components/label/_label-theme.scss | 4 + sass/themes/components/list/_list-theme.scss | 66 +- .../components/navbar/_navbar-theme.scss | 17 +- .../navdrawer/_navdrawer-theme.scss | 34 +- .../components/overlay/_overlay-theme.scss | 4 + .../paginator/_paginator-theme.scss | 12 +- .../components/progress/_circular-theme.scss | 7 +- .../components/progress/_linear-theme.scss | 5 + .../query-builder/_query-builder-theme.scss | 35 +- .../themes/components/radio/_radio-theme.scss | 33 +- .../components/rating/_rating-theme.scss | 7 +- .../components/ripple/_ripple-theme.scss | 4 + .../scrollbar/_scrollbar-theme.scss | 6 +- .../components/select/_select-theme.scss | 21 +- .../components/slider/_slider-theme.scss | 42 +- .../components/snackbar/_snackbar-theme.scss | 12 +- .../components/splitter/_splitter-theme.scss | 17 +- .../components/stepper/_stepper-theme.scss | 119 +- .../components/switch/_switch-theme.scss | 48 +- sass/themes/components/tabs/_tabs-theme.scss | 53 +- .../time-picker/_time-picker-theme.scss | 36 +- .../themes/components/toast/_toast-theme.scss | 13 +- .../components/tooltip/_tooltip-theme.scss | 12 +- sass/themes/components/tree/_tree-theme.scss | 35 +- .../watermark/_watermark-theme.scss | 15 +- scripts/buildComponentDocs.mjs | 39 + .../knowledge/component-selectors.test.ts | 421 +++ .../knowledge/component-themes.test.ts | 127 + src/mcp/generators/sass.ts | 90 +- src/mcp/index.ts | 40 + src/mcp/knowledge/component-selectors.ts | 752 ++++ src/mcp/knowledge/component-themes.ts | 91 + src/mcp/knowledge/index.ts | 44 +- src/mcp/tools/descriptions.ts | 164 + src/mcp/tools/handlers/component-theme.ts | 173 + src/mcp/tools/handlers/component-tokens.ts | 148 + src/mcp/tools/handlers/index.ts | 2 + src/mcp/tools/index.ts | 6 + src/mcp/tools/schemas.ts | 35 + 79 files changed, 6597 insertions(+), 784 deletions(-) create mode 100644 sass/json/components.scss create mode 100644 scripts/buildComponentDocs.mjs create mode 100644 src/mcp/__tests__/knowledge/component-selectors.test.ts create mode 100644 src/mcp/__tests__/knowledge/component-themes.test.ts create mode 100644 src/mcp/knowledge/component-selectors.ts create mode 100644 src/mcp/knowledge/component-themes.ts create mode 100644 src/mcp/tools/handlers/component-theme.ts create mode 100644 src/mcp/tools/handlers/component-tokens.ts diff --git a/package-lock.json b/package-lock.json index da246492..bc19e0f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "postcss-safe-parser": "^7.0.0", "prettier": "^3.2.5", "sass-true": "^9.0.0", + "sassdoc": "^2.7.4", "sassdoc-plugin-localization": "^2.0.0", "shx": "^0.3.4", "stylelint": "^15.6.2", @@ -1591,6 +1592,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/@standard-schema/spec": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", @@ -1598,6 +1609,19 @@ "dev": true, "license": "MIT" }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@types/chai": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", @@ -1805,6 +1829,13 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/a-sync-waterfall": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz", + "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==", + "dev": true, + "license": "MIT" + }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -1875,6 +1906,16 @@ } } }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1901,6 +1942,21 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/ap": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/ap/-/ap-0.2.0.tgz", @@ -1908,6 +1964,19 @@ "dev": true, "license": "MIT/X11" }, + "node_modules/append-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", + "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2057,6 +2126,13 @@ "node": ">=0.10.0" } }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", @@ -2115,6 +2191,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2122,6 +2209,20 @@ "dev": true, "license": "MIT" }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bluebird": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", @@ -2153,6 +2254,63 @@ "url": "https://opencollective.com/express" } }, + "node_modules/boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -2183,6 +2341,26 @@ "integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==", "license": "MIT/X11" }, + "node_modules/buffer-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", + "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -2192,6 +2370,68 @@ "node": ">= 0.8" } }, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cacheable-request/node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -2250,6 +2490,17 @@ "node": ">=6" } }, + "node_modules/camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, "node_modules/camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -2295,6 +2546,44 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cdocparser": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/cdocparser/-/cdocparser-0.13.0.tgz", + "integrity": "sha512-bMi4t0qjeT0xQ8ECBmWcilMYcUNYsERQoatXveMIbItgqliZDCNyv2xfkBoKrs5H08ApeRMoysJLwgPiHtv7HQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.2", + "lodash.assign": "^2.4.1", + "strip-indent": "^1.0.0" + } + }, + "node_modules/cdocparser/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/cdocparser/node_modules/strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-stdin": "^4.0.1" + }, + "bin": { + "strip-indent": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/chai": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.1.tgz", @@ -2338,6 +2627,137 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/chroma-js": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-1.4.1.tgz", + "integrity": "sha512-jTwQiT859RTFN/vIf7s+Vl/Z2LcMrvMv3WUFmd/4u76AdlFC0NTNgqEEFPcRiHmAswPsMiQEDZLM8vX8qXpZNQ==", + "dev": true + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/clean-css": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", + "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/cloneable-readable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + } + }, + "node_modules/cloneable-readable/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cloneable-readable/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/cloneable-readable/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/cloneable-readable/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2371,6 +2791,13 @@ "integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==", "license": "MIT" }, + "node_modules/commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "dev": true, + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2378,6 +2805,76 @@ "dev": true, "license": "MIT" }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "dev": true, + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/configstore/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/configstore/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/configstore/node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, "node_modules/consolidate": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.13.1.tgz", @@ -2411,6 +2908,13 @@ "node": ">= 0.6" } }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT" + }, "node_modules/cookie": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", @@ -2429,6 +2933,22 @@ "node": ">=6.6.0" } }, + "node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", @@ -2483,6 +3003,16 @@ "node": ">= 8" } }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/css-functions-list": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.3.tgz", @@ -2520,6 +3050,19 @@ "node": ">=4" } }, + "node_modules/dargs": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-4.1.0.tgz", + "integrity": "sha512-jyweV/k0rbv2WK4r9KLayuBrSh2Py0tNmV7LBoSMH4hMQyrG8OPyIOWB2VEx4DJKXWmK4lopYMVvORlDt2S8Aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", @@ -2641,6 +3184,29 @@ "node": ">=0.10.0" } }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -2648,6 +3214,13 @@ "dev": true, "license": "MIT" }, + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true, + "license": "MIT" + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -2719,6 +3292,15 @@ "node": ">=8" } }, + "node_modules/docopt": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/docopt/-/docopt-0.6.2.tgz", + "integrity": "sha512-NqTbaYeE4gA/wU1hdKFdU+AFahpDOpgGLzHP42k6H6DKExJd0A55KEVWYhL9FEmHmgeLvEU2vuKXDuU+4yToOw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -2732,6 +3314,19 @@ "node": ">=6.0.0" } }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -2746,6 +3341,116 @@ "node": ">= 0.4" } }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexer2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexer2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/duplexer3": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", + "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/duplexify/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/duplexify/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexify/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/duplexify/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -2768,6 +3473,25 @@ "node": ">= 0.8" } }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/ends-with": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ends-with/-/ends-with-0.2.0.tgz", + "integrity": "sha512-lRppY4dK3VkqBdR242sKcAJeYc8Gf/DhoX9AWvWI2RzccmLnqBQfwm2k4oSDv5MPDjUqawCauXhZkyWxkVhRsg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/error-ex": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", @@ -2931,6 +3655,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es6-denodeify": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-denodeify/-/es6-denodeify-0.1.5.tgz", + "integrity": "sha512-731Rf4NqlPvhkT1pIF7r8vZxESJlWocNpXLuyPlVnfEGXlwuJaMvU5WpyyDjpudDC2cgXVX849xljzvQqBg1QQ==", + "dev": true, + "license": "Unlicense" + }, + "node_modules/es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", + "dev": true, + "license": "MIT" + }, "node_modules/esbuild": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", @@ -2973,6 +3711,16 @@ "@esbuild/win32-x64": "0.27.2" } }, + "node_modules/escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -3274,6 +4022,20 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", @@ -3576,6 +4338,13 @@ "url": "https://opencollective.com/express" } }, + "node_modules/find-index": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", + "integrity": "sha512-uJ5vWrfBKMcE6y2Z8834dwEZj9mNGxYa3t3I53OwFeuZ8D9oc2E5zcsrkuhX6h4iYrjhiv0T3szQmxlAV9uxDg==", + "dev": true, + "license": "MIT" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -3615,6 +4384,57 @@ "dev": true, "license": "ISC" }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "node_modules/flush-write-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/flush-write-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/flush-write-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/flush-write-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -3696,6 +4516,71 @@ "rimraf": "bin.js" } }, + "node_modules/fs-mkdirp-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", + "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fs-mkdirp-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/fs-mkdirp-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/fs-mkdirp-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fs-mkdirp-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/fs-mkdirp-stream/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3805,16 +4690,39 @@ "node": ">= 0.4" } }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "node_modules/get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -3866,6 +4774,114 @@ "node": ">=10.13.0" } }, + "node_modules/glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/glob-stream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-stream/node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/glob-stream/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/glob-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/glob-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/glob-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/glob/node_modules/minimatch": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", @@ -3880,6 +4896,41 @@ "node": "*" } }, + "node_modules/glob2base": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", + "integrity": "sha512-ZyqlgowMbfj2NPjxaZZ/EtsXlOch28FRXgMd64vqZWk1bT9+wvSRLYD1om9M7QfQru51zJPAT17qXm4/zd+9QA==", + "dev": true, + "dependencies": { + "find-index": "^0.1.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/global-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", + "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "1.3.7" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-dirs/node_modules/ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", + "dev": true, + "license": "ISC" + }, "node_modules/global-modules": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", @@ -3993,6 +5044,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -4118,6 +5192,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -4130,6 +5214,16 @@ "node": ">= 0.4" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, "node_modules/hono": { "version": "4.11.1", "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.1.tgz", @@ -4160,6 +5254,52 @@ "dev": true, "license": "MIT" }, + "node_modules/html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + }, + "bin": { + "html-minifier": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/html-minifier/node_modules/uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/html-minifier/node_modules/uglify-js/node_modules/commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "dev": true, + "license": "MIT" + }, "node_modules/html-tags": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", @@ -4173,6 +5313,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/http-errors": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", @@ -4367,6 +5514,20 @@ "node": ">= 0.10" } }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -4428,6 +5589,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-boolean-object": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", @@ -4445,6 +5620,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true, + "license": "MIT" + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -4458,6 +5640,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", @@ -4578,6 +5773,23 @@ "node": ">=0.10.0" } }, + "node_modules/is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", @@ -4591,6 +5803,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-negative-zero": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", @@ -4604,6 +5826,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -4631,6 +5863,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -4686,6 +5928,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-set": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", @@ -4766,6 +6021,43 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-valid-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-weakmap": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", @@ -4812,10 +6104,27 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true, "license": "MIT" }, @@ -5007,6 +6316,85 @@ "dev": true, "license": "MIT" }, + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "license": "MIT", + "dependencies": { + "package-json": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/lead": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", + "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==", + "dev": true, + "license": "MIT", + "dependencies": { + "flush-write-stream": "^1.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5051,6 +6439,178 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash._basebind": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._basebind/-/lodash._basebind-2.4.1.tgz", + "integrity": "sha512-VGHm6DH+1UiuafQdE/DNMqxOcSyhRu0xO9+jPDq7xITRn5YOorGrHVQmavMVXCYmTm80YRTZZCn/jTW7MokwLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._basecreate": "~2.4.1", + "lodash._setbinddata": "~2.4.1", + "lodash._slice": "~2.4.1", + "lodash.isobject": "~2.4.1" + } + }, + "node_modules/lodash._basecreate": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-2.4.1.tgz", + "integrity": "sha512-8JJ3FnMPm54t3BwPLk8q8mPyQKQXm/rt9df+awr4NGtyJrtcCXM3Of1I86S6jVy1b4yAyFBb8wbKPEauuqzRmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._isnative": "~2.4.1", + "lodash.isobject": "~2.4.1", + "lodash.noop": "~2.4.1" + } + }, + "node_modules/lodash._basecreatecallback": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._basecreatecallback/-/lodash._basecreatecallback-2.4.1.tgz", + "integrity": "sha512-SLczhg860fGW7AKlYcuOFstDtJuQhaANlJ4Y/jrOoRxhmVtK41vbJDH3OefVRSRkSCQo4HI82QVkAVsoGa5gSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._setbinddata": "~2.4.1", + "lodash.bind": "~2.4.1", + "lodash.identity": "~2.4.1", + "lodash.support": "~2.4.1" + } + }, + "node_modules/lodash._basecreatewrapper": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.4.1.tgz", + "integrity": "sha512-x2ja1fa/qmzbizuXgVM4QAP9svtMbdxjG8Anl9bCeDAwLOVQ1vLrA0hLb/NkpbGi9evjtkl0aWLTEoOlUdBPQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._basecreate": "~2.4.1", + "lodash._setbinddata": "~2.4.1", + "lodash._slice": "~2.4.1", + "lodash.isobject": "~2.4.1" + } + }, + "node_modules/lodash._createwrapper": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._createwrapper/-/lodash._createwrapper-2.4.1.tgz", + "integrity": "sha512-5TCfLt1haQpsa7bgLYRKNNE4yqhO4ZxIayN1btQmazMchO6Q8JYFRMqbJ3W+uNmMm4R0Jw7KGkZX5YfDDnywuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._basebind": "~2.4.1", + "lodash._basecreatewrapper": "~2.4.1", + "lodash._slice": "~2.4.1", + "lodash.isfunction": "~2.4.1" + } + }, + "node_modules/lodash._isnative": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._isnative/-/lodash._isnative-2.4.1.tgz", + "integrity": "sha512-BOlKGKNHhCHswGOWtmVb5zBygyxN7EmTuzVOSQI6QSoGhG+kvv71gICFS1TBpnqvT1n53txK8CDK3u5D2/GZxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash._objecttypes": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz", + "integrity": "sha512-XpqGh1e7hhkOzftBfWE7zt+Yn9mVHFkDhicVttvKLsoCMLVVL+xTQjfjB4X4vtznauxv0QZ5ZAeqjvat0dh62Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash._setbinddata": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._setbinddata/-/lodash._setbinddata-2.4.1.tgz", + "integrity": "sha512-Vx0XKzpg2DFbQw4wrp1xSWd2sfl3W/BG6bucSRZmftS1AzbWRemCmBQDxyQTNhlLNec428PXkuuja+VNBZgu2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._isnative": "~2.4.1", + "lodash.noop": "~2.4.1" + } + }, + "node_modules/lodash._shimkeys": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.4.1.tgz", + "integrity": "sha512-lBrglYxLD/6KAJ8IEa5Lg+YHgNAL7FyKqXg4XOUI+Du/vtniLs1ZqS+yHNKPkK54waAgkdUnDOYaWf+rv4B+AA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._objecttypes": "~2.4.1" + } + }, + "node_modules/lodash._slice": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._slice/-/lodash._slice-2.4.1.tgz", + "integrity": "sha512-+odPJa4PE2UgYnQgJgkLs0UD03QU78R2ivhrFnG9GdtYOZdE6ObxOj7KiUEUlqOOgatFT+ZqSypFjDSduTigKg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.assign": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-2.4.1.tgz", + "integrity": "sha512-AqQ4AJz5buSx9ELXWt5dONwJyVPd4NTADMKhoVYWCugjoVf172/LpvVhwmSJn4g8/Dc0S8hxTe8rt5Dob3X9KQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._basecreatecallback": "~2.4.1", + "lodash._objecttypes": "~2.4.1", + "lodash.keys": "~2.4.1" + } + }, + "node_modules/lodash.bind": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-2.4.1.tgz", + "integrity": "sha512-hn2VWYZ+N9aYncRad4jORvlGgpFrn+axnPIWRvFxjk6CWcZH5b5alI8EymYsHITI23Z9wrW/+ORq+azrVFpOfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._createwrapper": "~2.4.1", + "lodash._slice": "~2.4.1" + } + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.identity": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.identity/-/lodash.identity-2.4.1.tgz", + "integrity": "sha512-VRYX+8XipeLjorag5bz3YBBRJ+5kj8hVBzfnaHgXPZAVTYowBdY5l0M5ZnOmlAMCOXBFabQtm7f5VqjMKEji0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isfunction": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-2.4.1.tgz", + "integrity": "sha512-6XcAB3izeQxPOQQNAJbbdjXbvWEt2Pn9ezPrjr4CwoLwmqsLVbsiEXD19cmmt4mbzOCOCdHzOQiUivUOJLra7w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isobject": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz", + "integrity": "sha512-sTebg2a1PoicYEZXD5PBdQcTlIJ6hUslrlWr7iV0O7n+i4596s2NQ9I5CaZ5FbXSfya/9WQsrYLANUJv9paYVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._objecttypes": "~2.4.1" + } + }, + "node_modules/lodash.keys": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.4.1.tgz", + "integrity": "sha512-ZpJhwvUXHSNL5wYd1RM6CUa2ZuqorG9ngoJ9Ix5Cce+uX7I5O/E06FCJdhSZ33b5dVyeQDnIlWH7B2s5uByZ7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._isnative": "~2.4.1", + "lodash._shimkeys": "~2.4.1", + "lodash.isobject": "~2.4.1" + } + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5058,6 +6618,23 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.noop": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.noop/-/lodash.noop-2.4.1.tgz", + "integrity": "sha512-uNcV98/blRhInPUGQEnj9ekXXfG+q+rfoNSFZgl/eBfog9yBDW9gfUv2AHX/rAF7zZRlzWhbslGhbGQFZlCkZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.support": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.support/-/lodash.support-2.4.1.tgz", + "integrity": "sha512-6SwqWwGFHhTXEiqB/yQgu8FYd//tm786d49y7kizHVCJH7zdzs191UQn3ES3tkkDbUddNRfkCRYqJFHtbLnbCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._isnative": "~2.4.1" + } + }, "node_modules/lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", @@ -5065,6 +6642,30 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -5198,6 +6799,13 @@ "node": ">= 0.8" } }, + "node_modules/memoize-decorator": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/memoize-decorator/-/memoize-decorator-1.0.2.tgz", + "integrity": "sha512-G2vHcq4c+EwnBAOeWCH1mNz99QPCgm4ECjhHOd3SFZm66jVlwhBLdqhCvnHxptaRyZfm8ap3igoeDfrO92+uHQ==", + "dev": true, + "license": "MIT" + }, "node_modules/meow": { "version": "10.1.5", "resolved": "https://registry.npmjs.org/meow/-/meow-10.1.5.tgz", @@ -5306,6 +6914,26 @@ "url": "https://opencollective.com/express" } }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -5344,12 +6972,36 @@ "node": ">= 6" } }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/multipipe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-1.0.2.tgz", + "integrity": "sha512-6uiC9OvY71vzSGX8lZvSqscE7ft9nPupJ8fMjrCNRAUy2LREUW42UL+V/NTrogr6rFgRydUrCX4ZitfpSNkSCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexer2": "^0.1.2", + "object-assign": "^4.1.0" + } + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -5402,6 +7054,16 @@ "dev": true, "license": "MIT" }, + "node_modules/no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "lower-case": "^1.1.1" + } + }, "node_modules/node-addon-api": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", @@ -5448,6 +7110,39 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/now-and-later": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.3.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -5603,6 +7298,56 @@ "node": ">= 0.8.0" } }, + "node_modules/ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.1" + } + }, + "node_modules/ordered-read-streams/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/ordered-read-streams/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/ordered-read-streams/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/ordered-read-streams/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/own-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", @@ -5621,6 +7366,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -5653,6 +7408,32 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^2.2.0" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -5694,6 +7475,13 @@ "node": ">= 0.8" } }, + "node_modules/path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", + "dev": true, + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -5926,6 +7714,16 @@ "node": ">= 0.8.0" } }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/prettier": { "version": "3.7.4", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", @@ -5984,6 +7782,13 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -5997,6 +7802,40 @@ "node": ">= 0.10" } }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/pumpify/node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -6007,6 +7846,19 @@ "node": ">=6" } }, + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-goat": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -6092,6 +7944,32 @@ "node": ">= 0.10" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -6162,6 +8040,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -6228,6 +8121,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true, + "license": "MIT" + }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -6249,6 +8149,139 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/registry-auth-token": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", + "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "license": "MIT", + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/remove-bom-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remove-bom-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/remove-bom-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/remove-bom-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/remove-bom-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/remove-bom-stream/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "dev": true, + "license": "ISC" + }, + "node_modules/replace-ext": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", + "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -6289,6 +8322,19 @@ "node": ">=4" } }, + "node_modules/resolve-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", + "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "value-or-function": "^3.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -6299,6 +8345,16 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -6460,6 +8516,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/safe-push-apply": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", @@ -6495,38 +8572,188 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-wipe": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/safe-wipe/-/safe-wipe-0.2.5.tgz", + "integrity": "sha512-MwTNf4YrRqCHsB5jUzOVdXoRbW4jkhgTvhlyfiaxox8EP7cOCiD4ydMOQCxDPR9KpvwdBSM2dQHScV1m85k8wQ==", + "dev": true, + "license": "Unlicense", + "dependencies": { + "extend": "^3.0.2", + "q": "1.*", + "rimraf": "2.*" + } + }, + "node_modules/safe-wipe/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-wipe/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, - "node_modules/sass": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.92.1.tgz", - "integrity": "sha512-ffmsdbwqb3XeyR8jJR6KelIXARM9bFQe8A6Q3W4Klmwy5Ckd5gz7jgUNHo4UOqutU5Sk1DtKLbpDP0nLCg1xqQ==", - "license": "MIT", - "optional": true, - "peer": true, + "node_modules/sass-convert": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/sass-convert/-/sass-convert-0.5.2.tgz", + "integrity": "sha512-eV9wXZg7MrHmnKLD6WojC/WX7lhLm+PSSLrOukzRIECa04fGbkmFDO9Ot9/82KjzSe+VEClYe9WDKzCuBz30Dg==", + "dev": true, + "license": "Unlicense", "dependencies": { - "chokidar": "^4.0.0", - "immutable": "^5.0.2", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" + "concat-stream": "^1.4.7", + "dargs": "^4.0.0", + "ends-with": "^0.2.0", + "es6-denodeify": "^0.1.0", + "es6-promise": "^3.0.2", + "memoize-decorator": "^1.0.2", + "object-assign": "^3.0.0", + "semver": "^5.0.1", + "semver-regex": "^1.0.0", + "through2": "^2.0.0", + "which": "^1.0.5" }, "engines": { - "node": ">=14.0.0" - }, - "optionalDependencies": { - "@parcel/watcher": "^2.4.1" + "node": ">=0.10.0", + "npm": ">=2.1.0" } }, - "node_modules/sass-embedded": { - "version": "1.92.1", - "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.92.1.tgz", - "integrity": "sha512-28YwLnF5atAhogt3E4hXzz/NB9dwKffyw08a7DEasLh94P7+aELkG3ENSHYCWB9QFN14hYNLfwr9ozUsPDhcDQ==", + "node_modules/sass-convert/node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/sass-convert/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/sass-convert/node_modules/object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sass-convert/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/sass-convert/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/sass-convert/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/sass-convert/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/sass-convert/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/sass-convert/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/sass-embedded": { + "version": "1.92.1", + "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.92.1.tgz", + "integrity": "sha512-28YwLnF5atAhogt3E4hXzz/NB9dwKffyw08a7DEasLh94P7+aELkG3ENSHYCWB9QFN14hYNLfwr9ozUsPDhcDQ==", "license": "MIT", "peer": true, "dependencies": { @@ -6896,6 +9123,42 @@ } } }, + "node_modules/sassdoc": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/sassdoc/-/sassdoc-2.7.4.tgz", + "integrity": "sha512-/HEjX9pMILkePyC4ZKGhkLqZHJZpsTxFwQIQNsLhV4XHiPKoWHrSmam1pMntM79tcdtBII3JX7ShfyZjHnrkyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.2.1", + "babel-runtime": "^6.26.0", + "chalk": "^2.4.2", + "concat-stream": "^2.0.0", + "docopt": "^0.6.1", + "glob": "^7.1.6", + "glob2base": "0.0.12", + "js-yaml": "^3.14.0", + "lodash.difference": "^4.5.0", + "lodash.uniq": "^4.5.0", + "minimatch": "^3.0.4", + "mkdirp": "^1.0.4", + "multipipe": "1.0.2", + "rimraf": "^3.0.2", + "safe-wipe": "0.2.5", + "sass-convert": "^0.5.0", + "sassdoc-theme-default": "^2.8.3", + "scss-comment-parser": "^0.8.4", + "strip-indent": "^3.0.0", + "through2": "1.1.1", + "update-notifier": "^4.1.0", + "vinyl-fs": "^3.0.3", + "vinyl-source-stream": "1.1.2", + "vinyl-string": "^1.0.2" + }, + "bin": { + "sassdoc": "bin/sassdoc" + } + }, "node_modules/sassdoc-extras": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/sassdoc-extras/-/sassdoc-extras-2.5.1.tgz", @@ -6941,6 +9204,253 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/sassdoc-theme-default": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/sassdoc-theme-default/-/sassdoc-theme-default-2.8.6.tgz", + "integrity": "sha512-s12y6pThpPDm33UScHfnfa/RBs9+gkCxl/YNWDTyLl3a6IxzusEdut1uwv4fpmpaOsTpcjGxZw839Moi4d/3Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-runtime": "^6.22.0", + "chroma-js": "^1.2.2", + "es6-denodeify": "^0.1.0", + "es6-promise": "^4.2.6", + "extend": "^3.0.2", + "fs-extra": "^2.0.0", + "html-minifier": "^3.5.21", + "nunjucks": "^3.1.7", + "sassdoc-extras": "^2.5.0" + } + }, + "node_modules/sassdoc-theme-default/node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/sassdoc-theme-default/node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/sassdoc-theme-default/node_modules/fs-extra": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz", + "integrity": "sha512-9ztMtDZtSKC78V8mev+k31qaTabbmuH5jatdvPBMikrFHvw5BqlYnQIn/WGK3WHeRooSTkRvLa2IPlaHjPq5Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0" + } + }, + "node_modules/sassdoc-theme-default/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/sassdoc-theme-default/node_modules/nunjucks": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz", + "integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "a-sync-waterfall": "^1.0.0", + "asap": "^2.0.3", + "commander": "^5.1.0" + }, + "bin": { + "nunjucks-precompile": "bin/precompile" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "chokidar": "^3.3.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/sassdoc-theme-default/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/sassdoc/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/sassdoc/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sassdoc/node_modules/chalk/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sassdoc/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/sassdoc/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/sassdoc/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/sassdoc/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sassdoc/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/sassdoc/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/sassdoc/node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sassdoc/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/scss-comment-parser": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/scss-comment-parser/-/scss-comment-parser-0.8.4.tgz", + "integrity": "sha512-ERw4BODvM22n8Ke8hJxuH3fKXLm0Q4chfUNHwDSOAExCths2ZXq8PT32vms4R9Om6dffRSXzzGZS1p38UU4EAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cdocparser": "^0.13.0" + } + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -6951,6 +9461,29 @@ "semver": "bin/semver.js" } }, + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semver-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-1.0.0.tgz", + "integrity": "sha512-1vZcoRC+LPtHFkLUPyrabsATDSHerxW+hJBN8h04HZOZBuewbXaNROtUVdEPrTdZsWNq6sfsXDhd48GB2xTG4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/send": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", @@ -7308,6 +9841,13 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -7345,6 +9885,23 @@ "node": ">= 0.4" } }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -7796,6 +10353,19 @@ "node": ">=10.0.0" } }, + "node_modules/term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -7803,8 +10373,108 @@ "dev": true, "license": "MIT" }, - "node_modules/tinybench": { - "version": "2.9.0", + "node_modules/through2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "integrity": "sha512-zEbpaeSMHxczpTzO1KkMHjBC1enTA68ojeaZGG4toqdASpb9t4xUZaYFBq2/9OHo5nTGFVSYd4c910OR+6wxbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": ">=1.1.13-1 <1.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, + "node_modules/through2-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "node_modules/through2-filter/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2-filter/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/through2-filter/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2-filter/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/through2-filter/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/through2/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", "dev": true, @@ -7879,6 +10549,30 @@ "node": ">=14.0.0" } }, + "node_modules/to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -7892,6 +10586,70 @@ "node": ">=8.0" } }, + "node_modules/to-through": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", + "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/to-through/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-through/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/to-through/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-through/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/to-through/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -8072,6 +10830,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -8120,6 +10895,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/undici-types": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", @@ -8127,6 +10912,30 @@ "dev": true, "license": "MIT" }, + "node_modules/unique-stream": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.4.0.tgz", + "integrity": "sha512-V6QarSfeSgDipGA9EZdoIzu03ZDlOFkk+FbEP5cwgrZXN3iIkYR91IjU2EnM6rB835kGQsqHX8qncObTXV+6KA==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "3.0.0" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -8146,6 +10955,65 @@ "node": ">= 0.8" } }, + "node_modules/update-notifier": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", + "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", + "dev": true, + "license": "MIT" + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -8156,6 +11024,19 @@ "punycode": "^2.1.0" } }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -8174,6 +11055,16 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/value-or-function": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", + "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/varint": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", @@ -8189,12 +11080,286 @@ "node": ">= 0.8" } }, + "node_modules/vinyl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", + "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-fs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "dev": true, + "license": "MIT", + "dependencies": { + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "value-or-function": "^3.0.0", + "vinyl": "^2.0.0", + "vinyl-sourcemap": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-fs/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vinyl-fs/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/vinyl-fs/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/vinyl-fs/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/vinyl-fs/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/vinyl-source-stream": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vinyl-source-stream/-/vinyl-source-stream-1.1.2.tgz", + "integrity": "sha512-X+1Jq+M6ufv/ky480hndPBsNb0ieqTQkvpakxMTxb7oUlyuNaJKL2HddYUrbTec0Lb0J53JlDiCetcgJ3b3Wmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "through2": "^2.0.3", + "vinyl": "^0.4.3" + } + }, + "node_modules/vinyl-source-stream/node_modules/clone": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", + "integrity": "sha512-g62n3Kb9cszeZvmvBUqP/dsEJD/+80pDA8u8KqHnAPrVnQ2Je9rVV6opxkhuWCd1kCn2gOibzDKxCtBvD3q5kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/vinyl-source-stream/node_modules/clone-stats": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vinyl-source-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vinyl-source-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/vinyl-source-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/vinyl-source-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/vinyl-source-stream/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/vinyl-source-stream/node_modules/vinyl": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", + "integrity": "sha512-pmza4M5VA15HOImIQYWhoXGlGNafCm0QK5BpBUXkzzEwrRxKqBsbAhTfkT2zMcJhUX1G1Gkid0xaV8WjOl7DsA==", + "dev": true, + "dependencies": { + "clone": "^0.2.0", + "clone-stats": "^0.0.1" + }, + "engines": { + "node": ">= 0.9" + } + }, + "node_modules/vinyl-sourcemap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", + "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-sourcemap/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vinyl-string": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/vinyl-string/-/vinyl-string-1.0.2.tgz", + "integrity": "sha512-mDkPUvCM7K9r0WYZKIWc/dfPH8wkJBbe/3wZUU9EJyw3g6VSACg6FLlcZ/QbP1lTSdtBsVjQoYG1a9K0cfoKeQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "vinyl": "^1.1.1" + } + }, + "node_modules/vinyl-string/node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/vinyl-string/node_modules/clone-stats": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vinyl-string/node_modules/replace-ext": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "integrity": "sha512-AFBWBy9EVRTa/LhEcG8QDP3FvpwZqmvN2QFDuJswFeaVhWnZMp8q3E6Zd90SR04PlIwfGdyVjNyLPyen/ek5CQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/vinyl-string/node_modules/vinyl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", + "integrity": "sha512-Ci3wnR2uuSAWFMSglZuB8Z2apBdtOyz8CV7dC6/U1XbltXBC+IuutUkXQISz01P+US2ouBuesSbV6zILZ6BuzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.0", + "clone-stats": "^0.0.1", + "replace-ext": "0.0.1" + }, + "engines": { + "node": ">= 0.9" + } + }, "node_modules/vite": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz", "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -8509,6 +11674,19 @@ "node": ">=8" } }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -8546,6 +11724,26 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/package.json b/package.json index 3f51bc71..3a11ffcd 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "build:docs:en:production": "set NODE_ENV=production && npx sassdoc ./sass -d docs", "build:docs:en:staging": "set NODE_ENV=staging && npx sassdoc ./sass -d docs", "build:e2e": "sass --quiet ./test/e2e/theme.scss ./test/e2e/theme.css", - "build:json": "node scripts/buildJSON.mjs", + "build:json": "node scripts/buildJSON.mjs && node scripts/buildComponentDocs.mjs", "build:tailwind": "npm run clean:tailwind && node scripts/buildTailwind.mjs", "build:mcp": "npm run build:json && tsc -p tsconfig.json && node -e \"require('fs').chmodSync('dist/mcp/index.js', '755')\"", "serve:docs": "npx http-server ./docs", @@ -109,6 +109,7 @@ "postcss-safe-parser": "^7.0.0", "prettier": "^3.2.5", "sass-true": "^9.0.0", + "sassdoc": "^2.7.4", "sassdoc-plugin-localization": "^2.0.0", "shx": "^0.3.4", "stylelint": "^15.6.2", diff --git a/sass/json/components.scss b/sass/json/components.scss new file mode 100644 index 00000000..9327a6fa --- /dev/null +++ b/sass/json/components.scss @@ -0,0 +1,52 @@ +// stylelint-disable selector-type-no-unknown, max-nesting-depth +@use 'sass:map'; +@use 'sass:list'; +@use 'sass:meta'; +@use '../themes/schemas' as schemas; +@use '../themes/functions' as *; + +$schemas: meta.module-variables(schemas); +$compound: ('button', 'icon-button'); + +/* +* @outputDir - /components +*/ +@each $key, $value in $schemas { + @each $_component, $_schema in map.remove($value, '_meta') { + @if list.index($compound, $_component) { + @each $_sub-component, $_sub-schema in $_schema { + $_t: map.get($_sub-schema, '_meta', 'theme'); + $_v: map.get($_sub-schema, '_meta', 'variant'); + + #{$_t} { + > #{$_v} { + > #{$_component}-#{$_sub-component} { + @each $_token, $_value in map.remove(digest-schema($_sub-schema), '_meta') { + @if $_token != typography { + --#{$_token}: #{$_value}; + } + } + } + } + } + } + } @else { + $_t: map.get($_schema, '_meta', 'theme'); + $_v: map.get($_schema, '_meta', 'variant'); + + @if $_v != null and $_t != null { + #{$_t} { + > #{$_v} { + > #{$_component} { + @each $_token, $_value in map.remove(digest-schema($_schema), '_meta') { + @if $_token != typography { + --#{$_token}: #{$_value}; + } + } + } + } + } + } + } + } +} diff --git a/sass/themes/components/action-strip/_action-strip-theme.scss b/sass/themes/components/action-strip/_action-strip-theme.scss index 0f584e9a..0524770b 100644 --- a/sass/themes/components/action-strip/_action-strip-theme.scss +++ b/sass/themes/components/action-strip/_action-strip-theme.scss @@ -13,12 +13,17 @@ /// @author Marin Popov //// +/// Action Strip Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$actions-background` - The actions background color. Auto-derives: icon-color. +/// /// If only background color is specified, text/icon color will be assigned automatically to a contrasting color. -/// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// -/// @param {Color} $icon-color [null] - The color used for the actions icons. +/// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. +/// @param {Color} $icon-color [null] - The color used for the actions icons. Auto-derived from actions-background. /// @param {Color} $background [null] - The color used for the action strip component content background. -/// @param {Color} $actions-background [null] - The color used for the actions background. +/// @param {Color} $actions-background [null] - The color used for the actions background. PRIMARY - derives icon-color. /// @param {Color} $delete-action [null] - The color used for the delete icon in action strip component. /// @param {List} $actions-border-radius [null] - The border radius used for actions container inside action strip component. /// diff --git a/sass/themes/components/avatar/_avatar-theme.scss b/sass/themes/components/avatar/_avatar-theme.scss index 9ca13ede..c11ee4c5 100644 --- a/sass/themes/components/avatar/_avatar-theme.scss +++ b/sass/themes/components/avatar/_avatar-theme.scss @@ -14,11 +14,17 @@ /// @author Marin Popov //// +/// Avatar Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` - The avatar background color. Auto-derives: color (text), icon-color. +/// /// If only background color is specified, text/icon color will be assigned automatically to a contrasting color. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $color [null] - The text color used of the avatar. -/// @param {Color} $icon-color [null] - The icon color used of the avatar. -/// @param {Color} $background [null] - The background color used of the avatar. +/// @param {Color} $background [null] - The background color used of the avatar. PRIMARY - derives color, icon-color. +/// @param {Color} $color [null] - The text color used of the avatar. Auto-derived from background. +/// @param {Color} $icon-color [null] - The icon color used of the avatar. Auto-derived from background. /// @param {Number} $border-radius [null] - The border-radius used of the avatar. /// @param {Number} $size [null] - The size of the avatar. /// @requires $light-material-schema diff --git a/sass/themes/components/badge/_badge-theme.scss b/sass/themes/components/badge/_badge-theme.scss index b69e8020..3ba1f1b5 100644 --- a/sass/themes/components/badge/_badge-theme.scss +++ b/sass/themes/components/badge/_badge-theme.scss @@ -14,14 +14,18 @@ /// @author Marin Popov //// -/// If only background color is specified, text/icon color -/// will be assigned automatically to a contrasting color. +/// Badge Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background-color` - The badge background color. Auto-derives: icon-color, text-color (via contrast). +/// +/// Setting just `$background-color` will create a complete badge theme with proper text/icon contrast. /// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $icon-color [null] - The icon color used. -/// @param {Color} $text-color [null] - The text color used. +/// @param {Color} $icon-color [null] - The icon color used. Auto-derived from background-color. +/// @param {Color} $text-color [null] - The text color used. Auto-derived from background-color. /// @param {Color} $border-color [null] - The border color used. -/// @param {Color} $background-color [null] - The background color used. +/// @param {Color} $background-color [null] - The background color used. PRIMARY - derives icon-color and text-color. /// @param {box-shadow} $shadow [null] - Sets a shadow to be used for the badge. /// @param {Number} $border-radius [null] - The border radius used for badge component. /// @param {Number} $size [null] - The size of the badge component. diff --git a/sass/themes/components/banner/_banner-theme.scss b/sass/themes/components/banner/_banner-theme.scss index 06c5c6d1..dc278358 100644 --- a/sass/themes/components/banner/_banner-theme.scss +++ b/sass/themes/components/banner/_banner-theme.scss @@ -13,14 +13,18 @@ /// @author Marin Popov //// -/// If only background color is specified, text/icon color -/// will be assigned automatically to a contrasting color. -/// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. +/// Banner Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$banner-background` - The banner background color. Auto-derives: banner-message-color, banner-illustration-color. /// -/// @param {Color} $banner-background [null] - The color used for the banner background. -/// @param {Color} $banner-message-color [null] - The color used for the banner label. +/// If only background color is specified, text/icon color will be assigned automatically to a contrasting color. +/// +/// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. +/// @param {Color} $banner-background [null] - The color used for the banner background. PRIMARY - derives message and illustration colors. +/// @param {Color} $banner-message-color [null] - The color used for the banner label. Auto-derived from banner-background. /// @param {Color} $banner-border-color [null] - The color used for the banner border. -/// @param {Color} $banner-illustration-color [null] - The color used for the banner illustration. +/// @param {Color} $banner-illustration-color [null] - The color used for the banner illustration. Auto-derived from banner-background. /// @param {Number} $border-radius [null] - The border-radius for the banner. /// /// @requires $light-material-schema diff --git a/sass/themes/components/bottom-nav/_bottom-nav-theme.scss b/sass/themes/components/bottom-nav/_bottom-nav-theme.scss index 97dcc9ef..9d3b4321 100644 --- a/sass/themes/components/bottom-nav/_bottom-nav-theme.scss +++ b/sass/themes/components/bottom-nav/_bottom-nav-theme.scss @@ -14,16 +14,24 @@ /// @author Marin Popov //// -/// If only background color is specified, -/// the label and icon colors will be assigned automatically to a contrasting color. +/// Bottom Navigation Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` - The bar background color. Auto-derives: label-color, icon-color, disabled colors. +/// - `$label-color` or `$icon-color` - Idle state colors. Either one derives the other, plus disabled colors. +/// - `$label-selected-color` or `$icon-selected-color` - Selected state colors. Either one derives the other. +/// +/// If only background color is specified, the label and icon colors will be assigned automatically to a contrasting color. +/// Label and icon colors are kept in sync - setting one derives the other if not explicitly set. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $background [null] - The background color used for the toast. -/// @param {Color} $label-color [null] - The label color used in idle state. -/// @param {Color} $icon-color [null] - The icon color used in idle state. -/// @param {Color} $label-selected-color [null] - The label color used in selected state. -/// @param {Color} $icon-selected-color [null] - The icon color used in selected state. -/// @param {Color} $icon-disabled-color [null] - The disabled color of the icon. -/// @param {Color} $label-disabled-color [null] - The disabled color of the label. +/// @param {Color} $background [null] - The background color used for the bar. PRIMARY - derives label-color, icon-color. +/// @param {Color} $label-color [null] - The label color used in idle state. Auto-derived from background. Derives icon-color if not set. +/// @param {Color} $icon-color [null] - The icon color used in idle state. Auto-derived from label-color if not set. +/// @param {Color} $label-selected-color [null] - The label color used in selected state. Derives icon-selected-color if not set. +/// @param {Color} $icon-selected-color [null] - The icon color used in selected state. Auto-derived from label-selected-color if not set. +/// @param {Color} $icon-disabled-color [null] - The disabled color of the icon. Auto-derived from label-disabled-color if not set. +/// @param {Color} $label-disabled-color [null] - The disabled color of the label. Auto-derived from label-color. /// @param {Color} $border-color [null] - The border color of the bottom navigation. /// @param {box-shadow} $shadow [null] - Sets a shadow to be used for the bar. /// @requires $light-material-schema diff --git a/sass/themes/components/button-group/_button-group-theme.scss b/sass/themes/components/button-group/_button-group-theme.scss index 6a4ad08b..feb27496 100644 --- a/sass/themes/components/button-group/_button-group-theme.scss +++ b/sass/themes/components/button-group/_button-group-theme.scss @@ -13,49 +13,56 @@ /// @author Marin Popov //// -/// If only background color is specified, text/icon color -/// will be assigned automatically to a contrasting color. +/// Button Group Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$item-background` - The base item background. Auto-derives: item-text-color, item-icon-color, item-border-color, all hover/selected/focused/disabled backgrounds and colors. +/// - `$item-selected-background` - The selected item background. Auto-derives: selected text/icon colors, selected hover/focus backgrounds. +/// +/// If only background color is specified, text/icon color will be assigned automatically to a contrasting color. /// Does ___not___ apply for disabled state colors. -/// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. +/// Border colors cascade from item-border-color through all states. +/// Icon colors are kept in sync with their corresponding text colors. /// +/// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {box-shadow} $shadow [null] - The shadow to be applied for the button group. -/// @param {Color} $item-text-color [null]- The text color for button group items. -/// @param {color} $item-icon-color [null]- The icon color for button group items. -/// @param {Color} $item-background [null] - The background color for button group items . -/// @param {Color} $item-border-color [null] - The border color between button group items. +/// @param {Color} $item-text-color [null]- The text color for button group items. Auto-derived from item-background. +/// @param {color} $item-icon-color [null]- The icon color for button group items. Auto-derived from item-text-color. +/// @param {Color} $item-background [null] - The background color for button group items. PRIMARY - derives all state colors. +/// @param {Color} $item-border-color [null] - The border color between button group items. Auto-derived from item-background. /// -/// @param {Color} $item-hover-text-color [null] - The hover text color for button group items. -/// @param {Color} $item-hover-icon-color [null] - The hover icon color for button group items. -/// @param {Color} $item-hover-background [null] - The hover background color for button group items. -/// @param {Color} $item-hover-border-color [null] - The hover border color between button group items. +/// @param {Color} $item-hover-text-color [null] - The hover text color for button group items. Auto-derived from item-hover-background. +/// @param {Color} $item-hover-icon-color [null] - The hover icon color for button group items. Auto-derived from item-hover-text-color. +/// @param {Color} $item-hover-background [null] - The hover background color for button group items. Auto-derived from item-background. +/// @param {Color} $item-hover-border-color [null] - The hover border color between button group items. Auto-derived from item-border-color. /// -/// @param {Color} $item-focused-text-color [null] - The focused text color for button group items. -/// @param {Color} $item-focused-background [null] - The focused background color for button group items. -/// @param {Color} $item-focused-border-color [null] - The focused border color for an item from the button group. -/// @param {Color} $item-focused-hover-background [null] - The focused & hover background color for button group items. -/// @param {Color} $idle-shadow-color [null] - The outline color of focused button group items. -/// @param {Color} $selected-shadow-color [null] - The outline color of focused/selected button group items. +/// @param {Color} $item-focused-text-color [null] - The focused text color for button group items. Auto-derived from item-focused-background. +/// @param {Color} $item-focused-background [null] - The focused background color for button group items. Auto-derived from item-hover-background. +/// @param {Color} $item-focused-border-color [null] - The focused border color for an item from the button group. Auto-derived from item-border-color. +/// @param {Color} $item-focused-hover-background [null] - The focused & hover background color for button group items. Auto-derived from item-focused-background. +/// @param {Color} $idle-shadow-color [null] - The outline color of focused button group items. Auto-derived from item-background or selected-shadow-color. +/// @param {Color} $selected-shadow-color [null] - The outline color of focused/selected button group items. Auto-derived from idle-shadow-color. /// -/// @param {Color} $disabled-text-color [null]- The text/icon color for a disabled item in the button group. -/// @param {Color} $disabled-background-color [null] - The background color for a disabled item in the button group. -/// @param {Color} $item-disabled-border [null] - The border color for a disabled item in the button group. +/// @param {Color} $disabled-text-color [null]- The text/icon color for a disabled item in the button group. Auto-derived from disabled-background-color. +/// @param {Color} $disabled-background-color [null] - The background color for a disabled item in the button group. Auto-derived from item-background. +/// @param {Color} $item-disabled-border [null] - The border color for a disabled item in the button group. Auto-derived from item-border-color. /// -/// @param {Color} $item-selected-text-color [null]- The text color for a selected item in the button group. -/// @param {Color} $item-selected-icon-color [null]- The icon color for a selected item in the button group. -/// @param {Color} $item-selected-background [null] - The background color for a selected item in the button group. -/// @param {Color} $item-selected-border-color [null] - The border color for a selected item from the button group. +/// @param {Color} $item-selected-text-color [null]- The text color for a selected item in the button group. Auto-derived from item-selected-background. +/// @param {Color} $item-selected-icon-color [null]- The icon color for a selected item in the button group. Auto-derived from item-selected-text-color. +/// @param {Color} $item-selected-background [null] - The background color for a selected item in the button group. PRIMARY for selected state. Auto-derived from item-background. +/// @param {Color} $item-selected-border-color [null] - The border color for a selected item from the button group. Auto-derived from item-border-color. /// -/// @param {Color} $item-selected-hover-text-color [null] - The text color for a selected item in hover state in the button group. -/// @param {Color} $item-selected-hover-icon-color [null] - The icon color for a selected item in hover state in the button group. -/// @param {Color} $item-selected-hover-background [null] - The background color for a selected item in hover state in the button group. -/// @param {Color} $item-selected-hover-border-color [null] - The border color for a selected item in hover state in the button group. -/// @param {Color} $item-selected-focus-background [null] - The background color for a selected item in focused state in the button group. -/// @param {Color} $item-selected-focus-hover-background [null] - The background color for a selected item in focused & hover state in the button group. +/// @param {Color} $item-selected-hover-text-color [null] - The text color for a selected item in hover state in the button group. Auto-derived from item-selected-hover-background. +/// @param {Color} $item-selected-hover-icon-color [null] - The icon color for a selected item in hover state in the button group. Auto-derived from item-selected-hover-text-color. +/// @param {Color} $item-selected-hover-background [null] - The background color for a selected item in hover state in the button group. Auto-derived from item-selected-background. +/// @param {Color} $item-selected-hover-border-color [null] - The border color for a selected item in hover state in the button group. Auto-derived from item-border-color. +/// @param {Color} $item-selected-focus-background [null] - The background color for a selected item in focused state in the button group. Auto-derived from item-selected-background. +/// @param {Color} $item-selected-focus-hover-background [null] - The background color for a selected item in focused & hover state in the button group. Auto-derived from item-selected-hover-background. /// -/// @param {Color} $disabled-selected-text-color [null] - The disabled text color for a selected item in the button group. -/// @param {Color} $disabled-selected-icon-color [null] - The disabled icon color for a selected item in the button group. -/// @param {Color} $disabled-selected-background [null] - The disabled background color for a selected item in the button group. -/// @param {Color} $disabled-selected-border-color [null] - The disabled border color for a selected item from the button group. +/// @param {Color} $disabled-selected-text-color [null] - The disabled text color for a selected item in the button group. Auto-derived from disabled-text-color. +/// @param {Color} $disabled-selected-icon-color [null] - The disabled icon color for a selected item in the button group. Auto-derived from disabled-selected-text-color. +/// @param {Color} $disabled-selected-background [null] - The disabled background color for a selected item in the button group. Auto-derived from item-selected-background. +/// @param {Color} $disabled-selected-border-color [null] - The disabled border color for a selected item from the button group. Auto-derived from item-border-color. /// /// @param {List} $border-radius [null] - The border radius used for button-group component. /// diff --git a/sass/themes/components/button/_button-theme.scss b/sass/themes/components/button/_button-theme.scss index cb8cca68..2c3c329d 100644 --- a/sass/themes/components/button/_button-theme.scss +++ b/sass/themes/components/button/_button-theme.scss @@ -18,29 +18,36 @@ /// @author Simeon Simeonoff //// -/// If only background color is specified, text/icon color -/// will be assigned automatically to a contrasting color. -/// Does ___not___ apply for disabled state colors. +/// Button Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` - The main button background. Auto-derives: foreground, icon-color (via contrast). +/// - `$hover-background` - Hover state background. Auto-derives: hover-foreground, icon-color-hover. +/// - `$focus-background` - Focus state background. Auto-derives: focus-foreground, focus-visible colors. +/// +/// Setting just `$background` will create a properly contrasted button. +/// Disabled state colors must be set explicitly (not auto-derived). +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $background [null] - The background color of the button. -/// @param {Color} $foreground [null] - The text color of the button. -/// @param {Color} $icon-color [null] - The icon color in the button. -/// @param {Color} $icon-color-hover [null] - The icon color in the button on hover. +/// @param {Color} $background [null] - The background color of the button. PRIMARY - derives foreground and icon-color. +/// @param {Color} $foreground [null] - The text color of the button. Auto-derived from background. +/// @param {Color} $icon-color [null] - The icon color in the button. Auto-derived from background. +/// @param {Color} $icon-color-hover [null] - The icon color in the button on hover. Auto-derived from hover-foreground. /// @param {Color} $hover-background [null] - The hover background color of the button. -/// @param {Color} $hover-foreground [null] - The hover text color of the button. +/// @param {Color} $hover-foreground [null] - The hover text color of the button. Auto-derived from hover-background. /// @param {Color} $focus-background [null] - The focus background color of the button. -/// @param {Color} $focus-foreground [null] - The focus text color of the button. +/// @param {Color} $focus-foreground [null] - The focus text color of the button. Auto-derived from focus-background. /// @param {Color} $focus-hover-background [null] - The background color on focus hovered state of the button. -/// @param {Color} $focus-hover-foreground [null] - The text color on focus hovered state of the button. -/// @param {Color} $focus-visible-background [null] - The focus-visible background color of the button. -/// @param {Color} $focus-visible-foreground [null] - The focus-visible text color of the button. +/// @param {Color} $focus-hover-foreground [null] - The text color on focus hovered state of the button. Auto-derived from focus-hover-background. +/// @param {Color} $focus-visible-background [null] - The focus-visible background color of the button. Auto-derived from focus-background. +/// @param {Color} $focus-visible-foreground [null] - The focus-visible text color of the button. Auto-derived from focus-visible-background. /// @param {Color} $active-background [null] - The active background of the button. /// @param {Color} $active-foreground [null] - The active text color of the button. /// @param {List} $border-radius [null] - The border radius of the button. /// @param {Color} $border-color [null] - The border color of the button. /// @param {Color} $hover-border-color [null] - The hover border color of the button. /// @param {Color} $focus-border-color [null] - The focus border color of the button. -/// @param {Color} $focus-visible-border-color [null] - The focus-visible border color of the button. +/// @param {Color} $focus-visible-border-color [null] - The focus-visible border color of the button. Auto-derived from focus-border-color. /// @param {Color} $active-border-color [null] - The active border color of the button. /// @param {Color} $shadow-color [null] - The shadow color of the button. /// @param {Color} $resting-shadow [null] - The shadow of the button in its idle state. diff --git a/sass/themes/components/button/_contained-button-theme.scss b/sass/themes/components/button/_contained-button-theme.scss index 6c36d7a9..3f2e275f 100644 --- a/sass/themes/components/button/_contained-button-theme.scss +++ b/sass/themes/components/button/_contained-button-theme.scss @@ -14,38 +14,44 @@ /// @author Simeon Simeonoff //// -/// If only background color is specified, text/icon color -/// will be assigned automatically to a contrasting color. -/// Does ___not___ apply for disabled state colors. +/// Contained Button Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` - The background color of the button. Auto-derives: foreground, icon-color, hover-background, focus-background, active-background, and their foreground colors. +/// - `$foreground` - The text color of the button. Auto-derives: hover-foreground, focus-foreground, active-foreground (as fallbacks). +/// +/// Setting background automatically calculates a contrasting foreground color and derives all state backgrounds with their contrasting foreground colors. Derivation behavior varies by design variant (material, fluent, bootstrap, indigo). +/// Does NOT apply for disabled state colors. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $background [null] - The background color of the button. -/// @param {Color} $foreground [null] - The text color of the button. -/// @param {Color} $icon-color [null] - The icon color in the button. -/// @param {Color} $icon-color-hover [null] - The icon color in the button on hover. -/// @param {Color} $hover-background [null] - The hover background color of the button. -/// @param {Color} $hover-foreground [null] - The hover text color of the button. -/// @param {Color} $focus-background [null] - The focus background color of the button. -/// @param {Color} $focus-foreground [null] - The focus text color of the button. -/// @param {Color} $focus-hover-background [null] - The background color on focus hovered state of the button. -/// @param {Color} $focus-hover-foreground [null] - The text color on focus hovered state of the button. -/// @param {Color} $focus-visible-background [null] - The focus-visible background color of the button. -/// @param {Color} $focus-visible-foreground [null] - The focus-visible text color of the button. -/// @param {Color} $active-background [null] - The active background of the button. -/// @param {Color} $active-foreground [null] - The active text color of the button. +/// @param {Color} $background [null] - The background color of the button. PRIMARY - derives foreground, icon-color, hover-background, focus-background, active-background. +/// @param {Color} $foreground [null] - The text color of the button. Auto-derived from background. PRIMARY for foreground inheritance. +/// @param {Color} $icon-color [null] - The icon color in the button. Auto-derived from background. +/// @param {Color} $icon-color-hover [null] - The icon color in the button on hover. Auto-derived from icon-color or hover-background. +/// @param {Color} $hover-background [null] - The hover background color of the button. Auto-derived from background. +/// @param {Color} $hover-foreground [null] - The hover text color of the button. Auto-derived from foreground or hover-background. +/// @param {Color} $focus-background [null] - The focus background color of the button. Auto-derived from background or focus-hover-background. +/// @param {Color} $focus-foreground [null] - The focus text color of the button. Auto-derived from foreground or focus-background. +/// @param {Color} $focus-hover-background [null] - The background color on focus hovered state. Auto-derived from hover-background. +/// @param {Color} $focus-hover-foreground [null] - The text color on focus hovered state. Auto-derived from foreground or focus-hover-background. +/// @param {Color} $focus-visible-background [null] - The focus-visible background color. Auto-derived from focus-background or background. +/// @param {Color} $focus-visible-foreground [null] - The focus-visible text color. Auto-derived from foreground or focus-visible-background. +/// @param {Color} $active-background [null] - The active background of the button. Auto-derived from background, focus-background, or hover-background. +/// @param {Color} $active-foreground [null] - The active text color of the button. Auto-derived from foreground or active-background. /// @param {List} $border-radius [null] - The border radius of the button. /// @param {Color} $border-color [null] - The border color of the button. /// @param {Color} $hover-border-color [null] - The hover border color of the button. /// @param {Color} $focus-border-color [null] - The focus border color of the button. -/// @param {Color} $focus-visible-border-color [null] - The focus-visible border color of the button. +/// @param {Color} $focus-visible-border-color [null] - The focus-visible border color. Auto-derived from focus-visible-foreground (fluent). /// @param {Color} $active-border-color [null] - The active border color of the button. -/// @param {Color} $shadow-color [null] - The shadow color of the button. +/// @param {Color} $shadow-color [null] - The shadow color of the button. Auto-derived from focus-visible-background (bootstrap/indigo). /// @param {Color} $resting-shadow [null] - The shadow of the button in its idle state. /// @param {Color} $hover-shadow [null] - The shadow of the button in its hover state. /// @param {Color} $focus-shadow [null] - The shadow of the button in its focus state. /// @param {Color} $active-shadow [null] - The shadow of the button in its focus state. -/// @param {Color} $disabled-background [null] - The disabled background color of the button. -/// @param {Color} $disabled-foreground [null] - The disabled text color of the button. -/// @param {Color} $disabled-icon-color [null] - The disabled icon color of the button. +/// @param {Color} $disabled-background [null] - The disabled background color. Auto-derived from background (bootstrap/indigo). +/// @param {Color} $disabled-foreground [null] - The disabled text color. Auto-derived from disabled-background. +/// @param {Color} $disabled-icon-color [null] - The disabled icon color. Auto-derived from disabled-foreground. /// @param {Color} $disabled-border-color [null] - The disabled border color of the button. /// /// @requires $light-material-schema diff --git a/sass/themes/components/button/_fab-button-theme.scss b/sass/themes/components/button/_fab-button-theme.scss index f43a3e20..183ec169 100644 --- a/sass/themes/components/button/_fab-button-theme.scss +++ b/sass/themes/components/button/_fab-button-theme.scss @@ -14,38 +14,45 @@ /// @author Simeon Simeonoff //// -/// If only background color is specified, text/icon color -/// will be assigned automatically to a contrasting color. -/// Does ___not___ apply for disabled state colors. +/// FAB Button Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` - The background color of the button. Auto-derives: foreground, icon-color, hover-background, focus-background, active-background, and their foreground colors. +/// - `$foreground` - The text color of the button. Used as fallback for state foreground colors. +/// - `$icon-color` - The icon color in the button. Used as fallback for icon-color-hover. +/// +/// Setting background automatically calculates a contrasting foreground and icon color, and derives all state backgrounds with their contrasting foreground colors. Derivation behavior varies by design variant (material, fluent, bootstrap, indigo). +/// Does NOT apply for disabled state colors. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $background [null] - The background color of the button. -/// @param {Color} $foreground [null] - The text color of the button. -/// @param {Color} $icon-color [null] - The icon color in the button. -/// @param {Color} $icon-color-hover [null] - The icon color in the button on hover. -/// @param {Color} $hover-background [null] - The hover background color of the button. -/// @param {Color} $hover-foreground [null] - The hover text color of the button. -/// @param {Color} $focus-background [null] - The focus background color of the button. -/// @param {Color} $focus-foreground [null] - The focus text color of the button. -/// @param {Color} $focus-hover-background [null] - The background color on focus hovered state of the button. -/// @param {Color} $focus-hover-foreground [null] - The text color on focus hovered state of the button. -/// @param {Color} $focus-visible-background [null] - The focus-visible background color of the button. -/// @param {Color} $focus-visible-foreground [null] - The focus-visible text color of the button. -/// @param {Color} $active-background [null] - The active background of the button. -/// @param {Color} $active-foreground [null] - The active text color of the button. +/// @param {Color} $background [null] - The background color of the button. PRIMARY - derives foreground, icon-color, hover-background, focus-background, active-background. +/// @param {Color} $foreground [null] - The text color of the button. Auto-derived from background. +/// @param {Color} $icon-color [null] - The icon color in the button. Auto-derived from background. +/// @param {Color} $icon-color-hover [null] - The icon color in the button on hover. Auto-derived from icon-color or hover-background. +/// @param {Color} $hover-background [null] - The hover background color. Auto-derived from background. +/// @param {Color} $hover-foreground [null] - The hover text color. Auto-derived from foreground or hover-background. +/// @param {Color} $focus-background [null] - The focus background color. Auto-derived from background or focus-hover-background. +/// @param {Color} $focus-foreground [null] - The focus text color. Auto-derived from foreground or focus-background. +/// @param {Color} $focus-hover-background [null] - The background color on focus hovered state. Auto-derived from hover-background. +/// @param {Color} $focus-hover-foreground [null] - The text color on focus hovered state. Auto-derived from foreground or focus-hover-background. +/// @param {Color} $focus-visible-background [null] - The focus-visible background color. Auto-derived from focus-background or background. +/// @param {Color} $focus-visible-foreground [null] - The focus-visible text color. Auto-derived from focus-visible-background. +/// @param {Color} $active-background [null] - The active background. Auto-derived from background, focus-background, or hover-background. +/// @param {Color} $active-foreground [null] - The active text color. Auto-derived from active-background. /// @param {List} $border-radius [null] - The border radius of the button. /// @param {Color} $border-color [null] - The border color of the button. /// @param {Color} $hover-border-color [null] - The hover border color of the button. /// @param {Color} $focus-border-color [null] - The focus border color of the button. -/// @param {Color} $focus-visible-border-color [null] - The focus-visible border color of the button. +/// @param {Color} $focus-visible-border-color [null] - The focus-visible border color. Auto-derived from focus-visible-foreground (fluent). /// @param {Color} $active-border-color [null] - The active border color of the button. -/// @param {Color} $shadow-color [null] - The shadow color of the button. +/// @param {Color} $shadow-color [null] - The shadow color. Auto-derived from focus-visible-background (bootstrap/indigo). /// @param {Color} $resting-shadow [null] - The shadow of the button in its idle state. /// @param {Color} $hover-shadow [null] - The shadow of the button in its hover state. /// @param {Color} $focus-shadow [null] - The shadow of the button in its focus state. /// @param {Color} $active-shadow [null] - The shadow of the button in its focus state. -/// @param {Color} $disabled-background [null] - The disabled background color of the button. -/// @param {Color} $disabled-foreground [null] - The disabled text color of the button. -/// @param {Color} $disabled-icon-color [null] - The disabled icon color of the button. +/// @param {Color} $disabled-background [null] - The disabled background color. Auto-derived from background (bootstrap/indigo). +/// @param {Color} $disabled-foreground [null] - The disabled text color. Auto-derived from disabled-background. +/// @param {Color} $disabled-icon-color [null] - The disabled icon color. Auto-derived from disabled-foreground or disabled-background. /// @param {Color} $disabled-border-color [null] - The disabled border color of the button. /// /// @requires $light-material-schema diff --git a/sass/themes/components/button/_flat-button-theme.scss b/sass/themes/components/button/_flat-button-theme.scss index d7ba7aa8..bf82235c 100644 --- a/sass/themes/components/button/_flat-button-theme.scss +++ b/sass/themes/components/button/_flat-button-theme.scss @@ -14,34 +14,42 @@ /// @author Simeon Simeonoff //// -/// If only background color is specified, text/icon color -/// will be assigned automatically to a contrasting color. -/// Does ___not___ apply for disabled state colors. +/// Flat Button Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$foreground` - The text color of the button. Auto-derives: hover-background, focus-background, active-background, hover-foreground, focus-foreground, active-foreground, disabled-foreground (variant-dependent). +/// - `$hover-background` - The hover background color. Auto-derives: hover-foreground. +/// - `$focus-background` - The focus background color. Auto-derives: focus-foreground, focus-visible-background. +/// - `$active-background` - The active background color. Auto-derives: active-foreground. +/// +/// For flat buttons, the foreground color is the primary token. Setting it derives all state backgrounds and their contrasting foreground colors. Derivation behavior varies by design variant (material, fluent, bootstrap, indigo). +/// Does NOT apply for disabled state colors. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {Color} $background [null] - The background color of the button. -/// @param {Color} $foreground [null] - The text color of the button. +/// @param {Color} $foreground [null] - The text color of the button. PRIMARY - derives hover/focus/active backgrounds and foregrounds. /// @param {Color} $icon-color [null] - The icon color in the button. -/// @param {Color} $icon-color-hover [null] - The icon color in the button on hover. -/// @param {Color} $hover-background [null] - The hover background color of the button. -/// @param {Color} $hover-foreground [null] - The hover text color of the button. -/// @param {Color} $focus-background [null] - The focus background color of the button. -/// @param {Color} $focus-foreground [null] - The focus text color of the button. -/// @param {Color} $focus-hover-background [null] - The background color on focus hovered state of the button. -/// @param {Color} $focus-hover-foreground [null] - The text color on focus hovered state of the button. -/// @param {Color} $focus-visible-background [null] - The focus-visible background color of the button. -/// @param {Color} $focus-visible-foreground [null] - The focus-visible text color of the button. -/// @param {Color} $active-background [null] - The active background of the button. -/// @param {Color} $active-foreground [null] - The active text color of the button. +/// @param {Color} $icon-color-hover [null] - The icon color in the button on hover. Auto-derived from hover-foreground. +/// @param {Color} $hover-background [null] - The hover background color of the button. PRIMARY - derives hover-foreground. Auto-derived from foreground. +/// @param {Color} $hover-foreground [null] - The hover text color of the button. Auto-derived from hover-background. +/// @param {Color} $focus-background [null] - The focus background color of the button. PRIMARY - derives focus-foreground. Auto-derived from foreground. +/// @param {Color} $focus-foreground [null] - The focus text color of the button. Auto-derived from focus-background. +/// @param {Color} $focus-hover-background [null] - The background color on focus hovered state. Auto-derived from foreground. +/// @param {Color} $focus-hover-foreground [null] - The text color on focus hovered state. Auto-derived from focus-hover-background. +/// @param {Color} $focus-visible-background [null] - The focus-visible background color. Auto-derived from focus-background or foreground. +/// @param {Color} $focus-visible-foreground [null] - The focus-visible text color. Auto-derived from focus-visible-background. +/// @param {Color} $active-background [null] - The active background of the button. Auto-derived from foreground. +/// @param {Color} $active-foreground [null] - The active text color of the button. Auto-derived from active-background. /// @param {List} $border-radius [null] - The border radius of the button. /// @param {Color} $border-color [null] - The border color of the button. /// @param {Color} $hover-border-color [null] - The hover border color of the button. /// @param {Color} $focus-border-color [null] - The focus border color of the button. -/// @param {Color} $focus-visible-border-color [null] - The focus-visible border color of the button. +/// @param {Color} $focus-visible-border-color [null] - The focus-visible border color. Auto-derived from focus-border-color or focus-visible-foreground. /// @param {Color} $active-border-color [null] - The active border color of the button. -/// @param {Color} $shadow-color [null] - The shadow color of the button. +/// @param {Color} $shadow-color [null] - The shadow color of the button. Auto-derived from focus-visible-foreground. /// @param {Color} $disabled-background [null] - The disabled background color of the button. -/// @param {Color} $disabled-foreground [null] - The disabled text color of the button. -/// @param {Color} $disabled-icon-color [null] - The disabled icon color of the button. +/// @param {Color} $disabled-foreground [null] - The disabled text color of the button. Auto-derived from foreground (bootstrap/indigo). +/// @param {Color} $disabled-icon-color [null] - The disabled icon color of the button. Auto-derived from disabled-foreground. /// @param {Color} $disabled-border-color [null] - The disabled border color of the button. /// /// @requires $light-material-schema diff --git a/sass/themes/components/button/_outlined-button-theme.scss b/sass/themes/components/button/_outlined-button-theme.scss index 054b96c1..5d3c8c6c 100644 --- a/sass/themes/components/button/_outlined-button-theme.scss +++ b/sass/themes/components/button/_outlined-button-theme.scss @@ -14,35 +14,43 @@ /// @author Simeon Simeonoff //// -/// If only background color is specified, text/icon color -/// will be assigned automatically to a contrasting color. -/// Does ___not___ apply for disabled state colors. +/// Outlined Button Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$foreground` - The text color of the button. Auto-derives: hover-background, focus-background, active-background, border colors, and state foreground colors. +/// - `$hover-background` - The hover background color. Auto-derives: hover-foreground, focus-hover-background, hover-border-color. +/// - `$focus-background` - The focus background color. Auto-derives: focus-foreground, focus-visible-background, focus-border-color. +/// - `$active-background` - The active background color. Auto-derives: active-foreground, active-border-color. +/// +/// For outlined buttons, the foreground color is the primary token. Setting it derives all state backgrounds, their contrasting foreground colors, and matching border colors. Derivation behavior varies by design variant (material, fluent, bootstrap, indigo). +/// Does NOT apply for disabled state colors. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {Color} $background [null] - The background color of the button. -/// @param {Color} $foreground [null] - The text color of the button. +/// @param {Color} $foreground [null] - The text color of the button. PRIMARY - derives hover/focus/active backgrounds, foregrounds, and borders. /// @param {Color} $icon-color [null] - The icon color in the button. -/// @param {Color} $icon-color-hover [null] - The icon color in the button on hover. -/// @param {Color} $hover-background [null] - The hover background color of the button. -/// @param {Color} $hover-foreground [null] - The hover text color of the button. -/// @param {Color} $focus-background [null] - The focus background color of the button. -/// @param {Color} $focus-foreground [null] - The focus text color of the button. -/// @param {Color} $focus-hover-background [null] - The background color on focus hovered state of the button. -/// @param {Color} $focus-hover-foreground [null] - The text color on focus hovered state of the button. -/// @param {Color} $focus-visible-background [null] - The focus-visible background color of the button. -/// @param {Color} $focus-visible-foreground [null] - The focus-visible text color of the button. -/// @param {Color} $active-background [null] - The active background of the button. -/// @param {Color} $active-foreground [null] - The active text color of the button. +/// @param {Color} $icon-color-hover [null] - The icon color in the button on hover. Auto-derived from hover-foreground. +/// @param {Color} $hover-background [null] - The hover background color. PRIMARY - derives hover-foreground. Auto-derived from foreground. +/// @param {Color} $hover-foreground [null] - The hover text color. Auto-derived from hover-background. +/// @param {Color} $focus-background [null] - The focus background color. PRIMARY - derives focus-foreground. Auto-derived from foreground. +/// @param {Color} $focus-foreground [null] - The focus text color. Auto-derived from focus-background. +/// @param {Color} $focus-hover-background [null] - The background color on focus hovered state. Auto-derived from foreground or hover-background. +/// @param {Color} $focus-hover-foreground [null] - The text color on focus hovered state. Auto-derived from focus-hover-background. +/// @param {Color} $focus-visible-background [null] - The focus-visible background color. Auto-derived from focus-background or hover-background. +/// @param {Color} $focus-visible-foreground [null] - The focus-visible text color. Auto-derived from focus-visible-background or foreground. +/// @param {Color} $active-background [null] - The active background of the button. Auto-derived from foreground. +/// @param {Color} $active-foreground [null] - The active text color. Auto-derived from active-background. /// @param {List} $border-radius [null] - The border radius of the button. -/// @param {Color} $border-color [null] - The border color of the button. -/// @param {Color} $hover-border-color [null] - The hover border color of the button. -/// @param {Color} $focus-border-color [null] - The focus border color of the button. -/// @param {Color} $focus-visible-border-color [null] - The focus-visible border color of the button. -/// @param {Color} $active-border-color [null] - The active border color of the button. -/// @param {Color} $shadow-color [null] - The shadow color of the button. +/// @param {Color} $border-color [null] - The border color of the button. Auto-derived from foreground. +/// @param {Color} $hover-border-color [null] - The hover border color. Auto-derived from hover-foreground or hover-background. +/// @param {Color} $focus-border-color [null] - The focus border color. Auto-derived from focus-foreground or focus-background. +/// @param {Color} $focus-visible-border-color [null] - The focus-visible border color. Auto-derived from focus-border-color or focus-visible-background. +/// @param {Color} $active-border-color [null] - The active border color. Auto-derived from active-foreground or active-background. +/// @param {Color} $shadow-color [null] - The shadow color of the button. Auto-derived from focus-visible-foreground or focus-visible-background. /// @param {Color} $disabled-background [null] - The disabled background color of the button. -/// @param {Color} $disabled-foreground [null] - The disabled text color of the button. -/// @param {Color} $disabled-icon-color [null] - The disabled icon color of the button. -/// @param {Color} $disabled-border-color [null] - The disabled border color of the button. +/// @param {Color} $disabled-foreground [null] - The disabled text color. Auto-derived from foreground (bootstrap). +/// @param {Color} $disabled-icon-color [null] - The disabled icon color. Auto-derived from disabled-foreground. +/// @param {Color} $disabled-border-color [null] - The disabled border color. Auto-derived from disabled-foreground (bootstrap). /// /// @requires $light-material-schema /// diff --git a/sass/themes/components/calendar/_calendar-theme.scss b/sass/themes/components/calendar/_calendar-theme.scss index e61be87a..4b2a3115 100644 --- a/sass/themes/components/calendar/_calendar-theme.scss +++ b/sass/themes/components/calendar/_calendar-theme.scss @@ -14,47 +14,51 @@ /// @author Marin Popov //// -/// If only header background color is specified, that color will be -/// used as the leading color for all accented elements, such as: -/// - current date color -/// - selected date background -/// - picker elements hover colors -/// - year/month hover/selected colors -/// If only background colors are specified, text/icon colors -/// will be assigned automatically to a contrasting color. +/// Calendar Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$header-background` - The main accent color. Auto-derives: header-foreground, date-selected colors, +/// picker hover colors, year/month selected colors, date-special colors, navigation hover colors. +/// - `$content-background` - The calendar body background. Auto-derives: content-foreground, inactive-color, +/// weekday-color, date-hover colors, week-number colors. +/// +/// Setting just `$header-background` will theme all accent/selection states consistently. +/// Setting just `$content-background` will theme the calendar body with proper contrast. +/// Text and icon colors are automatically calculated for accessibility. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// /// @param {Number} $size [null] - Size of days, months, and years views. /// @param {Number} $inner-size [null] - Inner size for calendar elements. -/// @param {Color} $weekday-color [null] - Color for weekday labels. +/// @param {Color} $weekday-color [null] - Color for weekday labels. Auto-derived from content-background. /// @param {Color} $actions-divider-color [null] - Divider color for date-picker actions. /// @param {List} $border-radius [null] - Border radius for calendar container. -/// @param {Color} $content-background [null] - Background color for calendar. +/// @param {Color} $content-background [null] - Background color for calendar. PRIMARY - derives content-foreground, inactive-color, date-hover colors, week-number colors. /// @param {Color} $border-color [null] - Border color for calendar container. -/// @param {Color} $header-background [null] - Header background color. -/// @param {Color} $header-foreground [null] - Header foreground color. -/// @param {Color} $picker-foreground [null] - Foreground for the calendar picker. +/// @param {Color} $header-background [null] - Header background color. PRIMARY - derives header-foreground and most accent/selection colors. +/// @param {Color} $header-foreground [null] - Header foreground color. Auto-derived from header-background. +/// @param {Color} $picker-foreground [null] - Foreground for the calendar picker. Auto-derived from picker-background. /// @param {Color} $picker-background [null] - Background for the calendar picker. -/// @param {Color} $picker-hover-foreground [null] - :Hover foreground for the calendar picker. -/// @param {Color} $picker-focus-foreground [null] - :Focus foreground for the calendar picker. -/// @param {Color} $navigation-color [null] - Icon color for month navigation. -/// @param {Color} $navigation-hover-color [null] - :Hover color for navigation icons. -/// @param {Color} $navigation-focus-color [null] - :Focus color for navigation icons. +/// @param {Color} $picker-hover-foreground [null] - :Hover foreground for the calendar picker. Auto-derived from header-background. +/// @param {Color} $picker-focus-foreground [null] - :Focus foreground for the calendar picker. Auto-derived from picker-hover-foreground. +/// @param {Color} $navigation-color [null] - Icon color for month navigation. Auto-derived from picker-background. +/// @param {Color} $navigation-hover-color [null] - :Hover color for navigation icons. Auto-derived from picker-hover-foreground. +/// @param {Color} $navigation-focus-color [null] - :Focus color for navigation icons. Auto-derived from navigation-hover-color. /// @param {List} $ym-border-radius [null] - Border radius for year/month views. -/// @param {Color} $ym-hover-foreground [null] - :Hover foreground for year/month. -/// @param {Color} $ym-hover-background [null] - :Hover background for year/month. -/// @param {Color} $ym-current-outline-color [null] - Outline color for current year/month. +/// @param {Color} $ym-hover-foreground [null] - :Hover foreground for year/month. Auto-derived from ym-hover-background. +/// @param {Color} $ym-hover-background [null] - :Hover background for year/month. Auto-derived from date-hover-background. +/// @param {Color} $ym-current-outline-color [null] - Outline color for current year/month. Auto-derived from date-current-border-color. /// @param {Color} $ym-current-outline-hover-color [null] - :Hover outline color for current year/month. /// @param {Color} $ym-current-outline-focus-color [null] - :Focus outline color for current year/month. /// @param {Color} $ym-current-background [null] - Background for current year/month. -/// @param {Color} $ym-current-foreground [null] - Foreground for current year/month. +/// @param {Color} $ym-current-foreground [null] - Foreground for current year/month. Auto-derived from ym-current-background. /// @param {Color} $ym-current-hover-foreground [null] - :Hover foreground for current year/month. /// @param {Color} $ym-current-hover-background [null] - :Hover background for current year/month. /// @param {Color} $ym-selected-outline-color [null] - Outline color for selected year/month. /// @param {Color} $ym-selected-hover-outline-color [null] - :Hover outline color for selected year/month. /// @param {Color} $ym-selected-focus-outline-color [null] - :Focus outline color for selected year/month. -/// @param {Color} $ym-selected-foreground [null] - Foreground for selected year/month. -/// @param {Color} $ym-selected-background [null] - Background for selected year/month. +/// @param {Color} $ym-selected-foreground [null] - Foreground for selected year/month. Auto-derived from ym-selected-background. +/// @param {Color} $ym-selected-background [null] - Background for selected year/month. Auto-derived from header-background. /// @param {Color} $ym-selected-hover-foreground [null] - :Hover foreground for selected year/month. /// @param {Color} $ym-selected-hover-background [null] - :Hover background for selected year/month. /// @param {Color} $ym-selected-current-outline-color [null] - Outline color for selected current year/month. @@ -65,25 +69,25 @@ /// @param {Color} $ym-selected-current-hover-foreground [null] - :Hover foreground for selected current year/month. /// @param {Color} $ym-selected-current-hover-background [null] - :Hover background for selected current year/month. /// @param {List} $week-number-border-radius [null] - Border radius for week number column. -/// @param {Color} $week-number-foreground [null] - Foreground for week number column. -/// @param {Color} $week-number-background [null] - Background for week number column. -/// @param {Color} $content-foreground [null] - The foreground color for idle dates. -/// @param {Color} $weekend-color [null] - Color for weekend days. -/// @param {Color} $inactive-color [null] - Color for inactive dates (outside current month). +/// @param {Color} $week-number-foreground [null] - Foreground for week number column. Auto-derived from week-number-background. +/// @param {Color} $week-number-background [null] - Background for week number column. Auto-derived from content-background. +/// @param {Color} $content-foreground [null] - The foreground color for idle dates. Auto-derived from content-background. +/// @param {Color} $weekend-color [null] - Color for weekend days. Auto-derived from content-foreground. +/// @param {Color} $inactive-color [null] - Color for inactive dates (outside current month). Auto-derived from content-background. /// @param {List} $date-border-radius [null] - Border radius for date cells. /// @param {Color} $date-border-color [null] - Border color for date cells. /// @param {Color} $date-hover-border-color [null] - :Hover border color for date cells. /// @param {Color} $date-focus-border-color [null] - :Focus border color for date cells. -/// @param {Color} $date-hover-background [null] - :Hover background for date cells. -/// @param {Color} $date-focus-background [null] - :Focus background for date cells. -/// @param {Color} $date-hover-foreground [null] - :Hover foreground for date cells. -/// @param {Color} $date-focus-foreground [null] - :Focus foreground for date cells. +/// @param {Color} $date-hover-background [null] - :Hover background for date cells. Auto-derived from content-background. +/// @param {Color} $date-focus-background [null] - :Focus background for date cells. Auto-derived from date-hover-background. +/// @param {Color} $date-hover-foreground [null] - :Hover foreground for date cells. Auto-derived from date-hover-background. +/// @param {Color} $date-focus-foreground [null] - :Focus foreground for date cells. Auto-derived from date-hover-foreground. /// @param {Color} $date-selected-border-color [null] - Border color for selected date. /// @param {Color} $date-selected-hover-border-color [null] - :Hover border color for selected date. /// @param {Color} $date-selected-focus-border-color [null] - :Focus border color for selected date. -/// @param {Color} $date-selected-background [null] - Background for selected date. -/// @param {Color} $date-selected-foreground [null] - Foreground for selected date. -/// @param {Color} $date-selected-hover-background [null] - :Hover background for selected date. +/// @param {Color} $date-selected-background [null] - Background for selected date. Auto-derived from header-background. +/// @param {Color} $date-selected-foreground [null] - Foreground for selected date. Auto-derived from date-selected-background. +/// @param {Color} $date-selected-hover-background [null] - :Hover background for selected date. Auto-derived from date-selected-background. /// @param {Color} $date-selected-focus-background [null] - :Focus background for selected date. /// @param {Color} $date-selected-hover-foreground [null] - :Hover foreground for selected date. /// @param {Color} $date-selected-focus-foreground [null] - :Focus foreground for selected date. @@ -134,7 +138,7 @@ /// @param {Color} $date-special-border-color [null] - Border color for special date. /// @param {Color} $date-special-hover-border-color [null] - :Hover border color for special date. /// @param {Color} $date-special-focus-border-color [null] - :Focus border color for special date. -/// @param {Color} $date-special-foreground [null] - Foreground for special date. +/// @param {Color} $date-special-foreground [null] - Foreground for special date. Auto-derived from header-background. /// @param {Color} $date-special-background [null] - Background for special date. /// @param {Color} $date-special-hover-foreground [null] - :Hover foreground for special date. /// @param {Color} $date-special-hover-background [null] - :Hover background for special date. diff --git a/sass/themes/components/card/_card-theme.scss b/sass/themes/components/card/_card-theme.scss index dc44e295..03e7e9c5 100644 --- a/sass/themes/components/card/_card-theme.scss +++ b/sass/themes/components/card/_card-theme.scss @@ -14,17 +14,23 @@ /// @author Simeon Simeonoff //// +/// Card Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` - The card background color. Auto-derives: header-text-color, subtitle-text-color, content-text-color, actions-text-color. +/// +/// Setting the background automatically calculates contrasting text colors for all card sections. +/// Content and subtitle text colors are slightly muted compared to header and actions. /// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $background [null] - The card background color. +/// @param {Color} $background [null] - The card background color. PRIMARY - derives all text colors. /// @param {Color} $outline-color [null] - The color of the outline for outlined type cards. -/// @param {Color} $header-text-color [null] - The text color of the card title. -/// @param {Color} $subtitle-text-color [null] - The text color of the card subtitle. -/// @param {Color} $content-text-color [null] - The text color of the card content. -/// @param {Color} $actions-text-color [null] - The text color of the card buttons. +/// @param {Color} $header-text-color [null] - The text color of the card title. Auto-derived from background. +/// @param {Color} $subtitle-text-color [null] - The text color of the card subtitle. Auto-derived from background (muted). +/// @param {Color} $content-text-color [null] - The text color of the card content. Auto-derived from background (muted). +/// @param {Color} $actions-text-color [null] - The text color of the card buttons. Auto-derived from background. /// @param {box-shadow} $resting-shadow [null] - The shadow of the card in its resting state. /// @param {box-shadow} $hover-shadow [null] - The shadow of the card in its hover state. -/// /// @param {List} $border-radius [null] - The border radius used for card component. /// /// @requires $light-material-schema diff --git a/sass/themes/components/carousel/_carousel-theme.scss b/sass/themes/components/carousel/_carousel-theme.scss index 172a1126..2579be24 100644 --- a/sass/themes/components/carousel/_carousel-theme.scss +++ b/sass/themes/components/carousel/_carousel-theme.scss @@ -14,29 +14,38 @@ /// @author Marin Popov //// +/// Carousel Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$button-background` - The nav button background. Auto-derives: button-arrow-color, button-hover-*, button-disabled-*, button-focus-border-color. +/// - `$indicator-background` - The indicator container background. Auto-derives: indicator-dot-color, indicator-border-color, indicator-active-*, indicator-focus-color. +/// +/// Button colors cascade from button-background through hover and disabled states. +/// Indicator colors cascade from indicator-background through active and focus states. +/// Behavior varies by variant (indigo has additional derivation patterns). +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {Color} $slide-background [null] - The slide background color. -/// @param {Color} $button-background [null] - The previous/next buttons idle background color. -/// @param {Color} $button-hover-background [null] - The previous/next buttons hover background color. -/// @param {Color} $button-disabled-background [null] - The previous/next buttons disabled background color. -/// @param {Color} $button-arrow-color [null] - The previous/next buttons idle arrow color. -/// @param {Color} $button-hover-arrow-color [null] - The previous/next buttons hover arrow color. -/// @param {Color} $button-disabled-arrow-color [null] - The previous/next buttons disabled arrow color. -/// @param {Color} $button-border-color [null] - The previous/next buttons idle border color. -/// @param {Color} $button-hover-border-color [null] - The previous/next buttons hover border color. -/// @param {Color} $button-focus-border-color [null] - The navigation buttons border color on focus. +/// @param {Color} $button-background [null] - The previous/next buttons idle background color. PRIMARY - derives arrow, hover, disabled, focus colors. +/// @param {Color} $button-hover-background [null] - The previous/next buttons hover background color. Auto-derived from button-background. +/// @param {Color} $button-disabled-background [null] - The previous/next buttons disabled background color. Auto-derived from button-background. +/// @param {Color} $button-arrow-color [null] - The previous/next buttons idle arrow color. Auto-derived from button-background. +/// @param {Color} $button-hover-arrow-color [null] - The previous/next buttons hover arrow color. Auto-derived from button-hover-background. +/// @param {Color} $button-disabled-arrow-color [null] - The previous/next buttons disabled arrow color. Auto-derived from button-disabled-background. +/// @param {Color} $button-border-color [null] - The previous/next buttons idle border color. Auto-derived from button-background (indigo). +/// @param {Color} $button-hover-border-color [null] - The previous/next buttons hover border color. Auto-derived from button-border-color. +/// @param {Color} $button-focus-border-color [null] - The navigation buttons border color on focus. Auto-derived from button-focus-arrow-color or button-background. /// @param {Color} $button-disabled-border-color [null] - The previous/next buttons disabled border color. -/// @param {Color} $indicator-background [null] - The indicators container background color. +/// @param {Color} $indicator-background [null] - The indicators container background color. PRIMARY - derives dot, border, active, focus colors. /// @param {Color} $label-indicator-background [null] - The label indicator container background color. -/// @param {Color} $indicator-dot-color [null] - The idle indicator dot color. -/// @param {Color} $indicator-hover-dot-color [null] - The hover indicator dot color. -/// @param {Color} $indicator-focus-color [null] - The indicators border and dot color on focus. -/// @param {Color} $indicator-border-color [null] - The idle indicator border color. -/// @param {Color} $indicator-active-dot-color [null] - The active indicator dot color. -/// @param {Color} $indicator-active-border-color [null] - The active indicator border color. -/// @param {Color} $indicator-active-hover-dot-color [null] - The active indicator dot color on hover. +/// @param {Color} $indicator-dot-color [null] - The idle indicator dot color. Auto-derived from indicator-background. +/// @param {Color} $indicator-hover-dot-color [null] - The hover indicator dot color. Auto-derived from indicator-dot-color. +/// @param {Color} $indicator-focus-color [null] - The indicators border and dot color on focus. Auto-derived from indicator-background or button-background. +/// @param {Color} $indicator-border-color [null] - The idle indicator border color. Auto-derived from indicator-background or indicator-dot-color. +/// @param {Color} $indicator-active-dot-color [null] - The active indicator dot color. Auto-derived from indicator-background or button-background. +/// @param {Color} $indicator-active-border-color [null] - The active indicator border color. Auto-derived from indicator-active-dot-color. +/// @param {Color} $indicator-active-hover-dot-color [null] - The active indicator dot color on hover. Auto-derived from indicator-active-dot-color. /// @param {box-shadow} $button-shadow [null] - Shadow underneath the previous/next buttons. -/// /// @param {List} $border-radius [null] - The border radius used for carousel component. /// /// @requires $light-material-schema diff --git a/sass/themes/components/chat/_chat-theme.scss b/sass/themes/components/chat/_chat-theme.scss index 7cb26a8e..583cffc3 100644 --- a/sass/themes/components/chat/_chat-theme.scss +++ b/sass/themes/components/chat/_chat-theme.scss @@ -13,24 +13,32 @@ //// /// Chat Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$header-background` - The background color of the chat header. Auto-derives: header-color. +/// - `$message-background` - The background color of message bubbles. Auto-derives: message-color, message-actions-color. +/// +/// Setting header-background automatically calculates a contrasting header-color. +/// Setting message-background automatically calculates contrasting message-color and message-actions-color. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @prop {Color} background [null] - The background color of the chat component. -/// @prop {Color} header-background [null] - The background color of the chat header. -/// @prop {Color} header-color [null] - The text color of the chat header. -/// @prop {Color} header-border [null] - The color used for the chat header border. -/// @prop {Color} message-background [null] - The background color of the sent message bubble. -/// @prop {Color} message-color [null] - The text color of the chat messages. -/// @prop {Color} message-actions-color [null] - The icon color of the chat message actions. -/// @prop {Color} file-background [null] - The background color of the image message container. -/// @prop {Color} file-icon-color [null] - The color of the attached file icon. -/// @prop {Color} file-icon-accent-color [null] - The accent color of the attached file icon. -/// @prop {Color} image-background [null] - The background color of the image message container. -/// @prop {Color} image-border [null] - The border color of the image message container. -/// @prop {Color} image-attachment-icon [null] - The color of the message attachment icon. -/// @prop {Color} chat-input-border [null] - The border color of the chat input area. -/// @prop {Color} progress-indicator-color [null] - The color of the progress indicator in the chat component. -/// @prop {Color} code-background [null] - The background color of the code snippets in the chat component. -/// @prop {Color} code-border [null] - The border color of the code snippets in the chat component. +/// @param {Color} $background [null] - The background color of the chat component. +/// @param {Color} $header-background [null] - The background color of the chat header. PRIMARY - derives header-color. +/// @param {Color} $header-color [null] - The text color of the chat header. Auto-derived from header-background. +/// @param {Color} $header-border [null] - The color used for the chat header border. +/// @param {Color} $message-background [null] - The background color of the sent message bubble. PRIMARY - derives message-color, message-actions-color. +/// @param {Color} $message-color [null] - The text color of the chat messages. Auto-derived from message-background. +/// @param {Color} $message-actions-color [null] - The icon color of the chat message actions. Auto-derived from message-color. +/// @param {Color} $file-background [null] - The background color of the image message container. +/// @param {Color} $file-icon-color [null] - The color of the attached file icon. +/// @param {Color} $file-icon-accent-color [null] - The accent color of the attached file icon. +/// @param {Color} $image-background [null] - The background color of the image message container. +/// @param {Color} $image-border [null] - The border color of the image message container. +/// @param {Color} $image-attachment-icon [null] - The color of the message attachment icon. +/// @param {Color} $chat-input-border [null] - The border color of the chat input area. +/// @param {Color} $progress-indicator-color [null] - The color of the progress indicator in the chat component. +/// @param {Color} $code-background [null] - The background color of the code snippets in the chat component. +/// @param {Color} $code-border [null] - The border color of the code snippets in the chat component. /// @requires $light-material-schema /// /// @example scss Change background color diff --git a/sass/themes/components/checkbox/_checkbox-theme.scss b/sass/themes/components/checkbox/_checkbox-theme.scss index fbe1260e..17b9f1fe 100644 --- a/sass/themes/components/checkbox/_checkbox-theme.scss +++ b/sass/themes/components/checkbox/_checkbox-theme.scss @@ -15,29 +15,38 @@ //// /// Checkbox Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$fill-color` - The checked state border and fill color. Auto-derives: tick-color, fill-color-hover, focus-border-color, focus-outline-color, disabled-indeterminate-color. +/// - `$empty-color` - The unchecked border color. Auto-derives: empty-color-hover, focus-outline-color (indigo). +/// - `$error-color` - The invalid state color. Auto-derives: error-color-hover, focus-outline-color-error. +/// +/// Setting just `$fill-color` will theme all checked states consistently. +/// The tick (checkmark) color is automatically calculated for contrast. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {Color} $label-color [null]- The text color used for the label text. -/// @param {Color} $label-color-hover [null]- The text color used for the label text on hover. -/// @param {Color} $empty-color [null] - The unchecked border color. -/// @param {Color} $empty-color-hover [null] - The unchecked border color on hover. +/// @param {Color} $label-color-hover [null]- The text color used for the label text on hover. Auto-derived from label-color. +/// @param {Color} $empty-color [null] - The unchecked border color. PRIMARY for unchecked states. +/// @param {Color} $empty-color-hover [null] - The unchecked border color on hover. Auto-derived from empty-color. /// @param {Color} $empty-fill-color [null] - The unchecked fill color. -/// @param {Color} $fill-color [null] - The checked border and fill colors. -/// @param {Color} $fill-color-hover [null] - The checked border and fill colors on hover. -/// @param {Color} $tick-color [null] - The checked mark color. +/// @param {Color} $fill-color [null] - The checked border and fill colors. PRIMARY - derives tick-color, focus colors. +/// @param {Color} $fill-color-hover [null] - The checked border and fill colors on hover. Auto-derived from fill-color. +/// @param {Color} $tick-color [null] - The checked mark color. Auto-derived from fill-color (contrast). /// @param {Color} $tick-color-hover [null] - The checked mark color on hover. /// @param {Number} $tick-width [null] - The checked mark width. /// @param {Color} $disabled-color [null] - The disabled border and fill colors. /// @param {Color} $disabled-tick-color [null] - The checked mark color in disabled state. -/// @param {Color} $disabled-indeterminate-color [null] - The disabled border and fill colors in indeterminate state. +/// @param {Color} $disabled-indeterminate-color [null] - The disabled border and fill colors in indeterminate state. Auto-derived from fill-color. /// @param {Color} $disabled-color-label [null] - The disabled label color. /// @param {List} $border-radius [null] - The border radius used for checkbox component. /// @param {List} $border-radius-ripple [null] - The border radius used for checkbox ripple. -/// @param {Color} $focus-outline-color [null] - The focus outlined color. -/// @param {Color} $focus-outline-color-focused [null] - The focus outlined color for focused state. -/// @param {Color} $focus-border-color [null] - The focus border color. -/// @param {Color} $error-color [null] - The border and fill colors in invalid state. -/// @param {Color} $error-color-hover [null] - The border and fill colors in invalid state on hover. -/// @param {Color} $focus-outline-color-error [null] - The focus outline error color. +/// @param {Color} $focus-outline-color [null] - The focus outlined color. Auto-derived from empty-color (indigo) or fill-color (bootstrap). +/// @param {Color} $focus-outline-color-focused [null] - The focus outlined color for focused state. Auto-derived from fill-color (indigo). +/// @param {Color} $focus-border-color [null] - The focus border color. Auto-derived from fill-color. +/// @param {Color} $error-color [null] - The border and fill colors in invalid state. PRIMARY for error states. +/// @param {Color} $error-color-hover [null] - The border and fill colors in invalid state on hover. Auto-derived from error-color. +/// @param {Color} $focus-outline-color-error [null] - The focus outline error color. Auto-derived from error-color. /// Set to light when the surrounding area is dark. /// /// @requires $light-material-schema diff --git a/sass/themes/components/chip/_chip-theme.scss b/sass/themes/components/chip/_chip-theme.scss index 34f0502b..18756426 100644 --- a/sass/themes/components/chip/_chip-theme.scss +++ b/sass/themes/components/chip/_chip-theme.scss @@ -14,12 +14,20 @@ //// /// Chip Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` - The main chip background. Auto-derives: text-color, border-color, hover/focus/selected backgrounds. +/// - `$selected-background` - Selected state background. Auto-derives: selected-text-color, selected-border-color, hover-selected/focus-selected colors. +/// +/// Setting just `$background` will create a complete chip theme with all states properly derived. +/// The selected state can be customized separately via `$selected-background`. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {List} $border-radius [null] - The chip border-radius. /// -/// @param {Color} $text-color [null] - The chip text color. -/// @param {Color} $background [null] - The chip background color. -/// @param {Color} $border-color [null] - The chip border color. +/// @param {Color} $text-color [null] - The chip text color. Auto-derived from background. +/// @param {Color} $background [null] - The chip background color. PRIMARY - derives text-color, border-color, hover/focus states. +/// @param {Color} $border-color [null] - The chip border color. Auto-derived from background. /// /// @param {Color} $disabled-text-color [null] - The disabled chip text color. /// @param {Color} $disabled-background [null] - The disabled chip background color. @@ -28,25 +36,25 @@ /// @param {Color} $ghost-background [null] - The chip ghost background color. /// @param {box-shadow} $ghost-shadow [null] - The chip ghost shadow. /// -/// @param {Color} $hover-text-color [null] - The chip text hover color. -/// @param {Color} $hover-background [null] - The chip hover background color. -/// @param {Color} $hover-border-color [null] - The chip hover border color. +/// @param {Color} $hover-text-color [null] - The chip text hover color. Auto-derived from hover-background. +/// @param {Color} $hover-background [null] - The chip hover background color. Auto-derived from background. +/// @param {Color} $hover-border-color [null] - The chip hover border color. Auto-derived from hover-background. /// -/// @param {Color} $focus-text-color [null] - The chip text focus color. -/// @param {Color} $focus-background [null] - The chip focus background color. -/// @param {color} $focus-border-color [null] - The chip focus border color. +/// @param {Color} $focus-text-color [null] - The chip text focus color. Auto-derived from focus-background. +/// @param {Color} $focus-background [null] - The chip focus background color. Auto-derived from background. +/// @param {color} $focus-border-color [null] - The chip focus border color. Auto-derived from focus-background. /// -/// @param {color} $selected-text-color [null] - The selected chip text color. -/// @param {color} $selected-background [null] - The selected chip background color. -/// @param {color} $selected-border-color [null] The selected chip border color. +/// @param {color} $selected-text-color [null] - The selected chip text color. Auto-derived from selected-background. +/// @param {color} $selected-background [null] - The selected chip background color. Auto-derived from background. +/// @param {color} $selected-border-color [null] The selected chip border color. Auto-derived from selected-background. /// -/// @param {color} $hover-selected-text-color [null] - The selected chip hover text color. -/// @param {color} $hover-selected-background [null] - The selected chip hover background color. -/// @param {color} $hover-selected-border-color [null] - The selected chip hover border color. +/// @param {color} $hover-selected-text-color [null] - The selected chip hover text color. Auto-derived from hover-selected-background. +/// @param {color} $hover-selected-background [null] - The selected chip hover background color. Auto-derived from selected-background. +/// @param {color} $hover-selected-border-color [null] - The selected chip hover border color. Auto-derived from hover-selected-background. /// -/// @param {color} $focus-selected-text-color [null] - The selected chip text focus color. -/// @param {color} $focus-selected-background [null] - The selected chip focus background color. -/// @param {color} $focus-selected-border-color [null] - The selected chip focus border color. +/// @param {color} $focus-selected-text-color [null] - The selected chip text focus color. Auto-derived from focus-selected-background. +/// @param {color} $focus-selected-background [null] - The selected chip focus background color. Auto-derived from selected-background. +/// @param {color} $focus-selected-border-color [null] - The selected chip focus border color. Auto-derived from focus-selected-background. /// /// @param {color} $remove-icon-color [null] - The remove icon color for the chip. /// @param {color} $remove-icon-color-focus [null] - The remove icon color on focus for the chip. diff --git a/sass/themes/components/column-actions/_column-actions-theme.scss b/sass/themes/components/column-actions/_column-actions-theme.scss index 3c2b6cf5..bfcf29a0 100644 --- a/sass/themes/components/column-actions/_column-actions-theme.scss +++ b/sass/themes/components/column-actions/_column-actions-theme.scss @@ -12,10 +12,16 @@ /// @author Marin Popov //// -/// Column actions Theme +/// Column Actions Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background-color` - The background color of the panel. Auto-derives: title-color. +/// +/// Setting background-color automatically calculates a contrasting title-color. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $title-color [null]- The text color used for the title of the list. -/// @param {Color} $background-color [null] - The background color of the panel. +/// @param {Color} $title-color [null]- The text color used for the title of the list. Auto-derived from background-color. +/// @param {Color} $background-color [null] - The background color of the panel. PRIMARY - derives title-color. /// /// @requires $light-material-schema /// diff --git a/sass/themes/components/combo/_combo-theme.scss b/sass/themes/components/combo/_combo-theme.scss index 67ccb4c3..9cd41d69 100644 --- a/sass/themes/components/combo/_combo-theme.scss +++ b/sass/themes/components/combo/_combo-theme.scss @@ -14,22 +14,32 @@ /// @author Simeon Simeonoff //// +/// Combo Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$toggle-button-background` - The toggle button background. Auto-derives: toggle-button-foreground, toggle-button-background-focus, toggle-button-foreground-focus, toggle-button-background-disabled, toggle-button-foreground-disabled, toggle-button-foreground-filled. +/// - `$empty-list-background` - The empty list background. Auto-derives: empty-list-placeholder-color. +/// - `$clear-button-background-focus` - The clear button focus background. Auto-derives: clear-button-foreground-focus. +/// +/// Toggle button colors cascade from toggle-button-background through focus and disabled states. +/// Behavior varies by variant (material uses shaded focus background, others use same as base). +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {Color} $search-separator-border-color [null] - The combo search box separator color. -/// @param {Color} $empty-list-placeholder-color [null] - The combo placeholder text color. -/// @param {Color} $empty-list-background [null] - The combo list background color. -/// @param {Color} $toggle-button-background [null] - The combo toggle button background color. -/// @param {Color} $toggle-button-background-focus [null] - The combo toggle button background color when the combo is focused in material box variant. -/// @param {Color} $toggle-button-background-focus--border [null] - The combo toggle button background color when the combo is focused in material border variant. -/// @param {Color} $toggle-button-background-disabled [null] - The combo toggle button background color when the combo is disabled. -/// @param {Color} $toggle-button-foreground [null] - The combo toggle button foreground color. -/// @param {Color} $toggle-button-foreground-focus [null] - The combo toggle button foreground color when the combo is focused. -/// @param {Color} $toggle-button-foreground-disabled [null] - The combo toggle button foreground color when the combo is disabled. -/// @param {Color} $toggle-button-foreground-filled [null] - The combo toggle button foreground color when the combo is filled. +/// @param {Color} $empty-list-placeholder-color [null] - The combo placeholder text color. Auto-derived from empty-list-background. +/// @param {Color} $empty-list-background [null] - The combo list background color. PRIMARY - derives empty-list-placeholder-color. +/// @param {Color} $toggle-button-background [null] - The combo toggle button background color. PRIMARY - derives all toggle button colors. +/// @param {Color} $toggle-button-background-focus [null] - The combo toggle button background color when the combo is focused in material box variant. Auto-derived from toggle-button-background. +/// @param {Color} $toggle-button-background-focus--border [null] - The combo toggle button background color when the combo is focused in material border variant. Auto-derived from toggle-button-background. +/// @param {Color} $toggle-button-background-disabled [null] - The combo toggle button background color when the combo is disabled. Auto-derived from toggle-button-background. +/// @param {Color} $toggle-button-foreground [null] - The combo toggle button foreground color. Auto-derived from toggle-button-background. +/// @param {Color} $toggle-button-foreground-focus [null] - The combo toggle button foreground color when the combo is focused. Auto-derived from toggle-button-background-focus. +/// @param {Color} $toggle-button-foreground-disabled [null] - The combo toggle button foreground color when the combo is disabled. Auto-derived from toggle-button-background. +/// @param {Color} $toggle-button-foreground-filled [null] - The combo toggle button foreground color when the combo is filled. Auto-derived from toggle-button-background. /// @param {Color} $clear-button-background [null] - The combo clear button background color. -/// @param {Color} $clear-button-background-focus [null] - The combo clear button background color when the combo is focused. +/// @param {Color} $clear-button-background-focus [null] - The combo clear button background color when the combo is focused. PRIMARY for clear button focus. /// @param {Color} $clear-button-foreground [null] - The combo clear button foreground color. -/// @param {Color} $clear-button-foreground-focus [null] - The combo clear button foreground color when the combo is focused. +/// @param {Color} $clear-button-foreground-focus [null] - The combo clear button foreground color when the combo is focused. Auto-derived from clear-button-background-focus. /// @requires $light-material-schema /// @example scss Change the combo empty list background /// $my-combo-theme: igx-checkbox-theme($empty-list-background); diff --git a/sass/themes/components/date-range-picker/_date-range-picker-theme.scss b/sass/themes/components/date-range-picker/_date-range-picker-theme.scss index b2317119..9600d048 100644 --- a/sass/themes/components/date-range-picker/_date-range-picker-theme.scss +++ b/sass/themes/components/date-range-picker/_date-range-picker-theme.scss @@ -11,6 +11,11 @@ /// @author Marin Popov //// +/// Date Range Picker Theme +/// +/// NOTE: This component has no automatic token derivation. +/// All tokens are directly passed to the schema without calculations. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {color} $label-color [null] - The color for date range separator label. @function date-range-picker-theme($schema: $light-material-schema, $label-color: null) { diff --git a/sass/themes/components/dialog/_dialog-theme.scss b/sass/themes/components/dialog/_dialog-theme.scss index fc8f3cb6..3bffcb63 100644 --- a/sass/themes/components/dialog/_dialog-theme.scss +++ b/sass/themes/components/dialog/_dialog-theme.scss @@ -15,13 +15,19 @@ //// /// Dialog Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` - The dialog background color. Auto-derives: title-color, message-color, border-color. +/// +/// Setting just `$background` will create a complete dialog theme with proper text contrast. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $background [null] - The dialog background color. -/// @param {Color} $title-color [null] - The dialog title text color. -/// @param {Color} $message-color [null] - The dialog message text color. +/// @param {Color} $background [null] - The dialog background color. PRIMARY - derives title-color, message-color, border-color. +/// @param {Color} $title-color [null] - The dialog title text color. Auto-derived from background. +/// @param {Color} $message-color [null] - The dialog message text color. Auto-derived from background (slightly transparent). /// @param {box-shadow} $shadow [null] - The shadow used for the dialog. /// @param {List} $border-radius [null] - The border radius used for dialog component. -/// @param {Color} $border-color [null] - The border color used for dialog component. +/// @param {Color} $border-color [null] - The border color used for dialog component. Auto-derived from background. /// @requires $light-material-schema /// @example scss Change the background color /// $my-dialog-theme: dialog-theme($background: black); diff --git a/sass/themes/components/divider/_divider-theme.scss b/sass/themes/components/divider/_divider-theme.scss index e0afc890..760f1ab9 100644 --- a/sass/themes/components/divider/_divider-theme.scss +++ b/sass/themes/components/divider/_divider-theme.scss @@ -13,6 +13,10 @@ /// @author Marin Popov //// +/// Divider Theme +/// +/// This theme has no automatic token derivation. All tokens are independent. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {Color} $color [null] - The color of the divider. (Gradients are not supported for dashed dividers). /// @param {number} $inset [null] - The inset value of the divider. diff --git a/sass/themes/components/dock-manager/_dock-manager-theme.scss b/sass/themes/components/dock-manager/_dock-manager-theme.scss index e7fdc5ad..59caa2ce 100644 --- a/sass/themes/components/dock-manager/_dock-manager-theme.scss +++ b/sass/themes/components/dock-manager/_dock-manager-theme.scss @@ -15,7 +15,12 @@ /// @author Marin Popov //// -/// If only background color is specified, text/icon color will be assigned automatically to a contrasting color. +/// Dock Manager Theme +/// +/// NOTE: This component uses a pass-through pattern with meta.keywords($rest). +/// All tokens are directly passed to the schema without automatic derivation. +/// Each token must be set individually for full customization. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {Color} $accent-color [null] - Sets the pinned header background color, the joystick background and border colors, as well as the context menu background color. /// @param {Color} $active-color [null] - Sets the active text and border colors for tabs, panes, and menus. diff --git a/sass/themes/components/drop-down/_drop-down-theme.scss b/sass/themes/components/drop-down/_drop-down-theme.scss index 9fb82389..7d1260f8 100644 --- a/sass/themes/components/drop-down/_drop-down-theme.scss +++ b/sass/themes/components/drop-down/_drop-down-theme.scss @@ -14,28 +14,37 @@ /// @author Simeon Simeonoff //// -/// Generates a drop-down theme. +/// Drop-down Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background-color` - The drop-down background. Auto-derives: item-text-color, hover-item-background, focused-item-background, selected-item-background, disabled-item-text-color, header-text-color. +/// - `$selected-item-background` - The selected item background. Auto-derives: selected-item-text-color, selected-hover-*, selected-focus-*, focused-item-border-color (indigo). +/// +/// Setting background-color cascades through all item states (hover, focused, selected, disabled). +/// Selected state colors derive from selected-item-background through hover and focus states. +/// Icon colors are derived from their corresponding text colors with reduced opacity. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $background-color [null] - The drop-down background color. -/// @param {Color} $header-text-color [null] - The drop-down header text color. -/// @param {Color} $item-text-color [null] - The drop-down item text color. -/// @param {Color} $item-icon-color [null] - The drop-down item icon color. -/// @param {Color} $hover-item-text-color [null] - The drop-down item hover text color. -/// @param {Color} $hover-item-icon-color [null] - The drop-down item hover icon color. -/// @param {Color} $hover-item-background [null] - The drop-down hover item background color. -/// @param {Color} $focused-item-background [null] - The drop-down focused item background color. -/// @param {Color} $focused-item-text-color [null] - The drop-down focused item text color. -/// @param {Color} $focused-item-border-color [null] - The drop-down item focused border color. -/// @param {Color} $selected-item-background [null] - The drop-down selected item background color. -/// @param {Color} $selected-item-text-color [null] - The drop-down selected item text color. -/// @param {Color} $selected-item-icon-color [null] - The drop-down selected item icon color. -/// @param {Color} $selected-hover-item-background [null] - The drop-down selected item hover background color. -/// @param {Color} $selected-hover-item-text-color [null] - The drop-down selected item hover text color. -/// @param {Color} $selected-hover-item-icon-color [null] - The drop-down selected item hover icon color. -/// @param {Color} $selected-focus-item-background [null] - The drop-down selected item focus background color. -/// @param {Color} $selected-focus-item-text-color [null] - The drop-down selected item focus text color. +/// @param {Color} $background-color [null] - The drop-down background color. PRIMARY - derives item, hover, focus, selected, disabled colors. +/// @param {Color} $header-text-color [null] - The drop-down header text color. Auto-derived from background-color. +/// @param {Color} $item-text-color [null] - The drop-down item text color. Auto-derived from background-color. +/// @param {Color} $item-icon-color [null] - The drop-down item icon color. Auto-derived from item-text-color. +/// @param {Color} $hover-item-text-color [null] - The drop-down item hover text color. Auto-derived from item-text-color. +/// @param {Color} $hover-item-icon-color [null] - The drop-down item hover icon color. Auto-derived from hover-item-text-color. +/// @param {Color} $hover-item-background [null] - The drop-down hover item background color. Auto-derived from background-color. +/// @param {Color} $focused-item-background [null] - The drop-down focused item background color. Auto-derived from background-color. +/// @param {Color} $focused-item-text-color [null] - The drop-down focused item text color. Auto-derived from focused-item-background. +/// @param {Color} $focused-item-border-color [null] - The drop-down item focused border color. Auto-derived from selected-item-background (indigo). +/// @param {Color} $selected-item-background [null] - The drop-down selected item background color. PRIMARY - derives selected text/icon and hover/focus states. Auto-derived from background-color. +/// @param {Color} $selected-item-text-color [null] - The drop-down selected item text color. Auto-derived from selected-item-background. +/// @param {Color} $selected-item-icon-color [null] - The drop-down selected item icon color. Auto-derived from selected-item-text-color. +/// @param {Color} $selected-hover-item-background [null] - The drop-down selected item hover background color. Auto-derived from selected-item-background. +/// @param {Color} $selected-hover-item-text-color [null] - The drop-down selected item hover text color. Auto-derived from selected-hover-item-background. +/// @param {Color} $selected-hover-item-icon-color [null] - The drop-down selected item hover icon color. Auto-derived from selected-hover-item-text-color. +/// @param {Color} $selected-focus-item-background [null] - The drop-down selected item focus background color. Auto-derived from selected-item-background. +/// @param {Color} $selected-focus-item-text-color [null] - The drop-down selected item focus text color. Auto-derived from selected-focus-item-background. /// @param {Color} $disabled-item-background [null] - The drop-down disabled item background color. -/// @param {Color} $disabled-item-text-color [null] - The drop-down disabled item text color. +/// @param {Color} $disabled-item-text-color [null] - The drop-down disabled item text color. Auto-derived from background-color or disabled-item-background. /// @param {box-shadow} $shadow [null] - Sets a shadow to be used for the drop-down. /// @param {Number} $border-width [null] - The border width used for drop-down component. /// @param {Color} $border-color [null] - The border color used for drop-down component. diff --git a/sass/themes/components/expansion-panel/_expansion-panel-theme.scss b/sass/themes/components/expansion-panel/_expansion-panel-theme.scss index ca270fa6..f42b0af3 100644 --- a/sass/themes/components/expansion-panel/_expansion-panel-theme.scss +++ b/sass/themes/components/expansion-panel/_expansion-panel-theme.scss @@ -13,17 +13,25 @@ /// @author Marin Popov //// -/// Expansion panel Theme +/// Expansion Panel Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$header-background` - The panel header background. Auto-derives: header-title-color, header-icon-color, header-description-color, header-focus-background, disabled colors. +/// - `$body-background` - The panel body background. Auto-derives: body-color. +/// +/// Setting header-background cascades to all header text/icon colors and focus/disabled states. +/// Body background independently derives its text color. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $header-background [null] - The panel header background color. -/// @param {Color} $header-focus-background [null] - The panel header focus background color. -/// @param {Color} $header-title-color [null] - The panel header title text color. -/// @param {Color} $header-description-color [null] - The panel header description text color. -/// @param {Color} $header-icon-color [null] - The panel header icon color. -/// @param {Color} $body-color [null] - The panel body text color. -/// @param {Color} $body-background [null] - The panel body background color. -/// @param {Color} $disabled-text-color [null] - The panel disabled text color. -/// @param {Color} $disabled-description-color [null] - The panel disabled header description text color. +/// @param {Color} $header-background [null] - The panel header background color. PRIMARY - derives header colors, focus, disabled. +/// @param {Color} $header-focus-background [null] - The panel header focus background color. Auto-derived from header-background. +/// @param {Color} $header-title-color [null] - The panel header title text color. Auto-derived from header-background. +/// @param {Color} $header-description-color [null] - The panel header description text color. Auto-derived from header-background (muted). +/// @param {Color} $header-icon-color [null] - The panel header icon color. Auto-derived from header-background. +/// @param {Color} $body-color [null] - The panel body text color. Auto-derived from body-background. +/// @param {Color} $body-background [null] - The panel body background color. PRIMARY for body - derives body-color. +/// @param {Color} $disabled-text-color [null] - The panel disabled text color. Auto-derived from header-background. +/// @param {Color} $disabled-description-color [null] - The panel disabled header description text color. Auto-derived from header-background. /// @param {Number} $expanded-margin [null] - The expansion panel margin in expanded state when positioned inside accordion. /// @param {List} $border-radius [null] - The border radius used for expansion-panel component. /// @requires $light-material-schema diff --git a/sass/themes/components/grid/_grid-summary-theme.scss b/sass/themes/components/grid/_grid-summary-theme.scss index 6bb8ed1c..16af4fa1 100644 --- a/sass/themes/components/grid/_grid-summary-theme.scss +++ b/sass/themes/components/grid/_grid-summary-theme.scss @@ -14,15 +14,23 @@ /// @author Marin Popov //// +/// Grid Summary Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background-color` - The summaries background color. Auto-derives: label-color, result-color, border-color, pinned-border-color. +/// - `$label-color` - The summaries label color. Auto-derives: label-hover-color. +/// +/// Setting background-color automatically calculates contrasting label and result colors, plus border colors. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $background-color [null] - The summaries background color is inherited form igx-grid__tfoot -/// @param {Color} $label-color [null] - The summaries label color. -/// @param {Color} $result-color [null] - The summaries value/result color. -/// @param {Color} $border-color [null] - The summaries border color. +/// @param {Color} $background-color [null] - The summaries background color. PRIMARY - derives label-color, result-color, border-color, pinned-border-color. +/// @param {Color} $label-color [null] - The summaries label color. PRIMARY - derives label-hover-color. Auto-derived from background-color. +/// @param {Color} $result-color [null] - The summaries value/result color. Auto-derived from background-color. +/// @param {Color} $border-color [null] - The summaries border color. Auto-derived from background-color. /// @param {Color} $pinned-border-width [null] - The border width of the summary panel. /// @param {Color} $pinned-border-style [null] - The border style of the summary panel. -/// @param {Color} $pinned-border-color [null] - The border color of the summary panel. -/// @param {Color} $label-hover-color [null] - The summaries hover label color. +/// @param {Color} $pinned-border-color [null] - The border color of the summary panel. Auto-derived from background-color. +/// @param {Color} $label-hover-color [null] - The summaries hover label color. Auto-derived from label-color. /// @requires $light-material-schema /// @example scss Change the summaries background and labels color /// $my-summary-theme: grid-summary-theme( diff --git a/sass/themes/components/grid/_grid-theme.scss b/sass/themes/components/grid/_grid-theme.scss index 91fffebf..94687954 100644 --- a/sass/themes/components/grid/_grid-theme.scss +++ b/sass/themes/components/grid/_grid-theme.scss @@ -14,87 +14,98 @@ /// @author Marin Popov //// +/// Grid Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$header-background` - The table header background color. Auto-derives: header-text-color, header-border-color, header-selected-background, sorted-header-icon-color, expand-all-icon-color, expand-all-icon-hover-color, group-row-background, grouparea-background, filtering-header-background, filtering-row-background. +/// - `$content-background` - The table body background color. Auto-derives: content-text-color, row-odd-background, row-even-background, row-hover-background, row-border-color, row-selected-background, cell-selected-background, cell-editing-background, cell-active-border-color, pinned-border-color, edit-mode-color. +/// - `$ghost-header-background` - The dragged header background color. Auto-derives: ghost-header-text-color, ghost-header-icon-color. +/// - `$group-row-background` - The grid group row background color. Auto-derives: expand-icon-color, group-row-selected-background, group-label-text, group-count-background. +/// - `$grouparea-background` - The grid group area background color. Auto-derives: grouparea-color, drop-area-background. +/// +/// Setting header-background and content-background gives you comprehensive grid styling with automatic contrast calculations. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $header-background [null] - The table header background color. -/// @param {Color} $header-text-color [null] - The table header text color. +/// @param {Color} $header-background [null] - The table header background color. PRIMARY - derives header-text-color, header-border-color, and many more. +/// @param {Color} $header-text-color [null] - The table header text color. Auto-derived from header-background. /// @param {String} $header-border-width [null] - The border width used for header borders. /// @param {String} $header-border-style [null] - The border style used for header borders. -/// @param {Color} $header-border-color [null] - The color used for header borders. -/// @param {Color} $header-selected-background [null] - The table header background color when selected (ex. column selection). -/// @param {Color} $header-selected-text-color [null] - The table header text color when selected (ex. column selection). -/// @param {Color} $sorted-header-icon-color [null] - The sort icon color when sorted. -/// @param {color} $sortable-header-icon-hover-color [null] - The icon color on hover in grid header when the column is sortable. -/// @param {Color} $content-background [null] - The table body background color. -/// @param {Color} $content-text-color [null] - The table body text color. -/// @param {Color} $ghost-header-text-color [null] - The dragged header text color. -/// @param {Color} $ghost-header-icon-color [null] - The dragged header icon color. -/// @param {Color} $ghost-header-background [null] - The dragged header background color. -/// @param {Color} $row-odd-background [null] - The background color of odd rows. -/// @param {Color} $row-even-background [null] - The background color of even rows. -/// @param {Color} $row-odd-text-color [null] - The text color of odd rows. -/// @param {Color} $row-even-text-color [null] - The text color of even rows. -/// @param {Color} $row-selected-background [null] - The selected row background color. -/// @param {Color} $row-selected-hover-background [null] - The selected row hover background color. -/// @param {Color} $row-selected-text-color [null] - The selected row text color. -/// @param {Color} $row-selected-hover-text-color [null] - The selected row hover text color. -/// @param {Color} $row-hover-background [null] - The hover row background color. -/// @param {Color} $row-hover-text-color [null] - The hover row text color. -/// @param {Color} $row-border-color [null] - The row bottom border color. +/// @param {Color} $header-border-color [null] - The color used for header borders. Auto-derived from header-background. +/// @param {Color} $header-selected-background [null] - The table header background color when selected. Auto-derived from header-background. +/// @param {Color} $header-selected-text-color [null] - The table header text color when selected. Auto-derived from header-selected-background. +/// @param {Color} $sorted-header-icon-color [null] - The sort icon color when sorted. Auto-derived from header-background. +/// @param {color} $sortable-header-icon-hover-color [null] - The icon color on hover when sortable. Auto-derived from sorted-header-icon-color. +/// @param {Color} $content-background [null] - The table body background color. PRIMARY - derives content-text-color, row backgrounds, cell backgrounds, borders. +/// @param {Color} $content-text-color [null] - The table body text color. Auto-derived from content-background. +/// @param {Color} $ghost-header-text-color [null] - The dragged header text color. Auto-derived from ghost-header-background. +/// @param {Color} $ghost-header-icon-color [null] - The dragged header icon color. Auto-derived from ghost-header-background. +/// @param {Color} $ghost-header-background [null] - The dragged header background color. PRIMARY - derives ghost-header-text-color, ghost-header-icon-color. +/// @param {Color} $row-odd-background [null] - The background color of odd rows. Auto-derived from content-background. +/// @param {Color} $row-even-background [null] - The background color of even rows. Auto-derived from content-background. +/// @param {Color} $row-odd-text-color [null] - The text color of odd rows. Auto-derived from row-odd-background. +/// @param {Color} $row-even-text-color [null] - The text color of even rows. Auto-derived from row-even-background. +/// @param {Color} $row-selected-background [null] - The selected row background color. Auto-derived from content-background. +/// @param {Color} $row-selected-hover-background [null] - The selected row hover background color. Auto-derived from row-selected-background. +/// @param {Color} $row-selected-text-color [null] - The selected row text color. Auto-derived from row-selected-background. +/// @param {Color} $row-selected-hover-text-color [null] - The selected row hover text color. Auto-derived from row-selected-hover-background. +/// @param {Color} $row-hover-background [null] - The hover row background color. Auto-derived from content-background. +/// @param {Color} $row-hover-text-color [null] - The hover row text color. Auto-derived from row-hover-background. +/// @param {Color} $row-border-color [null] - The row bottom border color. Auto-derived from content-background. /// @param {String} $pinned-border-width [null] - The border width of the pinned border. /// @param {String} $pinned-border-style [null] - The CSS border style of the pinned border. -/// @param {Color} $pinned-border-color [null] - The color of the pinned border. -/// @param {Color} $cell-active-border-color [null] - The border color for the currently active(focused) cell. -/// @param {Color} $cell-selected-background [null] - The selected cell background color. -/// @param {Color} $cell-selected-text-color [null] - The selected cell text color. -/// @param {Color} $cell-editing-background [null] - The background color of the cell being edited. -/// @param {Color} $cell-editing-foreground [null] - The cell text color in edit mode. -/// @param {Color} $cell-editing-focus-foreground [null] - The cell text color in edit mode on focus. -/// @param {Color} $cell-edited-value-color [null] - The text color of a cell that has been edited. -/// @param {Color} $cell-new-color [null] - The text color of a new, unedited cell. Used when adding new row in a grid. +/// @param {Color} $pinned-border-color [null] - The color of the pinned border. Auto-derived from content-background. +/// @param {Color} $cell-active-border-color [null] - The border color for the active cell. Auto-derived from content-background. +/// @param {Color} $cell-selected-background [null] - The selected cell background color. Auto-derived from content-background. +/// @param {Color} $cell-selected-text-color [null] - The selected cell text color. Auto-derived from cell-selected-background. +/// @param {Color} $cell-editing-background [null] - The background of the cell being edited. Auto-derived from content-background. +/// @param {Color} $cell-editing-foreground [null] - The cell text color in edit mode. Auto-derived from cell-editing-background. +/// @param {Color} $cell-editing-focus-foreground [null] - The cell text color in edit mode on focus. Auto-derived from cell-editing-background. +/// @param {Color} $cell-edited-value-color [null] - The text color of an edited cell. +/// @param {Color} $cell-new-color [null] - The text color of a new cell. /// @param {Color} $cell-disabled-color [null] - The text color of a disabled cell. -/// @param {Color} $cell-selected-within-background [null] - The background of the selected cell inside a selected row/column. -/// @param {Color} $cell-selected-within-text-color [null] - The color of the selected cell inside a selected row/column. -/// @param {Color} $edit-mode-color [null] - The color applied around the row/cell when in editing mode. -/// @param {Color} $edited-row-indicator [null] - The color applied to the edited row indicator line. +/// @param {Color} $cell-selected-within-background [null] - The background of selected cell in selected row. Auto-derived from row-selected-background. +/// @param {Color} $cell-selected-within-text-color [null] - The color of selected cell in selected row. Auto-derived from cell-selected-within-background. +/// @param {Color} $edit-mode-color [null] - The color around the row/cell in edit mode. Auto-derived from content-background. +/// @param {Color} $edited-row-indicator [null] - The edited row indicator line color. /// @param {Color} $resize-line-color [null] - The table header resize line color. -/// @param {Color} $drop-indicator-color [null] - The color applied to the line between the columns when dragging a column. -/// @param {Color} $grouparea-background [null] - The grid group area background color. -/// @param {Color} $grouparea-color [null] - The grid group area color. -/// @param {Color} $group-row-background [null] - The grid group row background color. -/// @param {Color} $group-row-selected-background [null] - The drop area background on drop color. +/// @param {Color} $drop-indicator-color [null] - The color of the column drag indicator line. +/// @param {Color} $grouparea-background [null] - The grid group area background color. PRIMARY - derives grouparea-color, drop-area-background. Auto-derived from header-background. +/// @param {Color} $grouparea-color [null] - The grid group area color. Auto-derived from grouparea-background. +/// @param {Color} $group-row-background [null] - The grid group row background color. PRIMARY - derives expand-icon-color, group-row-selected-background, group-label-text, group-count-background. Auto-derived from header-background. +/// @param {Color} $group-row-selected-background [null] - The group row selected background. Auto-derived from group-row-background. /// @param {Color} $group-label-column-name-text [null] - The grid group row column name text color. /// @param {Color} $group-label-icon [null] - The grid group row icon color. -/// @param {Color} $group-label-text [null] - The grid group row text color. -/// @param {Color} $expand-all-icon-color [null] - The grid header expand all group rows icon color. -/// @param {Color} $expand-all-icon-hover-color [null] - The grid header expand all group rows icon hover color. -/// @param {Color} $expand-icon-color [null] - The grid row expand icon color. -/// @param {Color} $expand-icon-hover-color [null] - The grid row expand icon hover color. -/// @param {Color} $active-expand-icon-color [null] - The drop area background on drop color. -/// @param {Color} $active-expand-icon-hover-color [null] - The drop area background on drop color. -/// @param {Color} $group-count-background [null] - The grid group row cont badge background color. -/// @param {Color} $group-count-text-color [null] - The grid group row cont badge text color. -/// @param {Color} $drop-area-text-color [null] - The drop area text color. -/// @param {Color} $drop-area-icon-color [null] - The drop area icon color. -/// @param {Color} $drop-area-background [null] - The drop area background color. -/// @param {Color} $drop-area-on-drop-background [null] - The drop area background on drop color. -/// @param {Color} $filtering-header-background [null] - The background color of the filtered column header. -/// @param {Color} $filtering-header-text-color [null] - The text color of the filtered column header. -/// @param {Color} $filtering-row-background [null] - The background color of the filtering row. -/// @param {Color} $filtering-row-text-color [null] - The text color of the filtering row. -/// @param {Color} $excel-filtering-header-foreground [null] - The text color of the header in the excel style filtering. -/// @param {Color} $excel-filtering-subheader-foreground [null] - The text color of the sorting and moving headers in the excel style filtering. -/// @param {Color} $excel-filtering-actions-foreground [null] - The text color of the excel style filtering options. -/// @param {Color} $excel-filtering-actions-hover-foreground [null] - The text color of the excel style filtering options in hover/focus state. -/// @param {Color} $excel-filtering-actions-disabled-foreground [null] - The text color of the excel style filtering options in disabled state. +/// @param {Color} $group-label-text [null] - The grid group row text color. Auto-derived from group-row-background or group-row-selected-background. +/// @param {Color} $expand-all-icon-color [null] - The header expand all icon color. Auto-derived from header-background. +/// @param {Color} $expand-all-icon-hover-color [null] - The header expand all icon hover color. Auto-derived from header-background. +/// @param {Color} $expand-icon-color [null] - The grid row expand icon color. Auto-derived from group-row-background or group-row-selected-background. +/// @param {Color} $expand-icon-hover-color [null] - The grid row expand icon hover color. Auto-derived from expand-icon-color. +/// @param {Color} $active-expand-icon-color [null] - The active expand icon color. +/// @param {Color} $active-expand-icon-hover-color [null] - The active expand icon hover color. +/// @param {Color} $group-count-background [null] - The group row count badge background. Auto-derived from group-row-background or group-row-selected-background. +/// @param {Color} $group-count-text-color [null] - The group row count badge text color. Auto-derived from group-count-background. +/// @param {Color} $drop-area-text-color [null] - The drop area text color. Auto-derived from drop-area-background. +/// @param {Color} $drop-area-icon-color [null] - The drop area icon color. Auto-derived from drop-area-background. +/// @param {Color} $drop-area-background [null] - The drop area background color. Auto-derived from grouparea-background. +/// @param {Color} $drop-area-on-drop-background [null] - The drop area background on drop. Auto-derived from drop-area-background. +/// @param {Color} $filtering-header-background [null] - The filtered column header background. Auto-derived from header-background. +/// @param {Color} $filtering-header-text-color [null] - The filtered column header text color. Auto-derived from filtering-header-background. +/// @param {Color} $filtering-row-background [null] - The filtering row background. Auto-derived from header-background. +/// @param {Color} $filtering-row-text-color [null] - The filtering row text color. Auto-derived from filtering-row-background. +/// @param {Color} $excel-filtering-header-foreground [null] - The excel filtering header text color. Auto-derived from filtering-row-background. +/// @param {Color} $excel-filtering-subheader-foreground [null] - The excel filtering subheader text color. Auto-derived from filtering-row-background. +/// @param {Color} $excel-filtering-actions-foreground [null] - The excel filtering actions text color. Auto-derived from filtering-row-background. +/// @param {Color} $excel-filtering-actions-hover-foreground [null] - The excel filtering actions hover text color. +/// @param {Color} $excel-filtering-actions-disabled-foreground [null] - The excel filtering actions disabled text color. Auto-derived from filtering-row-background. /// @param {Color} $tree-filtered-text-color [null] - Grouping row background color on focus. -/// @param {Color} $summaries-patch-background [null] - The leading summaries patch backround. Used in hierarchical grids. +/// @param {Color} $summaries-patch-background [null] - The leading summaries patch background. /// @param {Color} $row-highlight [null] - The grid row highlight indication color. /// @param {box-shadow} $grid-shadow [null] - The shadow of the grid. -/// @param {box-shadow} $drag-shadow [null] - The shadow used for movable elements (ex. column headers). +/// @param {box-shadow} $drag-shadow [null] - The shadow for movable elements. /// @param {color} $row-ghost-background [null] - The dragged row background color. /// @param {color} $row-drag-color [null] - The row drag handle color. /// @param {Color} $grid-border-color [null] - The color of the grid border. -/// @param {List} $drop-area-border-radius [null] - The border radius used for column drop area. +/// @param {List} $drop-area-border-radius [null] - The border radius for column drop area. /// @requires $light-material-schema /// @example scss Change the header background color /// $my-grid-theme: grid-theme($header-background: black); diff --git a/sass/themes/components/grid/_grid-toolbar-theme.scss b/sass/themes/components/grid/_grid-toolbar-theme.scss index b0dbdf23..28d669e0 100644 --- a/sass/themes/components/grid/_grid-toolbar-theme.scss +++ b/sass/themes/components/grid/_grid-toolbar-theme.scss @@ -14,15 +14,26 @@ /// @author Simeon Simeonoff //// +/// Grid Toolbar Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background-color` - The toolbar background color. Auto-derives: title-text-color. +/// - `$dropdown-background` - The toolbar drop-down background color. Auto-derives: item-text-color, item-hover-text-color, item-focus-text-color. +/// - `$item-hover-background` - The drop-down item hover background. Auto-derives: item-hover-text-color. +/// - `$item-focus-background` - The drop-down item focus background. Auto-derives: item-focus-text-color. +/// +/// Setting background-color automatically calculates a contrasting title-text-color. +/// Setting dropdown-background calculates contrasting text colors for dropdown items. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $background-color [null] - The toolbar background color. -/// @param {Color} $title-text-color [null] - The toolbar title text color. -/// @param {Color} $dropdown-background [null] - The toolbar drop-down background color. -/// @param {Color} $item-text-color [null] - The toolbar drop-down item text color. -/// @param {Color} $item-hover-background [null] - The toolbar drop-down item hover background color. -/// @param {Color} $item-hover-text-color [null] - The toolbar drop-down item hover text color. -/// @param {Color} $item-focus-background [null] - The toolbar drop-down item focus background color. -/// @param {Color} $item-focus-text-color [null] - The toolbar drop-down item focus text color. +/// @param {Color} $background-color [null] - The toolbar background color. PRIMARY - derives title-text-color. +/// @param {Color} $title-text-color [null] - The toolbar title text color. Auto-derived from background-color. +/// @param {Color} $dropdown-background [null] - The toolbar drop-down background color. PRIMARY - derives item-text-color. +/// @param {Color} $item-text-color [null] - The toolbar drop-down item text color. Auto-derived from dropdown-background. +/// @param {Color} $item-hover-background [null] - The toolbar drop-down item hover background color. PRIMARY - derives item-hover-text-color. +/// @param {Color} $item-hover-text-color [null] - The toolbar drop-down item hover text color. Auto-derived from dropdown-background or item-hover-background. +/// @param {Color} $item-focus-background [null] - The toolbar drop-down item focus background color. PRIMARY - derives item-focus-text-color. +/// @param {Color} $item-focus-text-color [null] - The toolbar drop-down item focus text color. Auto-derived from dropdown-background or item-focus-background. /// @param {Color} $border-color [null] - The toolbar border-bottom color. /// @requires $light-material-schema /// @example scss Change the toolbar background color diff --git a/sass/themes/components/grid/_pivot-data-selector-theme.scss b/sass/themes/components/grid/_pivot-data-selector-theme.scss index 4276cd33..8cd9185b 100644 --- a/sass/themes/components/grid/_pivot-data-selector-theme.scss +++ b/sass/themes/components/grid/_pivot-data-selector-theme.scss @@ -13,6 +13,11 @@ /// @author Simeon Simeonoff //// +/// Pivot Data Selector Theme +/// +/// NOTE: This component has no automatic token derivation. +/// All tokens are directly passed to the schema without calculations. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. @function pivot-data-selector-theme($schema: $light-material-schema, $background: null) { $name: 'igx-pivot-data-selector'; diff --git a/sass/themes/components/highlight/_highlight-theme.scss b/sass/themes/components/highlight/_highlight-theme.scss index 7d24fd38..a518cfa3 100644 --- a/sass/themes/components/highlight/_highlight-theme.scss +++ b/sass/themes/components/highlight/_highlight-theme.scss @@ -13,12 +13,19 @@ /// @author Simeon Simeonoff //// +/// Highlight Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$resting-background` - The resting state background. Auto-derives: resting-color. +/// - `$active-background` - The active state background. Auto-derives: active-color. +/// /// If only background color(s) specified, text color(s) will be assigned automatically to a contrasting color. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $resting-background [null]- The background color used for the highlight in its resting state. -/// @param {Color} $resting-color [null] - The text color used for the highlight in its resting state. -/// @param {Color} $active-background [null] - The background color used for the highlight in its active state. -/// @param {Color} $active-color [null] - The text color used for the highlight in its active state. +/// @param {Color} $resting-background [null]- The background color used for the highlight in its resting state. PRIMARY - derives resting-color. +/// @param {Color} $resting-color [null] - The text color used for the highlight in its resting state. Auto-derived from resting-background. +/// @param {Color} $active-background [null] - The background color used for the highlight in its active state. PRIMARY - derives active-color. +/// @param {Color} $active-color [null] - The text color used for the highlight in its active state. Auto-derived from active-background. /// @requires $light-material-schema /// @example scss Change the background and icon colors in icon highlight /// $my-highlight-theme: highlight-theme($resting-background: black, $active-color: white); diff --git a/sass/themes/components/icon-button/_contained-icon-button-theme.scss b/sass/themes/components/icon-button/_contained-icon-button-theme.scss index c54f9058..5f47fcaf 100644 --- a/sass/themes/components/icon-button/_contained-icon-button-theme.scss +++ b/sass/themes/components/icon-button/_contained-icon-button-theme.scss @@ -13,24 +13,32 @@ /// @author Silvia Ivanova //// -/// Generates a theme map for the contained variant of the icon button component. +/// Contained Icon Button Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` - Background color for the contained icon button. Auto-derives: foreground, hover-background, focus-background, active-background, and their foreground colors, plus shadow-color, disabled-background. +/// - `$foreground` - Foreground (icon) color. Used as fallback for state foreground colors. Auto-derived from background. +/// - `$border-color` - Border color. Auto-derives: focus-border-color. +/// +/// Setting background automatically calculates a contrasting foreground color and derives all state backgrounds with their contrasting foreground colors. Derivation behavior varies by design variant (material, fluent, bootstrap, indigo). +/// /// @param {Map} $schema [$light-material-schema] - The schema map or icon-button schema to use. -/// @param {Color} $background [null] - Background color for the contained icon button. -/// @param {Color} $foreground [null] - Foreground (icon) color. -/// @param {Color} $shadow-color [null] - Shadow color for the icon button. -/// @param {Color} $hover-background [null] - Background color on hover. -/// @param {Color} $hover-foreground [null] - Foreground color on hover. -/// @param {Color} $focus-background [null] - Background color on focus. -/// @param {Color} $focus-foreground [null] - Foreground color on focus. -/// @param {Color} $focus-hover-background [null] - Background color on focus + hover. -/// @param {Color} $focus-hover-foreground [null] - Foreground color on focus + hover. -/// @param {Color} $active-background [null] - Background color when active. -/// @param {Color} $active-foreground [null] - Foreground color when active. +/// @param {Color} $background [null] - Background color for the contained icon button. PRIMARY - derives foreground, hover-background, focus-background, active-background. +/// @param {Color} $foreground [null] - Foreground (icon) color. Auto-derived from background. +/// @param {Color} $shadow-color [null] - Shadow color. Auto-derived from focus-background. +/// @param {Color} $hover-background [null] - Background color on hover. Auto-derived from background. +/// @param {Color} $hover-foreground [null] - Foreground color on hover. Auto-derived from foreground or hover-background. +/// @param {Color} $focus-background [null] - Background color on focus. Auto-derived from background. +/// @param {Color} $focus-foreground [null] - Foreground color on focus. Auto-derived from foreground or focus-background. +/// @param {Color} $focus-hover-background [null] - Background color on focus + hover. Auto-derived from focus-background. +/// @param {Color} $focus-hover-foreground [null] - Foreground color on focus + hover. Auto-derived from foreground or focus-hover-background. +/// @param {Color} $active-background [null] - Background color when active. Auto-derived from background. +/// @param {Color} $active-foreground [null] - Foreground color when active. Auto-derived from foreground or active-background. /// @param {Length} $border-radius [null] - Border radius for the icon button. -/// @param {Color} $border-color [null] - Border color. -/// @param {Color} $focus-border-color [null] - Border color on focus. -/// @param {Color} $disabled-background [null] - Background color when disabled. -/// @param {Color} $disabled-foreground [null] - Foreground color when disabled. +/// @param {Color} $border-color [null] - Border color. PRIMARY - derives focus-border-color. +/// @param {Color} $focus-border-color [null] - Border color on focus. Auto-derived from foreground or border-color. +/// @param {Color} $disabled-background [null] - Background color when disabled. Auto-derived from background (bootstrap/indigo). +/// @param {Color} $disabled-foreground [null] - Foreground color when disabled. Auto-derived from foreground or disabled-background. /// @param {Color} $disabled-border-color [null] - Border color when disabled. /// @param {Length} $size [null] - Size of the icon button. /// @requires $light-material-schema diff --git a/sass/themes/components/icon-button/_flat-icon-button-theme.scss b/sass/themes/components/icon-button/_flat-icon-button-theme.scss index d182aefc..d9b0ea89 100644 --- a/sass/themes/components/icon-button/_flat-icon-button-theme.scss +++ b/sass/themes/components/icon-button/_flat-icon-button-theme.scss @@ -13,24 +13,33 @@ /// @author Silvia Ivanova //// -/// Generates a theme map for the flat variant of the icon button component. +/// Flat Icon Button Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$foreground` - Foreground (icon) color. Auto-derives: hover-background, focus-background, active-background, hover-foreground, focus-foreground, active-foreground, disabled-foreground, shadow-color, focus-border-color (variant-dependent). +/// - `$hover-background` - Background color on hover. Auto-derives: hover-foreground. +/// - `$focus-background` - Background color on focus. Auto-derives: focus-foreground. +/// - `$active-background` - Background color when active. Auto-derives: active-foreground. +/// +/// For flat icon buttons, the foreground color is the primary token. Setting it derives all state backgrounds and their contrasting foreground colors. Derivation behavior varies by design variant (material, fluent, bootstrap, indigo). +/// /// @param {Map} $schema [$light-material-schema] - The schema map or icon-button schema to use. /// @param {Color} $background [null] - Background color for the flat icon button. -/// @param {Color} $foreground [null] - Foreground (icon) color. -/// @param {Color} $shadow-color [null] - Shadow color for the icon button. -/// @param {Color} $hover-background [null] - Background color on hover. -/// @param {Color} $hover-foreground [null] - Foreground color on hover. -/// @param {Color} $focus-background [null] - Background color on focus. -/// @param {Color} $focus-foreground [null] - Foreground color on focus. -/// @param {Color} $focus-hover-background [null] - Background color on focus + hover. -/// @param {Color} $focus-hover-foreground [null] - Foreground color on focus + hover. -/// @param {Color} $active-background [null] - Background color when active. -/// @param {Color} $active-foreground [null] - Foreground color when active. +/// @param {Color} $foreground [null] - Foreground (icon) color. PRIMARY - derives hover/focus/active backgrounds and foregrounds. +/// @param {Color} $shadow-color [null] - Shadow color. Auto-derived from foreground (bootstrap). +/// @param {Color} $hover-background [null] - Background color on hover. PRIMARY - derives hover-foreground. Auto-derived from foreground. +/// @param {Color} $hover-foreground [null] - Foreground color on hover. Auto-derived from hover-background or foreground. +/// @param {Color} $focus-background [null] - Background color on focus. PRIMARY - derives focus-foreground. Auto-derived from foreground. +/// @param {Color} $focus-foreground [null] - Foreground color on focus. Auto-derived from focus-background or foreground. +/// @param {Color} $focus-hover-background [null] - Background color on focus + hover. Auto-derived from foreground or hover-background. +/// @param {Color} $focus-hover-foreground [null] - Foreground color on focus + hover. Auto-derived from focus-hover-background or foreground. +/// @param {Color} $active-background [null] - Background color when active. Auto-derived from foreground. +/// @param {Color} $active-foreground [null] - Foreground color when active. Auto-derived from active-background, foreground, or hover-foreground. /// @param {Length} $border-radius [null] - Border radius for the icon button. /// @param {Color} $border-color [null] - Border color. -/// @param {Color} $focus-border-color [null] - Border color on focus. +/// @param {Color} $focus-border-color [null] - Border color on focus. Auto-derived from foreground (indigo). /// @param {Color} $disabled-background [null] - Background color when disabled. -/// @param {Color} $disabled-foreground [null] - Foreground color when disabled. +/// @param {Color} $disabled-foreground [null] - Foreground color when disabled. Auto-derived from foreground (bootstrap/indigo). /// @param {Color} $disabled-border-color [null] - Border color when disabled. /// @param {Length} $size [null] - Size of the icon button. /// @requires $light-material-schema diff --git a/sass/themes/components/icon-button/_icon-button-theme.scss b/sass/themes/components/icon-button/_icon-button-theme.scss index f171fb4a..cfc91663 100644 --- a/sass/themes/components/icon-button/_icon-button-theme.scss +++ b/sass/themes/components/icon-button/_icon-button-theme.scss @@ -16,17 +16,26 @@ /// @author Silvia Ivanova //// -/// Generates a theme map for the icon button component. +/// Icon Button Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` - Background color for the icon button. Auto-derives: foreground. +/// - `$hover-background` - Background color on hover. Auto-derives: hover-foreground. +/// - `$focus-background` - Background color on focus. Auto-derives: focus-foreground. +/// - `$focus-hover-background` - Background color on focus + hover. Auto-derives: focus-hover-foreground. +/// +/// Setting any background token automatically calculates a contrasting foreground color for that state. +/// /// @param {Map} $schema [$light-material-schema] - The schema map or icon-button schema to use. -/// @param {Color} $background [null] - Background color for the icon button. -/// @param {Color} $foreground [null] - Foreground (icon) color. +/// @param {Color} $background [null] - Background color for the icon button. PRIMARY - derives foreground. +/// @param {Color} $foreground [null] - Foreground (icon) color. Auto-derived from background. /// @param {Color} $shadow-color [null] - Shadow color for the icon button. -/// @param {Color} $hover-background [null] - Background color on hover. -/// @param {Color} $hover-foreground [null] - Foreground color on hover. -/// @param {Color} $focus-background [null] - Background color on focus. -/// @param {Color} $focus-foreground [null] - Foreground color on focus. -/// @param {Color} $focus-hover-background [null] - Background color on focus + hover. -/// @param {Color} $focus-hover-foreground [null] - Foreground color on focus + hover. +/// @param {Color} $hover-background [null] - Background color on hover. PRIMARY - derives hover-foreground. +/// @param {Color} $hover-foreground [null] - Foreground color on hover. Auto-derived from hover-background. +/// @param {Color} $focus-background [null] - Background color on focus. PRIMARY - derives focus-foreground. +/// @param {Color} $focus-foreground [null] - Foreground color on focus. Auto-derived from focus-background. +/// @param {Color} $focus-hover-background [null] - Background color on focus + hover. PRIMARY - derives focus-hover-foreground. +/// @param {Color} $focus-hover-foreground [null] - Foreground color on focus + hover. Auto-derived from focus-hover-background. /// @param {Color} $active-background [null] - Background color when active. /// @param {Color} $active-foreground [null] - Foreground color when active. /// @param {Length} $border-radius [null] - Border radius for the icon button. diff --git a/sass/themes/components/icon-button/_outlined-icon-button-theme.scss b/sass/themes/components/icon-button/_outlined-icon-button-theme.scss index a012cd20..fbd525f3 100644 --- a/sass/themes/components/icon-button/_outlined-icon-button-theme.scss +++ b/sass/themes/components/icon-button/_outlined-icon-button-theme.scss @@ -13,25 +13,34 @@ /// @author Silvia Ivanova //// -/// Generates a theme map for the outlined variant of the icon button component. +/// Outlined Icon Button Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$foreground` - Foreground (icon) color. Auto-derives: hover-background, focus-background, active-background, hover-foreground, focus-foreground, active-foreground, border-color, focus-border-color, disabled-foreground (variant-dependent). +/// - `$hover-background` - Background color on hover. Auto-derives: hover-foreground. +/// - `$focus-background` - Background color on focus. Auto-derives: focus-foreground, shadow-color. +/// - `$active-background` - Background color when active. Auto-derives: active-foreground, focus-border-color. +/// +/// For outlined icon buttons, the foreground color is the primary token. Setting it derives all state backgrounds, their contrasting foreground colors, and matching border colors. Derivation behavior varies by design variant (material, fluent, bootstrap, indigo). +/// /// @param {Map} $schema [$light-material-schema] - The schema map or icon-button schema to use. /// @param {Color} $background [null] - Background color for the outlined icon button. -/// @param {Color} $foreground [null] - Foreground (icon) color. -/// @param {Color} $shadow-color [null] - Shadow color for the icon button. -/// @param {Color} $hover-background [null] - Background color on hover. -/// @param {Color} $hover-foreground [null] - Foreground color on hover. -/// @param {Color} $focus-background [null] - Background color on focus. -/// @param {Color} $focus-foreground [null] - Foreground color on focus. -/// @param {Color} $focus-hover-background [null] - Background color on focus + hover. -/// @param {Color} $focus-hover-foreground [null] - Foreground color on focus + hover. -/// @param {Color} $active-background [null] - Background color when active. -/// @param {Color} $active-foreground [null] - Foreground color when active. +/// @param {Color} $foreground [null] - Foreground (icon) color. PRIMARY - derives hover/focus/active backgrounds, foregrounds, and borders. +/// @param {Color} $shadow-color [null] - Shadow color. Auto-derived from focus-background (bootstrap). +/// @param {Color} $hover-background [null] - Background color on hover. PRIMARY - derives hover-foreground. Auto-derived from foreground. +/// @param {Color} $hover-foreground [null] - Foreground color on hover. Auto-derived from hover-background or foreground. +/// @param {Color} $focus-background [null] - Background color on focus. PRIMARY - derives focus-foreground. Auto-derived from foreground. +/// @param {Color} $focus-foreground [null] - Foreground color on focus. Auto-derived from focus-background or foreground. +/// @param {Color} $focus-hover-background [null] - Background color on focus + hover. Auto-derived from foreground or focus-background. +/// @param {Color} $focus-hover-foreground [null] - Foreground color on focus + hover. Auto-derived from focus-hover-background or foreground. +/// @param {Color} $active-background [null] - Background color when active. Auto-derived from foreground. +/// @param {Color} $active-foreground [null] - Foreground color when active. Auto-derived from active-background or hover-foreground. /// @param {Length} $border-radius [null] - Border radius for the icon button. -/// @param {Color} $border-color [null] - Border color. -/// @param {Color} $focus-border-color [null] - Border color on focus. +/// @param {Color} $border-color [null] - Border color. Auto-derived from foreground. +/// @param {Color} $focus-border-color [null] - Border color on focus. Auto-derived from foreground or active-background. /// @param {Color} $disabled-background [null] - Background color when disabled. -/// @param {Color} $disabled-foreground [null] - Foreground color when disabled. -/// @param {Color} $disabled-border-color [null] - Border color when disabled. +/// @param {Color} $disabled-foreground [null] - Foreground color when disabled. Auto-derived from foreground (bootstrap/indigo). +/// @param {Color} $disabled-border-color [null] - Border color when disabled. Auto-derived from border-color (bootstrap/indigo). /// @param {Length} $size [null] - Size of the icon button. /// @requires $light-material-schema /// @return {Map} - A map containing the theme name, selector, and theme values for the outlined icon button. diff --git a/sass/themes/components/icon/_icon-theme.scss b/sass/themes/components/icon/_icon-theme.scss index 3d6f0fed..a8b9b616 100644 --- a/sass/themes/components/icon/_icon-theme.scss +++ b/sass/themes/components/icon/_icon-theme.scss @@ -14,6 +14,10 @@ /// @author Marin Popov //// +/// Icon Theme +/// +/// This theme has no automatic token derivation. All tokens are independent. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {Color} $color [null] - The icon color. /// @param {String} $size [null] - The icon size. diff --git a/sass/themes/components/input/_file-input-theme.scss b/sass/themes/components/input/_file-input-theme.scss index 5cf117e7..e2f94d32 100644 --- a/sass/themes/components/input/_file-input-theme.scss +++ b/sass/themes/components/input/_file-input-theme.scss @@ -12,23 +12,33 @@ /// @access public //// +/// File Input Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$file-names-background` - The file names container background color. Auto-derives: file-names-background--focused, file-names-background--filled, file-names-background--disabled, file-names-foreground, file-names-foreground--focused, file-names-foreground--filled, file-names-foreground--disabled. +/// - `$file-selector-button-background` - The file input selector button background color. Auto-derives: file-selector-button-background--focused, file-selector-button-background--filled, file-selector-button-background--disabled, file-selector-button-foreground, file-selector-button-foreground--focused, file-selector-button-foreground--filled, file-selector-button-foreground--disabled. +/// +/// Setting file-names-background automatically calculates contrasting foreground colors for all states. +/// Setting file-selector-button-background automatically calculates contrasting button foreground colors for all states. +/// NOTE: Derivation only occurs if the background is not `transparent`. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $file-names-background [null] - The file names container background color. -/// @param {Color} $file-names-background--focused [null] - The file names container background color when the file input is focused. -/// @param {Color} $file-names-background--filled [null] - The file names container background color when the file input is filled. -/// @param {Color} $file-names-background--disabled [null] - The file names container background color when the file input is disabled. -/// @param {Color} $file-names-foreground [null] - The file names color. -/// @param {Color} $file-names-foreground--focused [null] - The file names color when the file input is focused. -/// @param {Color} $file-names-foreground--filled [null] - The file names color when the file input is filled. -/// @param {Color} $file-names-foreground--disabled [null] - The file names color when the file input is disabled. -/// @param {Color} $file-selector-button-background [null] - The file input selector button background color. -/// @param {Color} $file-selector-button-background--focused [null] - The selector button background color when the file input is focused. -/// @param {Color} $file-selector-button-background--filled [null] - The selector button background color when the file input is filled. -/// @param {Color} $file-selector-button-background--disabled [null] - The selector button background color when the file input is disabled. -/// @param {Color} $file-selector-button-foreground [null] - The file input selector button foreground color. -/// @param {Color} $file-selector-button-foreground--focused [null] - The selector button foreground color when the file input is focused. -/// @param {Color} $file-selector-button-foreground--filled [null] - The selector button foreground color when the file input is filled. -/// @param {Color} $file-selector-button-foreground--disabled [null] - The selector button foreground color when the file input is disabled. +/// @param {Color} $file-names-background [null] - The file names container background color. PRIMARY - derives all file-names foreground colors. +/// @param {Color} $file-names-background--focused [null] - The file names container background color when focused. Auto-derived from file-names-background. +/// @param {Color} $file-names-background--filled [null] - The file names container background color when filled. Auto-derived from file-names-background. +/// @param {Color} $file-names-background--disabled [null] - The file names container background color when disabled. Auto-derived from file-names-background. +/// @param {Color} $file-names-foreground [null] - The file names color. Auto-derived from file-names-background. +/// @param {Color} $file-names-foreground--focused [null] - The file names color when focused. Auto-derived from file-names-background--focused. +/// @param {Color} $file-names-foreground--filled [null] - The file names color when filled. Auto-derived from file-names-background--filled. +/// @param {Color} $file-names-foreground--disabled [null] - The file names color when disabled. Auto-derived from file-names-background--disabled. +/// @param {Color} $file-selector-button-background [null] - The selector button background color. PRIMARY - derives all selector button foreground colors. +/// @param {Color} $file-selector-button-background--focused [null] - The selector button background color when focused. Auto-derived from file-selector-button-background. +/// @param {Color} $file-selector-button-background--filled [null] - The selector button background color when filled. Auto-derived from file-selector-button-background. +/// @param {Color} $file-selector-button-background--disabled [null] - The selector button background color when disabled. Auto-derived from file-selector-button-background. +/// @param {Color} $file-selector-button-foreground [null] - The selector button foreground color. Auto-derived from file-selector-button-background. +/// @param {Color} $file-selector-button-foreground--focused [null] - The selector button foreground color when focused. Auto-derived from file-selector-button-background--focused. +/// @param {Color} $file-selector-button-foreground--filled [null] - The selector button foreground color when filled. Auto-derived from file-selector-button-background--filled. +/// @param {Color} $file-selector-button-foreground--disabled [null] - The selector button foreground color when disabled. Auto-derived from file-selector-button-background--disabled. /// @example scss Change the focused border and label colors /// $my-file-input-theme: file-input-theme($file-names-foreground: #09f); /// // Pass the theme to the css-vars() mixin diff --git a/sass/themes/components/input/_input-theme.scss b/sass/themes/components/input/_input-theme.scss index ed06e2e5..fb3d4702 100644 --- a/sass/themes/components/input/_input-theme.scss +++ b/sass/themes/components/input/_input-theme.scss @@ -13,45 +13,58 @@ /// @author Simeon Simeonoff //// +/// Input Group Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$box-background` - Box type input background. Auto-derives: text colors, prefix/suffix colors, placeholder colors, disabled background. +/// - `$search-background` - Search type input background. Auto-derives: text colors, prefix/suffix colors, placeholder colors, disabled background. +/// - `$border-color` - Border color for border/fluent types. Auto-derives: hover-border-color, focused-border-color, focused-secondary-color. +/// - `$idle-bottom-line-color` - Bottom line color (material). Auto-derives: hover/focused bottom line colors, focused-secondary-color. +/// - `$focused-border-color` - Focused state accent color. Auto-derives: focused-secondary-color. +/// +/// For Material variant, set `$box-background` for box type inputs. +/// For all variants, set `$search-background` for search type inputs. +/// Text colors are automatically calculated for accessibility. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $idle-text-color [null] - The input text color in the idle state. -/// @param {Color} $filled-text-color [null] - The input text color in the filled state. +/// @param {Color} $idle-text-color [null] - The input text color in the idle state. Auto-derived from box/search-background. +/// @param {Color} $filled-text-color [null] - The input text color in the filled state. Auto-derived from box/search-background. /// @param {Color} $filled-text-hover-color [null] - The input text color in the filled state on hover. -/// @param {Color} $focused-text-color [null] - The input text color in the focused state. -/// @param {Color} $disabled-text-color [null] - The input text color in the disabled state. +/// @param {Color} $focused-text-color [null] - The input text color in the focused state. Auto-derived from box-background-focus or search-background. +/// @param {Color} $disabled-text-color [null] - The input text color in the disabled state. Auto-derived from disabled background. /// @param {Color} $helper-text-color [null] - The helper text color. /// @param {Color} $text-error-color [null] - The color used for the error message. /// @param {Color} $icon-error-color [null] - The color used for the error icon. -/// @param {Color} $input-prefix-color [null] - The input prefix color in the idle state. -/// @param {Color} $input-prefix-background [null] - The background color of an input prefix in the idle state. -/// @param {Color} $input-prefix-color--filled [null] - The input prefix color in the filled state. +/// @param {Color} $input-prefix-color [null] - The input prefix color in the idle state. Auto-derived from box/search-background. +/// @param {Color} $input-prefix-background [null] - The background color of an input prefix in the idle state. Synced with suffix-background. +/// @param {Color} $input-prefix-color--filled [null] - The input prefix color in the filled state. Auto-derived from prefix-color or background. /// @param {Color} $input-prefix-background--filled] - The background color of an input prefix in the filled state. -/// @param {Color} $input-prefix-color--focused [null] - The input prefix color in the focused state. +/// @param {Color} $input-prefix-color--focused [null] - The input prefix color in the focused state. Auto-derived from prefix-color--filled or background. /// @param {Color} $input-prefix-background--focused [null] - The background color of an input prefix in the focused state. -/// @param {Color} $input-suffix-color [null] - The input suffix color in the idle state. -/// @param {Color} $input-suffix-background [null] - The background color of an input suffix in the idle state. +/// @param {Color} $input-suffix-color [null] - The input suffix color in the idle state. Auto-derived from box/search-background. Synced with prefix-color. +/// @param {Color} $input-suffix-background [null] - The background color of an input suffix in the idle state. Synced with prefix-background. /// @param {Color} $input-suffix-color--filled [null] - The input suffix color in the filled state. /// @param {Color} $input-suffix-background-filled [null] - The background color of an input suffix in the filled state. /// @param {Color} $input-suffix-color--focused [null] - The input suffix color in the focused state. /// @param {Color} $input-suffix-background--focused [null] - The background color of an input suffix in the focused state. -/// @param {Color} $idle-secondary-color [null] - The label color in the idle state. -/// @param {Color} $focused-secondary-color [null] - The label color in the focused state. -/// @param {Color} $idle-bottom-line-color [null] - The bottom line and border colors in the idle state. -/// @param {Color} $hover-bottom-line-color [null] - The bottom line and border colors in the hover state. -/// @param {Color} $focused-bottom-line-color [null] - The bottom line and border colors in the focused state. +/// @param {Color} $idle-secondary-color [null] - The label color in the idle state. Auto-derived from box-background or placeholder-color. +/// @param {Color} $focused-secondary-color [null] - The label color in the focused state. Auto-derived from focused-bottom-line-color or focused-border-color. +/// @param {Color} $idle-bottom-line-color [null] - The bottom line and border colors in the idle state. PRIMARY for material bottom line. +/// @param {Color} $hover-bottom-line-color [null] - The bottom line and border colors in the hover state. Auto-derived from idle-bottom-line-color. +/// @param {Color} $focused-bottom-line-color [null] - The bottom line and border colors in the focused state. Auto-derived from hover-bottom-line-color. /// @param {Color} $disabled-bottom-line-color [null] - The bottom line and border colors in the disabled state. -/// @param {Color} $border-color [null] - The border color for input groups of type border and fluent. -/// @param {Color} $hover-border-color [null] - The hover input border for input groups of type border and fluent. -/// @param {Color} $focused-border-color [null] - The focused input border color for input groups of type border and fluent. +/// @param {Color} $border-color [null] - The border color for input groups of type border and fluent. PRIMARY for border inputs. +/// @param {Color} $hover-border-color [null] - The hover input border for input groups of type border and fluent. Auto-derived from border-color. +/// @param {Color} $focused-border-color [null] - The focused input border color for input groups of type border and fluent. Auto-derived from hover-border-color. /// @param {Color} $disabled-border-color [null] - The disabled border color for input groups of type border and fluent. -/// @param {Color} $box-background [null] - The background color of an input group of type box. -/// @param {Color} $box-background-hover [null] - The background color on hover of an input group of type box. -/// @param {Color} $box-background-focus [null] - The background color on focus of an input group of type box. -/// @param {Color} $box-disabled-background [null] - The background color of an input group of type box in the disabled state. +/// @param {Color} $box-background [null] - The background color of an input group of type box. PRIMARY for material box inputs. +/// @param {Color} $box-background-hover [null] - The background color on hover of an input group of type box. Auto-derived from box-background. +/// @param {Color} $box-background-focus [null] - The background color on focus of an input group of type box. Auto-derived from box-background. +/// @param {Color} $box-disabled-background [null] - The background color of an input group of type box in the disabled state. Auto-derived from box-background. /// @param {Color} $border-background [null] - The background color of an input group of type border. /// @param {Color} $border-disabled-background [null] - The background color of an input group of type border in the disabled state. -/// @param {Color} $search-background [null] - The background color of an input group of type search. -/// @param {Color} $search-disabled-background [null] - The background color of an input group of type search in the disabled state. +/// @param {Color} $search-background [null] - The background color of an input group of type search. PRIMARY for search inputs. +/// @param {Color} $search-disabled-background [null] - The background color of an input group of type search in the disabled state. Auto-derived from search-background. /// @param {box-shadow} $search-resting-shadow [null] - The shadow color of an input group of type search in its resting state. /// @param {box-shadow} $search-hover-shadow [null] - The shadow color of an input group of type search in its hover state. /// @param {box-shadow} $search-disabled-shadow [null] - The shadow color of an input group of type search in its disabled state. @@ -61,9 +74,9 @@ /// @param {List} $box-border-radius [null] - The border radius used for box input. /// @param {List} $border-border-radius [null] - The border radius used for border input. /// @param {List} $search-border-radius [null] - The border radius used for search input. -/// @param {Color} placeholder-color [null] - The placeholder color of an input group. -/// @param {Color} hover-placeholder-color [null] - The placeholder color of an input group on hover. -/// @param {Color} disabled-placeholder-color [null] - The disabled placeholder color of an input group. +/// @param {Color} placeholder-color [null] - The placeholder color of an input group. Auto-derived from box/search-background. +/// @param {Color} hover-placeholder-color [null] - The placeholder color of an input group on hover. Auto-derived from box-background-hover or placeholder-color. +/// @param {Color} disabled-placeholder-color [null] - The disabled placeholder color of an input group. Auto-derived from disabled background. /// @example scss Change the focused border and label colors /// $my-input-group-theme: input-group-theme($focused-secondary-color: pink, $focused-bottom-line-color: pink); /// // Pass the theme to the css-vars() mixin diff --git a/sass/themes/components/label/_label-theme.scss b/sass/themes/components/label/_label-theme.scss index 8a9d60e9..9e9b7003 100644 --- a/sass/themes/components/label/_label-theme.scss +++ b/sass/themes/components/label/_label-theme.scss @@ -13,6 +13,10 @@ /// @author Simeon Simeonoff //// +/// Label Theme +/// +/// This theme has no automatic token derivation. All tokens are independent. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {Map} $color [null] - The text color. /// @param {Map} $disabled-color [null] - The disabled text color. diff --git a/sass/themes/components/list/_list-theme.scss b/sass/themes/components/list/_list-theme.scss index 72bdb971..492d8c16 100644 --- a/sass/themes/components/list/_list-theme.scss +++ b/sass/themes/components/list/_list-theme.scss @@ -14,38 +14,48 @@ /// @author Marin Popov //// +/// List Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` or `$item-background` - The list/item background. Auto-derives: header-background, item-background-hover, item-background-active, item-background-selected, all text/action/thumbnail colors. +/// +/// Setting background or item-background cascades through all item states (hover, active, selected). +/// Each state derives its own text colors, title, subtitle, action, and thumbnail colors. +/// Subtitle colors are slightly muted (0.74 opacity) compared to main text colors. +/// Border color auto-derived in fluent/bootstrap variants. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $background [null] - The list background color. -/// @param {Color} $header-background [null] - The list header background color. -/// @param {Color} $header-text-color [null] - The list header text color. -/// @param {Color} $item-background [null] - The list item background color. -/// @param {Color} $item-background-hover [null] - The list item hover background color. -/// @param {Color} $item-background-active [null] - The active list item background color. -/// @param {Color} $item-background-selected [null] - The selected list item background color. -/// @param {Color} $item-text-color [null] - The list item text color. -/// @param {Color} $item-text-color-hover [null] - The list item hover text color. -/// @param {Color} $item-text-color-active [null] - The active list item text color. -/// @param {Color} $item-text-color-selected [null] - The selected list item text color. -/// @param {Color} $item-title-color [null] - The list item title color. -/// @param {Color} $item-title-color-hover [null] - The list item hover title color. -/// @param {Color} $item-title-color-active [null] - The active list item title color. -/// @param {Color} $item-title-color-selected [null] - The selected list item title color. -/// @param {Color} $item-subtitle-color [null] - The list item subtitle color. -/// @param {Color} $item-subtitle-color-hover [null] - The list item hover subtitle color. -/// @param {Color} $item-subtitle-color-active [null] - The active list item subtitle color. -/// @param {Color} $item-subtitle-color-selected [null] - The selected list item subtitle color. -/// @param {Color} $item-action-color [null] - The list item action color. -/// @param {Color} $item-action-color-hover [null] - The list item hover action color. -/// @param {Color} $item-action-color-active [null] - The active list item action color. -/// @param {Color} $item-action-color-selected [null] - The selected list item action color. -/// @param {Color} $item-thumbnail-color [null] - The list item thumbnail color. -/// @param {Color} $item-thumbnail-color-hover [null] - The list item hover thumbnail color. -/// @param {Color} $item-thumbnail-color-active [null] - The active list item thumbnail color. -/// @param {Color} $item-thumbnail-color-selected [null] - The selected list item thumbnail color. +/// @param {Color} $background [null] - The list background color. PRIMARY - derives item-background if not set. +/// @param {Color} $header-background [null] - The list header background color. Auto-derived from background or item-background. +/// @param {Color} $header-text-color [null] - The list header text color. Auto-derived from header-background. +/// @param {Color} $item-background [null] - The list item background color. PRIMARY - derives all item state colors. +/// @param {Color} $item-background-hover [null] - The list item hover background color. Auto-derived from item-background. +/// @param {Color} $item-background-active [null] - The active list item background color. Auto-derived from item-background-hover. +/// @param {Color} $item-background-selected [null] - The selected list item background color. Auto-derived from item-background-active. +/// @param {Color} $item-text-color [null] - The list item text color. Auto-derived from item-background. +/// @param {Color} $item-text-color-hover [null] - The list item hover text color. Auto-derived from item-background-hover. +/// @param {Color} $item-text-color-active [null] - The active list item text color. Auto-derived from item-background-active. +/// @param {Color} $item-text-color-selected [null] - The selected list item text color. Auto-derived from item-background-selected. +/// @param {Color} $item-title-color [null] - The list item title color. Auto-derived from item-text-color. +/// @param {Color} $item-title-color-hover [null] - The list item hover title color. Auto-derived from item-text-color-hover. +/// @param {Color} $item-title-color-active [null] - The active list item title color. Auto-derived from item-text-color-active. +/// @param {Color} $item-title-color-selected [null] - The selected list item title color. Auto-derived from item-text-color-selected. +/// @param {Color} $item-subtitle-color [null] - The list item subtitle color. Auto-derived from item-text-color (muted). +/// @param {Color} $item-subtitle-color-hover [null] - The list item hover subtitle color. Auto-derived from item-text-color-hover (muted). +/// @param {Color} $item-subtitle-color-active [null] - The active list item subtitle color. Auto-derived from item-text-color-active (muted). +/// @param {Color} $item-subtitle-color-selected [null] - The selected list item subtitle color. Auto-derived from item-text-color-selected (muted). +/// @param {Color} $item-action-color [null] - The list item action color. Auto-derived from item-text-color. +/// @param {Color} $item-action-color-hover [null] - The list item hover action color. Auto-derived from item-text-color-hover. +/// @param {Color} $item-action-color-active [null] - The active list item action color. Auto-derived from item-text-color-active. +/// @param {Color} $item-action-color-selected [null] - The selected list item action color. Auto-derived from item-text-color-selected. +/// @param {Color} $item-thumbnail-color [null] - The list item thumbnail color. Auto-derived from item-text-color. +/// @param {Color} $item-thumbnail-color-hover [null] - The list item hover thumbnail color. Auto-derived from item-text-color-hover. +/// @param {Color} $item-thumbnail-color-active [null] - The active list item thumbnail color. Auto-derived from item-text-color-active. +/// @param {Color} $item-thumbnail-color-selected [null] - The selected list item thumbnail color. Auto-derived from item-text-color-selected. /// @param {List} $border-radius [null] - The border radius used for list component. /// @param {List} $item-border-radius [null] - The border radius used for list item. /// @param {Color} $border-width [null] - The list border width. -/// @param {Number} $border-color [null] - The list border color. +/// @param {Number} $border-color [null] - The list border color. Auto-derived from item-background (fluent/bootstrap). /// @requires $light-material-schema /// @example scss Change the list background color /// $my-list-theme: list-theme($background: black); diff --git a/sass/themes/components/navbar/_navbar-theme.scss b/sass/themes/components/navbar/_navbar-theme.scss index ee575855..82630338 100644 --- a/sass/themes/components/navbar/_navbar-theme.scss +++ b/sass/themes/components/navbar/_navbar-theme.scss @@ -14,13 +14,20 @@ /// @author Marin Popov //// +/// Navbar Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` - The navbar background color. Auto-derives: text-color, idle-icon-color, hover-icon-color, border-color (indigo). +/// +/// Setting just `$background` will create a complete navbar theme with proper contrast. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $background [null] - The navbar background color. -/// @param {Color} $text-color [null] - The navbar text color. -/// @param {Color} $border-color [null] - The navbar border color. +/// @param {Color} $background [null] - The navbar background color. PRIMARY - derives text-color and icon colors. +/// @param {Color} $text-color [null] - The navbar text color. Auto-derived from background. +/// @param {Color} $border-color [null] - The navbar border color. Auto-derived from background (indigo). /// @param {box-shadow} $shadow [null] - The shadow of the navbar. -/// @param {Color} $idle-icon-color [null] - The navbar idle icon color. -/// @param {Color} $hover-icon-color [null] - The navbar hover icon color. +/// @param {Color} $idle-icon-color [null] - The navbar idle icon color. Auto-derived from background. +/// @param {Color} $hover-icon-color [null] - The navbar hover icon color. Auto-derived from idle-icon-color or background. /// @param {Bool} $disable-shadow [true] - Sets the navbar shadow visibility. /// @requires $light-material-schema /// @example scss Change the background color diff --git a/sass/themes/components/navdrawer/_navdrawer-theme.scss b/sass/themes/components/navdrawer/_navdrawer-theme.scss index b0d70714..dcab5b3d 100644 --- a/sass/themes/components/navdrawer/_navdrawer-theme.scss +++ b/sass/themes/components/navdrawer/_navdrawer-theme.scss @@ -14,21 +14,29 @@ /// @author Marin Popov //// -/// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. +/// Navigation Drawer Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` - The drawer background color. Auto-derives: all item text/icon colors, item-hover-background, item-active-background, disabled colors. +/// - `$item-active-background` - The active item background. Auto-derives: item-active-text-color, item-active-icon-color. /// -/// @param {Color} $background [null] - The navigation drawer background color. +/// Setting background cascades through all item states (idle, hover, active, disabled). +/// The active state colors can be independently controlled via item-active-background. +/// +/// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. +/// @param {Color} $background [null] - The navigation drawer background color. PRIMARY - derives all item colors. /// @param {Color} $border-color [null] - The navigation drawer right border color. -/// @param {Color} $item-header-text-color [null] - The header's idle text color. -/// @param {Color} $item-text-color [null] - The item's idle text color. -/// @param {Color} $item-icon-color [null] - The item's icon color. -/// @param {Color} $item-active-text-color [null] - The item's active text color. -/// @param {Color} $item-active-background [null] - The item's active background color. -/// @param {Color} $item-active-icon-color [null] - The item's icon active color. -/// @param {Color} $item-hover-background [null] - The item's hover background color. -/// @param {Color} $item-hover-text-color [null] - The item's hover text color. -/// @param {Color} $item-hover-icon-color [null] - The item's hover icon color. -/// @param {Color} $item-disabled-text-color [null] - The item's disabled text color. -/// @param {Color} $item-disabled-icon-color [null] - The item's disabled icon color. +/// @param {Color} $item-header-text-color [null] - The header's idle text color. Auto-derived from background. +/// @param {Color} $item-text-color [null] - The item's idle text color. Auto-derived from background. +/// @param {Color} $item-icon-color [null] - The item's icon color. Auto-derived from background. +/// @param {Color} $item-active-text-color [null] - The item's active text color. Auto-derived from item-active-background. +/// @param {Color} $item-active-background [null] - The item's active background color. PRIMARY for active state - derives active text/icon. Auto-derived from background. +/// @param {Color} $item-active-icon-color [null] - The item's icon active color. Auto-derived from item-active-background. +/// @param {Color} $item-hover-background [null] - The item's hover background color. Auto-derived from background. +/// @param {Color} $item-hover-text-color [null] - The item's hover text color. Auto-derived from background. +/// @param {Color} $item-hover-icon-color [null] - The item's hover icon color. Auto-derived from background. +/// @param {Color} $item-disabled-text-color [null] - The item's disabled text color. Auto-derived from background (muted). +/// @param {Color} $item-disabled-icon-color [null] - The item's disabled icon color. Auto-derived from background (muted). /// @param {Color} $shadow [null] - Sets a custom shadow to be used by the drawer. /// @param {List} $border-radius [null] - The border radius used for the navdrawer. /// @param {List} $item-border-radius [null] - The border radius used for the navdrawer item. diff --git a/sass/themes/components/overlay/_overlay-theme.scss b/sass/themes/components/overlay/_overlay-theme.scss index 66a7b255..cc5b14f1 100644 --- a/sass/themes/components/overlay/_overlay-theme.scss +++ b/sass/themes/components/overlay/_overlay-theme.scss @@ -14,6 +14,10 @@ /// @author Marin Popov //// +/// Overlay Theme +/// +/// This theme has no automatic token derivation. Only one token: background-color. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {Color} $background-color [null] - The background color used for modal overlays. /// @requires $light-material-schema diff --git a/sass/themes/components/paginator/_paginator-theme.scss b/sass/themes/components/paginator/_paginator-theme.scss index 107dbfe3..4bd23ef4 100644 --- a/sass/themes/components/paginator/_paginator-theme.scss +++ b/sass/themes/components/paginator/_paginator-theme.scss @@ -14,10 +14,16 @@ /// @author Simeon Simeonoff //// -/// Grid Paging Theme +/// Paginator Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background-color` - The paginator background. Auto-derives: text-color. +/// +/// Setting background-color automatically calculates a contrasting text color. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $text-color [currentColor] - The text color. -/// @param {Color} $background-color [rgba(0, 0, 0, .04)] - The background color of the paging panel. +/// @param {Color} $text-color [currentColor] - The text color. Auto-derived from background-color. +/// @param {Color} $background-color [rgba(0, 0, 0, .04)] - The background color of the paging panel. PRIMARY - derives text-color. /// @param {Color} $border-color [rgba(0, 0, 0, .26)] - The border color of the paging panel. /// @requires $light-material-schema /// @example scss Change the stripes color diff --git a/sass/themes/components/progress/_circular-theme.scss b/sass/themes/components/progress/_circular-theme.scss index 58a3e31b..cf21c5a5 100644 --- a/sass/themes/components/progress/_circular-theme.scss +++ b/sass/themes/components/progress/_circular-theme.scss @@ -14,9 +14,14 @@ /// @access public //// +/// Circular Progress Theme +/// +/// This theme has no automatic token derivation. All fill colors are independent. +/// The fill-color-default can accept a single color or a list of two colors for gradient effect. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {Color} $base-circle-color [null] - The base circle fill color. -/// @param {Color | List} $fill-color-default [null] - The progress circle fill color. +/// @param {Color | List} $fill-color-default [null] - The progress circle fill color. Can be a single color or list of two colors for gradient. /// @param {Color} $fill-color-danger [null] - The track danger fill color. /// @param {Color} $fill-color-warning [null] - The track warning fill color. /// @param {Color} $fill-color-info [null] - The track info fill color. diff --git a/sass/themes/components/progress/_linear-theme.scss b/sass/themes/components/progress/_linear-theme.scss index 1ed326ec..3e418c42 100644 --- a/sass/themes/components/progress/_linear-theme.scss +++ b/sass/themes/components/progress/_linear-theme.scss @@ -12,6 +12,11 @@ /// @access public //// +/// Linear Progress Theme +/// +/// This theme has no automatic token derivation. All tokens are independent. +/// Use the semantic fill colors (danger, warning, info, success) for status-based progress indicators. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {Color} $track-color [null] - The main track color. /// @param {Color} $fill-color-default [null] - The track default fill color. diff --git a/sass/themes/components/query-builder/_query-builder-theme.scss b/sass/themes/components/query-builder/_query-builder-theme.scss index 5157d704..1c4b0c0d 100644 --- a/sass/themes/components/query-builder/_query-builder-theme.scss +++ b/sass/themes/components/query-builder/_query-builder-theme.scss @@ -12,23 +12,32 @@ /// @access public //// +/// Query Builder Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` - The background color. Auto-derives: label-foreground, header-background. +/// - `$header-background` - The header background color. Auto-derives: header-foreground, subquery-header-background. +/// - `$subquery-header-background` - The subquery header background. Auto-derives: subquery-border-color. +/// - `$subquery-border-color` - The subquery border color. Auto-derives: separator-color, header-border (bootstrap). +/// +/// Setting background starts a derivation chain: background → header-background → subquery-header-background → subquery-border-color → separator-color. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} background [null] - The background color of the filtering row. -/// @param {Color} header-background [null] - The background color of the query builder header. -/// @param {Color} header-foreground [null] - The foreground color of the query builder header. -/// @param {Color} header-border [null] - The border color of the query builder header. +/// @param {Color} $background [null] - The background color of the filtering row. PRIMARY - derives label-foreground, header-background. +/// @param {Color} $header-background [null] - The background color of the query builder header. PRIMARY - derives header-foreground, subquery-header-background. Auto-derived from background. +/// @param {Color} $header-foreground [null] - The foreground color of the query builder header. Auto-derived from header-background. +/// @param {Color} $header-border [null] - The border color of the query builder header. Auto-derived from subquery-border-color (bootstrap only). /// -/// @param {Map} subquery-header-background [null] - The background color of the subquery header. -/// @param {Map} subquery-border-color [null] - The border color of the query block. -/// @param {Map} separator-color [null] - The separator color of the query block. -/// @param {Number} subquery-border-radius [null] - The border radius of the subquery block. +/// @param {Map} $subquery-header-background [null] - The background color of the subquery header. PRIMARY - derives subquery-border-color. Auto-derived from header-background. +/// @param {Map} $subquery-border-color [null] - The border color of the query block. PRIMARY - derives separator-color. Auto-derived from subquery-header-background. +/// @param {Map} $separator-color [null] - The separator color of the query block. Auto-derived from subquery-border-color. +/// @param {Number} $subquery-border-radius [null] - The border radius of the subquery block. /// -/// @param {Map} label-foreground [null] - The color for query builder labels "from" & "select". -/// @param {Map} separator-color [null] - The separator color of the query builder tree block. -/// @param {Number} border-radius [null] - The border radius of the query builder. +/// @param {Map} $label-foreground [null] - The color for query builder labels "from" & "select". Auto-derived from background. +/// @param {Number} $border-radius [null] - The border radius of the query builder. /// -/// @param {Color} color-expression-group-and [null] - The color of advanced filtering "AND" condition group. -/// @param {Color} color-expression-group-or [null] - The color of advanced filtering "OR" condition group. +/// @param {Color} $color-expression-group-and [null] - The color of advanced filtering "AND" condition group. +/// @param {Color} $color-expression-group-or [null] - The color of advanced filtering "OR" condition group. /// /// @example scss Set custom query-builder colors /// $my-query-builder-theme: query-builder-theme($background: red); diff --git a/sass/themes/components/radio/_radio-theme.scss b/sass/themes/components/radio/_radio-theme.scss index 5b024145..b56fd780 100644 --- a/sass/themes/components/radio/_radio-theme.scss +++ b/sass/themes/components/radio/_radio-theme.scss @@ -14,25 +14,34 @@ /// @author Marin Popov //// +/// Radio Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$fill-color` - The checked state border and dot color. Auto-derives: fill-color-hover, fill-hover-border-color, focus colors. +/// - `$empty-color` - The unchecked border color. Auto-derives: hover-color, focus-outline-color (indigo). +/// - `$error-color` - The invalid state color. Auto-derives: error-color-hover, focus-outline-color-error. +/// +/// Setting just `$fill-color` will theme all checked states consistently. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// /// @param {Color} $label-color [null]- The text color used for the label text. -/// @param {Color} $label-color-hover [null]- The text color used for the label text on hover. -/// @param {Color} $empty-color [null] - The unchecked border color. +/// @param {Color} $label-color-hover [null]- The text color used for the label text on hover. Auto-derived from label-color. +/// @param {Color} $empty-color [null] - The unchecked border color. PRIMARY for unchecked states. /// @param {Color} $empty-fill-color [null] - The unchecked radio fill color. -/// @param {Color} $fill-color [null] - The checked border and dot colors. +/// @param {Color} $fill-color [null] - The checked border and dot colors. PRIMARY - derives hover/focus colors. /// @param {Color} $disabled-color [null] - The disabled border and dot colors. /// @param {Color} $disabled-label-color [null] - The disabled label color. /// @param {Color} $disabled-fill-color [null] - The disabled checked border and dot colors. -/// @param {Color} $hover-color [null] - The border and dot colors on hover. -/// @param {Color} $fill-color-hover [null] - The checked dot color on hover. -/// @param {Color} $fill-hover-border-color [null] - The checked border color on hover. -/// @param {Color} $focus-border-color [null] - The focus border color. -/// @param {Color} $focus-outline-color [null] - The focus outlined color. -/// @param {Color} $focus-outline-color-filled [null] - The focus outline color when radio is filled. -/// @param {Color} $error-color [null] - The label, border and dot color in invalid state. -/// @param {Color} $error-color-hover [null] - The label, border and dot color in invalid state on hover. -/// @param {Color} $focus-outline-color-error [null] - The focus outline color in invalid state. +/// @param {Color} $hover-color [null] - The border and dot colors on hover. Auto-derived from empty-color. +/// @param {Color} $fill-color-hover [null] - The checked dot color on hover. Auto-derived from fill-color. +/// @param {Color} $fill-hover-border-color [null] - The checked border color on hover. Auto-derived from fill-color-hover. +/// @param {Color} $focus-border-color [null] - The focus border color. Auto-derived from fill-color (bootstrap). +/// @param {Color} $focus-outline-color [null] - The focus outlined color. Auto-derived from empty-color (indigo) or fill-color (bootstrap). +/// @param {Color} $focus-outline-color-filled [null] - The focus outline color when radio is filled. Auto-derived from fill-color (indigo). +/// @param {Color} $error-color [null] - The label, border and dot color in invalid state. PRIMARY for error states. +/// @param {Color} $error-color-hover [null] - The label, border and dot color in invalid state on hover. Auto-derived from error-color. +/// @param {Color} $focus-outline-color-error [null] - The focus outline color in invalid state. Auto-derived from error-color. /// /// @requires $light-material-schema /// diff --git a/sass/themes/components/rating/_rating-theme.scss b/sass/themes/components/rating/_rating-theme.scss index 4e0c10fd..5b943567 100644 --- a/sass/themes/components/rating/_rating-theme.scss +++ b/sass/themes/components/rating/_rating-theme.scss @@ -14,8 +14,13 @@ /// @author Marin Popov //// -/// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. +/// Rating Theme +/// +/// This theme has no automatic token derivation. All tokens are independent. +/// Use symbol-empty-color and symbol-full-color for text-based symbols. +/// Use symbol-empty-filter and symbol-full-filter for image/SVG-based symbols. /// +/// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {Color} $label-color [null] - sets the color for the label. /// @param {Number} $symbol-size [null] - the size of the symbols. /// @param {Color} $symbol-empty-color [null] - sets the idle color for the symbol when it is a plane text. diff --git a/sass/themes/components/ripple/_ripple-theme.scss b/sass/themes/components/ripple/_ripple-theme.scss index 4df96792..a6d57a6b 100644 --- a/sass/themes/components/ripple/_ripple-theme.scss +++ b/sass/themes/components/ripple/_ripple-theme.scss @@ -13,6 +13,10 @@ /// @author Marin Popov //// +/// Ripple Theme +/// +/// This theme has no automatic token derivation. Only one token: color. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {Color} $color [null] - The color of the ripple. /// @requires $light-material-schema diff --git a/sass/themes/components/scrollbar/_scrollbar-theme.scss b/sass/themes/components/scrollbar/_scrollbar-theme.scss index 4284cd1a..0360b6c6 100644 --- a/sass/themes/components/scrollbar/_scrollbar-theme.scss +++ b/sass/themes/components/scrollbar/_scrollbar-theme.scss @@ -12,7 +12,11 @@ /// @author Simeon Simeonoff //// -/// If only background color is specified, text/icon color will be assigned automatically to a contrasting color. +/// Scrollbar Theme +/// +/// This theme has no automatic token derivation. All tokens are independent. +/// Configure thumb, track, and corner elements separately. +/// /// @param {Color} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {String | Number} $sb-size [null] - The size of the scrollbar. /// @param {String | Number} $sb-thumb-min-height [null] - The min-height of the thumb. diff --git a/sass/themes/components/select/_select-theme.scss b/sass/themes/components/select/_select-theme.scss index e6f05d6a..db868c0c 100644 --- a/sass/themes/components/select/_select-theme.scss +++ b/sass/themes/components/select/_select-theme.scss @@ -14,16 +14,25 @@ /// @author Simeon Simeonoff //// +/// Select Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$toggle-button-background` - The toggle button background. Auto-derives: toggle-button-foreground, toggle-button-background-focus, toggle-button-foreground-focus, toggle-button-foreground-filled. +/// +/// Toggle button colors cascade from toggle-button-background through focus states. +/// Behavior varies by variant (material uses shaded focus background, others use same as base). +/// Bootstrap/indigo variants derive focus foreground from border variant background. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @requires $light-material-schema -/// @param {Color} $toggle-button-background [null] - The select toggle button background color. -/// @param {Color} $toggle-button-background-focus [null] - The select toggle button background color when the select is focused. +/// @param {Color} $toggle-button-background [null] - The select toggle button background color. PRIMARY - derives all toggle button colors. +/// @param {Color} $toggle-button-background-focus [null] - The select toggle button background color when the select is focused. Auto-derived from toggle-button-background (variant-dependent). /// @param {Color} $toggle-button-background-disabled [null] - The select toggle button background color when the select is disabled. -/// @param {Color} $toggle-button-foreground [null] - The select toggle button foreground color. -/// @param {Color} $toggle-button-foreground-focus [null] - The select toggle button foreground color when the select is focused. +/// @param {Color} $toggle-button-foreground [null] - The select toggle button foreground color. Auto-derived from toggle-button-background. +/// @param {Color} $toggle-button-foreground-focus [null] - The select toggle button foreground color when the select is focused. Auto-derived from toggle-button-background-focus (variant-dependent). /// @param {Color} $toggle-button-foreground-disabled [null] - The select toggle button foreground color when the select is disabled. -/// @param {Color} $toggle-button-foreground-filled [null] - The select toggle button foreground color when the select is filled. -/// @param {Color} $toggle-button-background-focus--border [null] - The select toggle button background color when the select is focused in material border variant. +/// @param {Color} $toggle-button-foreground-filled [null] - The select toggle button foreground color when the select is filled. Auto-derived from toggle-button-background. +/// @param {Color} $toggle-button-background-focus--border [null] - The select toggle button background color when the select is focused in material border variant. Auto-derived from toggle-button-background (bootstrap/indigo). /// @example scss Change the select empty list background /// $my-select-theme: igx-select-theme($empty-list-background); /// // Pass the theme to the css-vars mixin diff --git a/sass/themes/components/slider/_slider-theme.scss b/sass/themes/components/slider/_slider-theme.scss index 2ae3934c..5d2b1f0f 100644 --- a/sass/themes/components/slider/_slider-theme.scss +++ b/sass/themes/components/slider/_slider-theme.scss @@ -14,24 +14,36 @@ /// @author Marin Popov //// +/// Slider Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$track-color` - The filled track color. Auto-derives: track-hover-color, label-background-color, thumb-color (material), thumb-border-color (fluent/indigo), disabled-fill-track-color. +/// - `$base-track-color` - The unfilled track background. Auto-derives: base-track-hover-color, track-step-color, disabled-base-track-color. +/// - `$thumb-color` - The thumb color (material). Auto-derives: label-background-color (bootstrap), thumb-border-color (bootstrap), disabled-thumb-color. +/// +/// The relationship between track and thumb varies by design variant: +/// - Material: track-color and thumb-color are bidirectional (set either one) +/// - Fluent/Indigo: track-color derives thumb-border-color +/// - Bootstrap: thumb-color derives thumb-border-color and label-background-color +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $track-color [null] - The color of the track. -/// @param {Color} $track-step-color [null] - The color of the track steps. +/// @param {Color} $track-color [null] - The color of the track. PRIMARY - derives hover, label, and thumb colors. +/// @param {Color} $track-step-color [null] - The color of the track steps. Auto-derived from base-track-color. /// @param {Number} $track-step-size [null] - The size of the track steps. -/// @param {Color} $track-hover-color [null] - The color of the track on hover. -/// @param {Color} $thumb-color [null] - The color of the thumb. -/// @param {Color} $thumb-focus-color [null] - The focus color of the thumb. -/// @param {Color} $thumb-border-color [null] - The thumb border color. -/// @param {Color} $thumb-border-hover-color [null] - The thumb border color when hovered. +/// @param {Color} $track-hover-color [null] - The color of the track on hover. Auto-derived from track-color. +/// @param {Color} $thumb-color [null] - The color of the thumb. Auto-derived from track-color (material) or set independently. +/// @param {Color} $thumb-focus-color [null] - The focus color of the thumb. Auto-derived from thumb-border-color or thumb-color. +/// @param {Color} $thumb-border-color [null] - The thumb border color. Auto-derived from track-color (fluent/indigo) or thumb-color (bootstrap). +/// @param {Color} $thumb-border-hover-color [null] - The thumb border color when hovered. Auto-derived from thumb-border-color. /// @param {Color} $thumb-border-focus-color [null] - The thumb border color when focused. -/// @param {Color} $thumb-disabled-border-color [null] - The thumb border color when it's disabled. -/// @param {Color} $disabled-thumb-color [null] - The thumb color when its disabled. -/// @param {Color} $label-background-color [null] - The background color of the bubble label. -/// @param {Color} $label-text-color [null] - The text color of the bubble label. -/// @param {Color} $base-track-color [null] - The base background color of the track. -/// @param {Color} $base-track-hover-color [null] - The base background color of the track on hover. -/// @param {Color} $disabled-base-track-color [null] - The base background color of the track when is disabled. -/// @param {Color} $disabled-fill-track-color [null] - The base background color of the fill track when is disabled. +/// @param {Color} $thumb-disabled-border-color [null] - The thumb border color when it's disabled. Auto-derived from thumb-border-color. +/// @param {Color} $disabled-thumb-color [null] - The thumb color when its disabled. Auto-derived from thumb-color. +/// @param {Color} $label-background-color [null] - The background color of the bubble label. Auto-derived from track-color or thumb-color. +/// @param {Color} $label-text-color [null] - The text color of the bubble label. Auto-derived from label-background-color. +/// @param {Color} $base-track-color [null] - The base background color of the track. PRIMARY for unfilled track. Auto-derived from track-color (material). +/// @param {Color} $base-track-hover-color [null] - The base background color of the track on hover. Auto-derived from base-track-color. +/// @param {Color} $disabled-base-track-color [null] - The base background color of the track when is disabled. Auto-derived from base-track-color. +/// @param {Color} $disabled-fill-track-color [null] - The base background color of the fill track when is disabled. Auto-derived from track-color. /// @param {Color} $tick-label-color [null] - The color of the tick label. /// @param {Color} $tick-color [null] - The background-color of the tick. /// @requires $light-material-schema diff --git a/sass/themes/components/snackbar/_snackbar-theme.scss b/sass/themes/components/snackbar/_snackbar-theme.scss index f658c6fb..6783ddc8 100644 --- a/sass/themes/components/snackbar/_snackbar-theme.scss +++ b/sass/themes/components/snackbar/_snackbar-theme.scss @@ -14,12 +14,18 @@ /// @author Marin Popov //// +/// Snackbar Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` - The background color. Auto-derives: text-color, button-color. +/// /// If you specify a background color, but do not specify colors for either the /// button or the text, their colors will be set automatically to a contrasting color. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $background [null] - The background color used in the snackbar. -/// @param {Color} $text-color [null] - The text color used in the snackbar. -/// @param {Color} $button-color [null] - The button color used in the snackbar. +/// @param {Color} $background [null] - The background color used in the snackbar. PRIMARY - derives text-color, button-color. +/// @param {Color} $text-color [null] - The text color used in the snackbar. Auto-derived from background. +/// @param {Color} $button-color [null] - The button color used in the snackbar. Auto-derived from background. /// @param {box-shadow} $shadow [null] - Sets a shadow to be used for the snackbar. /// @param {List} $border-radius [null] - The border radius used for the snackbar component. /// @requires $light-material-schema diff --git a/sass/themes/components/splitter/_splitter-theme.scss b/sass/themes/components/splitter/_splitter-theme.scss index b1f4fee3..b9adf0e8 100644 --- a/sass/themes/components/splitter/_splitter-theme.scss +++ b/sass/themes/components/splitter/_splitter-theme.scss @@ -12,13 +12,20 @@ /// @access public //// -/// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. +/// Splitter Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$bar-color` - The bar background color. Auto-derives: handle-color, expander-color, focus-color. /// -/// @param {Color} $bar-color [null] - The background color of the bar. -/// @param {Color} $handle-color [null] - The color for the bar drag handle. -/// @param {Color} $expander-color [null] - The color for the arrow expander's. +/// Setting bar-color automatically calculates contrasting colors for handle and expander. +/// Focus color behavior varies by variant (indigo uses same as bar-color, others use shaded version). +/// +/// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. +/// @param {Color} $bar-color [null] - The background color of the bar. PRIMARY - derives handle, expander, focus colors. +/// @param {Color} $handle-color [null] - The color for the bar drag handle. Auto-derived from bar-color. +/// @param {Color} $expander-color [null] - The color for the arrow expander's. Auto-derived from bar-color. /// @param {List} $border-radius [null] - the border radios of the splitter bar drag handle -/// @param {Color} $focus-color [null] - The color used for focused splitter bar. +/// @param {Color} $focus-color [null] - The color used for focused splitter bar. Auto-derived from bar-color (variant-dependent). /// @param {Number} $size [null] - The size of the splitter, its width for vertical and height for horizontal splitter. /// @requires $light-material-schema /// @example scss Set a custom expander color diff --git a/sass/themes/components/stepper/_stepper-theme.scss b/sass/themes/components/stepper/_stepper-theme.scss index d430bbbc..72873ce0 100644 --- a/sass/themes/components/stepper/_stepper-theme.scss +++ b/sass/themes/components/stepper/_stepper-theme.scss @@ -13,68 +13,81 @@ /// @author Marin Popov //// +/// Stepper Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$step-background` - The base step background. Auto-derives: hover/focus backgrounds, indicator colors, title/subtitle colors for all step states (incomplete, current, invalid, complete, disabled). +/// - `$indicator-background` - The step indicator background. Auto-derives: indicator-color, indicator-outline. +/// - `$invalid-indicator-background` - The invalid step indicator. Auto-derives: invalid title/subtitle colors when step-background not set. +/// - `$current-indicator-background` - The current step indicator. Auto-derives: current-indicator-color, current-indicator-outline. +/// - `$complete-indicator-background` - The completed step indicator. Auto-derives: complete-indicator-color. +/// +/// Setting step-background cascades through all step states (incomplete, current, invalid, complete, disabled). +/// Each state (current, invalid, complete) can be independently themed by setting its specific tokens. +/// Indicator colors are derived from their respective indicator backgrounds. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// /// @param {Color} $content-foreground [null] - The foreground of the step content. -/// @param {Color} $step-background [null] - The background of the step header. -/// @param {Color} $step-hover-background [null] - The background of the step header on hover. -/// @param {Color} $step-focus-background [null] - The background of the step header on focus. -/// @param {Color} $title-color [null] - The color of the step title. -/// @param {Color} $title-hover-color [null] - The color of the step title on hover. -/// @param {Color} $title-focus-color [null] - The color of the step title on focus. -/// @param {Color} $subtitle-color [null] - The color of the step subtitle. -/// @param {Color} $subtitle-hover-color [null] - The color of the step subtitle on hover. -/// @param {Color} $subtitle-focus-color [null] - The color of the step subtitle on focus. -/// @param {Color} $indicator-color [null] - The text color of the step indicator. -/// @param {Color} $indicator-background [null] - The background color of the step indicator. -/// @param {Color} $indicator-outline [null] - The outline color of the step indicator. +/// @param {Color} $step-background [null] - The background of the step header. PRIMARY - derives all step states. +/// @param {Color} $step-hover-background [null] - The background of the step header on hover. Auto-derived from step-background. +/// @param {Color} $step-focus-background [null] - The background of the step header on focus. Auto-derived from step-background. +/// @param {Color} $title-color [null] - The color of the step title. Auto-derived from step-background. +/// @param {Color} $title-hover-color [null] - The color of the step title on hover. Auto-derived from step-hover-background. +/// @param {Color} $title-focus-color [null] - The color of the step title on focus. Auto-derived from step-focus-background. +/// @param {Color} $subtitle-color [null] - The color of the step subtitle. Auto-derived from step-background. +/// @param {Color} $subtitle-hover-color [null] - The color of the step subtitle on hover. Auto-derived from step-hover-background. +/// @param {Color} $subtitle-focus-color [null] - The color of the step subtitle on focus. Auto-derived from step-focus-background. +/// @param {Color} $indicator-color [null] - The text color of the step indicator. Auto-derived from indicator-background. +/// @param {Color} $indicator-background [null] - The background color of the step indicator. PRIMARY for indicator - derives indicator-color, indicator-outline. Auto-derived from step-background. +/// @param {Color} $indicator-outline [null] - The outline color of the step indicator. Auto-derived from indicator-background. /// -/// @param {Color} $invalid-step-background [null] - The background of the invalid step header. -/// @param {Color} $invalid-step-hover-background [null] - The background of the invalid step header on hover. -/// @param {Color} $invalid-step-focus-background [null] - The background of the invalid step header on focus. -/// @param {Color} $invalid-title-color [null] - The color of the invalid step title. -/// @param {Color} $invalid-title-hover-color [null] - The color of the invalid step title on hover. -/// @param {Color} $invalid-title-focus-color [null] - The color of the invalid step title on focus. -/// @param {Color} $invalid-subtitle-color [null] - The color of the invalid step subtitle. -/// @param {Color} $invalid-subtitle-hover-color [null] - The color of the invalid step subtitle on hover. -/// @param {Color} $invalid-subtitle-focus-color [null] - The color of the invalid step subtitle on focus. -/// @param {Color} $invalid-indicator-color [null] - The color of the invalid step indicator. -/// @param {Color} $invalid-indicator-background [null] - The background color of the invalid step indicator. -/// @param {Color} $invalid-indicator-outline [null] - The outline color of the invalid step indicator. +/// @param {Color} $invalid-step-background [null] - The background of the invalid step header. Auto-derived from step-background. +/// @param {Color} $invalid-step-hover-background [null] - The background of the invalid step header on hover. Auto-derived from invalid-step-background. +/// @param {Color} $invalid-step-focus-background [null] - The background of the invalid step header on focus. Auto-derived from invalid-step-background. +/// @param {Color} $invalid-title-color [null] - The color of the invalid step title. Auto-derived from invalid-indicator-background. +/// @param {Color} $invalid-title-hover-color [null] - The color of the invalid step title on hover. Auto-derived from invalid-indicator-background. +/// @param {Color} $invalid-title-focus-color [null] - The color of the invalid step title on focus. Auto-derived from invalid-indicator-background. +/// @param {Color} $invalid-subtitle-color [null] - The color of the invalid step subtitle. Auto-derived from invalid-indicator-background. +/// @param {Color} $invalid-subtitle-hover-color [null] - The color of the invalid step subtitle on hover. Auto-derived from invalid-indicator-background. +/// @param {Color} $invalid-subtitle-focus-color [null] - The color of the invalid step subtitle on focus. Auto-derived from invalid-indicator-background. +/// @param {Color} $invalid-indicator-color [null] - The color of the invalid step indicator. Auto-derived from invalid-indicator-background. +/// @param {Color} $invalid-indicator-background [null] - The background color of the invalid step indicator. PRIMARY for invalid state. +/// @param {Color} $invalid-indicator-outline [null] - The outline color of the invalid step indicator. Auto-derived from invalid-indicator-background. /// -/// @param {Color} $current-step-background [null] - The background of the current step header. -/// @param {Color} $current-step-hover-background [null] - The background of the current step header on hover. -/// @param {Color} $current-step-focus-background [null] - The background of the current step header on focus. -/// @param {Color} $current-title-color [null] - The color of the current step title. -/// @param {Color} $current-title-hover-color [null] - The color of the current step title on hover. -/// @param {Color} $current-title-focus-color [null] - The color of the current step title on focus. -/// @param {Color} $current-subtitle-color [null] - The color of the current step subtitle. -/// @param {Color} $current-subtitle-hover-color [null] - The color of the current step subtitle on hover. -/// @param {Color} $current-subtitle-focus-color [null] - The color of the current step subtitle on focus. -/// @param {Color} $current-indicator-color [null] - The color of the current step indicator. -/// @param {Color} $current-indicator-background [null] - The background color of the current step indicator. -/// @param {Color} $current-indicator-outline [null] - The outline color of the current step indicator. +/// @param {Color} $current-step-background [null] - The background of the current step header. Auto-derived from step-background. +/// @param {Color} $current-step-hover-background [null] - The background of the current step header on hover. Auto-derived from current-step-background. +/// @param {Color} $current-step-focus-background [null] - The background of the current step header on focus. Auto-derived from current-step-background. +/// @param {Color} $current-title-color [null] - The color of the current step title. Auto-derived from current-step-background. +/// @param {Color} $current-title-hover-color [null] - The color of the current step title on hover. Auto-derived from current-step-hover-background. +/// @param {Color} $current-title-focus-color [null] - The color of the current step title on focus. Auto-derived from current-step-focus-background. +/// @param {Color} $current-subtitle-color [null] - The color of the current step subtitle. Auto-derived from current-step-background. +/// @param {Color} $current-subtitle-hover-color [null] - The color of the current step subtitle on hover. Auto-derived from current-step-hover-background. +/// @param {Color} $current-subtitle-focus-color [null] - The color of the current step subtitle on focus. Auto-derived from current-step-focus-background. +/// @param {Color} $current-indicator-color [null] - The color of the current step indicator. Auto-derived from current-indicator-background. +/// @param {Color} $current-indicator-background [null] - The background color of the current step indicator. PRIMARY for current state. Auto-derived from current-step-background. +/// @param {Color} $current-indicator-outline [null] - The outline color of the current step indicator. Auto-derived from current-indicator-background. /// -/// @param {Color} $complete-step-background [null] - The background of the complete step header. -/// @param {Color} $complete-step-hover-background [null] - The background of the complete step header on hover. -/// @param {Color} $complete-step-focus-background [null] - The background of the complete step header on focus. -/// @param {Color} $complete-title-color [null] - The color of the complete step title. -/// @param {Color} $complete-title-hover-color [null] - The color of the complete step title on hover. -/// @param {Color} $complete-title-focus-color [null] - The color of the complete step title on focus. -/// @param {Color} $complete-subtitle-color [null] - The color of the complete step subtitle. -/// @param {Color} $complete-subtitle-hover-color [null] - The color of the complete step subtitle on hover. -/// @param {Color} $complete-subtitle-focus-color [null] - The color of the complete step subtitle on focus. -/// @param {Color} $complete-indicator-color [null] - The color of the completed step indicator. -/// @param {Color} $complete-indicator-background [null] - The background color of the completed step indicator. +/// @param {Color} $complete-step-background [null] - The background of the complete step header. Auto-derived from step-background. +/// @param {Color} $complete-step-hover-background [null] - The background of the complete step header on hover. Auto-derived from complete-step-background. +/// @param {Color} $complete-step-focus-background [null] - The background of the complete step header on focus. Auto-derived from complete-step-background. +/// @param {Color} $complete-title-color [null] - The color of the complete step title. Auto-derived from complete-step-background. +/// @param {Color} $complete-title-hover-color [null] - The color of the complete step title on hover. Auto-derived from complete-step-hover-background. +/// @param {Color} $complete-title-focus-color [null] - The color of the complete step title on focus. Auto-derived from complete-step-focus-background. +/// @param {Color} $complete-subtitle-color [null] - The color of the complete step subtitle. Auto-derived from complete-step-background. +/// @param {Color} $complete-subtitle-hover-color [null] - The color of the complete step subtitle on hover. Auto-derived from complete-step-hover-background. +/// @param {Color} $complete-subtitle-focus-color [null] - The color of the complete step subtitle on focus. Auto-derived from complete-step-focus-background. +/// @param {Color} $complete-indicator-color [null] - The color of the completed step indicator. Auto-derived from complete-indicator-background. +/// @param {Color} $complete-indicator-background [null] - The background color of the completed step indicator. PRIMARY for complete state. Auto-derived from complete-step-background. /// @param {Color} $complete-indicator-outline [null] - The outline color of the completed step indicator. /// -/// @param {Color} $disabled-title-color [null] - The title color of the disabled step. -/// @param {Color} $disabled-subtitle-color [null] - The subtitle color of the disabled step. -/// @param {Color} $disabled-indicator-color [null] - The indicator color of the disabled step. -/// @param {Color} $disabled-indicator-background [null] - The indicator background of the disabled step. -/// @param {Color} $disabled-indicator-outline [null] - The indicator outline color of the disabled step. +/// @param {Color} $disabled-title-color [null] - The title color of the disabled step. Auto-derived from step-background. +/// @param {Color} $disabled-subtitle-color [null] - The subtitle color of the disabled step. Auto-derived from step-background. +/// @param {Color} $disabled-indicator-color [null] - The indicator color of the disabled step. Auto-derived from disabled-indicator-background. +/// @param {Color} $disabled-indicator-background [null] - The indicator background of the disabled step. Auto-derived from step-background. +/// @param {Color} $disabled-indicator-outline [null] - The indicator outline color of the disabled step. Auto-derived from disabled-indicator-background. /// -/// @param {Color} $step-separator-color [null] - The separator border-color of between the steps. +/// @param {Color} $step-separator-color [null] - The separator border-color of between the steps. Auto-derived from step-background or indicator-background. /// @param {Color} $complete-step-separator-color [null] - The separator border-color between the completed steps. /// /// @param {Color} $step-separator-style [null] - The separator border-style of between the steps. diff --git a/sass/themes/components/switch/_switch-theme.scss b/sass/themes/components/switch/_switch-theme.scss index 511b1dde..736547ca 100644 --- a/sass/themes/components/switch/_switch-theme.scss +++ b/sass/themes/components/switch/_switch-theme.scss @@ -14,17 +14,27 @@ /// @author Marin Popov //// +/// Switch Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$track-on-color` - The ON state track color. Auto-derives: thumb-on-color, border-on-color, track-on-hover-color, track-on-disabled-color, focus colors. +/// - `$track-off-color` - The OFF state track color. Auto-derives: thumb-off-color, border-color, track-disabled-color. +/// +/// The relationship between track and thumb colors varies by design variant: +/// - Material: track-on-color and thumb-on-color derive from each other (set either one) +/// - Fluent/Bootstrap/Indigo: thumb color auto-derived from track as contrast color +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $thumb-on-color [null] - The color of the thumb when the switch is on. -/// @param {Color} $track-on-color [null] - The color of the track when the switch is on. -/// @param {Color} $track-on-hover-color [null] - The color of the track when the switch is on and hovered. -/// @param {Color} $thumb-off-color [null] - The color of the thumb when the switch is off. -/// @param {Color} $thumb-off-hover-color [null] - The color of the thumb when the switch is off and hovered. -/// @param {Color} $track-off-color [null] - The color of the track when the switch is off. -/// @param {Color} $thumb-disabled-color [null] - The color of the thumb when the switch is disabled. -/// @param {Color} $thumb-on-disabled-color [null] - The color of the thumb when the switch is on and disabled. -/// @param {Color} $track-disabled-color [null] - The color of the track when the switch is disabled. -/// @param {Color} $track-on-disabled-color [null] - The color of the track when the switch is on and disabled. +/// @param {Color} $thumb-on-color [null] - The color of the thumb when the switch is on. Auto-derived from track-on-color (non-material) or bidirectional with track-on-color (material). +/// @param {Color} $track-on-color [null] - The color of the track when the switch is on. PRIMARY for ON state. +/// @param {Color} $track-on-hover-color [null] - The color of the track when the switch is on and hovered. Auto-derived from track-on-color. +/// @param {Color} $thumb-off-color [null] - The color of the thumb when the switch is off. Auto-derived from track-off-color or border-color. +/// @param {Color} $thumb-off-hover-color [null] - The color of the thumb when the switch is off and hovered. Auto-derived from thumb-off-color. +/// @param {Color} $track-off-color [null] - The color of the track when the switch is off. PRIMARY for OFF state. +/// @param {Color} $thumb-disabled-color [null] - The color of the thumb when the switch is disabled. Auto-derived from thumb-off-color. +/// @param {Color} $thumb-on-disabled-color [null] - The color of the thumb when the switch is on and disabled. Auto-derived from thumb-on-color. +/// @param {Color} $track-disabled-color [null] - The color of the track when the switch is disabled. Auto-derived from track-off-color. +/// @param {Color} $track-on-disabled-color [null] - The color of the track when the switch is on and disabled. Auto-derived from track-on-color. /// @param {Color} $label-color [null] - The color of the switch label /// @param {Color} $label-hover-color [null] - The color of the switch label on hover. /// @param {Color} $label-disabled-color [null] - The color of the switch label when the switch is disabled @@ -34,15 +44,15 @@ /// @param {List} $border-radius-track [null] - The border radius used for switch track. /// @param {List} $border-radius-thumb [null] - The border radius used for switch thumb. /// @param {List} $border-radius-ripple [null] - The border radius used for switch ripple. -/// @param {Color} $border-color [null] - The border color of the switch. -/// @param {Color} $border-hover-color [null] - The border color of the switch on hover. -/// @param {Color} $border-disabled-color [null] - The border color of the switch when it is disabled. -/// @param {Color} $border-on-color [null] - The border color when the switch is on. -/// @param {Color} $border-on-hover-color [null] - The border color when the switch is on and hovered. -/// @param {Color} $focus-outline-color [null] - The focus outlined color. -/// @param {Color} $focus-outline-color-focused [null] - The focus outlined color for focused state. -/// @param {Color} $focus-fill-color [null] - The focus fill color. -/// @param {Color} $focus-fill-hover-color [null] - The focus fill color on hover. +/// @param {Color} $border-color [null] - The border color of the switch. Auto-derived from thumb-off-color. +/// @param {Color} $border-hover-color [null] - The border color of the switch on hover. Auto-derived from track-off-color or border-color. +/// @param {Color} $border-disabled-color [null] - The border color of the switch when it is disabled. Auto-derived from border-color. +/// @param {Color} $border-on-color [null] - The border color when the switch is on. Auto-derived from track-on-color. +/// @param {Color} $border-on-hover-color [null] - The border color when the switch is on and hovered. Auto-derived from border-on-color. +/// @param {Color} $focus-outline-color [null] - The focus outlined color. Auto-derived from border-color (indigo) or track-on-color (bootstrap). +/// @param {Color} $focus-outline-color-focused [null] - The focus outlined color for focused state. Auto-derived from border-on-color (indigo). +/// @param {Color} $focus-fill-color [null] - The focus fill color. Auto-derived from track-on-color (bootstrap). +/// @param {Color} $focus-fill-hover-color [null] - The focus fill color on hover. Auto-derived from focus-fill-color. /// @requires $light-material-schema /// /// @example scss Set custom track and thumb on colors diff --git a/sass/themes/components/tabs/_tabs-theme.scss b/sass/themes/components/tabs/_tabs-theme.scss index 5827a201..7c85b183 100644 --- a/sass/themes/components/tabs/_tabs-theme.scss +++ b/sass/themes/components/tabs/_tabs-theme.scss @@ -13,32 +13,41 @@ /// @author Marin Popov //// +/// Tabs Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$item-background` - The tabs header background. Auto-derives: item-text-color, item-icon-color, item-hover colors, item-active colors, button colors, border-color. +/// - `$item-active-color` - The active tab text color. Auto-derives: item-active-icon-color, indicator-color, item-active-hover colors. +/// +/// Setting just `$item-background` will theme all tab states consistently. +/// The `$item-active-color` controls the indicator and active text appearance. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $item-text-color [null] - The color used for the tab text color. -/// @param {Color} $item-background [null] - The background color used for the tabs header. -/// @param {Color} $item-hover-background [null] - The background used for the tabs on hover. -/// @param {Color} $item-hover-color [null] - The text color used for the tabs on hover. -/// @param {Color} $item-icon-color [null] - The color used for the tab icon. -/// @param {Color} $item-active-icon-color [null] - The color used for the active tab icon. -/// @param {Color} $item-active-hover-icon-color [null] - The color used for the active tab icon on hover and focus. -/// @param {Color} $item-hover-icon-color [null] - The color used for the tab icon on hover. +/// @param {Color} $item-text-color [null] - The color used for the tab text color. Auto-derived from item-background or synced with item-icon-color. +/// @param {Color} $item-background [null] - The background color used for the tabs header. PRIMARY - derives most colors. +/// @param {Color} $item-hover-background [null] - The background used for the tabs on hover. Auto-derived from item-background. +/// @param {Color} $item-hover-color [null] - The text color used for the tabs on hover. Auto-derived from item-text-color or item-hover-background. +/// @param {Color} $item-icon-color [null] - The color used for the tab icon. Auto-derived from item-background or synced with item-text-color. +/// @param {Color} $item-active-icon-color [null] - The color used for the active tab icon. Auto-derived from item-active-color or item-active-background. +/// @param {Color} $item-active-hover-icon-color [null] - The color used for the active tab icon on hover and focus. Auto-derived from item-active-icon-color. +/// @param {Color} $item-hover-icon-color [null] - The color used for the tab icon on hover. Auto-derived from item-icon-color or item-hover-background. /// @param {Color} $item-disabled-icon-color [null] - The color used for the disabled tab icon. -/// @param {Color} $item-active-color [null] - The color used for the active tabs text. -/// @param {Color} $item-active-hover-color [null] - The color used for the active tabs text on hover and focus. -/// @param {Color} $item-active-background [null] - The color used for the active tab background. -/// @param {Color} $item-active-hover-background [null] - The color used for the active tab background on hover and focus. +/// @param {Color} $item-active-color [null] - The color used for the active tabs text. PRIMARY for active/indicator - derives indicator-color. +/// @param {Color} $item-active-hover-color [null] - The color used for the active tabs text on hover and focus. Auto-derived from item-active-color. +/// @param {Color} $item-active-background [null] - The color used for the active tab background. Auto-derived from item-background. +/// @param {Color} $item-active-hover-background [null] - The color used for the active tab background on hover and focus. Auto-derived from item-active-background. /// @param {Color} $item-disabled-color [null] - The color used for the disabled tabs text. -/// @param {Color} $indicator-color [null] - The color used for the active tab indicator. -/// @param {Color} $button-color [null] - The color used for the button icon/text color. -/// @param {Color} $button-hover-color [null] - The color used for the button icon/text color on hover. -/// @param {Color} $button-disabled-color [null] - The color used for the disabled button icon/text. -/// @param {Color} $button-background [null] - The color used for the button background. -/// @param {Color} $button-hover-background [null] - The color used for the button background on hover. +/// @param {Color} $indicator-color [null] - The color used for the active tab indicator. Auto-derived from item-active-color. +/// @param {Color} $button-color [null] - The color used for the button icon/text color. Auto-derived from button-background or item-text-color. +/// @param {Color} $button-hover-color [null] - The color used for the button icon/text color on hover. Auto-derived from button-color or button-hover-background. +/// @param {Color} $button-disabled-color [null] - The color used for the disabled button icon/text. Auto-derived from button-color. +/// @param {Color} $button-background [null] - The color used for the button background. Auto-derived from item-background. +/// @param {Color} $button-hover-background [null] - The color used for the button background on hover. Auto-derived from item-background or button-background. /// @param {List} $border-radius [null] - The border radius for the tabs. -/// @param {Color} $border-color [null] - The border color of the tabs. -/// @param {Color} $border-color--hover [null] - The border color of the tabs on hover. -/// @param {Color} $tab-ripple-color [null] - The color used for the button background. -/// @param {Color} $button-ripple-color [null] - The color used for the button background on hover. +/// @param {Color} $border-color [null] - The border color of the tabs. Auto-derived from item-background (bootstrap). +/// @param {Color} $border-color--hover [null] - The border color of the tabs on hover. Auto-derived from border-color. +/// @param {Color} $tab-ripple-color [null] - The color used for the tab ripple effect. Auto-derived from item-active-background or item-background. +/// @param {Color} $button-ripple-color [null] - The color used for the button ripple effect. Auto-derived from button-color. /// @requires $light-material-schema /// @example scss Set a custom background color /// $my-tabs-theme: tabs-theme( diff --git a/sass/themes/components/time-picker/_time-picker-theme.scss b/sass/themes/components/time-picker/_time-picker-theme.scss index a354515b..08697ec3 100644 --- a/sass/themes/components/time-picker/_time-picker-theme.scss +++ b/sass/themes/components/time-picker/_time-picker-theme.scss @@ -13,23 +13,31 @@ /// @author Marin Popov //// -/// If only background color is specified, text/icon color -/// will be assigned automatically to a contrasting color. +/// Time Picker Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background-color` - The picker panel background. Auto-derives: text-color, selected-text-color, active-item-background, border-color. +/// - `$selected-text-color` or `$active-item-background` - The selected/active accent color. These derive from each other and from header-background. +/// - `$header-background` - The header background. Auto-derives: header-hour-text-color. Also derivable from selected-text-color or background-color. +/// +/// If only background color is specified, text/icon color will be assigned automatically to a contrasting color. /// Does ___not___ apply for disabled state colors. +/// Selected-text-color and active-item-background are interconnected - setting one derives the other. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $text-color [null] - The text color of a open time picker. -/// @param {Color} $hover-text-color [null] - The hover text color of a open time picker. -/// @param {Color} $selected-text-color [null] - The text color of a selected item in time picker. -/// @param {Color} $active-item-background [null] - The background color for current item in focused column inside the time picker. -/// @param {Color} $active-item-foreground [null] - The foreground color for current item in focused column inside the time picker. -/// @param {Color} $disabled-text-color [null] - The text color for disabled values. -/// @param {Color} $disabled-item-background [null] - The background color for disabled values . -/// @param {Color} $header-background [null] - The header background color of a time picker. -/// @param {Color} $header-hour-text-color [null] - The header hour text color of a time picker. -/// @param {Color} $background-color [null] - The time-picker panel background color. +/// @param {Color} $text-color [null] - The text color of a open time picker. Auto-derived from background-color. +/// @param {Color} $hover-text-color [null] - The hover text color of a open time picker. Auto-derived from text-color. +/// @param {Color} $selected-text-color [null] - The text color of a selected item in time picker. Auto-derived from background-color or active-item-background. +/// @param {Color} $active-item-background [null] - The background color for current item in focused column inside the time picker. Auto-derived from selected-text-color or background-color. +/// @param {Color} $active-item-foreground [null] - The foreground color for current item in focused column inside the time picker. Auto-derived from active-item-background. +/// @param {Color} $disabled-text-color [null] - The text color for disabled values. Auto-derived from disabled-item-background. +/// @param {Color} $disabled-item-background [null] - The background color for disabled values. +/// @param {Color} $header-background [null] - The header background color of a time picker. Auto-derived from selected-text-color or background-color. +/// @param {Color} $header-hour-text-color [null] - The header hour text color of a time picker. Auto-derived from header-background. +/// @param {Color} $background-color [null] - The time-picker panel background color. PRIMARY - derives text, selected, active, border colors. /// @param {Number} $time-item-size [null] - The height of the time item. -/// @param {Color} $divider-color [null] - The color for the actions area divider. -/// @param {Color} $border-color [null] - The border color around the time picker. +/// @param {Color} $divider-color [null] - The color for the actions area divider. Auto-derived from border-color. +/// @param {Color} $border-color [null] - The border color around the time picker. Auto-derived from background-color. /// @param {box-shadow} $modal-shadow [null] - The custom shadow to be used for the time picker in modal mode. /// @param {box-shadow} $dropdown-shadow [null] - The custom shadow to be used for the time picker in dropdown mode. /// @param {List} $border-radius [null] - The border radius used for the outline of the picker. diff --git a/sass/themes/components/toast/_toast-theme.scss b/sass/themes/components/toast/_toast-theme.scss index ca6e8997..42774142 100644 --- a/sass/themes/components/toast/_toast-theme.scss +++ b/sass/themes/components/toast/_toast-theme.scss @@ -14,10 +14,17 @@ /// @author Marin Popov //// +/// Toast Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` - The background color. Auto-derives: text-color, border-color. +/// +/// Setting the background automatically calculates contrasting text and a semi-transparent border. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $background [null] - The background color used for the toast. -/// @param {Color} $text-color [null] - The text-color used for the toast. -/// @param {Color} $border-color [null] - The border-color used for the toast. +/// @param {Color} $background [null] - The background color used for the toast. PRIMARY - derives text-color, border-color. +/// @param {Color} $text-color [null] - The text-color used for the toast. Auto-derived from background. +/// @param {Color} $border-color [null] - The border-color used for the toast. Auto-derived from text-color. /// @param {List} $border-radius [null] - The border radius used for the toast component. /// @param {box-shadow} $shadow [null] - Sets a shadow to be used for the toast. /// @requires $light-material-schema diff --git a/sass/themes/components/tooltip/_tooltip-theme.scss b/sass/themes/components/tooltip/_tooltip-theme.scss index 7d38b252..37337d49 100644 --- a/sass/themes/components/tooltip/_tooltip-theme.scss +++ b/sass/themes/components/tooltip/_tooltip-theme.scss @@ -14,10 +14,16 @@ /// @author Marin Popov //// -/// Returns a map containing all style properties related to the theming of the tooltip. +/// Tooltip Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` - The background color. Auto-derives: text-color. +/// +/// Setting the background automatically calculates a contrasting text color. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} $background [null] - The background color of the tooltip. -/// @param {Color} $text-color [null] - The text color of the tooltip. +/// @param {Color} $background [null] - The background color of the tooltip. PRIMARY - derives text-color. +/// @param {Color} $text-color [null] - The text color of the tooltip. Auto-derived from background. /// @param {List} $border-radius [null] - The border radius used for the tooltip component. /// @param {box-shadow} $shadow [null] - Sets a shadow to be used for the tooltip component. /// @requires $light-material-schema diff --git a/sass/themes/components/tree/_tree-theme.scss b/sass/themes/components/tree/_tree-theme.scss index 8610851d..6edd7ba7 100644 --- a/sass/themes/components/tree/_tree-theme.scss +++ b/sass/themes/components/tree/_tree-theme.scss @@ -13,23 +13,32 @@ /// @author Marin Popov //// -/// Returns a map containing all style properties related to the theming of the tree component. +/// Tree Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$background` - The node background. Auto-derives: foreground, all state backgrounds (selected, active, active-selected, disabled), hover colors. +/// - `$background-selected` - The selected node background. Auto-derives: foreground-selected, hover-selected-color. +/// - `$background-active` - The active node background. Auto-derives: foreground-active, background-active-selected. +/// +/// Setting background cascades through all node states (selected, active, disabled). +/// Each state derives its own foreground (text) color from its background. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. -/// @param {Color} background [null] - The background color used for the tree node. -/// @param {Color} foreground [null] - The color used for the tree node content. +/// @param {Color} background [null] - The background color used for the tree node. PRIMARY - derives all state colors. +/// @param {Color} foreground [null] - The color used for the tree node content. Auto-derived from background. /// @param {Color} icon-color [null] - The color used for the tree node icon. -/// @param {Color} background-selected [null] - The background color used for the selected tree node. -/// @param {Color} foreground-selected [null] - The color used for the content of the selected tree node. -/// @param {Color} background-active [null] - The background color used for the active tree node. -/// @param {Color} foreground-active [null] - The color used for the content of the active tree node. -/// @param {Color} background-active-selected [null] - The background color used for the active selected tree node. -/// @param {Color} foreground-active-selected [null] - The color used for the content of the active selected tree node. -/// @param {Color} background-disabled [null] - The background color used for the tree node in disabled state. -/// @param {Color} foreground-disabled [null] - The color used for the content of the disabled tree node. +/// @param {Color} background-selected [null] - The background color used for the selected tree node. Auto-derived from background. +/// @param {Color} foreground-selected [null] - The color used for the content of the selected tree node. Auto-derived from background-selected. +/// @param {Color} background-active [null] - The background color used for the active tree node. Auto-derived from background. +/// @param {Color} foreground-active [null] - The color used for the content of the active tree node. Auto-derived from background-active. +/// @param {Color} background-active-selected [null] - The background color used for the active selected tree node. Auto-derived from background-active. +/// @param {Color} foreground-active-selected [null] - The color used for the content of the active selected tree node. Auto-derived from background-active-selected. +/// @param {Color} background-disabled [null] - The background color used for the tree node in disabled state. Auto-derived from background. +/// @param {Color} foreground-disabled [null] - The color used for the content of the disabled tree node. Auto-derived from background-disabled. /// @param {Color} drop-area-color [null] - The background color used for the tree node drop aria. /// @param {Color} border-color [null] - The outline shadow color used for tree node in focus state. -/// @param {Color} hover-color [null] - The background color used for the tree node on hover. -/// @param {Color} hover-selected-color [null] - The background color used for the selected tree node on hover. +/// @param {Color} hover-color [null] - The background color used for the tree node on hover. Auto-derived from background. +/// @param {Color} hover-selected-color [null] - The background color used for the selected tree node on hover. Auto-derived from background-selected. /// @requires $light-material-schema /// /// @example scss Change the tree background diff --git a/sass/themes/components/watermark/_watermark-theme.scss b/sass/themes/components/watermark/_watermark-theme.scss index 59940b7d..fdb24d39 100644 --- a/sass/themes/components/watermark/_watermark-theme.scss +++ b/sass/themes/components/watermark/_watermark-theme.scss @@ -13,20 +13,23 @@ /// @author Marin Popov //// -/// Returns a map containing all style properties related to the theming the watermark directive. +/// Watermark Theme +/// +/// PRIMARY TOKENS (set these first for quick theming): +/// - `$link-background` - The link background color. Auto-derives: color (text). +/// +/// Setting link-background automatically calculates a contrasting text color. +/// /// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the component. /// @param {Color} $base-color [null] - The base color for all elements of the watermark. /// @param {Color} $image-color [null] - The color used for the stamp image. /// @param {Number} $image-opacity [null] - The opacity of the stamp image. -/// @param {Color} $link-background [null] - The background color used for the link. -/// @param {Color} $color [null] - The color used for the link text. +/// @param {Color} $link-background [null] - The background color used for the link. PRIMARY - derives color. +/// @param {Color} $color [null] - The color used for the link text. Auto-derived from link-background. /// @param {Color} $border-color [null] - The border color used for the link. /// @param {List} $border-radius [null] - The border radius used for the link. /// /// @example scss Change the watermark link background -/// $my-watermark-theme: watermark-theme($link-background: magenta); -/// // Pass the theme to the css-vars() mixin -/// @include css-vars($my-watermark-theme); /// @requires $light-material-schema @function watermark-theme( $schema: $light-material-schema, diff --git a/scripts/buildComponentDocs.mjs b/scripts/buildComponentDocs.mjs new file mode 100644 index 00000000..55b81dbc --- /dev/null +++ b/scripts/buildComponentDocs.mjs @@ -0,0 +1,39 @@ +import sassdoc from 'sassdoc'; +import {writeFile, mkdir} from 'fs/promises'; +import report from './report.mjs'; + +async function extractComponentThemes() { + const data = await sassdoc.parse('./sass/themes/components/**/*-theme.scss', { + verbose: false, + }); + + // Filter to theme functions only + const themeFunctions = data.filter( + (item) => item.context.type === 'function' && item.context.name.endsWith('-theme'), + ); + + const components = {}; + + for (const fn of themeFunctions) { + const componentName = fn.context.name.replace(/-theme$/, ''); + + components[componentName] = { + name: componentName, + themeFunctionName: fn.context.name, + description: fn.description || '', + tokens: (fn.parameter || []) + .filter((p) => p.name !== 'schema') + .map((p) => ({ + name: p.name, + type: p.type || 'unknown', + description: p.description || '', + })), + }; + } + + await mkdir('./json/components', {recursive: true}); + await writeFile('./json/components/themes.json', JSON.stringify(components, null, 2)); + + report.info(`Extracted ${Object.keys(components).length} component themes`); +} +extractComponentThemes(); diff --git a/src/mcp/__tests__/knowledge/component-selectors.test.ts b/src/mcp/__tests__/knowledge/component-selectors.test.ts new file mode 100644 index 00000000..41e407fc --- /dev/null +++ b/src/mcp/__tests__/knowledge/component-selectors.test.ts @@ -0,0 +1,421 @@ +/** + * Tests for component-selectors.ts knowledge base + * + * These tests verify function behavior using stable test cases that don't + * depend on specific production data values, making them resilient to data changes. + */ + +import {describe, it, expect} from 'vitest'; +import { + COMPONENT_SELECTORS, + COMPONENT_VARIANTS, + COMPOUND_COMPONENTS, + getComponentSelector, + hasVariants, + getVariants, + isVariantTheme, + getCompoundComponentInfo, + isCompoundComponent, + getPartSelector, + hasPartSelectors, + getAllPartSelectors, +} from '../../knowledge/component-selectors.js'; + +describe('Component Selectors Knowledge Base', () => { + // ===== Data Structure Sanity Checks ===== + // These tests verify the data structures exist and have the expected shape, + // without asserting on specific values that may change. + + describe('COMPONENT_SELECTORS data structure', () => { + it('should be a non-empty object', () => { + expect(COMPONENT_SELECTORS).toBeDefined(); + expect(typeof COMPONENT_SELECTORS).toBe('object'); + expect(Object.keys(COMPONENT_SELECTORS).length).toBeGreaterThan(0); + }); + + it('each entry should have angular and webcomponents properties', () => { + for (const [name, selector] of Object.entries(COMPONENT_SELECTORS)) { + expect(selector, `${name} should have angular property`).toHaveProperty('angular'); + expect(selector, `${name} should have webcomponents property`).toHaveProperty('webcomponents'); + } + }); + + it('selectors should be strings, arrays of strings, or null', () => { + for (const [name, selector] of Object.entries(COMPONENT_SELECTORS)) { + const angularIsValid = + selector.angular === null || + typeof selector.angular === 'string' || + (Array.isArray(selector.angular) && selector.angular.every((s) => typeof s === 'string')); + const webcomponentsIsValid = + selector.webcomponents === null || + typeof selector.webcomponents === 'string' || + (Array.isArray(selector.webcomponents) && selector.webcomponents.every((s) => typeof s === 'string')); + + expect(angularIsValid, `${name}.angular should be string, string[], or null`).toBe(true); + expect(webcomponentsIsValid, `${name}.webcomponents should be string, string[], or null`).toBe(true); + } + }); + }); + + describe('COMPONENT_VARIANTS data structure', () => { + it('should be a non-empty object', () => { + expect(COMPONENT_VARIANTS).toBeDefined(); + expect(typeof COMPONENT_VARIANTS).toBe('object'); + expect(Object.keys(COMPONENT_VARIANTS).length).toBeGreaterThan(0); + }); + + it('each entry should be an array of strings', () => { + for (const [name, variants] of Object.entries(COMPONENT_VARIANTS)) { + expect(Array.isArray(variants), `${name} variants should be an array`).toBe(true); + for (const variant of variants) { + expect(typeof variant, `${name} variant should be a string`).toBe('string'); + } + } + }); + }); + + describe('COMPOUND_COMPONENTS data structure', () => { + it('should be a non-empty object', () => { + expect(COMPOUND_COMPONENTS).toBeDefined(); + expect(typeof COMPOUND_COMPONENTS).toBe('object'); + expect(Object.keys(COMPOUND_COMPONENTS).length).toBeGreaterThan(0); + }); + + it('each entry should have description and relatedThemes', () => { + for (const [name, info] of Object.entries(COMPOUND_COMPONENTS)) { + expect(info, `${name} should have description`).toHaveProperty('description'); + expect(typeof info.description, `${name}.description should be a string`).toBe('string'); + expect(info, `${name} should have relatedThemes`).toHaveProperty('relatedThemes'); + expect(Array.isArray(info.relatedThemes), `${name}.relatedThemes should be an array`).toBe(true); + } + }); + + it('innerSelectors keys should match relatedThemes when present', () => { + for (const [name, info] of Object.entries(COMPOUND_COMPONENTS)) { + if (info.innerSelectors?.webcomponents) { + const partsKeys = Object.keys(info.innerSelectors.webcomponents); + for (const theme of info.relatedThemes) { + expect(partsKeys, `${name}.innerSelectors.webcomponents should include key for ${theme}`).toContain(theme); + } + } + if (info.innerSelectors?.angular) { + const angularKeys = Object.keys(info.innerSelectors.angular); + for (const theme of info.relatedThemes) { + expect(angularKeys, `${name}.innerSelectors.angular should include key for ${theme}`).toContain(theme); + } + } + } + }); + }); + + // ===== Function Behavior Tests ===== + // These tests verify function logic by testing against any existing data, + // checking return types and edge cases rather than specific values. + + describe('getComponentSelector()', () => { + it('should always return an array', () => { + // Test with a component we know exists + const firstComponent = Object.keys(COMPONENT_SELECTORS)[0]; + const angularResult = getComponentSelector(firstComponent, 'angular'); + const webcomponentsResult = getComponentSelector(firstComponent, 'webcomponents'); + + expect(Array.isArray(angularResult)).toBe(true); + expect(Array.isArray(webcomponentsResult)).toBe(true); + }); + + it('should return non-empty array for existing components', () => { + const firstComponent = Object.keys(COMPONENT_SELECTORS)[0]; + const result = getComponentSelector(firstComponent, 'angular'); + expect(result.length).toBeGreaterThan(0); + }); + + it('should return empty array for unknown component', () => { + const result = getComponentSelector('__nonexistent_component__', 'angular'); + expect(result).toEqual([]); + }); + + it('should return empty array for unknown component on webcomponents platform', () => { + const result = getComponentSelector('__nonexistent_component__', 'webcomponents'); + expect(result).toEqual([]); + }); + + it('should normalize single selector to array', () => { + // Find a component with a single selector (string, not array) + const componentWithSingleSelector = Object.entries(COMPONENT_SELECTORS).find( + ([, sel]) => typeof sel.angular === 'string', + ); + + if (componentWithSingleSelector) { + const [name] = componentWithSingleSelector; + const result = getComponentSelector(name, 'angular'); + expect(Array.isArray(result)).toBe(true); + expect(result.length).toBe(1); + } + }); + + it('should preserve array selectors as-is', () => { + // Find a component with array selectors + const componentWithArraySelector = Object.entries(COMPONENT_SELECTORS).find(([, sel]) => + Array.isArray(sel.angular), + ); + + if (componentWithArraySelector) { + const [name, sel] = componentWithArraySelector; + const result = getComponentSelector(name, 'angular'); + expect(Array.isArray(result)).toBe(true); + expect(result.length).toBe((sel.angular as string[]).length); + } + }); + }); + + describe('hasVariants()', () => { + it('should return true for components in COMPONENT_VARIANTS', () => { + const firstVariantComponent = Object.keys(COMPONENT_VARIANTS)[0]; + expect(hasVariants(firstVariantComponent)).toBe(true); + }); + + it('should return false for components not in COMPONENT_VARIANTS', () => { + // Find a component that is NOT in COMPONENT_VARIANTS + const nonVariantComponent = Object.keys(COMPONENT_SELECTORS).find((name) => !(name in COMPONENT_VARIANTS)); + + if (nonVariantComponent) { + expect(hasVariants(nonVariantComponent)).toBe(false); + } + }); + + it('should return false for unknown components', () => { + expect(hasVariants('__nonexistent_component__')).toBe(false); + }); + }); + + describe('getVariants()', () => { + it('should return array for components with variants', () => { + const firstVariantComponent = Object.keys(COMPONENT_VARIANTS)[0]; + const result = getVariants(firstVariantComponent); + expect(Array.isArray(result)).toBe(true); + expect(result.length).toBeGreaterThan(0); + }); + + it('should return empty array for components without variants', () => { + const nonVariantComponent = Object.keys(COMPONENT_SELECTORS).find((name) => !(name in COMPONENT_VARIANTS)); + + if (nonVariantComponent) { + expect(getVariants(nonVariantComponent)).toEqual([]); + } + }); + + it('should return empty array for unknown components', () => { + expect(getVariants('__nonexistent_component__')).toEqual([]); + }); + }); + + describe('isVariantTheme()', () => { + it('should return true for variant theme names', () => { + // Get the first variant from the first component that has variants + const firstVariantComponent = Object.keys(COMPONENT_VARIANTS)[0]; + const firstVariant = COMPONENT_VARIANTS[firstVariantComponent][0]; + expect(isVariantTheme(firstVariant)).toBe(true); + }); + + it('should return false for base component names', () => { + const baseComponentName = Object.keys(COMPONENT_VARIANTS)[0]; + expect(isVariantTheme(baseComponentName)).toBe(false); + }); + + it('should return false for unknown names', () => { + expect(isVariantTheme('__nonexistent_theme__')).toBe(false); + }); + }); + + describe('getCompoundComponentInfo()', () => { + it('should return info object for compound components', () => { + const firstCompound = Object.keys(COMPOUND_COMPONENTS)[0]; + const result = getCompoundComponentInfo(firstCompound); + expect(result).toBeDefined(); + expect(result).toHaveProperty('description'); + expect(result).toHaveProperty('relatedThemes'); + }); + + it('should return undefined for non-compound components', () => { + const nonCompoundComponent = Object.keys(COMPONENT_SELECTORS).find((name) => !(name in COMPOUND_COMPONENTS)); + + if (nonCompoundComponent) { + expect(getCompoundComponentInfo(nonCompoundComponent)).toBeUndefined(); + } + }); + + it('should return undefined for unknown components', () => { + expect(getCompoundComponentInfo('__nonexistent_component__')).toBeUndefined(); + }); + }); + + describe('isCompoundComponent()', () => { + it('should return true for compound components', () => { + const firstCompound = Object.keys(COMPOUND_COMPONENTS)[0]; + expect(isCompoundComponent(firstCompound)).toBe(true); + }); + + it('should return false for non-compound components', () => { + const nonCompoundComponent = Object.keys(COMPONENT_SELECTORS).find((name) => !(name in COMPOUND_COMPONENTS)); + + if (nonCompoundComponent) { + expect(isCompoundComponent(nonCompoundComponent)).toBe(false); + } + }); + + it('should return false for unknown components', () => { + expect(isCompoundComponent('__nonexistent_component__')).toBe(false); + }); + }); + + describe('getPartSelector()', () => { + it('should return undefined for non-compound component', () => { + const nonCompoundComponent = Object.keys(COMPONENT_SELECTORS).find((name) => !(name in COMPOUND_COMPONENTS)); + + if (nonCompoundComponent) { + expect(getPartSelector(nonCompoundComponent, 'any-theme')).toBeUndefined(); + } + }); + + it('should return undefined for unknown compound component', () => { + expect(getPartSelector('__nonexistent_component__', 'any-theme')).toBeUndefined(); + }); + + it('should return undefined for non-existent related theme', () => { + const firstCompound = Object.keys(COMPOUND_COMPONENTS)[0]; + expect(getPartSelector(firstCompound, '__nonexistent_theme__')).toBeUndefined(); + }); + + it('should return undefined for TODO placeholders', () => { + // Find a compound component with a TODO placeholder + const compoundWithTodo = Object.entries(COMPOUND_COMPONENTS).find( + ([, info]) => + info.innerSelectors?.webcomponents && Object.values(info.innerSelectors.webcomponents).includes('TODO'), + ); + + if (compoundWithTodo) { + const [name, info] = compoundWithTodo; + const todoTheme = Object.entries(info.innerSelectors!.webcomponents).find(([, value]) => value === 'TODO')?.[0]; + if (todoTheme) { + expect(getPartSelector(name, todoTheme)).toBeUndefined(); + } + } + }); + + it('should return actual selector when not TODO', () => { + // Find a compound component with a non-TODO selector + const compoundWithSelector = Object.entries(COMPOUND_COMPONENTS).find( + ([, info]) => + info.innerSelectors?.webcomponents && + Object.values(info.innerSelectors.webcomponents).some((v) => v !== 'TODO' && v !== ''), + ); + + if (compoundWithSelector) { + const [name, info] = compoundWithSelector; + const definedTheme = Object.entries(info.innerSelectors!.webcomponents).find( + ([, value]) => value !== 'TODO' && value !== '', + )?.[0]; + if (definedTheme) { + const result = getPartSelector(name, definedTheme); + expect(result).toBeDefined(); + expect(typeof result).toBe('string'); + expect(result).not.toBe('TODO'); + } + } + }); + + it('should not throw for valid compound component and theme', () => { + const firstCompound = Object.keys(COMPOUND_COMPONENTS)[0]; + const firstTheme = COMPOUND_COMPONENTS[firstCompound].relatedThemes[0]; + expect(() => getPartSelector(firstCompound, firstTheme)).not.toThrow(); + }); + }); + + describe('hasPartSelectors()', () => { + it('should return false for non-compound component', () => { + const nonCompoundComponent = Object.keys(COMPONENT_SELECTORS).find((name) => !(name in COMPOUND_COMPONENTS)); + + if (nonCompoundComponent) { + expect(hasPartSelectors(nonCompoundComponent)).toBe(false); + } + }); + + it('should return false for unknown component', () => { + expect(hasPartSelectors('__nonexistent_component__')).toBe(false); + }); + + it('should return boolean for all compound components', () => { + for (const name of Object.keys(COMPOUND_COMPONENTS)) { + const result = hasPartSelectors(name); + expect(typeof result).toBe('boolean'); + } + }); + + it('should return true when any selector is not TODO', () => { + // Find compound with at least one non-TODO selector + const compoundWithSelector = Object.entries(COMPOUND_COMPONENTS).find( + ([, info]) => + info.innerSelectors?.webcomponents && + Object.values(info.innerSelectors.webcomponents).some((v) => v !== 'TODO' && v !== ''), + ); + + if (compoundWithSelector) { + const [name] = compoundWithSelector; + expect(hasPartSelectors(name)).toBe(true); + } + }); + + it('should return false when all selectors are TODO', () => { + // Find compound with all TODO selectors + const compoundAllTodo = Object.entries(COMPOUND_COMPONENTS).find( + ([, info]) => + info.innerSelectors?.webcomponents && + Object.values(info.innerSelectors.webcomponents).length > 0 && + Object.values(info.innerSelectors.webcomponents).every((v) => v === 'TODO'), + ); + + if (compoundAllTodo) { + const [name] = compoundAllTodo; + expect(hasPartSelectors(name)).toBe(false); + } + }); + }); + + describe('getAllPartSelectors()', () => { + it('should return undefined for non-compound component', () => { + const nonCompoundComponent = Object.keys(COMPONENT_SELECTORS).find((name) => !(name in COMPOUND_COMPONENTS)); + + if (nonCompoundComponent) { + expect(getAllPartSelectors(nonCompoundComponent)).toBeUndefined(); + } + }); + + it('should return undefined for unknown component', () => { + expect(getAllPartSelectors('__nonexistent_component__')).toBeUndefined(); + }); + + it('should return object or undefined for compound components', () => { + for (const [name, info] of Object.entries(COMPOUND_COMPONENTS)) { + const result = getAllPartSelectors(name); + if (info.innerSelectors?.webcomponents) { + expect(result).toBeDefined(); + expect(typeof result).toBe('object'); + } else { + expect(result).toBeUndefined(); + } + } + }); + + it('should return all relatedThemes as keys when innerSelectors.webcomponents exists', () => { + for (const [name, info] of Object.entries(COMPOUND_COMPONENTS)) { + if (info.innerSelectors?.webcomponents) { + const result = getAllPartSelectors(name); + expect(result).toBeDefined(); + for (const theme of info.relatedThemes) { + expect(result).toHaveProperty(theme); + } + } + } + }); + }); +}); diff --git a/src/mcp/__tests__/knowledge/component-themes.test.ts b/src/mcp/__tests__/knowledge/component-themes.test.ts new file mode 100644 index 00000000..8d62a48d --- /dev/null +++ b/src/mcp/__tests__/knowledge/component-themes.test.ts @@ -0,0 +1,127 @@ +/** + * Tests for component-themes.ts knowledge base + */ + +import {describe, it, expect} from 'vitest'; +import { + COMPONENT_THEMES, + COMPONENT_NAMES, + getComponentTheme, + getTokenNames, + validateTokens, + searchComponents, +} from '../../knowledge/component-themes.js'; + +describe('Component Themes Knowledge Base', () => { + describe('COMPONENT_THEMES', () => { + it('should contain expected components', () => { + expect(COMPONENT_THEMES).toHaveProperty('avatar'); + expect(COMPONENT_THEMES).toHaveProperty('button'); + expect(COMPONENT_THEMES).toHaveProperty('flat-button'); + expect(COMPONENT_THEMES).toHaveProperty('grid'); + }); + + it('should have correct structure for each component', () => { + const avatar = COMPONENT_THEMES['avatar']; + expect(avatar).toHaveProperty('name', 'avatar'); + expect(avatar).toHaveProperty('themeFunctionName', 'avatar-theme'); + expect(avatar).toHaveProperty('tokens'); + expect(Array.isArray(avatar.tokens)).toBe(true); + }); + + it('should have tokens with correct properties', () => { + const avatar = COMPONENT_THEMES['avatar']; + const token = avatar.tokens.find((t) => t.name === 'background'); + expect(token).toBeDefined(); + expect(token).toHaveProperty('name', 'background'); + expect(token).toHaveProperty('type'); + expect(token).toHaveProperty('description'); + }); + }); + + describe('COMPONENT_NAMES', () => { + it('should be an array of component names', () => { + expect(Array.isArray(COMPONENT_NAMES)).toBe(true); + expect(COMPONENT_NAMES.length).toBeGreaterThan(50); + }); + + it('should include button variants', () => { + expect(COMPONENT_NAMES).toContain('button'); + expect(COMPONENT_NAMES).toContain('flat-button'); + expect(COMPONENT_NAMES).toContain('contained-button'); + expect(COMPONENT_NAMES).toContain('outlined-button'); + expect(COMPONENT_NAMES).toContain('fab-button'); + }); + }); + + describe('getComponentTheme()', () => { + it('should return theme for valid component', () => { + const theme = getComponentTheme('avatar'); + expect(theme).toBeDefined(); + expect(theme?.name).toBe('avatar'); + }); + + it('should return undefined for invalid component', () => { + const theme = getComponentTheme('nonexistent'); + expect(theme).toBeUndefined(); + }); + + it('should be case-sensitive', () => { + // Our normalized comparison should handle this in handlers + const theme = getComponentTheme('Avatar'); + expect(theme).toBeUndefined(); + }); + }); + + describe('getTokenNames()', () => { + it('should return token names for valid component', () => { + const tokens = getTokenNames('avatar'); + expect(tokens).toContain('background'); + expect(tokens).toContain('color'); + }); + + it('should return empty array for invalid component', () => { + const tokens = getTokenNames('nonexistent'); + expect(tokens).toEqual([]); + }); + }); + + describe('validateTokens()', () => { + it('should validate correct tokens', () => { + const result = validateTokens('avatar', ['background', 'color']); + expect(result.isValid).toBe(true); + expect(result.invalidTokens).toEqual([]); + }); + + it('should identify invalid tokens', () => { + const result = validateTokens('avatar', ['background', 'invalid-token']); + expect(result.isValid).toBe(false); + expect(result.invalidTokens).toContain('invalid-token'); + }); + + it('should return valid tokens list', () => { + const result = validateTokens('avatar', ['background']); + expect(result.validTokens).toContain('background'); + expect(result.validTokens).toContain('color'); + }); + }); + + describe('searchComponents()', () => { + it('should find components by partial name', () => { + const results = searchComponents('button'); + expect(results).toContain('button'); + expect(results).toContain('flat-button'); + expect(results).toContain('button-group'); + }); + + it('should return empty array for no matches', () => { + const results = searchComponents('xyz123nonexistent'); + expect(results).toEqual([]); + }); + + it('should be case-insensitive', () => { + const results = searchComponents('AVATAR'); + expect(results).toContain('avatar'); + }); + }); +}); diff --git a/src/mcp/generators/sass.ts b/src/mcp/generators/sass.ts index 7c6e4d1a..6a932f3e 100644 --- a/src/mcp/generators/sass.ts +++ b/src/mcp/generators/sass.ts @@ -15,17 +15,14 @@ import type { GeneratedCode, DesignSystem, ThemeVariant, + Platform, } from '../utils/types.js'; -import { - quoteFontFamily, - generateUseStatement, - toVariableName, - generateHeader, -} from '../utils/sass.js'; +import {quoteFontFamily, generateUseStatement, toVariableName, generateHeader} from '../utils/sass.js'; import { TYPOGRAPHY_PRESETS, generateAngularThemeSass, generateWebComponentsThemeSass, + getComponentTheme, } from '../knowledge/index.js'; // Re-export utilities for external use @@ -169,7 +166,7 @@ export function generateTheme(input: CreateThemeInput): GeneratedCode { function generateAngularTheme( input: CreateThemeInput, designSystem: DesignSystem, - variant: ThemeVariant + variant: ThemeVariant, ): GeneratedCode { const code = generateAngularThemeSass({ designSystem, @@ -208,7 +205,7 @@ function generateAngularTheme( function generateWebComponentsTheme( input: CreateThemeInput, designSystem: DesignSystem, - variant: ThemeVariant + variant: ThemeVariant, ): GeneratedCode { const code = generateWebComponentsThemeSass({ designSystem, @@ -254,7 +251,7 @@ function generateWebComponentsTheme( function generateGenericTheme( input: CreateThemeInput, designSystem: DesignSystem, - variant: ThemeVariant + variant: ThemeVariant, ): GeneratedCode { const themeName = input.name ? toVariableName(input.name) : `${variant}-${designSystem}`; const paletteVar = `$${themeName}-palette`; @@ -320,3 +317,78 @@ function generateGenericTheme( variables, }; } + +// ============================================================================ +// Component Theme Generator +// ============================================================================ + +/** + * Input for generating a component theme. + */ +export interface CreateComponentThemeInput { + /** Target platform */ + platform?: Platform; + /** Component name (e.g., "flat-button", "avatar") */ + component: string; + /** Token name-value pairs */ + tokens: Record; + /** Optional CSS selector to scope the theme */ + selector?: string; + /** Optional custom variable name */ + name?: string; +} + +/** + * Generate Sass code for a component theme. + */ +export function generateComponentTheme(input: CreateComponentThemeInput): GeneratedCode { + const theme = getComponentTheme(input.component); + + if (!theme) { + throw new Error(`Unknown component: ${input.component}`); + } + + const themeFn = theme.themeFunctionName; + const themeName = input.name ? `$${toVariableName(input.name)}` : `$custom-${input.component}-theme`; + + // Build token arguments + const tokenArgs: string[] = []; + for (const [tokenName, value] of Object.entries(input.tokens)) { + // Convert value to string if needed + const stringValue = typeof value === 'number' ? String(value) : value; + tokenArgs.push(`$${tokenName}: ${stringValue}`); + } + + // Determine selector + let selector = input.selector || ':root'; + + // Generate the code + const sections: string[] = [ + generateHeader(`Custom ${input.component} theme`), + generateUseStatement(input.platform), + '', + `// Custom ${input.component} theme`, + `${themeName}: ${themeFn}(`, + ]; + + // Add token arguments with proper indentation + if (tokenArgs.length > 0) { + sections.push(` ${tokenArgs.join(',\n ')}`); + } + sections.push(');'); + + // Add css-vars mixin to apply the theme + sections.push(''); + sections.push(`// Apply the theme to ${selector}`); + sections.push(`${selector} {`); + sections.push(` @include css-vars(${themeName});`); + sections.push('}'); + + const code = sections.join('\n') + '\n'; + + return { + code, + description: `Generated custom ${input.component} theme with ${Object.keys(input.tokens).length} token(s)`, + variables: [themeName], + }; +} diff --git a/src/mcp/index.ts b/src/mcp/index.ts index 8c9a1e4e..8050dbaa 100644 --- a/src/mcp/index.ts +++ b/src/mcp/index.ts @@ -16,12 +16,16 @@ import { createTypographySchema, createElevationsSchema, createThemeSchema, + getComponentDesignTokensSchema, + createComponentThemeSchema, handleDetectPlatform, handleCreatePalette, handleCreateCustomPalette, handleCreateTypography, handleCreateElevations, handleCreateTheme, + handleGetComponentDesignTokens, + handleCreateComponentTheme, } from './tools/index.js'; import {TOOL_DESCRIPTIONS} from './tools/descriptions.js'; @@ -180,6 +184,42 @@ function registerTools(server: McpServer): void { return await handleCreateTheme(validated); }, ); + + // get_component_design_tokens tool + server.registerTool( + 'get_component_design_tokens', + { + title: 'Get Component Design Tokens', + description: TOOL_DESCRIPTIONS.get_component_design_tokens, + inputSchema: { + component: getComponentDesignTokensSchema.shape.component, + }, + }, + async (params) => { + const validated = getComponentDesignTokensSchema.parse(params); + return await handleGetComponentDesignTokens(validated); + }, + ); + + // create_component_theme tool + server.registerTool( + 'create_component_theme', + { + title: 'Create Component Theme', + description: TOOL_DESCRIPTIONS.create_component_theme, + inputSchema: { + platform: createComponentThemeSchema.shape.platform, + component: createComponentThemeSchema.shape.component, + tokens: createComponentThemeSchema.shape.tokens, + selector: createComponentThemeSchema.shape.selector, + name: createComponentThemeSchema.shape.name, + }, + }, + async (params) => { + const validated = createComponentThemeSchema.parse(params); + return await handleCreateComponentTheme(validated); + }, + ); } /** diff --git a/src/mcp/knowledge/component-selectors.ts b/src/mcp/knowledge/component-selectors.ts new file mode 100644 index 00000000..f207956b --- /dev/null +++ b/src/mcp/knowledge/component-selectors.ts @@ -0,0 +1,752 @@ +/** + * Component selectors knowledge base. + * Maps component names to their platform-specific CSS selectors, + * defines component variants, and compound component relationships. + */ + +import type {Platform} from './platforms/index.js'; + +/** + * Platform-specific selectors for a component. + * Use `null` to indicate a component is not available on a platform. + */ +export interface ComponentSelectors { + /** Angular selector(s) - can be single string, array, or null if not available on Angular */ + angular: string | string[] | null; + /** Web Components selector(s) - can be single string, array, or null if not available on Web Components */ + webcomponents: string | string[] | null; +} + +/** + * Platform-specific inner selectors for targeting related themes within a compound component. + * These ensure themes are scoped to the compound component context, not applied globally. + */ +export interface CompoundInnerSelectors { + /** + * Angular scoped selectors for styling related themes within this compound component. + * Maps related theme name to the scoped selector (e.g., 'igx-combo igx-checkbox'). + * Use 'TODO' as placeholder for selectors that need to be filled in. + */ + angular: Record; + /** + * Web Components ::part() selectors for styling related themes within this compound component. + * Maps related theme name to the full selector including ::part(). + * Example: { 'drop-down': 'igc-combo::part(list)' } + * Use 'TODO' as placeholder for selectors that need to be filled in. + */ + webcomponents: Record; +} + +/** + * Information about a compound component (one that contains multiple themeable sub-components). + */ +export interface CompoundComponentInfo { + /** Description of what the compound component contains */ + description: string; + /** Related theme functions needed for full customization */ + relatedThemes: string[]; + /** + * Platform-specific inner selectors for targeting related themes within this compound component. + * These ensure themes are scoped to the compound component context, not applied globally. + */ + innerSelectors?: CompoundInnerSelectors; +} + +/** + * CSS selectors for each component by platform. + * Used to scope component themes to specific elements. + */ +export const COMPONENT_SELECTORS: Record = { + // Basic components + 'action-strip': { + angular: 'igx-action-strip', + webcomponents: null, + }, + avatar: { + angular: 'igx-avatar', + webcomponents: 'igc-avatar', + }, + badge: { + angular: 'igx-badge', + webcomponents: 'igc-badge', + }, + banner: { + angular: 'igx-banner', + webcomponents: 'igc-banner', + }, + 'bottom-nav': { + angular: 'igx-bottom-nav', + webcomponents: 'igc-bottom-nav', + }, + button: { + angular: '.igx-button', + webcomponents: 'igc-button', + }, + 'flat-button': { + angular: '.igx-button--flat', + webcomponents: 'igc-button[variant="flat"]', + }, + 'contained-button': { + angular: ['.igx-button--contained'], + webcomponents: 'igc-button[variant="contained"]', + }, + 'outlined-button': { + angular: ['.igx-button--outlined'], + webcomponents: 'igc-button[variant="outlined"]', + }, + 'fab-button': { + angular: ['.igx-button--fab'], + webcomponents: 'igc-button[variant="fab"]', + }, + 'icon-button': { + angular: ['.igx-icon-button'], + webcomponents: 'igc-icon-button', + }, + 'flat-icon-button': { + angular: ['.igx-icon-button--flat'], + webcomponents: 'igc-icon-button[variant="flat"]', + }, + 'contained-icon-button': { + angular: ['.igx-icon-button--contained'], + webcomponents: 'igc-icon-button[variant="contained"]', + }, + 'outlined-icon-button': { + angular: ['.igx-icon-button--outlined'], + webcomponents: 'igc-icon-button[variant="outlined"]', + }, + 'button-group': { + angular: 'igx-buttongroup', + webcomponents: 'igc-button-group', + }, + calendar: { + angular: 'igx-calendar', + webcomponents: 'igc-calendar', + }, + card: { + angular: 'igx-card', + webcomponents: 'igc-card', + }, + carousel: { + angular: 'igx-carousel', + webcomponents: 'igc-carousel', + }, + chat: { + angular: 'igx-chat', + webcomponents: 'igc-chat', + }, + checkbox: { + angular: 'igx-checkbox', + webcomponents: 'igc-checkbox', + }, + chip: { + angular: 'igx-chip', + webcomponents: 'igc-chip', + }, + 'column-actions': { + angular: 'igx-column-actions', + webcomponents: null, + }, + combo: { + angular: 'igx-combo', + webcomponents: 'igc-combo', + }, + 'date-picker': { + angular: 'igx-date-picker', + webcomponents: 'igc-date-picker', + }, + 'date-range-picker': { + angular: 'igx-date-range-picker', + webcomponents: 'igc-date-range-picker', + }, + dialog: { + angular: 'igx-dialog', + webcomponents: 'igc-dialog', + }, + divider: { + angular: 'igx-divider', + webcomponents: null, + }, + 'dock-manager': { + angular: 'igc-dockmanager', + webcomponents: 'igc-dockmanager', + }, + 'drop-down': { + angular: '.igx-drop-down__list', + webcomponents: 'igc-dropdown', + }, + 'expansion-panel': { + angular: 'igx-expansion-panel', + webcomponents: 'igc-expansion-panel', + }, + 'file-input': { + angular: 'igx-input-group[class~="igx-input-group--file"]', + webcomponents: 'igc-file-input', + }, + grid: { + angular: ['igx-grid', 'igx-tree-grid', 'igx-hierarchical-grid', 'igx-pivot-grid'], + webcomponents: ['igc-grid', 'igc-tree-grid', 'igc-hierarchical-grid', 'igc-pivot-grid'], + }, + 'grid-summary': { + angular: 'igx-grid-summary', + webcomponents: 'igc-grid-summary', + }, + 'grid-toolbar': { + angular: 'igx-grid-toolbar', + webcomponents: 'igc-grid-toolbar', + }, + highlight: { + angular: 'igx-highlight', + webcomponents: 'igc-highlight', + }, + icon: { + angular: 'igx-icon', + webcomponents: 'igc-icon', + }, + 'input-group': { + angular: 'igx-input-group', + webcomponents: 'igc-input', + }, + label: { + angular: '[igxLabel]', + webcomponents: 'igc-label', + }, + list: { + angular: 'igx-list', + webcomponents: 'igc-list', + }, + navbar: { + angular: 'igx-navbar', + webcomponents: 'igc-navbar', + }, + navdrawer: { + angular: 'igx-nav-drawer', + webcomponents: 'igc-nav-drawer', + }, + overlay: { + angular: '.igx-overlay__content', + webcomponents: null, + }, + paginator: { + angular: 'igx-paginator', + webcomponents: 'igc-paginator', + }, + 'pivot-data-selector': { + angular: 'igx-pivot-data-selector', + webcomponents: 'igc-pivot-data-selector', + }, + 'progress-circular': { + angular: 'igx-circular-bar', + webcomponents: 'igc-circular-progress', + }, + 'progress-linear': { + angular: 'igx-linear-bar', + webcomponents: 'igc-linear-progress', + }, + 'query-builder': { + angular: 'igx-query-builder', + webcomponents: null, + }, + radio: { + angular: 'igx-radio', + webcomponents: 'igc-radio', + }, + rating: { + angular: 'igx-rating', + webcomponents: 'igc-rating', + }, + ripple: { + angular: 'igx-ripple', + webcomponents: 'igc-ripple', + }, + scrollbar: { + angular: '.ig-scrollbar', + webcomponents: '.ig-scrollbar', + }, + select: { + angular: 'igx-select', + webcomponents: 'igc-select', + }, + slider: { + angular: 'igx-slider', + webcomponents: 'igc-slider', + }, + snackbar: { + angular: 'igx-snackbar', + webcomponents: 'igc-snackbar', + }, + splitter: { + angular: 'igx-splitter', + webcomponents: 'igc-splitter', + }, + stepper: { + angular: 'igx-stepper', + webcomponents: 'igc-stepper', + }, + switch: { + angular: 'igx-switch', + webcomponents: 'igc-switch', + }, + tabs: { + angular: 'igx-tabs', + webcomponents: 'igc-tabs', + }, + 'time-picker': { + angular: 'igx-time-picker', + webcomponents: 'igc-date-time-input', + }, + toast: { + angular: 'igx-toast', + webcomponents: 'igc-toast', + }, + tooltip: { + angular: 'igx-tooltip', + webcomponents: 'igc-tooltip', + }, + tree: { + angular: 'igx-tree', + webcomponents: 'igc-tree', + }, + watermark: { + angular: 'igc-trial-watermark', + webcomponents: 'igc-trial-watermark', + }, +}; + +/** + * Components that have variant-specific theme functions. + * Maps the base component to its themed variants. + */ +export const COMPONENT_VARIANTS: Record = { + button: ['flat-button', 'contained-button', 'outlined-button', 'fab-button'], + 'icon-button': ['flat-icon-button', 'contained-icon-button', 'outlined-icon-button'], +}; + +/** + * List of variant theme names (for quick lookup). + */ +export const VARIANT_THEME_NAMES = new Set(Object.values(COMPONENT_VARIANTS).flat()); + +/** + * Compound components that require theming multiple sub-components for full customization. + */ +export const COMPOUND_COMPONENTS: Record = { + combo: { + description: + 'The combo component uses an input-group for the input field, a drop-down for the selection list, and checkboxes for showing selected items.', + relatedThemes: ['input-group', 'drop-down', 'checkbox'], + innerSelectors: { + angular: { + 'input-group': 'igx-combo igx-input-group', + 'drop-down': '.igx-drop-down__list', + checkbox: 'igx-combo-item igx-checkbox', + }, + webcomponents: { + 'input-group': 'igc-combo::part(input)', + 'drop-down': 'igc-combo::part(list)', + checkbox: 'igc-combo-item::part(checkbox)', + }, + }, + }, + select: { + description: 'The select component uses an input-group for the display and a drop-down for the options list.', + relatedThemes: ['input-group', 'drop-down'], + innerSelectors: { + angular: { + 'input-group': 'igx-select igx-input-group', + 'drop-down': '.igx-drop-down__list', + }, + webcomponents: { + 'input-group': 'igc-select::part(input)', + 'drop-down': 'igc-select', + }, + }, + }, + 'date-picker': { + description: 'The date picker combines input-group and calendar components.', + relatedThemes: ['input-group', 'calendar'], + innerSelectors: { + angular: { + 'input-group': 'igx-date-picker igx-input-group', + calendar: 'igx-date-picker igx-calendar', + }, + webcomponents: { + 'input-group': 'igc-date-picker::part(input)', + calendar: 'igc-date-picker igc-calendar', + }, + }, + }, + 'date-range-picker': { + description: 'The date range picker combines input-group and calendar components.', + relatedThemes: ['input-group', 'calendar'], + innerSelectors: { + angular: { + 'input-group': 'igx-date-range-picker igx-date-range-start, igx-date-picker igx-date-range-end', + calendar: 'igx-date-range-picker igx-calendar', + }, + webcomponents: { + 'input-group': 'igc-date-range-picker::part(input)', + calendar: 'igc-date-range-picker igc-calendar', + }, + }, + }, + 'time-picker': { + description: 'The time picker uses input-group internally.', + relatedThemes: ['input-group'], + innerSelectors: { + angular: { + 'input-group': 'igx-time-picker igx-input-group', + }, + webcomponents: { + 'input-group': 'igc-date-time-input', + }, + }, + }, + grid: { + description: + 'The grid is a complex compound component with many themeable parts including filtering, editing, and selection.', + relatedThemes: [ + 'checkbox', + 'chip', + 'input-group', + 'drop-down', + 'button', + 'icon-button', + 'calendar', + 'snackbar', + 'paginator', + 'grid-summary', + 'grid-toolbar', + ], + innerSelectors: { + angular: { + checkbox: 'igx-grid igx-checkbox', + chip: 'igx-grid igx-chip', + 'input-group': 'igx-grid igx-input-group', + 'drop-down': 'igx-grid .igx-drop-down', + button: 'igx-grid .igx-button', + 'icon-button': 'igx-grid .igx-icon-button', + calendar: 'igx-grid igx-calendar', + snackbar: 'igx-grid igx-snackbar', + paginator: 'igx-grid igx-paginator', + 'grid-summary': 'igx-grid igx-grid-summary-cell', + 'grid-toolbar': 'igx-grid igx-grid-toolbar', + }, + webcomponents: { + checkbox: 'TODO', + chip: 'TODO', + 'input-group': 'TODO', + 'drop-down': 'TODO', + button: 'TODO', + 'icon-button': 'TODO', + calendar: 'TODO', + snackbar: 'TODO', + paginator: 'TODO', + 'grid-summary': 'TODO', + 'grid-toolbar': 'TODO', + }, + }, + }, + 'query-builder': { + description: + 'The query builder uses inputs, dropdowns, chips, and buttons, and button-groups for building query expressions.', + relatedThemes: ['input-group', 'drop-down', 'chip', 'button', 'button-group', 'icon-button'], + innerSelectors: { + angular: { + 'input-group': 'igx-query-builder igx-input-group', + 'drop-down': 'igx-query-builder .igx-drop-down', + chip: 'igx-query-builder igx-chip', + button: 'igx-query-builder .igx-button', + 'button-group': 'igx-query-builder igx-buttongroup', + 'icon-button': 'igx-query-builder .igx-icon-button', + }, + webcomponents: { + 'input-group': 'TODO', + 'drop-down': 'TODO', + chip: 'TODO', + button: 'TODO', + 'button-group': 'TODO', + 'icon-button': 'TODO', + }, + }, + }, + 'pivot-data-selector': { + description: 'The pivot data selector uses checkboxes, expansion panels, lists, and chips.', + relatedThemes: ['checkbox', 'expansion-panel', 'chip', 'list'], + innerSelectors: { + angular: { + checkbox: 'igx-pivot-data-selector igx-checkbox', + 'expansion-panel': 'igx-pivot-data-selector igx-expansion-panel', + chip: 'igx-pivot-data-selector igx-chip', + list: 'igx-pivot-data-selector igx-list', + }, + webcomponents: { + checkbox: 'TODO', + 'expansion-panel': 'TODO', + chip: 'TODO', + list: 'TODO', + }, + }, + }, +}; + +/** + * Get the selector(s) for a component on a specific platform. + * @param componentName - The component name + * @param platform - The target platform + * @returns Array of selectors (normalized to always return array), empty array if component not found or not available on platform + */ +export function getComponentSelector(componentName: string, platform: Platform): string[] { + const selectors = COMPONENT_SELECTORS[componentName]; + if (!selectors) { + return []; + } + + const platformSelectors = platform === 'angular' ? selectors.angular : selectors.webcomponents; + + // Return empty array if component is not available on this platform + if (platformSelectors === null) { + return []; + } + + return Array.isArray(platformSelectors) ? platformSelectors : [platformSelectors]; +} + +/** + * Check if a component is available on a specific platform. + * @param componentName - The component name + * @param platform - The target platform ('angular' or 'webcomponents') + * @returns True if the component is available on the platform, false otherwise + */ +export function isComponentAvailable(componentName: string, platform: Platform): boolean { + const selectors = COMPONENT_SELECTORS[componentName]; + if (!selectors) { + return false; + } + + const platformSelector = platform === 'angular' ? selectors.angular : selectors.webcomponents; + return platformSelector !== null; +} + +/** + * Get all component names available on a specific platform. + * @param platform - The target platform ('angular' or 'webcomponents') + * @returns Array of component names available on the platform + */ +export function getComponentsForPlatform(platform: Platform): string[] { + return Object.entries(COMPONENT_SELECTORS) + .filter(([, selectors]) => { + const platformSelector = platform === 'angular' ? selectors.angular : selectors.webcomponents; + return platformSelector !== null; + }) + .map(([name]) => name); +} + +/** + * Get platform availability for a component. + * @param componentName - The component name + * @returns Object indicating availability on each platform, or undefined if component not found + */ +export function getComponentPlatformAvailability( + componentName: string, +): {angular: boolean; webcomponents: boolean} | undefined { + const selectors = COMPONENT_SELECTORS[componentName]; + if (!selectors) { + return undefined; + } + + return { + angular: selectors.angular !== null, + webcomponents: selectors.webcomponents !== null, + }; +} + +/** + * Check if a component has variants. + * @param componentName - The component name (e.g., 'button') + * @returns True if the component has variant-specific themes + */ +export function hasVariants(componentName: string): boolean { + return componentName in COMPONENT_VARIANTS; +} + +/** + * Get variants for a component. + * @param componentName - The component name (e.g., 'button') + * @returns Array of variant names or empty array + */ +export function getVariants(componentName: string): string[] { + return COMPONENT_VARIANTS[componentName] ?? []; +} + +/** + * Check if a component name is a variant theme. + * @param themeName - The theme name to check + * @returns True if this is a variant theme (e.g., 'flat-button') + */ +export function isVariantTheme(themeName: string): boolean { + return VARIANT_THEME_NAMES.has(themeName); +} + +/** + * Get compound component info if applicable. + * @param componentName - The component name + * @returns Compound info or undefined + */ +export function getCompoundComponentInfo(componentName: string): CompoundComponentInfo | undefined { + return COMPOUND_COMPONENTS[componentName]; +} + +/** + * Check if a component is a compound component. + * @param componentName - The component name + * @returns True if this is a compound component + */ +export function isCompoundComponent(componentName: string): boolean { + return componentName in COMPOUND_COMPONENTS; +} + +/** + * Get the Web Components ::part() selector for a related theme within a compound component. + * @param compoundComponent - The compound component name (e.g., 'combo') + * @param relatedTheme - The related theme name (e.g., 'drop-down') + * @returns The ::part() selector string, or undefined if not found/not applicable/still TODO + */ +export function getPartSelector(compoundComponent: string, relatedTheme: string): string | undefined { + const info = COMPOUND_COMPONENTS[compoundComponent]; + + if (!info?.innerSelectors?.webcomponents) { + return undefined; + } + + const selector = info.innerSelectors.webcomponents[relatedTheme]; + // Return undefined for TODO placeholders + if (!selector || selector === 'TODO') { + return undefined; + } + + return selector; +} + +/** + * Get the Angular scoped selector for a related theme within a compound component. + * @param compoundComponent - The compound component name (e.g., 'combo') + * @param relatedTheme - The related theme name (e.g., 'checkbox') + * @returns The scoped selector string (e.g., 'igx-combo igx-checkbox'), or undefined if not found/still TODO + */ +export function getAngularInnerSelector(compoundComponent: string, relatedTheme: string): string | undefined { + const info = COMPOUND_COMPONENTS[compoundComponent]; + + if (!info?.innerSelectors?.angular) { + return undefined; + } + + const selector = info.innerSelectors.angular[relatedTheme]; + // Return undefined for TODO placeholders + if (!selector || selector === 'TODO') { + return undefined; + } + + return selector; +} + +/** + * Get the inner selector for a related theme within a compound component for a specific platform. + * @param compoundComponent - The compound component name (e.g., 'combo') + * @param relatedTheme - The related theme name (e.g., 'checkbox') + * @param platform - The target platform ('angular' or 'webcomponents') + * @returns The selector string, or undefined if not found/still TODO + */ +export function getInnerSelector( + compoundComponent: string, + relatedTheme: string, + platform: Platform, +): string | undefined { + return platform === 'angular' + ? getAngularInnerSelector(compoundComponent, relatedTheme) + : getPartSelector(compoundComponent, relatedTheme); +} + +/** + * Check if a compound component has Web Components part selectors defined (non-TODO values). + * @param compoundComponent - The compound component name + * @returns True if innerSelectors.webcomponents is defined and has at least one non-TODO value + */ +export function hasPartSelectors(compoundComponent: string): boolean { + const info = COMPOUND_COMPONENTS[compoundComponent]; + + if (!info?.innerSelectors?.webcomponents) { + return false; + } + + return Object.values(info.innerSelectors.webcomponents).some((v) => v !== 'TODO'); +} + +/** + * Check if a compound component has Angular inner selectors defined (non-TODO values). + * @param compoundComponent - The compound component name + * @returns True if innerSelectors.angular is defined and has at least one non-TODO value + */ +export function hasAngularInnerSelectors(compoundComponent: string): boolean { + const info = COMPOUND_COMPONENTS[compoundComponent]; + + if (!info?.innerSelectors?.angular) { + return false; + } + + return Object.values(info.innerSelectors.angular).some((v) => v !== 'TODO'); +} + +/** + * Check if a compound component has inner selectors defined for a specific platform. + * @param compoundComponent - The compound component name + * @param platform - The target platform ('angular' or 'webcomponents') + * @returns True if inner selectors are defined and has at least one non-TODO value + */ +export function hasInnerSelectors(compoundComponent: string, platform: Platform): boolean { + return platform === 'angular' ? hasAngularInnerSelectors(compoundComponent) : hasPartSelectors(compoundComponent); +} + +/** + * Get all Web Components part selectors for a compound component. + * @param compoundComponent - The compound component name + * @returns Record of related theme to selector, or undefined if not a compound component + */ +export function getAllPartSelectors(compoundComponent: string): Record | undefined { + const info = COMPOUND_COMPONENTS[compoundComponent]; + + if (!info?.innerSelectors?.webcomponents) { + return undefined; + } + + return info.innerSelectors.webcomponents; +} + +/** + * Get all Angular inner selectors for a compound component. + * @param compoundComponent - The compound component name + * @returns Record of related theme to selector, or undefined if not a compound component + */ +export function getAllAngularInnerSelectors(compoundComponent: string): Record | undefined { + const info = COMPOUND_COMPONENTS[compoundComponent]; + + if (!info?.innerSelectors?.angular) { + return undefined; + } + + return info.innerSelectors.angular; +} + +/** + * Get all inner selectors for a compound component for a specific platform. + * @param compoundComponent - The compound component name + * @param platform - The target platform ('angular' or 'webcomponents') + * @returns Record of related theme to selector, or undefined if not a compound component + */ +export function getAllInnerSelectors( + compoundComponent: string, + platform: Platform, +): Record | undefined { + return platform === 'angular' + ? getAllAngularInnerSelectors(compoundComponent) + : getAllPartSelectors(compoundComponent); +} diff --git a/src/mcp/knowledge/component-themes.ts b/src/mcp/knowledge/component-themes.ts new file mode 100644 index 00000000..0fa09042 --- /dev/null +++ b/src/mcp/knowledge/component-themes.ts @@ -0,0 +1,91 @@ +/** + * Component themes knowledge base - loads component theme data from JSON. + * This provides the LLM with accurate design tokens for each component. + */ + +import themesData from '../../../json/components/themes.json' with {type: 'json'}; + +/** + * Represents a design token (themeable property) for a component. + */ +export interface ComponentToken { + /** Token name (e.g., 'background', 'border-color') */ + name: string; + /** Sass type (e.g., 'Color', 'Number', 'List', 'box-shadow') */ + type: string; + /** Description of what this token controls */ + description: string; +} + +/** + * Represents a component theme definition. + */ +export interface ComponentTheme { + /** Component name (e.g., 'button', 'avatar') */ + name: string; + /** The Sass function name (e.g., 'button-theme', 'avatar-theme') */ + themeFunctionName: string; + /** Description of the theme function */ + description: string; + /** Available design tokens */ + tokens: ComponentToken[]; +} + +/** + * All component themes loaded from JSON. + */ +export const COMPONENT_THEMES = themesData as Record; + +/** + * List of all available component names. + */ +export const COMPONENT_NAMES = Object.keys(COMPONENT_THEMES); + +/** + * Get a component theme by name. + * @param componentName - The component name (e.g., 'button', 'avatar') + * @returns The component theme or undefined if not found + */ +export function getComponentTheme(componentName: string): ComponentTheme | undefined { + return COMPONENT_THEMES[componentName]; +} + +/** + * Get the token names for a component. + * @param componentName - The component name + * @returns Array of token names or empty array if component not found + */ +export function getTokenNames(componentName: string): string[] { + const theme = getComponentTheme(componentName); + return theme ? theme.tokens.map((t) => t.name) : []; +} + +/** + * Validate that all provided tokens exist for a component. + * @param componentName - The component name + * @param tokenNames - Array of token names to validate + * @returns Object with isValid flag and any invalid tokens + */ +export function validateTokens( + componentName: string, + tokenNames: string[], +): {isValid: boolean; invalidTokens: string[]; validTokens: string[]} { + const validTokens = getTokenNames(componentName); + const invalidTokens = tokenNames.filter((name) => !validTokens.includes(name)); + + return { + isValid: invalidTokens.length === 0, + invalidTokens, + validTokens, + }; +} + +/** + * Find components that match a search query. + * @param query - Search string to match against component names + * @returns Array of matching component names + */ +export function searchComponents(query: string): string[] { + const lowerQuery = query.toLowerCase(); + return COMPONENT_NAMES.filter((name) => name.toLowerCase().includes(lowerQuery)); +} diff --git a/src/mcp/knowledge/index.ts b/src/mcp/knowledge/index.ts index 91accd16..68352107 100644 --- a/src/mcp/knowledge/index.ts +++ b/src/mcp/knowledge/index.ts @@ -126,5 +126,47 @@ export { TYPEFACES as TYPEFACE_PRESETS, TYPE_SCALES as TYPE_SCALE_PRESETS, PALETTES as PALETTES_PRESETS, - ELEVATIONS as ELEVATIONS_PRESETS + ELEVATIONS as ELEVATIONS_PRESETS, } from './platforms/common.js'; + +// Component Themes +export { + type ComponentToken, + type ComponentTheme, + COMPONENT_THEMES, + COMPONENT_NAMES, + getComponentTheme, + getTokenNames, + validateTokens, + searchComponents, +} from './component-themes.js'; + +// Component Selectors +export { + type ComponentSelectors, + type CompoundComponentInfo, + type CompoundInnerSelectors, + COMPONENT_SELECTORS, + COMPONENT_VARIANTS, + VARIANT_THEME_NAMES, + COMPOUND_COMPONENTS, + getComponentSelector, + hasVariants, + getVariants, + isVariantTheme, + getCompoundComponentInfo, + isCompoundComponent, + getPartSelector, + getAngularInnerSelector, + getInnerSelector, + hasPartSelectors, + hasAngularInnerSelectors, + hasInnerSelectors, + getAllPartSelectors, + getAllAngularInnerSelectors, + getAllInnerSelectors, + // Platform availability + isComponentAvailable, + getComponentsForPlatform, + getComponentPlatformAvailability, +} from './component-selectors.js'; diff --git a/src/mcp/tools/descriptions.ts b/src/mcp/tools/descriptions.ts index 22ca0adb..05fbdfab 100644 --- a/src/mcp/tools/descriptions.ts +++ b/src/mcp/tools/descriptions.ts @@ -536,6 +536,157 @@ export const TOOL_DESCRIPTIONS = { - theming://platforms/react: React platform configuration - theming://platforms/blazor: Blazor platform configuration `, + + // --------------------------------------------------------------------------- + // get_component_design_tokens - Discovery tool + // --------------------------------------------------------------------------- + get_component_design_tokens: `Discover available design tokens (themeable properties) for an Ignite UI component. + + + ALWAYS call this tool FIRST before using create_component_theme. It returns the + exact token names that can be customized for a component, preventing hallucination + of invalid property names. + + + + 1. Provide the component name (e.g., "button", "avatar", "grid") + 2. Receive list of all available tokens with their types and descriptions + 3. Use the token names in create_component_theme + + + + COMPONENT NAMING: + - Basic components: Use simple names like "avatar", "badge", "card" + - Button variants: Use specific variant names like "flat-button", "contained-button", + "outlined-button", "fab-button" (NOT just "button") + - Icon button variants: "flat-icon-button", "contained-icon-button", "outlined-icon-button" + + COMPOUND COMPONENTS: + - Some components like "combo", "grid", "select" are compound - they use multiple + internal components that may also need theming + - The response includes hints about related themes for compound components + + VARIANTS INFO: + - If you query a base component that has variants (e.g., "button"), the response + lists available variants to help you choose the right one + + + + Returns: + - component: The component name + - themeFunctionName: The Sass function to use (e.g., "button-theme") + - description: Information about the component theme + - tokens: Array of { name, type, description } for each available token + - variants: (if applicable) List of variant-specific theme names + - compoundInfo: (if applicable) Related themes for compound components + + + + - Unknown component: Returns list of similar component names as suggestions + - Partial match: If query partially matches multiple components, returns all matches + + + + Get tokens for flat button: + { + "component": "flat-button" + } + + Returns tokens like: background, foreground, hover-background, border-radius, etc. + + + + - create_component_theme: Use the discovered tokens to create a custom theme +`, + + // --------------------------------------------------------------------------- + // create_component_theme - Theme generation tool + // --------------------------------------------------------------------------- + create_component_theme: `Generate Sass code to customize an Ignite UI component's appearance using design tokens. + + + Use this tool AFTER calling get_component_design_tokens to customize specific + component styles. The generated code can be included in your theme file to + override default component appearances. + + + + 1. First call get_component_design_tokens to discover available tokens + 2. Choose which tokens to customize based on your design requirements + 3. Call this tool with component name and token values + 4. Receive ready-to-use Sass code with the component theme + + + + TOKEN VALIDATION: + - All provided token names are validated against the component's schema + - Invalid tokens return an error with the list of valid token names + - You don't need to specify all tokens - only those you want to customize + + TOKEN VALUE FORMATS: + - Colors: Any valid CSS color format (hex, rgb, hsl, named colors) + - Dimensions: Include units (e.g., "8px", "0.5rem", "2em") + - Border radius: Can be single value or shorthand ("8px" or "8px 8px 0 0") + - Shadows: Full box-shadow syntax ("0 2px 4px rgba(0,0,0,0.1)") + + SELECTORS: + - Default selector is auto-detected based on platform and component + - Angular: Uses "igx-*" element selectors or attribute selectors + - Web Components: Uses "igc-*" element selectors + - Custom selectors supported for targeted styling (e.g., ".my-button") + + + + Returns: + - Generated Sass code with: + - Platform-specific @use import + - Theme function call with provided token values + - css-vars mixin to apply the theme to the selector + - Description of what was generated + - List of tokens used + + + + - Unknown component: Returns error with list of available components + - Invalid tokens: Returns error listing invalid tokens and valid alternatives + - Invalid color format: Returns error with format guidance + + + + Custom blue flat button with rounded corners (Angular): + { + "platform": "angular", + "component": "flat-button", + "tokens": { + "background": "#1976D2", + "foreground": "#FFFFFF", + "hover-background": "#1565C0", + "border-radius": "24px" + } + } + + Generates: + \`\`\`scss + @use 'igniteui-angular/theming' as *; + + $custom-flat-button-theme: flat-button-theme( + $background: #1976D2, + $foreground: #FFFFFF, + $hover-background: #1565C0, + $border-radius: 24px + ); + + :root { + @include css-vars($custom-flat-button-theme); + } + \`\`\` + + + + - get_component_design_tokens: MUST call first to discover valid tokens + - detect_platform: Run to auto-detect platform for correct imports + - create_theme: Use for full theme (palette + typography + elevations) +`, } as const; // ============================================================================ @@ -613,4 +764,17 @@ Important: Gray progression is INVERTED for dark themes (50=darkest, 900=lightes grayShades: `Object with all gray shade values. ${FRAGMENTS.GRAY_SHADES}. For light themes: 50=lightest, 900=darkest. For dark themes: 50=darkest, 900=lightest.`, contrastOverrides: `USUALLY OMIT THIS FIELD. Contrast colors are auto-generated using adaptive-contrast(). Only provide this if you have specific accessibility requirements with exact contrast values (rare). When omitted (recommended), the generated Sass code automatically includes adaptive-contrast(#shadeColor) for each shade, which auto-selects black or white for optimal readability.`, + + // --------------------------------------------------------------------------- + // Component theming parameters + // --------------------------------------------------------------------------- + component: `Component name to get design tokens for (e.g., "button", "avatar", "grid"). Use exact names like "flat-button" for button variants. Call this tool to discover available tokens BEFORE using create_component_theme.`, + + componentTheme: `Component name to theme (e.g., "button", "avatar", "flat-button", "grid"). Must match a valid component from get_component_design_tokens. For button/icon-button variants, use specific names like "flat-button", "contained-button", "outlined-button", "fab-button".`, + + tokens: `Object mapping token names to values. Token names must be valid for the component (use get_component_design_tokens to discover them). Values can be CSS colors, dimensions with units, or other Sass-compatible values. Example: { "background": "#1976D2", "border-radius": "8px" }`, + + selector: `Optional CSS selector to scope the theme. If omitted, uses the platform's default selector for the component. For Angular: "igx-*" selectors, for Web Components: "igc-*" selectors. You can specify custom selectors like ".my-custom-button" for targeted styling.`, + + themeName: `Optional name for the generated theme variable (without $ prefix). If omitted, auto-generates based on component name (e.g., "$custom-button-theme").`, } as const; diff --git a/src/mcp/tools/handlers/component-theme.ts b/src/mcp/tools/handlers/component-theme.ts new file mode 100644 index 00000000..17c4d594 --- /dev/null +++ b/src/mcp/tools/handlers/component-theme.ts @@ -0,0 +1,173 @@ +/** + * Handler for create_component_theme tool. + * Generates Sass code to customize a component's appearance. + */ + +import {generateComponentTheme} from '../../generators/sass.js'; +import { + getComponentTheme, + validateTokens, + COMPONENT_NAMES, + searchComponents, + getComponentSelector, + isComponentAvailable, + getComponentPlatformAvailability, +} from '../../knowledge/index.js'; +import type {CreateComponentThemeParams} from '../schemas.js'; + +export async function handleCreateComponentTheme(params: CreateComponentThemeParams) { + const {platform, component, tokens, selector, name} = params; + const normalizedComponent = component.toLowerCase().trim(); + + // Validate component exists + const theme = getComponentTheme(normalizedComponent); + if (!theme) { + const suggestions = searchComponents(normalizedComponent); + const componentList = suggestions.length > 0 ? suggestions.slice(0, 10) : COMPONENT_NAMES.slice(0, 15); + + return { + content: [ + { + type: 'text' as const, + text: `**Error:** Component "${component}" not found. + +${suggestions.length > 0 ? '**Similar components:**' : '**Available components:**'} +${componentList.map((c) => `- ${c}`).join('\n')} + +**Tip:** Use \`get_component_design_tokens\` first to discover valid component names and their tokens.`, + }, + ], + isError: true, + }; + } + + // Check platform availability if platform is specified + let platformWarning: string | null = null; + if (platform) { + const isAvailable = isComponentAvailable(normalizedComponent, platform); + if (!isAvailable) { + const availability = getComponentPlatformAvailability(normalizedComponent); + const availablePlatforms: string[] = []; + if (availability?.angular) availablePlatforms.push('Angular'); + if (availability?.webcomponents) availablePlatforms.push('Web Components'); + + platformWarning = `**Warning:** The \`${component}\` component is not available on ${platform === 'angular' ? 'Ignite UI for Angular' : 'Ignite UI for Web Components'}. ${availablePlatforms.length > 0 ? `It is available on: ${availablePlatforms.join(', ')}.` : ''}`; + } + } + + // Validate tokens + const tokenNames = Object.keys(tokens); + if (tokenNames.length === 0) { + return { + content: [ + { + type: 'text' as const, + text: `**Error:** No tokens provided. At least one token must be specified. + +Use \`get_component_design_tokens\` with component "${component}" to see available tokens.`, + }, + ], + isError: true, + }; + } + + const validation = validateTokens(normalizedComponent, tokenNames); + if (!validation.isValid) { + return { + content: [ + { + type: 'text' as const, + text: `**Error:** Invalid token(s) for component "${component}": +${validation.invalidTokens.map((t) => `- \`${t}\``).join('\n')} + +**Valid tokens for ${component}:** +${validation.validTokens + .slice(0, 20) + .map((t) => `- \`${t}\``) + .join('\n')}${validation.validTokens.length > 20 ? `\n... and ${validation.validTokens.length - 20} more` : ''} + +Use \`get_component_design_tokens\` to see all tokens with descriptions.`, + }, + ], + isError: true, + }; + } + + // Determine the selector + let finalSelector = selector; + if (!finalSelector && platform) { + // Get platform-specific default selector + const selectors = getComponentSelector(normalizedComponent, platform); + if (selectors.length > 0) { + // Use the first selector as default + finalSelector = selectors[0]; + } + } + + // Generate the Sass code + try { + const result = generateComponentTheme({ + platform, + component: normalizedComponent, + tokens, + selector: finalSelector, + name, + }); + + // Build response + const responseParts: string[] = []; + + // Add platform warning if applicable (before the main content) + if (platformWarning) { + responseParts.push(platformWarning); + responseParts.push(''); + } + + responseParts.push(result.description); + responseParts.push(''); + + // Platform info + const platformNote = platform + ? `Platform: ${platform === 'angular' ? 'Ignite UI for Angular' : `Ignite UI for ${platform.charAt(0).toUpperCase() + platform.slice(1)}`}` + : 'Platform: Not specified (generic output). Specify `platform` for optimized imports.'; + responseParts.push(platformNote); + + // Selector info + if (finalSelector) { + responseParts.push(`Selector: \`${finalSelector}\``); + } + + responseParts.push(''); + responseParts.push(`Variables created: ${result.variables.join(', ')}`); + responseParts.push(''); + responseParts.push('```scss'); + responseParts.push(result.code.trimEnd()); + responseParts.push('```'); + + // Add usage hint + responseParts.push(''); + responseParts.push('---'); + responseParts.push( + '**Usage:** Import this Sass file in your main styles file, or include the code in your theme file.', + ); + + return { + content: [ + { + type: 'text' as const, + text: responseParts.join('\n'), + }, + ], + }; + } catch (error) { + return { + content: [ + { + type: 'text' as const, + text: `**Error generating theme:** ${error instanceof Error ? error.message : String(error)}`, + }, + ], + isError: true, + }; + } +} diff --git a/src/mcp/tools/handlers/component-tokens.ts b/src/mcp/tools/handlers/component-tokens.ts new file mode 100644 index 00000000..7fc38234 --- /dev/null +++ b/src/mcp/tools/handlers/component-tokens.ts @@ -0,0 +1,148 @@ +/** + * Handler for get_component_design_tokens tool. + * Returns available design tokens for a component theme. + */ + +import { + getComponentTheme, + searchComponents, + COMPONENT_NAMES, + hasVariants, + getVariants, + isCompoundComponent, + getCompoundComponentInfo, + hasPartSelectors, + hasAngularInnerSelectors, +} from '../../knowledge/index.js'; +import type {GetComponentDesignTokensParams} from '../schemas.js'; + +export async function handleGetComponentDesignTokens(params: GetComponentDesignTokensParams) { + const {component} = params; + const normalizedName = component.toLowerCase().trim(); + + // Try exact match first + const theme = getComponentTheme(normalizedName); + + if (!theme) { + // Component not found - provide helpful suggestions + const suggestions = searchComponents(normalizedName); + + // If no suggestions from search, show a subset of available components + const componentList = suggestions.length > 0 ? suggestions.slice(0, 10) : COMPONENT_NAMES.slice(0, 20); + + return { + content: [ + { + type: 'text' as const, + text: `Component "${component}" not found. + +${suggestions.length > 0 ? '**Similar components:**' : '**Available components (partial list):**'} +${componentList.map((c) => `- ${c}`).join('\n')} + +${suggestions.length === 0 ? `\nTotal available: ${COMPONENT_NAMES.length} components. Use a more specific name to search.` : ''} + +**Tip:** For button variants, use specific names like "flat-button", "contained-button", "outlined-button", or "fab-button".`, + }, + ], + }; + } + + // Build response parts + const responseParts: string[] = []; + + // Header + responseParts.push(`## Design Tokens for \`${theme.name}\``); + responseParts.push(''); + + // Theme function info + responseParts.push(`**Theme Function:** \`${theme.themeFunctionName}()\``); + responseParts.push(''); + + // Description if present + if (theme.description && theme.description.trim()) { + responseParts.push('**Description:**'); + responseParts.push(theme.description.trim()); + responseParts.push(''); + } + + // Variants hint for base components + if (hasVariants(normalizedName)) { + const variants = getVariants(normalizedName); + responseParts.push('**Note:** This component has variant-specific themes:'); + responseParts.push(variants.map((v) => `- \`${v}\``).join('\n')); + responseParts.push(''); + responseParts.push('Consider using the specific variant theme for more targeted styling.'); + responseParts.push(''); + } + + // Compound component hint + if (isCompoundComponent(normalizedName)) { + const compoundInfo = getCompoundComponentInfo(normalizedName); + if (compoundInfo) { + responseParts.push('**Compound Component:**'); + responseParts.push(compoundInfo.description); + responseParts.push(''); + responseParts.push('**Related themes for full customization:**'); + responseParts.push(''); + + // Check if we have inner selectors defined for either platform + const hasAngular = hasAngularInnerSelectors(normalizedName); + const hasWC = hasPartSelectors(normalizedName); + + if ((hasAngular || hasWC) && compoundInfo.innerSelectors) { + // Show table with both Angular and Web Components selectors + responseParts.push('| Theme | Angular Selector | Web Components Selector |'); + responseParts.push('|-------|------------------|------------------------|'); + + for (const relatedTheme of compoundInfo.relatedThemes) { + const angularSelector = compoundInfo.innerSelectors.angular?.[relatedTheme]; + const wcSelector = compoundInfo.innerSelectors.webcomponents?.[relatedTheme]; + + const angularDisplay = angularSelector && angularSelector !== 'TODO' ? `\`${angularSelector}\`` : '*(TBD)*'; + const wcDisplay = wcSelector && wcSelector !== 'TODO' ? `\`${wcSelector}\`` : '*(TBD)*'; + + responseParts.push(`| \`${relatedTheme}\` | ${angularDisplay} | ${wcDisplay} |`); + } + responseParts.push(''); + responseParts.push( + '**Tip:** Use the scoped selectors above to style internal components. For Angular, these are descendant selectors. For Web Components, use `::part()` selectors to penetrate the shadow DOM.', + ); + } else { + // Fallback to simple list if no selectors defined yet + responseParts.push(compoundInfo.relatedThemes.map((t) => `- \`${t}\``).join('\n')); + } + responseParts.push(''); + } + } + + // Tokens table + if (theme.tokens.length > 0) { + responseParts.push(`**Available Tokens (${theme.tokens.length}):**`); + responseParts.push(''); + responseParts.push('| Token Name | Type | Description |'); + responseParts.push('|------------|------|-------------|'); + + for (const token of theme.tokens) { + // Clean up description - remove newlines and extra whitespace + const cleanDesc = token.description.replace(/\s+/g, ' ').trim(); + responseParts.push(`| \`${token.name}\` | ${token.type} | ${cleanDesc} |`); + } + responseParts.push(''); + } else { + responseParts.push('**No customizable tokens available for this component.**'); + responseParts.push(''); + } + + // Usage hint + responseParts.push('---'); + responseParts.push('**Next step:** Use `create_component_theme` with the tokens above to generate Sass code.'); + + return { + content: [ + { + type: 'text' as const, + text: responseParts.join('\n'), + }, + ], + }; +} diff --git a/src/mcp/tools/handlers/index.ts b/src/mcp/tools/handlers/index.ts index 048ca9ef..e788447f 100644 --- a/src/mcp/tools/handlers/index.ts +++ b/src/mcp/tools/handlers/index.ts @@ -8,3 +8,5 @@ export {handleCreateCustomPalette} from './custom-palette.js'; export {handleCreateTypography} from './typography.js'; export {handleCreateElevations} from './elevations.js'; export {handleCreateTheme} from './theme.js'; +export {handleGetComponentDesignTokens} from './component-tokens.js'; +export {handleCreateComponentTheme} from './component-theme.js'; diff --git a/src/mcp/tools/index.ts b/src/mcp/tools/index.ts index 7b511c49..ef519119 100644 --- a/src/mcp/tools/index.ts +++ b/src/mcp/tools/index.ts @@ -9,6 +9,8 @@ export { createTypographySchema, createElevationsSchema, createThemeSchema, + getComponentDesignTokensSchema, + createComponentThemeSchema, platformSchema, type DetectPlatformParams, type CreatePaletteParams, @@ -16,6 +18,8 @@ export { type CreateTypographyParams, type CreateElevationsParams, type CreateThemeParams, + type GetComponentDesignTokensParams, + type CreateComponentThemeParams, type Platform, } from './schemas.js'; @@ -26,4 +30,6 @@ export { handleCreateTypography, handleCreateElevations, handleCreateTheme, + handleGetComponentDesignTokens, + handleCreateComponentTheme, } from './handlers/index.js'; diff --git a/src/mcp/tools/schemas.ts b/src/mcp/tools/schemas.ts index 4d9412a5..eee4c554 100644 --- a/src/mcp/tools/schemas.ts +++ b/src/mcp/tools/schemas.ts @@ -236,3 +236,38 @@ export const createCustomPaletteSchema = z.object({ }); export type CreateCustomPaletteParams = z.infer; + +// ============================================================================ +// Component Theming Schemas +// ============================================================================ + +/** + * Schema for get_component_design_tokens tool. + */ +export const getComponentDesignTokensSchema = z.object({ + component: z.string().describe(PARAM_DESCRIPTIONS.component), +}); + +/** + * Schema for token value in create_component_theme. + * Supports colors, numbers with units, and other Sass-compatible values. + */ +const tokenValueSchema = z.union([ + colorSchema, + z.string().describe('CSS value (e.g., "8px", "1rem", "0 2px 4px rgba(0,0,0,0.1)")'), + z.number().describe('Numeric value'), +]); + +/** + * Schema for create_component_theme tool. + */ +export const createComponentThemeSchema = z.object({ + platform: platformSchema, + component: z.string().describe(PARAM_DESCRIPTIONS.componentTheme), + tokens: z.record(z.string(), tokenValueSchema).describe(PARAM_DESCRIPTIONS.tokens), + selector: z.string().optional().describe(PARAM_DESCRIPTIONS.selector), + name: z.string().optional().describe(PARAM_DESCRIPTIONS.themeName), +}); + +export type GetComponentDesignTokensParams = z.infer; +export type CreateComponentThemeParams = z.infer; From 0d0f80ee910904f6c52620e854ba1910636cf925 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Mon, 19 Jan 2026 17:01:57 +0200 Subject: [PATCH 03/38] feat: add CSS variables generation when creating palettes --- src/mcp/__tests__/generators/css.test.ts | 220 +++++++++++++ src/mcp/__tests__/tools/schemas.test.ts | 169 +++++++++- src/mcp/__tests__/utils/preprocessing.test.ts | 300 ++++++++++++++++++ src/mcp/generators/css.ts | 171 ++++++++++ src/mcp/index.ts | 23 +- src/mcp/tools/descriptions.ts | 53 +++- src/mcp/tools/handlers/custom-palette.ts | 118 ++++++- src/mcp/tools/handlers/palette.ts | 79 +++++ src/mcp/tools/schemas.ts | 18 +- src/mcp/utils/preprocessing.ts | 87 +++++ src/mcp/utils/sass.ts | 9 +- src/mcp/utils/types.ts | 28 +- 12 files changed, 1241 insertions(+), 34 deletions(-) create mode 100644 src/mcp/__tests__/generators/css.test.ts create mode 100644 src/mcp/__tests__/utils/preprocessing.test.ts create mode 100644 src/mcp/generators/css.ts create mode 100644 src/mcp/utils/preprocessing.ts diff --git a/src/mcp/__tests__/generators/css.test.ts b/src/mcp/__tests__/generators/css.test.ts new file mode 100644 index 00000000..4044eb61 --- /dev/null +++ b/src/mcp/__tests__/generators/css.test.ts @@ -0,0 +1,220 @@ +import {describe, it, expect} from 'vitest'; +import * as path from 'path'; +import {fileURLToPath} from 'url'; +import {generatePaletteCss, generateCustomPaletteCss, formatCssOutput} from '../../generators/css.js'; +import { SHADE_LEVELS } from '../../utils/types.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// From src/mcp/__tests__/generators/ we need to go up 4 levels to package root +const PACKAGE_ROOT = path.resolve(__dirname, '..', '..', '..', '..'); +const TEST_LOAD_PATHS = [PACKAGE_ROOT]; + +describe('generatePaletteCss', () => { + it('should generate CSS custom properties for a basic palette', async () => { + const result = await generatePaletteCss({ + primary: '#1976d2', + secondary: '#ff9800', + surface: '#fafafa', + variant: 'light', + _loadPaths: TEST_LOAD_PATHS, + }); + + expect(result.css).toBeDefined(); + expect(result.description).toContain('light palette'); + expect(result.description).toContain('#1976d2'); + + expect(result.css).toContain(':root'); + expect(result.css).toContain('--ig-primary-50'); + expect(result.css).toContain('--ig-primary-500'); + expect(result.css).toContain('--ig-primary-900'); + expect(result.css).toContain('--ig-secondary-50'); + expect(result.css).toContain('--ig-secondary-500'); + expect(result.css).toContain('--ig-surface-50'); + expect(result.css).toContain('--ig-surface-500'); + expect(result.css).toContain('--ig-gray-50'); + expect(result.css).toContain('--ig-gray-500'); + expect(result.css).toContain('--ig-wcag-aa'); + expect(result.css).toContain('--ig-contrast-level'); + + // CSS variables should have actual color values (hsl, hsla, rgb, rgba, color, or hex) + // This regex matches CSS variable declarations with color values + const colorValuePattern = /--ig-primary-500:\s*(hsl|hsla|rgb|rgba|color|#)[\w\d(),.\s%-]+;/; + expect(result.css).toMatch(colorValuePattern); + }); + + it('should generate CSS for a dark palette', async () => { + const result = await generatePaletteCss({ + primary: '#bb86fc', + secondary: '#03dac6', + surface: '#121212', + variant: 'dark', + _loadPaths: TEST_LOAD_PATHS, + }); + + expect(result.css).toBeDefined(); + expect(result.description).toContain('dark palette'); + expect(result.css).toContain('--ig-primary-500'); + expect(result.css).toContain('--ig-secondary-500'); + expect(result.css).toContain('--ig-surface-500'); + expect(result.css).toContain('--ig-gray-500'); + }); + + it('should include optional colors when provided', async () => { + const result = await generatePaletteCss({ + primary: '#1976d2', + secondary: '#ff9800', + surface: '#fafafa', + info: '#2196f3', + success: '#4caf50', + warn: '#ff9800', + error: '#f44336', + _loadPaths: TEST_LOAD_PATHS, + }); + + expect(result.css).toContain('--ig-info-500'); + expect(result.css).toContain('--ig-success-500'); + expect(result.css).toContain('--ig-warn-500'); + expect(result.css).toContain('--ig-error-500'); + }); + + it('should include contrast variables for each shade', async () => { + const result = await generatePaletteCss({ + primary: '#1976d2', + secondary: '#ff9800', + surface: '#fafafa', + _loadPaths: TEST_LOAD_PATHS, + }); + + expect(result.css).toContain('--ig-primary-500-contrast'); + expect(result.css).toContain('--ig-secondary-500-contrast'); + }); + + it('should generate valid color values for all palette shades', async () => { + const result = await generatePaletteCss({ + primary: '#1976d2', + secondary: '#ff9800', + surface: '#fafafa', + _loadPaths: TEST_LOAD_PATHS, + }); + + const getVarValue = (css: string, varName: string): string | null => { + const match = css.match(new RegExp(`${varName}:\\s*([^;]+);`)); + + return match ? match[1].trim() : null; + }; + + const colorPattern = /^(hsl|hsla|rgb|rgba|color|#)/; + + for (const shade of SHADE_LEVELS) { + const value = getVarValue(result.css, `--ig-primary-${shade}`); + + expect(value, `--ig-primary-${shade} should have a value`).not.toBeNull(); + expect(value, `--ig-primary-${shade} should be a valid color`).toMatch(colorPattern); + } + + const contrastValue = getVarValue(result.css, '--ig-primary-500-contrast'); + + expect(contrastValue, '--ig-primary-500-contrast should have a value').not.toBeNull(); + expect(contrastValue, '--ig-primary-500-contrast should be a valid color').toMatch(colorPattern); + }); + + it('should throw an error for invalid colors', async () => { + await expect( + generatePaletteCss({ + primary: 'not-a-color', + secondary: '#ff9800', + surface: '#fafafa', + _loadPaths: TEST_LOAD_PATHS, + }), + ).rejects.toThrow(); + }); +}); + +describe('generateCustomPaletteCss', () => { + it('should generate CSS for a custom palette with shades mode', async () => { + const result = await generateCustomPaletteCss({ + variant: 'light', + surfaceColor: '#fafafa', + colors: { + primary: {mode: 'shades', baseColor: '#1976d2'}, + secondary: {mode: 'shades', baseColor: '#ff9800'}, + surface: {mode: 'shades', baseColor: '#fafafa'}, + gray: {mode: 'shades', baseColor: '#000000'}, + info: {mode: 'shades', baseColor: '#2196f3'}, + success: {mode: 'shades', baseColor: '#4caf50'}, + warn: {mode: 'shades', baseColor: '#ff9800'}, + error: {mode: 'shades', baseColor: '#f44336'}, + }, + _loadPaths: TEST_LOAD_PATHS, + }); + + expect(result.css).toBeDefined(); + expect(result.description).toContain('custom'); + expect(result.description).toContain('light'); + + // Should contain all palette variables + expect(result.css).toContain('--ig-primary-500'); + expect(result.css).toContain('--ig-secondary-500'); + expect(result.css).toContain('--ig-gray-500'); + }); + + it('should generate CSS for a custom palette with explicit shades', async () => { + const result = await generateCustomPaletteCss({ + variant: 'light', + surfaceColor: '#FAFAFA', + colors: { + primary: { + mode: 'explicit', + shades: { + '50': '#e3f2fd', + '100': '#bbdefb', + '200': '#90caf9', + '300': '#64b5f6', + '400': '#42a5f5', + '500': '#2196f3', + '600': '#1e88e5', + '700': '#1976d2', + '800': '#1565c0', + '900': '#0d47a1', + A100: '#82b1ff', + A200: '#448aff', + A400: '#2979ff', + A700: '#2962ff', + }, + }, + secondary: {mode: 'shades', baseColor: '#ff9800'}, + surface: {mode: 'shades', baseColor: '#fafafa'}, + gray: {mode: 'shades', baseColor: '#000000'}, + info: {mode: 'shades', baseColor: '#2196f3'}, + success: {mode: 'shades', baseColor: '#4caf50'}, + warn: {mode: 'shades', baseColor: '#ff9800'}, + error: {mode: 'shades', baseColor: '#f44336'}, + }, + _loadPaths: TEST_LOAD_PATHS, + }); + + expect(result.css).toBeDefined(); + expect(result.css).toContain('--ig-primary-500'); + expect(result.css).toContain('--ig-primary-50'); + expect(result.css).toContain('--ig-primary-900'); + + const primary500Match = result.css.match(/--ig-primary-500:\s*([^;]+);/); + + expect(primary500Match).not.toBeNull(); + expect(primary500Match![1].trim()).toMatch(/^(hsl|hsla|rgb|rgba|#)/); + }); +}); + +describe('formatCssOutput', () => { + it('should add a header comment to CSS output', () => { + const css = ':root { --ig-primary-500: #1976d2; }'; + const description = 'Test palette'; + const formatted = formatCssOutput(css, description); + + expect(formatted).toContain('/* Generated by Ignite UI Theming MCP Server */'); + expect(formatted).toContain('/* Test palette */'); + expect(formatted).toContain(':root { --ig-primary-500: #1976d2; }'); + }); +}); diff --git a/src/mcp/__tests__/tools/schemas.test.ts b/src/mcp/__tests__/tools/schemas.test.ts index 6d295dfd..3875b0e0 100644 --- a/src/mcp/__tests__/tools/schemas.test.ts +++ b/src/mcp/__tests__/tools/schemas.test.ts @@ -9,7 +9,7 @@ */ import {describe, it, expect} from 'vitest'; -import {colorSchema} from '../../tools/schemas.js'; +import {colorSchema, createCustomPaletteSchema} from '../../tools/schemas.js'; describe('colorSchema', () => { describe('hex colors', () => { @@ -288,3 +288,170 @@ describe('colorSchema', () => { }); }); }); + +describe('createCustomPaletteSchema', () => { + describe('color definition validation', () => { + it('rejects plain string colors for primary/secondary/surface', () => { + const result = createCustomPaletteSchema.safeParse({ + primary: '#1976d2', + secondary: '#ff9800', + surface: '#fafafa', + }); + + expect(result.success).toBe(false); + + if (!result.success) { + const paths = result.error.errors.map((e) => e.path.join('.')); + + expect(paths).toContain('primary'); + expect(paths).toContain('secondary'); + expect(paths).toContain('surface'); + } + }); + + it('accepts shades mode with baseColor', () => { + const result = createCustomPaletteSchema.safeParse({ + primary: {mode: 'shades', baseColor: '#1976d2'}, + secondary: {mode: 'shades', baseColor: '#ff9800'}, + surface: {mode: 'shades', baseColor: '#fafafa'}, + }); + + expect(result.success).toBe(true); + }); + + it('accepts explicit mode with all 14 shades for chromatic colors', () => { + const allShades = { + '50': '#e3f2fd', + '100': '#bbdefb', + '200': '#90caf9', + '300': '#64b5f6', + '400': '#42a5f5', + '500': '#2196f3', + '600': '#1e88e5', + '700': '#1976d2', + '800': '#1565c0', + '900': '#0d47a1', + A100: '#82b1ff', + A200: '#448aff', + A400: '#2979ff', + A700: '#2962ff', + }; + + const result = createCustomPaletteSchema.safeParse({ + primary: {mode: 'explicit', shades: allShades}, + secondary: {mode: 'shades', baseColor: '#ff9800'}, + surface: {mode: 'shades', baseColor: '#fafafa'}, + }); + + expect(result.success).toBe(true); + }); + + it('rejects explicit mode with missing shades', () => { + const incompleteShades = { + '500': '#2196f3', + '700': '#1976d2', + }; + + const result = createCustomPaletteSchema.safeParse({ + primary: {mode: 'explicit', shades: incompleteShades}, + secondary: {mode: 'shades', baseColor: '#ff9800'}, + surface: {mode: 'shades', baseColor: '#fafafa'}, + }); + + expect(result.success).toBe(false); + }); + + it('accepts gray with only 10 shades (no accent shades)', () => { + const grayShades = { + '50': '#fafafa', + '100': '#f5f5f5', + '200': '#eeeeee', + '300': '#e0e0e0', + '400': '#bdbdbd', + '500': '#9e9e9e', + '600': '#757575', + '700': '#616161', + '800': '#424242', + '900': '#212121', + }; + + const result = createCustomPaletteSchema.safeParse({ + primary: {mode: 'shades', baseColor: '#1976d2'}, + secondary: {mode: 'shades', baseColor: '#ff9800'}, + surface: {mode: 'shades', baseColor: '#fafafa'}, + gray: {mode: 'explicit', shades: grayShades}, + }); + + expect(result.success).toBe(true); + }); + + it('rejects invalid mode value', () => { + const result = createCustomPaletteSchema.safeParse({ + primary: {mode: 'invalid', baseColor: '#1976d2'}, + secondary: {mode: 'shades', baseColor: '#ff9800'}, + surface: {mode: 'shades', baseColor: '#fafafa'}, + }); + + expect(result.success).toBe(false); + }); + + it('rejects shades mode without baseColor', () => { + const result = createCustomPaletteSchema.safeParse({ + primary: {mode: 'shades'}, + secondary: {mode: 'shades', baseColor: '#FF9800'}, + surface: {mode: 'shades', baseColor: '#FAFAFA'}, + }); + + expect(result.success).toBe(false); + }); + + it('rejects explicit mode without shades', () => { + const result = createCustomPaletteSchema.safeParse({ + primary: {mode: 'explicit'}, + secondary: {mode: 'shades', baseColor: '#ff9800'}, + surface: {mode: 'shades', baseColor: '#fafafa'}, + }); + + expect(result.success).toBe(false); + }); + }); + + describe('optional parameters', () => { + it('accepts variant parameter', () => { + const result = createCustomPaletteSchema.safeParse({ + primary: {mode: 'shades', baseColor: '#1976d2'}, + secondary: {mode: 'shades', baseColor: '#ff9800'}, + surface: {mode: 'shades', baseColor: '#fafafa'}, + variant: 'dark', + }); + + expect(result.success).toBe(true); + }); + + it('accepts output parameter', () => { + const result = createCustomPaletteSchema.safeParse({ + primary: {mode: 'shades', baseColor: '#1976d2'}, + secondary: {mode: 'shades', baseColor: '#ff9800'}, + surface: {mode: 'shades', baseColor: '#fafafa'}, + output: 'css', + }); + + expect(result.success).toBe(true); + }); + + it('accepts all optional color groups', () => { + const result = createCustomPaletteSchema.safeParse({ + primary: {mode: 'shades', baseColor: '#1976d2'}, + secondary: {mode: 'shades', baseColor: '#ff9800'}, + surface: {mode: 'shades', baseColor: '#fafafa'}, + gray: {mode: 'shades', baseColor: '#9e9e9e'}, + info: {mode: 'shades', baseColor: '#2196f3'}, + success: {mode: 'shades', baseColor: '#4caf50'}, + warn: {mode: 'shades', baseColor: '#ff9800'}, + error: {mode: 'shades', baseColor: '#f44336'}, + }); + + expect(result.success).toBe(true); + }); + }); +}); diff --git a/src/mcp/__tests__/utils/preprocessing.test.ts b/src/mcp/__tests__/utils/preprocessing.test.ts new file mode 100644 index 00000000..2236766b --- /dev/null +++ b/src/mcp/__tests__/utils/preprocessing.test.ts @@ -0,0 +1,300 @@ +import {describe, it, expect} from 'vitest'; +import {z} from 'zod'; +import {deepParseJsonStrings, withPreprocessing} from '../../utils/preprocessing.js'; + +describe('deepParseJsonStrings', () => { + describe('string handling', () => { + it('parses JSON object strings', () => { + const result = deepParseJsonStrings('{"mode": "shades", "baseColor": "#1976D2"}'); + + expect(result).toEqual({mode: 'shades', baseColor: '#1976D2'}); + }); + + it('parses JSON array strings', () => { + const result = deepParseJsonStrings('[1, 2, 3]'); + + expect(result).toEqual([1, 2, 3]); + }); + + it('leaves regular strings unchanged', () => { + expect(deepParseJsonStrings('hello')).toBe('hello'); + expect(deepParseJsonStrings('#FF0000')).toBe('#FF0000'); + expect(deepParseJsonStrings('red')).toBe('red'); + }); + + it('leaves invalid JSON strings unchanged', () => { + expect(deepParseJsonStrings('{invalid json}')).toBe('{invalid json}'); + expect(deepParseJsonStrings('[not valid')).toBe('[not valid'); + }); + + it('handles whitespace around JSON strings', () => { + const result = deepParseJsonStrings(' {"key": "value"} '); + + expect(result).toEqual({key: 'value'}); + }); + }); + + describe('object handling', () => { + it('recursively parses JSON strings in object properties', () => { + const input = { + primary: '{"mode": "shades", "baseColor": "red"}', + secondary: '{"mode": "shades", "baseColor": "blue"}', + name: 'my-palette', + }; + + const result = deepParseJsonStrings(input); + + expect(result).toEqual({ + primary: {mode: 'shades', baseColor: 'red'}, + secondary: {mode: 'shades', baseColor: 'blue'}, + name: 'my-palette', + }); + }); + + it('handles mixed object and string values', () => { + const input = { + primary: {mode: 'shades', baseColor: 'red'}, + secondary: '{"mode": "shades", "baseColor": "blue"}', + }; + + const result = deepParseJsonStrings(input); + + expect(result).toEqual({ + primary: {mode: 'shades', baseColor: 'red'}, + secondary: {mode: 'shades', baseColor: 'blue'}, + }); + }); + + it('handles deeply nested JSON strings', () => { + const input = { + level1: '{"level2": "{\\"level3\\": \\"value\\"}"}', + }; + + const result = deepParseJsonStrings(input); + + expect(result).toEqual({ + level1: {level2: {level3: 'value'}}, + }); + }); + + it('preserves non-JSON properties', () => { + const input = { + name: 'test', + count: 42, + active: true, + data: null, + }; + + const result = deepParseJsonStrings(input); + + expect(result).toEqual(input); + }); + }); + + describe('array handling', () => { + it('recursively parses JSON strings in arrays', () => { + const input = ['{"key": "value"}', 'regular string', 42]; + + const result = deepParseJsonStrings(input); + + expect(result).toEqual([{key: 'value'}, 'regular string', 42]); + }); + + it('handles arrays inside objects', () => { + const input = { + items: ['{"id": 1}', '{"id": 2}'], + }; + + const result = deepParseJsonStrings(input); + + expect(result).toEqual({ + items: [{id: 1}, {id: 2}], + }); + }); + }); + + describe('primitive handling', () => { + it('returns numbers unchanged', () => { + expect(deepParseJsonStrings(42)).toBe(42); + expect(deepParseJsonStrings(3.14)).toBe(3.14); + }); + + it('returns booleans unchanged', () => { + expect(deepParseJsonStrings(true)).toBe(true); + expect(deepParseJsonStrings(false)).toBe(false); + }); + + it('returns null unchanged', () => { + expect(deepParseJsonStrings(null)).toBe(null); + }); + + it('returns undefined unchanged', () => { + expect(deepParseJsonStrings(undefined)).toBe(undefined); + }); + }); + + describe('real-world scenarios', () => { + it('handles create_custom_palette input with JSON string colors', () => { + const input = { + primary: '{"mode": "shades", "baseColor": "red"}', + secondary: '{"mode": "shades", "baseColor": "blue"}', + surface: '{"mode": "shades", "baseColor": "white"}', + variant: 'light', + output: 'css', + }; + + const result = deepParseJsonStrings(input); + + expect(result).toEqual({ + primary: {mode: 'shades', baseColor: 'red'}, + secondary: {mode: 'shades', baseColor: 'blue'}, + surface: {mode: 'shades', baseColor: 'white'}, + variant: 'light', + output: 'css', + }); + }); + + it('handles create_component_theme input with JSON string tokens', () => { + const input = { + component: 'button', + tokens: '{"background": "#1976D2", "border-radius": "4px"}', + }; + + const result = deepParseJsonStrings(input); + + expect(result).toEqual({ + component: 'button', + tokens: {background: '#1976D2', 'border-radius': '4px'}, + }); + }); + + it('handles create_typography input with JSON string customScale', () => { + const input = { + fontFamily: 'Roboto', + customScale: '{"h1": {"fontSize": "2rem"}, "body1": {"fontSize": "1rem"}}', + }; + + const result = deepParseJsonStrings(input); + + expect(result).toEqual({ + fontFamily: 'Roboto', + customScale: { + h1: {fontSize: '2rem'}, + body1: {fontSize: '1rem'}, + }, + }); + }); + + it('handles explicit shades with all 14 values', () => { + const explicitShades = { + '50': '#E3F2FD', + '100': '#BBDEFB', + '200': '#90CAF9', + '300': '#64B5F6', + '400': '#42A5F5', + '500': '#2196F3', + '600': '#1E88E5', + '700': '#1976D2', + '800': '#1565C0', + '900': '#0D47A1', + A100: '#82B1FF', + A200: '#448AFF', + A400: '#2979FF', + A700: '#2962FF', + }; + + const input = { + primary: JSON.stringify({mode: 'explicit', shades: explicitShades}), + secondary: '{"mode": "shades", "baseColor": "blue"}', + surface: '{"mode": "shades", "baseColor": "white"}', + }; + + const result = deepParseJsonStrings(input); + + expect(result).toEqual({ + primary: {mode: 'explicit', shades: explicitShades}, + secondary: {mode: 'shades', baseColor: 'blue'}, + surface: {mode: 'shades', baseColor: 'white'}, + }); + }); + }); +}); + +describe('withPreprocessing', () => { + it('preprocesses params and validates with schema', async () => { + const schema = z.object({ + data: z.object({ + value: z.string(), + }), + }); + + const handler = async (params: {data: {value: string}}) => ({ + content: [{type: 'text' as const, text: params.data.value}], + }); + + const wrapped = withPreprocessing(schema, handler); + + const result = await wrapped({ + data: '{"value": "hello"}', + }); + + expect(result).toEqual({ + content: [{type: 'text', text: 'hello'}], + }); + }); + + it('throws on schema validation failure', async () => { + const schema = z.object({ + required: z.string(), + }); + + const handler = async (params: {required: string}) => ({ + content: [{type: 'text' as const, text: params.required}], + }); + + const wrapped = withPreprocessing(schema, handler); + + await expect(wrapped({})).rejects.toThrow(); + }); + + it('works with synchronous handlers', async () => { + const schema = z.object({ + name: z.string(), + }); + + const handler = (params: {name: string}) => ({ + content: [{type: 'text' as const, text: `Hello, ${params.name}`}], + }); + + const wrapped = withPreprocessing(schema, handler); + + const result = await wrapped({name: 'World'}); + + expect(result).toEqual({ + content: [{type: 'text', text: 'Hello, World'}], + }); + }); + + it('handles already-parsed objects without modification', async () => { + const schema = z.object({ + nested: z.object({ + key: z.string(), + }), + }); + + const handler = async (params: {nested: {key: string}}) => ({ + content: [{type: 'text' as const, text: params.nested.key}], + }); + + const wrapped = withPreprocessing(schema, handler); + + // Pass object directly (not as JSON string) + const result = await wrapped({ + nested: {key: 'value'}, + }); + + expect(result).toEqual({ + content: [{type: 'text', text: 'value'}], + }); + }); +}); diff --git a/src/mcp/generators/css.ts b/src/mcp/generators/css.ts new file mode 100644 index 00000000..d24b348b --- /dev/null +++ b/src/mcp/generators/css.ts @@ -0,0 +1,171 @@ +/** + * CSS code generator for Ignite UI Theming. + * Generates CSS custom properties (variables) by compiling Sass and extracting the output. + * + */ + +import * as sass from 'sass-embedded'; +import * as path from 'path'; +import {fileURLToPath} from 'url'; +import type {ColorDefinition, GrayDefinition, ThemeVariant} from '../utils/types.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// From dist/mcp/generators/ we need to go up 3 levels to package root +const PACKAGE_ROOT = path.resolve(__dirname, '..', '..', '..'); + +/** + * Result from generating CSS palette variables. + */ +export interface CssPaletteResult { + css: string; + description: string; +} + +/** + * Options for generating standard palette CSS variables. + */ +export interface PaletteCssOptions { + primary: string; + secondary: string; + surface: string; + gray?: string; + info?: string; + success?: string; + warn?: string; + error?: string; + variant?: ThemeVariant; + _loadPaths?: string[]; +} + +/** + * Generate CSS custom properties for a standard palette. + * + * This function compiles Sass code that uses the palette() function and + * @include palette() mixin, then returns the compiled CSS output. + * + * @example + * const result = await generatePaletteCss({ + * primary: '#1976d2', + * secondary: '#ff9800', + * surface: '#fafafa', + * variant: 'light' + * }); + * // result.css contains :root { --ig-primary-50: ...; --ig-primary-100: ...; ... } + */ +export async function generatePaletteCss(options: PaletteCssOptions): Promise { + const variant = options.variant ?? 'light'; + + const paletteArgs: string[] = [ + `$primary: ${options.primary}`, + `$secondary: ${options.secondary}`, + `$surface: ${options.surface}`, + ]; + + if (options.gray) paletteArgs.push(`$gray: ${options.gray}`); + if (options.info) paletteArgs.push(`$info: ${options.info}`); + if (options.success) paletteArgs.push(`$success: ${options.success}`); + if (options.warn) paletteArgs.push(`$warn: ${options.warn}`); + if (options.error) paletteArgs.push(`$error: ${options.error}`); + + const sassCode = ` +@use 'sass/color' as *; + +$palette: palette( + ${paletteArgs.join(',\n ')} +); + +@include palette($palette); +`; + + try { + const loadPaths = options._loadPaths ?? [PACKAGE_ROOT]; + const result = await sass.compileStringAsync(sassCode, { + loadPaths, + style: 'expanded', + }); + + return { + css: result.css, + description: `Generated CSS custom properties for a ${variant} palette with primary color ${options.primary}`, + }; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Failed to compile palette CSS: ${message}`); + } +} + +/** + * Options for generating custom palette CSS variables. + */ +export interface CustomPaletteCssOptions { + variant?: ThemeVariant; + surfaceColor?: string; + colors: { + primary: ColorDefinition; + secondary: ColorDefinition; + surface: ColorDefinition; + gray: GrayDefinition; + info: ColorDefinition; + success: ColorDefinition; + warn: ColorDefinition; + error: ColorDefinition; + }; + _loadPaths?: string[]; +} + +/** + * Generate CSS custom properties for a custom palette. + * + * This function generates Sass code for the custom palette structure + * (using either shades() function or explicit values), compiles it, + * and returns the CSS output. + */ +export async function generateCustomPaletteCss(options: CustomPaletteCssOptions): Promise { + const variant = options.variant ?? 'light'; + const {generateCustomPaletteCode} = await import('../utils/sass.js'); + + const paletteLines = generateCustomPaletteCode({ + variant, + variableName: 'custom', + surfaceColor: options.surfaceColor, + colors: options.colors, + }); + + const sassCode = ` +@use 'sass/color' as *; + +${paletteLines.join('\n')} + +@include palette($custom-palette); +`; + + try { + const loadPaths = options._loadPaths ?? [PACKAGE_ROOT]; + const result = await sass.compileStringAsync(sassCode, { + loadPaths, + style: 'expanded', + }); + + return { + css: result.css, + description: `Generated CSS custom properties for a custom ${variant} palette`, + }; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + + throw new Error(`Failed to compile custom palette CSS: ${message}`); + } +} + +/** + * Format CSS output for display. + * Adds a header comment and ensures consistent formatting. + */ +export function formatCssOutput(css: string, description: string): string { + const header = `/* Generated by Ignite UI Theming MCP Server */ +/* ${description} */ +`; + return header + css; +} diff --git a/src/mcp/index.ts b/src/mcp/index.ts index 8050dbaa..72593983 100644 --- a/src/mcp/index.ts +++ b/src/mcp/index.ts @@ -28,6 +28,7 @@ import { handleCreateComponentTheme, } from './tools/index.js'; import {TOOL_DESCRIPTIONS} from './tools/descriptions.js'; +import {withPreprocessing} from './utils/preprocessing.js'; import {RESOURCE_DEFINITIONS, getResourceContent} from './resources/index.js'; @@ -77,6 +78,9 @@ function registerTools(server: McpServer): void { description: TOOL_DESCRIPTIONS.create_palette, inputSchema: { platform: createPaletteSchema.shape.platform, + variant: createPaletteSchema.shape.variant, + name: createPaletteSchema.shape.name, + output: createPaletteSchema.shape.output, primary: createPaletteSchema.shape.primary, secondary: createPaletteSchema.shape.secondary, surface: createPaletteSchema.shape.surface, @@ -85,8 +89,6 @@ function registerTools(server: McpServer): void { success: createPaletteSchema.shape.success, warn: createPaletteSchema.shape.warn, error: createPaletteSchema.shape.error, - variant: createPaletteSchema.shape.variant, - name: createPaletteSchema.shape.name, }, }, async (params) => { @@ -106,6 +108,7 @@ function registerTools(server: McpServer): void { variant: createCustomPaletteSchema.shape.variant, designSystem: createCustomPaletteSchema.shape.designSystem, name: createCustomPaletteSchema.shape.name, + output: createCustomPaletteSchema.shape.output, primary: createCustomPaletteSchema.shape.primary, secondary: createCustomPaletteSchema.shape.secondary, surface: createCustomPaletteSchema.shape.surface, @@ -116,10 +119,7 @@ function registerTools(server: McpServer): void { error: createCustomPaletteSchema.shape.error, }, }, - async (params) => { - const validated = createCustomPaletteSchema.parse(params); - return await handleCreateCustomPalette(validated); - }, + withPreprocessing(createCustomPaletteSchema, handleCreateCustomPalette), ); // create_typography tool @@ -132,13 +132,11 @@ function registerTools(server: McpServer): void { platform: createTypographySchema.shape.platform, fontFamily: createTypographySchema.shape.fontFamily, designSystem: createTypographySchema.shape.designSystem, + customScale: createTypographySchema.shape.customScale, name: createTypographySchema.shape.name, }, }, - async (params) => { - const validated = createTypographySchema.parse(params); - return handleCreateTypography(validated); - }, + withPreprocessing(createTypographySchema, handleCreateTypography), ); // create_elevations tool @@ -215,10 +213,7 @@ function registerTools(server: McpServer): void { name: createComponentThemeSchema.shape.name, }, }, - async (params) => { - const validated = createComponentThemeSchema.parse(params); - return await handleCreateComponentTheme(validated); - }, + withPreprocessing(createComponentThemeSchema, handleCreateComponentTheme), ); } diff --git a/src/mcp/tools/descriptions.ts b/src/mcp/tools/descriptions.ts index 05fbdfab..6818c2ce 100644 --- a/src/mcp/tools/descriptions.ts +++ b/src/mcp/tools/descriptions.ts @@ -111,10 +111,20 @@ export const TOOL_DESCRIPTIONS = { that will produce good automatic shade distribution. + + - "sass" (default): Generates Sass code using the palette() function. Requires Sass compilation. + - "css": Generates CSS custom properties (variables) directly. Ready to use in any CSS file. + + Use "css" output when: + - Working with vanilla CSS projects without Sass + - You want immediately usable CSS variables + - Using CSS-in-JS or other non-Sass styling approaches + + 1. Validates input colors against the theme variant 2. Analyzes color luminance for shade generation suitability - 3. Generates Sass code using the palette() function + 3. Generates Sass code OR compiles to CSS based on output parameter 4. Adds warning comments to code if issues detected 5. Returns validation warnings and tips in response @@ -134,10 +144,11 @@ export const TOOL_DESCRIPTIONS = { Returns: - - Generated Sass code with palette() function call - - Platform-specific module imports + - Generated Sass code with palette() function call, OR + - Generated CSS with custom properties (:root { --ig-primary-50: ...; }) + - Platform-specific module imports (Sass only) - Validation warnings (if any colors have issues) - - Variable name created (e.g., $my-palette) + - Variable name created (e.g., $my-palette) (Sass only) @@ -147,13 +158,22 @@ export const TOOL_DESCRIPTIONS = { - Blue brand with orange accent on light theme: + Blue brand with orange accent on light theme (Sass output): { "primary": "#1976D2", "secondary": "#FF9800", "surface": "#FAFAFA", "variant": "light" } + + Same palette as CSS variables: + { + "primary": "#1976D2", + "secondary": "#FF9800", + "surface": "#FAFAFA", + "variant": "light", + "output": "css" + } @@ -190,6 +210,17 @@ export const TOOL_DESCRIPTIONS = { - You want to mix auto-generated and manually specified color groups + + - "sass" (default): Generates Sass code with palette map structure. Requires Sass compilation. + - "css": Generates CSS custom properties (variables) directly. Ready to use in any CSS file. + + Use "css" output when: + - Working with vanilla CSS projects without Sass + - You want immediately usable CSS variables + - Building prototypes or quick demos + - Using CSS-in-JS or other non-Sass styling approaches + + 1. For each color group, choose a mode: - mode:"shades" → Auto-generate all shades from baseColor using shades() function @@ -259,9 +290,10 @@ export const TOOL_DESCRIPTIONS = { Returns: - - Generated Sass code with color() map definitions + - Generated Sass code with color() map definitions, OR + - Generated CSS with custom properties (:root { --ig-primary-50: ...; }) - Summary of which colors use shades() vs explicit values - - Variable name created (e.g., $custom-light-palette) + - Variable name created (e.g., $custom-light-palette) (Sass only) - Validation warnings (if any) @@ -560,12 +592,12 @@ export const TOOL_DESCRIPTIONS = { - Button variants: Use specific variant names like "flat-button", "contained-button", "outlined-button", "fab-button" (NOT just "button") - Icon button variants: "flat-icon-button", "contained-icon-button", "outlined-icon-button" - + COMPOUND COMPONENTS: - Some components like "combo", "grid", "select" are compound - they use multiple internal components that may also need theming - The response includes hints about related themes for compound components - + VARIANTS INFO: - If you query a base component that has variants (e.g., "button"), the response lists available variants to help you choose the right one @@ -591,7 +623,7 @@ export const TOOL_DESCRIPTIONS = { { "component": "flat-button" } - + Returns tokens like: background, foreground, hover-background, border-radius, etc. @@ -705,6 +737,7 @@ export const PARAM_DESCRIPTIONS = { variant: FRAGMENTS.VARIANT, designSystem: FRAGMENTS.DESIGN_SYSTEM, name: `Custom variable name (without $ prefix). If omitted, auto-generates based on tool and variant (e.g., "custom-light", "my-theme").`, + output: `Output format: "sass" generates Sass code using igniteui-theming library functions. "css" generates CSS custom properties (variables) directly - useful for vanilla CSS projects or when you don't want Sass compilation. Defaults to "sass".`, // --------------------------------------------------------------------------- // detect_platform parameters diff --git a/src/mcp/tools/handlers/custom-palette.ts b/src/mcp/tools/handlers/custom-palette.ts index acb8991d..4c5adf4f 100644 --- a/src/mcp/tools/handlers/custom-palette.ts +++ b/src/mcp/tools/handlers/custom-palette.ts @@ -3,6 +3,7 @@ */ import {generateCustomPaletteCode, generateUseStatement, toVariableName, generateHeader} from '../../utils/sass.js'; +import {generateCustomPaletteCss, formatCssOutput} from '../../generators/css.js'; import {PALETTE_PRESETS, type PalettePresetName} from '../../knowledge/palettes.js'; import {validateCustomPalette, formatCustomPaletteValidation} from '../../validators/index.js'; import type {CreateCustomPaletteParams} from '../schemas.js'; @@ -11,6 +12,7 @@ import type {ShadesBasedColor, ColorDefinition, GrayDefinition} from '../../util export async function handleCreateCustomPalette(params: CreateCustomPaletteParams) { const variant = params.variant ?? 'light'; const designSystem = params.designSystem ?? 'material'; + const output = params.output ?? 'sass'; const presetName = `${variant}-${designSystem}-palette` as PalettePresetName; const preset = PALETTE_PRESETS[presetName]; @@ -77,11 +79,125 @@ export async function handleCreateCustomPalette(params: CreateCustomPaletteParam }; } + // Branch based on output format + if (output === 'css') { + return handleCssOutput(params, variant, designSystem, surfaceColorForGray, colors, validation); + } + + return handleSassOutput(params, variant, designSystem, surfaceColorForGray, colors, validation); +} + +/** + * Handle CSS output format - generates CSS custom properties directly. + */ +async function handleCssOutput( + params: CreateCustomPaletteParams, + variant: string, + designSystem: string, + surfaceColorForGray: string, + colors: { + primary: ColorDefinition; + secondary: ColorDefinition; + surface: ColorDefinition; + gray: GrayDefinition; + info: ColorDefinition; + success: ColorDefinition; + warn: ColorDefinition; + error: ColorDefinition; + }, + validation: Awaited>, +) { + try { + const result = await generateCustomPaletteCss({ + variant: params.variant, + surfaceColor: surfaceColorForGray, + colors, + }); + + const formattedCss = formatCssOutput(result.css, result.description); + + // Build response + const responseParts: string[] = [`**Custom Palette Generated (CSS)**`]; + responseParts.push(''); + responseParts.push( + `Created CSS custom properties for a custom ${variant} color palette based on ${designSystem} defaults.`, + ); + responseParts.push(''); + responseParts.push('Output format: CSS custom properties'); + + // Show which colors use which mode + const shadesMode = Object.entries(colors) + .filter(([_, def]) => def.mode === 'shades') + .map(([name]) => name); + const explicitMode = Object.entries(colors) + .filter(([_, def]) => def.mode === 'explicit') + .map(([name]) => name); + + responseParts.push(''); + if (shadesMode.length > 0) { + responseParts.push(`**Using shades() function:** ${shadesMode.join(', ')}`); + } + if (explicitMode.length > 0) { + responseParts.push(`**Using explicit shades:** ${explicitMode.join(', ')}`); + } + + // Add warnings if any + if (validation.warnings.length > 0) { + responseParts.push(''); + responseParts.push(formatCustomPaletteValidation(validation)); + } + + responseParts.push(''); + responseParts.push('```css'); + responseParts.push(formattedCss.trimEnd()); + responseParts.push('```'); + + return { + content: [ + { + type: 'text' as const, + text: responseParts.join('\n'), + }, + ], + }; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + return { + content: [ + { + type: 'text' as const, + text: `**Error generating CSS palette**\n\n${message}`, + }, + ], + }; + } +} + +/** + * Handle Sass output format - generates Sass code with palette map structure. + */ +function handleSassOutput( + params: CreateCustomPaletteParams, + variant: string, + designSystem: string, + surfaceColorForGray: string, + colors: { + primary: ColorDefinition; + secondary: ColorDefinition; + surface: ColorDefinition; + gray: GrayDefinition; + info: ColorDefinition; + success: ColorDefinition; + warn: ColorDefinition; + error: ColorDefinition; + }, + validation: Awaited>, +) { // Generate the Sass code const paletteName = params.name ? toVariableName(params.name) : `custom-${variant}`; const paletteLines = generateCustomPaletteCode({ platform: params.platform, - variant, + variant: params.variant, variableName: paletteName, surfaceColor: surfaceColorForGray, colors, diff --git a/src/mcp/tools/handlers/palette.ts b/src/mcp/tools/handlers/palette.ts index 64f05f66..2d4e8788 100644 --- a/src/mcp/tools/handlers/palette.ts +++ b/src/mcp/tools/handlers/palette.ts @@ -3,11 +3,13 @@ */ import {generatePalette} from '../../generators/sass.js'; +import {generatePaletteCss, formatCssOutput} from '../../generators/css.js'; import type {CreatePaletteParams} from '../schemas.js'; import {validatePaletteColors, formatValidationResult, generateWarningComments} from '../../validators/index.js'; export async function handleCreatePalette(params: CreatePaletteParams) { const variant = params.variant ?? 'light'; + const output = params.output ?? 'sass'; // Validate surface and gray colors against the variant const validation = await validatePaletteColors({ @@ -16,6 +18,82 @@ export async function handleCreatePalette(params: CreatePaletteParams) { gray: params.gray, }); + // Branch based on output format + if (output === 'css') { + return handleCssOutput(params, validation); + } + + return handleSassOutput(params, validation); +} + +/** + * Handle CSS output format - generates CSS custom properties directly. + */ +async function handleCssOutput( + params: CreatePaletteParams, + validation: Awaited>, +) { + try { + const result = await generatePaletteCss({ + primary: params.primary, + secondary: params.secondary, + surface: params.surface, + gray: params.gray, + info: params.info, + success: params.success, + warn: params.warn, + error: params.error, + variant: params.variant, + }); + + const formattedCss = formatCssOutput(result.css, result.description); + + // Build response text + const responseParts: string[] = [result.description]; + responseParts.push(''); + responseParts.push('Output format: CSS custom properties'); + + // Add validation warnings and tips + const validationText = formatValidationResult(validation); + + if (validationText) { + responseParts.push(''); + responseParts.push(validationText); + } + + responseParts.push(''); + responseParts.push('```css'); + responseParts.push(formattedCss.trimEnd()); + responseParts.push('```'); + + return { + content: [ + { + type: 'text' as const, + text: responseParts.join('\n'), + }, + ], + }; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + return { + content: [ + { + type: 'text' as const, + text: `**Error generating CSS palette**\n\n${message}`, + }, + ], + }; + } +} + +/** + * Handle Sass output format - generates Sass code using the palette() function. + */ +function handleSassOutput( + params: CreatePaletteParams, + validation: Awaited>, +) { // Generate the palette code const result = generatePalette({ platform: params.platform, @@ -58,6 +136,7 @@ export async function handleCreatePalette(params: CreatePaletteParams) { // Add validation warnings and tips const validationText = formatValidationResult(validation); + if (validationText) { responseParts.push(''); responseParts.push(validationText); diff --git a/src/mcp/tools/schemas.ts b/src/mcp/tools/schemas.ts index eee4c554..4f894675 100644 --- a/src/mcp/tools/schemas.ts +++ b/src/mcp/tools/schemas.ts @@ -11,7 +11,14 @@ import {z} from 'zod'; import {SHADE_LEVELS} from '../knowledge/index.js'; -import {PLATFORMS, DESIGN_SYSTEMS, VARIANTS, ELEVATION_PRESETS, ALL_COLOR_SHADES} from '../utils/types.js'; +import { + PLATFORMS, + DESIGN_SYSTEMS, + VARIANTS, + ELEVATION_PRESETS, + ALL_COLOR_SHADES, + OUTPUT_FORMATS, +} from '../utils/types.js'; import {PARAM_DESCRIPTIONS} from './descriptions.js'; /** @@ -65,6 +72,11 @@ export const designSystemSchema = z.enum(DESIGN_SYSTEMS).optional(); */ export const elevationPresetSchema = z.enum(ELEVATION_PRESETS).optional(); +/** + * Output format schema - derived from OUTPUT_FORMATS constant. + */ +export const outputFormatSchema = z.enum(OUTPUT_FORMATS).optional(); + /** * Platform schema - derived from PLATFORMS constant. */ @@ -92,6 +104,7 @@ export const createPaletteSchema = z.object({ error: colorSchema.optional().describe(PARAM_DESCRIPTIONS.error), variant: variantSchema.describe(PARAM_DESCRIPTIONS.variant), name: z.string().optional().describe(PARAM_DESCRIPTIONS.name), + output: outputFormatSchema.describe(PARAM_DESCRIPTIONS.output), }); /** @@ -155,7 +168,7 @@ export type CreateElevationsParams = z.infer; export type CreateThemeParams = z.infer; // Re-export canonical types from utils/types.ts for convenience -export type {Platform, DesignSystem, ThemeVariant, ElevationPreset} from '../utils/types.js'; +export type {Platform, DesignSystem, ThemeVariant, ElevationPreset, OutputFormat} from '../utils/types.js'; // ============================================================================ // Custom Palette Schemas @@ -221,6 +234,7 @@ export const createCustomPaletteSchema = z.object({ variant: variantSchema.describe(PARAM_DESCRIPTIONS.variant), designSystem: designSystemSchema.describe(PARAM_DESCRIPTIONS.designSystem), name: z.string().optional().describe(PARAM_DESCRIPTIONS.name), + output: outputFormatSchema.describe(PARAM_DESCRIPTIONS.output), // Required colors - use colorDefinition description for detailed guidance primary: colorDefinitionSchema.describe(PARAM_DESCRIPTIONS.colorDefinition), diff --git a/src/mcp/utils/preprocessing.ts b/src/mcp/utils/preprocessing.ts new file mode 100644 index 00000000..17a987cf --- /dev/null +++ b/src/mcp/utils/preprocessing.ts @@ -0,0 +1,87 @@ +/** + * Generic preprocessing utilities for MCP tool inputs. + * + * Handles cases where MCP clients (like MCP Inspector) serialize nested objects + * as JSON strings when users type them in text fields. + */ + +import type {z} from 'zod'; + +/** + * Recursively parse JSON strings in a value. + * + * This function handles cases where nested objects are passed as JSON strings + * (e.g., from MCP Inspector text fields or MCP clients that send nested objects as strings). + * It only attempts to parse strings that look like JSON objects or arrays (starting with `{` or `[`). + * + * @param value - The value to process + * @returns The value with any JSON strings parsed into objects/arrays + * + * @example + * // String that looks like JSON is parsed + * deepParseJsonStrings('{"mode": "shades"}') // => { mode: 'shades' } + * + * // Regular strings are left as-is + * deepParseJsonStrings('hello') // => 'hello' + * + * // Nested objects are processed recursively + * deepParseJsonStrings({ primary: '{"mode": "shades"}' }) + * // => { primary: { mode: 'shades' } } + */ +export function deepParseJsonStrings(value: unknown): unknown { + if (typeof value === 'string') { + const trimmed = value.trim(); + + if (trimmed.startsWith('{') || trimmed.startsWith('[')) { + try { + const parsed = JSON.parse(trimmed); + + // Recurse in case the parsed value contains more JSON strings + return deepParseJsonStrings(parsed); + } catch { + // Invalid JSON, keep as string + return value; + } + } + return value; + } + + if (Array.isArray(value)) { + return value.map(deepParseJsonStrings); + } + + if (value !== null && typeof value === 'object') { + return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, deepParseJsonStrings(v)])); + } + + return value; +} + +/** + * Create a tool handler with automatic JSON string preprocessing. + * + * This wrapper ensures that nested objects passed as JSON strings (common when + * using MCP Inspector) are properly parsed before schema validation. + * + * @param schema - The Zod schema for validating the tool's parameters + * @param handler - The tool handler function + * @returns A wrapped handler that preprocesses inputs before validation + * + * @example + * server.registerTool( + * 'create_custom_palette', + * { ... }, + * withPreprocessing(createCustomPaletteSchema, handleCreateCustomPalette) + * ); + */ +export function withPreprocessing>( + schema: z.ZodSchema, + handler: (params: TParams) => Promise | TResult, +): (params: unknown) => Promise { + return async (rawParams: unknown) => { + const preprocessed = deepParseJsonStrings(rawParams); + const validated = schema.parse(preprocessed); + + return handler(validated); + }; +} diff --git a/src/mcp/utils/sass.ts b/src/mcp/utils/sass.ts index 168f9af6..9be9e397 100644 --- a/src/mcp/utils/sass.ts +++ b/src/mcp/utils/sass.ts @@ -125,7 +125,7 @@ export interface PaletteCodeOptions { /** Error state color */ error?: string; /** Theme variant (affects surface default) */ - variant?: ThemeVariant + variant?: ThemeVariant; /** Variable name for the palette (without $) */ variableName?: string; /** Whether to use inline color values or reference Sass variables */ @@ -331,7 +331,8 @@ export function generateCustomPaletteCode(options: CustomPaletteCodeOptions): st for (let i = 0; i < colorGroups.length; i++) { const {name, def, shades, isGray} = colorGroups[i]; - const isLast = i === colorGroups.length - 1; + // Always add comma after each color group since _meta comes last + const needsComma = true; if (def.mode === 'shades') { // Use shades() function @@ -346,7 +347,7 @@ export function generateCustomPaletteCode(options: CustomPaletteCodeOptions): st } else { lines.push(` (${shadesListStr})`); } - lines.push(` )${isLast ? '' : ','}`); + lines.push(` )${needsComma ? ',' : ''}`); } else { // Explicit shade map lines.push(` '${name}': (`); @@ -366,7 +367,7 @@ export function generateCustomPaletteCode(options: CustomPaletteCodeOptions): st lines.push(` '${shade}-raw': ${color}${isLastShade ? '' : ','}`); } - lines.push(` )${isLast ? '' : ','}`); + lines.push(` )${needsComma ? ',' : ''}`); } } diff --git a/src/mcp/utils/types.ts b/src/mcp/utils/types.ts index 38b7a51b..7d785893 100644 --- a/src/mcp/utils/types.ts +++ b/src/mcp/utils/types.ts @@ -38,6 +38,14 @@ export const VARIANTS = ['light', 'dark'] as const; */ export const ELEVATION_PRESETS = ['material', 'indigo'] as const; +/** + * Supported output formats for code generation. + * + * - sass: Generates Sass code using the igniteui-theming library functions + * - css: Generates CSS custom properties (variables) directly + */ +export const OUTPUT_FORMATS = ['sass', 'css'] as const; + /** * Standard shade levels used in the theming system. */ @@ -72,6 +80,11 @@ export type ThemeVariant = (typeof VARIANTS)[number]; */ export type ElevationPreset = (typeof ELEVATION_PRESETS)[number]; +/** + * Output format for code generation. + */ +export type OutputFormat = (typeof OUTPUT_FORMATS)[number]; + /** * Standard shade level type. */ @@ -215,7 +228,16 @@ export const ALL_COLOR_SHADES = [...SHADE_LEVELS, ...ACCENT_SHADE_LEVELS] as con * All palette color groups. * These are the color families that make up a complete palette. */ -export const PALETTE_COLOR_GROUPS = ['primary', 'secondary', 'gray', 'surface', 'info', 'success', 'warn', 'error'] as const; +export const PALETTE_COLOR_GROUPS = [ + 'primary', + 'secondary', + 'gray', + 'surface', + 'info', + 'success', + 'warn', + 'error', +] as const; /** * Type for palette color group names. @@ -227,7 +249,9 @@ export type PaletteColorGroup = (typeof PALETTE_COLOR_GROUPS)[number]; * These groups use 14 shades (50-900, A100-A700). * Derived from PALETTE_COLOR_GROUPS to maintain single source of truth. */ -export const CHROMATIC_COLOR_GROUPS = PALETTE_COLOR_GROUPS.filter((g): g is Exclude => g !== 'gray'); +export const CHROMATIC_COLOR_GROUPS = PALETTE_COLOR_GROUPS.filter( + (g): g is Exclude => g !== 'gray', +); /** * Type for chromatic color group names. From 78331f38081f80267347244a87ec91727fe99657 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Wed, 21 Jan 2026 18:49:33 +0200 Subject: [PATCH 04/38] feat: add CSS output option when generating component themes --- src/mcp/__tests__/generators/css.test.ts | 129 ++++++++++++- .../__tests__/tools/handlers/handlers.test.ts | 177 ++++++++++++++++++ src/mcp/generators/css.ts | 102 ++++++++++ src/mcp/generators/sass.ts | 19 +- src/mcp/index.ts | 1 + src/mcp/knowledge/component-selectors.ts | 22 ++- src/mcp/knowledge/index.ts | 2 + src/mcp/knowledge/platforms/index.ts | 34 +++- src/mcp/tools/handlers/component-theme.ts | 116 +++++++++++- src/mcp/tools/schemas.ts | 3 +- 10 files changed, 582 insertions(+), 23 deletions(-) diff --git a/src/mcp/__tests__/generators/css.test.ts b/src/mcp/__tests__/generators/css.test.ts index 4044eb61..d0001839 100644 --- a/src/mcp/__tests__/generators/css.test.ts +++ b/src/mcp/__tests__/generators/css.test.ts @@ -2,7 +2,7 @@ import {describe, it, expect} from 'vitest'; import * as path from 'path'; import {fileURLToPath} from 'url'; import {generatePaletteCss, generateCustomPaletteCss, formatCssOutput} from '../../generators/css.js'; -import { SHADE_LEVELS } from '../../utils/types.js'; +import {SHADE_LEVELS} from '../../utils/types.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -218,3 +218,130 @@ describe('formatCssOutput', () => { expect(formatted).toContain(':root { --ig-primary-500: #1976d2; }'); }); }); + +describe('generateComponentThemeCss', () => { + // Note: Button themes have a nested structure (flat, outlined, contained, fab) + // which requires special handling. Using avatar for simpler tests. + + it('should generate CSS custom properties for an avatar theme', async () => { + const {generateComponentThemeCss} = await import('../../generators/css.js'); + + const result = await generateComponentThemeCss({ + platform: 'webcomponents', + component: 'avatar', + tokens: {background: '#ff5722'}, + selector: 'igc-avatar', + _loadPaths: TEST_LOAD_PATHS, + }); + + expect(result.css).toBeDefined(); + expect(result.description).toContain('avatar'); + expect(result.description).toContain('1 token'); + + // Should contain the selector + expect(result.css).toContain('igc-avatar'); + + // Should contain CSS custom properties with correct prefix in var() fallback + expect(result.css).toContain('--background: var(--ig-avatar-background'); + }); + + it('should use platform-specific selector as default when no selector provided', async () => { + const {generateComponentThemeCss} = await import('../../generators/css.js'); + + const result = await generateComponentThemeCss({ + platform: 'webcomponents', + component: 'avatar', + tokens: {background: '#ff5722'}, + _loadPaths: TEST_LOAD_PATHS, + }); + + // Should use the Web Components selector as default + expect(result.css).toContain('igc-avatar'); + }); + + it('should use platform-specific selector when platform is specified', async () => { + const {generateComponentThemeCss} = await import('../../generators/css.js'); + + const result = await generateComponentThemeCss({ + component: 'avatar', + platform: 'webcomponents', + tokens: {background: '#ff5722'}, + _loadPaths: TEST_LOAD_PATHS, + }); + + // Should use the Web Components selector + expect(result.css).toContain('igc-avatar'); + }); + + it('should handle numeric token values', async () => { + const {generateComponentThemeCss} = await import('../../generators/css.js'); + + const result = await generateComponentThemeCss({ + platform: 'webcomponents', + component: 'badge', + tokens: { + 'background-color': '#1976d2', + 'border-radius': 4, + }, + selector: 'igc-badge', + _loadPaths: TEST_LOAD_PATHS, + }); + + expect(result.css).toBeDefined(); + expect(result.css).toContain('igc-badge'); + }); + + it('should throw error for unknown component', async () => { + const {generateComponentThemeCss} = await import('../../generators/css.js'); + + await expect( + generateComponentThemeCss({ + platform: 'webcomponents', + component: 'unknown-component', + tokens: {background: '#1976d2'}, + _loadPaths: TEST_LOAD_PATHS, + }), + ).rejects.toThrow('Unknown component'); + }); + + it('should generate valid CSS for multiple tokens', async () => { + const {generateComponentThemeCss} = await import('../../generators/css.js'); + + const result = await generateComponentThemeCss({ + platform: 'webcomponents', + component: 'avatar', + tokens: { + background: '#ff5722', + color: 'white', + 'icon-color': 'white', + 'border-radius': '8px', + }, + selector: '.my-avatar', + _loadPaths: TEST_LOAD_PATHS, + }); + + expect(result.css).toContain('.my-avatar'); + expect(result.description).toContain('4 token'); + + // CSS should be valid (no Sass syntax remaining) + expect(result.css).not.toContain('$'); + expect(result.css).not.toContain('@include'); + expect(result.css).not.toContain('@use'); + }); + + it('should handle Angular selector with igx prefix', async () => { + const {generateComponentThemeCss} = await import('../../generators/css.js'); + + const result = await generateComponentThemeCss({ + component: 'avatar', + platform: 'angular', + tokens: {background: '#ff5722'}, + _loadPaths: TEST_LOAD_PATHS, + }); + + // Should use the Angular selector + expect(result.css).toMatch(/igx-avatar/); + // Should use igx prefix for variables in var() fallback + expect(result.css).toContain('--background: var(--igx-avatar-background'); + }); +}); diff --git a/src/mcp/__tests__/tools/handlers/handlers.test.ts b/src/mcp/__tests__/tools/handlers/handlers.test.ts index 0d030eb9..08656fd9 100644 --- a/src/mcp/__tests__/tools/handlers/handlers.test.ts +++ b/src/mcp/__tests__/tools/handlers/handlers.test.ts @@ -13,6 +13,7 @@ import {handleCreateTheme} from '../../../tools/handlers/theme.js'; import {handleCreateTypography} from '../../../tools/handlers/typography.js'; import {handleCreateElevations} from '../../../tools/handlers/elevations.js'; import {handleCreateCustomPalette} from '../../../tools/handlers/custom-palette.js'; +import {handleCreateComponentTheme} from '../../../tools/handlers/component-theme.js'; describe('handleCreatePalette', () => { it('returns MCP response format', async () => { @@ -334,3 +335,179 @@ describe('handleCreateCustomPalette', () => { expect(text).toContain('explicit shades'); }); }); + +describe('handleCreateComponentTheme', () => { + it('returns error when platform is not provided', async () => { + const result = await handleCreateComponentTheme({ + component: 'avatar', + tokens: { + background: '#ff5722', + }, + } as any); + + expect(result.isError).toBe(true); + const text = result.content[0].text; + expect(text).toContain('Error'); + expect(text).toContain('platform'); + expect(text).toContain('required'); + }); + + it('returns MCP response format for valid component', async () => { + const result = await handleCreateComponentTheme({ + platform: 'webcomponents', + component: 'avatar', + tokens: { + background: '#ff5722', + }, + }); + + expect(result).toHaveProperty('content'); + expect(result.content).toBeInstanceOf(Array); + expect(result.content[0]).toHaveProperty('type', 'text'); + expect(result.content[0]).toHaveProperty('text'); + }); + + it('generates Sass code by default with platform-specific selector', async () => { + const result = await handleCreateComponentTheme({ + platform: 'webcomponents', + component: 'avatar', + tokens: { + background: '#ff5722', + }, + }); + + const text = result.content[0].text; + expect(text).toContain('```scss'); + expect(text).toContain('avatar-theme('); + expect(text).toContain('$background: #ff5722'); + expect(text).toContain('igc-avatar'); // Platform-specific selector + expect(text).toContain('css-vars-from-theme'); // New mixin + }); + + it('generates CSS code when output is css', async () => { + const result = await handleCreateComponentTheme({ + platform: 'webcomponents', + component: 'avatar', + tokens: { + background: '#ff5722', + }, + output: 'css', + }); + + const text = result.content[0].text; + expect(text).toContain('```css'); + expect(text).toContain('--background: var(--ig-avatar-background'); // Correct prefix in var() fallback + expect(text).toContain('#ff5722'); + }); + + it('returns error for base button component (has variants)', async () => { + const result = await handleCreateComponentTheme({ + platform: 'webcomponents', + component: 'button', + tokens: { + background: '#ff5722', + }, + }); + + const text = result.content[0].text; + expect(result.isError).toBe(true); + expect(text).toContain('Error'); + expect(text).toContain('multiple variants'); + expect(text).toContain('flat-button'); + expect(text).toContain('contained-button'); + expect(text).toContain('outlined-button'); + expect(text).toContain('fab-button'); + }); + + it('returns error for base icon-button component (has variants)', async () => { + const result = await handleCreateComponentTheme({ + platform: 'webcomponents', + component: 'icon-button', + tokens: { + background: '#ff5722', + }, + }); + + const text = result.content[0].text; + expect(result.isError).toBe(true); + expect(text).toContain('Error'); + expect(text).toContain('multiple variants'); + expect(text).toContain('flat-icon-button'); + expect(text).toContain('contained-icon-button'); + expect(text).toContain('outlined-icon-button'); + }); + + it('works with specific button variant (flat-button)', async () => { + const result = await handleCreateComponentTheme({ + platform: 'webcomponents', + component: 'flat-button', + tokens: { + background: '#ff5722', + }, + }); + + const text = result.content[0].text; + expect(result.isError).not.toBe(true); + expect(text).toContain('```scss'); + expect(text).toContain('flat-button-theme('); + }); + + it('works with components that have no variants (avatar)', async () => { + const result = await handleCreateComponentTheme({ + platform: 'webcomponents', + component: 'avatar', + tokens: { + background: '#ff5722', + }, + }); + + const text = result.content[0].text; + expect(result.isError).not.toBe(true); + expect(text).toContain('```scss'); + expect(text).toContain('avatar-theme('); + }); + + it('validates tokens and returns error for invalid token', async () => { + const result = await handleCreateComponentTheme({ + platform: 'webcomponents', + component: 'avatar', + tokens: { + invalidToken: '#ff5722', + }, + }); + + const text = result.content[0].text; + expect(result.isError).toBe(true); + expect(text).toContain('Error'); + expect(text).toContain('invalidToken'); + }); + + it('uses correct prefix for Angular platform', async () => { + const result = await handleCreateComponentTheme({ + component: 'avatar', + platform: 'angular', + tokens: { + background: '#ff5722', + }, + output: 'css', + }); + + const text = result.content[0].text; + expect(text).toContain('igx-avatar'); // Angular selector + expect(text).toContain('--background: var(--igx-avatar-background'); // Angular prefix in var() fallback + }); + + it('includes platform-specific selector when platform is provided', async () => { + const result = await handleCreateComponentTheme({ + component: 'avatar', + platform: 'webcomponents', + tokens: { + background: '#ff5722', + }, + output: 'css', + }); + + const text = result.content[0].text; + expect(text).toContain('igc-avatar'); + }); +}); diff --git a/src/mcp/generators/css.ts b/src/mcp/generators/css.ts index d24b348b..e0d98460 100644 --- a/src/mcp/generators/css.ts +++ b/src/mcp/generators/css.ts @@ -169,3 +169,105 @@ export function formatCssOutput(css: string, description: string): string { `; return header + css; } + +/** + * Options for generating component theme CSS variables. + */ +export interface ComponentThemeCssOptions { + platform: 'angular' | 'webcomponents' | 'react' | 'blazor'; + /** Component name (e.g., "button", "avatar") */ + component: string; + /** Token name-value pairs */ + tokens: Record; + /** CSS selector to scope the theme (optional) */ + selector?: string; + /** Custom variable name (optional) */ + name?: string; + /** Internal testing parameter for load paths */ + _loadPaths?: string[]; +} + +/** + * Result from generating component theme CSS. + */ +export interface CssComponentThemeResult { + css: string; + description: string; +} + +/** + * Generate CSS custom properties for a component theme. + * + * This function compiles Sass code that uses the component theme function + * and @include css-vars-from-theme() mixin, then returns the compiled CSS output. + * + * @example + * const result = await generateComponentThemeCss({ + * platform: 'webcomponents', + * component: 'button', + * tokens: { background: '#1976d2', 'text-color': 'white' }, + * selector: 'igc-button' + * }); + * // result.css contains: igc-button { --ig-button-background: var(--ig-button-background, #1976d2); ... } + */ +export async function generateComponentThemeCss(options: ComponentThemeCssOptions): Promise { + // Import functions we need (dynamic import to avoid circular dependencies) + const {getComponentTheme, getComponentSelector, getVariablePrefix} = await import('../knowledge/index.js'); + const {toVariableName} = await import('../utils/sass.js'); + + // Validate component exists + const theme = getComponentTheme(options.component); + + if (!theme) { + throw new Error(`Unknown component: ${options.component}`); + } + + const themeFn = theme.themeFunctionName; + const themeName = options.name ? `$${toVariableName(options.name)}` : `$custom-${options.component}-theme`; + + const tokenArgs: string[] = []; + + for (const [tokenName, value] of Object.entries(options.tokens)) { + const stringValue = typeof value === 'number' ? String(value) : value; + tokenArgs.push(`$${tokenName}: ${stringValue}`); + } + + // Determine selector - use platform-specific component selector as default + const defaultSelectors = getComponentSelector(options.component, options.platform); + const selector = options.selector || (defaultSelectors.length > 0 ? defaultSelectors[0] : options.component); + + // Get variable prefix from platform + const prefix = getVariablePrefix(options.platform); + const varName = `${prefix}-${options.component}`; + + // Generate Sass code + const sassCode = ` +@use 'sass/themes' as *; + +// Custom ${options.component} theme +${themeName}: ${themeFn}( + ${tokenArgs.join(',\n ')} +); + +// Apply the theme to ${selector} +${selector} { + @include css-vars-from-theme(${themeName}, '${varName}'); +} +`; + + try { + const loadPaths = options._loadPaths ?? [PACKAGE_ROOT]; + const result = await sass.compileStringAsync(sassCode, { + loadPaths, + style: 'expanded', + }); + + return { + css: result.css, + description: `Generated CSS custom properties for ${options.component} component with ${Object.keys(options.tokens).length} token(s)`, + }; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Failed to compile component theme CSS: ${message}`); + } +} diff --git a/src/mcp/generators/sass.ts b/src/mcp/generators/sass.ts index 4d1b59b1..255a481b 100644 --- a/src/mcp/generators/sass.ts +++ b/src/mcp/generators/sass.ts @@ -25,6 +25,8 @@ import { generateAngularThemeSass, generateWebComponentsThemeSass, getComponentTheme, + getComponentSelector, + getVariablePrefix, } from '../knowledge/index.js'; // Re-export utilities for external use @@ -328,8 +330,8 @@ function generateGenericTheme( * Input for generating a component theme. */ export interface CreateComponentThemeInput { - /** Target platform */ - platform?: Platform; + /** Target platform (required) */ + platform: Platform; /** Component name (e.g., "flat-button", "avatar") */ component: string; /** Token name-value pairs */ @@ -361,8 +363,13 @@ export function generateComponentTheme(input: CreateComponentThemeInput): Genera tokenArgs.push(`$${tokenName}: ${stringValue}`); } - // Determine selector - let selector = input.selector || ':root'; + // Determine selector - use platform-specific component selector as default + const defaultSelectors = getComponentSelector(input.component, input.platform); + const selector = input.selector || (defaultSelectors.length > 0 ? defaultSelectors[0] : input.component); + + // Get variable prefix from platform + const prefix = getVariablePrefix(input.platform); + const varName = `${prefix}-${input.component}`; // Generate the code const sections: string[] = [ @@ -379,11 +386,11 @@ export function generateComponentTheme(input: CreateComponentThemeInput): Genera } sections.push(');'); - // Add css-vars mixin to apply the theme + // Add css-vars-from-theme mixin to apply the theme sections.push(''); sections.push(`// Apply the theme to ${selector}`); sections.push(`${selector} {`); - sections.push(` @include css-vars(${themeName});`); + sections.push(` @include css-vars-from-theme(${themeName}, '${varName}');`); sections.push('}'); const code = sections.join('\n') + '\n'; diff --git a/src/mcp/index.ts b/src/mcp/index.ts index 72593983..36863f36 100644 --- a/src/mcp/index.ts +++ b/src/mcp/index.ts @@ -211,6 +211,7 @@ function registerTools(server: McpServer): void { tokens: createComponentThemeSchema.shape.tokens, selector: createComponentThemeSchema.shape.selector, name: createComponentThemeSchema.shape.name, + output: createComponentThemeSchema.shape.output, }, }, withPreprocessing(createComponentThemeSchema, handleCreateComponentTheme), diff --git a/src/mcp/knowledge/component-selectors.ts b/src/mcp/knowledge/component-selectors.ts index f207956b..5950b55b 100644 --- a/src/mcp/knowledge/component-selectors.ts +++ b/src/mcp/knowledge/component-selectors.ts @@ -158,6 +158,11 @@ export const COMPONENT_SELECTORS: Record = { angular: 'igx-date-range-picker', webcomponents: 'igc-date-range-picker', }, + // TODO: this component uses the input-group theme, but has no dedicated theme function + 'date-time-input': { + angular: null, + webcomponents: 'igc-date-time-input', + }, dialog: { angular: 'igx-dialog', webcomponents: 'igc-dialog', @@ -409,7 +414,10 @@ export const COMPOUND_COMPONENTS: Record = { 'chip', 'input-group', 'drop-down', - 'button', + 'flat-button', + 'outlined-button', + 'contained-button', + 'fab-button', 'icon-button', 'calendar', 'snackbar', @@ -423,7 +431,10 @@ export const COMPOUND_COMPONENTS: Record = { chip: 'igx-grid igx-chip', 'input-group': 'igx-grid igx-input-group', 'drop-down': 'igx-grid .igx-drop-down', - button: 'igx-grid .igx-button', + 'flat-button': 'igx-grid .igx-button--flat', + 'outlined-button': 'igx-grid .igx-button--outlined', + 'contained-button': 'igx-grid .igx-button--contained', + 'fab-button': 'igx-grid .igx-button--fab', 'icon-button': 'igx-grid .igx-icon-button', calendar: 'igx-grid igx-calendar', snackbar: 'igx-grid igx-snackbar', @@ -436,7 +447,10 @@ export const COMPOUND_COMPONENTS: Record = { chip: 'TODO', 'input-group': 'TODO', 'drop-down': 'TODO', - button: 'TODO', + 'flat-button': 'TODO', + 'outlined-button': 'TODO', + 'contained-button': 'TODO', + 'fab-button': 'TODO', 'icon-button': 'TODO', calendar: 'TODO', snackbar: 'TODO', @@ -449,6 +463,8 @@ export const COMPOUND_COMPONENTS: Record = { 'query-builder': { description: 'The query builder uses inputs, dropdowns, chips, and buttons, and button-groups for building query expressions.', + // TODO: 'button' and 'icon-button' are base variants - need to determine which specific variants + // (flat-button, outlined-button, etc.) are actually used and update relatedThemes accordingly relatedThemes: ['input-group', 'drop-down', 'chip', 'button', 'button-group', 'icon-button'], innerSelectors: { angular: { diff --git a/src/mcp/knowledge/index.ts b/src/mcp/knowledge/index.ts index 68352107..05fd3bb2 100644 --- a/src/mcp/knowledge/index.ts +++ b/src/mcp/knowledge/index.ts @@ -117,6 +117,8 @@ export { detectPlatformFromDependencies, detectConfigFiles, PLATFORM_METADATA, + PLATFORM_VARIABLE_PREFIX, + getVariablePrefix, } from './platforms/index.js'; export { diff --git a/src/mcp/knowledge/platforms/index.ts b/src/mcp/knowledge/platforms/index.ts index 2cfc2d1d..f1eb6d87 100644 --- a/src/mcp/knowledge/platforms/index.ts +++ b/src/mcp/knowledge/platforms/index.ts @@ -45,16 +45,10 @@ export { } from './webcomponents.js'; // React platform -export { - REACT_PLATFORM, - REACT_USAGE_EXAMPLES, -} from './react.js'; +export {REACT_PLATFORM, REACT_USAGE_EXAMPLES} from './react.js'; // Blazor platform -export { - BLAZOR_PLATFORM, - BLAZOR_USAGE_EXAMPLES, -} from './blazor.js'; +export {BLAZOR_PLATFORM, BLAZOR_USAGE_EXAMPLES} from './blazor.js'; // Re-export Platform type from canonical source export type {Platform} from '../../utils/types.js'; @@ -255,7 +249,7 @@ export function detectConfigFiles(projectRoot: string = '.'): ConfigFileSignal[] export function detectPlatformFromDependencies( dependencies: Record = {}, devDependencies: Record = {}, - projectRoot: string = '.' + projectRoot: string = '.', ): PlatformDetectionResult { const allDeps = {...dependencies, ...devDependencies}; const signals: DetectionSignal[] = []; @@ -356,7 +350,7 @@ export function detectPlatformFromDependencies( // Find the detected package for backward compatibility const detectedPackageSignal = signals.find( - (s) => s.type === 'ignite_package' && IGNITE_PACKAGE_PATTERNS[topPlatform]?.includes(s.package) + (s) => s.type === 'ignite_package' && IGNITE_PACKAGE_PATTERNS[topPlatform]?.includes(s.package), ) as PackageDetectionSignal | undefined; return { @@ -372,6 +366,26 @@ export function detectPlatformFromDependencies( // PLATFORM METADATA // ============================================================================ +/** + * CSS variable prefix for each platform. + * Angular uses 'igx-' prefix, all other platforms use 'ig-' prefix. + */ +export const PLATFORM_VARIABLE_PREFIX: Record = { + angular: 'igx', + webcomponents: 'ig', + react: 'ig', + blazor: 'ig', +}; + +/** + * Get the CSS variable prefix for a given platform + * @param platform - The platform to get the prefix for + * @returns The CSS variable prefix (e.g., 'igx' for Angular, 'ig' for others) + */ +export function getVariablePrefix(platform: Platform): string { + return PLATFORM_VARIABLE_PREFIX[platform]; +} + /** * Platform metadata for display purposes */ diff --git a/src/mcp/tools/handlers/component-theme.ts b/src/mcp/tools/handlers/component-theme.ts index 17c4d594..67e8eec6 100644 --- a/src/mcp/tools/handlers/component-theme.ts +++ b/src/mcp/tools/handlers/component-theme.ts @@ -12,13 +12,35 @@ import { getComponentSelector, isComponentAvailable, getComponentPlatformAvailability, + hasVariants, + getVariants, } from '../../knowledge/index.js'; import type {CreateComponentThemeParams} from '../schemas.js'; export async function handleCreateComponentTheme(params: CreateComponentThemeParams) { - const {platform, component, tokens, selector, name} = params; + const {platform, component, tokens, selector, name, output = 'sass'} = params; const normalizedComponent = component.toLowerCase().trim(); + if (!platform) { + return { + content: [ + { + type: 'text' as const, + text: `**Error:** The \`platform\` parameter is required. + +**Valid platforms:** +- \`angular\` - Ignite UI for Angular +- \`webcomponents\` - Ignite UI for Web Components +- \`react\` - Ignite UI for React +- \`blazor\` - Ignite UI for Blazor + +Please specify which platform you're using to generate the correct variable prefixes and selectors.`, + }, + ], + isError: true, + }; + } + // Validate component exists const theme = getComponentTheme(normalizedComponent); if (!theme) { @@ -41,6 +63,28 @@ ${componentList.map((c) => `- ${c}`).join('\n')} }; } + // Check if component is a base variant component (button, icon-button) + // These components require specific variants for theming + if (hasVariants(normalizedComponent)) { + const variants = getVariants(normalizedComponent); + return { + content: [ + { + type: 'text' as const, + text: `**Error:** The \`${component}\` component has multiple variants and requires a specific variant for theming. + +**Available variants:** +${variants.map((v) => `- \`${v}\``).join('\n')} + +Please use \`create_component_theme\` with one of the specific variant names above. + +**Tip:** Use \`get_component_design_tokens\` with a specific variant (e.g., \`${variants[0]}\`) to see available tokens.`, + }, + ], + isError: true, + }; + } + // Check platform availability if platform is specified let platformWarning: string | null = null; if (platform) { @@ -104,7 +148,75 @@ Use \`get_component_design_tokens\` to see all tokens with descriptions.`, } } - // Generate the Sass code + if (output === 'css') { + try { + const {generateComponentThemeCss, formatCssOutput} = await import('../../generators/css.js'); + + const result = await generateComponentThemeCss({ + platform, + component: normalizedComponent, + tokens, + selector: finalSelector, + name, + }); + + // Build response + const responseParts: string[] = []; + + // Add platform warning if applicable (before the main content) + if (platformWarning) { + responseParts.push(platformWarning); + responseParts.push(''); + } + + responseParts.push(result.description); + responseParts.push(''); + + // Platform info + const platformNote = platform + ? `Platform: ${platform === 'angular' ? 'Ignite UI for Angular' : `Ignite UI for ${platform.charAt(0).toUpperCase() + platform.slice(1)}`}` + : 'Platform: Not specified (generic output). Specify `platform` for optimized imports.'; + responseParts.push(platformNote); + + // Selector info + if (finalSelector) { + responseParts.push(`Selector: \`${finalSelector}\``); + } + + responseParts.push(''); + responseParts.push('```css'); + responseParts.push(formatCssOutput(result.css, result.description).trimEnd()); + responseParts.push('```'); + + // Add usage hint + responseParts.push(''); + responseParts.push('---'); + responseParts.push( + "**Usage:** Include this CSS in your stylesheet or add it to your application's global styles.", + ); + + return { + content: [ + { + type: 'text' as const, + text: responseParts.join('\n'), + }, + ], + }; + } catch (error) { + return { + content: [ + { + type: 'text' as const, + text: `**Error generating CSS:** ${error instanceof Error ? error.message : String(error)}`, + }, + ], + isError: true, + }; + } + } + + // Generate the Sass code (original behavior) try { const result = generateComponentTheme({ platform, diff --git a/src/mcp/tools/schemas.ts b/src/mcp/tools/schemas.ts index 4f894675..7b1f29c1 100644 --- a/src/mcp/tools/schemas.ts +++ b/src/mcp/tools/schemas.ts @@ -276,11 +276,12 @@ const tokenValueSchema = z.union([ * Schema for create_component_theme tool. */ export const createComponentThemeSchema = z.object({ - platform: platformSchema, + platform: z.enum(PLATFORMS).describe(PARAM_DESCRIPTIONS.platform), component: z.string().describe(PARAM_DESCRIPTIONS.componentTheme), tokens: z.record(z.string(), tokenValueSchema).describe(PARAM_DESCRIPTIONS.tokens), selector: z.string().optional().describe(PARAM_DESCRIPTIONS.selector), name: z.string().optional().describe(PARAM_DESCRIPTIONS.themeName), + output: outputFormatSchema.describe(PARAM_DESCRIPTIONS.output), }); export type GetComponentDesignTokensParams = z.infer; From b0ecb2475c0886879c0114fc0f69cfdd2deedcf5 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Thu, 22 Jan 2026 10:25:25 +0200 Subject: [PATCH 05/38] feat(mcp): add design system and variant support to component themes Add designSystem and variant parameters to create_component_theme tool, enabling component themes to use the correct schema (e.g., -bootstrap-schema, -material-schema) based on the user's design system choice. Changes: - Add designSystem and variant parameters (default to material/light) - Pass schema as first parameter to component theme functions - Import schemas module in CSS generator for compilation - Update tool descriptions with design system examples - Add comprehensive tests for different design systems and variants BREAKING CHANGE: All component theme function calls now include schema parameter --- src/mcp/__tests__/generators/css.test.ts | 62 ++++++++++++++++++ .../__tests__/tools/handlers/handlers.test.ts | 65 +++++++++++++++++++ src/mcp/generators/css.ts | 40 ++++++++---- src/mcp/generators/sass.ts | 17 +++-- src/mcp/index.ts | 2 + src/mcp/tools/descriptions.ts | 51 +++++++++++++-- src/mcp/tools/handlers/component-theme.ts | 22 ++++++- src/mcp/tools/schemas.ts | 2 + 8 files changed, 237 insertions(+), 24 deletions(-) diff --git a/src/mcp/__tests__/generators/css.test.ts b/src/mcp/__tests__/generators/css.test.ts index d0001839..f40fb1f5 100644 --- a/src/mcp/__tests__/generators/css.test.ts +++ b/src/mcp/__tests__/generators/css.test.ts @@ -228,6 +228,8 @@ describe('generateComponentThemeCss', () => { const result = await generateComponentThemeCss({ platform: 'webcomponents', + designSystem: 'material', + variant: 'light', component: 'avatar', tokens: {background: '#ff5722'}, selector: 'igc-avatar', @@ -250,6 +252,8 @@ describe('generateComponentThemeCss', () => { const result = await generateComponentThemeCss({ platform: 'webcomponents', + designSystem: 'material', + variant: 'light', component: 'avatar', tokens: {background: '#ff5722'}, _loadPaths: TEST_LOAD_PATHS, @@ -265,6 +269,8 @@ describe('generateComponentThemeCss', () => { const result = await generateComponentThemeCss({ component: 'avatar', platform: 'webcomponents', + designSystem: 'material', + variant: 'light', tokens: {background: '#ff5722'}, _loadPaths: TEST_LOAD_PATHS, }); @@ -278,6 +284,8 @@ describe('generateComponentThemeCss', () => { const result = await generateComponentThemeCss({ platform: 'webcomponents', + designSystem: 'material', + variant: 'light', component: 'badge', tokens: { 'background-color': '#1976d2', @@ -297,6 +305,8 @@ describe('generateComponentThemeCss', () => { await expect( generateComponentThemeCss({ platform: 'webcomponents', + designSystem: 'material', + variant: 'light', component: 'unknown-component', tokens: {background: '#1976d2'}, _loadPaths: TEST_LOAD_PATHS, @@ -309,6 +319,8 @@ describe('generateComponentThemeCss', () => { const result = await generateComponentThemeCss({ platform: 'webcomponents', + designSystem: 'material', + variant: 'light', component: 'avatar', tokens: { background: '#ff5722', @@ -335,6 +347,8 @@ describe('generateComponentThemeCss', () => { const result = await generateComponentThemeCss({ component: 'avatar', platform: 'angular', + designSystem: 'material', + variant: 'light', tokens: {background: '#ff5722'}, _loadPaths: TEST_LOAD_PATHS, }); @@ -344,4 +358,52 @@ describe('generateComponentThemeCss', () => { // Should use igx prefix for variables in var() fallback expect(result.css).toContain('--background: var(--igx-avatar-background'); }); + + it('should include schema parameter for bootstrap design system', async () => { + const {generateComponentThemeCss} = await import('../../generators/css.js'); + + const result = await generateComponentThemeCss({ + component: 'avatar', + platform: 'webcomponents', + designSystem: 'bootstrap', + variant: 'light', + tokens: {background: '#ff5722'}, + _loadPaths: TEST_LOAD_PATHS, + }); + + // Check the description includes bootstrap + expect(result.description).toContain('bootstrap'); + expect(result.description).toContain('light'); + }); + + it('should include schema parameter for dark variant', async () => { + const {generateComponentThemeCss} = await import('../../generators/css.js'); + + const result = await generateComponentThemeCss({ + component: 'avatar', + platform: 'webcomponents', + designSystem: 'material', + variant: 'dark', + tokens: {background: '#ff5722'}, + _loadPaths: TEST_LOAD_PATHS, + }); + + // Check the description includes dark + expect(result.description).toContain('dark'); + }); + + it('should default to material light when not specified', async () => { + const {generateComponentThemeCss} = await import('../../generators/css.js'); + + const result = await generateComponentThemeCss({ + component: 'avatar', + platform: 'webcomponents', + tokens: {background: '#ff5722'}, + _loadPaths: TEST_LOAD_PATHS, + }); + + // Should default to material light + expect(result.description).toContain('material'); + expect(result.description).toContain('light'); + }); }); diff --git a/src/mcp/__tests__/tools/handlers/handlers.test.ts b/src/mcp/__tests__/tools/handlers/handlers.test.ts index 08656fd9..42193aaf 100644 --- a/src/mcp/__tests__/tools/handlers/handlers.test.ts +++ b/src/mcp/__tests__/tools/handlers/handlers.test.ts @@ -355,6 +355,8 @@ describe('handleCreateComponentTheme', () => { it('returns MCP response format for valid component', async () => { const result = await handleCreateComponentTheme({ platform: 'webcomponents', + designSystem: 'material', + variant: 'light', component: 'avatar', tokens: { background: '#ff5722', @@ -370,6 +372,8 @@ describe('handleCreateComponentTheme', () => { it('generates Sass code by default with platform-specific selector', async () => { const result = await handleCreateComponentTheme({ platform: 'webcomponents', + designSystem: 'material', + variant: 'light', component: 'avatar', tokens: { background: '#ff5722', @@ -387,6 +391,8 @@ describe('handleCreateComponentTheme', () => { it('generates CSS code when output is css', async () => { const result = await handleCreateComponentTheme({ platform: 'webcomponents', + designSystem: 'material', + variant: 'light', component: 'avatar', tokens: { background: '#ff5722', @@ -403,6 +409,8 @@ describe('handleCreateComponentTheme', () => { it('returns error for base button component (has variants)', async () => { const result = await handleCreateComponentTheme({ platform: 'webcomponents', + designSystem: 'material', + variant: 'light', component: 'button', tokens: { background: '#ff5722', @@ -422,6 +430,8 @@ describe('handleCreateComponentTheme', () => { it('returns error for base icon-button component (has variants)', async () => { const result = await handleCreateComponentTheme({ platform: 'webcomponents', + designSystem: 'material', + variant: 'light', component: 'icon-button', tokens: { background: '#ff5722', @@ -440,6 +450,8 @@ describe('handleCreateComponentTheme', () => { it('works with specific button variant (flat-button)', async () => { const result = await handleCreateComponentTheme({ platform: 'webcomponents', + designSystem: 'material', + variant: 'light', component: 'flat-button', tokens: { background: '#ff5722', @@ -455,6 +467,8 @@ describe('handleCreateComponentTheme', () => { it('works with components that have no variants (avatar)', async () => { const result = await handleCreateComponentTheme({ platform: 'webcomponents', + designSystem: 'material', + variant: 'light', component: 'avatar', tokens: { background: '#ff5722', @@ -470,6 +484,8 @@ describe('handleCreateComponentTheme', () => { it('validates tokens and returns error for invalid token', async () => { const result = await handleCreateComponentTheme({ platform: 'webcomponents', + designSystem: 'material', + variant: 'light', component: 'avatar', tokens: { invalidToken: '#ff5722', @@ -486,6 +502,8 @@ describe('handleCreateComponentTheme', () => { const result = await handleCreateComponentTheme({ component: 'avatar', platform: 'angular', + designSystem: 'material', + variant: 'light', tokens: { background: '#ff5722', }, @@ -501,6 +519,8 @@ describe('handleCreateComponentTheme', () => { const result = await handleCreateComponentTheme({ component: 'avatar', platform: 'webcomponents', + designSystem: 'material', + variant: 'light', tokens: { background: '#ff5722', }, @@ -510,4 +530,49 @@ describe('handleCreateComponentTheme', () => { const text = result.content[0].text; expect(text).toContain('igc-avatar'); }); + + it('includes design system and variant in response', async () => { + const result = await handleCreateComponentTheme({ + component: 'avatar', + platform: 'webcomponents', + designSystem: 'bootstrap', + variant: 'dark', + tokens: { + background: '#ff5722', + }, + }); + + const text = result.content[0].text; + expect(text).toContain('Bootstrap'); + expect(text).toContain('dark'); + }); + + it('defaults to material light when not specified', async () => { + const result = await handleCreateComponentTheme({ + component: 'avatar', + platform: 'webcomponents', + tokens: { + background: '#ff5722', + }, + }); + + const text = result.content[0].text; + expect(text).toContain('Material'); + expect(text).toContain('light'); + }); + + it('includes schema parameter in generated Sass code', async () => { + const result = await handleCreateComponentTheme({ + component: 'avatar', + platform: 'webcomponents', + designSystem: 'bootstrap', + variant: 'light', + tokens: { + background: '#ff5722', + }, + }); + + const text = result.content[0].text; + expect(text).toContain('$schema: $light-bootstrap-schema'); + }); }); diff --git a/src/mcp/generators/css.ts b/src/mcp/generators/css.ts index e0d98460..294e0877 100644 --- a/src/mcp/generators/css.ts +++ b/src/mcp/generators/css.ts @@ -8,6 +8,7 @@ import * as sass from 'sass-embedded'; import * as path from 'path'; import {fileURLToPath} from 'url'; import type {ColorDefinition, GrayDefinition, ThemeVariant} from '../utils/types.js'; +import type {PLATFORMS} from '../utils/types.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -23,6 +24,14 @@ export interface CssPaletteResult { description: string; } +/** + * Result from generating component theme CSS. + */ +export interface CssComponentThemeResult { + css: string; + description: string; +} + /** * Options for generating standard palette CSS variables. */ @@ -174,7 +183,11 @@ export function formatCssOutput(css: string, description: string): string { * Options for generating component theme CSS variables. */ export interface ComponentThemeCssOptions { - platform: 'angular' | 'webcomponents' | 'react' | 'blazor'; + platform: (typeof PLATFORMS)[number]; + /** Design system (defaults to 'material') */ + designSystem?: string; + /** Theme variant - light or dark (defaults to 'light') */ + variant?: string; /** Component name (e.g., "button", "avatar") */ component: string; /** Token name-value pairs */ @@ -187,14 +200,6 @@ export interface ComponentThemeCssOptions { _loadPaths?: string[]; } -/** - * Result from generating component theme CSS. - */ -export interface CssComponentThemeResult { - css: string; - description: string; -} - /** * Generate CSS custom properties for a component theme. * @@ -204,6 +209,8 @@ export interface CssComponentThemeResult { * @example * const result = await generateComponentThemeCss({ * platform: 'webcomponents', + * designSystem: 'bootstrap', + * variant: 'light', * component: 'button', * tokens: { background: '#1976d2', 'text-color': 'white' }, * selector: 'igc-button' @@ -212,7 +219,8 @@ export interface CssComponentThemeResult { */ export async function generateComponentThemeCss(options: ComponentThemeCssOptions): Promise { // Import functions we need (dynamic import to avoid circular dependencies) - const {getComponentTheme, getComponentSelector, getVariablePrefix} = await import('../knowledge/index.js'); + const {getComponentTheme, getComponentSelector, getVariablePrefix, SCHEMA_PRESETS} = + await import('../knowledge/index.js'); const {toVariableName} = await import('../utils/sass.js'); // Validate component exists @@ -222,10 +230,17 @@ export async function generateComponentThemeCss(options: ComponentThemeCssOption throw new Error(`Unknown component: ${options.component}`); } + const designSystem = options.designSystem ?? 'material'; + const variant = options.variant ?? 'light'; const themeFn = theme.themeFunctionName; const themeName = options.name ? `$${toVariableName(options.name)}` : `$custom-${options.component}-theme`; - const tokenArgs: string[] = []; + // Get the schema variable based on design system and variant + const schemaVar = + SCHEMA_PRESETS[variant as 'light' | 'dark'][designSystem as 'material' | 'indigo' | 'bootstrap' | 'fluent']; + + // Build token arguments - schema comes first + const tokenArgs: string[] = [`$schema: ${schemaVar}`]; for (const [tokenName, value] of Object.entries(options.tokens)) { const stringValue = typeof value === 'number' ? String(value) : value; @@ -243,6 +258,7 @@ export async function generateComponentThemeCss(options: ComponentThemeCssOption // Generate Sass code const sassCode = ` @use 'sass/themes' as *; +@use 'sass/themes/schemas' as *; // Custom ${options.component} theme ${themeName}: ${themeFn}( @@ -264,7 +280,7 @@ ${selector} { return { css: result.css, - description: `Generated CSS custom properties for ${options.component} component with ${Object.keys(options.tokens).length} token(s)`, + description: `Generated CSS custom properties for ${options.component} component with ${Object.keys(options.tokens).length} token(s) using ${designSystem} design system (${variant} variant)`, }; } catch (error) { const message = error instanceof Error ? error.message : String(error); diff --git a/src/mcp/generators/sass.ts b/src/mcp/generators/sass.ts index 255a481b..f2027c74 100644 --- a/src/mcp/generators/sass.ts +++ b/src/mcp/generators/sass.ts @@ -27,6 +27,7 @@ import { getComponentTheme, getComponentSelector, getVariablePrefix, + SCHEMA_PRESETS, } from '../knowledge/index.js'; // Re-export utilities for external use @@ -330,8 +331,11 @@ function generateGenericTheme( * Input for generating a component theme. */ export interface CreateComponentThemeInput { - /** Target platform (required) */ platform: Platform; + /** Design system (defaults to 'material') */ + designSystem?: DesignSystem; + /** Theme variant - light or dark (defaults to 'light') */ + variant?: ThemeVariant; /** Component name (e.g., "flat-button", "avatar") */ component: string; /** Token name-value pairs */ @@ -352,11 +356,16 @@ export function generateComponentTheme(input: CreateComponentThemeInput): Genera throw new Error(`Unknown component: ${input.component}`); } + const designSystem: DesignSystem = input.designSystem ?? 'material'; + const variant: ThemeVariant = input.variant ?? 'light'; const themeFn = theme.themeFunctionName; const themeName = input.name ? `$${toVariableName(input.name)}` : `$custom-${input.component}-theme`; - // Build token arguments - const tokenArgs: string[] = []; + // Get the schema variable based on design system and variant + const schemaVar = SCHEMA_PRESETS[variant][designSystem]; + + // Build token arguments - schema comes first + const tokenArgs: string[] = [`$schema: ${schemaVar}`]; for (const [tokenName, value] of Object.entries(input.tokens)) { // Convert value to string if needed const stringValue = typeof value === 'number' ? String(value) : value; @@ -397,7 +406,7 @@ export function generateComponentTheme(input: CreateComponentThemeInput): Genera return { code, - description: `Generated custom ${input.component} theme with ${Object.keys(input.tokens).length} token(s)`, + description: `Generated custom ${input.component} theme with ${Object.keys(input.tokens).length} token(s) using ${designSystem} design system (${variant} variant)`, variables: [themeName], }; } diff --git a/src/mcp/index.ts b/src/mcp/index.ts index 36863f36..17e7e37e 100644 --- a/src/mcp/index.ts +++ b/src/mcp/index.ts @@ -207,6 +207,8 @@ function registerTools(server: McpServer): void { description: TOOL_DESCRIPTIONS.create_component_theme, inputSchema: { platform: createComponentThemeSchema.shape.platform, + designSystem: createComponentThemeSchema.shape.designSystem, + variant: createComponentThemeSchema.shape.variant, component: createComponentThemeSchema.shape.component, tokens: createComponentThemeSchema.shape.tokens, selector: createComponentThemeSchema.shape.selector, diff --git a/src/mcp/tools/descriptions.ts b/src/mcp/tools/descriptions.ts index 6818c2ce..cdd5d338 100644 --- a/src/mcp/tools/descriptions.ts +++ b/src/mcp/tools/descriptions.ts @@ -645,11 +645,19 @@ export const TOOL_DESCRIPTIONS = { 1. First call get_component_design_tokens to discover available tokens 2. Choose which tokens to customize based on your design requirements - 3. Call this tool with component name and token values - 4. Receive ready-to-use Sass code with the component theme + 3. Specify designSystem and variant to match your theme (defaults to Material light) + 4. Call this tool with component name and token values + 5. Receive ready-to-use Sass code with the component theme + DESIGN SYSTEM & VARIANT: + - designSystem: Choose "material" (default), "bootstrap", "fluent", or "indigo" + - variant: Choose "light" (default) or "dark" + - The correct schema (e.g., $light-bootstrap-schema, $dark-material-schema) is + automatically selected and passed to the component theme function + - This ensures component tokens inherit proper defaults from the design system + TOKEN VALIDATION: - All provided token names are validated against the component's schema - Invalid tokens return an error with the list of valid token names @@ -672,9 +680,10 @@ export const TOOL_DESCRIPTIONS = { Returns: - Generated Sass code with: - Platform-specific @use import - - Theme function call with provided token values - - css-vars mixin to apply the theme to the selector + - Theme function call with $schema parameter and provided token values + - css-vars-from-theme mixin to apply the theme to the selector - Description of what was generated + - Design system and variant used - List of tokens used @@ -685,9 +694,11 @@ export const TOOL_DESCRIPTIONS = { - Custom blue flat button with rounded corners (Angular): + Custom blue flat button with rounded corners (Angular, Material Design): { "platform": "angular", + "designSystem": "material", + "variant": "light", "component": "flat-button", "tokens": { "background": "#1976D2", @@ -702,14 +713,40 @@ export const TOOL_DESCRIPTIONS = { @use 'igniteui-angular/theming' as *; $custom-flat-button-theme: flat-button-theme( + $schema: $light-material-schema, $background: #1976D2, $foreground: #FFFFFF, $hover-background: #1565C0, $border-radius: 24px ); - :root { - @include css-vars($custom-flat-button-theme); + igx-button[igxButton="flat"] { + @include css-vars-from-theme($custom-flat-button-theme, 'igx-button'); + } + \`\`\` + + Bootstrap dark theme example: + { + "platform": "webcomponents", + "designSystem": "bootstrap", + "variant": "dark", + "component": "avatar", + "tokens": { + "background": "#ff5722" + } + } + + Generates: + \`\`\`scss + @use 'igniteui-theming' as *; + + $custom-avatar-theme: avatar-theme( + $schema: $dark-bootstrap-schema, + $background: #ff5722 + ); + + igc-avatar { + @include css-vars-from-theme($custom-avatar-theme, 'ig-avatar'); } \`\`\` diff --git a/src/mcp/tools/handlers/component-theme.ts b/src/mcp/tools/handlers/component-theme.ts index 67e8eec6..fa9e31d6 100644 --- a/src/mcp/tools/handlers/component-theme.ts +++ b/src/mcp/tools/handlers/component-theme.ts @@ -18,7 +18,16 @@ import { import type {CreateComponentThemeParams} from '../schemas.js'; export async function handleCreateComponentTheme(params: CreateComponentThemeParams) { - const {platform, component, tokens, selector, name, output = 'sass'} = params; + const { + platform, + component, + tokens, + selector, + name, + output = 'sass', + designSystem = 'material', + variant = 'light', + } = params; const normalizedComponent = component.toLowerCase().trim(); if (!platform) { @@ -43,6 +52,7 @@ Please specify which platform you're using to generate the correct variable pref // Validate component exists const theme = getComponentTheme(normalizedComponent); + if (!theme) { const suggestions = searchComponents(normalizedComponent); const componentList = suggestions.length > 0 ? suggestions.slice(0, 10) : COMPONENT_NAMES.slice(0, 15); @@ -158,6 +168,8 @@ Use \`get_component_design_tokens\` to see all tokens with descriptions.`, tokens, selector: finalSelector, name, + designSystem, + variant, }); // Build response @@ -178,6 +190,9 @@ Use \`get_component_design_tokens\` to see all tokens with descriptions.`, : 'Platform: Not specified (generic output). Specify `platform` for optimized imports.'; responseParts.push(platformNote); + // Design system info + responseParts.push(`Design System: ${designSystem.charAt(0).toUpperCase() + designSystem.slice(1)} (${variant})`); + // Selector info if (finalSelector) { responseParts.push(`Selector: \`${finalSelector}\``); @@ -224,6 +239,8 @@ Use \`get_component_design_tokens\` to see all tokens with descriptions.`, tokens, selector: finalSelector, name, + designSystem, + variant, }); // Build response @@ -244,6 +261,9 @@ Use \`get_component_design_tokens\` to see all tokens with descriptions.`, : 'Platform: Not specified (generic output). Specify `platform` for optimized imports.'; responseParts.push(platformNote); + // Design system info + responseParts.push(`Design System: ${designSystem.charAt(0).toUpperCase() + designSystem.slice(1)} (${variant})`); + // Selector info if (finalSelector) { responseParts.push(`Selector: \`${finalSelector}\``); diff --git a/src/mcp/tools/schemas.ts b/src/mcp/tools/schemas.ts index 7b1f29c1..644f1da4 100644 --- a/src/mcp/tools/schemas.ts +++ b/src/mcp/tools/schemas.ts @@ -277,6 +277,8 @@ const tokenValueSchema = z.union([ */ export const createComponentThemeSchema = z.object({ platform: z.enum(PLATFORMS).describe(PARAM_DESCRIPTIONS.platform), + designSystem: designSystemSchema.describe(PARAM_DESCRIPTIONS.designSystem), + variant: variantSchema.describe(PARAM_DESCRIPTIONS.variant), component: z.string().describe(PARAM_DESCRIPTIONS.componentTheme), tokens: z.record(z.string(), tokenValueSchema).describe(PARAM_DESCRIPTIONS.tokens), selector: z.string().optional().describe(PARAM_DESCRIPTIONS.selector), From 68886fb285a6ee93826253516e1a520b75628391 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Mon, 26 Jan 2026 14:11:58 +0200 Subject: [PATCH 06/38] docs(mcp): add comprehensive MCP server documentation to READMEs - Add MCP Server section to main README.md with overview, quick start, and client setup instructions - Expand src/mcp/README.md with React and Blazor platform support - Document all 8 tools including get_component_design_tokens and create_component_theme - Add 2-5 meaningful prompt examples for each tool - Include setup instructions for VS Code, WebStorm, Claude Desktop, and Cursor - Provide both local development and published package (npx) configuration paths - Rename PLAN.md to ROADMAP.md for clarity - Remove outdated IMPROVEMENTS.md file - Update package.json to remove unused mcp:dev script --- README.md | 286 ++++++++++++++++- package.json | 1 - src/mcp/IMPROVEMENTS.md | 148 --------- src/mcp/README.md | 382 +++++++++++++++++------ src/mcp/{PLAN.md => ROADMAP.md} | 156 ++++----- src/mcp/knowledge/component-selectors.ts | 3 + src/mcp/tools/descriptions.ts | 2 +- 7 files changed, 626 insertions(+), 352 deletions(-) delete mode 100644 src/mcp/IMPROVEMENTS.md rename src/mcp/{PLAN.md => ROADMAP.md} (83%) diff --git a/README.md b/README.md index 7bf4c78e..05c19b59 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -

Ignite UI Theming - from Infragistics

@@ -8,6 +7,7 @@ The Ignite UI Theming repository collects a set of Sass mixins, functions, and variables used to create themes for a variety of UI frameworks built by Infragistics. The theming package makes it super easy to create palettes, elevations and typography styles for your projects. ## Palettes + We provide four predefined palettes - material, bootstrap, fluent and indigo that have all the necessary colors along with diffent variants of those colors to make it even easier picking the right one for your case. Here's what they look like: ![Palettes](https://user-images.githubusercontent.com/45598235/189592212-0d58b08d-3c98-4f27-8ec3-c6f674c9942b.png) @@ -18,10 +18,10 @@ To access any of the colors in the palettes, you can use the `color` function: background: color($light-material-palette, 'primary', 500); ``` -You can take a further look on what color functions and mixins the package contains and how to use them in the [Colors Wiki Page](https://github.com/IgniteUI/igniteui-theming/wiki/Colors-(Draft)) - +You can take a further look on what color functions and mixins the package contains and how to use them in the [Colors Wiki Page]() ## Typography + Another valuable module of our theming package is the typography, helping you have consistency all over your project. There are again four typography presets for the four themes that we provide out of the box. ![Typography](https://user-images.githubusercontent.com/45598235/189596034-d8697bc1-e683-4d4a-a113-96e17fc90d4b.png) @@ -32,9 +32,10 @@ You can set any of the typefaces by using the `typography` mixin, which accepts @include typography($font-family: $material-typeface, $type-scale: $material-type-scale); ``` -Learn more about the typography module in the package by checking out the [Typography Wiki Page](https://github.com/IgniteUI/igniteui-theming/wiki/Typography-(Draft)) +Learn more about the typography module in the package by checking out the [Typography Wiki Page]() ## Elevations + The theming package is providing one preset of shadows that can be used to give your components a lift. They're super helpful using with buttons, cards, navigation bars, etc. ![Elevations](https://user-images.githubusercontent.com/45598235/189627744-1fa47d35-6b3b-4b7a-b26e-5b46fe4311a4.png) @@ -45,7 +46,7 @@ You can set elevations 0-24, by using the `elevation` function, which accepts th box-shadow: elevation(12); ``` -Learn more about elevations and their abilities in the [Elevations Wiki Page](https://github.com/IgniteUI/igniteui-theming/wiki/Elevations-(draft)) +Learn more about elevations and their abilities in the [Elevations Wiki Page]() ## Usage @@ -106,8 +107,283 @@ npm run serve:docs ## Testing and Debugging ### Preview Palettes + To preview a palette you can pass the palette (`material`, `bootstrap`, `fluent`, `indigo`) and variant (`light` or `dark`) to the `palette` and `variant` arguments respectively. If you want to output the result to a file in the `./dist` folder add the `out` option. ``` npm run preview:palette -- --palette=material --variant=light --out ``` + +--- + +## MCP Server (AI-Assisted Theming) + +The Ignite UI Theming package includes a [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that enables AI assistants to generate production-ready theming code for your Ignite UI applications. + +### What is MCP? + +The Model Context Protocol allows AI assistants (like Claude, GitHub Copilot, and others) to connect to external tools and data sources. The Ignite UI Theming MCP server acts as an expert theming assistant that can: + +- 🎨 **Generate color palettes** with automatic shade variations +- 📝 **Create typography systems** following design standards +- 🌓 **Build complete themes** for light and dark modes +- 🎯 **Customize components** with design tokens +- ✅ **Validate colors** for accessibility compliance + +### Quick Start + +#### 1. Install and Build + +```bash +npm install igniteui-theming +npm run build:mcp +``` + +#### 2. Configure Your AI Client + +The MCP server works with any MCP-compatible client. Here are setup instructions for popular clients: + +
+VS Code (with MCP-compatible extensions) + +**For local development** - Create or edit `.vscode/settings.json`: + +```json +{ + "mcp.servers": { + "igniteui-theming": { + "command": "node", + "args": ["/absolute/path/to/igniteui-theming/dist/mcp/index.js"] + } + } +} +``` + +**Using published package**: + +```json +{ + "mcp.servers": { + "igniteui-theming": { + "command": "npx", + "args": ["igniteui-theming-mcp"] + } + } +} +``` + +
+ +
+WebStorm / JetBrains IDEs + +1. Go to **Settings → Tools → AI Assistant → MCP Servers** +2. Click **+ Add MCP Server** +3. Configure: + - **Name**: `igniteui-theming` + - **Command**: `node` (for local) or `npx` (for package) + - **Arguments**: + - Local: `/absolute/path/to/igniteui-theming/dist/mcp/index.js` + - Package: `igniteui-theming-mcp` +4. Click **OK** and restart AI Assistant + +
+ +
+Claude Desktop + +Add to your configuration file: + +**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` +**Windows**: `%APPDATA%\Claude\claude_desktop_config.json` + +**For local development**: + +```json +{ + "mcpServers": { + "igniteui-theming": { + "command": "node", + "args": ["/absolute/path/to/igniteui-theming/dist/mcp/index.js"] + } + } +} +``` + +**Using published package**: + +```json +{ + "mcpServers": { + "igniteui-theming": { + "command": "npx", + "args": ["igniteui-theming-mcp"] + } + } +} +``` + +
+ +
+Cursor + +Create or edit `.cursor/mcp.json` in your project: + +**For local development**: + +```json +{ + "mcpServers": { + "igniteui-theming": { + "command": "node", + "args": ["/absolute/path/to/igniteui-theming/dist/mcp/index.js"] + } + } +} +``` + +**Using published package**: + +```json +{ + "mcpServers": { + "igniteui-theming": { + "command": "npx", + "args": ["igniteui-theming-mcp"] + } + } +} +``` + +
+ +### What Can It Do? + +#### 🎨 Create Complete Themes + +Simply describe your theme to your AI assistant: + +> "Create a Material Design dark theme for my Angular app with that takes inspiration from the Gruvbox color scheme." + +The AI will generate production-ready Sass code with: + +- Color palette with all shade variations +- Typography setup with proper type scales +- Elevation shadows +- Platform-specific imports and configuration + +#### 🌈 Generate Color Palettes + +> "Generate a light theme palette using teal as primary and purple as secondary" + +Get perfectly calculated color shades following design system standards. + +#### 📝 Setup Typography + +> "Set up typography using Inter font with Material Design type scale for Web Components" + +Get proper typography configuration with font families and responsive type scales. + +#### 🎯 Customize Components + +> "What design tokens are available for the button component?" +> +> "Create a flat button theme with purple background and white text" + +Discover and customize individual component styles using design tokens. + +### Available Capabilities + +The MCP server provides **8 tools** and **16 resources**: + +#### Tools (Actions) + +| Tool | Description | +| ----------------------------- | --------------------------------------------------------------- | +| `detect_platform` | Auto-detect which Ignite UI platform your project uses | +| `create_palette` | Generate color palette with automatic shade calculations | +| `create_custom_palette` | Create palette with fine-grained control over individual shades | +| `create_typography` | Setup typography with font families and type scales | +| `create_elevations` | Configure elevation shadows | +| `create_theme` | Generate complete theme (palette + typography + elevations) | +| `get_component_design_tokens` | Discover customizable properties for components | +| `create_component_theme` | Generate component-specific theme code | + +#### Resources (Reference Data) + +- **Platform Information**: Configuration for Angular, Web Components, React, and Blazor +- **Preset Libraries**: Pre-built palettes, typography, and elevation sets +- **Color Guidance**: Best practices for color selection and usage +- **Design System Schemas**: Material, Bootstrap, Fluent, and Indigo configurations + +### Supported Platforms + +- **Angular** - `igniteui-angular` +- **Web Components** - `igniteui-webcomponents` +- **React** - `igniteui-react` +- **Blazor** - `igniteui-blazor` + +### Example Interactions + +
+Creating a new project theme + +**You**: "I'm starting a new Angular project with Ignite UI. Create a complete Material Design theme with primary blue, secondary coral, light theme, and Roboto font" + +**AI**: _Uses `create_theme` tool and generates complete Sass code ready to use_ + +
+ +
+Adding dark mode + +**You**: "I need a dark mode version with the same primary blue but dark surface" + +**AI**: _Uses `create_theme` with `variant: "dark"` and generates dark theme code_ + +
+ +
+Customizing components + +**You**: "What properties can I customize on the card component?" + +**AI**: _Uses `get_component_design_tokens` to show available tokens_ + +**You**: "Make the card have a light gray background with subtle shadow" + +**AI**: _Uses `create_component_theme` to generate component theme code_ + +
+ +### Full Documentation + +For detailed documentation including: + +- Complete tool parameter reference +- All prompt examples +- Platform-specific differences +- Troubleshooting guide +- Development instructions + +See the [MCP Server README](./src/mcp/README.md) + +### Development Scripts + +```bash +# Build for production +npm run build:mcp + +# Debug with MCP Inspector +npm run mcp:inspector + +# Run tests +npm run test +``` + +--- + +## Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. diff --git a/package.json b/package.json index 3a11ffcd..b0ac469d 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "lint:prettier": "prettier \"./sass/**/*.scss\" --check --ignore-path .gitignore", "format": "stylelint \"./sass/**/*.{scss,css}\" --fix --allow-empty-input --ignore-path .gitignore && prettier \"./sass/**/*.{scss,css}\" --write --ignore-path .gitignore", "prepare": "husky install", - "mcp:dev": "tsx src/mcp/index.ts", "mcp:inspector": "npx @modelcontextprotocol/inspector dist/mcp/index.js", "test": "vitest run", "coverage": "vitest run --coverage" diff --git a/src/mcp/IMPROVEMENTS.md b/src/mcp/IMPROVEMENTS.md deleted file mode 100644 index 50834897..00000000 --- a/src/mcp/IMPROVEMENTS.md +++ /dev/null @@ -1,148 +0,0 @@ -# MCP Server Code Quality & Maintainability Improvements - -## Goals - -1. **Improve maintainability** for when the Sass framework changes -2. **Prepare architecture** for upcoming component theming and additional tools -3. **Add comprehensive test coverage** with real, meaningful tests -4. **Reduce code duplication** and improve consistency - ---- - -## Phase 1: Foundation Cleanup (Low Risk, High Value) - COMPLETED - -### 1.1 Consolidate Duplicate Types and Constants - DONE - -**What:** Create a single source of truth for shared types and constants. - -**Changes made:** -- `src/mcp/utils/types.ts` - Added canonical constants: `PLATFORMS`, `DESIGN_SYSTEMS`, `VARIANTS`, `ELEVATION_PRESETS` -- `src/mcp/tools/schemas.ts` - Now imports constants from `utils/types.ts`, Zod schemas derive from them -- `src/mcp/knowledge/platforms/index.ts` - Now imports `Platform` from `utils/types.ts` -- `src/mcp/knowledge/typography.ts` - Now imports `DesignSystem` from `utils/types.ts` - -### 1.2 Centralize Utility Functions - DONE - -**What:** Move duplicated helper functions to a single location. - -**Changes made:** -- `src/mcp/utils/sass.ts` - Added `toVariableName()` and `generateHeader()` with proper validation -- `src/mcp/tools/handlers/custom-palette.ts` - Removed local duplicates, now imports from `utils/sass.ts` -- `src/mcp/generators/sass.ts` - Re-exports utilities for external use - -### 1.3 Fix Type Safety Issues - DONE - -**What:** Remove unsafe non-null assertions and add proper type guards. - -**Changes made:** -- `src/mcp/utils/color.ts` - Refactored `PaletteSuitabilityAnalysis` to use discriminated union: - - `PaletteSuitabilitySuitable` (suitable: true) - - `PaletteSuitabilityUnsuitable` (suitable: false, issue and description are guaranteed) -- `src/mcp/validators/palette.ts` - Removed `!` assertions, TypeScript now correctly narrows types - ---- - -## Phase 2: Test Infrastructure - COMPLETED - -### 2.1 Set Up Vitest Test Framework - DONE - -**Files created:** -- `vitest.config.mcp.ts` - Vitest configuration for MCP code - -### 2.2 Add Unit Tests for Utils - DONE - -**Test files created:** -- `src/mcp/__tests__/utils/sass.test.ts` - 24 tests for Sass utility functions -- `src/mcp/__tests__/utils/color.test.ts` - 30 tests for color analysis utilities - -### 2.3 Add Unit Tests for Validators - DONE - -**Test files created:** -- `src/mcp/__tests__/validators/custom-palette.test.ts` - 16 tests for custom palette validation - -### 2.4 Add Unit Tests for Generators - DONE - -**Test files created:** -- `src/mcp/__tests__/generators/sass.test.ts` - 28 tests for Sass code generators - -**Test approach:** -1. Test that generated code contains expected Sass constructs -2. Compile the generated code with sass-embedded to verify it's valid Sass -3. Test platform-specific output differences - -### 2.5 Add Unit Tests for Tool Handlers - DONE - -**Test files created:** -- `src/mcp/__tests__/tools/handlers/handlers.test.ts` - 25 tests for all tool handlers - -**Current test count: 123 tests, all passing** - ---- - -## Phase 3: Structural Improvements for Extensibility - COMPLETED - -### 3.1 Create Sass API Manifest - DONE - -**What:** Centralize Sass API knowledge for easier updates when framework changes. - -**Files created:** -- `src/mcp/knowledge/sass-api.ts` - Central manifest of all Sass API knowledge: - - `SASS_FUNCTIONS` - All Sass functions (palette, typography, elevations, spacing) - - `SASS_MIXINS` - All Sass mixins (palette, typography, elevations, etc.) - - `SASS_VARIABLE_PATTERNS` - Variable naming conventions for each module - - `CSS_CUSTOM_PROPERTIES` - CSS custom property patterns - - Helper functions: `getSassFunctionsByModule()`, `getSassMixinsByModule()`, etc. -- `src/mcp/__tests__/knowledge/sass-api.test.ts` - 52 tests - -### 3.2 Refactor Web Components Generator - DONE - -**What:** Break the 213-line function into smaller, testable pieces. - -**Changes made to `src/mcp/knowledge/platforms/webcomponents.ts`:** -- Extracted `generateWCHeader()` - file header comment -- Extracted `getWCElevationPreset()` - elevation variable lookup -- Extracted `generateWCImports()` - import statements -- Extracted `generateWCProgressProperties()` - CSS @property declarations -- Extracted `generateWCRootVariables()` - :root CSS variables -- Extracted `generateWCRtlSupport()` - RTL direction support -- Extracted `generateWCScrollbarCustomization()` - scrollbar styling -- Extracted `generateWCThemingMixins()` - palette/typography/elevations/spacing mixins -- Updated `src/mcp/knowledge/platforms/index.ts` - exports new helper functions -- `src/mcp/__tests__/knowledge/webcomponents.test.ts` - 26 tests - -### 3.3 Add Error Handling Consistency - DONE - -**What:** Standardize error handling across the codebase. - -**Files created:** -- `src/mcp/utils/result.ts` - Result type for explicit error handling: - - `Result` - discriminated union (Success | Failure) - - Helper functions: `success()`, `failure()`, `isSuccess()`, `isFailure()` - - `mapResult()`, `unwrap()`, `unwrapOr()` - utility functions - - `McpError` type with error codes: `INVALID_COLOR`, `INVALID_PARAMETER`, `SASS_COMPILATION_ERROR`, `VALIDATION_ERROR`, `NOT_FOUND`, `UNKNOWN_ERROR` - - `McpResult` - Result type using McpError for failures - - `ValidationResult` type with errors and warnings arrays - - Helper functions: `validationSuccess()`, `validationFailure()`, `combineValidationResults()`, `formatValidationMessages()` -- `src/mcp/__tests__/utils/result.test.ts` - 42 tests - ---- - -## Summary & Progress - -| Phase | Tasks | Status | Notes | -|-------|-------|--------|-------| -| 1.1 | Consolidate Types/Constants | DONE | Single source of truth in `utils/types.ts` | -| 1.2 | Centralize Utility Functions | DONE | `toVariableName`, `generateHeader` in `utils/sass.ts` | -| 1.3 | Fix Type Safety Issues | DONE | Discriminated union for `PaletteSuitabilityAnalysis` | -| 2.1 | Test Framework Setup | DONE | Vitest configured | -| 2.2 | Unit Tests for Utils | DONE | sass.test.ts (24), color.test.ts (30), result.test.ts (42) | -| 2.3 | Unit Tests for Validators | DONE | custom-palette.test.ts (16) | -| 2.4 | Unit Tests for Generators | DONE | sass.test.ts (28) | -| 2.5 | Unit Tests for Handlers | DONE | handlers.test.ts (25) | -| 3.1 | Sass API Manifest | DONE | sass-api.ts + 52 tests | -| 3.2 | Refactor WC Generator | DONE | 8 helper functions extracted + 26 tests | -| 3.3 | Error Handling | DONE | result.ts with Result + ValidationResult types | - -**Total tests: 243 passing** - -**Run tests:** `npm run test:mcp` diff --git a/src/mcp/README.md b/src/mcp/README.md index 88bc3249..abc56a6a 100644 --- a/src/mcp/README.md +++ b/src/mcp/README.md @@ -13,10 +13,12 @@ This MCP server helps you create custom themes for Ignite UI applications by gen ### Supported Platforms -| Platform | Package | Description | -|----------|---------|-------------| -| `angular` | `igniteui-angular` | Ignite UI for Angular applications | -| `webcomponents` | `igniteui-webcomponents` | Ignite UI for Web Components | +| Platform | Package | Description | +| --------------- | ------------------------ | ---------------------------------- | +| `angular` | `igniteui-angular` | Ignite UI for Angular applications | +| `webcomponents` | `igniteui-webcomponents` | Ignite UI for Web Components | +| `react` | `igniteui-react` | Ignite UI for React applications | +| `blazor` | `igniteui-blazor` | Ignite UI for Blazor applications | ### Supported Design Systems @@ -43,171 +45,365 @@ npm run build:mcp ### 3. Configure Your AI Client -#### Claude Desktop +The MCP server uses STDIO transport and can be configured with any MCP-compatible client. + +#### Editor Clients + +##### VS Code (with MCP-compatible extensions) + +**Using local clone (for development):** + +Create or edit `.vscode/settings.json`: + +```json +{ + "mcp.servers": { + "igniteui-theming": { + "command": "node", + "args": ["/absolute/path/to/igniteui-theming/dist/mcp/index.js"] + } + } +} +``` + +**Using installed package (via npx):** + +```json +{ + "mcp.servers": { + "igniteui-theming": { + "command": "npx", + "args": ["igniteui-theming-mcp"] + } + } +} +``` + +##### WebStorm / JetBrains IDEs + +1. Go to **Settings → Tools → AI Assistant → MCP Servers** +2. Click **+ Add MCP Server** +3. Configure: + - **Name**: `igniteui-theming` + - **Command**: `node` (for local) or `npx` (for installed package) + - **Arguments**: + - Local: `/absolute/path/to/igniteui-theming/dist/mcp/index.js` + - Package: `igniteui-theming-mcp` +4. Click **OK** and restart AI Assistant + +#### Desktop Clients + +##### Claude Desktop Add to your Claude Desktop configuration file: **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` +**Using local clone:** + ```json { "mcpServers": { "igniteui-theming": { "command": "node", - "args": ["/path/to/igniteui-theming/dist/mcp/index.js"] + "args": ["/absolute/path/to/igniteui-theming/dist/mcp/index.js"] } } } ``` -#### Using npx (after publishing) +**Using installed package (via npx):** ```json { "mcpServers": { "igniteui-theming": { "command": "npx", - "args": ["igniteui-theming/mcp"] + "args": ["igniteui-theming-mcp"] } } } ``` +##### Cursor + +Create or edit `.cursor/mcp.json` in your project: + +```json +{ + "mcpServers": { + "igniteui-theming": { + "command": "node", + "args": ["/absolute/path/to/igniteui-theming/dist/mcp/index.js"] + } + } +} +``` + +Or using npx: + +```json +{ + "mcpServers": { + "igniteui-theming": { + "command": "npx", + "args": ["igniteui-theming-mcp"] + } + } +} +``` + +#### Other MCP Clients + +For any other MCP-compatible client, use the STDIO transport configuration: + +- **Command**: `node` (or `npx`) +- **Arguments**: + - Local: `/absolute/path/to/igniteui-theming/dist/mcp/index.js` + - Package: `igniteui-theming-mcp` + +```` + --- ## Tools Reference -The MCP server provides 6 tools for theme generation. +The MCP server provides tools for theme generation. ### `detect_platform` Automatically detects whether your project uses Ignite UI for Angular or Web Components by analyzing `package.json`. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `packageJsonPath` | string | No | Path to package.json (default: `./package.json`) | +| Parameter | Type | Required | Description | +| ----------------- | ------ | -------- | ------------------------------------------------ | +| `packageJsonPath` | string | No | Path to package.json (default: `./package.json`) | + +**Example prompts:** -**Example prompt:** > "Detect which Ignite UI platform my project uses" +> "What Ignite UI package is installed in this project?" + +> "Check if I'm using Angular or Web Components for Ignite UI" + --- ### `create_palette` Generates a color palette with automatically calculated shade variations (50-900, A100-A700). -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `platform` | `"angular"` \| `"webcomponents"` | No | Target platform | -| `primary` | string | Yes | Primary brand color (hex, rgb, hsl, or named) | -| `secondary` | string | Yes | Secondary/accent color | -| `surface` | string | Yes | Background/surface color | -| `gray` | string | No | Gray/neutral color (auto-calculated if omitted) | -| `info` | string | No | Info state color | -| `success` | string | No | Success state color | -| `warn` | string | No | Warning state color | -| `error` | string | No | Error state color | -| `variant` | `"light"` \| `"dark"` | No | Theme variant (default: `"light"`) | -| `name` | string | No | Custom variable name | +| Parameter | Type | Required | Description | +| ----------- | -------------------------------- | -------- | ----------------------------------------------- | +| `platform` | `angular` \| `webcomponents"` | No | Target platform | +| `primary` | string | Yes | Primary brand color (hex, rgb, hsl, or named) | +| `secondary` | string | Yes | Secondary/accent color | +| `surface` | string | Yes | Background/surface color | +| `gray` | string | No | Gray/neutral color (auto-calculated if omitted) | +| `info` | string | No | Info state color | +| `success` | string | No | Success state color | +| `warn` | string | No | Warning state color | +| `error` | string | No | Error state color | +| `variant` | `"light"` \| `"dark"` | No | Theme variant (default: `"light"`) | +| `name` | string | No | Custom variable name | **Example prompts:** -> "Create a color palette with blue (#1976D2) as primary and orange (#FF9800) as secondary for a light theme" + +> "Create a color palette with blue as primary and orange as secondary for a light theme" > "Generate a dark theme palette using my brand colors: primary #6366F1, secondary #EC4899, surface #1E1E1E" +> "I need a light palette with teal primary, purple secondary, and white surface" + +> "Make me a professional dark mode palette with navy blue and gold accent" + --- ### `create_custom_palette` Creates a palette with fine-grained control over individual shade values. Use this when you have exact brand guidelines or when automatic shade generation produces suboptimal results. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `platform` | `"angular"` \| `"webcomponents"` | No | Target platform | -| `variant` | `"light"` \| `"dark"` | No | Theme variant | -| `designSystem` | `"material"` \| `"bootstrap"` \| `"fluent"` \| `"indigo"` | No | Design system preset | -| `name` | string | No | Custom variable name | -| `primary` | ColorDefinition | Yes | Primary color definition | -| `secondary` | ColorDefinition | Yes | Secondary color definition | -| `surface` | ColorDefinition | Yes | Surface color definition | -| `gray` | ColorDefinition | No | Gray color definition | -| `info` | ColorDefinition | No | Info color definition | -| `success` | ColorDefinition | No | Success color definition | -| `warn` | ColorDefinition | No | Warning color definition | -| `error` | ColorDefinition | No | Error color definition | +| Parameter | Type | Required | Description | +| -------------- | --------------------------------------------------------- | -------- | -------------------------- | +| `platform` | `angular` \| `webcomponents` | No | Target platform | +| `variant` | `"light"` \| `"dark"` | No | Theme variant | +| `designSystem` | `"material"` \| `"bootstrap"` \| `"fluent"` \| `"indigo"` | No | Design system preset | +| `name` | string | No | Custom variable name | +| `primary` | ColorDefinition | Yes | Primary color definition | +| `secondary` | ColorDefinition | Yes | Secondary color definition | +| `surface` | ColorDefinition | Yes | Surface color definition | +| `gray` | ColorDefinition | No | Gray color definition | +| `info` | ColorDefinition | No | Info color definition | +| `success` | ColorDefinition | No | Success color definition | +| `warn` | ColorDefinition | No | Warning color definition | +| `error` | ColorDefinition | No | Error color definition | **ColorDefinition** can be: + - `{ mode: "shades", baseColor: "#hexcolor" }` - Auto-generate shades from base color - `{ mode: "explicit", shades: { "50": "#...", "100": "#...", ... } }` - Specify all 14 shades manually **Example prompts:** + > "Create a custom palette where primary uses explicit shades from my brand guidelines, but secondary and surface are auto-generated" > "I have exact hex values for all 14 shades of my primary green color. Create a custom palette with these explicit values." +> "Our design system specifies exact colors for primary-500, primary-600, primary-700. Use those exact values and auto-generate the rest." + +> "Make a custom palette with explicit shades for primary (#3B82F6 as base) but let secondary auto-generate from #EC4899" + --- ### `create_typography` Sets up typography with your preferred font family. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `platform` | `"angular"` \| `"webcomponents"` | No | Target platform | -| `fontFamily` | string | Yes | Font family with fallbacks | -| `designSystem` | `"material"` \| `"bootstrap"` \| `"fluent"` \| `"indigo"` | No | Design system for type scale | -| `name` | string | No | Custom variable name | +| Parameter | Type | Required | Description | +| -------------- | --------------------------------------------------------- | -------- | ---------------------------- | +| `platform` | `"angular"` \| `"webcomponents"` | No | Target platform | +| `fontFamily` | string | Yes | Font family with fallbacks | +| `designSystem` | `"material"` \| `"bootstrap"` \| `"fluent"` \| `"indigo"` | No | Design system for type scale | +| `name` | string | No | Custom variable name | **Example prompts:** + > "Set up typography using Inter font with Material Design type scale" > "Configure typography with 'Segoe UI', Arial, sans-serif for a Fluent design system" +> "I want to use Roboto font for my Angular app with Bootstrap type scale" + +> "Set up typography with system fonts: -apple-system, BlinkMacSystemFont, 'Segoe UI' for Material Design" + --- ### `create_elevations` Configures elevation shadows for visual depth. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `platform` | `"angular"` \| `"webcomponents"` | No | Target platform | -| `designSystem` | `"material"` \| `"indigo"` | No | Elevation preset | -| `name` | string | No | Custom variable name | +| Parameter | Type | Required | Description | +| -------------- | -------------------------------- | -------- | -------------------- | +| `platform` | `"angular"` \| `"webcomponents"` | No | Target platform | +| `designSystem` | `"material"` \| `"indigo"` | No | Elevation preset | +| `name` | string | No | Custom variable name | **Example prompts:** + > "Set up Material Design elevations for my Angular app" > "Create Indigo-style shadows for my web components project" +> "I need Material Design shadows for my React components" + +> "Configure Indigo elevations with subtle shadows for a minimalist design" + --- ### `create_theme` Generates a complete, production-ready theme with palette, typography, and elevations combined. -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `platform` | `"angular"` \| `"webcomponents"` | No | Target platform | -| `designSystem` | `"material"` \| `"bootstrap"` \| `"fluent"` \| `"indigo"` | No | Design system | -| `primaryColor` | string | Yes | Primary brand color | -| `secondaryColor` | string | Yes | Secondary/accent color | -| `surfaceColor` | string | Yes | Background/surface color | -| `variant` | `"light"` \| `"dark"` | No | Theme variant | -| `name` | string | No | Custom theme name | -| `fontFamily` | string | No | Font family | -| `includeTypography` | boolean | No | Include typography (default: `true`) | -| `includeElevations` | boolean | No | Include elevations (default: `true`) | -| `includeSpacing` | boolean | No | Include spacing - Web Components only (default: `true`) | +| Parameter | Type | Required | Description | +| ------------------- | --------------------------------------------------------- | -------- | ------------------------------------------------------- | +| `platform` | `"angular"` \| `"webcomponents"` | No | Target platform | +| `designSystem` | `"material"` \| `"bootstrap"` \| `"fluent"` \| `"indigo"` | No | Design system | +| `primaryColor` | string | Yes | Primary brand color | +| `secondaryColor` | string | Yes | Secondary/accent color | +| `surfaceColor` | string | Yes | Background/surface color | +| `variant` | `"light"` \| `"dark"` | No | Theme variant | +| `name` | string | No | Custom theme name | +| `fontFamily` | string | No | Font family | +| `includeTypography` | boolean | No | Include typography (default: `true`) | +| `includeElevations` | boolean | No | Include elevations (default: `true`) | +| `includeSpacing` | boolean | No | Include spacing - Web Components only (default: `true`) | **Example prompts:** + > "Create a complete Material Design dark theme for my Angular app with primary #3F51B5, secondary #FF4081, and a dark surface" > "Generate a production-ready Bootstrap light theme using my brand colors: primary teal (#009688), secondary amber (#FFC107)" > "Create a Fluent theme for Web Components with Segoe UI font, blue primary, and orange accent colors" +> "I need a dark Indigo theme for React with navy blue primary (#1E3A8A), warm orange secondary (#F97316), and charcoal surface (#18181B)" + +> "Make a light Material theme for Blazor using our brand: primary #7C3AED (purple), secondary #10B981 (green), with Inter font" + +--- + +### `get_component_design_tokens` + +Discovers available design tokens (customizable properties) for a specific Ignite UI component. Use this tool **before** `create_component_theme` to see what tokens are available. + +| Parameter | Type | Required | Description | +| ----------- | ------ | -------- | ----------------------------------------------- | +| `component` | string | Yes | Component name (e.g., "button", "card", "grid") | + +**Example prompts:** + +> "What design tokens are available for the button component?" + +> "Show me all the customizable properties for the data grid" + +> "I want to style the card component - what tokens can I use?" + +**Sample response:** + +```json +{ + "component": "button", + "tokens": { + "background": "Background color of the button", + "foreground": "Text color of the button", + "border-color": "Border color of the button", + "hover-background": "Background color on hover", + "disabled-foreground": "Text color when disabled" + } +} +```` + +--- + +### `create_component_theme` + +Generates Sass code to customize a specific component's appearance using design tokens. Call `get_component_design_tokens` first to discover available tokens. + +| Parameter | Type | Required | Description | +| -------------- | ----------------------------------------------------------- | -------- | ------------------------------------- | +| `platform` | `"angular"` \| `"webcomponents"` \| `"react"` \| `"blazor"` | No | Target platform | +| `component` | string | Yes | Component name | +| `designSystem` | `"material"` \| `"bootstrap"` \| `"fluent"` \| `"indigo"` | No | Design system | +| `variant` | `"light"` \| `"dark"` | No | Theme variant | +| `tokens` | object | Yes | Design token values (key-value pairs) | + +**Example prompts:** + +> "Create a button theme with a purple background (#8B5CF6) and white text" + +> "Style the card component with a light gray background and subtle shadow" + +> "Make the data grid header bold with a blue background (#1E40AF)" + +> "Customize the input component for dark mode with a dark background and bright border" + +**Example interaction:** + +``` +User: "I want to create a custom theme for buttons with my brand colors" + +AI: First, let me check what design tokens are available for buttons. +[calls get_component_design_tokens with component="button"] + +AI: Great! I can customize these properties: background, foreground, border-color, +hover-background, and more. What are your brand colors? + +User: "Primary purple #8B5CF6, white text, and lighter purple #A78BFA on hover" + +AI: Perfect! Let me create that theme for you. +[calls create_component_theme with tokens] +``` + --- ## Resources Reference @@ -216,32 +412,32 @@ The MCP server exposes read-only resources that provide reference data. ### Platform Resources -| URI | Description | -|-----|-------------| -| `theming://platforms` | List of supported platforms | -| `theming://platforms/angular` | Angular platform configuration and usage examples | +| URI | Description | +| ----------------------------------- | -------------------------------------------------- | +| `theming://platforms` | List of supported platforms | +| `theming://platforms/angular` | Angular platform configuration and usage examples | | `theming://platforms/webcomponents` | Web Components platform configuration and examples | ### Preset Resources -| URI | Description | -|-----|-------------| -| `theming://presets/palettes` | All predefined palette configurations | -| `theming://presets/palettes/light` | Light mode palette presets | -| `theming://presets/palettes/dark` | Dark mode palette presets | -| `theming://presets/typography` | Typography presets for all design systems | -| `theming://presets/elevations` | Elevation shadow presets | +| URI | Description | +| ---------------------------------- | ----------------------------------------- | +| `theming://presets/palettes` | All predefined palette configurations | +| `theming://presets/palettes/light` | Light mode palette presets | +| `theming://presets/palettes/dark` | Dark mode palette presets | +| `theming://presets/typography` | Typography presets for all design systems | +| `theming://presets/elevations` | Elevation shadow presets | ### Color Guidance Resources -| URI | Description | -|-----|-------------| -| `theming://guidance/colors` | Overview of color guidance resources | -| `theming://guidance/colors/rules` | Light/dark theme color rules | -| `theming://guidance/colors/usage` | Which shades to use for different purposes | -| `theming://guidance/colors/roles` | Semantic meaning of each color family | -| `theming://guidance/colors/states` | Color changes for interaction states | -| `theming://guidance/colors/themes` | Design system-specific color patterns | +| URI | Description | +| ---------------------------------- | ------------------------------------------ | +| `theming://guidance/colors` | Overview of color guidance resources | +| `theming://guidance/colors/rules` | Light/dark theme color rules | +| `theming://guidance/colors/usage` | Which shades to use for different purposes | +| `theming://guidance/colors/roles` | Semantic meaning of each color family | +| `theming://guidance/colors/states` | Color changes for interaction states | +| `theming://guidance/colors/themes` | Design system-specific color patterns | --- @@ -250,8 +446,9 @@ The MCP server exposes read-only resources that provide reference data. ### Scenario 1: New Project Setup > "I'm starting a new Angular project with Ignite UI. Create a complete Material Design theme with: +> > - Primary: our brand blue #2563EB -> - Secondary: coral accent #F97316 +> - Secondary: coral accent #F97316 > - Light theme > - Roboto font" @@ -259,7 +456,7 @@ The AI will use `create_theme` to generate ready-to-use Sass code. ### Scenario 2: Dark Mode Variant -> "I need a dark mode version of my theme. Use the same primary blue #2563EB but with a dark surface color #121212" +> "I need a dark mode version of my theme. Use the same primary blue but with a dark surface color #121212" ### Scenario 3: Brand Guidelines with Exact Colors @@ -275,7 +472,7 @@ The AI will use `create_typography` to generate only the typography setup. ### Scenario 5: Platform Detection -> "Check my package.json and tell me which Ignite UI platform I'm using, then create an appropriate theme" +> "Check my project and tell me which Ignite UI platform I'm using, then create an appropriate theme" The AI will first use `detect_platform`, then use the detected platform for `create_theme`. @@ -301,12 +498,6 @@ The AI will first use `detect_platform`, then use the detected platform for `cre ## Development -### Running in Development Mode - -```bash -npm run mcp:dev -``` - ### Running Tests ```bash @@ -332,14 +523,16 @@ npm run mcp:inspector ### "Platform not detected" If `detect_platform` returns `null`, ensure: + - The `package.json` path is correct -- Your project has `igniteui-angular` or `igniteui-webcomponents` in dependencies +- Your project has `igniteui-angular`, `igniteui-webcomponents`, `igniteui-react`, or `Ignite UI for Blazor` in dependencies You can always specify the `platform` parameter explicitly. ### "Luminance warning" on colors If you see warnings about color luminance, it means your chosen color may produce suboptimal automatic shade generation. Options: + 1. Choose a color with mid-range luminance (not too light or too dark) 2. Use `create_custom_palette` with explicit shade values @@ -351,6 +544,7 @@ For dark themes, use dark surface colors (low luminance like `#121212`). ### Generated code doesn't compile Ensure you have the correct Ignite UI package installed: + - Angular: `npm install igniteui-angular` - Web Components: `npm install igniteui-webcomponents` diff --git a/src/mcp/PLAN.md b/src/mcp/ROADMAP.md similarity index 83% rename from src/mcp/PLAN.md rename to src/mcp/ROADMAP.md index 217c8589..e296c95e 100644 --- a/src/mcp/PLAN.md +++ b/src/mcp/ROADMAP.md @@ -1,4 +1,4 @@ -# Ignite UI Theming MCP Server - Implementation Plan +# Ignite UI Theming MCP Server - ROADMAP ## Executive Summary @@ -22,17 +22,19 @@ The server should understand context, make smart defaults, and guide users towar The MCP server supports two target platforms for theme generation: -| Platform | Package | Theming Module | Key Characteristics | -|----------|---------|----------------|---------------------| -| `angular` | `igniteui-angular` | `igniteui-angular/theming` | Uses `core()` + `theme()` mixins, forwards igniteui-theming with overrides | -| `webcomponents` | `igniteui-webcomponents` | `igniteui-theming` | Uses individual mixins (`palette()`, `typography()`, `elevations()`), supports runtime switching | +| Platform | Package | Theming Module | Key Characteristics | +|-----------------|--------------------------|----------------------------|--------------------------------------------------------------------------------------------------| +| `angular` | `igniteui-angular` | `igniteui-angular/theming` | Uses `core()` + `theme()` mixins, forwards igniteui-theming with overrides | +| `webcomponents` | `igniteui-webcomponents` | `igniteui-theming` | Uses individual mixins (`palette()`, `typography()`, `elevations()`), supports runtime switching | +| `react` | `igniteui-react` | `igniteui-theming` | Uses individual mixins (`palette()`, `typography()`, `elevations()`), supports runtime switching | +| `blazor` | `igniteui-blazor` | `igniteui-theming` | Uses individual mixins (`palette()`, `typography()`, `elevations()`), supports runtime switching | ### Platform Detection Strategy The server can detect the target platform through multiple methods: 1. **Explicit Parameter**: User specifies `platform: 'angular'` or `platform: 'webcomponents'` -2. **Automatic Detection**: `detect_platform` tool reads `package.json` to infer platform from dependencies +2. **Automatic Detection**: `detect_platform` tool reads `package.json` and other platform-specific files to infer platform from dependencies 3. **Fallback**: Generate platform-agnostic code when detection fails ### Key Platform Differences @@ -65,12 +67,12 @@ The server can detect the target platform through multiple methods: - Requires `ig-typography` CSS class on root element - Typography module is overridden with Angular-specific implementation -#### Ignite UI for Web Components +#### Ignite UI for Web Components (et al.) ```scss // Uses igniteui-theming directly -@use 'igniteui-theming/sass/color/presets/light/material' as *; @use 'igniteui-theming' as *; +@use 'igniteui-theming/sass/color/presets/light/material' as *; @use 'igniteui-theming/sass/typography/presets/material' as *; @use 'igniteui-theming/sass/elevations/presets' as *; @@ -120,8 +122,7 @@ The server can detect the target platform through multiple methods: │ ┌──────────────────────────────────────────────────────┐ │ │ │ • SassGenerator - Generates valid Sass code │ │ │ │ • CssGenerator - Generates CSS custom properties │ │ -│ │ • Validator - Validates via dart-sass (optional) │ │ -│ │ • SchemaEngine - Processes theme schemas │ │ +│ │ • Validator - Validates via Sass │ │ │ └──────────────────────────────────────────────────────┘ │ ├─────────────────────────────────────────────────────────────┤ │ Knowledge Base (Embedded) │ @@ -148,13 +149,14 @@ Tools are the core of the MCP server - they perform actions and generate code. #### Tool Category 1: Theme Foundation -| Tool Name | Description | Input Schema | Output | -| ------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------- | --------------------- | -| `create_theme` | Create a complete theme foundation | `{ platform?, designSystem?, primaryColor, secondaryColor?, surfaceColor?, variant?, name? }` | Sass/CSS theme code | -| `create_palette` | Generate a color palette | `{ platform?, primary, secondary?, surface?, gray?, info?, success?, warn?, error?, variant? }` | Palette definition | -| `create_typography` | Set up typography system | `{ platform?, fontFamily, designSystem?, baseFontSize?, customScale? }` | Typography setup code | -| `create_elevations` | Configure elevation/shadow system | `{ platform?, designSystem?, customColors? }` | Elevations setup code | -| `detect_platform` | Detect target platform from project| `{ packageJsonPath? }` | Platform detection | +| Tool Name | Description | Input Schema | Output | +| ------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------- | --------------------- | +| `detect_platform` | Detect target platform from project | `{ packageJsonPath? }` | Platform detection | +| `create_palette` | Generate a color palette | `{ platform, variant, designSystem?, name?, output?, primary, secondary, surface, gray?, info?, success?, warn?, error? }` | Palette definition | +| `create_custom_palette` | Generate a custom color palette | `{ platform, variant, designSystem?, name?, output?, primary, secondary, surface, gray?, info?, success?, warn?, error? }` | Palette definition | +| `create_typography` | Set up typography system | `{ platform, fontFamily, designSystem?, baseFontSize?, customScale? }` | Typography setup code | +| `create_elevations` | Configure elevation/shadow system | `{ platform, designSystem?, customColors? }` | Elevations setup code | +| `create_theme` | Create a complete theme foundation | `{ platform?, designSystem?, primaryColor, secondaryColor?, surfaceColor?, variant?, name? }` | Sass/CSS theme code | #### Tool Category 2: Color Operations @@ -181,13 +183,12 @@ Tools are the core of the MCP server - they perform actions and generate code. | `get_sizable_value` | Get responsive size value | `{ small, medium, large }` | Sizable expression | | `get_padding` | Get contextual padding | `{ small?, medium?, large?, direction? }` | Padding expression | -#### Tool Category 5: Component Theming (Extensible) +#### Tool Category 5: Component Theming -| Tool Name | Description | Input Schema | Output | -| ------------------------ | -------------------------- | ----------------------------------- | -------------------- | -| `create_component_theme` | Create a component theme | `{ component, schema?, overrides }` | Component theme code | -| `list_component_themes` | List available components | `{ category? }` | Component catalog | -| `get_component_schema` | Get schema for a component | `{ component, designSystem? }` | Schema definition | +| Tool Name | Description | Input Schema | Output | +| ----------------------------- | -------------------------- | ---------------------------------------------------------- | -------------------- | +| `create_component_theme` | Create a component theme | `{ platform, designSystem?, variant?, component, tokens }` | Component theme code | +| `get_component_design_tokens` | Get schema for a component | `{ component }` | Schema definition | #### Tool Category 6: Validation & Utilities @@ -208,6 +209,8 @@ Resources provide read-only context that AI applications can use. | `theming://platforms` | List of supported platforms | `application/json` | | `theming://platforms/angular` | Angular platform configuration & usage | `application/json` | | `theming://platforms/webcomponents` | Web Components platform config & usage | `application/json` | +| `theming://platforms/react` | React platform config & usage | `application/json` | +| `theming://platforms/blazor` | Blazor platform config & usage | `application/json` | #### Resource Category 2: Presets (Direct Resources) @@ -218,7 +221,6 @@ Resources provide read-only context that AI applications can use. | `theming://presets/palettes/dark` | Dark palette variants | `application/json` | | `theming://presets/typography` | All typography presets | `application/json` | | `theming://presets/elevations` | Elevation definitions | `application/json` | -| `theming://presets/easings` | Animation easing functions | `application/json` | #### Resource Category 4: Schemas (Direct Resources) @@ -249,34 +251,35 @@ Resources provide read-only context that AI applications can use. | `theming://docs/mixins/{name}` | Mixin documentation | | `theming://docs/variables/{name}` | Variable documentation | -### 3. Prompts (User-Controlled Templates) - -Pre-built interaction templates for common theming tasks. - -| Prompt Name | Description | Arguments | -| ------------------------- | ------------------------------------------ | --------------------------------------- | -| `create-app-theme` | Guided theme creation for an application | `appType`, `primaryColor?`, `variant?` | -| `brand-to-palette` | Convert brand colors to a full palette | `brandColors[]`, `style?` | -| `accessibility-audit` | Check theme for accessibility issues | `themeCode` | -| `migrate-theme` | Migrate from one design system to another | `fromSystem`, `toSystem`, `currentCode` | -| `dark-mode-variant` | Create dark mode variant of existing theme | `lightThemeCode` | -| `component-customization` | Guide through customizing a component | `componentName`, `goals` | +#### Category 7: Guidance (Direct Resources) +| URI | Description | MIME Type | +| ----------------------------------- | ------------------------------------------------ | ------------------ | +| `theming://guidance/colors` | Color usage guidelines | `text/markdown` | +| `theming://guidance/colors/rules` | Color Shades scaling guidance | `text/markdown` | +| `theming://guidance/colors/usage` | Color Shades usage guidance | `text/markdown` | +| `theming://guidance/colors/roles` | Color Shades roles guidance | `text/markdown` | +| `theming://guidance/colors/states` | Color Shades in components states guidance | `text/markdown` | +| `theming://guidance/colors/themes` | How color shades are used across themes | `text/markdown` | --- ## Implementation Phases -### Phase 1: Foundation (MVP) +### Phase 1: Foundation (Done) -**Goal**: Core palette, typography, and elevation generation +**Goal**: Core palette, typography, and elevation generation, and per-component themes **Deliverables**: - MCP server scaffolding with STDIO transport -- `create_theme` tool (basic) +- `detect_platform` tool +- `create_theme` tool - `create_palette` tool +- `create_custom_palette` tool - `create_typography` tool - `create_elevations` tool +- `get_component_design_tokens` tool +- `create_component_theme` tool - Preset resources (palettes, typography, elevations) - Basic Sass and CSS code generation @@ -288,7 +291,7 @@ Pre-built interaction templates for common theming tasks. - Both elevation presets (material, indigo) - Shade generation algorithms -### Phase 2: Color Intelligence +### Phase 2: Color Intelligence (Partially Done) **Goal**: Smart color operations, validation, and suggestions @@ -305,7 +308,7 @@ Pre-built interaction templates for common theming tasks. **Implemented: Surface/Gray Color Validation** -The `create_palette` and `create_theme` tools now validate surface and gray colors against the theme variant: +The `create_palette`, `create_custom_palette`, and `create_theme` tools validate surface and gray colors against the theme variant: | Variant | Surface Requirement | Gray Requirement | |---------|---------------------|------------------| @@ -320,15 +323,6 @@ The `create_palette` and `create_theme` tools now validate surface and gray colo - Tips suggest omitting gray parameter to let it auto-calculate - Uses Sass `luminance()` function via `sass-embedded` for accurate calculation -**New files:** -- `src/mcp/utils/color.ts` - Sass-powered color analysis (luminance, contrast) -- `src/mcp/validators/palette.ts` - Validation logic -- `src/mcp/validators/index.ts` - Validators barrel export -- `src/mcp/knowledge/colors.ts` - Color rules documentation - -**New resource:** -- `theming://guidance/colors` - Markdown documentation about color rules - **Data to Embed**: - WCAG contrast calculation algorithms @@ -365,34 +359,6 @@ The `create_palette` and `create_theme` tools now validate surface and gray colo - Sass compilation service for validation - Error message interpretation -### Phase 5: Component Themes (Extensible) - -**Goal**: Per-component theme generation - -**Deliverables**: - -- `create_component_theme` tool -- `list_component_themes` tool -- `get_component_schema` tool -- Component catalog resources -- Component examples resources - -**Strategy for Component Extensibility**: - -```typescript -// Component registry pattern -interface ComponentThemeDefinition { - name: string; - properties: PropertyDefinition[]; - schema: Record; - defaults: Record>; - generator: (options: ThemeOptions) => string; -} - -// Components can be added incrementally -const componentRegistry = new Map(); -``` - --- ## Data Extraction Strategy @@ -568,7 +534,7 @@ Both platforms generate similar CSS custom properties: --- -## File Structure +## File Structure (Initial Scaffolding) ``` src/mcp/ @@ -674,15 +640,8 @@ export default defineConfig({ ```json { "@modelcontextprotocol/sdk": "^1.0.0", - "zod": "^3.0.0" -} -``` - -### Optional Dependencies (for validation) - -```json -{ - "sass": "^1.92.0" + "zod": "^3.0.0", + "sass-embedded": "^1.92.0" } ``` @@ -789,13 +748,13 @@ export default defineConfig({ ## Open Questions -1. **Sass Compilation for Validation**: Should we bundle dart-sass for runtime validation, or make it optional/lazy-loaded to reduce package size? - -2. **HTTP Transport**: Should Phase 1 include HTTP transport for remote hosting, or is STDIO sufficient for MVP? - -3. **Component Priority**: Which components should be prioritized for Phase 5? Suggest: button, card, input, grid (most commonly themed) +1. **HTTP Transport**: + - Q: Will Phase 1 include HTTP transport for remote hosting, or is STDIO sufficient for MVP? + - A: No. Phase 1 will focus on STDIO. HTTP transport can be added in a later phase if needed. -4. **Caching**: Should validated themes be cached? What invalidation strategy? +2. **Caching**: + - Q: Should validated themes be cached? What invalidation strategy? + - A: Not in Phase 1. Caching can be considered in future phases based on performance needs. --- @@ -897,12 +856,3 @@ export default defineConfig({ - `$ease-in-quad`, `$ease-in-cubic`, `$ease-in-quart`, etc. - `$ease-out-quad`, `$ease-out-cubic`, `$ease-out-quart`, etc. - `$ease-in-out-quad`, `$ease-in-out-cubic`, etc. ---- - -## Next Steps - -1. Review and approve this plan -2. Set up project scaffolding with Vite -3. Implement Phase 1 tools -4. Test with Claude Desktop/Code and other AI assistants -5. Iterate based on feedback diff --git a/src/mcp/knowledge/component-selectors.ts b/src/mcp/knowledge/component-selectors.ts index 5950b55b..7942f564 100644 --- a/src/mcp/knowledge/component-selectors.ts +++ b/src/mcp/knowledge/component-selectors.ts @@ -410,6 +410,7 @@ export const COMPOUND_COMPONENTS: Record = { description: 'The grid is a complex compound component with many themeable parts including filtering, editing, and selection.', relatedThemes: [ + 'action-strip', 'checkbox', 'chip', 'input-group', @@ -427,6 +428,7 @@ export const COMPOUND_COMPONENTS: Record = { ], innerSelectors: { angular: { + 'action-strip': 'igx-grid igx-action-strip', checkbox: 'igx-grid igx-checkbox', chip: 'igx-grid igx-chip', 'input-group': 'igx-grid igx-input-group', @@ -443,6 +445,7 @@ export const COMPOUND_COMPONENTS: Record = { 'grid-toolbar': 'igx-grid igx-grid-toolbar', }, webcomponents: { + 'action-strip': 'TODO', checkbox: 'TODO', chip: 'TODO', 'input-group': 'TODO', diff --git a/src/mcp/tools/descriptions.ts b/src/mcp/tools/descriptions.ts index cdd5d338..d2dc561b 100644 --- a/src/mcp/tools/descriptions.ts +++ b/src/mcp/tools/descriptions.ts @@ -645,7 +645,7 @@ export const TOOL_DESCRIPTIONS = { 1. First call get_component_design_tokens to discover available tokens 2. Choose which tokens to customize based on your design requirements - 3. Specify designSystem and variant to match your theme (defaults to Material light) + 3. Specify designSystem and variant to match the global theme or the one explicitly requested (defaults to Material light) 4. Call this tool with component name and token values 5. Receive ready-to-use Sass code with the component theme From 4fb38f2c9d3a50e35048622c62cc8ca16b89723a Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Mon, 26 Jan 2026 15:02:38 +0200 Subject: [PATCH 07/38] feat(mcp): add get_color tool for palette color retrieval Add new MCP tool that retrieves Ignite UI Theming palette colors as CSS variable references with optional contrast and opacity variations. Features: - Retrieves any palette color (primary, secondary, gray, surface, info, success, warn, error) - Supports all shade variants (50-900, A100-A700) - Returns contrast colors via 'contrast' parameter - Applies opacity using CSS relative color syntax - Validates gray colors don't use accent shades This consolidates the planned get_color and get_contrast_color tools from the roadmap into a single, more versatile tool using a contrast boolean flag. Changes: - Add getColorSchema with Zod validation and gray shade validation - Implement handleGetColor handler with usage examples - Register get_color tool in MCP server - Update ROADMAP.md to reflect tool consolidation and progress --- src/mcp/ROADMAP.md | 115 +++++++++++++++----------------- src/mcp/index.ts | 23 +++++++ src/mcp/tools/descriptions.ts | 74 ++++++++++++++++++++ src/mcp/tools/handlers/color.ts | 105 +++++++++++++++++++++++++++++ src/mcp/tools/handlers/index.ts | 1 + src/mcp/tools/index.ts | 3 + src/mcp/tools/schemas.ts | 39 +++++++++++ 7 files changed, 298 insertions(+), 62 deletions(-) create mode 100644 src/mcp/tools/handlers/color.ts diff --git a/src/mcp/ROADMAP.md b/src/mcp/ROADMAP.md index e296c95e..7be2442f 100644 --- a/src/mcp/ROADMAP.md +++ b/src/mcp/ROADMAP.md @@ -23,7 +23,7 @@ The server should understand context, make smart defaults, and guide users towar The MCP server supports two target platforms for theme generation: | Platform | Package | Theming Module | Key Characteristics | -|-----------------|--------------------------|----------------------------|--------------------------------------------------------------------------------------------------| +| --------------- | ------------------------ | -------------------------- | ------------------------------------------------------------------------------------------------ | | `angular` | `igniteui-angular` | `igniteui-angular/theming` | Uses `core()` + `theme()` mixins, forwards igniteui-theming with overrides | | `webcomponents` | `igniteui-webcomponents` | `igniteui-theming` | Uses individual mixins (`palette()`, `typography()`, `elevations()`), supports runtime switching | | `react` | `igniteui-react` | `igniteui-theming` | Uses individual mixins (`palette()`, `typography()`, `elevations()`), supports runtime switching | @@ -43,25 +43,20 @@ The server can detect the target platform through multiple methods: ```scss // Uses igniteui-angular/theming module -@use "igniteui-angular/theming" as *; +@use 'igniteui-angular/theming' as *; // Requires core() mixin first (Angular-specific) @include core(); // Typography mixin (Angular overrides this) -@include typography( - $font-family: $material-typeface, - $type-scale: $material-type-scale -); +@include typography($font-family: $material-typeface, $type-scale: $material-type-scale); // theme() mixin (Angular-specific, combines palette + schema + elevations) -@include theme( - $palette: $light-material-palette, - $schema: $light-material-schema -); +@include theme($palette: $light-material-palette, $schema: $light-material-schema); ``` **Angular-specific features:** + - `core()` mixin with `$print-layout` and `$enhanced-accessibility` options - `theme()` mixin with `$exclude`, `$roundness`, `$elevation` options - Requires `ig-typography` CSS class on root element @@ -89,6 +84,7 @@ The server can detect the target platform through multiple methods: ``` **Web Components-specific features:** + - No `core()` or `theme()` mixins - uses igniteui-theming directly - Ships precompiled CSS themes in `dist/themes/` - Supports runtime theme switching via `configureTheme()` JavaScript API @@ -150,7 +146,7 @@ Tools are the core of the MCP server - they perform actions and generate code. #### Tool Category 1: Theme Foundation | Tool Name | Description | Input Schema | Output | -| ------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------- | --------------------- | +| ----------------------- | ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | --------------------- | | `detect_platform` | Detect target platform from project | `{ packageJsonPath? }` | Platform detection | | `create_palette` | Generate a color palette | `{ platform, variant, designSystem?, name?, output?, primary, secondary, surface, gray?, info?, success?, warn?, error? }` | Palette definition | | `create_custom_palette` | Generate a custom color palette | `{ platform, variant, designSystem?, name?, output?, primary, secondary, surface, gray?, info?, success?, warn?, error? }` | Palette definition | @@ -160,12 +156,12 @@ Tools are the core of the MCP server - they perform actions and generate code. #### Tool Category 2: Color Operations -| Tool Name | Description | Input Schema | Output | -| ----------------------- | ------------------------------------ | ----------------------------------- | ------------------------------- | -| `get_color` | Retrieve a color from a palette | `{ color, variant?, opacity? }` | CSS variable reference or value | -| `get_contrast_color` | Get accessible contrast color | `{ backgroundColor, wcagLevel? }` | Contrast color value | -| `generate_color_shades` | Generate all shades for a color | `{ baseColor, name }` | Complete shade map | -| `suggest_palette` | Suggest palette based on description | `{ description, mood?, industry? }` | Recommended colors | +| Tool Name | Description | Input Schema | Output | +| ----------------------- | ------------------------------------ | ------------------------------------------ | ---------------------- | +| `get_color` | Retrieve a palette color as CSS var | `{ color, variant?, contrast?, opacity? }` | CSS variable reference | +| `suggest_palette` | Suggest palette based on description | `{ description, mood?, industry? }` | Recommended colors | + +**Note:** `get_contrast_color` has been consolidated into `get_color` via the `contrast` parameter. #### Tool Category 3: Typography Operations @@ -204,13 +200,13 @@ Resources provide read-only context that AI applications can use. #### Resource Category 1: Platform Information (Direct Resources) -| URI | Description | MIME Type | -| ------------------------------------ | ---------------------------------------- | ------------------ | -| `theming://platforms` | List of supported platforms | `application/json` | -| `theming://platforms/angular` | Angular platform configuration & usage | `application/json` | -| `theming://platforms/webcomponents` | Web Components platform config & usage | `application/json` | -| `theming://platforms/react` | React platform config & usage | `application/json` | -| `theming://platforms/blazor` | Blazor platform config & usage | `application/json` | +| URI | Description | MIME Type | +| ----------------------------------- | -------------------------------------- | ------------------ | +| `theming://platforms` | List of supported platforms | `application/json` | +| `theming://platforms/angular` | Angular platform configuration & usage | `application/json` | +| `theming://platforms/webcomponents` | Web Components platform config & usage | `application/json` | +| `theming://platforms/react` | React platform config & usage | `application/json` | +| `theming://platforms/blazor` | Blazor platform config & usage | `application/json` | #### Resource Category 2: Presets (Direct Resources) @@ -252,14 +248,15 @@ Resources provide read-only context that AI applications can use. | `theming://docs/variables/{name}` | Variable documentation | #### Category 7: Guidance (Direct Resources) -| URI | Description | MIME Type | -| ----------------------------------- | ------------------------------------------------ | ------------------ | -| `theming://guidance/colors` | Color usage guidelines | `text/markdown` | -| `theming://guidance/colors/rules` | Color Shades scaling guidance | `text/markdown` | -| `theming://guidance/colors/usage` | Color Shades usage guidance | `text/markdown` | -| `theming://guidance/colors/roles` | Color Shades roles guidance | `text/markdown` | -| `theming://guidance/colors/states` | Color Shades in components states guidance | `text/markdown` | -| `theming://guidance/colors/themes` | How color shades are used across themes | `text/markdown` | + +| URI | Description | MIME Type | +| ---------------------------------- | ------------------------------------------ | --------------- | +| `theming://guidance/colors` | Color usage guidelines | `text/markdown` | +| `theming://guidance/colors/rules` | Color Shades scaling guidance | `text/markdown` | +| `theming://guidance/colors/usage` | Color Shades usage guidance | `text/markdown` | +| `theming://guidance/colors/roles` | Color Shades roles guidance | `text/markdown` | +| `theming://guidance/colors/states` | Color Shades in components states guidance | `text/markdown` | +| `theming://guidance/colors/themes` | How color shades are used across themes | `text/markdown` | --- @@ -299,9 +296,7 @@ Resources provide read-only context that AI applications can use. - ✅ Color validation for surface/gray colors (validates against theme variant) - ✅ Color guidance resource (`theming://guidance/colors`) -- `get_color` tool -- `get_contrast_color` tool -- `generate_color_shades` tool +- ✅ `get_color` tool (includes contrast color retrieval via `contrast` parameter) - `suggest_palette` tool (AI-friendly descriptions) - `check_contrast` tool - Schema resources @@ -310,14 +305,15 @@ Resources provide read-only context that AI applications can use. The `create_palette`, `create_custom_palette`, and `create_theme` tools validate surface and gray colors against the theme variant: -| Variant | Surface Requirement | Gray Requirement | -|---------|---------------------|------------------| -| `light` | Light color (luminance > 0.5) | Dark color (luminance ≤ 0.5) | -| `dark` | Dark color (luminance ≤ 0.5) | Light color (luminance > 0.5) | +| Variant | Surface Requirement | Gray Requirement | +| ------- | ----------------------------- | ----------------------------- | +| `light` | Light color (luminance > 0.5) | Dark color (luminance ≤ 0.5) | +| `dark` | Dark color (luminance ≤ 0.5) | Light color (luminance > 0.5) | **Why is gray inverted?** The `palette()` function generates gray shades that need to contrast against the surface. Light themes need dark gray text, dark themes need light gray text. **Validation behavior:** + - Warnings are shown but code is still generated (non-blocking) - Warning comments are added to generated Sass code - Tips suggest omitting gray parameter to let it auto-calculate @@ -368,7 +364,6 @@ The MCP server needs embedded knowledge from the Sass source files. ### Approach: Build-Time Extraction 1. **Parse Sass files** during build to extract: - - Color presets and multipliers -> JSON - Typography presets -> JSON - Elevation presets -> JSON @@ -424,7 +419,7 @@ The MCP server generates platform-specific Sass code based on the detected or sp // Generated by Ignite UI Theming MCP Server // Platform: Angular -@use "igniteui-angular/theming" as *; +@use 'igniteui-angular/theming' as *; // Initialize core styles (required for Angular) @include core(); @@ -438,19 +433,14 @@ $my-palette: palette( ); // Typography setup -@include typography( - $font-family: $material-typeface, - $type-scale: $material-type-scale -); +@include typography($font-family: $material-typeface, $type-scale: $material-type-scale); // Apply complete theme (palette + schema + elevations) -@include theme( - $palette: $my-palette, - $schema: $light-material-schema -); +@include theme($palette: $my-palette, $schema: $light-material-schema); ``` **Angular-specific notes:** + - Uses `igniteui-angular/theming` module (forwards igniteui-theming with overrides) - Requires `core()` mixin to be called first - Uses unified `theme()` mixin instead of individual `palette()`, `elevations()` calls @@ -463,10 +453,10 @@ $my-palette: palette( // Generated by Ignite UI Theming MCP Server // Platform: Web Components -@use "igniteui-theming/sass/color/presets/light/material" as light-preset; -@use "igniteui-theming" as *; -@use "igniteui-theming/sass/typography/presets/material" as typography-preset; -@use "igniteui-theming/sass/elevations/presets" as elevation-preset; +@use 'igniteui-theming/sass/color/presets/light/material' as light-preset; +@use 'igniteui-theming' as *; +@use 'igniteui-theming/sass/typography/presets/material' as typography-preset; +@use 'igniteui-theming/sass/elevations/presets' as elevation-preset; // Theme identification variables :root { @@ -486,10 +476,7 @@ $my-palette: palette( @include palette($my-palette); // Typography setup -@include typography( - $font-family: typography-preset.$typeface, - $type-scale: typography-preset.$type-scale -); +@include typography($font-family: typography-preset.$typeface, $type-scale: typography-preset.$type-scale); // Elevations @include elevations(elevation-preset.$material-elevations); @@ -499,6 +486,7 @@ $my-palette: palette( ``` **Web Components-specific notes:** + - Uses `igniteui-theming` directly (not via Angular forwarding) - No `core()` or unified `theme()` mixins - uses individual mixins - Supports runtime theme switching via `configureTheme()` JavaScript API @@ -688,6 +676,7 @@ export default defineConfig({ ``` **Response**: + ```json { "platform": "angular", @@ -748,13 +737,15 @@ export default defineConfig({ ## Open Questions -1. **HTTP Transport**: - - Q: Will Phase 1 include HTTP transport for remote hosting, or is STDIO sufficient for MVP? - - A: No. Phase 1 will focus on STDIO. HTTP transport can be added in a later phase if needed. +1. **HTTP Transport**: + +- Q: Will Phase 1 include HTTP transport for remote hosting, or is STDIO sufficient for MVP? +- A: No. Phase 1 will focus on STDIO. HTTP transport can be added in a later phase if needed. 2. **Caching**: - - Q: Should validated themes be cached? What invalidation strategy? - - A: Not in Phase 1. Caching can be considered in future phases based on performance needs. + +- Q: Should validated themes be cached? What invalidation strategy? +- A: Not in Phase 1. Caching can be considered in future phases based on performance needs. --- diff --git a/src/mcp/index.ts b/src/mcp/index.ts index 17e7e37e..74ec9f12 100644 --- a/src/mcp/index.ts +++ b/src/mcp/index.ts @@ -8,6 +8,7 @@ import {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js'; import {StdioServerTransport} from '@modelcontextprotocol/sdk/server/stdio.js'; +import {z} from 'zod'; import { detectPlatformSchema, @@ -18,6 +19,7 @@ import { createThemeSchema, getComponentDesignTokensSchema, createComponentThemeSchema, + getColorSchema, handleDetectPlatform, handleCreatePalette, handleCreateCustomPalette, @@ -26,9 +28,11 @@ import { handleCreateTheme, handleGetComponentDesignTokens, handleCreateComponentTheme, + handleGetColor, } from './tools/index.js'; import {TOOL_DESCRIPTIONS} from './tools/descriptions.js'; import {withPreprocessing} from './utils/preprocessing.js'; +import {PALETTE_COLOR_GROUPS, SHADE_LEVELS, ACCENT_SHADE_LEVELS} from './utils/types.js'; import {RESOURCE_DEFINITIONS, getResourceContent} from './resources/index.js'; @@ -218,6 +222,25 @@ function registerTools(server: McpServer): void { }, withPreprocessing(createComponentThemeSchema, handleCreateComponentTheme), ); + + // get_color tool + server.registerTool( + 'get_color', + { + title: 'Get Palette Color', + description: TOOL_DESCRIPTIONS.get_color, + inputSchema: { + color: z.enum(PALETTE_COLOR_GROUPS as unknown as [string, ...string[]]), + variant: z.enum([...SHADE_LEVELS, ...ACCENT_SHADE_LEVELS] as unknown as [string, ...string[]]).optional(), + contrast: z.boolean().optional(), + opacity: z.number().min(0).max(1).optional(), + }, + }, + async (params) => { + const validated = getColorSchema.parse(params); + return handleGetColor(validated); + }, + ); } /** diff --git a/src/mcp/tools/descriptions.ts b/src/mcp/tools/descriptions.ts index d2dc561b..8637958e 100644 --- a/src/mcp/tools/descriptions.ts +++ b/src/mcp/tools/descriptions.ts @@ -756,6 +756,69 @@ export const TOOL_DESCRIPTIONS = { - detect_platform: Run to auto-detect platform for correct imports - create_theme: Use for full theme (palette + typography + elevations)
`, + + // --------------------------------------------------------------------------- + // get_color - Color retrieval tool + // --------------------------------------------------------------------------- + get_color: `Retrieve a palette color from Ignite UI Theming as a CSS variable reference. + + + Use this tool when you need to reference a specific palette color in CSS or Sass code. + Returns CSS variable references that work in both Sass and CSS contexts. + + Common scenarios: + - Setting component backgrounds/foregrounds using theme colors + - Creating hover/focus states with opacity variations + - Ensuring text contrast against colored backgrounds + + + + 1. Specify the color family (primary, secondary, gray, etc.) + 2. Optionally specify a shade variant (50-900, A100-A700) + 3. Optionally request the contrast color for text readability + 4. Optionally apply opacity for transparency effects + + + + Basic color: + { color: "primary" } + → var(--ig-primary-500) + + Specific shade: + { color: "primary", variant: "600" } + → var(--ig-primary-600) + + Contrast color: + { color: "primary", variant: "600", contrast: true } + → var(--ig-primary-600-contrast) + + With opacity: + { color: "primary", opacity: 0.5 } + → hsl(from var(--ig-primary-500) h s l / 0.5) + + Contrast with opacity: + { color: "primary", contrast: true, opacity: 0.7 } + → hsl(from var(--ig-primary-500-contrast) h s l / 0.7) + + + + CSS VARIABLE NAMING: + - Base colors: --ig-{color}-{variant} (e.g., --ig-primary-500) + - Contrast: --ig-{color}-{variant}-contrast (e.g., --ig-primary-500-contrast) + + GRAY RESTRICTIONS: + - Gray only supports standard shades (50-900), not accent shades (A100-A700) + + OPACITY HANDLING: + - Uses CSS relative color syntax: hsl(from h s l / ) + - Works in modern browsers (CSS Color Level 4) + - For Sass projects, this syntax is passed through unchanged + + + + - create_palette: Generate a complete palette with these colors + - create_component_theme: Use retrieved colors in component theming +`, } as const; // ============================================================================ @@ -847,4 +910,15 @@ Important: Gray progression is INVERTED for dark themes (50=darkest, 900=lightes selector: `Optional CSS selector to scope the theme. If omitted, uses the platform's default selector for the component. For Angular: "igx-*" selectors, for Web Components: "igc-*" selectors. You can specify custom selectors like ".my-custom-button" for targeted styling.`, themeName: `Optional name for the generated theme variable (without $ prefix). If omitted, auto-generates based on component name (e.g., "$custom-button-theme").`, + + // --------------------------------------------------------------------------- + // Color operations parameters (for get_color) + // --------------------------------------------------------------------------- + colorName: `Palette color family name: "primary" (brand color), "secondary" (accent), "gray" (neutrals), "surface" (backgrounds), "info" winformational), "success" (positive), "warn" (warnings), "error" (errors/destructive).`, + + shadeVariant: `Color shade variant. Standard shades: 50 (lightest) through 900 (darkest). Accent shades: A100, A200, A400, A700 (more saturated). Default: "500" (base color). Note: Gray only supports standard shades (50-900).`, + + contrastFlag: `If true, returns the contrast color for the specified shade instead of the shade itself. Contrast colors are pre-computed for optimal text readability. Default: false.`, + + opacity: `Opacity value between 0 (fully transparent) and 1 (fully opaque). When provided, wraps the color in CSS relative color syntax: hsl(from var(...) h s l / opacity).`, } as const; diff --git a/src/mcp/tools/handlers/color.ts b/src/mcp/tools/handlers/color.ts new file mode 100644 index 00000000..1972fed6 --- /dev/null +++ b/src/mcp/tools/handlers/color.ts @@ -0,0 +1,105 @@ +/** + * Handler for get_color tool. + * Retrieves palette colors as CSS variable references. + */ + +import type {GetColorParams} from '../schemas.js'; + +/** + * Build a CSS variable reference for a palette color. + */ +function buildColorReference(color: string, variant: string, contrast: boolean): string { + const suffix = contrast ? '-contrast' : ''; + return `var(--ig-${color}-${variant}${suffix})`; +} + +/** + * Wrap a color reference with opacity using CSS relative color syntax. + */ +function applyOpacity(colorRef: string, opacity: number): string { + return `hsl(from ${colorRef} h s l / ${opacity})`; +} + +export async function handleGetColor(params: GetColorParams) { + const {color, variant = '500', contrast = false, opacity} = params; + + // Build the color reference + let result = buildColorReference(color, variant, contrast); + + // Apply opacity if specified + if (opacity !== undefined) { + result = applyOpacity(result, opacity); + } + + // Build response + const description = buildDescription(color, variant, contrast, opacity); + + return { + content: [ + { + type: 'text' as const, + text: [ + description, + '', + '```css', + result, + '```', + '', + buildUsageExample(color, variant, contrast, opacity, result), + ].join('\n'), + }, + ], + }; +} + +/** + * Build a human-readable description of what was returned. + */ +function buildDescription(color: string, variant: string, contrast: boolean, opacity?: number): string { + let desc = contrast + ? `Contrast color for ${color} ${variant}` + : `${color.charAt(0).toUpperCase() + color.slice(1)} color, shade ${variant}`; + + if (opacity !== undefined) { + desc += ` at ${Math.round(opacity * 100)}% opacity`; + } + + return desc; +} + +/** + * Build a usage example showing how to use the returned value. + */ +function buildUsageExample( + color: string, + variant: string, + contrast: boolean, + opacity: number | undefined, + result: string, +): string { + const examples: string[] = ['**Usage example:**']; + + if (contrast) { + examples.push('```scss'); + examples.push(`.my-element {`); + examples.push(` background: var(--ig-${color}-${variant});`); + examples.push(` color: ${result};`); + examples.push(`}`); + examples.push('```'); + } else if (opacity !== undefined) { + examples.push('```scss'); + examples.push(`.my-element {`); + examples.push(` background: ${result};`); + examples.push(`}`); + examples.push('```'); + } else { + examples.push('```scss'); + examples.push(`.my-element {`); + examples.push(` background: ${result};`); + examples.push(` color: var(--ig-${color}-${variant}-contrast);`); + examples.push(`}`); + examples.push('```'); + } + + return examples.join('\n'); +} diff --git a/src/mcp/tools/handlers/index.ts b/src/mcp/tools/handlers/index.ts index e788447f..d21fe1d4 100644 --- a/src/mcp/tools/handlers/index.ts +++ b/src/mcp/tools/handlers/index.ts @@ -10,3 +10,4 @@ export {handleCreateElevations} from './elevations.js'; export {handleCreateTheme} from './theme.js'; export {handleGetComponentDesignTokens} from './component-tokens.js'; export {handleCreateComponentTheme} from './component-theme.js'; +export {handleGetColor} from './color.js'; diff --git a/src/mcp/tools/index.ts b/src/mcp/tools/index.ts index ef519119..698fbaee 100644 --- a/src/mcp/tools/index.ts +++ b/src/mcp/tools/index.ts @@ -11,6 +11,7 @@ export { createThemeSchema, getComponentDesignTokensSchema, createComponentThemeSchema, + getColorSchema, platformSchema, type DetectPlatformParams, type CreatePaletteParams, @@ -20,6 +21,7 @@ export { type CreateThemeParams, type GetComponentDesignTokensParams, type CreateComponentThemeParams, + type GetColorParams, type Platform, } from './schemas.js'; @@ -32,4 +34,5 @@ export { handleCreateTheme, handleGetComponentDesignTokens, handleCreateComponentTheme, + handleGetColor, } from './handlers/index.js'; diff --git a/src/mcp/tools/schemas.ts b/src/mcp/tools/schemas.ts index 644f1da4..67f3a1ad 100644 --- a/src/mcp/tools/schemas.ts +++ b/src/mcp/tools/schemas.ts @@ -18,6 +18,8 @@ import { ELEVATION_PRESETS, ALL_COLOR_SHADES, OUTPUT_FORMATS, + PALETTE_COLOR_GROUPS, + ACCENT_SHADE_LEVELS, } from '../utils/types.js'; import {PARAM_DESCRIPTIONS} from './descriptions.js'; @@ -288,3 +290,40 @@ export const createComponentThemeSchema = z.object({ export type GetComponentDesignTokensParams = z.infer; export type CreateComponentThemeParams = z.infer; + +// ============================================================================ +// Color Operations Schemas +// ============================================================================ + +/** + * Base schema for get_color tool input. + */ +const getColorBaseSchema = z.object({ + color: z.enum(PALETTE_COLOR_GROUPS as unknown as [string, ...string[]]).describe(PARAM_DESCRIPTIONS.colorName), + variant: z + .enum([...SHADE_LEVELS, ...ACCENT_SHADE_LEVELS] as unknown as [string, ...string[]]) + .optional() + .describe(PARAM_DESCRIPTIONS.shadeVariant), + contrast: z.boolean().optional().describe(PARAM_DESCRIPTIONS.contrastFlag), + opacity: z.number().min(0).max(1).optional().describe(PARAM_DESCRIPTIONS.opacity), +}); + +/** + * Schema for get_color tool with validation. + * Retrieves palette colors as CSS variable references. + */ +export const getColorSchema = getColorBaseSchema.refine( + (data) => { + if (data.color === 'gray' && data.variant) { + return !ACCENT_SHADE_LEVELS.includes(data.variant as any); + } + + return true; + }, + { + message: 'Gray color does not support accent shades (A100, A200, A400, A700). Use standard shades: 50-900.', + path: ['variant'], + }, +); + +export type GetColorParams = z.infer; From 19a831d76bddd435d9f15dc2d86aece3eb7e43c0 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Tue, 27 Jan 2026 07:49:58 +0200 Subject: [PATCH 08/38] feat(mcp): add support for licensed @infragistics packages - add `licensed` parameter to all theming tools for Angular projects - update Sass generator to use `@infragistics/igniteui-angular/theming` import - enhance platform detection to identify licensed package usage - update tool schemas and parameter descriptions --- src/mcp/__tests__/utils/sass.test.ts | 12 +++++++++++- src/mcp/generators/sass.ts | 12 +++++++----- src/mcp/index.ts | 6 ++++++ src/mcp/knowledge/index.ts | 1 + src/mcp/knowledge/platforms/index.ts | 21 +++++++++++++++++---- src/mcp/tools/descriptions.ts | 1 + src/mcp/tools/handlers/component-theme.ts | 1 + src/mcp/tools/handlers/custom-palette.ts | 2 +- src/mcp/tools/handlers/elevations.ts | 1 + src/mcp/tools/handlers/palette.ts | 6 ++---- src/mcp/tools/handlers/platform.ts | 21 ++++++++++++++++++--- src/mcp/tools/handlers/theme.ts | 6 +++--- src/mcp/tools/handlers/typography.ts | 1 + src/mcp/tools/schemas.ts | 11 +++++++++++ src/mcp/utils/sass.ts | 8 +++++--- src/mcp/utils/types.ts | 10 ++++++++++ 16 files changed, 96 insertions(+), 24 deletions(-) diff --git a/src/mcp/__tests__/utils/sass.test.ts b/src/mcp/__tests__/utils/sass.test.ts index 6759e04e..13789323 100644 --- a/src/mcp/__tests__/utils/sass.test.ts +++ b/src/mcp/__tests__/utils/sass.test.ts @@ -2,7 +2,7 @@ * Tests for Sass utility functions. */ -import { describe, it, expect } from 'vitest'; +import {describe, it, expect} from 'vitest'; import { toVariableName, generateHeader, @@ -93,11 +93,21 @@ describe('generateUseStatement', () => { expect(result).toBe('@use "igniteui-angular/theming" as *;'); }); + it('generates licensed Angular import when licensed is true', () => { + const result = generateUseStatement('angular', true); + expect(result).toBe('@use "@infragistics/igniteui-angular/theming" as *;'); + }); + it('generates generic import for webcomponents platform', () => { const result = generateUseStatement('webcomponents'); expect(result).toBe("@use 'igniteui-theming' as *;"); }); + it('ignores licensed flag for webcomponents (always free)', () => { + const result = generateUseStatement('webcomponents', true); + expect(result).toBe("@use 'igniteui-theming' as *;"); + }); + it('generates generic import when platform is undefined', () => { const result = generateUseStatement(); expect(result).toBe("@use 'igniteui-theming' as *;"); diff --git a/src/mcp/generators/sass.ts b/src/mcp/generators/sass.ts index f2027c74..b107089b 100644 --- a/src/mcp/generators/sass.ts +++ b/src/mcp/generators/sass.ts @@ -70,7 +70,7 @@ export function generatePalette(input: CreatePaletteInput): GeneratedCode { if (input.error) paletteArgs.push(`$error: ${input.error}`); const code = `${generateHeader(`${variant} palette with primary color ${input.primary}`)} -${generateUseStatement(input.platform)} +${generateUseStatement(input.platform, input.licensed)} // Custom ${variant} palette ${varName}: palette( @@ -100,7 +100,7 @@ export function generateTypography(input: CreateTypographyInput): GeneratedCode const typeface = input.fontFamily || preset.typeface; const code = `${generateHeader(`Typography setup using ${designSystem} type scale`)} -${generateUseStatement(input.platform)} +${generateUseStatement(input.platform, input.licensed)} // Typography setup with ${designSystem} type scale @include typography( @@ -124,7 +124,7 @@ export function generateElevations(input: CreateElevationsInput): GeneratedCode const elevationsVar = `$${preset}-elevations`; const code = `${generateHeader(`Elevations setup using ${preset} preset`)} -${generateUseStatement(input.platform)} +${generateUseStatement(input.platform, input.licensed)} // Elevations setup with ${preset} shadows @include elevations(${elevationsVar}); @@ -278,7 +278,7 @@ function generateGenericTheme( const sections: string[] = [ generateHeader(`Complete ${variant} theme based on ${designSystem} design system`), '// NOTE: Specify platform ("angular" or "webcomponents") for optimized output', - generateUseStatement(), + generateUseStatement(input.platform, input.licensed), '', `// ${themeName} palette`, `${paletteVar}: palette(`, @@ -332,6 +332,8 @@ function generateGenericTheme( */ export interface CreateComponentThemeInput { platform: Platform; + /** Whether to use licensed @infragistics package (Angular only, defaults to false) */ + licensed?: boolean; /** Design system (defaults to 'material') */ designSystem?: DesignSystem; /** Theme variant - light or dark (defaults to 'light') */ @@ -383,7 +385,7 @@ export function generateComponentTheme(input: CreateComponentThemeInput): Genera // Generate the code const sections: string[] = [ generateHeader(`Custom ${input.component} theme`), - generateUseStatement(input.platform), + generateUseStatement(input.platform, input.licensed), '', `// Custom ${input.component} theme`, `${themeName}: ${themeFn}(`, diff --git a/src/mcp/index.ts b/src/mcp/index.ts index 74ec9f12..117240a9 100644 --- a/src/mcp/index.ts +++ b/src/mcp/index.ts @@ -82,6 +82,7 @@ function registerTools(server: McpServer): void { description: TOOL_DESCRIPTIONS.create_palette, inputSchema: { platform: createPaletteSchema.shape.platform, + licensed: createPaletteSchema.shape.licensed, variant: createPaletteSchema.shape.variant, name: createPaletteSchema.shape.name, output: createPaletteSchema.shape.output, @@ -109,6 +110,7 @@ function registerTools(server: McpServer): void { description: TOOL_DESCRIPTIONS.create_custom_palette, inputSchema: { platform: createCustomPaletteSchema.shape.platform, + licensed: createCustomPaletteSchema.shape.licensed, variant: createCustomPaletteSchema.shape.variant, designSystem: createCustomPaletteSchema.shape.designSystem, name: createCustomPaletteSchema.shape.name, @@ -134,6 +136,7 @@ function registerTools(server: McpServer): void { description: TOOL_DESCRIPTIONS.create_typography, inputSchema: { platform: createTypographySchema.shape.platform, + licensed: createTypographySchema.shape.licensed, fontFamily: createTypographySchema.shape.fontFamily, designSystem: createTypographySchema.shape.designSystem, customScale: createTypographySchema.shape.customScale, @@ -151,6 +154,7 @@ function registerTools(server: McpServer): void { description: TOOL_DESCRIPTIONS.create_elevations, inputSchema: { platform: createElevationsSchema.shape.platform, + licensed: createElevationsSchema.shape.licensed, designSystem: createElevationsSchema.shape.designSystem, name: createElevationsSchema.shape.name, }, @@ -169,6 +173,7 @@ function registerTools(server: McpServer): void { description: TOOL_DESCRIPTIONS.create_theme, inputSchema: { platform: createThemeSchema.shape.platform, + licensed: createThemeSchema.shape.licensed, designSystem: createThemeSchema.shape.designSystem, primaryColor: createThemeSchema.shape.primaryColor, secondaryColor: createThemeSchema.shape.secondaryColor, @@ -211,6 +216,7 @@ function registerTools(server: McpServer): void { description: TOOL_DESCRIPTIONS.create_component_theme, inputSchema: { platform: createComponentThemeSchema.shape.platform, + licensed: createComponentThemeSchema.shape.licensed, designSystem: createComponentThemeSchema.shape.designSystem, variant: createComponentThemeSchema.shape.variant, component: createComponentThemeSchema.shape.component, diff --git a/src/mcp/knowledge/index.ts b/src/mcp/knowledge/index.ts index 05fd3bb2..a69d72df 100644 --- a/src/mcp/knowledge/index.ts +++ b/src/mcp/knowledge/index.ts @@ -115,6 +115,7 @@ export { type FrameworkDetectionSignal, type PlatformAlternative, detectPlatformFromDependencies, + isLicensedPackage, detectConfigFiles, PLATFORM_METADATA, PLATFORM_VARIABLE_PREFIX, diff --git a/src/mcp/knowledge/platforms/index.ts b/src/mcp/knowledge/platforms/index.ts index f1eb6d87..9b86005f 100644 --- a/src/mcp/knowledge/platforms/index.ts +++ b/src/mcp/knowledge/platforms/index.ts @@ -386,6 +386,17 @@ export function getVariablePrefix(platform: Platform): string { return PLATFORM_VARIABLE_PREFIX[platform]; } +/** + * Determine if a detected package is a licensed @infragistics package. + * Only applies to Angular - other platforms always use the free igniteui-theming package. + * + * @param detectedPackage - The package name detected from package.json + * @returns True if the package is a licensed @infragistics package + */ +export function isLicensedPackage(detectedPackage?: string): boolean { + return detectedPackage?.startsWith('@infragistics/') ?? false; +} + /** * Platform metadata for display purposes */ @@ -395,9 +406,11 @@ export const PLATFORM_METADATA = { name: 'Ignite UI for Angular', shortName: 'Angular', packageName: 'igniteui-angular', + licensedPackageName: '@infragistics/igniteui-angular', themingModule: 'igniteui-angular/theming', + licensedThemingModule: '@infragistics/igniteui-angular/theming', description: - 'Uses core() and theme() mixins from igniteui-angular/theming module. Requires ig-typography CSS class on root element.', + 'Uses core() and theme() mixins from igniteui-angular/theming module. Requires ig-typography CSS class on root element. Available as OSS (igniteui-angular) or licensed (@infragistics/igniteui-angular) package.', }, webcomponents: { id: 'webcomponents', @@ -406,7 +419,7 @@ export const PLATFORM_METADATA = { packageName: 'igniteui-webcomponents', themingModule: 'igniteui-theming', description: - 'Uses igniteui-theming directly with palette(), typography(), and elevations() mixins. Supports runtime theme switching via configureTheme().', + 'Uses igniteui-theming directly with palette(), typography(), and elevations() mixins. Supports runtime theme switching via configureTheme(). The igniteui-theming package is always free/OSS.', }, react: { id: 'react', @@ -415,7 +428,7 @@ export const PLATFORM_METADATA = { packageName: 'igniteui-react', themingModule: 'igniteui-theming', description: - 'Uses igniteui-theming directly with palette(), typography(), and elevations() mixins. Common with Vite or Next.js projects.', + 'Uses igniteui-theming directly with palette(), typography(), and elevations() mixins. Common with Vite or Next.js projects. The igniteui-theming package is always free/OSS.', }, blazor: { id: 'blazor', @@ -424,6 +437,6 @@ export const PLATFORM_METADATA = { packageName: 'IgniteUI.Blazor', themingModule: 'igniteui-theming', description: - 'Uses igniteui-theming for Sass compilation in .NET Blazor projects. Theme styles are compiled to CSS and referenced in Blazor components.', + 'Uses igniteui-theming for Sass compilation in .NET Blazor projects. Theme styles are compiled to CSS and referenced in Blazor components. The igniteui-theming package is always free/OSS.', }, } as const; diff --git a/src/mcp/tools/descriptions.ts b/src/mcp/tools/descriptions.ts index 8637958e..9b8528ab 100644 --- a/src/mcp/tools/descriptions.ts +++ b/src/mcp/tools/descriptions.ts @@ -834,6 +834,7 @@ export const PARAM_DESCRIPTIONS = { // Common parameters (used across multiple tools) // --------------------------------------------------------------------------- platform: FRAGMENTS.PLATFORM, + licensed: `Use licensed @infragistics package (Angular only). Set to true if using @infragistics/igniteui-angular from private ProGet registry. Defaults to false (uses open-source igniteui-angular from npm). Note: igniteui-theming is always free/OSS for all other platforms.`, variant: FRAGMENTS.VARIANT, designSystem: FRAGMENTS.DESIGN_SYSTEM, name: `Custom variable name (without $ prefix). If omitted, auto-generates based on tool and variant (e.g., "custom-light", "my-theme").`, diff --git a/src/mcp/tools/handlers/component-theme.ts b/src/mcp/tools/handlers/component-theme.ts index fa9e31d6..679d1cdd 100644 --- a/src/mcp/tools/handlers/component-theme.ts +++ b/src/mcp/tools/handlers/component-theme.ts @@ -235,6 +235,7 @@ Use \`get_component_design_tokens\` to see all tokens with descriptions.`, try { const result = generateComponentTheme({ platform, + licensed: params.licensed, component: normalizedComponent, tokens, selector: finalSelector, diff --git a/src/mcp/tools/handlers/custom-palette.ts b/src/mcp/tools/handlers/custom-palette.ts index 4c5adf4f..32ba8d61 100644 --- a/src/mcp/tools/handlers/custom-palette.ts +++ b/src/mcp/tools/handlers/custom-palette.ts @@ -206,7 +206,7 @@ function handleSassOutput( const varName = `$${paletteName}-palette`; const code = `${generateHeader(`Custom ${variant} palette with explicit shade control`)} -${generateUseStatement(params.platform)} +${generateUseStatement(params.platform, params.licensed)} ${paletteLines.join('\n')} diff --git a/src/mcp/tools/handlers/elevations.ts b/src/mcp/tools/handlers/elevations.ts index 518717a3..134e3ef5 100644 --- a/src/mcp/tools/handlers/elevations.ts +++ b/src/mcp/tools/handlers/elevations.ts @@ -8,6 +8,7 @@ import type {CreateElevationsParams} from '../schemas.js'; export function handleCreateElevations(params: CreateElevationsParams) { const result = generateElevations({ platform: params.platform, + licensed: params.licensed, designSystem: params.designSystem, name: params.name, }); diff --git a/src/mcp/tools/handlers/palette.ts b/src/mcp/tools/handlers/palette.ts index 2d4e8788..c65c5beb 100644 --- a/src/mcp/tools/handlers/palette.ts +++ b/src/mcp/tools/handlers/palette.ts @@ -90,13 +90,11 @@ async function handleCssOutput( /** * Handle Sass output format - generates Sass code using the palette() function. */ -function handleSassOutput( - params: CreatePaletteParams, - validation: Awaited>, -) { +function handleSassOutput(params: CreatePaletteParams, validation: Awaited>) { // Generate the palette code const result = generatePalette({ platform: params.platform, + licensed: params.licensed, primary: params.primary, secondary: params.secondary, surface: params.surface, diff --git a/src/mcp/tools/handlers/platform.ts b/src/mcp/tools/handlers/platform.ts index a36b994c..2f93172c 100644 --- a/src/mcp/tools/handlers/platform.ts +++ b/src/mcp/tools/handlers/platform.ts @@ -18,6 +18,7 @@ import {resolve, dirname} from 'node:path'; import {z} from 'zod'; import { detectPlatformFromDependencies, + isLicensedPackage, PLATFORM_METADATA, type PlatformDetectionResult, type DetectionSignal, @@ -46,6 +47,7 @@ export interface DetectPlatformResult { signals: DetectionSignal[]; }>; detectedPackage?: string; + licensed?: boolean; signals?: DetectionSignal[]; reason: string; platformInfo?: { @@ -123,6 +125,8 @@ export async function handleDetectPlatform(params: DetectPlatformParams) { if (result.detectedPackage) { response.detectedPackage = result.detectedPackage; + // Determine if licensed package (only relevant for Angular) + response.licensed = isLicensedPackage(result.detectedPackage); } // Add platform info if detected @@ -170,17 +174,28 @@ export async function handleDetectPlatform(params: DetectPlatformParams) { if (result.detectedPackage) { text += `**Detected Package:** ${result.detectedPackage}\n`; + const licensed = isLicensedPackage(result.detectedPackage); + if (result.platform === 'angular') { + text += `**Package Type:** ${licensed ? 'Licensed (@infragistics)' : 'Open Source (npm)'}\n`; + } } if (result.signals && result.signals.length > 0) { text += `**Detection Signals:** ${result.signals.map(formatSignal).join(', ')}\n`; } - text += `**Theming Module:** \`${metadata.themingModule}\`\n\n`; + const themingModule = + result.platform === 'angular' && response.licensed + ? (metadata as any).licensedThemingModule + : metadata.themingModule; + text += `**Theming Module:** \`${themingModule}\`\n\n`; text += `### Usage\n\n`; - text += `When generating theme code, use \`platform: '${result.platform}'\` to ensure `; - text += `the correct Sass syntax is generated for this platform.\n\n`; + text += `When generating theme code, use \`platform: '${result.platform}'\``; + if (result.platform === 'angular' && response.licensed) { + text += ` and \`licensed: true\``; + } + text += ` to ensure the correct Sass syntax is generated for this platform.\n\n`; text += `${metadata.description}`; // Add confidence-specific notes diff --git a/src/mcp/tools/handlers/theme.ts b/src/mcp/tools/handlers/theme.ts index 213b5862..1ecf8a6b 100644 --- a/src/mcp/tools/handlers/theme.ts +++ b/src/mcp/tools/handlers/theme.ts @@ -33,6 +33,7 @@ export async function handleCreateTheme(params: CreateThemeParams) { // Generate the theme code const result = generateTheme({ platform: params.platform, + licensed: params.licensed, designSystem: params.designSystem, primaryColor: params.primaryColor, secondaryColor: params.secondaryColor, @@ -75,7 +76,7 @@ export async function handleCreateTheme(params: CreateThemeParams) { const responseParts: string[] = [result.description]; // Add platform hint if not specified - let platformNote = '' + let platformNote = ''; switch (params.platform) { case 'angular': @@ -91,8 +92,7 @@ export async function handleCreateTheme(params: CreateThemeParams) { platformNote = 'Platform: Ignite UI for Blazor'; break; default: - platformNote = - 'Platform: Not specified (generic output). Specify `platform` for optimized code.'; + platformNote = 'Platform: Not specified (generic output). Specify `platform` for optimized code.'; break; } diff --git a/src/mcp/tools/handlers/typography.ts b/src/mcp/tools/handlers/typography.ts index 9df14884..2d657d7d 100644 --- a/src/mcp/tools/handlers/typography.ts +++ b/src/mcp/tools/handlers/typography.ts @@ -8,6 +8,7 @@ import type {CreateTypographyParams} from '../schemas.js'; export function handleCreateTypography(params: CreateTypographyParams) { const result = generateTypography({ platform: params.platform, + licensed: params.licensed, fontFamily: params.fontFamily, designSystem: params.designSystem, customScale: params.customScale, diff --git a/src/mcp/tools/schemas.ts b/src/mcp/tools/schemas.ts index 67f3a1ad..6a79d439 100644 --- a/src/mcp/tools/schemas.ts +++ b/src/mcp/tools/schemas.ts @@ -84,6 +84,11 @@ export const outputFormatSchema = z.enum(OUTPUT_FORMATS).optional(); */ export const platformSchema = z.enum(PLATFORMS).optional().describe(PARAM_DESCRIPTIONS.platform); +/** + * Licensed package schema - for @infragistics prefixed packages. + */ +export const licensedSchema = z.boolean().optional().describe(PARAM_DESCRIPTIONS.licensed); + /** * Schema for detect_platform tool. */ @@ -96,6 +101,7 @@ export const detectPlatformSchema = z.object({ */ export const createPaletteSchema = z.object({ platform: platformSchema, + licensed: licensedSchema, primary: colorSchema.describe(PARAM_DESCRIPTIONS.primary), secondary: colorSchema.describe(PARAM_DESCRIPTIONS.secondary), surface: colorSchema.describe(PARAM_DESCRIPTIONS.surface), @@ -128,6 +134,7 @@ export const typeStyleSchema = z.object({ */ export const createTypographySchema = z.object({ platform: platformSchema, + licensed: licensedSchema, fontFamily: z.string().describe(PARAM_DESCRIPTIONS.fontFamily), designSystem: designSystemSchema.describe(PARAM_DESCRIPTIONS.designSystem), customScale: z.record(typeStyleSchema).optional().describe(PARAM_DESCRIPTIONS.customScale), @@ -139,6 +146,7 @@ export const createTypographySchema = z.object({ */ export const createElevationsSchema = z.object({ platform: platformSchema, + licensed: licensedSchema, designSystem: elevationPresetSchema.describe(PARAM_DESCRIPTIONS.elevationPreset), name: z.string().optional().describe(PARAM_DESCRIPTIONS.name), }); @@ -148,6 +156,7 @@ export const createElevationsSchema = z.object({ */ export const createThemeSchema = z.object({ platform: platformSchema, + licensed: licensedSchema, designSystem: designSystemSchema.describe(PARAM_DESCRIPTIONS.designSystem), primaryColor: colorSchema.describe(PARAM_DESCRIPTIONS.primaryColor), secondaryColor: colorSchema.describe(PARAM_DESCRIPTIONS.secondaryColor), @@ -233,6 +242,7 @@ const grayDefinitionSchema = z.union([shadesBasedColorSchema, explicitGrayShades */ export const createCustomPaletteSchema = z.object({ platform: platformSchema, + licensed: licensedSchema, variant: variantSchema.describe(PARAM_DESCRIPTIONS.variant), designSystem: designSystemSchema.describe(PARAM_DESCRIPTIONS.designSystem), name: z.string().optional().describe(PARAM_DESCRIPTIONS.name), @@ -279,6 +289,7 @@ const tokenValueSchema = z.union([ */ export const createComponentThemeSchema = z.object({ platform: z.enum(PLATFORMS).describe(PARAM_DESCRIPTIONS.platform), + licensed: licensedSchema, designSystem: designSystemSchema.describe(PARAM_DESCRIPTIONS.designSystem), variant: variantSchema.describe(PARAM_DESCRIPTIONS.variant), component: z.string().describe(PARAM_DESCRIPTIONS.componentTheme), diff --git a/src/mcp/utils/sass.ts b/src/mcp/utils/sass.ts index 9be9e397..1d3a2dc6 100644 --- a/src/mcp/utils/sass.ts +++ b/src/mcp/utils/sass.ts @@ -94,13 +94,15 @@ export function generateHeader(description: string): string { * Uses platform-specific import paths when platform is specified. * * @param platform - Target platform (angular or webcomponents) + * @param licensed - Whether to use the licensed @infragistics package (Angular only, defaults to false) * @returns The appropriate @use statement for the platform */ -export function generateUseStatement(platform?: Platform): string { +export function generateUseStatement(platform?: Platform, licensed?: boolean): string { if (platform === 'angular') { - return '@use "igniteui-angular/theming" as *;'; + const packagePath = licensed ? '@infragistics/igniteui-angular' : 'igniteui-angular'; + return `@use "${packagePath}/theming" as *;`; } - // Web Components or unspecified (default to igniteui-theming) + // Web Components, React, Blazor, or unspecified (always use igniteui-theming - it's free) return "@use 'igniteui-theming' as *;"; } diff --git a/src/mcp/utils/types.ts b/src/mcp/utils/types.ts index 7d785893..88b70fe6 100644 --- a/src/mcp/utils/types.ts +++ b/src/mcp/utils/types.ts @@ -101,6 +101,8 @@ export type AccentShadeLevel = (typeof ACCENT_SHADE_LEVELS)[number]; export interface CreatePaletteInput { /** Target platform for code generation */ platform?: Platform; + /** Whether to use licensed @infragistics package (Angular only, defaults to false) */ + licensed?: boolean; /** Primary brand color (hex, rgb, or hsl) */ primary: string; /** Secondary/accent color (required by Sass palette function) */ @@ -129,6 +131,8 @@ export interface CreatePaletteInput { export interface CreateTypographyInput { /** Target platform for code generation */ platform?: Platform; + /** Whether to use licensed @infragistics package (Angular only, defaults to false) */ + licensed?: boolean; /** Font family string */ fontFamily: string; /** Design system preset to use for type scale */ @@ -159,6 +163,8 @@ export interface TypeStyleInput { export interface CreateElevationsInput { /** Target platform for code generation */ platform?: Platform; + /** Whether to use licensed @infragistics package (Angular only, defaults to false) */ + licensed?: boolean; /** Design system preset to use (material or indigo) */ designSystem?: 'material' | 'indigo'; /** Custom name for the elevations variable */ @@ -171,6 +177,8 @@ export interface CreateElevationsInput { export interface CreateThemeInput { /** Target platform for code generation */ platform?: Platform; + /** Whether to use licensed @infragistics package (Angular only, defaults to false) */ + licensed?: boolean; /** Design system to base the theme on */ designSystem?: DesignSystem; /** Primary brand color */ @@ -310,6 +318,8 @@ export type GrayDefinition = ShadesBasedColor | ExplicitGrayShades; export interface CreateCustomPaletteInput { /** Target platform for code generation */ platform?: Platform; + /** Whether to use licensed @infragistics package (Angular only, defaults to false) */ + licensed?: boolean; /** Theme variant (light or dark) */ variant?: ThemeVariant; /** Design system to use for default color values */ From afad1f96c07f8f143ff4709db62c1dbaaac5e240 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Wed, 28 Jan 2026 09:28:31 +0200 Subject: [PATCH 09/38] feat(mcp): add goal-oriented layout scale tools Adds set_size, set_spacing, and set_roundness tools to the MCP server for controlling component sizing, spacing multipliers, and border-radius factors via CSS variables. This implementation includes: - Global and component-scoped CSS variable overrides. - Semantic size keyword support (small, medium, large) mapped to framework defaults. - New layout documentation resources and detailed tool descriptions. - Comprehensive schema validation and unit tests for the new handlers. Also updates the ROADMAP and README to reflect the new capabilities and resource URIs. --- package-lock.json | 499 +++++++++--------- src/mcp/README.md | 102 +++- src/mcp/ROADMAP.md | 160 +----- src/mcp/__tests__/knowledge/sass-api.test.ts | 8 + .../__tests__/tools/handlers/handlers.test.ts | 38 ++ src/mcp/__tests__/tools/schemas.test.ts | 36 +- src/mcp/index.ts | 69 +++ src/mcp/knowledge/index.ts | 11 + src/mcp/knowledge/layout-docs.ts | 212 ++++++++ src/mcp/knowledge/sass-api.ts | 9 + src/mcp/resources/presets.ts | 111 +++- src/mcp/tools/descriptions.ts | 138 ++++- src/mcp/tools/handlers/index.ts | 1 + src/mcp/tools/handlers/layout.ts | 240 +++++++++ src/mcp/tools/index.ts | 10 + src/mcp/tools/schemas.ts | 45 ++ 16 files changed, 1270 insertions(+), 419 deletions(-) create mode 100644 src/mcp/knowledge/layout-docs.ts create mode 100644 src/mcp/tools/handlers/layout.ts diff --git a/package-lock.json b/package-lock.json index 944e75d3..b6e7efd8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -132,9 +132,9 @@ } }, "node_modules/@bufbuild/protobuf": { - "version": "2.10.2", - "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.10.2.tgz", - "integrity": "sha512-uFsRXwIGyu+r6AMdz+XijIIZJYpoWeYzILt5yZ2d3mCjQrWUTVpVD9WL/jZAbvp+Ed04rOhrsk7FiTcEDseB5A==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.11.0.tgz", + "integrity": "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==", "license": "(Apache-2.0 AND BSD-3-Clause)" }, "node_modules/@csstools/css-parser-algorithms": { @@ -868,12 +868,12 @@ } }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.25.2", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.2.tgz", - "integrity": "sha512-LZFeo4F9M5qOhC/Uc1aQSrBHxMrvxett+9KLHt7OhcExtoiRN9DKgbZffMP/nxjutWDQpfMDfP3nkHI4X9ijww==", + "version": "1.25.3", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.3.tgz", + "integrity": "sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ==", "license": "MIT", "dependencies": { - "@hono/node-server": "^1.19.7", + "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", @@ -945,9 +945,9 @@ } }, "node_modules/@parcel/watcher": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.4.tgz", - "integrity": "sha512-WYa2tUVV5HiArWPB3ydlOc4R2ivq0IDrlqhMi3l7mVsFEXNcTfxYFPIHXHXIh/ca/y/V5N4E1zecyxdIBjYnkQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", "hasInstallScript": true, "license": "MIT", "optional": true, @@ -965,25 +965,25 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.4", - "@parcel/watcher-darwin-arm64": "2.5.4", - "@parcel/watcher-darwin-x64": "2.5.4", - "@parcel/watcher-freebsd-x64": "2.5.4", - "@parcel/watcher-linux-arm-glibc": "2.5.4", - "@parcel/watcher-linux-arm-musl": "2.5.4", - "@parcel/watcher-linux-arm64-glibc": "2.5.4", - "@parcel/watcher-linux-arm64-musl": "2.5.4", - "@parcel/watcher-linux-x64-glibc": "2.5.4", - "@parcel/watcher-linux-x64-musl": "2.5.4", - "@parcel/watcher-win32-arm64": "2.5.4", - "@parcel/watcher-win32-ia32": "2.5.4", - "@parcel/watcher-win32-x64": "2.5.4" + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" } }, "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.4.tgz", - "integrity": "sha512-hoh0vx4v+b3BNI7Cjoy2/B0ARqcwVNrzN/n7DLq9ZB4I3lrsvhrkCViJyfTj/Qi5xM9YFiH4AmHGK6pgH1ss7g==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", "cpu": [ "arm64" ], @@ -1001,9 +1001,9 @@ } }, "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.4.tgz", - "integrity": "sha512-kphKy377pZiWpAOyTgQYPE5/XEKVMaj6VUjKT5VkNyUJlr2qZAn8gIc7CPzx+kbhvqHDT9d7EqdOqRXT6vk0zw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", "cpu": [ "arm64" ], @@ -1021,9 +1021,9 @@ } }, "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.4.tgz", - "integrity": "sha512-UKaQFhCtNJW1A9YyVz3Ju7ydf6QgrpNQfRZ35wNKUhTQ3dxJ/3MULXN5JN/0Z80V/KUBDGa3RZaKq1EQT2a2gg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", "cpu": [ "x64" ], @@ -1041,9 +1041,9 @@ } }, "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.4.tgz", - "integrity": "sha512-Dib0Wv3Ow/m2/ttvLdeI2DBXloO7t3Z0oCp4bAb2aqyqOjKPPGrg10pMJJAQ7tt8P4V2rwYwywkDhUia/FgS+Q==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", "cpu": [ "x64" ], @@ -1061,9 +1061,9 @@ } }, "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.4.tgz", - "integrity": "sha512-I5Vb769pdf7Q7Sf4KNy8Pogl/URRCKu9ImMmnVKYayhynuyGYMzuI4UOWnegQNa2sGpsPSbzDsqbHNMyeyPCgw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", "cpu": [ "arm" ], @@ -1081,9 +1081,9 @@ } }, "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.4.tgz", - "integrity": "sha512-kGO8RPvVrcAotV4QcWh8kZuHr9bXi9a3bSZw7kFarYR0+fGliU7hd/zevhjw8fnvIKG3J9EO5G6sXNGCSNMYPQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", "cpu": [ "arm" ], @@ -1101,9 +1101,9 @@ } }, "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.4.tgz", - "integrity": "sha512-KU75aooXhqGFY2W5/p8DYYHt4hrjHZod8AhcGAmhzPn/etTa+lYCDB2b1sJy3sWJ8ahFVTdy+EbqSBvMx3iFlw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", "cpu": [ "arm64" ], @@ -1121,9 +1121,9 @@ } }, "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.4.tgz", - "integrity": "sha512-Qx8uNiIekVutnzbVdrgSanM+cbpDD3boB1f8vMtnuG5Zau4/bdDbXyKwIn0ToqFhIuob73bcxV9NwRm04/hzHQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", "cpu": [ "arm64" ], @@ -1141,9 +1141,9 @@ } }, "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.4.tgz", - "integrity": "sha512-UYBQvhYmgAv61LNUn24qGQdjtycFBKSK3EXr72DbJqX9aaLbtCOO8+1SkKhD/GNiJ97ExgcHBrukcYhVjrnogA==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", "cpu": [ "x64" ], @@ -1161,9 +1161,9 @@ } }, "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.4.tgz", - "integrity": "sha512-YoRWCVgxv8akZrMhdyVi6/TyoeeMkQ0PGGOf2E4omODrvd1wxniXP+DBynKoHryStks7l+fDAMUBRzqNHrVOpg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", "cpu": [ "x64" ], @@ -1181,9 +1181,9 @@ } }, "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.4.tgz", - "integrity": "sha512-iby+D/YNXWkiQNYcIhg8P5hSjzXEHaQrk2SLrWOUD7VeC4Ohu0WQvmV+HDJokZVJ2UjJ4AGXW3bx7Lls9Ln4TQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", "cpu": [ "arm64" ], @@ -1201,9 +1201,9 @@ } }, "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.4.tgz", - "integrity": "sha512-vQN+KIReG0a2ZDpVv8cgddlf67J8hk1WfZMMP7sMeZmJRSmEax5xNDNWKdgqSe2brOKTQQAs3aCCUal2qBHAyg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", "cpu": [ "ia32" ], @@ -1221,9 +1221,9 @@ } }, "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.4.tgz", - "integrity": "sha512-3A6efb6BOKwyw7yk9ro2vus2YTt2nvcd56AuzxdMiVOxL9umDyN5PKkKfZ/gZ9row41SjVmTVQNWQhaRRGpOKw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", "cpu": [ "x64" ], @@ -1267,9 +1267,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz", - "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.0.tgz", + "integrity": "sha512-tPgXB6cDTndIe1ah7u6amCI1T0SsnlOuKgg10Xh3uizJk4e5M1JGaUMk7J4ciuAUcFpbOiNhm2XIjP9ON0dUqA==", "cpu": [ "arm" ], @@ -1281,9 +1281,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz", - "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.0.tgz", + "integrity": "sha512-sa4LyseLLXr1onr97StkU1Nb7fWcg6niokTwEVNOO7awaKaoRObQ54+V/hrF/BP1noMEaaAW6Fg2d/CfLiq3Mg==", "cpu": [ "arm64" ], @@ -1295,9 +1295,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz", - "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.0.tgz", + "integrity": "sha512-/NNIj9A7yLjKdmkx5dC2XQ9DmjIECpGpwHoGmA5E1AhU0fuICSqSWScPhN1yLCkEdkCwJIDu2xIeLPs60MNIVg==", "cpu": [ "arm64" ], @@ -1309,9 +1309,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz", - "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.0.tgz", + "integrity": "sha512-xoh8abqgPrPYPr7pTYipqnUi1V3em56JzE/HgDgitTqZBZ3yKCWI+7KUkceM6tNweyUKYru1UMi7FC060RyKwA==", "cpu": [ "x64" ], @@ -1323,9 +1323,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz", - "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.0.tgz", + "integrity": "sha512-PCkMh7fNahWSbA0OTUQ2OpYHpjZZr0hPr8lId8twD7a7SeWrvT3xJVyza+dQwXSSq4yEQTMoXgNOfMCsn8584g==", "cpu": [ "arm64" ], @@ -1337,9 +1337,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz", - "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.0.tgz", + "integrity": "sha512-1j3stGx+qbhXql4OCDZhnK7b01s6rBKNybfsX+TNrEe9JNq4DLi1yGiR1xW+nL+FNVvI4D02PUnl6gJ/2y6WJA==", "cpu": [ "x64" ], @@ -1351,9 +1351,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz", - "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.0.tgz", + "integrity": "sha512-eyrr5W08Ms9uM0mLcKfM/Uzx7hjhz2bcjv8P2uynfj0yU8GGPdz8iYrBPhiLOZqahoAMB8ZiolRZPbbU2MAi6Q==", "cpu": [ "arm" ], @@ -1365,9 +1365,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz", - "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.0.tgz", + "integrity": "sha512-Xds90ITXJCNyX9pDhqf85MKWUI4lqjiPAipJ8OLp8xqI2Ehk+TCVhF9rvOoN8xTbcafow3QOThkNnrM33uCFQA==", "cpu": [ "arm" ], @@ -1379,9 +1379,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz", - "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.0.tgz", + "integrity": "sha512-Xws2KA4CLvZmXjy46SQaXSejuKPhwVdaNinldoYfqruZBaJHqVo6hnRa8SDo9z7PBW5x84SH64+izmldCgbezw==", "cpu": [ "arm64" ], @@ -1393,9 +1393,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz", - "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.0.tgz", + "integrity": "sha512-hrKXKbX5FdaRJj7lTMusmvKbhMJSGWJ+w++4KmjiDhpTgNlhYobMvKfDoIWecy4O60K6yA4SnztGuNTQF+Lplw==", "cpu": [ "arm64" ], @@ -1407,9 +1407,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz", - "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.0.tgz", + "integrity": "sha512-6A+nccfSDGKsPm00d3xKcrsBcbqzCTAukjwWK6rbuAnB2bHaL3r9720HBVZ/no7+FhZLz/U3GwwZZEh6tOSI8Q==", "cpu": [ "loong64" ], @@ -1421,9 +1421,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz", - "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.0.tgz", + "integrity": "sha512-4P1VyYUe6XAJtQH1Hh99THxr0GKMMwIXsRNOceLrJnaHTDgk1FTcTimDgneRJPvB3LqDQxUmroBclQ1S0cIJwQ==", "cpu": [ "loong64" ], @@ -1435,9 +1435,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz", - "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.0.tgz", + "integrity": "sha512-8Vv6pLuIZCMcgXre6c3nOPhE0gjz1+nZP6T+hwWjr7sVH8k0jRkH+XnfjjOTglyMBdSKBPPz54/y1gToSKwrSQ==", "cpu": [ "ppc64" ], @@ -1449,9 +1449,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz", - "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.0.tgz", + "integrity": "sha512-r1te1M0Sm2TBVD/RxBPC6RZVwNqUTwJTA7w+C/IW5v9Ssu6xmxWEi+iJQlpBhtUiT1raJ5b48pI8tBvEjEFnFA==", "cpu": [ "ppc64" ], @@ -1463,9 +1463,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz", - "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.0.tgz", + "integrity": "sha512-say0uMU/RaPm3CDQLxUUTF2oNWL8ysvHkAjcCzV2znxBr23kFfaxocS9qJm+NdkRhF8wtdEEAJuYcLPhSPbjuQ==", "cpu": [ "riscv64" ], @@ -1477,9 +1477,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz", - "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.0.tgz", + "integrity": "sha512-/MU7/HizQGsnBREtRpcSbSV1zfkoxSTR7wLsRmBPQ8FwUj5sykrP1MyJTvsxP5KBq9SyE6kH8UQQQwa0ASeoQQ==", "cpu": [ "riscv64" ], @@ -1491,9 +1491,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz", - "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.0.tgz", + "integrity": "sha512-Q9eh+gUGILIHEaJf66aF6a414jQbDnn29zeu0eX3dHMuysnhTvsUvZTCAyZ6tJhUjnvzBKE4FtuaYxutxRZpOg==", "cpu": [ "s390x" ], @@ -1505,9 +1505,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz", - "integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.0.tgz", + "integrity": "sha512-OR5p5yG5OKSxHReWmwvM0P+VTPMwoBS45PXTMYaskKQqybkS3Kmugq1W+YbNWArF8/s7jQScgzXUhArzEQ7x0A==", "cpu": [ "x64" ], @@ -1519,9 +1519,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz", - "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.0.tgz", + "integrity": "sha512-XeatKzo4lHDsVEbm1XDHZlhYZZSQYym6dg2X/Ko0kSFgio+KXLsxwJQprnR48GvdIKDOpqWqssC3iBCjoMcMpw==", "cpu": [ "x64" ], @@ -1533,9 +1533,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz", - "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.0.tgz", + "integrity": "sha512-Lu71y78F5qOfYmubYLHPcJm74GZLU6UJ4THkf/a1K7Tz2ycwC2VUbsqbJAXaR6Bx70SRdlVrt2+n5l7F0agTUw==", "cpu": [ "x64" ], @@ -1547,9 +1547,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz", - "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.0.tgz", + "integrity": "sha512-v5xwKDWcu7qhAEcsUubiav7r+48Uk/ENWdr82MBZZRIm7zThSxCIVDfb3ZeRRq9yqk+oIzMdDo6fCcA5DHfMyA==", "cpu": [ "arm64" ], @@ -1561,9 +1561,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz", - "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.0.tgz", + "integrity": "sha512-XnaaaSMGSI6Wk8F4KK3QP7GfuuhjGchElsVerCplUuxRIzdvZ7hRBpLR0omCmw+kI2RFJB80nenhOoGXlJ5TfQ==", "cpu": [ "arm64" ], @@ -1575,9 +1575,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz", - "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.0.tgz", + "integrity": "sha512-3K1lP+3BXY4t4VihLw5MEg6IZD3ojSYzqzBG571W3kNQe4G4CcFpSUQVgurYgib5d+YaCjeFow8QivWp8vuSvA==", "cpu": [ "ia32" ], @@ -1589,9 +1589,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz", - "integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.0.tgz", + "integrity": "sha512-MDk610P/vJGc5L5ImE4k5s+GZT3en0KoK1MKPXCRgzmksAMk79j4h3k1IerxTNqwDLxsGxStEZVBqG0gIqZqoA==", "cpu": [ "x64" ], @@ -1603,9 +1603,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz", - "integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.0.tgz", + "integrity": "sha512-Zv7v6q6aV+VslnpwzqKAmrk5JdVkLUzok2208ZXGipjb+msxBr/fJPZyeEXiFgH7k62Ak0SLIfxQRZQvTuf7rQ==", "cpu": [ "x64" ], @@ -1639,9 +1639,9 @@ } }, "node_modules/@sinclair/typebox": { - "version": "0.34.47", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.47.tgz", - "integrity": "sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw==", + "version": "0.34.48", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz", + "integrity": "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==", "dev": true, "license": "MIT" }, @@ -1715,12 +1715,11 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.19.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.6.tgz", - "integrity": "sha512-qm+G8HuG6hOHQigsi7VGuLjUVu6TtBo/F05zvX04Mw2uCg9Dv0Qxy3Qw7j41SidlTcl5D/5yg0SEZqOB+EqZnQ==", + "version": "22.19.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.7.tgz", + "integrity": "sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -1740,14 +1739,14 @@ "license": "ISC" }, "node_modules/@vitest/coverage-v8": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.17.tgz", - "integrity": "sha512-/6zU2FLGg0jsd+ePZcwHRy3+WpNTBBhDY56P4JTRqUN/Dp6CvOEa9HrikcQ4KfV2b2kAHUFB4dl1SuocWXSFEw==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.18.tgz", + "integrity": "sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.0.17", + "@vitest/utils": "4.0.18", "ast-v8-to-istanbul": "^0.3.10", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", @@ -1761,8 +1760,8 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "4.0.17", - "vitest": "4.0.17" + "@vitest/browser": "4.0.18", + "vitest": "4.0.18" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -1771,16 +1770,16 @@ } }, "node_modules/@vitest/expect": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.17.tgz", - "integrity": "sha512-mEoqP3RqhKlbmUmntNDDCJeTDavDR+fVYkSOw8qRwJFaW/0/5zA9zFeTrHqNtcmwh6j26yMmwx2PqUDPzt5ZAQ==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", + "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.0.17", - "@vitest/utils": "4.0.17", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", "chai": "^6.2.1", "tinyrainbow": "^3.0.3" }, @@ -1789,13 +1788,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.17.tgz", - "integrity": "sha512-+ZtQhLA3lDh1tI2wxe3yMsGzbp7uuJSWBM1iTIKCbppWTSBN09PUC+L+fyNlQApQoR+Ps8twt2pbSSXg2fQVEQ==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", + "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.0.17", + "@vitest/spy": "4.0.18", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -1816,9 +1815,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.17.tgz", - "integrity": "sha512-Ah3VAYmjcEdHg6+MwFE17qyLqBHZ+ni2ScKCiW2XrlSBV4H3Z7vYfPfz7CWQ33gyu76oc0Ai36+kgLU3rfF4nw==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", + "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", "dev": true, "license": "MIT", "dependencies": { @@ -1829,13 +1828,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.17.tgz", - "integrity": "sha512-JmuQyf8aMWoo/LmNFppdpkfRVHJcsgzkbCA+/Bk7VfNH7RE6Ut2qxegeyx2j3ojtJtKIbIGy3h+KxGfYfk28YQ==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", + "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.0.17", + "@vitest/utils": "4.0.18", "pathe": "^2.0.3" }, "funding": { @@ -1843,13 +1842,13 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.17.tgz", - "integrity": "sha512-npPelD7oyL+YQM2gbIYvlavlMVWUfNNGZPcu0aEUQXt7FXTuqhmgiYupPnAanhKvyP6Srs2pIbWo30K0RbDtRQ==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", + "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.17", + "@vitest/pretty-format": "4.0.18", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -1858,9 +1857,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.17.tgz", - "integrity": "sha512-I1bQo8QaP6tZlTomQNWKJE6ym4SHf3oLS7ceNjozxxgzavRAgZDc06T7kD8gb9bXKEgcLNt00Z+kZO6KaJ62Ew==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", + "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", "dev": true, "license": "MIT", "funding": { @@ -1868,13 +1867,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.17.tgz", - "integrity": "sha512-RG6iy+IzQpa9SB8HAFHJ9Y+pTzI+h8553MrciN9eC6TFBErqrQaTas4vG+MVj8S4uKk8uTT2p0vgZPnTdxd96w==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", + "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.17", + "@vitest/pretty-format": "4.0.18", "tinyrainbow": "^3.0.3" }, "funding": { @@ -1997,9 +1996,8 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, + "extraneous": true, "license": "ISC", - "optional": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -2264,9 +2262,8 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, + "extraneous": true, "license": "MIT", - "optional": true, "engines": { "node": ">=8" }, @@ -3001,9 +2998,9 @@ "license": "MIT" }, "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", "license": "MIT", "dependencies": { "object-assign": "^4", @@ -3011,6 +3008,10 @@ }, "engines": { "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/cosmiconfig": { @@ -4183,7 +4184,6 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", - "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -5271,9 +5271,9 @@ } }, "node_modules/hono": { - "version": "4.11.4", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.4.tgz", - "integrity": "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==", + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.6.tgz", + "integrity": "sha512-ofIiiHyl34SV6AuhE3YT2mhO5HRWokce+eUYE82TsP6z0/H3JeJcjVWEMSIAiw2QkjDOEpES/lYsg8eEbsLtdw==", "license": "MIT", "peer": true, "engines": { @@ -5639,9 +5639,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, + "extraneous": true, "license": "MIT", - "optional": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -6464,9 +6463,9 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "dev": true, "license": "MIT" }, @@ -7754,9 +7753,9 @@ } }, "node_modules/prettier": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", - "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", "bin": { @@ -8447,9 +8446,9 @@ } }, "node_modules/rollup": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz", - "integrity": "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.0.tgz", + "integrity": "sha512-e5lPJi/aui4TO1LpAXIRLySmwXSE8k3b9zoGfd42p67wzxog4WHjiZF3M2uheQih4DGyc25QEV4yRBbpueNiUA==", "dev": true, "license": "MIT", "dependencies": { @@ -8463,31 +8462,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.55.1", - "@rollup/rollup-android-arm64": "4.55.1", - "@rollup/rollup-darwin-arm64": "4.55.1", - "@rollup/rollup-darwin-x64": "4.55.1", - "@rollup/rollup-freebsd-arm64": "4.55.1", - "@rollup/rollup-freebsd-x64": "4.55.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", - "@rollup/rollup-linux-arm-musleabihf": "4.55.1", - "@rollup/rollup-linux-arm64-gnu": "4.55.1", - "@rollup/rollup-linux-arm64-musl": "4.55.1", - "@rollup/rollup-linux-loong64-gnu": "4.55.1", - "@rollup/rollup-linux-loong64-musl": "4.55.1", - "@rollup/rollup-linux-ppc64-gnu": "4.55.1", - "@rollup/rollup-linux-ppc64-musl": "4.55.1", - "@rollup/rollup-linux-riscv64-gnu": "4.55.1", - "@rollup/rollup-linux-riscv64-musl": "4.55.1", - "@rollup/rollup-linux-s390x-gnu": "4.55.1", - "@rollup/rollup-linux-x64-gnu": "4.55.1", - "@rollup/rollup-linux-x64-musl": "4.55.1", - "@rollup/rollup-openbsd-x64": "4.55.1", - "@rollup/rollup-openharmony-arm64": "4.55.1", - "@rollup/rollup-win32-arm64-msvc": "4.55.1", - "@rollup/rollup-win32-ia32-msvc": "4.55.1", - "@rollup/rollup-win32-x64-gnu": "4.55.1", - "@rollup/rollup-win32-x64-msvc": "4.55.1", + "@rollup/rollup-android-arm-eabi": "4.57.0", + "@rollup/rollup-android-arm64": "4.57.0", + "@rollup/rollup-darwin-arm64": "4.57.0", + "@rollup/rollup-darwin-x64": "4.57.0", + "@rollup/rollup-freebsd-arm64": "4.57.0", + "@rollup/rollup-freebsd-x64": "4.57.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.0", + "@rollup/rollup-linux-arm-musleabihf": "4.57.0", + "@rollup/rollup-linux-arm64-gnu": "4.57.0", + "@rollup/rollup-linux-arm64-musl": "4.57.0", + "@rollup/rollup-linux-loong64-gnu": "4.57.0", + "@rollup/rollup-linux-loong64-musl": "4.57.0", + "@rollup/rollup-linux-ppc64-gnu": "4.57.0", + "@rollup/rollup-linux-ppc64-musl": "4.57.0", + "@rollup/rollup-linux-riscv64-gnu": "4.57.0", + "@rollup/rollup-linux-riscv64-musl": "4.57.0", + "@rollup/rollup-linux-s390x-gnu": "4.57.0", + "@rollup/rollup-linux-x64-gnu": "4.57.0", + "@rollup/rollup-linux-x64-musl": "4.57.0", + "@rollup/rollup-openbsd-x64": "4.57.0", + "@rollup/rollup-openharmony-arm64": "4.57.0", + "@rollup/rollup-win32-arm64-msvc": "4.57.0", + "@rollup/rollup-win32-ia32-msvc": "4.57.0", + "@rollup/rollup-win32-x64-gnu": "4.57.0", + "@rollup/rollup-win32-x64-msvc": "4.57.0", "fsevents": "~2.3.2" } }, @@ -8676,7 +8675,6 @@ "integrity": "sha512-ffmsdbwqb3XeyR8jJR6KelIXARM9bFQe8A6Q3W4Klmwy5Ckd5gz7jgUNHo4UOqutU5Sk1DtKLbpDP0nLCg1xqQ==", "license": "MIT", "optional": true, - "peer": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -8821,7 +8819,6 @@ "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.92.1.tgz", "integrity": "sha512-28YwLnF5atAhogt3E4hXzz/NB9dwKffyw08a7DEasLh94P7+aELkG3ENSHYCWB9QFN14hYNLfwr9ozUsPDhcDQ==", "license": "MIT", - "peer": true, "dependencies": { "@bufbuild/protobuf": "^2.5.0", "buffer-builder": "^0.2.0", @@ -9292,10 +9289,8 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, + "extraneous": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -9347,9 +9342,8 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, + "extraneous": true, "license": "ISC", - "optional": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -9387,9 +9381,8 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, + "extraneous": true, "license": "MIT", - "optional": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -10610,7 +10603,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -10776,7 +10768,6 @@ "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" @@ -10932,7 +10923,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -11531,7 +11521,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -11540,20 +11529,19 @@ } }, "node_modules/vitest": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.17.tgz", - "integrity": "sha512-FQMeF0DJdWY0iOnbv466n/0BudNdKj1l5jYgl5JVTwjSsZSlqyXFt/9+1sEyhR6CLowbZpV7O1sCHrzBhucKKg==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", + "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@vitest/expect": "4.0.17", - "@vitest/mocker": "4.0.17", - "@vitest/pretty-format": "4.0.17", - "@vitest/runner": "4.0.17", - "@vitest/snapshot": "4.0.17", - "@vitest/spy": "4.0.17", - "@vitest/utils": "4.0.17", + "@vitest/expect": "4.0.18", + "@vitest/mocker": "4.0.18", + "@vitest/pretty-format": "4.0.18", + "@vitest/runner": "4.0.18", + "@vitest/snapshot": "4.0.18", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", "es-module-lexer": "^1.7.0", "expect-type": "^1.2.2", "magic-string": "^0.30.21", @@ -11581,10 +11569,10 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.0.17", - "@vitest/browser-preview": "4.0.17", - "@vitest/browser-webdriverio": "4.0.17", - "@vitest/ui": "4.0.17", + "@vitest/browser-playwright": "4.0.18", + "@vitest/browser-preview": "4.0.18", + "@vitest/browser-webdriverio": "4.0.18", + "@vitest/ui": "4.0.18", "happy-dom": "*", "jsdom": "*" }, @@ -11714,9 +11702,9 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", - "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", "dev": true, "license": "MIT", "dependencies": { @@ -11857,7 +11845,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/src/mcp/README.md b/src/mcp/README.md index abc56a6a..57ceb249 100644 --- a/src/mcp/README.md +++ b/src/mcp/README.md @@ -163,10 +163,6 @@ For any other MCP-compatible client, use the STDIO transport configuration: - Local: `/absolute/path/to/igniteui-theming/dist/mcp/index.js` - Package: `igniteui-theming-mcp` -```` - ---- - ## Tools Reference The MCP server provides tools for theme generation. @@ -211,7 +207,7 @@ Generates a color palette with automatically calculated shade variations (50-900 > "Create a color palette with blue as primary and orange as secondary for a light theme" -> "Generate a dark theme palette using my brand colors: primary #6366F1, secondary #EC4899, surface #1E1E1E" +> "Generate a dark theme palette using my brand colors: primary #6366f1, secondary #ec4899, surface #1e1e1e" > "I need a light palette with teal primary, purple secondary, and white surface" @@ -251,7 +247,7 @@ Creates a palette with fine-grained control over individual shade values. Use th > "Our design system specifies exact colors for primary-500, primary-600, primary-700. Use those exact values and auto-generate the rest." -> "Make a custom palette with explicit shades for primary (#3B82F6 as base) but let secondary auto-generate from #EC4899" +> "Make a custom palette with explicit shades for primary (#3b82f6 as base) but let secondary auto-generate from #ec4899" --- @@ -320,15 +316,77 @@ Generates a complete, production-ready theme with palette, typography, and eleva **Example prompts:** -> "Create a complete Material Design dark theme for my Angular app with primary #3F51B5, secondary #FF4081, and a dark surface" +> "Create a complete Material Design dark theme for my Angular app with primary #3f51b5, secondary #ff4081, and a dark surface" -> "Generate a production-ready Bootstrap light theme using my brand colors: primary teal (#009688), secondary amber (#FFC107)" +> "Generate a production-ready Bootstrap light theme using my brand colors: primary teal (#009688), secondary amber (#ffc107)" > "Create a Fluent theme for Web Components with Segoe UI font, blue primary, and orange accent colors" -> "I need a dark Indigo theme for React with navy blue primary (#1E3A8A), warm orange secondary (#F97316), and charcoal surface (#18181B)" +> "I need a dark Indigo theme for React with navy blue primary (#1e3a8a), warm orange secondary (#f97316), and charcoal surface (#18181B)" -> "Make a light Material theme for Blazor using our brand: primary #7C3AED (purple), secondary #10B981 (green), with Inter font" +> "Make a light Material theme for Blazor using our brand: primary #7c3aed (purple), secondary #10b981 (green), with Inter font" + +--- + +### `set_size` + +Sets the size scale for all components or a specific component by updating `--ig-size`. + +| Parameter | Type | Required | Description | +| ----------- | -------------------------------------- | -------- | ------------------------------------------------------- | +| `size` | `"small"` \| `"medium"` \| `"large"` \| `1` \| `2` \| `3` | Yes | Size value (small/medium/large or 1/2/3) | +| `component` | string | No | Component name to scope (e.g., `"flat-button"`) | +| `scope` | string | No | CSS selector scope (default `:root`) | +| `platform` | `"angular"` \| `"webcomponents"` \| `"react"` \| `"blazor"` | No | Target platform for selectors | +| `output` | `"css"` \| `"sass"` | No | Output format (default: `"css"`) | + +**Example prompts:** + +> "Make all components small" + +> "Make flat buttons medium" + +--- + +### `set_spacing` + +Sets the spacing scale for all components or a specific component by updating `--ig-spacing`. + +| Parameter | Type | Required | Description | +| ----------- | -------------------------------------- | -------- | ------------------------------------------------------- | +| `spacing` | number | Yes | Spacing scale (0 = none, 1 = default, 2 = double) | +| `inline` | number | No | Override inline spacing (`--ig-spacing-inline`) | +| `block` | number | No | Override block spacing (`--ig-spacing-block`) | +| `component` | string | No | Component name to scope | +| `scope` | string | No | CSS selector scope (default `:root`) | +| `platform` | `"angular"` \| `"webcomponents"` \| `"react"` \| `"blazor"` | No | Target platform for selectors | +| `output` | `"css"` \| `"sass"` | No | Output format (default: `"css"`) | + +**Example prompts:** + +> "The calendar feels bloated, reduce its spacing" + +> "Tighten spacing in .compact sections" + +--- + +### `set_roundness` + +Sets the roundness scale for all components or a specific component by updating `--ig-radius-factor`. + +| Parameter | Type | Required | Description | +| ------------- | -------------------------------------- | -------- | ------------------------------------------------------- | +| `radiusFactor` | number | Yes | Roundness factor (0 = min, 1 = max) | +| `component` | string | No | Component name to scope | +| `scope` | string | No | CSS selector scope (default `:root`) | +| `platform` | `"angular"` \| `"webcomponents"` \| `"react"` \| `"blazor"` | No | Target platform for selectors | +| `output` | `"css"` \| `"sass"` | No | Output format (default: `"css"`) | + +**Example prompts:** + +> "Make flat buttons more round" + +> "Reduce the roundness globally" --- @@ -379,11 +437,11 @@ Generates Sass code to customize a specific component's appearance using design **Example prompts:** -> "Create a button theme with a purple background (#8B5CF6) and white text" +> "Create a button theme with a purple background (#8b5cf6) and white text" > "Style the card component with a light gray background and subtle shadow" -> "Make the data grid header bold with a blue background (#1E40AF)" +> "Make the data grid header bold with a blue background (#1e40af)" > "Customize the input component for dark mode with a dark background and bright border" @@ -398,7 +456,7 @@ AI: First, let me check what design tokens are available for buttons. AI: Great! I can customize these properties: background, foreground, border-color, hover-background, and more. What are your brand colors? -User: "Primary purple #8B5CF6, white text, and lighter purple #A78BFA on hover" +User: "Primary purple #8b5cf6, white text, and lighter purple #a78bfa on hover" AI: Perfect! Let me create that theme for you. [calls create_component_theme with tokens] @@ -439,6 +497,18 @@ The MCP server exposes read-only resources that provide reference data. | `theming://guidance/colors/states` | Color changes for interaction states | | `theming://guidance/colors/themes` | Design system-specific color patterns | +### Layout Documentation Resources + +| URI | Description | +| ---------------------------------------- | -------------------------------------- | +| `theming://docs/spacing-and-sizing` | Layout scale overview | +| `theming://docs/functions/pad` | pad() function documentation | +| `theming://docs/functions/sizable` | sizable() function documentation | +| `theming://docs/functions/border-radius` | border-radius() function documentation | +| `theming://docs/mixins/spacing` | spacing() mixin documentation | +| `theming://docs/mixins/sizing` | sizing() mixin documentation | +| `theming://docs/mixins/sizable` | sizable() mixin documentation | + --- ## Example Usage Scenarios @@ -447,8 +517,8 @@ The MCP server exposes read-only resources that provide reference data. > "I'm starting a new Angular project with Ignite UI. Create a complete Material Design theme with: > -> - Primary: our brand blue #2563EB -> - Secondary: coral accent #F97316 +> - Primary: our brand blue #2563eb +> - Secondary: coral accent #f97316 > - Light theme > - Roboto font" @@ -538,7 +608,7 @@ If you see warnings about color luminance, it means your chosen color may produc ### "Surface color doesn't match variant" -For light themes, use light surface colors (high luminance like `#FAFAFA`). +For light themes, use light surface colors (high luminance like `#fafafa`). For dark themes, use dark surface colors (low luminance like `#121212`). ### Generated code doesn't compile diff --git a/src/mcp/ROADMAP.md b/src/mcp/ROADMAP.md index 7be2442f..2807aab2 100644 --- a/src/mcp/ROADMAP.md +++ b/src/mcp/ROADMAP.md @@ -156,10 +156,10 @@ Tools are the core of the MCP server - they perform actions and generate code. #### Tool Category 2: Color Operations -| Tool Name | Description | Input Schema | Output | -| ----------------------- | ------------------------------------ | ------------------------------------------ | ---------------------- | -| `get_color` | Retrieve a palette color as CSS var | `{ color, variant?, contrast?, opacity? }` | CSS variable reference | -| `suggest_palette` | Suggest palette based on description | `{ description, mood?, industry? }` | Recommended colors | +| Tool Name | Description | Input Schema | Output | +| ----------------- | ------------------------------------ | ------------------------------------------ | ---------------------- | +| `get_color` | Retrieve a palette color as CSS var | `{ color, variant?, contrast?, opacity? }` | CSS variable reference | +| `suggest_palette` | Suggest palette based on description | `{ description, mood?, industry? }` | Recommended colors | **Note:** `get_contrast_color` has been consolidated into `get_color` via the `contrast` parameter. @@ -173,11 +173,11 @@ Tools are the core of the MCP server - they perform actions and generate code. #### Tool Category 4: Spacing & Sizing -| Tool Name | Description | Input Schema | Output | -| ----------------------- | ------------------------- | ----------------------------------------- | ------------------ | -| `create_spacing_system` | Define spacing scale | `{ baseUnit?, scale? }` | Spacing variables | -| `get_sizable_value` | Get responsive size value | `{ small, medium, large }` | Sizable expression | -| `get_padding` | Get contextual padding | `{ small?, medium?, large?, direction? }` | Padding expression | +| Tool Name | Description | Input Schema | Output | +| --------------- | -------------------------------------- | ---------------------------------------------------------------------- | ----------------------- | +| `set_size` | Set size scale (global/component) | `{ component?, scope?, size, platform?, output? }` | CSS/Sass variable block | +| `set_spacing` | Set spacing scale (global/component) | `{ component?, scope?, spacing, inline?, block?, platform?, output? }` | CSS/Sass variable block | +| `set_roundness` | Set roundness scale (global/component) | `{ component?, scope?, radiusFactor, platform?, output? }` | CSS/Sass variable block | #### Tool Category 5: Component Theming @@ -241,11 +241,12 @@ Resources provide read-only context that AI applications can use. #### Resource Category 6: Documentation (Resource Templates) -| URI Template | Description | -| --------------------------------- | ---------------------- | -| `theming://docs/functions/{name}` | Function documentation | -| `theming://docs/mixins/{name}` | Mixin documentation | -| `theming://docs/variables/{name}` | Variable documentation | +| URI Template | Description | +| ----------------------------------- | ---------------------- | +| `theming://docs/functions/{name}` | Function documentation | +| `theming://docs/mixins/{name}` | Mixin documentation | +| `theming://docs/variables/{name}` | Variable documentation | +| `theming://docs/spacing-and-sizing` | Layout scale overview | #### Category 7: Guidance (Direct Resources) @@ -334,9 +335,9 @@ The `create_palette`, `create_custom_palette`, and `create_theme` tools validate - `create_type_style` tool - `get_type_scale_category` tool - `convert_units` tool -- `create_spacing_system` tool -- `get_sizable_value` tool -- `get_padding` tool +- `set_size` tool +- `set_spacing` tool +- `set_roundness` tool - Typography documentation resources ### Phase 4: Validation & Intelligence @@ -520,131 +521,6 @@ Both platforms generate similar CSS custom properties: } ``` ---- - -## File Structure (Initial Scaffolding) - -``` -src/mcp/ -├── index.ts # Entry point, server initialization -├── server.ts # MCP server configuration -├── transport/ -│ ├── stdio.ts # STDIO transport -│ └── http.ts # HTTP transport (future) -├── tools/ -│ ├── index.ts # Tool registry -│ ├── handlers/ # Tool handler implementations -│ │ ├── theme.ts # create_theme handler -│ │ ├── palette.ts # create_palette handler -│ │ ├── typography.ts # create_typography handler -│ │ ├── elevations.ts # create_elevations handler -│ │ └── platform.ts # detect_platform handler -│ └── schemas.ts # Zod schemas for tool inputs -├── resources/ -│ ├── index.ts # Resource registry -│ ├── presets.ts # Preset resources -│ ├── schemas.ts # Schema resources -│ ├── components.ts # Component catalog -│ └── docs.ts # Documentation resources -├── prompts/ -│ ├── index.ts # Prompt registry -│ └── templates.ts # Prompt definitions -├── generators/ -│ ├── sass.ts # Sass code generation (platform-aware) -│ ├── css.ts # CSS code generation -│ └── templates/ # Code templates -├── validators/ -│ ├── sass.ts # Sass validation (dart-sass) -│ └── contrast.ts # WCAG contrast validation -├── knowledge/ -│ ├── index.ts # Knowledge base exports -│ ├── palettes.ts # Embedded palette data -│ ├── typography.ts # Embedded typography data -│ ├── elevations.ts # Embedded elevation data -│ ├── multipliers.ts # Color multipliers -│ ├── platforms/ # Platform-specific knowledge -│ │ ├── index.ts # Platform exports, detection -│ │ ├── angular.ts # Angular platform config & generator -│ │ └── webcomponents.ts # Web Components platform config & generator -│ └── components/ # Component schemas -└── utils/ - ├── color.ts # Color manipulation utilities - ├── units.ts # Unit conversion - └── types.ts # TypeScript types -``` - ---- - -## Build Configuration - -### Vite Configuration - -```typescript -// vite.config.mcp.ts -import {defineConfig} from 'vite'; -import {resolve} from 'path'; - -export default defineConfig({ - build: { - lib: { - entry: resolve(__dirname, 'src/mcp/index.ts'), - formats: ['es'], - fileName: 'index', - }, - outDir: 'mcp', - rollupOptions: { - external: ['@modelcontextprotocol/sdk'], - }, - }, -}); -``` - -### Package.json Updates - -```json -{ - "bin": { - "igniteui-theming-mcp": "./mcp/index.js" - }, - "exports": { - "./mcp": { - "import": "./mcp/index.js" - } - }, - "files": ["mcp/"], - "scripts": { - "build:mcp": "vite build --config vite.config.mcp.ts", - "mcp:dev": "tsx src/mcp/index.ts" - } -} -``` - ---- - -## Dependencies - -### Runtime Dependencies - -```json -{ - "@modelcontextprotocol/sdk": "^1.0.0", - "zod": "^3.0.0", - "sass-embedded": "^1.92.0" -} -``` - -### Dev Dependencies - -```json -{ - "vite": "^5.0.0", - "typescript": "^5.0.0", - "tsx": "^4.0.0" -} -``` - ---- - ## Usage Examples ### Claude Desktop Configuration diff --git a/src/mcp/__tests__/knowledge/sass-api.test.ts b/src/mcp/__tests__/knowledge/sass-api.test.ts index 3b113cdc..f8f79389 100644 --- a/src/mcp/__tests__/knowledge/sass-api.test.ts +++ b/src/mcp/__tests__/knowledge/sass-api.test.ts @@ -176,11 +176,19 @@ describe('CSS_VARIABLE_PATTERNS', () => { }); it('has correct size variables', () => { + expect(CSS_VARIABLE_PATTERNS.sizes.base).toBe('--ig-size'); expect(CSS_VARIABLE_PATTERNS.sizes.small).toBe('--ig-size-small'); expect(CSS_VARIABLE_PATTERNS.sizes.medium).toBe('--ig-size-medium'); expect(CSS_VARIABLE_PATTERNS.sizes.large).toBe('--ig-size-large'); }); + it('has correct spacing and roundness variables', () => { + expect(CSS_VARIABLE_PATTERNS.spacing.base).toBe('--ig-spacing'); + expect(CSS_VARIABLE_PATTERNS.spacing.inline).toBe('--ig-spacing-inline'); + expect(CSS_VARIABLE_PATTERNS.spacing.block).toBe('--ig-spacing-block'); + expect(CSS_VARIABLE_PATTERNS.roundness).toBe('--ig-radius-factor'); + }); + it('has correct scrollbar variables', () => { expect(CSS_VARIABLE_PATTERNS.scrollbar.size).toBe('--ig-scrollbar-size'); expect(CSS_VARIABLE_PATTERNS.scrollbar.thumbBackground).toBe('--ig-scrollbar-thumb-background'); diff --git a/src/mcp/__tests__/tools/handlers/handlers.test.ts b/src/mcp/__tests__/tools/handlers/handlers.test.ts index 42193aaf..a0975038 100644 --- a/src/mcp/__tests__/tools/handlers/handlers.test.ts +++ b/src/mcp/__tests__/tools/handlers/handlers.test.ts @@ -14,6 +14,7 @@ import {handleCreateTypography} from '../../../tools/handlers/typography.js'; import {handleCreateElevations} from '../../../tools/handlers/elevations.js'; import {handleCreateCustomPalette} from '../../../tools/handlers/custom-palette.js'; import {handleCreateComponentTheme} from '../../../tools/handlers/component-theme.js'; +import {handleSetRoundness, handleSetSize, handleSetSpacing} from '../../../tools/handlers/layout.js'; describe('handleCreatePalette', () => { it('returns MCP response format', async () => { @@ -224,6 +225,43 @@ describe('handleCreateTypography', () => { }); }); +describe('layout handlers', () => { + it('set_size returns size override code', async () => { + const result = await handleSetSize({ + size: 'small', + component: 'flat-button', + platform: 'webcomponents', + }); + + const text = result.content[0].text; + expect(text).toContain('--ig-size: 1;'); + expect(text).toContain('igc-button[variant="flat"]'); + }); + + it('set_spacing requires spacing and returns override code', async () => { + const result = await handleSetSpacing({ + spacing: 0.75, + scope: '.compact', + }); + + const text = result.content[0].text; + expect(text).toContain('--ig-spacing: 0.75;'); + expect(text).toContain('.compact'); + }); + + it('set_roundness returns radius factor override', async () => { + const result = await handleSetRoundness({ + radiusFactor: 0.8, + component: 'avatar', + platform: 'angular', + }); + + const text = result.content[0].text; + expect(text).toContain('--ig-radius-factor: 0.8;'); + expect(text).toContain('igx-avatar'); + }); +}); + describe('handleCreateElevations', () => { it('returns MCP response format', () => { const result = handleCreateElevations({}); diff --git a/src/mcp/__tests__/tools/schemas.test.ts b/src/mcp/__tests__/tools/schemas.test.ts index 3875b0e0..ba7c019e 100644 --- a/src/mcp/__tests__/tools/schemas.test.ts +++ b/src/mcp/__tests__/tools/schemas.test.ts @@ -9,7 +9,13 @@ */ import {describe, it, expect} from 'vitest'; -import {colorSchema, createCustomPaletteSchema} from '../../tools/schemas.js'; +import { + colorSchema, + createCustomPaletteSchema, + setRoundnessSchema, + setSizeSchema, + setSpacingSchema, +} from '../../tools/schemas.js'; describe('colorSchema', () => { describe('hex colors', () => { @@ -289,6 +295,34 @@ describe('colorSchema', () => { }); }); +describe('layout schemas', () => { + it('accepts size keywords and numeric values', () => { + expect(setSizeSchema.safeParse({size: 'small'}).success).toBe(true); + expect(setSizeSchema.safeParse({size: 1}).success).toBe(true); + expect(setSizeSchema.safeParse({size: 2}).success).toBe(true); + expect(setSizeSchema.safeParse({size: 3}).success).toBe(true); + expect(setSizeSchema.safeParse({size: 1.5}).success).toBe(false); + expect(setSizeSchema.safeParse({size: 4}).success).toBe(false); + }); + + it('requires spacing for set_spacing', () => { + expect(setSpacingSchema.safeParse({spacing: 1}).success).toBe(true); + expect(setSpacingSchema.safeParse({inline: 0.5}).success).toBe(false); + }); + + it('rejects negative spacing values', () => { + expect(setSpacingSchema.safeParse({spacing: -0.5}).success).toBe(false); + expect(setSpacingSchema.safeParse({spacing: 1, inline: -0.5}).success).toBe(false); + expect(setSpacingSchema.safeParse({spacing: 1, block: -0.25}).success).toBe(false); + }); + + it('enforces radiusFactor between 0 and 1', () => { + expect(setRoundnessSchema.safeParse({radiusFactor: 0}).success).toBe(true); + expect(setRoundnessSchema.safeParse({radiusFactor: 1}).success).toBe(true); + expect(setRoundnessSchema.safeParse({radiusFactor: 1.1}).success).toBe(false); + }); +}); + describe('createCustomPaletteSchema', () => { describe('color definition validation', () => { it('rejects plain string colors for primary/secondary/surface', () => { diff --git a/src/mcp/index.ts b/src/mcp/index.ts index 117240a9..96f4a749 100644 --- a/src/mcp/index.ts +++ b/src/mcp/index.ts @@ -20,6 +20,10 @@ import { getComponentDesignTokensSchema, createComponentThemeSchema, getColorSchema, + setSizeSchema, + setSpacingSchema, + setSpacingInputSchema, + setRoundnessSchema, handleDetectPlatform, handleCreatePalette, handleCreateCustomPalette, @@ -29,6 +33,9 @@ import { handleGetComponentDesignTokens, handleCreateComponentTheme, handleGetColor, + handleSetSize, + handleSetSpacing, + handleSetRoundness, } from './tools/index.js'; import {TOOL_DESCRIPTIONS} from './tools/descriptions.js'; import {withPreprocessing} from './utils/preprocessing.js'; @@ -192,6 +199,68 @@ function registerTools(server: McpServer): void { }, ); + // set_size tool + server.registerTool( + 'set_size', + { + title: 'Set Size Scale', + description: TOOL_DESCRIPTIONS.set_size, + inputSchema: { + platform: setSizeSchema.shape.platform, + component: setSizeSchema.shape.component, + scope: setSizeSchema.shape.scope, + size: setSizeSchema.shape.size, + output: setSizeSchema.shape.output, + }, + }, + async (params) => { + const validated = setSizeSchema.parse(params); + return handleSetSize(validated); + }, + ); + + // set_spacing tool + server.registerTool( + 'set_spacing', + { + title: 'Set Spacing Scale', + description: TOOL_DESCRIPTIONS.set_spacing, + inputSchema: { + platform: setSpacingInputSchema.shape.platform, + component: setSpacingInputSchema.shape.component, + scope: setSpacingInputSchema.shape.scope, + spacing: setSpacingInputSchema.shape.spacing, + inline: setSpacingInputSchema.shape.inline, + block: setSpacingInputSchema.shape.block, + output: setSpacingInputSchema.shape.output, + }, + }, + async (params) => { + const validated = setSpacingSchema.parse(params); + return handleSetSpacing(validated); + }, + ); + + // set_roundness tool + server.registerTool( + 'set_roundness', + { + title: 'Set Roundness Scale', + description: TOOL_DESCRIPTIONS.set_roundness, + inputSchema: { + platform: setRoundnessSchema.shape.platform, + component: setRoundnessSchema.shape.component, + scope: setRoundnessSchema.shape.scope, + radiusFactor: setRoundnessSchema.shape.radiusFactor, + output: setRoundnessSchema.shape.output, + }, + }, + async (params) => { + const validated = setRoundnessSchema.parse(params); + return handleSetRoundness(validated); + }, + ); + // get_component_design_tokens tool server.registerTool( 'get_component_design_tokens', diff --git a/src/mcp/knowledge/index.ts b/src/mcp/knowledge/index.ts index a69d72df..55bd36fe 100644 --- a/src/mcp/knowledge/index.ts +++ b/src/mcp/knowledge/index.ts @@ -132,6 +132,17 @@ export { ELEVATIONS as ELEVATIONS_PRESETS, } from './platforms/common.js'; +// Layout docs +export { + LAYOUT_OVERVIEW_DOC, + PAD_FUNCTION_DOC, + SIZABLE_FUNCTION_DOC, + BORDER_RADIUS_FUNCTION_DOC, + SPACING_MIXIN_DOC, + SIZING_MIXIN_DOC, + SIZABLE_MIXIN_DOC, +} from './layout-docs.js'; + // Component Themes export { type ComponentToken, diff --git a/src/mcp/knowledge/layout-docs.ts b/src/mcp/knowledge/layout-docs.ts new file mode 100644 index 00000000..255cab62 --- /dev/null +++ b/src/mcp/knowledge/layout-docs.ts @@ -0,0 +1,212 @@ +/** + * Layout documentation resources for sizing, spacing, and roundness. + */ + +export const LAYOUT_OVERVIEW_DOC = [ + '# Layout scale overview', + '', + 'Ignite UI components expose sizing, spacing, and roundness through CSS custom properties.', + 'You can set them globally on :root or locally on a specific component selector.', + '', + '## Size', + '--ig-size is the primary control. Components map it into --component-size internally:', + '--component-size: var(--ig-size, ).', + '', + 'Size affects any styles that use sizable() or pad() functions.', + 'Suggested values:', + '- 1 = small', + '- 2 = medium (default in mosts components)', + '- 3 = large', + '- fractional values are NOT ALLOWED (0.75, 1.5)', + '', + '## Spacing', + '--ig-spacing scales spacing used by pad(), pad-inline(), and pad-block().', + 'Suggested values:', + '- 0 = no spacing', + '- 1 = default', + '- 2 = double', + '- fractional values are ALLOWED (0.75, 1.5)', + '', + 'You can override inline or block independently:', + '- --ig-spacing-inline', + '- --ig-spacing-block', + '', + '## Roundness', + '--ig-radius-factor scales border radius values when border-radius() is used.', + '- 0 = minimum radius', + '- 1 = maximum radius', + '- values between 0 and 1 interpolate between min and max', + '', + '## Examples', + '', + '### CSS (global)', + '```css', + ':root {', + ' --ig-size: 2;', + ' --ig-spacing: 0.75;', + ' --ig-radius-factor: 0.8;', + '}', + '```', + '', + '### CSS (component scope)', + '```css', + 'igx-calendar,', + 'igc-calendar {', + ' --ig-size: 1;', + ' --ig-spacing: 0.5;', + ' --ig-radius-factor: 0.9;', + '}', + '```', + '', + '### Sass notes', + '- To react to --ig-size, component styles must include @include sizable().', + '- To use pad(), pad-inline(), or pad-block(), include @include spacing() once.', + '- border-radius() responds to --ig-radius-factor without extra mixins.', +].join('\n'); + +export const PAD_FUNCTION_DOC = [ + '# pad() function', + '', + 'Returns a size-aware spacing value based on --ig-spacing and size flags.', + '', + '## Mechanism', + 'pad() uses --is-small/medium/large (from @include sizable()) and multiplies the', + 'chosen size by spacing variables:', + '- --ig-spacing', + '- --ig-spacing-inline (optional)', + '- --ig-spacing-block (optional)', + '', + '## Sass example', + '```scss', + '.my-card {', + ' padding: pad(4px, 8px, 16px);', + '}', + '```', + '', + '## CSS example', + '```css', + '.my-card {', + ' --ig-spacing: 0.75;', + '}', + '```', + '', + '## Notes', + '- Requires @include sizing() and @include sizable() in component styles.', + '- Requires @include spacing() once to set spacing variables.', +].join('\n'); + +export const SIZABLE_FUNCTION_DOC = [ + '# sizable() function', + '', + 'Returns a size-aware value based on --ig-size and --component-size.', + '', + '## Mechanism', + 'sizable() chooses between small/medium/large values using:', + '- --component-size (resolved from --ig-size)', + '- --ig-size-small/medium/large', + '- --is-small/medium/large from @include sizable()', + '', + '## Sass example', + '```scss', + '.my-avatar {', + ' width: sizable(32px, 40px, 48px);', + ' height: sizable(32px, 40px, 48px);', + '}', + '```', + '', + '## CSS example', + '```css', + ':root {', + ' --ig-size: 2;', + '}', + '```', + '', + '## Notes', + '- Requires @include sizable() in component styles.', +].join('\n'); + +export const BORDER_RADIUS_FUNCTION_DOC = [ + '# border-radius() function', + '', + 'Clamps a radius value between min and max using --ig-radius-factor (0 to 1).', + '', + '## Mechanism', + 'border-radius() calculates:', + 'clamp(min, calc(var(--ig-radius-factor) * max), max)', + '', + '## Sass example', + '```scss', + '.my-pill {', + ' border-radius: border-radius(16px, 4px, 20px);', + '}', + '```', + '', + '## CSS example', + '```css', + '.my-pill {', + ' --ig-radius-factor: 0.8;', + '}', + '```', + '', + '## Notes', + '- Works without additional mixins.', +].join('\n'); + +export const SPACING_MIXIN_DOC = [ + '# spacing() mixin', + '', + 'Defines spacing custom properties used by pad(), pad-inline(), and pad-block().', + '', + '## Sass example', + '```scss', + '@include spacing();', + '```', + '', + '## CSS example', + '```css', + ':root {', + ' --ig-spacing: 1;', + ' --ig-spacing-inline: 0.75;', + ' --ig-spacing-block: 0.5;', + '}', + '```', + '', + '## Notes', + '- spacing() is typically included once at the root scope.', +].join('\n'); + +export const SIZING_MIXIN_DOC = [ + '# sizing() mixin', + '', + 'Defines @property rules for size levels:', + '- --ig-size-small', + '- --ig-size-medium', + '- --ig-size-large', + '', + '## Sass example', + '```scss', + '@include sizing();', + '```', + '', + '## Notes', + '- Typically included once at the root scope.', +].join('\n'); + +export const SIZABLE_MIXIN_DOC = [ + '# sizable() mixin', + '', + 'Defines size state flags used by sizable() and pad():', + '- --is-small', + '- --is-medium', + '- --is-large', + '', + '## Sass example', + '```scss', + '.my-component {', + ' @include sizable();', + '}', + '```', + '', + '## Notes', + '- Required for components to react to --ig-size changes.', +].join('\n'); diff --git a/src/mcp/knowledge/sass-api.ts b/src/mcp/knowledge/sass-api.ts index 64e89a51..8768a46a 100644 --- a/src/mcp/knowledge/sass-api.ts +++ b/src/mcp/knowledge/sass-api.ts @@ -340,10 +340,19 @@ export const CSS_VARIABLE_PATTERNS = { themeVariant: '--ig-theme-variant', /** Component size levels */ sizes: { + base: '--ig-size', small: '--ig-size-small', medium: '--ig-size-medium', large: '--ig-size-large', }, + /** Spacing controls */ + spacing: { + base: '--ig-spacing', + inline: '--ig-spacing-inline', + block: '--ig-spacing-block', + }, + /** Roundness scaling */ + roundness: '--ig-radius-factor', /** Scrollbar customization */ scrollbar: { size: '--ig-scrollbar-size', diff --git a/src/mcp/resources/presets.ts b/src/mcp/resources/presets.ts index 2fb6bf9a..fe7d4bf3 100644 --- a/src/mcp/resources/presets.ts +++ b/src/mcp/resources/presets.ts @@ -27,6 +27,13 @@ import { TYPE_SCALE_PRESETS, ELEVATIONS_PRESETS, SCHEMA_PRESETS, + LAYOUT_OVERVIEW_DOC, + PAD_FUNCTION_DOC, + SIZABLE_FUNCTION_DOC, + BORDER_RADIUS_FUNCTION_DOC, + SPACING_MIXIN_DOC, + SIZING_MIXIN_DOC, + SIZABLE_MIXIN_DOC, REACT_PLATFORM, REACT_USAGE_EXAMPLES, BLAZOR_PLATFORM, @@ -61,6 +68,14 @@ export const RESOURCE_URIS = { GUIDANCE_COLORS_ROLES: `${RESOURCE_SCHEME}://guidance/colors/roles`, GUIDANCE_COLORS_STATES: `${RESOURCE_SCHEME}://guidance/colors/states`, GUIDANCE_COLORS_THEMES: `${RESOURCE_SCHEME}://guidance/colors/themes`, + // Layout documentation resources + DOCS_LAYOUT_OVERVIEW: `${RESOURCE_SCHEME}://docs/spacing-and-sizing`, + DOCS_FUNCTION_PAD: `${RESOURCE_SCHEME}://docs/functions/pad`, + DOCS_FUNCTION_SIZABLE: `${RESOURCE_SCHEME}://docs/functions/sizable`, + DOCS_FUNCTION_BORDER_RADIUS: `${RESOURCE_SCHEME}://docs/functions/border-radius`, + DOCS_MIXIN_SPACING: `${RESOURCE_SCHEME}://docs/mixins/spacing`, + DOCS_MIXIN_SIZING: `${RESOURCE_SCHEME}://docs/mixins/sizing`, + DOCS_MIXIN_SIZABLE: `${RESOURCE_SCHEME}://docs/mixins/sizable`, } as const; /** @@ -168,10 +183,52 @@ export const RESOURCE_DEFINITIONS = [ { uri: RESOURCE_URIS.GUIDANCE_COLORS_THEMES, name: 'Design System Patterns', - description: - 'Color usage characteristics specific to Material, Fluent, Bootstrap, and Indigo design systems.', + description: 'Color usage characteristics specific to Material, Fluent, Bootstrap, and Indigo design systems.', mimeType: 'application/json', }, + // Layout documentation resources + { + uri: RESOURCE_URIS.DOCS_LAYOUT_OVERVIEW, + name: 'Layout Scale Overview', + description: 'Overview of size, spacing, and roundness variables with examples for CSS and Sass.', + mimeType: 'text/markdown', + }, + { + uri: RESOURCE_URIS.DOCS_FUNCTION_PAD, + name: 'pad() Function', + description: 'Documentation for the pad() spacing function and its usage.', + mimeType: 'text/markdown', + }, + { + uri: RESOURCE_URIS.DOCS_FUNCTION_SIZABLE, + name: 'sizable() Function', + description: 'Documentation for the sizable() function and size-based values.', + mimeType: 'text/markdown', + }, + { + uri: RESOURCE_URIS.DOCS_FUNCTION_BORDER_RADIUS, + name: 'border-radius() Function', + description: 'Documentation for the border-radius() function and roundness scaling.', + mimeType: 'text/markdown', + }, + { + uri: RESOURCE_URIS.DOCS_MIXIN_SPACING, + name: 'spacing() Mixin', + description: 'Documentation for the spacing() mixin and spacing variables.', + mimeType: 'text/markdown', + }, + { + uri: RESOURCE_URIS.DOCS_MIXIN_SIZING, + name: 'sizing() Mixin', + description: 'Documentation for the sizing() mixin and size custom properties.', + mimeType: 'text/markdown', + }, + { + uri: RESOURCE_URIS.DOCS_MIXIN_SIZABLE, + name: 'sizable() Mixin', + description: 'Documentation for the sizable() mixin and size flags.', + mimeType: 'text/markdown', + }, ]; // ============================================================================ @@ -406,6 +463,56 @@ const RESOURCE_HANDLERS: Map = new Map([ mimeType: 'application/json', }), ], + // Layout documentation resources + [ + RESOURCE_URIS.DOCS_LAYOUT_OVERVIEW, + () => ({ + content: LAYOUT_OVERVIEW_DOC, + mimeType: 'text/markdown', + }), + ], + [ + RESOURCE_URIS.DOCS_FUNCTION_PAD, + () => ({ + content: PAD_FUNCTION_DOC, + mimeType: 'text/markdown', + }), + ], + [ + RESOURCE_URIS.DOCS_FUNCTION_SIZABLE, + () => ({ + content: SIZABLE_FUNCTION_DOC, + mimeType: 'text/markdown', + }), + ], + [ + RESOURCE_URIS.DOCS_FUNCTION_BORDER_RADIUS, + () => ({ + content: BORDER_RADIUS_FUNCTION_DOC, + mimeType: 'text/markdown', + }), + ], + [ + RESOURCE_URIS.DOCS_MIXIN_SPACING, + () => ({ + content: SPACING_MIXIN_DOC, + mimeType: 'text/markdown', + }), + ], + [ + RESOURCE_URIS.DOCS_MIXIN_SIZING, + () => ({ + content: SIZING_MIXIN_DOC, + mimeType: 'text/markdown', + }), + ], + [ + RESOURCE_URIS.DOCS_MIXIN_SIZABLE, + () => ({ + content: SIZABLE_MIXIN_DOC, + mimeType: 'text/markdown', + }), + ], ]); /** diff --git a/src/mcp/tools/descriptions.ts b/src/mcp/tools/descriptions.ts index 9b8528ab..956771b1 100644 --- a/src/mcp/tools/descriptions.ts +++ b/src/mcp/tools/descriptions.ts @@ -559,7 +559,7 @@ export const TOOL_DESCRIPTIONS = { - create_elevations: Use if you only need elevation shadows - + - theming://presets/palettes: View available preset palette colors - theming://guidance/colors: Color guidance overview - theming://guidance/colors/rules: Light/dark theme color rules @@ -567,6 +567,129 @@ export const TOOL_DESCRIPTIONS = { - theming://platforms/webcomponents: Web Components platform configuration - theming://platforms/react: React platform configuration - theming://platforms/blazor: Blazor platform configuration + `, + + // --------------------------------------------------------------------------- + // set_size - Layout tool + // --------------------------------------------------------------------------- + set_size: `Set global or component-specific sizing by updating --ig-size. + + + Use this tool for requests like: + - "Make the calendar smaller" + - "The buttons feel too big" + - "Use the small size everywhere" + + + + - Sets --ig-size in the chosen scope (defaults to :root) + - Accepts "small", "medium", "large" (mapped to 1, 2, 3) or numeric values + + + + - Components map --ig-size to --component-size internally + - Styles using sizable() require @include sizable() in component styles + + + + Make flat buttons medium: + { + "component": "flat-button", + "size": "medium" + } + + Make everything small globally: + { + "size": "small" + } + + + + - theming://docs/spacing-and-sizing + - theming://docs/functions/sizable + - theming://docs/mixins/sizable +`, + + // --------------------------------------------------------------------------- + // set_spacing - Layout tool + // --------------------------------------------------------------------------- + set_spacing: `Set global or component-specific spacing by updating --ig-spacing. + + + Use this tool for requests like: + - "The button feels bloated" + - "Tighten the spacing on the form" + - "Double the padding on cards" + + + + - Sets --ig-spacing in the chosen scope (defaults to :root) + - Optional overrides for --ig-spacing-inline and --ig-spacing-block + - 0 = no spacing, 1 = default, 2 = double (fractions allowed) + - spacing is required; inline/block are optional overrides + + + + - pad(), pad-inline(), pad-block() require @include spacing() once + + + + Reduce calendar spacing: + { + "component": "calendar", + "spacing": 0.75 + } + + Override inline spacing: + { + "scope": ".compact", + "inline": 0.5, + "block": 0.75 + } + + + + - theming://docs/spacing-and-sizing + - theming://docs/functions/pad + - theming://docs/mixins/spacing +`, + + // --------------------------------------------------------------------------- + // set_roundness - Layout tool + // --------------------------------------------------------------------------- + set_roundness: `Set global or component-specific roundness by updating --ig-radius-factor. + + + Use this tool for requests like: + - "Make the flat buttons more round" + - "Square off the cards" + + + + - Sets --ig-radius-factor in the chosen scope (defaults to :root) + - 0 = minimum radius, 1 = maximum radius, values between interpolate + + + + - border-radius() responds to --ig-radius-factor without extra mixins + + + + Round avatars more: + { + "component": "avatar", + "radiusFactor": 0.9 + } + + Globally reduce roundness: + { + "radiusFactor": 0.8 + } + + + + - theming://docs/spacing-and-sizing + - theming://docs/functions/border-radius `, // --------------------------------------------------------------------------- @@ -838,7 +961,7 @@ export const PARAM_DESCRIPTIONS = { variant: FRAGMENTS.VARIANT, designSystem: FRAGMENTS.DESIGN_SYSTEM, name: `Custom variable name (without $ prefix). If omitted, auto-generates based on tool and variant (e.g., "custom-light", "my-theme").`, - output: `Output format: "sass" generates Sass code using igniteui-theming library functions. "css" generates CSS custom properties (variables) directly - useful for vanilla CSS projects or when you don't want Sass compilation. Defaults to "sass".`, + output: `Output format: "sass" generates Sass code using igniteui-theming library functions. "css" generates CSS custom properties (variables) directly - useful for vanilla CSS projects or when you don't want Sass compilation. Defaults to tool-specific output ("sass" for theme generators, "css" for layout setters).`, // --------------------------------------------------------------------------- // detect_platform parameters @@ -912,6 +1035,17 @@ Important: Gray progression is INVERTED for dark themes (50=darkest, 900=lightes themeName: `Optional name for the generated theme variable (without $ prefix). If omitted, auto-generates based on component name (e.g., "$custom-button-theme").`, + // --------------------------------------------------------------------------- + // Layout tool parameters + // --------------------------------------------------------------------------- + layoutComponent: `Optional component name to scope the layout change (e.g., "flat-button", "calendar", "avatar"). If omitted, the change applies globally via :root.`, + scope: `Optional CSS selector scope for the change (e.g., ".my-theme", ":root", "#app"). Ignored when component is provided.`, + sizeValue: `Size value to set for --ig-size. Accepts "small" (1), "medium" (2), "large" (3), or numeric 1, 2, 3 only.`, + spacing: `Spacing scale multiplier for --ig-spacing. 0 = none, 1 = default, 2 = double. Fractions allowed.`, + spacingInline: `Inline spacing scale multiplier for --ig-spacing-inline. Overrides inline spacing only.`, + spacingBlock: `Block spacing scale multiplier for --ig-spacing-block. Overrides block spacing only.`, + radiusFactor: `Roundness scale factor for --ig-radius-factor. 0 = minimum radius, 1 = maximum radius. Values must be between 0 and 1.`, + // --------------------------------------------------------------------------- // Color operations parameters (for get_color) // --------------------------------------------------------------------------- diff --git a/src/mcp/tools/handlers/index.ts b/src/mcp/tools/handlers/index.ts index d21fe1d4..6e987d57 100644 --- a/src/mcp/tools/handlers/index.ts +++ b/src/mcp/tools/handlers/index.ts @@ -11,3 +11,4 @@ export {handleCreateTheme} from './theme.js'; export {handleGetComponentDesignTokens} from './component-tokens.js'; export {handleCreateComponentTheme} from './component-theme.js'; export {handleGetColor} from './color.js'; +export {handleSetSize, handleSetSpacing, handleSetRoundness} from './layout.js'; diff --git a/src/mcp/tools/handlers/layout.ts b/src/mcp/tools/handlers/layout.ts new file mode 100644 index 00000000..163e2775 --- /dev/null +++ b/src/mcp/tools/handlers/layout.ts @@ -0,0 +1,240 @@ +/** + * Handlers for layout scale tools: set_size, set_spacing, set_roundness. + */ + +import {COMPONENT_SELECTORS, getComponentPlatformAvailability, getComponentSelector} from '../../knowledge/index.js'; +import type {Platform} from '../../utils/types.js'; +import type {SetRoundnessParams, SetSizeParams, SetSpacingParams} from '../schemas.js'; + +const SIZE_KEYWORDS: Record = { + small: 1, + medium: 2, + large: 3, +}; + +interface ScopeResolution { + selectors: string[]; + notes: string[]; + scopeLabel: string; +} + +interface ScopeError { + error: string; +} + +function normalizeComponentName(component?: string): string | null { + return component ? component.toLowerCase().trim() : null; +} + +function buildSelectorList(value: string | string[]): string[] { + return Array.isArray(value) ? value : [value]; +} + +function resolveScope( + component: string | undefined, + scope: string | undefined, + platform: Platform | undefined, +): ScopeResolution | ScopeError { + const notes: string[] = []; + + if (component) { + const normalized = normalizeComponentName(component); + + if (!normalized || !COMPONENT_SELECTORS[normalized]) { + const available = Object.keys(COMPONENT_SELECTORS); + const suggestions = normalized ? available.filter((name) => name.includes(normalized)).slice(0, 10) : []; + const list = suggestions.length > 0 ? suggestions : available.slice(0, 15); + + return { + error: `**Error:** Component "${component}" not found. + +${suggestions.length > 0 ? '**Similar components:**' : '**Available components:**'} +${list.map((name) => `- ${name}`).join('\n')}`, + }; + } + + if (scope) { + notes.push('Scope ignored because component was provided.'); + } + + const selectorsEntry = COMPONENT_SELECTORS[normalized]; + let selectors: string[] = []; + + if (platform) { + selectors = getComponentSelector(normalized, platform); + + if (selectors.length === 0) { + const availability = getComponentPlatformAvailability(normalized); + const availablePlatforms: string[] = []; + + if (availability?.angular) availablePlatforms.push('angular'); + if (availability?.webcomponents) availablePlatforms.push('webcomponents'); + + return { + error: `**Error:** Component "${component}" is not available on platform "${platform}". +${availablePlatforms.length > 0 ? `Available platforms: ${availablePlatforms.join(', ')}.` : ''}`, + }; + } + } else { + if (selectorsEntry.angular) { + selectors = selectors.concat(buildSelectorList(selectorsEntry.angular)); + } + + if (selectorsEntry.webcomponents) { + selectors = selectors.concat(buildSelectorList(selectorsEntry.webcomponents)); + } + + if (selectorsEntry.angular && selectorsEntry.webcomponents) { + notes.push('Platform not specified; output includes Angular and Web Components selectors.'); + } + } + + return { + selectors: Array.from(new Set(selectors)), + notes, + scopeLabel: `component "${normalized}"`, + }; + } + + if (scope) { + return { + selectors: [scope], + notes, + scopeLabel: `scope "${scope}"`, + }; + } + + return { + selectors: [':root'], + notes, + scopeLabel: 'global scope (:root)', + }; +} + +function formatSelectorBlock(selectors: string[], declarations: string[]): string { + const selectorLine = selectors.join(',\n'); + const lines = [selectorLine, '{', ...declarations.map((line) => ` ${line}`), '}']; + + return lines.join('\n'); +} + +function buildResponse( + description: string, + output: 'css' | 'sass', + code: string, + notes: string[], + guidance: string[], +): {content: {type: 'text'; text: string}[]} { + const responseParts: string[] = [description]; + + if (notes.length > 0) { + responseParts.push('', ...notes); + } + + if (guidance.length > 0) { + responseParts.push('', ...guidance); + } + + responseParts.push(''); + responseParts.push(output === 'sass' ? '```scss' : '```css'); + responseParts.push(code); + responseParts.push('```'); + + return { + content: [ + { + type: 'text' as const, + text: responseParts.join('\n'), + }, + ], + }; +} + +function coerceSizeValue(size: string | number): {display: string; value: number} { + if (typeof size === 'number') { + return {display: String(size), value: size}; + } + + const normalized = size.toLowerCase(); + const value = SIZE_KEYWORDS[normalized]; + + return {display: `${size} (${value})`, value}; +} + +export async function handleSetSize(params: SetSizeParams) { + const {component, scope, platform, size, output = 'css'} = params; + const resolution = resolveScope(component, scope, platform); + + if ('error' in resolution) { + return { + content: [{type: 'text' as const, text: resolution.error}], + isError: true, + }; + } + + const {selectors, notes, scopeLabel} = resolution; + const {display, value} = coerceSizeValue(size); + + const declarations: string[] = [`--ig-size: ${value};`]; + const code = formatSelectorBlock(selectors, declarations); + const description = `Set size to ${display} in ${scopeLabel}.`; + + const guidance = + output === 'sass' + ? [ + 'Sass note: sizable() requires @include sizable() in component styles.', + 'Components map --ig-size to --component-size internally.', + ] + : []; + + return buildResponse(description, output, code, notes, guidance); +} + +export async function handleSetSpacing(params: SetSpacingParams) { + const {component, scope, platform, spacing, inline, block, output = 'css'} = params; + const resolution = resolveScope(component, scope, platform); + + if ('error' in resolution) { + return { + content: [{type: 'text' as const, text: resolution.error}], + isError: true, + }; + } + + const {selectors, notes, scopeLabel} = resolution; + const declarations: string[] = []; + + if (spacing !== undefined) declarations.push(`--ig-spacing: ${spacing};`); + if (inline !== undefined) declarations.push(`--ig-spacing-inline: ${inline};`); + if (block !== undefined) declarations.push(`--ig-spacing-block: ${block};`); + + const code = formatSelectorBlock(selectors, declarations); + const description = `Set spacing in ${scopeLabel}.`; + const guidance = + output === 'sass' ? ['Sass note: pad() functions require @include spacing() once at root scope.'] : []; + + return buildResponse(description, output, code, notes, guidance); +} + +export async function handleSetRoundness(params: SetRoundnessParams) { + const {component, scope, platform, radiusFactor, output = 'css'} = params; + const resolution = resolveScope(component, scope, platform); + + if ('error' in resolution) { + return { + content: [{type: 'text' as const, text: resolution.error}], + isError: true, + }; + } + + const {selectors, notes, scopeLabel} = resolution; + + const declarations = [`--ig-radius-factor: ${radiusFactor};`]; + const code = formatSelectorBlock(selectors, declarations); + const description = `Set roundness factor to ${radiusFactor} in ${scopeLabel}.`; + + const guidance = + output === 'sass' ? ['Sass note: border-radius() responds to --ig-radius-factor without extra mixins.'] : []; + + return buildResponse(description, output, code, notes, guidance); +} diff --git a/src/mcp/tools/index.ts b/src/mcp/tools/index.ts index 698fbaee..79f51c7d 100644 --- a/src/mcp/tools/index.ts +++ b/src/mcp/tools/index.ts @@ -12,6 +12,10 @@ export { getComponentDesignTokensSchema, createComponentThemeSchema, getColorSchema, + setSizeSchema, + setSpacingSchema, + setSpacingInputSchema, + setRoundnessSchema, platformSchema, type DetectPlatformParams, type CreatePaletteParams, @@ -22,6 +26,9 @@ export { type GetComponentDesignTokensParams, type CreateComponentThemeParams, type GetColorParams, + type SetSizeParams, + type SetSpacingParams, + type SetRoundnessParams, type Platform, } from './schemas.js'; @@ -35,4 +42,7 @@ export { handleGetComponentDesignTokens, handleCreateComponentTheme, handleGetColor, + handleSetSize, + handleSetSpacing, + handleSetRoundness, } from './handlers/index.js'; diff --git a/src/mcp/tools/schemas.ts b/src/mcp/tools/schemas.ts index 6a79d439..ff85d90f 100644 --- a/src/mcp/tools/schemas.ts +++ b/src/mcp/tools/schemas.ts @@ -79,6 +79,11 @@ export const elevationPresetSchema = z.enum(ELEVATION_PRESETS).optional(); */ export const outputFormatSchema = z.enum(OUTPUT_FORMATS).optional(); +/** + * Size keyword schema for layout tools. + */ +export const sizeKeywordSchema = z.enum(['small', 'medium', 'large']); + /** * Platform schema - derived from PLATFORMS constant. */ @@ -338,3 +343,43 @@ export const getColorSchema = getColorBaseSchema.refine( ); export type GetColorParams = z.infer; + +// ============================================================================ +// Layout Tools Schemas +// ============================================================================ + +const sizeValueSchema = z + .union([sizeKeywordSchema, z.number().int().min(1).max(3)]) + .describe(PARAM_DESCRIPTIONS.sizeValue); + +export const setSizeSchema = z.object({ + platform: platformSchema, + component: z.string().optional().describe(PARAM_DESCRIPTIONS.layoutComponent), + scope: z.string().optional().describe(PARAM_DESCRIPTIONS.scope), + size: sizeValueSchema, + output: outputFormatSchema.describe(PARAM_DESCRIPTIONS.output), +}); + +export const setSpacingInputSchema = z.object({ + platform: platformSchema, + component: z.string().optional().describe(PARAM_DESCRIPTIONS.layoutComponent), + scope: z.string().optional().describe(PARAM_DESCRIPTIONS.scope), + spacing: z.number().min(0).describe(PARAM_DESCRIPTIONS.spacing), + inline: z.number().min(0).optional().describe(PARAM_DESCRIPTIONS.spacingInline), + block: z.number().min(0).optional().describe(PARAM_DESCRIPTIONS.spacingBlock), + output: outputFormatSchema.describe(PARAM_DESCRIPTIONS.output), +}); + +export const setSpacingSchema = setSpacingInputSchema; + +export const setRoundnessSchema = z.object({ + platform: platformSchema, + component: z.string().optional().describe(PARAM_DESCRIPTIONS.layoutComponent), + scope: z.string().optional().describe(PARAM_DESCRIPTIONS.scope), + radiusFactor: z.number().min(0).max(1).describe(PARAM_DESCRIPTIONS.radiusFactor), + output: outputFormatSchema.describe(PARAM_DESCRIPTIONS.output), +}); + +export type SetSizeParams = z.infer; +export type SetSpacingParams = z.infer; +export type SetRoundnessParams = z.infer; From 223a0eb56dca24398077e74a310a371dc7ee1c0a Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Wed, 28 Jan 2026 12:15:13 +0200 Subject: [PATCH 10/38] fix(mpc): wrong banner and combo checkbox selectors --- src/mcp/knowledge/component-selectors.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mcp/knowledge/component-selectors.ts b/src/mcp/knowledge/component-selectors.ts index 7942f564..b18c1546 100644 --- a/src/mcp/knowledge/component-selectors.ts +++ b/src/mcp/knowledge/component-selectors.ts @@ -71,7 +71,7 @@ export const COMPONENT_SELECTORS: Record = { webcomponents: 'igc-badge', }, banner: { - angular: 'igx-banner', + angular: '.igx-banner', webcomponents: 'igc-banner', }, 'bottom-nav': { @@ -347,8 +347,8 @@ export const COMPOUND_COMPONENTS: Record = { }, webcomponents: { 'input-group': 'igc-combo::part(input)', - 'drop-down': 'igc-combo::part(list)', - checkbox: 'igc-combo-item::part(checkbox)', + 'drop-down': 'igc-combo::part(list-wrapper)', + checkbox: 'igc-combo::part(checkbox)', }, }, }, From 0b262ea99774a5cb5f9c168970f6407a6dc8d336 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Wed, 28 Jan 2026 13:38:05 +0200 Subject: [PATCH 11/38] tests(mcp): add missing tests --- src/mcp/__tests__/resources/resources.test.ts | 53 +++++++++++++++++++ .../__tests__/tools/handlers/color.test.ts | 29 ++++++++++ 2 files changed, 82 insertions(+) create mode 100644 src/mcp/__tests__/resources/resources.test.ts create mode 100644 src/mcp/__tests__/tools/handlers/color.test.ts diff --git a/src/mcp/__tests__/resources/resources.test.ts b/src/mcp/__tests__/resources/resources.test.ts new file mode 100644 index 00000000..1f824a22 --- /dev/null +++ b/src/mcp/__tests__/resources/resources.test.ts @@ -0,0 +1,53 @@ +import {describe, it, expect} from 'vitest'; +import {RESOURCE_URIS, getResourceContent} from '../../resources/index.js'; + +describe('resource handlers', () => { + it('returns platform listing resource', () => { + const result = getResourceContent(RESOURCE_URIS.PLATFORMS); + + expect(result).not.toBeNull(); + expect(result?.mimeType).toBe('application/json'); + + const payload = JSON.parse(result?.content ?? '{}'); + expect(payload.platforms).toContain('angular'); + expect(payload.platforms).toContain('webcomponents'); + }); + + it('returns angular platform resource', () => { + const result = getResourceContent(RESOURCE_URIS.PLATFORM_ANGULAR); + + expect(result).not.toBeNull(); + expect(result?.mimeType).toBe('application/json'); + + const payload = JSON.parse(result?.content ?? '{}'); + expect(payload.platform?.id ?? payload.platform?.name ?? payload.platform).toBeTruthy(); + expect(payload.schemas).toBeDefined(); + expect(payload.palettes).toBeDefined(); + }); + + it('returns palette presets resource', () => { + const result = getResourceContent(RESOURCE_URIS.PALETTES); + + expect(result).not.toBeNull(); + expect(result?.mimeType).toBe('application/json'); + + const payload = JSON.parse(result?.content ?? '{}'); + expect(Object.keys(payload).length).toBeGreaterThan(0); + }); + + it('returns color guidance markdown resource', () => { + const result = getResourceContent(RESOURCE_URIS.GUIDANCE_COLORS_RULES); + + expect(result).not.toBeNull(); + expect(result?.mimeType).toBe('text/markdown'); + expect(result?.content.length).toBeGreaterThan(0); + }); + + it('returns layout documentation resource', () => { + const result = getResourceContent(RESOURCE_URIS.DOCS_LAYOUT_OVERVIEW); + + expect(result).not.toBeNull(); + expect(result?.mimeType).toBe('text/markdown'); + expect(result?.content.length).toBeGreaterThan(0); + }); +}); diff --git a/src/mcp/__tests__/tools/handlers/color.test.ts b/src/mcp/__tests__/tools/handlers/color.test.ts new file mode 100644 index 00000000..57446ff0 --- /dev/null +++ b/src/mcp/__tests__/tools/handlers/color.test.ts @@ -0,0 +1,29 @@ +import {describe, it, expect} from 'vitest'; +import {handleGetColor} from '../../../tools/handlers/color.js'; + +describe('handleGetColor', () => { + it('returns a CSS variable reference by default', async () => { + const result = await handleGetColor({color: 'primary'}); + const text = result.content[0].text; + + expect(text).toContain('```css'); + expect(text).toContain('var(--ig-primary-500)'); + expect(text).toContain('Primary color, shade 500'); + }); + + it('returns contrast color when requested', async () => { + const result = await handleGetColor({color: 'primary', contrast: true}); + const text = result.content[0].text; + + expect(text).toContain('Contrast color for primary 500'); + expect(text).toContain('var(--ig-primary-500-contrast)'); + }); + + it('applies opacity using relative color syntax', async () => { + const result = await handleGetColor({color: 'primary', opacity: 0.5}); + const text = result.content[0].text; + + expect(text).toContain('50% opacity'); + expect(text).toContain('hsl(from var(--ig-primary-500) h s l / 0.5)'); + }); +}); From 98d1f9613c18969884313a36cf4fb6591c0a0fe1 Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Wed, 28 Jan 2026 13:48:56 +0200 Subject: [PATCH 12/38] feat(openspec): initialize artifact-driven workflow and mcp specifications --- .claude/commands/opsx/apply.md | 152 +++++ .claude/commands/opsx/archive.md | 157 ++++++ .claude/commands/opsx/bulk-archive.md | 242 ++++++++ .claude/commands/opsx/continue.md | 114 ++++ .claude/commands/opsx/explore.md | 174 ++++++ .claude/commands/opsx/ff.md | 94 ++++ .claude/commands/opsx/new.md | 69 +++ .claude/commands/opsx/onboard.md | 525 +++++++++++++++++ .claude/commands/opsx/sync.md | 134 +++++ .claude/commands/opsx/verify.md | 164 ++++++ .claude/skills/openspec-apply-change/SKILL.md | 156 ++++++ .../skills/openspec-archive-change/SKILL.md | 114 ++++ .../openspec-bulk-archive-change/SKILL.md | 246 ++++++++ .../skills/openspec-continue-change/SKILL.md | 118 ++++ .claude/skills/openspec-explore/SKILL.md | 290 ++++++++++ .claude/skills/openspec-ff-change/SKILL.md | 101 ++++ .claude/skills/openspec-new-change/SKILL.md | 74 +++ .claude/skills/openspec-onboard/SKILL.md | 529 ++++++++++++++++++ .claude/skills/openspec-sync-specs/SKILL.md | 138 +++++ .../skills/openspec-verify-change/SKILL.md | 168 ++++++ .crush/commands/opsx/apply.md | 152 +++++ .crush/commands/opsx/archive.md | 157 ++++++ .crush/commands/opsx/bulk-archive.md | 242 ++++++++ .crush/commands/opsx/continue.md | 114 ++++ .crush/commands/opsx/explore.md | 174 ++++++ .crush/commands/opsx/ff.md | 94 ++++ .crush/commands/opsx/new.md | 69 +++ .crush/commands/opsx/onboard.md | 525 +++++++++++++++++ .crush/commands/opsx/sync.md | 134 +++++ .crush/commands/opsx/verify.md | 164 ++++++ .crush/skills/openspec-apply-change/SKILL.md | 156 ++++++ .../skills/openspec-archive-change/SKILL.md | 114 ++++ .../openspec-bulk-archive-change/SKILL.md | 246 ++++++++ .../skills/openspec-continue-change/SKILL.md | 118 ++++ .crush/skills/openspec-explore/SKILL.md | 290 ++++++++++ .crush/skills/openspec-ff-change/SKILL.md | 101 ++++ .crush/skills/openspec-new-change/SKILL.md | 74 +++ .crush/skills/openspec-onboard/SKILL.md | 529 ++++++++++++++++++ .crush/skills/openspec-sync-specs/SKILL.md | 138 +++++ .crush/skills/openspec-verify-change/SKILL.md | 168 ++++++ .github/prompts/opsx-apply.prompt.md | 149 +++++ .github/prompts/opsx-archive.prompt.md | 154 +++++ .github/prompts/opsx-bulk-archive.prompt.md | 239 ++++++++ .github/prompts/opsx-continue.prompt.md | 111 ++++ .github/prompts/opsx-explore.prompt.md | 171 ++++++ .github/prompts/opsx-ff.prompt.md | 91 +++ .github/prompts/opsx-new.prompt.md | 66 +++ .github/prompts/opsx-onboard.prompt.md | 522 +++++++++++++++++ .github/prompts/opsx-sync.prompt.md | 131 +++++ .github/prompts/opsx-verify.prompt.md | 161 ++++++ .github/skills/openspec-apply-change/SKILL.md | 156 ++++++ .../skills/openspec-archive-change/SKILL.md | 114 ++++ .../openspec-bulk-archive-change/SKILL.md | 246 ++++++++ .../skills/openspec-continue-change/SKILL.md | 118 ++++ .github/skills/openspec-explore/SKILL.md | 290 ++++++++++ .github/skills/openspec-ff-change/SKILL.md | 101 ++++ .github/skills/openspec-new-change/SKILL.md | 74 +++ .github/skills/openspec-onboard/SKILL.md | 529 ++++++++++++++++++ .github/skills/openspec-sync-specs/SKILL.md | 138 +++++ .../skills/openspec-verify-change/SKILL.md | 168 ++++++ .opencode/command/opsx-apply.md | 149 +++++ .opencode/command/opsx-archive.md | 154 +++++ .opencode/command/opsx-bulk-archive.md | 239 ++++++++ .opencode/command/opsx-continue.md | 111 ++++ .opencode/command/opsx-explore.md | 171 ++++++ .opencode/command/opsx-ff.md | 91 +++ .opencode/command/opsx-new.md | 66 +++ .opencode/command/opsx-onboard.md | 522 +++++++++++++++++ .opencode/command/opsx-sync.md | 131 +++++ .opencode/command/opsx-verify.md | 161 ++++++ .../skills/openspec-apply-change/SKILL.md | 156 ++++++ .../skills/openspec-archive-change/SKILL.md | 114 ++++ .../openspec-bulk-archive-change/SKILL.md | 246 ++++++++ .../skills/openspec-continue-change/SKILL.md | 118 ++++ .opencode/skills/openspec-explore/SKILL.md | 290 ++++++++++ .opencode/skills/openspec-ff-change/SKILL.md | 101 ++++ .opencode/skills/openspec-new-change/SKILL.md | 74 +++ .opencode/skills/openspec-onboard/SKILL.md | 529 ++++++++++++++++++ .opencode/skills/openspec-sync-specs/SKILL.md | 138 +++++ .../skills/openspec-verify-change/SKILL.md | 168 ++++++ .../.openspec.yaml | 2 + .../2026-01-28-mcp-mvp-retrofit/design.md | 38 ++ .../2026-01-28-mcp-mvp-retrofit/proposal.md | 33 ++ .../specs/color-reference/spec.md | 20 + .../specs/component-theming/spec.md | 55 ++ .../specs/css-output/spec.md | 24 + .../specs/custom-palette/spec.md | 30 + .../specs/elevations/spec.md | 15 + .../specs/layout-overrides/spec.md | 33 ++ .../specs/palette-generation/spec.md | 44 ++ .../specs/platform-detection/spec.md | 35 ++ .../specs/resources/spec.md | 46 ++ .../specs/theme-generation/spec.md | 55 ++ .../specs/typography/spec.md | 23 + .../2026-01-28-mcp-mvp-retrofit/tasks.md | 28 + .../mcp-color-intelligence/.openspec.yaml | 2 + .../changes/mcp-color-intelligence/design.md | 26 + .../mcp-color-intelligence/proposal.md | 26 + .../mcp-color-intelligence/specs/spec.md | 13 + .../changes/mcp-color-intelligence/tasks.md | 14 + .../mcp-prompt-resources/.openspec.yaml | 2 + .../changes/mcp-prompt-resources/design.md | 24 + .../changes/mcp-prompt-resources/proposal.md | 23 + .../mcp-prompt-resources/specs/spec.md | 5 + .../changes/mcp-prompt-resources/tasks.md | 15 + .../mcp-typography-utilities/.openspec.yaml | 2 + .../mcp-typography-utilities/design.md | 25 + .../mcp-typography-utilities/proposal.md | 25 + .../mcp-typography-utilities/specs/spec.md | 13 + .../changes/mcp-typography-utilities/tasks.md | 14 + .../.openspec.yaml | 2 + .../mcp-validation-intelligence/design.md | 24 + .../mcp-validation-intelligence/proposal.md | 24 + .../mcp-validation-intelligence/specs/spec.md | 9 + .../mcp-validation-intelligence/tasks.md | 13 + openspec/config.yaml | 13 + openspec/specs/color-reference/spec.md | 24 + openspec/specs/component-theming/spec.md | 59 ++ openspec/specs/css-output/spec.md | 28 + openspec/specs/custom-palette/spec.md | 34 ++ openspec/specs/elevations/spec.md | 19 + openspec/specs/layout-overrides/spec.md | 37 ++ openspec/specs/palette-generation/spec.md | 48 ++ openspec/specs/platform-detection/spec.md | 39 ++ openspec/specs/resources/spec.md | 50 ++ openspec/specs/theme-generation/spec.md | 59 ++ openspec/specs/typography/spec.md | 27 + 127 files changed, 16195 insertions(+) create mode 100644 .claude/commands/opsx/apply.md create mode 100644 .claude/commands/opsx/archive.md create mode 100644 .claude/commands/opsx/bulk-archive.md create mode 100644 .claude/commands/opsx/continue.md create mode 100644 .claude/commands/opsx/explore.md create mode 100644 .claude/commands/opsx/ff.md create mode 100644 .claude/commands/opsx/new.md create mode 100644 .claude/commands/opsx/onboard.md create mode 100644 .claude/commands/opsx/sync.md create mode 100644 .claude/commands/opsx/verify.md create mode 100644 .claude/skills/openspec-apply-change/SKILL.md create mode 100644 .claude/skills/openspec-archive-change/SKILL.md create mode 100644 .claude/skills/openspec-bulk-archive-change/SKILL.md create mode 100644 .claude/skills/openspec-continue-change/SKILL.md create mode 100644 .claude/skills/openspec-explore/SKILL.md create mode 100644 .claude/skills/openspec-ff-change/SKILL.md create mode 100644 .claude/skills/openspec-new-change/SKILL.md create mode 100644 .claude/skills/openspec-onboard/SKILL.md create mode 100644 .claude/skills/openspec-sync-specs/SKILL.md create mode 100644 .claude/skills/openspec-verify-change/SKILL.md create mode 100644 .crush/commands/opsx/apply.md create mode 100644 .crush/commands/opsx/archive.md create mode 100644 .crush/commands/opsx/bulk-archive.md create mode 100644 .crush/commands/opsx/continue.md create mode 100644 .crush/commands/opsx/explore.md create mode 100644 .crush/commands/opsx/ff.md create mode 100644 .crush/commands/opsx/new.md create mode 100644 .crush/commands/opsx/onboard.md create mode 100644 .crush/commands/opsx/sync.md create mode 100644 .crush/commands/opsx/verify.md create mode 100644 .crush/skills/openspec-apply-change/SKILL.md create mode 100644 .crush/skills/openspec-archive-change/SKILL.md create mode 100644 .crush/skills/openspec-bulk-archive-change/SKILL.md create mode 100644 .crush/skills/openspec-continue-change/SKILL.md create mode 100644 .crush/skills/openspec-explore/SKILL.md create mode 100644 .crush/skills/openspec-ff-change/SKILL.md create mode 100644 .crush/skills/openspec-new-change/SKILL.md create mode 100644 .crush/skills/openspec-onboard/SKILL.md create mode 100644 .crush/skills/openspec-sync-specs/SKILL.md create mode 100644 .crush/skills/openspec-verify-change/SKILL.md create mode 100644 .github/prompts/opsx-apply.prompt.md create mode 100644 .github/prompts/opsx-archive.prompt.md create mode 100644 .github/prompts/opsx-bulk-archive.prompt.md create mode 100644 .github/prompts/opsx-continue.prompt.md create mode 100644 .github/prompts/opsx-explore.prompt.md create mode 100644 .github/prompts/opsx-ff.prompt.md create mode 100644 .github/prompts/opsx-new.prompt.md create mode 100644 .github/prompts/opsx-onboard.prompt.md create mode 100644 .github/prompts/opsx-sync.prompt.md create mode 100644 .github/prompts/opsx-verify.prompt.md create mode 100644 .github/skills/openspec-apply-change/SKILL.md create mode 100644 .github/skills/openspec-archive-change/SKILL.md create mode 100644 .github/skills/openspec-bulk-archive-change/SKILL.md create mode 100644 .github/skills/openspec-continue-change/SKILL.md create mode 100644 .github/skills/openspec-explore/SKILL.md create mode 100644 .github/skills/openspec-ff-change/SKILL.md create mode 100644 .github/skills/openspec-new-change/SKILL.md create mode 100644 .github/skills/openspec-onboard/SKILL.md create mode 100644 .github/skills/openspec-sync-specs/SKILL.md create mode 100644 .github/skills/openspec-verify-change/SKILL.md create mode 100644 .opencode/command/opsx-apply.md create mode 100644 .opencode/command/opsx-archive.md create mode 100644 .opencode/command/opsx-bulk-archive.md create mode 100644 .opencode/command/opsx-continue.md create mode 100644 .opencode/command/opsx-explore.md create mode 100644 .opencode/command/opsx-ff.md create mode 100644 .opencode/command/opsx-new.md create mode 100644 .opencode/command/opsx-onboard.md create mode 100644 .opencode/command/opsx-sync.md create mode 100644 .opencode/command/opsx-verify.md create mode 100644 .opencode/skills/openspec-apply-change/SKILL.md create mode 100644 .opencode/skills/openspec-archive-change/SKILL.md create mode 100644 .opencode/skills/openspec-bulk-archive-change/SKILL.md create mode 100644 .opencode/skills/openspec-continue-change/SKILL.md create mode 100644 .opencode/skills/openspec-explore/SKILL.md create mode 100644 .opencode/skills/openspec-ff-change/SKILL.md create mode 100644 .opencode/skills/openspec-new-change/SKILL.md create mode 100644 .opencode/skills/openspec-onboard/SKILL.md create mode 100644 .opencode/skills/openspec-sync-specs/SKILL.md create mode 100644 .opencode/skills/openspec-verify-change/SKILL.md create mode 100644 openspec/changes/archive/2026-01-28-mcp-mvp-retrofit/.openspec.yaml create mode 100644 openspec/changes/archive/2026-01-28-mcp-mvp-retrofit/design.md create mode 100644 openspec/changes/archive/2026-01-28-mcp-mvp-retrofit/proposal.md create mode 100644 openspec/changes/archive/2026-01-28-mcp-mvp-retrofit/specs/color-reference/spec.md create mode 100644 openspec/changes/archive/2026-01-28-mcp-mvp-retrofit/specs/component-theming/spec.md create mode 100644 openspec/changes/archive/2026-01-28-mcp-mvp-retrofit/specs/css-output/spec.md create mode 100644 openspec/changes/archive/2026-01-28-mcp-mvp-retrofit/specs/custom-palette/spec.md create mode 100644 openspec/changes/archive/2026-01-28-mcp-mvp-retrofit/specs/elevations/spec.md create mode 100644 openspec/changes/archive/2026-01-28-mcp-mvp-retrofit/specs/layout-overrides/spec.md create mode 100644 openspec/changes/archive/2026-01-28-mcp-mvp-retrofit/specs/palette-generation/spec.md create mode 100644 openspec/changes/archive/2026-01-28-mcp-mvp-retrofit/specs/platform-detection/spec.md create mode 100644 openspec/changes/archive/2026-01-28-mcp-mvp-retrofit/specs/resources/spec.md create mode 100644 openspec/changes/archive/2026-01-28-mcp-mvp-retrofit/specs/theme-generation/spec.md create mode 100644 openspec/changes/archive/2026-01-28-mcp-mvp-retrofit/specs/typography/spec.md create mode 100644 openspec/changes/archive/2026-01-28-mcp-mvp-retrofit/tasks.md create mode 100644 openspec/changes/mcp-color-intelligence/.openspec.yaml create mode 100644 openspec/changes/mcp-color-intelligence/design.md create mode 100644 openspec/changes/mcp-color-intelligence/proposal.md create mode 100644 openspec/changes/mcp-color-intelligence/specs/spec.md create mode 100644 openspec/changes/mcp-color-intelligence/tasks.md create mode 100644 openspec/changes/mcp-prompt-resources/.openspec.yaml create mode 100644 openspec/changes/mcp-prompt-resources/design.md create mode 100644 openspec/changes/mcp-prompt-resources/proposal.md create mode 100644 openspec/changes/mcp-prompt-resources/specs/spec.md create mode 100644 openspec/changes/mcp-prompt-resources/tasks.md create mode 100644 openspec/changes/mcp-typography-utilities/.openspec.yaml create mode 100644 openspec/changes/mcp-typography-utilities/design.md create mode 100644 openspec/changes/mcp-typography-utilities/proposal.md create mode 100644 openspec/changes/mcp-typography-utilities/specs/spec.md create mode 100644 openspec/changes/mcp-typography-utilities/tasks.md create mode 100644 openspec/changes/mcp-validation-intelligence/.openspec.yaml create mode 100644 openspec/changes/mcp-validation-intelligence/design.md create mode 100644 openspec/changes/mcp-validation-intelligence/proposal.md create mode 100644 openspec/changes/mcp-validation-intelligence/specs/spec.md create mode 100644 openspec/changes/mcp-validation-intelligence/tasks.md create mode 100644 openspec/config.yaml create mode 100644 openspec/specs/color-reference/spec.md create mode 100644 openspec/specs/component-theming/spec.md create mode 100644 openspec/specs/css-output/spec.md create mode 100644 openspec/specs/custom-palette/spec.md create mode 100644 openspec/specs/elevations/spec.md create mode 100644 openspec/specs/layout-overrides/spec.md create mode 100644 openspec/specs/palette-generation/spec.md create mode 100644 openspec/specs/platform-detection/spec.md create mode 100644 openspec/specs/resources/spec.md create mode 100644 openspec/specs/theme-generation/spec.md create mode 100644 openspec/specs/typography/spec.md diff --git a/.claude/commands/opsx/apply.md b/.claude/commands/opsx/apply.md new file mode 100644 index 00000000..645bbdb8 --- /dev/null +++ b/.claude/commands/opsx/apply.md @@ -0,0 +1,152 @@ +--- +name: "OPSX: Apply" +description: Implement tasks from an OpenSpec change (Experimental) +category: Workflow +tags: [workflow, artifacts, experimental] +--- + +Implement tasks from an OpenSpec change. + +**Input**: Optionally specify a change name (e.g., `/opsx:apply add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes. + +**Steps** + +1. **Select the change** + + If a name is provided, use it. Otherwise: + - Infer from conversation context if the user mentioned a change + - Auto-select if only one active change exists + - If ambiguous, run `openspec list --json` to get available changes and use the **AskUserQuestion tool** to let the user select + + Always announce: "Using change: " and how to override (e.g., `/opsx:apply `). + +2. **Check status to understand the schema** + ```bash + openspec status --change "" --json + ``` + Parse the JSON to understand: + - `schemaName`: The workflow being used (e.g., "spec-driven") + - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others) + +3. **Get apply instructions** + + ```bash + openspec instructions apply --change "" --json + ``` + + This returns: + - Context file paths (varies by schema) + - Progress (total, complete, remaining) + - Task list with status + - Dynamic instruction based on current state + + **Handle states:** + - If `state: "blocked"` (missing artifacts): show message, suggest using `/opsx:continue` + - If `state: "all_done"`: congratulate, suggest archive + - Otherwise: proceed to implementation + +4. **Read context files** + + Read the files listed in `contextFiles` from the apply instructions output. + The files depend on the schema being used: + - **spec-driven**: proposal, specs, design, tasks + - Other schemas: follow the contextFiles from CLI output + +5. **Show current progress** + + Display: + - Schema being used + - Progress: "N/M tasks complete" + - Remaining tasks overview + - Dynamic instruction from CLI + +6. **Implement tasks (loop until done or blocked)** + + For each pending task: + - Show which task is being worked on + - Make the code changes required + - Keep changes minimal and focused + - Mark task complete in the tasks file: `- [ ]` → `- [x]` + - Continue to next task + + **Pause if:** + - Task is unclear → ask for clarification + - Implementation reveals a design issue → suggest updating artifacts + - Error or blocker encountered → report and wait for guidance + - User interrupts + +7. **On completion or pause, show status** + + Display: + - Tasks completed this session + - Overall progress: "N/M tasks complete" + - If all done: suggest archive + - If paused: explain why and wait for guidance + +**Output During Implementation** + +``` +## Implementing: (schema: ) + +Working on task 3/7: +[...implementation happening...] +✓ Task complete + +Working on task 4/7: +[...implementation happening...] +✓ Task complete +``` + +**Output On Completion** + +``` +## Implementation Complete + +**Change:** +**Schema:** +**Progress:** 7/7 tasks complete ✓ + +### Completed This Session +- [x] Task 1 +- [x] Task 2 +... + +All tasks complete! Ready to archive this change. +``` + +**Output On Pause (Issue Encountered)** + +``` +## Implementation Paused + +**Change:** +**Schema:** +**Progress:** 4/7 tasks complete + +### Issue Encountered + + +**Options:** +1.