diff --git a/package-lock.json b/package-lock.json index ad682899..3c4392e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@solvro/config", - "version": "2.3.4", + "version": "3.0.0-beta.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@solvro/config", - "version": "2.3.4", + "version": "3.0.0-beta.9", "license": "MPL-2.0", "dependencies": { "@adonisjs/eslint-config": "^3.1.0", @@ -20,20 +20,25 @@ "@tanstack/eslint-plugin-query": "^5.101.2", "@trivago/prettier-plugin-sort-imports": "^6.0.2", "@typescript-eslint/eslint-plugin": "^8.62.0", + "@vitest/eslint-plugin": "^1.6.18", "commander": "^15.0.0", "eslint-config-flat-gitignore": "^2.3.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-antfu": "^3.2.3", "eslint-plugin-import": "^2.32.0", + "eslint-plugin-jest": "^29.15.2", "eslint-plugin-jsdoc": "^63.0.10", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-n": "^18.2.1", + "eslint-plugin-playwright": "^2.10.4", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.3", "eslint-plugin-react-you-might-not-need-an-effect": "^1.0.1", + "eslint-plugin-regexp": "^3.1.0", "eslint-plugin-unicorn": "^64.0.0", "eslint-plugin-unused-imports": "^4.4.1", + "eslint-plugin-zod": "^4.5.1", "execa": "^9.6.1", "find-up-simple": "^1.0.1", "globals": "^17.7.0", @@ -53,6 +58,7 @@ "@commitlint/cli": "^21.1.0", "@commitlint/types": "^21.1.0", "@eslint/config-inspector": "^3.0.4", + "@nelsonlaidev/eslint-plugin": "^0.2.4", "@next/eslint-plugin-next": "^16.2.9", "@semantic-release/git": "^10.0.1", "@types/node": "^26.0.1", @@ -194,12 +200,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -208,29 +214,29 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.29.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", - "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -256,13 +262,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -272,13 +278,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -297,36 +303,36 @@ } }, "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -336,52 +342,52 @@ } }, "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==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "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==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", - "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "license": "MIT", "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", - "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -391,31 +397,31 @@ } }, "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", "debug": "^4.3.1" }, "engines": { @@ -423,13 +429,13 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -439,7 +445,7 @@ "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, + "devOptional": true, "license": "MIT", "engines": { "node": ">=18" @@ -787,7 +793,6 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -799,7 +804,6 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -810,7 +814,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -849,7 +852,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -866,7 +868,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -883,7 +884,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -900,7 +900,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -917,7 +916,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -934,7 +932,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -951,7 +948,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -968,7 +964,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -985,7 +980,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1002,7 +996,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1019,7 +1012,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1036,7 +1028,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1053,7 +1044,6 @@ "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1070,7 +1060,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1087,7 +1076,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1104,7 +1092,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1121,7 +1108,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1138,7 +1124,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1155,7 +1140,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1172,7 +1156,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1189,7 +1172,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1206,7 +1188,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1223,7 +1204,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1240,7 +1220,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1257,7 +1236,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1274,7 +1252,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1342,6 +1319,19 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint-zod/utils": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@eslint-zod/utils/-/utils-2.3.0.tgz", + "integrity": "sha512-6XEQLA5lDOOLnX05bgzDT3DyxlCGgLDFX3q0wYSSUSyVJj5WD+8wdlIAFY8kjatSDHWJQ+qFI/BdiDh9o50nBQ==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.57.0", + "esquery": "^1.6.0" + }, + "engines": { + "node": "^20 || ^22 || >=24" + } + }, "node_modules/@eslint/compat": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-2.0.5.tgz", @@ -1704,7 +1694,6 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz", "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -1719,6 +1708,64 @@ "@emnapi/runtime": "^1.7.1" } }, + "node_modules/@nelsonlaidev/eslint-plugin": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@nelsonlaidev/eslint-plugin/-/eslint-plugin-0.2.4.tgz", + "integrity": "sha512-MSXAp5w6Qisllh9UR16trkBqXzhf8NdX2D0qnhSUxNrEthOBbrFJuJqwhLCKfo+5lbrmbepHge4GyXX8ydlIFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.57.2", + "minimatch": "^10.2.4" + }, + "peerDependencies": { + "eslint": "^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@nelsonlaidev/eslint-plugin/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@nelsonlaidev/eslint-plugin/node_modules/brace-expansion": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@nelsonlaidev/eslint-plugin/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@next/eslint-plugin-next": { "version": "16.2.9", "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.2.9.tgz", @@ -2171,7 +2218,7 @@ "version": "0.133.0", "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", - "dev": true, + "devOptional": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" @@ -2567,7 +2614,7 @@ "version": "1.0.0-next.29", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@rolldown/binding-android-arm64": { @@ -2577,7 +2624,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2594,7 +2640,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2611,7 +2656,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2628,7 +2672,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2645,7 +2688,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2662,7 +2704,6 @@ "cpu": [ "arm64" ], - "dev": true, "libc": [ "glibc" ], @@ -2682,7 +2723,6 @@ "cpu": [ "arm64" ], - "dev": true, "libc": [ "musl" ], @@ -2702,7 +2742,6 @@ "cpu": [ "ppc64" ], - "dev": true, "libc": [ "glibc" ], @@ -2722,7 +2761,6 @@ "cpu": [ "s390x" ], - "dev": true, "libc": [ "glibc" ], @@ -2742,7 +2780,6 @@ "cpu": [ "x64" ], - "dev": true, "libc": [ "glibc" ], @@ -2762,7 +2799,6 @@ "cpu": [ "x64" ], - "dev": true, "libc": [ "musl" ], @@ -2782,7 +2818,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2799,7 +2834,6 @@ "cpu": [ "wasm32" ], - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -2818,7 +2852,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2835,7 +2868,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2849,7 +2881,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { @@ -4026,7 +4058,7 @@ "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, + "devOptional": true, "license": "MIT" }, "node_modules/@stylistic/eslint-plugin": { @@ -4115,7 +4147,6 @@ "version": "0.10.2", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -4126,7 +4157,7 @@ "version": "5.2.3", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/deep-eql": "*", @@ -4137,7 +4168,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/estree": { @@ -4162,7 +4193,7 @@ "version": "26.0.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-26.0.1.tgz", "integrity": "sha512-fc3KiUoBt6kie0N9bIW3E47vZsuaMf0PM2AaUpLCLT0s/LvX1nxAim6Fc049cNxODPpGm6qRAuUOB86SkRuPQw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~8.3.0" @@ -4601,7 +4632,7 @@ "version": "4.1.9", "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.9.tgz", "integrity": "sha512-G9/lgqibheLVBDRuya45EbsEXTYcWoSG+TLg7i2axuzx0Eq62eXn+aWXyaVdV5vKvFSWd6ywcX8hA7la9Pvu8g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^1.0.2", @@ -4628,11 +4659,41 @@ } } }, + "node_modules/@vitest/eslint-plugin": { + "version": "1.6.20", + "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.6.20.tgz", + "integrity": "sha512-xRwWHFG0Utp6hXtbGiWk4VdKXCGdExD8kbWrrmFEiG5dk8anOJ+vbWbeOa8EbkocKQRTsx7JAWETccZiBgFp/Q==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "^8.58.0", + "@typescript-eslint/utils": "^8.58.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "*", + "eslint": ">=8.57.0", + "typescript": ">=5.0.0", + "vitest": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "typescript": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, "node_modules/@vitest/expect": { "version": "4.1.9", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.9.tgz", "integrity": "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", @@ -4650,7 +4711,7 @@ "version": "4.1.9", "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.9.tgz", "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@vitest/spy": "4.1.9", @@ -4677,7 +4738,7 @@ "version": "4.1.9", "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.9.tgz", "integrity": "sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "tinyrainbow": "^3.1.0" @@ -4690,7 +4751,7 @@ "version": "4.1.9", "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.9.tgz", "integrity": "sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@vitest/utils": "4.1.9", @@ -4704,7 +4765,7 @@ "version": "4.1.9", "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.9.tgz", "integrity": "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@vitest/pretty-format": "4.1.9", @@ -4720,7 +4781,7 @@ "version": "4.1.9", "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.9.tgz", "integrity": "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==", - "dev": true, + "devOptional": true, "license": "MIT", "funding": { "url": "https://opencollective.com/vitest" @@ -4730,7 +4791,7 @@ "version": "4.1.9", "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.1.9.tgz", "integrity": "sha512-U/cRvtqfEPj27FI1n9cyUvi4vXXdcLhjJiI+InYKdk8hP4VrS6RXOjGL7rfFaeBc37iRKANsR6eEzIoC7lmgBQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@vitest/utils": "4.1.9", @@ -4752,7 +4813,7 @@ "version": "4.1.9", "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.9.tgz", "integrity": "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@vitest/pretty-format": "4.1.9", @@ -5079,7 +5140,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=12" @@ -5095,7 +5156,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz", "integrity": "sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.31", @@ -5107,7 +5168,7 @@ "version": "10.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/async-function": { @@ -5359,7 +5420,7 @@ "version": "6.2.2", "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=18" @@ -6175,7 +6236,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -6577,9 +6638,9 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.2.tgz", - "integrity": "sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.3.tgz", + "integrity": "sha512-0PuBxFi+4uPanB97iDxCLWuHeYud2FALrw5HFZGtAF38UpJDbDC8frwp2cnDyae692CQ0dou60UwWfhgsa4U/g==", "license": "MIT", "dependencies": { "call-bind": "^1.0.9", @@ -6607,7 +6668,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/es-object-atoms": { @@ -6681,7 +6742,7 @@ "version": "0.27.7", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", - "dev": true, + "devOptional": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -6996,6 +7057,35 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-jest": { + "version": "29.15.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.15.3.tgz", + "integrity": "sha512-iK2nHK4zBfxkkeP0japj/wvECG2z8qCdnQsOKdsNF82SfLvkD46jcrmkWTwfGCTYV9XPOZcJ7QyjFyppnp94WQ==", + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.0.0" + }, + "engines": { + "node": "^20.12.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^8.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "jest": "*", + "typescript": ">=4.8.4 <7.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, "node_modules/eslint-plugin-jsdoc": { "version": "63.0.10", "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-63.0.10.tgz", @@ -7160,6 +7250,21 @@ "node": ">= 4" } }, + "node_modules/eslint-plugin-playwright": { + "version": "2.10.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-2.10.4.tgz", + "integrity": "sha512-l0V/VxyqfFbtqCTxj5AdRn3Q6S/hIW4nKBnKZVleVbZ24N2My6Usj//ytX3dKKqAoSbvKck9YtSytfdZ5qjLuA==", + "license": "MIT", + "dependencies": { + "globals": "^17.3.0" + }, + "engines": { + "node": ">=16.9.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, "node_modules/eslint-plugin-prettier": { "version": "5.5.5", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", @@ -7281,9 +7386,9 @@ } }, "node_modules/eslint-plugin-react/node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -7311,6 +7416,27 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-regexp": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-3.1.1.tgz", + "integrity": "sha512-MxR5nqoQCtVWmJwia0D2+NlXX1xzdpkslsVOZLEYQ4PQWEaL65PCZXURxaBc3lPnkNFpNxzMIRmYVxdl8giXRA==", + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "comment-parser": "^1.4.0", + "jsdoc-type-pratt-parser": "^7.0.0", + "refa": "^0.12.1", + "regexp-ast-analysis": "^0.7.1", + "scslre": "^0.3.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "peerDependencies": { + "eslint": ">=9.38.0" + } + }, "node_modules/eslint-plugin-unicorn": { "version": "64.0.0", "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-64.0.0.tgz", @@ -7371,6 +7497,35 @@ } } }, + "node_modules/eslint-plugin-zod": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-zod/-/eslint-plugin-zod-4.7.0.tgz", + "integrity": "sha512-unziYvD8FGxhfL6rYuC3Cjdx/K3yMWSTv6t5uB9KEgzMajDXuQcp67/WDxdUiEFhGY1LlXJs03xQc+Pg6+vqrw==", + "license": "MIT", + "dependencies": { + "@eslint-zod/utils": "2.3.0", + "@typescript-eslint/utils": "^8.57.0" + }, + "engines": { + "node": "^20 || ^22 || >=24" + }, + "peerDependencies": { + "eslint": "^9 || ^10", + "oxlint": "^1.59.0", + "zod": "^4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "oxlint": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, "node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", @@ -7506,7 +7661,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.0" @@ -7558,7 +7713,7 @@ "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, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=12.0.0" @@ -7723,7 +7878,7 @@ "version": "0.8.2", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/figures": { @@ -7902,7 +8057,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -8475,7 +8629,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/http-proxy-agent": { @@ -9164,7 +9318,7 @@ "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, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=8" @@ -9174,7 +9328,7 @@ "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, + "devOptional": true, "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", @@ -9189,7 +9343,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", @@ -9494,7 +9648,7 @@ "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "dev": true, + "devOptional": true, "license": "MPL-2.0", "dependencies": { "detect-libc": "^2.0.3" @@ -9527,7 +9681,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9548,7 +9701,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9569,7 +9721,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9590,7 +9741,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9611,7 +9761,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9632,7 +9781,6 @@ "cpu": [ "arm64" ], - "dev": true, "libc": [ "glibc" ], @@ -9656,7 +9804,6 @@ "cpu": [ "arm64" ], - "dev": true, "libc": [ "musl" ], @@ -9680,7 +9827,6 @@ "cpu": [ "x64" ], - "dev": true, "libc": [ "glibc" ], @@ -9704,7 +9850,6 @@ "cpu": [ "x64" ], - "dev": true, "libc": [ "musl" ], @@ -9728,7 +9873,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9749,7 +9893,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -10057,7 +10200,7 @@ "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, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" @@ -10067,7 +10210,7 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.29.0", @@ -10110,7 +10253,7 @@ "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, + "devOptional": true, "license": "MIT", "dependencies": { "semver": "^7.5.3" @@ -10338,7 +10481,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10" @@ -10366,7 +10509,7 @@ "version": "3.3.12", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", - "dev": true, + "devOptional": true, "funding": [ { "type": "github", @@ -12963,7 +13106,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", - "dev": true, + "devOptional": true, "funding": [ "https://github.com/sponsors/sxzz", "https://opencollective.com/debug" @@ -13541,7 +13684,7 @@ "version": "8.5.15", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", - "dev": true, + "devOptional": true, "funding": [ { "type": "opencollective", @@ -13979,6 +14122,18 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/refa": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/refa/-/refa-0.12.1.tgz", + "integrity": "sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==", + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.8.0" + }, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/reflect-metadata": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", @@ -14007,6 +14162,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regexp-ast-analysis": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regexp-ast-analysis/-/regexp-ast-analysis-0.7.1.tgz", + "integrity": "sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==", + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.8.0", + "refa": "^0.12.1" + }, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/regexp-tree": { "version": "0.1.27", "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", @@ -14174,7 +14342,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@oxc-project/types": "=0.133.0", @@ -14346,6 +14514,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/scslre": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/scslre/-/scslre-0.3.0.tgz", + "integrity": "sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==", + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.8.0", + "refa": "^0.12.0", + "regexp-ast-analysis": "^0.7.0" + }, + "engines": { + "node": "^14.0.0 || >=16.0.0" + } + }, "node_modules/semantic-release": { "version": "25.0.5", "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-25.0.5.tgz", @@ -14652,7 +14834,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/signal-exit": { @@ -14777,7 +14959,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@polka/url": "^1.0.0-next.24", @@ -14891,7 +15073,7 @@ "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==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -14973,14 +15155,14 @@ "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/std-env": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/stop-iteration-iterator": { @@ -15453,14 +15635,14 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/tinyexec": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=18" @@ -15486,7 +15668,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=14.0.0" @@ -15524,7 +15706,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -15600,7 +15782,6 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, "license": "0BSD", "optional": true }, @@ -15718,7 +15899,7 @@ "version": "4.22.4", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.4.tgz", "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "esbuild": "~0.28.0" @@ -15740,7 +15921,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -15757,7 +15937,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -15774,7 +15953,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -15791,7 +15969,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -15808,7 +15985,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -15825,7 +16001,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -15842,7 +16017,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -15859,7 +16033,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -15876,7 +16049,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -15893,7 +16065,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -15910,7 +16081,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -15927,7 +16097,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -15944,7 +16113,6 @@ "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -15961,7 +16129,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -15978,7 +16145,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -15995,7 +16161,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16012,7 +16177,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16029,7 +16193,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16046,7 +16209,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16063,7 +16225,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16080,7 +16241,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16097,7 +16257,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16114,7 +16273,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16131,7 +16289,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16148,7 +16305,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16165,7 +16321,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -16179,7 +16334,7 @@ "version": "0.28.0", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", - "dev": true, + "devOptional": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -16684,7 +16839,7 @@ "version": "8.3.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/unicode-emoji-modifier-base": { @@ -16855,7 +17010,7 @@ "version": "8.0.16", "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", @@ -16933,7 +17088,7 @@ "version": "4.1.9", "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.9.tgz", "integrity": "sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@vitest/expect": "4.1.9", @@ -17147,7 +17302,7 @@ "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, + "devOptional": true, "license": "MIT", "dependencies": { "siginfo": "^2.0.0", @@ -17284,7 +17439,7 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "dev": true, + "devOptional": true, "license": "ISC", "bin": { "yaml": "bin.mjs" diff --git a/package.json b/package.json index d672ba32..7db8849a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@solvro/config", - "version": "2.3.4", + "version": "3.0.0-beta.9", "description": "Solvro's engineering style guide", "keywords": [ "eslint", @@ -34,7 +34,9 @@ "require": "./dist/commitlint/index.cjs" } }, - "bin": "./bin/index.js", + "bin": { + "config": "bin/index.js" + }, "files": [ "dist" ], @@ -70,20 +72,25 @@ "@tanstack/eslint-plugin-query": "^5.101.2", "@trivago/prettier-plugin-sort-imports": "^6.0.2", "@typescript-eslint/eslint-plugin": "^8.62.0", + "@vitest/eslint-plugin": "^1.6.18", "commander": "^15.0.0", "eslint-config-flat-gitignore": "^2.3.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-antfu": "^3.2.3", "eslint-plugin-import": "^2.32.0", + "eslint-plugin-jest": "^29.15.2", "eslint-plugin-jsdoc": "^63.0.10", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-n": "^18.2.1", + "eslint-plugin-playwright": "^2.10.4", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.3", "eslint-plugin-react-you-might-not-need-an-effect": "^1.0.1", + "eslint-plugin-regexp": "^3.1.0", "eslint-plugin-unicorn": "^64.0.0", "eslint-plugin-unused-imports": "^4.4.1", + "eslint-plugin-zod": "^4.5.1", "execa": "^9.6.1", "find-up-simple": "^1.0.1", "globals": "^17.7.0", @@ -100,6 +107,7 @@ "@commitlint/cli": "^21.1.0", "@commitlint/types": "^21.1.0", "@eslint/config-inspector": "^3.0.4", + "@nelsonlaidev/eslint-plugin": "^0.2.4", "@next/eslint-plugin-next": "^16.2.9", "@semantic-release/git": "^10.0.1", "@types/node": "^26.0.1", diff --git a/src/cli/index.ts b/src/cli/index.ts index 33b58510..aafd1b3f 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -9,6 +9,8 @@ import { confirmProjectType } from "../utils/confirm-project-type"; import { isGitClean } from "../utils/is-git-clean"; import { PackageJson } from "../utils/package-json"; import { polishConfirm } from "../utils/polish-confirm"; +import { printIntro } from "../utils/print-intro"; +import { printOutro } from "../utils/print-outro"; import { installCommitLint } from "./install-commitlint"; import { installEslint } from "./install-eslint"; import { installGithubActions } from "./install-ga"; @@ -44,9 +46,7 @@ const options: CliOptions = program.opts(); const isNonInteractive = checkIsNonInteractive(); async function main() { - if (!isNonInteractive) { - p.intro(c.bold(c.bgBlue(" @solvro/config "))); - } + printIntro(); const packageJson = new PackageJson(); packageJson.verifyPackageManager(); @@ -56,9 +56,8 @@ async function main() { // Git clean check if (options.force !== true && !isGitClean()) { if (isNonInteractive) { - console.error( - "Repozytorium Git ma niezatwierdzone zmiany. Użyj --force, aby pominąć to sprawdzenie.", - ); + p.log.error("Repozytorium Git ma niezatwierdzone zmiany."); + p.cancel("Użyj --force, aby pominąć to sprawdzenie."); process.exit(1); } @@ -82,11 +81,11 @@ async function main() { eslint?.version == null ? "" : ` Obecnie zainstalowana jest wersja ${c.yellow(eslint.version)}.`; - const errorMessage = `ESLint w wersji powyżej 9 ${c.red("nie jest jeszcze wspierany")}.${versionInfo}`; + const errorMessage = `ESLint w wersji powyżej 9 nie jest jeszcze wspierany.${versionInfo}`; const errorRetry = "Proszę zainstalować wersję 9 i spróbować ponownie."; if (isNonInteractive) { - console.error(errorMessage); - console.error(errorRetry); + p.log.error(errorMessage); + p.cancel(errorRetry); process.exit(1); } const isConfirmed = await polishConfirm({ @@ -163,8 +162,9 @@ async function main() { } if (toolsToInstall.length === 0) { - console.error( - "Nie wybrano żadnych narzędzi. Użyj --eslint, --prettier, --gh-action, --commitlint, lub --all", + p.log.error("Nie wybrano żadnych narzędzi."); + p.cancel( + "Użyj --eslint, --prettier, --gh-action, --commitlint, lub --all", ); process.exit(1); } @@ -235,8 +235,7 @@ async function main() { await packageJson.localExecute("prettier", "--write", "package.json"); } - const printSuccess = isNonInteractive ? console.info : p.outro; - printSuccess("✅ Konfiguracja zakończona pomyślnie!"); + printOutro(); } async function mainWrapper() { @@ -244,19 +243,11 @@ async function mainWrapper() { await main(); } catch (error: unknown) { if (process.env.NODE_ENV === "development") { - console.error( - c.red("Unhandled error in main:"), - error instanceof Error ? error.message : error, - ); + p.cancel("Unhandled error in main:"); + console.error(error instanceof Error ? error.message : error); } else { - const errorMessage = - "Wystąpił nieoczekiwany błąd :( Proszę zgłosić go twórcom:"; - if (isNonInteractive) { - console.error(errorMessage); - console.error(BUG_TRACKER_URL); - } else { - p.cancel(`${errorMessage} ${BUG_TRACKER_URL}`); - } + p.log.error("Wystąpił nieoczekiwany błąd :("); + p.cancel(`Proszę zgłosić go twórcom: ${BUG_TRACKER_URL}`); } process.exit(1); } diff --git a/src/cli/install-eslint.ts b/src/cli/install-eslint.ts index 81acb254..e5cb63d9 100644 --- a/src/cli/install-eslint.ts +++ b/src/cli/install-eslint.ts @@ -41,7 +41,7 @@ export const installEslint = async (isNonInteractive = false) => { if (!is15) { p.cancel( - "Next.js musi być w conajmniej wersji 15. Zaktualizuj Next.js i spróbuj ponownie.\nWięcej informacji tutaj: https://nextjs.org/docs/app/building-your-application/upgrading/version-15", + "Next.js musi być w co najmniej wersji 15. Zaktualizuj Next.js i spróbuj ponownie.\nWięcej informacji tutaj: https://nextjs.org/docs/app/building-your-application/upgrading/version-15", ); process.exit(1); } @@ -60,7 +60,7 @@ export const installEslint = async (isNonInteractive = false) => { ); if (eslintContent.includes("export default solvro(")) { - p.note("Eslint jest już skonfigurowany. Pomijam."); + p.log.warning("ESLint jest już skonfigurowany. Pomijam."); return; } else { @@ -69,11 +69,11 @@ export const installEslint = async (isNonInteractive = false) => { await fs.rm(path.join(root, eslintConfig)); } else { const isConfirmed = await polishConfirm({ - message: `Znaleziono plik konfiguracyjny Eslint. Czy chcesz go nadpisać?`, + message: `Znaleziono plik konfiguracyjny ESLint. Czy chcesz go nadpisać?`, }); if (p.isCancel(isConfirmed) || !isConfirmed) { - p.cancel("Nadpisz plik konfiguracyjny Eslint i spróbuj ponownie."); + p.cancel("Nadpisz plik konfiguracyjny ESLint i spróbuj ponownie."); process.exit(1); } @@ -94,5 +94,5 @@ export default solvro(); `, ); - p.note("Plik konfiguracyjny Eslint został utworzony."); + p.log.step("Plik konfiguracyjny ESLint został utworzony."); }; diff --git a/src/cli/install-ga.ts b/src/cli/install-ga.ts index f71b5b50..ad3ae1c1 100644 --- a/src/cli/install-ga.ts +++ b/src/cli/install-ga.ts @@ -94,6 +94,17 @@ export const installGithubActions = async () => { pnpmVersion, }), ); + // https://github.com/Solvro/lib-web-solvro-config/issues/431 + const formatScriptUpdated = await packageJson.updateScriptIfExists( + "format", + "prettier --write .", + 'prettier --write "src/**/*.ts" "test/**/*.ts"', + ); + if (!formatScriptUpdated) { + p.log.warning( + "Aktualizacja skryptu format została pominięta, ponieważ został on zmieniony lub nie istnieje. Ręcznie zaktualizuj skrypt format w package.json, aby formatował wszystkie pliki projektu, a nie tylko te w katalogach src i test.", + ); + } } if (!existsSync(path.join(gitDirectory, ".github/dependabot.yml"))) { diff --git a/src/cli/install-prettier.ts b/src/cli/install-prettier.ts index cd6fddc6..80f1e000 100644 --- a/src/cli/install-prettier.ts +++ b/src/cli/install-prettier.ts @@ -44,7 +44,7 @@ export const installPrettier = async (isNonInteractive = false) => { if (prettierConfig !== undefined || packageJson.json.prettier !== undefined) { if (packageJson.json.prettier === solvroPrettierPath) { - p.note("Konfiguracja Prettiera jest już ustawiona. Pomijam."); + p.log.warning("Konfiguracja Prettiera jest już ustawiona. Pomijam."); return; } @@ -73,5 +73,5 @@ export const installPrettier = async (isNonInteractive = false) => { await packageJson.save(); - p.note("Konfiguracja Prettiera została dodana."); + p.log.step("Konfiguracja Prettiera została dodana."); }; diff --git a/src/constants/github.ts b/src/constants/github.ts index 7286a4d4..c69f90b6 100644 --- a/src/constants/github.ts +++ b/src/constants/github.ts @@ -1,2 +1,2 @@ -const REPO_URL = "https://github.com/Solvro/lib-web-solvro-config"; +export const REPO_URL = "https://github.com/Solvro/lib-web-solvro-config"; export const BUG_TRACKER_URL = `${REPO_URL}/issues/new`; diff --git a/src/eslint/configs/javascript.ts b/src/eslint/configs/javascript.ts index bd5639ef..43cb5fa3 100644 --- a/src/eslint/configs/javascript.ts +++ b/src/eslint/configs/javascript.ts @@ -2,7 +2,7 @@ import type { ConfigWithExtends } from "@eslint/config-helpers"; import eslint from "@eslint/js"; import globals from "globals"; -import { pluginAntfu, pluginUnusedImports } from "../plugins"; +import { pluginAntfu, pluginRegexp, pluginUnusedImports } from "../plugins"; export function javascript(): ConfigWithExtends[] { return [ @@ -35,10 +35,12 @@ export function javascript(): ConfigWithExtends[] { name: "solvro/javascript/rules", plugins: { antfu: pluginAntfu, + regexp: pluginRegexp, "unused-imports": pluginUnusedImports, }, rules: { ...eslint.configs.recommended.rules, + ...pluginRegexp.configs["flat/recommended"].rules, "accessor-pairs": [ "error", { enforceForClassMembers: true, setWithoutGet: true }, @@ -201,6 +203,7 @@ export function javascript(): ConfigWithExtends[] { "prefer-rest-params": "error", "prefer-spread": "error", "prefer-template": "error", + "preserve-caught-error": ["error", { requireCatchParameter: true }], "symbol-description": "error", "unicode-bom": ["error", "never"], "unused-imports/no-unused-imports": "error", diff --git a/src/eslint/configs/react.ts b/src/eslint/configs/react.ts index b61baffc..d17ebecc 100644 --- a/src/eslint/configs/react.ts +++ b/src/eslint/configs/react.ts @@ -1,11 +1,15 @@ -import type { ConfigWithExtends } from "@eslint/config-helpers"; -import pluginQuery from "@tanstack/eslint-plugin-query"; -import pluginReact from "eslint-plugin-react"; -import pluginReactHooks from "eslint-plugin-react-hooks"; -import pluginReactRefresh from "eslint-plugin-react-refresh"; -import reactYouMightNotNeedAnEffect from "eslint-plugin-react-you-might-not-need-an-effect"; +import type { ConfigWithExtends, Plugin } from "@eslint/config-helpers"; import { isPackageListedSync } from "local-pkg"; +import { + pluginNelsonLai, + pluginQuery, + pluginReact, + pluginReactEffects, + pluginReactHooks, + pluginReactRefresh, +} from "../plugins"; + const nextJsPackages = ["next"]; const vitePackages = ["vite"]; @@ -56,8 +60,8 @@ export async function react(): Promise { name: "solvro/react/setup", plugins: { react: pluginReact, - "react-hooks": pluginReactHooks, + "@nelsonlaidev": pluginNelsonLai as unknown as Plugin, }, }, ...nextjsConfig, @@ -101,10 +105,15 @@ export async function react(): Promise { }, ], "react/no-array-index-key": "warn", + // https://github.com/nelsonlaidev/config/tree/main/packages/eslint-plugin + "@nelsonlaidev/lucide-icon-suffix": "error", + "@nelsonlaidev/shadcn-cn-wrap-variants": "error", + "@nelsonlaidev/shadcn-cva-variants-suffix": "error", + "@nelsonlaidev/shadcn-prefer-spinner": "error", }, }, ...pluginQuery.configs["flat/recommended"], - reactYouMightNotNeedAnEffect.configs.recommended, + pluginReactEffects.configs.recommended, { name: "solvro/react/disables", files: ["**/components/ui/*.{jsx,tsx}"], diff --git a/src/eslint/configs/testing.ts b/src/eslint/configs/testing.ts new file mode 100644 index 00000000..c75e9a72 --- /dev/null +++ b/src/eslint/configs/testing.ts @@ -0,0 +1,95 @@ +import type { ConfigWithExtends } from "@eslint/config-helpers"; +import vitest from "@vitest/eslint-plugin"; +import jest from "eslint-plugin-jest"; +import playwright from "eslint-plugin-playwright"; +import { isPackageListed } from "local-pkg"; + +export const testing = async ({ + testFiles, + playwrightTestFiles, +}: { + testFiles: string[]; + playwrightTestFiles: string[]; +}): Promise => { + const isVitest = await isPackageListed("vitest"); + const isJest = await isPackageListed("jest"); + + if (isVitest && isJest) { + throw new Error( + "Both Vitest and Jest are installed: please uninstall one of them.", + ); + } + + const isPlaywright = await isPackageListed("@playwright/test"); + + const playwrightConfig = isPlaywright + ? ([ + { + ...playwright.configs["flat/recommended"], + files: playwrightTestFiles, + rules: { + ...playwright.configs["flat/recommended"].rules, + "playwright/prefer-native-locators": "warn", + "playwright/prefer-locator": "warn", + "playwright/prefer-comparison-matcher": "warn", + "playwright/require-top-level-describe": "error", + "playwright/prefer-hooks-on-top": "warn", + "playwright/prefer-hooks-in-order": "warn", + "playwright/prefer-equality-matcher": "error", + "playwright/no-raw-locators": "warn", + }, + }, + ] as const satisfies ConfigWithExtends[]) + : []; + + const vitestConfig = isVitest + ? ([ + { + files: testFiles, + plugins: { + vitest, + }, + rules: { + ...vitest.configs.recommended.rules, + "vitest/consistent-test-it": [ + "error", + { + fn: "it", + }, + ], + "vitest/no-focused-tests": ["warn"], + "vitest/no-mocks-import": ["error"], + "vitest/no-test-return-statement": ["error"], + "vitest/prefer-lowercase-title": ["error"], + "vitest/require-top-level-describe": ["warn"], + "vitest/prefer-vi-mocked": ["error"], + "vitest/prefer-hooks-in-order": ["warn"], + "vitest/prefer-hooks-on-top": ["warn"], + "vitest/prefer-each": ["warn"], + "vitest/no-conditional-tests": ["error"], + "vitest/prefer-comparison-matcher": ["error"], + "vitest/no-conditional-in-test": ["warn"], + "vitest/consistent-vitest-vi": ["error"], + "@typescript-eslint/unbound-method": "off", + "vitest/unbound-method": ["error"], + }, + }, + ] as const satisfies ConfigWithExtends[]) + : []; + + const jestConfig = isJest + ? ([ + { + files: testFiles, + plugins: { + jest, + }, + rules: { + ...jest.configs.recommended.rules, + }, + }, + ] as const) + : []; + + return [...playwrightConfig, ...vitestConfig, ...jestConfig]; +}; diff --git a/src/eslint/configs/zod-v3.ts b/src/eslint/configs/zod-v3.ts new file mode 100644 index 00000000..1b330b76 --- /dev/null +++ b/src/eslint/configs/zod-v3.ts @@ -0,0 +1,55 @@ +import type { ConfigWithExtends } from "@eslint/config-helpers"; + +import { pluginZod } from "../plugins"; + +export function zodV3(): ConfigWithExtends[] { + return [ + { + name: "solvro/eslint-zod-v3/rules", + plugins: { + zod: pluginZod, + }, + rules: { + // Style & consistency + "zod/array-style": ["error", { style: "function" }], + "zod/consistent-import": ["error", { syntax: "namespace" }], + "zod/consistent-schema-var-name": ["error", { after: "Schema" }], + "zod/consistent-schema-output-type-style": [ + "error", + { style: "infer" }, + ], + + // Disallow unsafe patterns + "zod/no-any-schema": "error", + "zod/no-empty-custom-schema": "error", + "zod/no-optional-and-default-together": "error", + "zod/no-throw-in-refine": "error", + "zod/no-transform-in-record-key": "error", + + // Preferred patterns + "zod/prefer-enum-over-literal-union": "error", + "zod/prefer-strict-object": "error", + "zod/prefer-string-schema-with-trim": "warn", + "zod/prefer-trim-before-string-length-checks": "error", + + // Rules below are Zod v4 specific — disabled for v3 projects + "zod/no-native-enum": "off", + "zod/no-number-schema-with-int": "off", + "zod/no-number-schema-with-finite": "off", + "zod/no-number-schema-with-safe": "off", + "zod/no-number-schema-with-step": "off", + "zod/no-number-schema-with-is-finite": "off", + "zod/no-number-schema-with-is-int": "off", + "zod/no-promise-schema": "off", + "zod/no-schema-with-is-nullable": "off", + "zod/no-schema-with-is-optional": "off", + "zod/no-string-schema-with-uuid": "off", + "zod/prefer-loose-object": "off", + "zod/prefer-meta": "off", + "zod/prefer-meta-last": "off", + "zod/prefer-top-level-string-formats": "off", + "zod/require-error-message": "off", + }, + }, + ]; +} diff --git a/src/eslint/configs/zod-v4.ts b/src/eslint/configs/zod-v4.ts new file mode 100644 index 00000000..32af6166 --- /dev/null +++ b/src/eslint/configs/zod-v4.ts @@ -0,0 +1,39 @@ +import type { ConfigWithExtends } from "@eslint/config-helpers"; + +import { pluginZod } from "../plugins"; +import { zodV3 } from "./zod-v3"; + +export function zodV4(): ConfigWithExtends[] { + return [ + { + name: "solvro/eslint-zod-v4/rules", + plugins: { + zod: pluginZod, + }, + + rules: { + ...zodV3()[0].rules, + + // Zod v4 specific rules + "zod/no-native-enum": "error", + "zod/no-number-schema-with-int": "error", + "zod/no-number-schema-with-finite": "error", + "zod/no-number-schema-with-safe": "error", + "zod/no-number-schema-with-step": "error", + "zod/no-number-schema-with-is-finite": "error", + "zod/no-number-schema-with-is-int": "error", + "zod/no-promise-schema": "error", + "zod/no-schema-with-is-nullable": "error", + "zod/no-schema-with-is-optional": "error", + "zod/prefer-loose-object": "error", + "zod/prefer-meta": "error", + "zod/prefer-meta-last": "error", + "zod/prefer-top-level-string-formats": "error", + "zod/require-error-message": "error", + + // Deprecated rule — off in both v3 and v4 + "zod/no-string-schema-with-uuid": "off", + }, + }, + ]; +} diff --git a/src/eslint/index.ts b/src/eslint/index.ts index 24615e98..fc09fa3e 100644 --- a/src/eslint/index.ts +++ b/src/eslint/index.ts @@ -1,8 +1,9 @@ import type { Config, ConfigWithExtends } from "@eslint/config-helpers"; import { defineConfig } from "eslint/config"; import { findUpSync } from "find-up-simple"; -import { isPackageListed } from "local-pkg"; +import { getPackageInfo, isPackageListed } from "local-pkg"; import path from "node:path"; +import semver from "semver"; import { basePreset, defaultOverridesPreset } from "./presets/base"; @@ -12,6 +13,7 @@ export const solvro = async ( const isAdonis = await isPackageListed("@adonisjs/core"); const isReact = await isPackageListed("react"); const isNestJs = await isPackageListed("@nestjs/core"); + const isZod = await isPackageListed("zod"); if (isReact && isAdonis) { throw new Error("You can't use both Adonis and React in the same project"); @@ -53,6 +55,20 @@ export const solvro = async ( }, }; + if (isZod) { + const zodInfo = await getPackageInfo("zod"); + const zodVersion = zodInfo?.version; + const isV4 = zodVersion != null && semver.satisfies(zodVersion, ">=4.0.0"); + + if (isV4) { + const { zodV4 } = await import("./configs/zod-v4.js"); + projectConfigs.push(...zodV4()); + } else { + const { zodV3 } = await import("./configs/zod-v3.js"); + projectConfigs.push(...zodV3()); + } + } + const defaultOverrides = defaultOverridesPreset(); return defineConfig( diff --git a/src/eslint/plugins.ts b/src/eslint/plugins.ts index 91838057..b80e399b 100644 --- a/src/eslint/plugins.ts +++ b/src/eslint/plugins.ts @@ -1,6 +1,14 @@ -export { default as pluginComments } from "@eslint-community/eslint-plugin-eslint-comments"; export { default as pluginAntfu } from "eslint-plugin-antfu"; +export { default as pluginComments } from "@eslint-community/eslint-plugin-eslint-comments"; export { default as pluginImport } from "eslint-plugin-import"; +export { default as pluginNelsonLai } from "@nelsonlaidev/eslint-plugin"; export { default as pluginNode } from "eslint-plugin-n"; +export { default as pluginQuery } from "@tanstack/eslint-plugin-query"; +export { default as pluginReact } from "eslint-plugin-react"; +export { default as pluginReactEffects } from "eslint-plugin-react-you-might-not-need-an-effect"; +export { default as pluginReactHooks } from "eslint-plugin-react-hooks"; +export { default as pluginReactRefresh } from "eslint-plugin-react-refresh"; +export { default as pluginRegexp } from "eslint-plugin-regexp"; export { default as pluginUnicorn } from "eslint-plugin-unicorn"; export { default as pluginUnusedImports } from "eslint-plugin-unused-imports"; +export { default as pluginZod } from "eslint-plugin-zod"; diff --git a/src/eslint/presets/react.ts b/src/eslint/presets/react.ts index c216a74a..59d938d8 100644 --- a/src/eslint/presets/react.ts +++ b/src/eslint/presets/react.ts @@ -3,6 +3,7 @@ import type { ConfigWithExtends } from "@eslint/config-helpers"; import { a11y } from "../configs/a11y"; import { imports } from "../configs/imports"; import { react } from "../configs/react"; +import { testing } from "../configs/testing"; import { typescriptStrict } from "../configs/typescript-strict"; import { unicorn } from "../configs/unicorn"; @@ -11,5 +12,9 @@ export const reactPreset = async (): Promise => [ ...unicorn(), ...typescriptStrict(), ...imports({ forbidDefaultExport: true }), + ...(await testing({ + testFiles: ["**/*.test.ts", "**/*.test.tsx"], + playwrightTestFiles: ["**/*.spec.ts", "**/*.spec.tsx"], + })), ...(await react()), ]; diff --git a/src/utils/format-link.ts b/src/utils/format-link.ts new file mode 100644 index 00000000..b5046001 --- /dev/null +++ b/src/utils/format-link.ts @@ -0,0 +1,3 @@ +import c from "picocolors"; + +export const formatLink = (link: string) => c.white(c.underline(link)); diff --git a/src/utils/get-git-branch.ts b/src/utils/get-git-branch.ts new file mode 100644 index 00000000..e73ccead --- /dev/null +++ b/src/utils/get-git-branch.ts @@ -0,0 +1,20 @@ +import { execSync } from "node:child_process"; +import type { ExecSyncOptions } from "node:child_process"; + +export function getGitBranch(options?: ExecSyncOptions): string | null { + try { + const result = execSync( + "git symbolic-ref --quiet --short HEAD || git rev-parse --short HEAD", + { + encoding: "utf8", + stdio: ["ignore", "pipe", "ignore"], + ...options, + }, + ); + + const branch = result.toString().trim(); + return branch === "" ? null : branch; + } catch { + return null; + } +} diff --git a/src/utils/is-git-clean.ts b/src/utils/is-git-clean.ts index 3f323681..b4d667b0 100644 --- a/src/utils/is-git-clean.ts +++ b/src/utils/is-git-clean.ts @@ -1,9 +1,10 @@ import { execSync } from "node:child_process"; +import type { ExecSyncOptions } from "node:child_process"; -export function isGitClean(): boolean { +export function isGitClean(options?: ExecSyncOptions): boolean { try { - execSync("git diff-index --quiet HEAD --"); - return true; + const diff = execSync("git status --porcelain", options); + return diff.toString().trim() === ""; } catch { return false; } diff --git a/src/utils/print-intro.ts b/src/utils/print-intro.ts new file mode 100644 index 00000000..3a102647 --- /dev/null +++ b/src/utils/print-intro.ts @@ -0,0 +1,27 @@ +import * as p from "@clack/prompts"; +import { readFileSync } from "node:fs"; +import c from "picocolors"; + +import { getGitBranch } from "./get-git-branch"; +import { isGitClean } from "./is-git-clean"; + +export const printIntro = () => { + const packageJsonUrl = new URL("../../package.json", import.meta.url); + const packageJson = JSON.parse(readFileSync(packageJsonUrl, "utf8")) as { + version?: string; + }; + const packageRoot = new URL("./", packageJsonUrl); + const execOptions = { cwd: packageRoot }; + const version = + packageJson.version == null || packageJson.version.trim() === "" + ? c.red("(unknown version)") + : c.green(c.bold(`v${packageJson.version}`)); + const branchName = getGitBranch(execOptions); + const dirtyStatus = + branchName == null + ? "" + : c.white(` (${isGitClean(execOptions) ? branchName : "dirty"})`); + p.intro( + ` ${c.blueBright(c.bold("@solvro/config"))} ${version}${dirtyStatus} `, + ); +}; diff --git a/src/utils/print-outro.ts b/src/utils/print-outro.ts new file mode 100644 index 00000000..a16afa2f --- /dev/null +++ b/src/utils/print-outro.ts @@ -0,0 +1,21 @@ +import * as p from "@clack/prompts"; +import c from "picocolors"; + +import { REPO_URL } from "../constants"; +import { formatLink } from "./format-link"; + +const PROJECT_DOCS_URL = + "https://docs.solvro.pl/projects/creating#konfiguracja-repozytorium"; + +export const printOutro = () => { + p.log.success("Konfiguracja zakończona pomyślnie!"); + p.note( + `\ +1. ${c.white(`${c.bold("Obowiązkowo")} zapoznaj się z ${c.cyan("dokumentacją tworzenia projektów")}:`)} + ${formatLink(PROJECT_DOCS_URL)} +2. ${c.white(`Pamiętaj o zostawianiu nam ${c.yellow("gwiazdek na GitHubie")}! ⭐`)} + ${formatLink(REPO_URL)}`, + "Kolejne kroki", + ); + p.outro("Miłego dnia! 👋"); +}; diff --git a/src/utils/warn-inconsistent-user-agent.ts b/src/utils/warn-inconsistent-user-agent.ts index 4646762a..575079b6 100644 --- a/src/utils/warn-inconsistent-user-agent.ts +++ b/src/utils/warn-inconsistent-user-agent.ts @@ -6,7 +6,6 @@ import { PACKAGE_MANAGER_CONFIGS, SUPPORTED_PACKAGE_MANAGERS, } from "../constants"; -import { checkIsNonInteractive } from "./check-is-non-interactive"; import { isSupportedPackageManager } from "./is-supported-package-manager"; const hintInstallWithDetected = (manager: PackageManagerConfig) => ` @@ -38,9 +37,5 @@ ${ : warnUnsupported(detectedPackageManager) }`; - if (checkIsNonInteractive()) { - console.error(warningMessage); - } else { - p.cancel(warningMessage); - } + p.cancel(warningMessage); }; diff --git a/src/utils/warn-missing-lockfile.ts b/src/utils/warn-missing-lockfile.ts index ccde01fd..c418bccb 100644 --- a/src/utils/warn-missing-lockfile.ts +++ b/src/utils/warn-missing-lockfile.ts @@ -2,7 +2,6 @@ import * as p from "@clack/prompts"; import c from "picocolors"; import type { PackageManagerConfig } from "../constants"; -import { checkIsNonInteractive } from "./check-is-non-interactive"; export const warnMissingLockfile = ({ manager, @@ -20,9 +19,5 @@ ${c.white("Jeśli to się zgadza, zainstaluj najpierw zależności projektu i sp ${c.cyan(manager.installDependencies)} ${c.cyan(`${manager.downloadExecute} @solvro/config@latest`)}`; - if (checkIsNonInteractive()) { - console.error(warningMessage); - } else { - p.cancel(warningMessage); - } + p.cancel(warningMessage); }; diff --git a/src/utils/warn-unsupported-package-manager.ts b/src/utils/warn-unsupported-package-manager.ts index b742e49d..93f7509f 100644 --- a/src/utils/warn-unsupported-package-manager.ts +++ b/src/utils/warn-unsupported-package-manager.ts @@ -6,7 +6,7 @@ import { PACKAGE_MANAGER_CONFIGS, SUPPORTED_PACKAGE_MANAGERS, } from "../constants/package-managers"; -import { checkIsNonInteractive } from "./check-is-non-interactive"; +import { formatLink } from "./format-link"; export const warnUnsupportedPackageManager = ({ userAgent, @@ -22,7 +22,7 @@ Próbujesz uruchomić ten skrypt ${c.yellow(packageManager)}-em, ale @solvro/con ${SUPPORTED_PACKAGE_MANAGERS.map((manager) => c.white(`- ${c.cyan(manager)}`)).join("\n")} ${c.white(`Chcesz, aby dodano wsparcie dla ${c.yellow(packageManager)}-a? Daj nam znać!`)} -${c.white(c.underline(BUG_TRACKER_URL))} +${formatLink(BUG_TRACKER_URL)} ${c.white(`W międzyczasie użyj innego menedżera:`)} @@ -30,9 +30,5 @@ ${Object.values(PACKAGE_MANAGER_CONFIGS) .map((config) => c.cyan(`${config.downloadExecute} @solvro/config`)) .join(c.white("\nlub\n"))}`; - if (checkIsNonInteractive()) { - console.error(warningMessage); - } else { - p.cancel(warningMessage); - } + p.cancel(warningMessage); }; diff --git a/tests/integration.test.ts b/tests/integration.test.ts index e6e20cb9..f3fac6cd 100644 --- a/tests/integration.test.ts +++ b/tests/integration.test.ts @@ -195,6 +195,27 @@ describe("NestJS Integration Tests", () => { expect(packageJson).toContain('"prettier": "@solvro/config/prettier"'); }); + + test(`should update the default NestJS format script without warnings with ${packageManager.name}`, async () => { + const env = testEnv; + await env.setup(); + + const appPath = await env.createNestjsApp("format-script-test-app"); + + await env.installSolvroConfig(appPath); + await env.initGitRepo(appPath); + + const output = await env.runSolvroConfig(appPath, ["--all", "--force"]); + expect(output).toContain("Konfiguracja zakończona pomyślnie"); + expect(output).not.toContain( + "Aktualizacja skryptu format została pominięta", + ); + + const packageJson = JSON.parse(env.readFile(appPath, "package.json")) as { + scripts: Record; + }; + expect(packageJson.scripts.format).toBe("prettier --write ."); + }); }); describe("Vite Integration Tests", () => {