diff --git a/package-lock.json b/package-lock.json index 01107e77b..de727fc39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "dependencies": { "@next/env": "16.2.10", "@supabase/ssr": "^0.12.3", - "@supabase/supabase-js": "^2.108.2", + "@supabase/supabase-js": "^2.110.7", "exceljs": "^4.4.0", "jszip": "^3.10.1", "lucide-react": "^1.25.0", @@ -30,7 +30,7 @@ }, "devDependencies": { "@axe-core/playwright": "^4.12.1", - "@babel/parser": "^7.29.7", + "@babel/parser": "^8.0.4", "@next/bundle-analyzer": "^16.2.10", "@tailwindcss/postcss": "^4.3.3", "@testing-library/dom": "^10.4.1", @@ -201,6 +201,22 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/@babel/parser": { + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/generator": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", @@ -218,6 +234,22 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/generator/node_modules/@babel/parser": { + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/helper-compilation-targets": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", @@ -322,19 +354,53 @@ } }, "node_modules/@babel/parser": { - "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==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.4.tgz", + "integrity": "sha512-srpptsAkEbbNIC/q8nT7o+m6CQe8CJUTV/t7MYc9NnWlgYVtHOb7JH6SorxMhN0kuRJjVqXbKClG6xSbPtzz+g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.7" + "@babel/types": "^8.0.4" }, "bin": { "parser": "bin/babel-parser.js" }, "engines": { - "node": ">=6.0.0" + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/parser/node_modules/@babel/helper-string-parser": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz", + "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/parser/node_modules/@babel/helper-validator-identifier": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz", + "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/parser/node_modules/@babel/types": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.4.tgz", + "integrity": "sha512-eY+Yn3dCqTGmyiq2QRU66lA5FL8lqqqvecHt0fF3uHONIa7ToYsaCiWV8lOKqAs0Rb2SjixiKFROngnulPtt2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^8.0.0", + "@babel/helper-validator-identifier": "^8.0.4" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" } }, "node_modules/@babel/runtime": { @@ -362,6 +428,22 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/template/node_modules/@babel/parser": { + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/traverse": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", @@ -381,6 +463,22 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/traverse/node_modules/@babel/parser": { + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/types": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", @@ -4982,9 +5080,9 @@ "license": "MIT" }, "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.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -6528,6 +6626,22 @@ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" } }, + "node_modules/eslint-plugin-react-hooks/node_modules/@babel/parser": { + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", @@ -8738,6 +8852,22 @@ "source-map-js": "^1.2.1" } }, + "node_modules/magicast/node_modules/@babel/parser": { + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -10043,9 +10173,9 @@ } }, "node_modules/readdir-glob/node_modules/brace-expansion": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", - "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.2.tgz", + "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" diff --git a/package.json b/package.json index 7bce24b72..b18e9944e 100644 --- a/package.json +++ b/package.json @@ -182,7 +182,7 @@ "dependencies": { "@next/env": "16.2.10", "@supabase/ssr": "^0.12.3", - "@supabase/supabase-js": "^2.108.2", + "@supabase/supabase-js": "^2.110.7", "exceljs": "^4.4.0", "jszip": "^3.10.1", "lucide-react": "^1.25.0", @@ -202,11 +202,13 @@ "postcss": "^8.5.15", "esbuild": "0.28.1", "tmp": "^0.2.7", - "uuid": "^11.1.1" + "uuid": "^11.1.1", + "brace-expansion@1": "^1.1.16", + "brace-expansion@2": "^2.1.2" }, "devDependencies": { "@axe-core/playwright": "^4.12.1", - "@babel/parser": "^7.29.7", + "@babel/parser": "^8.0.4", "@next/bundle-analyzer": "^16.2.10", "@tailwindcss/postcss": "^4.3.3", "@testing-library/dom": "^10.4.1", diff --git a/tests/architecture-boundaries.test.ts b/tests/architecture-boundaries.test.ts index 1e4d6ec74..aeffe7a33 100644 --- a/tests/architecture-boundaries.test.ts +++ b/tests/architecture-boundaries.test.ts @@ -23,7 +23,9 @@ function sourceFiles() { function parseModuleSource(sourceText: string) { return parse(sourceText, { sourceType: "module", - plugins: ["jsx", "typescript", "importAttributes"], + // @babel/parser 8 parses import attributes by default; the standalone + // "importAttributes" plugin was removed (and is now a type error). + plugins: ["jsx", "typescript"], }); } @@ -60,9 +62,33 @@ function moduleSpecifiersFromSource(_filePath: string, sourceText: string) { } } + const addDynamicSpecifier = (moduleSpecifier: Record | undefined) => { + if (!moduleSpecifier) return; + 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); + } + }; + const visit = (node: unknown) => { if (!node || typeof node !== "object") return; const current = node as Record; + // @babel/parser 8 models dynamic `import(...)` as an ESTree-aligned + // ImportExpression (specifier in `source`, import-attributes in `options`). + // @babel/parser 7 modelled it as a CallExpression whose callee is an + // `Import` node with the specifier in `arguments[0]`. Handle both shapes so + // this boundary graph stays parser-major agnostic. + if (current.type === "ImportExpression") { + addDynamicSpecifier(current.source as Record | undefined); + } const argumentsList = Array.isArray(current.arguments) ? current.arguments : null; if ( current.type === "CallExpression" && @@ -71,21 +97,8 @@ function moduleSpecifiersFromSource(_filePath: string, sourceText: string) { (argumentsList.length === 1 || argumentsList.length === 2) ) { 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); - } + if (callee.type === "Import") { + addDynamicSpecifier(argumentsList[0] as Record | undefined); } } for (const value of Object.values(current)) { diff --git a/tests/client-secret-surface.test.ts b/tests/client-secret-surface.test.ts index 9db8dcf02..39b816ced 100644 --- a/tests/client-secret-surface.test.ts +++ b/tests/client-secret-surface.test.ts @@ -58,7 +58,9 @@ function localImports(file: string) { const text = readFileSync(file, "utf8"); const source = parse(text, { sourceType: "module", - plugins: ["jsx", "typescript", "importAttributes"], + // @babel/parser 8 parses import attributes by default; the standalone + // "importAttributes" plugin was removed (and is now a type error). + plugins: ["jsx", "typescript"], }); const specifiers: string[] = []; for (const statement of source.program.body) {