diff --git a/package-lock.json b/package-lock.json index 27fc24b2b..23568dda5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,7 @@ "prettier": "^3.9.4", "tailwindcss": "^4.3.1", "tsx": "^4.22.4", - "typescript": "^6.0.3", + "typescript": "^6.0.0", "vitest": "^4.1.10" }, "engines": { @@ -2906,101 +2906,15 @@ "@types/react": "^19.2.0" } }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.3.tgz", - "integrity": "sha512-PwFvSKsXGShKGW6n5bZOhGHEcCZXM8HofLK9fNsEwZXzFRjoY+XT1Vsf1zgyXdwTr0ZYz1/2tkZ0DBTT9jZjhw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.59.3", - "@typescript-eslint/type-utils": "8.59.3", - "@typescript-eslint/utils": "8.59.3", - "@typescript-eslint/visitor-keys": "8.59.3", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.59.3", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.3.tgz", - "integrity": "sha512-HPwA+hVkfcriajbNvTmZv4VRauibay+cWArYUYq7u7W7PmGShMxbPxLvrwDme55a6d5alG3nrYfhyJ/G28XlLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.59.3", - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/typescript-estree": "8.59.3", - "@typescript-eslint/visitor-keys": "8.59.3", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.3.tgz", - "integrity": "sha512-ECiUWa/KYRGDFUqTNehaRgzDshnJfkTABJxVemHk4ko22gcr0ukloKjWvyQ64g8YCV/UI47kN1dbmjf/GaQYng==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.59.3", - "@typescript-eslint/types": "^8.59.3", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.3.tgz", - "integrity": "sha512-t2LvZnoEfzKtnPjgeEu41xw5gxq9mQVfYy4OoZ4Vlt0sk3JwxmhCca/AR7DwOiHrjWgjAj6as4AhRLKSDfvZIA==", + "version": "8.63.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.63.0.tgz", + "integrity": "sha512-uUyfMWCnDSN8bCpcrY8nGP2BLkQ9Xn0GsipcONcpIDWhwhO4ZSyHvyS14U3X75mzxWxL3I2UZIrenTzdzcJO8A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/visitor-keys": "8.59.3" + "@typescript-eslint/types": "8.63.0", + "@typescript-eslint/visitor-keys": "8.63.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3010,52 +2924,10 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.3.tgz", - "integrity": "sha512-PcIJHjmaREXLgIAIzLnSY9VucEzz8FKXsRgFa1DmdGCK/5tJpW03TKJF01Q6VZd1lLdz2sIKPWaDUZN9dp//dw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.3.tgz", - "integrity": "sha512-g71d8QD8UaiHGvrJwyIS1hCX5r63w6Jll+4VEYhEAHXTDIqX1JgxhTAbEHtKntL9kuc4jRo7/GWw5xfCepSccQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/typescript-estree": "8.59.3", - "@typescript-eslint/utils": "8.59.3", - "debug": "^4.4.3", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, "node_modules/@typescript-eslint/types": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.3.tgz", - "integrity": "sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg==", + "version": "8.63.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.63.0.tgz", + "integrity": "sha512-xyLtl9DUBBFrcJS4x2pIqGLH68/tC2uOa4Z7pUteW09D3bXnnXUom4dyPikzWgB7llmIc1zoeI3aoUdC4rPK/Q==", "dev": true, "license": "MIT", "engines": { @@ -3066,118 +2938,14 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.3.tgz", - "integrity": "sha512-CbRjVRAf7Lr9Kr8RopKcbY45p2VfmmHrm0ygOCYFi7oU8q19m0Fs/6iHS7kNOmwpp+ob07ZVcAqlxUod9lYdmg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.59.3", - "@typescript-eslint/tsconfig-utils": "8.59.3", - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/visitor-keys": "8.59.3", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", - "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.3.tgz", - "integrity": "sha512-JAvT14goBzRzzzZyqq3P9BLArIxTtQURUtFgQ/V7FO+eU+Gg6ES+5ymOPP1wRxXcxAYeivCk4uS3jCKWI1K8Zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.59.3", - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/typescript-estree": "8.59.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.3.tgz", - "integrity": "sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg==", + "version": "8.63.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.63.0.tgz", + "integrity": "sha512-UexrHGnGTpbuQHct2ExOc2ZcFbGUS9FOesCxxqdBGcpI1BxYu/LZ6U8Aq6/72XtF/qRBk9nhuGHFJIXXMhPMdw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.59.3", + "@typescript-eslint/types": "8.63.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -5126,6 +4894,29 @@ } } }, + "node_modules/eslint-config-next/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/eslint-config-next/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/eslint-config-next/node_modules/eslint-import-resolver-typescript": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", @@ -5281,6 +5072,239 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint-config-next/node_modules/ignore": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", + "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint-config-next/node_modules/typescript-eslint": { + "version": "8.63.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.63.0.tgz", + "integrity": "sha512-xgwXyzG4sK9ALkBxbyGkTMMOS+imnW65iPhxCQMK83KhxyoDNW7l+IDqEf9vMdoUidHpOoS967RCq4eMiTexwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.63.0", + "@typescript-eslint/parser": "8.63.0", + "@typescript-eslint/typescript-estree": "8.63.0", + "@typescript-eslint/utils": "8.63.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/eslint-config-next/node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.63.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.63.0.tgz", + "integrity": "sha512-rvwSgqT+DHpWdzfSzPatRLm02a0GlESt++9iy3hLCDY4BgkaLcl8LBi9Yh7XGFBpwcBE/K3024QuXWTpbz4FfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.63.0", + "@typescript-eslint/type-utils": "8.63.0", + "@typescript-eslint/utils": "8.63.0", + "@typescript-eslint/visitor-keys": "8.63.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.63.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/eslint-config-next/node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "8.63.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.63.0.tgz", + "integrity": "sha512-Nzzh/OGxVCOjObjaj1CQF2RUasyYy2Jfuh+zZ3PjLzG2fYRriAiZLib9UKtO+CpQAS3YHiAS+ckZDclwqI1TPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.63.0", + "@typescript-eslint/typescript-estree": "8.63.0", + "@typescript-eslint/utils": "8.63.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/eslint-config-next/node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { + "version": "8.63.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.63.0.tgz", + "integrity": "sha512-gwh4gvvlaVDKKxyfxMG+Gnu1u9X0OQBwyGLkbwB65dIzBKnxeRiJlNFqlI3zwVhNXJIs6qV7mlFCn/BIajlVig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.63.0", + "@typescript-eslint/types": "8.63.0", + "@typescript-eslint/typescript-estree": "8.63.0", + "@typescript-eslint/visitor-keys": "8.63.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/eslint-config-next/node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.63.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.63.0.tgz", + "integrity": "sha512-ygBkU+B7ex5UI/gKhaqexWev79uISfIv7XQCRNYO/jmD8rGLPyWLAb3KMRT6nd8Gt9bmUBi9+iX6tBdYfOY81Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.63.0", + "@typescript-eslint/tsconfig-utils": "8.63.0", + "@typescript-eslint/types": "8.63.0", + "@typescript-eslint/visitor-keys": "8.63.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/eslint-config-next/node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": { + "version": "8.63.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.63.0.tgz", + "integrity": "sha512-e5dh0/UI0ok53AlZ5wRkXCB32z/f2jUZqPR/ygAw5WYaSw8j9EoJWlS7wQjr/dmOaqWjnPIn2m+HhVPCMWGZVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.63.0", + "@typescript-eslint/types": "^8.63.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/eslint-config-next/node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.63.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.63.0.tgz", + "integrity": "sha512-sUAbkulqBAsncKnbRP3+7CtQFRKicexnj7ZwNC6ddCR7EmrXvjvdCYMJbUIqMd6lwoEriZjwLo08aS5tSjVMHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/eslint-config-next/node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "8.63.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.63.0.tgz", + "integrity": "sha512-fUKaeAvrTuQg/Tgt3nliAUSZHJM6DlCcfyEmxCvlX8kieWSStBX+5O5Fnidtc3i2JrH+9c/GL4RY2iasd/GPTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.63.0", + "@typescript-eslint/types": "8.63.0", + "@typescript-eslint/typescript-estree": "8.63.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/eslint-config-next/node_modules/typescript-eslint/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/eslint-config-next/node_modules/typescript-eslint/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/eslint-import-resolver-node": { "version": "0.3.10", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz", @@ -9614,30 +9638,6 @@ "node": ">=14.17" } }, - "node_modules/typescript-eslint": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.59.3.tgz", - "integrity": "sha512-KgusgyDgG4LI8Ih/sWaCtZ06tckLAS5CvT5A4D1Q7bYVoAAyzwiZvE4BmwDHkhRVkvhRBepKeASoFzQetha7Fg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.59.3", - "@typescript-eslint/parser": "8.59.3", - "@typescript-eslint/typescript-estree": "8.59.3", - "@typescript-eslint/utils": "8.59.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", diff --git a/package.json b/package.json index 683023ce3..f09e8783c 100644 --- a/package.json +++ b/package.json @@ -171,7 +171,7 @@ "prettier": "^3.9.4", "tailwindcss": "^4.3.1", "tsx": "^4.22.4", - "typescript": "^6.0.3", + "typescript": "^6.0.0", "vitest": "^4.1.10" } } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 0a6846206..105024c44 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -34,10 +34,11 @@ const baseMetadata: Metadata = { */ export async function generateMetadata(): Promise { const allowRequestOrigin = process.env.NODE_ENV !== "production"; - const requestHeaders = allowRequestOrigin ? await headers() : new Headers(); + const requestHeaders = await headers(); + const metadataHeaders = allowRequestOrigin ? requestHeaders : new Headers(); return { ...baseMetadata, - metadataBase: resolveMetadataBase(requestHeaders, { + metadataBase: resolveMetadataBase(metadataHeaders, { configuredSiteUrl: process.env.NEXT_PUBLIC_SITE_URL, trustedDeploymentDomain: process.env.RAILWAY_PUBLIC_DOMAIN, allowRequestOrigin, diff --git a/tests/architecture-boundaries.test.ts b/tests/architecture-boundaries.test.ts index 5bb00fec5..323aec37c 100644 --- a/tests/architecture-boundaries.test.ts +++ b/tests/architecture-boundaries.test.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; import path from "node:path"; -import ts from "typescript"; +import { parse } from "@babel/parser"; import { describe, expect, it } from "vitest"; const projectRoot = path.resolve(import.meta.dirname, ".."); @@ -20,62 +20,78 @@ function sourceFiles() { return files; } -function scriptKind(filePath: string) { - if (filePath.endsWith(".tsx")) return ts.ScriptKind.TSX; - if (filePath.endsWith(".jsx")) return ts.ScriptKind.JSX; - if (filePath.endsWith(".js") || filePath.endsWith(".mjs")) return ts.ScriptKind.JS; - return ts.ScriptKind.TS; +function parseModuleSource(sourceText: string) { + return parse(sourceText, { + sourceType: "module", + plugins: ["jsx", "typescript", "importAttributes"], + }); } -function moduleSpecifiersFromSource(filePath: string, sourceText: string) { - const source = ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true, scriptKind(filePath)); +function moduleSpecifiersFromSource(_filePath: string, sourceText: string) { const staticImports = new Set(); const dynamicImports = new Set(); + const source = parseModuleSource(sourceText); - for (const statement of source.statements) { - if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) { - const clause = statement.importClause; - const namedImports = - clause?.namedBindings && ts.isNamedImports(clause.namedBindings) ? clause.namedBindings : null; + for (const statement of source.program.body) { + if (statement.type === "ImportDeclaration") { const typeOnly = - clause?.isTypeOnly || + statement.importKind === "type" || Boolean( - clause && - !clause.name && - namedImports?.elements.length && - namedImports.elements.every((item) => item.isTypeOnly), + !statement.specifiers.some((specifier) => specifier.type === "ImportDefaultSpecifier") && + statement.specifiers.some((specifier) => specifier.type === "ImportSpecifier") && + statement.specifiers.every( + (specifier) => specifier.type === "ImportSpecifier" && specifier.importKind === "type", + ), ); - if (!typeOnly) staticImports.add(statement.moduleSpecifier.text); + if (!typeOnly) staticImports.add(statement.source.value); } if ( - ts.isExportDeclaration(statement) && - statement.moduleSpecifier && - ts.isStringLiteral(statement.moduleSpecifier) + (statement.type === "ExportNamedDeclaration" || statement.type === "ExportAllDeclaration") && + statement.source ) { const typeOnly = - statement.isTypeOnly || + statement.exportKind === "type" || Boolean( - statement.exportClause && - ts.isNamedExports(statement.exportClause) && - statement.exportClause.elements.length > 0 && - statement.exportClause.elements.every((item) => item.isTypeOnly), + statement.type === "ExportNamedDeclaration" && + statement.specifiers.length > 0 && + statement.specifiers.every((specifier) => "exportKind" in specifier && specifier.exportKind === "type"), ); - if (!typeOnly) staticImports.add(statement.moduleSpecifier.text); + if (!typeOnly) staticImports.add(statement.source.value); } } - const visit = (node: ts.Node) => { - const moduleSpecifier = ts.isCallExpression(node) ? node.arguments[0] : undefined; + const visit = (node: unknown) => { + if (!node || typeof node !== "object") return; + const current = node as Record; + const argumentsList = Array.isArray(current.arguments) ? current.arguments : null; if ( - ts.isCallExpression(node) && - node.expression.kind === ts.SyntaxKind.ImportKeyword && - (node.arguments.length === 1 || node.arguments.length === 2) && - moduleSpecifier && - ts.isStringLiteralLike(moduleSpecifier) + current.type === "CallExpression" && + current.callee && + argumentsList && + (argumentsList.length === 1 || argumentsList.length === 2) ) { - dynamicImports.add(moduleSpecifier.text); + const callee = current.callee as Record; + const moduleSpecifier = argumentsList[0] as Record | undefined; + if (callee.type === "Import" && moduleSpecifier) { + if (moduleSpecifier.type === "StringLiteral" && typeof moduleSpecifier.value === "string") { + dynamicImports.add(moduleSpecifier.value); + } else if ( + moduleSpecifier.type === "TemplateLiteral" && + Array.isArray(moduleSpecifier.expressions) && + moduleSpecifier.expressions.length === 0 && + Array.isArray(moduleSpecifier.quasis) && + moduleSpecifier.quasis.length === 1 + ) { + const cooked = ((moduleSpecifier.quasis[0] as Record).value as Record) + ?.cooked; + if (typeof cooked === "string") dynamicImports.add(cooked); + } + } + } + for (const value of Object.values(current)) { + if (Array.isArray(value)) value.forEach(visit); + else visit(value); } - ts.forEachChild(node, visit); }; visit(source); @@ -188,13 +204,8 @@ describe("architecture boundaries", () => { it("keeps server environment and provider modules out of the client graph", () => { const { files, graph, parsed } = runtimeGraph(); const clientEntries = files.filter((file) => { - const firstStatement = parsed.get(file)?.source.statements[0]; - return Boolean( - firstStatement && - ts.isExpressionStatement(firstStatement) && - ts.isStringLiteral(firstStatement.expression) && - firstStatement.expression.text === "use client", - ); + const program = parsed.get(file)?.source.program; + return program?.directives?.some((directive) => directive.value.value === "use client"); }); const clientGraph = new Set(clientEntries); const pending = [...clientEntries]; diff --git a/tests/client-secret-surface.test.ts b/tests/client-secret-surface.test.ts index 4cd651cd0..6f0ee9f1d 100644 --- a/tests/client-secret-surface.test.ts +++ b/tests/client-secret-surface.test.ts @@ -11,7 +11,7 @@ import { } from "node:fs"; import { tmpdir } from "node:os"; import { dirname, extname, join, relative, resolve } from "node:path"; -import ts from "typescript"; +import { parse } from "@babel/parser"; import { describe, expect, it } from "vitest"; const ROOT = process.cwd(); @@ -25,8 +25,8 @@ const importCache = new Map(); function sourceFiles(dir: string): string[] { return readdirSync(dir, { recursive: true }) .map(String) - .filter((name) => SOURCE_EXTENSIONS.includes(extname(name))) - .map((name) => join(dir, name)); + .map((name) => join(dir, name)) + .filter((file) => SOURCE_EXTENSIONS.includes(extname(file)) && statSync(file).isFile()); } function isClientModule(text: string) { @@ -45,7 +45,9 @@ function resolveLocalImport(importer: string, specifier: string) { ...SOURCE_EXTENSIONS.map((extension) => `${base}${extension}`), ...SOURCE_EXTENSIONS.map((extension) => join(base, `index${extension}`)), ]) { - if (existsSync(candidate) && statSync(candidate).isFile()) return candidate; + if (SOURCE_EXTENSIONS.includes(extname(candidate)) && existsSync(candidate) && statSync(candidate).isFile()) { + return candidate; + } } return null; } @@ -54,26 +56,30 @@ function localImports(file: string) { const cached = importCache.get(file); if (cached) return cached; const text = readFileSync(file, "utf8"); - const source = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true); + const source = parse(text, { + sourceType: "module", + plugins: ["jsx", "typescript", "importAttributes"], + }); const specifiers: string[] = []; - for (const statement of source.statements) { - if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) { - const clause = statement.importClause; - const namedBindings = clause?.namedBindings; + for (const statement of source.program.body) { + if (statement.type === "ImportDeclaration") { const isTypeOnly = - clause?.isTypeOnly || - (namedBindings && - ts.isNamedImports(namedBindings) && - namedBindings.elements.every((element) => element.isTypeOnly)); - if (!isTypeOnly) specifiers.push(statement.moduleSpecifier.text); + statement.importKind === "type" || + Boolean( + !statement.specifiers.some((specifier) => specifier.type === "ImportDefaultSpecifier") && + statement.specifiers.some((specifier) => specifier.type === "ImportSpecifier") && + statement.specifiers.every( + (specifier) => specifier.type === "ImportSpecifier" && specifier.importKind === "type", + ), + ); + if (!isTypeOnly) specifiers.push(statement.source.value); } if ( - ts.isExportDeclaration(statement) && - !statement.isTypeOnly && - statement.moduleSpecifier && - ts.isStringLiteral(statement.moduleSpecifier) + (statement.type === "ExportNamedDeclaration" || statement.type === "ExportAllDeclaration") && + statement.exportKind !== "type" && + statement.source ) { - specifiers.push(statement.moduleSpecifier.text); + specifiers.push(statement.source.value); } } const imports = specifiers.flatMap((specifier) => { diff --git a/tests/clinical-dashboard-merge-artifacts.test.ts b/tests/clinical-dashboard-merge-artifacts.test.ts index 52b088525..7e4a2aca4 100644 --- a/tests/clinical-dashboard-merge-artifacts.test.ts +++ b/tests/clinical-dashboard-merge-artifacts.test.ts @@ -1,6 +1,6 @@ import { readFileSync } from "node:fs"; import { resolve } from "node:path"; -import * as ts from "typescript"; +import { parse } from "@babel/parser"; import { describe, expect, it } from "vitest"; // The dashboard render surfaces are progressively being extracted from the @@ -17,7 +17,10 @@ const scannedFiles = [ return { path, source, - ast: ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX), + ast: parse(source, { + sourceType: "module", + plugins: ["jsx", "typescript"], + }), }; }); @@ -28,37 +31,38 @@ const globalSearchShellSource = readFileSync( const clinicalDashboardSource = readFileSync(resolve(process.cwd(), "src/components/ClinicalDashboard.tsx"), "utf8"); const globalStylesSource = readFileSync(resolve(process.cwd(), "src/app/globals.css"), "utf8"); -type FoundDeclaration = { node: ts.FunctionDeclaration; ast: ts.SourceFile }; +type FoundDeclaration = { source: string }; function findFunctionDeclaration(name: string): FoundDeclaration | null { for (const file of scannedFiles) { - let found: ts.FunctionDeclaration | null = null; - - function visit(node: ts.Node) { - if (found) return; - if (ts.isFunctionDeclaration(node) && node.name?.text === name) { - found = node; + let found: string | null = null; + const visit = (node: unknown) => { + if (found || !node || typeof node !== "object") return; + const current = node as Record; + const identifier = current.id as Record | undefined; + if ( + current.type === "FunctionDeclaration" && + identifier?.type === "Identifier" && + identifier.name === name && + typeof current.start === "number" && + typeof current.end === "number" + ) { + found = file.source.slice(current.start, current.end); return; } - ts.forEachChild(node, visit); - } - + for (const value of Object.values(current)) { + if (Array.isArray(value)) value.forEach(visit); + else visit(value); + } + }; visit(file.ast); - if (found) return { node: found, ast: file.ast }; + if (found) return { source: found }; } return null; } -function descendantIdentifiers(node: ts.Node) { - const identifiers = new Set(); - - function visit(current: ts.Node) { - if (ts.isIdentifier(current)) identifiers.add(current.text); - ts.forEachChild(current, visit); - } - - visit(node); - return identifiers; +function descendantIdentifiers(source: string) { + return new Set(source.match(/\b[A-Za-z_$][\w$]*\b/g) ?? []); } describe("ClinicalDashboard merge-artifact guards", () => { @@ -96,8 +100,8 @@ describe("ClinicalDashboard merge-artifact guards", () => { expect(panel, "ClinicalOutputPanel should remain a local function declaration").not.toBeNull(); if (!panel) throw new Error("ClinicalOutputPanel should remain a local function declaration"); - const panelSource = panel.node.getText(panel.ast); - const panelIdentifiers = descendantIdentifiers(panel.node); + const panelSource = panel.source; + const panelIdentifiers = descendantIdentifiers(panel.source); expect(panelIdentifiers.has("copiedWardNote")).toBe(false); expect(panelIdentifiers.has("onCopyWardNote")).toBe(false); @@ -113,7 +117,7 @@ describe("ClinicalDashboard merge-artifact guards", () => { expect(answer, "NaturalLanguageAnswer should remain a local function declaration").not.toBeNull(); if (!answer) throw new Error("NaturalLanguageAnswer should remain a local function declaration"); - const answerSource = answer.node.getText(answer.ast); + const answerSource = answer.source; expect(answerSource).toContain("plain-answer-prose"); expect(answerSource).not.toContain("parseAnswerDisplayContent"); expect(answerSource).not.toContain("AnswerSymbolTile");