fix(nuxt): definePageMeta and others not work with vue-class-decorator and vue-facing-decorator#30025
Conversation
|
|
WalkthroughThe pull request introduces updates to the Changes
Assessment against linked issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
|
New and removed dependencies detected. Learn more about Socket for GitHub ↗︎
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Outside diff range and nitpick comments (7)
packages/nuxt/src/pages/route-rules.ts (2)
10-11: LGTM! TypeScript parsing support added correctly.The imports are properly configured to enable TypeScript parsing capabilities.
Add a newline after the imports for better code organization:
import * as acorn from 'acorn' import tsPlugin from 'acorn-typescript' + const ROUTE_RULE_RE = /\bdefineRouteRules\(/🧰 Tools
🪛 eslint (1.23.1)
[error] 11-11: Expected 1 empty line after import statement not followed by another import.
(import/newline-after-import)
Line range hint
29-45: Consider adding TypeScript-specific error messages.While the implementation correctly handles TypeScript syntax, consider enhancing the error message to specifically mention TypeScript support when parsing fails. This would make debugging easier for users working with decorators and TypeScript syntax.
Example enhancement:
- throw new Error('[nuxt] Error parsing route rules. They should be JSON-serializable.') + throw new Error('[nuxt] Error parsing route rules. Ensure the rules are JSON-serializable and TypeScript decorators are properly configured.')packages/nuxt/src/core/plugins/prehydrate.ts (1)
25-28: Consider performance impact of TypeScript parsingWhile the TypeScript parser integration is necessary, it might impact build performance. Consider adding a performance test comparing the old vs new implementation.
Would you like me to help create a performance benchmark for this change?
packages/nuxt/package.json (1)
74-74: Consider using fixed version for consistency with acorn.While the added dependency is compatible with the current acorn version, consider using a fixed version for
acorn-typescriptto maintain consistency with howacornis versioned in this package.- "acorn-typescript": "^1.4.13", + "acorn-typescript": "1.4.13",packages/nuxt/src/core/plugins/plugin-metadata.ts (1)
Line range hint
78-80: Ensure consistent TypeScript parsing in all parsing instancesThe
RemovePluginMetadataPluginis still usingthis.parsefor code parsing. To maintain consistency and support TypeScript syntax throughout, consider updating the parser to use the extended TypeScript parser here as well.Apply this diff to update the parsing method:
try { - walk(this.parse(code, { + walk(acorn.Parser.extend(tsPlugin()).parse(code, { sourceType: 'module', ecmaVersion: 'latest', }) as Node, {packages/nuxt/src/pages/utils.ts (2)
230-233: Type assertion 'as unknown as Program' may be too genericUsing
as unknown as Programcould mask potential type inconsistencies. Consider using a more precise type assertion to enhance type safety.Apply this diff to improve the type assertion:
-}) as unknown as Program +}) as ProgramIf the
parsemethod returns an AST compatible withProgram, this change ensures type correctness.
245-251: Inconsistent use of single and double quotesThe code uses both single (
' ') and double (" ") quotes for strings. To adhere to the project's style guidelines and resolve the ESLint errors, please use single quotes consistently.Apply the following diff to correct the quote usage:
-if ((node.type !== "ArrowFunctionExpression" && node.type !== 'ExpressionStatement') +if ((node.type !== 'ArrowFunctionExpression' && node.type !== 'ExpressionStatement')Repeat this change for lines 246 to 251 to address all instances:
- || (node.body.type !== "CallExpression" && node.expression.type !== 'CallExpression') + || (node.body.type !== 'CallExpression' && node.expression.type !== 'CallExpression') - || (node.body.callee.type !== "Identifier" && node.expression.callee.type !== 'Identifier') + || (node.body.callee.type !== 'Identifier' && node.expression.callee.type !== 'Identifier') - || (node.body.callee.name !== "definePageMeta" && node.expression.callee.name !== 'definePageMeta')) { return } + || (node.body.callee.name !== 'definePageMeta' && node.expression.callee.name !== 'definePageMeta')) { return }🧰 Tools
🪛 eslint (1.23.1)
[error] 245-245: Strings must use singlequote.
(@stylistic/quotes)
[error] 246-246: Strings must use singlequote.
(@stylistic/quotes)
[error] 247-247: Strings must use singlequote.
(@stylistic/quotes)
[error] 248-248: Strings must use singlequote.
(@stylistic/quotes)
[error] 251-251: Strings must use singlequote.
(@stylistic/quotes)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (5)
packages/nuxt/package.json(1 hunks)packages/nuxt/src/core/plugins/plugin-metadata.ts(2 hunks)packages/nuxt/src/core/plugins/prehydrate.ts(2 hunks)packages/nuxt/src/pages/route-rules.ts(2 hunks)packages/nuxt/src/pages/utils.ts(3 hunks)
🧰 Additional context used
🪛 eslint (1.23.1)
packages/nuxt/src/core/plugins/plugin-metadata.ts
[error] 52-52: Strings must use singlequote.
(@stylistic/quotes)
[error] 53-53: Strings must use singlequote.
(@stylistic/quotes)
packages/nuxt/src/pages/route-rules.ts
[error] 11-11: Expected 1 empty line after import statement not followed by another import.
(import/newline-after-import)
packages/nuxt/src/pages/utils.ts
[error] 245-245: Strings must use singlequote.
(@stylistic/quotes)
[error] 246-246: Strings must use singlequote.
(@stylistic/quotes)
[error] 247-247: Strings must use singlequote.
(@stylistic/quotes)
[error] 248-248: Strings must use singlequote.
(@stylistic/quotes)
[error] 251-251: Strings must use singlequote.
(@stylistic/quotes)
🔇 Additional comments (6)
packages/nuxt/src/pages/route-rules.ts (1)
29-32: LGTM! Parser configuration properly enables TypeScript support.
The integration of the TypeScript plugin and parser options is well implemented. The addition of locations: true will improve error reporting capabilities.
Let's verify the error handling with TypeScript syntax:
✅ Verification successful
Parser configuration is properly implemented with error handling
The implementation includes appropriate error handling for TypeScript syntax:
- The code uses
esbuildtransform withtsloader before parsing - Proper error handling is implemented for route rules parsing with a clear error message
- The parser configuration with TypeScript plugin is wrapped in a broader error handling context
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for TypeScript-specific error handling cases in the codebase
# Search for TypeScript-specific test cases
rg -l "defineRouteRules.*@.*decorator" || echo "No TypeScript decorator tests found"
# Look for error handling patterns around defineRouteRules
rg "defineRouteRules.*try.*catch" -A 5
Length of output: 162
Script:
#!/bin/bash
# Let's verify the error handling implementation around the parser
# Check the implementation of error handling in the route-rules file
rg "walk.*acorn" -A 10 packages/nuxt/src/pages/route-rules.ts
# Look for test files related to route rules
fd "route-rules.test" -t f
# Check for any TypeScript-specific test files
fd "route-rules.*ts" -t f
# Look for any error handling patterns in the route rules implementation
rg "try.*catch.*walk" -A 10 packages/nuxt/src/pages/route-rules.ts
Length of output: 768
Script:
#!/bin/bash
# Let's check the broader context of the file to understand error handling
# Get the full content of route-rules.ts to see the complete implementation
cat packages/nuxt/src/pages/route-rules.ts
# Look for any test files that might test error cases
fd test -t f | rg -i "route|rules"
Length of output: 2430
packages/nuxt/src/core/plugins/prehydrate.ts (2)
8-9: LGTM: Import statements for TypeScript support
The addition of acorn and its TypeScript plugin aligns with the PR's objective to support TypeScript parsing.
25-28: Verify TypeScript parsing with edge cases
The TypeScript parser integration looks good. However, we should verify it handles all decorator scenarios correctly.
✅ Verification successful
Based on the analysis of the shell script outputs, I can now make a definitive assessment. The codebase shows that the TypeScript parser integration is used primarily for parsing definePageMeta, defineRouteRules, and other similar constructs. The parser configuration with locations: true is consistent across multiple files and is used to provide proper source mapping information.
TypeScript parser integration is correctly configured
The parser extension with TypeScript support is properly implemented and used consistently throughout the codebase. The addition of locations: true is necessary for source mapping and is used by other parsers in the codebase (e.g., in route-rules.ts, page-meta.ts).
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for Vue components using decorators in test files
rg -l "@Component|@Prop|@Watch|@Emit" --type ts
# Search for definePageMeta usage with decorators
rg -A 5 "definePageMeta.*@" --type ts
Length of output: 89
Script:
#!/bin/bash
# Let's analyze the actual usage of the parser in the codebase
ast-grep --pattern 'walk($$$)'
# Check for any TypeScript-specific syntax in the files being parsed
rg -A 5 "definePageMeta" --type ts
# Look for actual decorator usage in the codebase
rg -A 5 "@\w+" --type ts
# Check the test files to see if they cover TypeScript parsing
fd "test" -e ts -x cat {}
Length of output: 101289
packages/nuxt/package.json (1)
74-74: Verify security and stability of acorn-typescript.
Let's verify the latest stable version and check for any security advisories for the new dependency.
✅ Verification successful
✓ acorn-typescript version is up-to-date and secure
The package version 1.4.13 specified in package.json matches the latest version available on NPM, and there are no known security vulnerabilities reported in GitHub's advisory database.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check latest versions and security advisories for acorn-typescript
# Check NPM for latest versions
echo "Latest version from NPM:"
curl -s https://registry.npmjs.org/acorn-typescript/latest | jq '.version'
# Check for security advisories
echo "Security advisories from GitHub:"
gh api graphql -f query='
{
securityVulnerabilities(first: 5, ecosystem: NPM, package: "acorn-typescript") {
nodes {
advisory {
summary
severity
publishedAt
}
vulnerableVersionRange
firstPatchedVersion {
identifier
}
}
}
}'
Length of output: 567
packages/nuxt/src/core/plugins/plugin-metadata.ts (1)
12-13: Import acorn and acorn-typescript for TypeScript parsing
The addition of the acorn and acorn-typescript imports correctly enables TypeScript parsing capabilities.
packages/nuxt/src/pages/utils.ts (1)
14-15: Properly imported acorn and acorn-typescript for TypeScript parsing
The inclusion of acorn and acorn-typescript imports correctly configures the parser to handle TypeScript syntax, which addresses the issue of parsing errors when processing TypeScript code with decorators.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (1)
packages/nuxt/src/core/plugins/plugin-metadata.ts (1)
51-54: Consider caching parsed AST for performanceWhile the current implementation works well, consider caching the parsed AST for frequently accessed plugins to improve performance, especially in development mode where plugins are parsed multiple times.
Example approach:
const astCache = new Map<string, Node>(); function getParsedAST(code: string) { if (astCache.has(code)) { return astCache.get(code); } const ast = acorn.Parser.extend(tsPlugin()).parse(code, { sourceType: 'module', ecmaVersion: 'latest', locations: true }); astCache.set(code, ast); return ast; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
packages/nuxt/src/core/plugins/plugin-metadata.ts(2 hunks)
🔇 Additional comments (2)
packages/nuxt/src/core/plugins/plugin-metadata.ts (2)
12-13: LGTM: Imports for TypeScript parsing support
The addition of acorn and its TypeScript plugin is appropriate for enabling TypeScript parsing capabilities.
51-54: Verify TypeScript decorator parsing support
The parser configuration looks good with TypeScript support enabled. Let's verify it handles decorators correctly.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (2)
packages/nuxt/src/pages/utils.ts (2)
230-234: Add error handling for parser initializationWhile the TypeScript plugin integration is correct, consider adding error handling for parser initialization to gracefully handle potential plugin loading failures.
- const ast = acorn.Parser.extend(tsPlugin()).parse(js.code, { + let parser; + try { + parser = acorn.Parser.extend(tsPlugin()); + } catch (err) { + console.warn('[nuxt] Failed to initialize TypeScript parser:', err); + parser = acorn.Parser; + } + const ast = parser.parse(js.code, { sourceType: 'module', ecmaVersion: 'latest', locations: true, ranges: true, }) as unknown as Program
245-248: Improve readability of node type checkingThe complex condition makes the code hard to maintain. Consider extracting the conditions into named functions for better readability.
+ function isArrowOrExpressionStatement(node: any): boolean { + return node.type === 'ArrowFunctionExpression' || node.type === 'ExpressionStatement'; + } + + function isDefinePageMetaCall(node: any): boolean { + const callExpr = node.body?.type === 'CallExpression' ? node.body : node.expression; + return callExpr?.type === 'CallExpression' && + callExpr?.callee?.type === 'Identifier' && + callExpr?.callee?.name === 'definePageMeta'; + } + - if ((node.type !== 'ArrowFunctionExpression' && node.type !== 'ExpressionStatement') - || (node.body.type !== 'CallExpression' && node.expression.type !== 'CallExpression') - || (node.body.callee.type !== 'Identifier' && node.expression.callee.type !== 'Identifier') - || (node.body.callee.name !== 'definePageMeta' && node.expression.callee.name !== 'definePageMeta')) { return } + if (!isArrowOrExpressionStatement(node) || !isDefinePageMetaCall(node)) { return }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (2)
packages/nuxt/src/pages/route-rules.ts(2 hunks)packages/nuxt/src/pages/utils.ts(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/nuxt/src/pages/route-rules.ts
🔇 Additional comments (2)
packages/nuxt/src/pages/utils.ts (2)
14-15: LGTM: Import changes for TypeScript support
The change from direct parse import to namespace import and addition of acorn-typescript plugin aligns with the PR objective to support TypeScript decorators.
Line range hint 230-253: Verify decorator parsing functionality
Let's verify that the changes correctly handle TypeScript decorators in the codebase.
packages/nuxt/src/pages/utils.ts
Outdated
| const pageMetaArgument = node.type !== 'ArrowFunctionExpression' | ||
| ? ((node as ExpressionStatement).body as any).arguments[0] as ObjectExpression | ||
| : ((node as ExpressionStatement).expression as CallExpression).arguments[0] as ObjectExpression |
There was a problem hiding this comment.
Add type safety for node property access
The current implementation assumes properties exist without checking, which could lead to runtime errors. Add proper type guards and null checks.
- const pageMetaArgument = node.type !== 'ArrowFunctionExpression'
- ? ((node as ExpressionStatement).body as any).arguments[0] as ObjectExpression
- : ((node as ExpressionStatement).expression as CallExpression).arguments[0] as ObjectExpression
+ const getArguments = (node: any): ObjectExpression | undefined => {
+ if (node.type !== 'ArrowFunctionExpression') {
+ return node?.body?.arguments?.[0];
+ }
+ return node?.expression?.arguments?.[0];
+ };
+
+ const pageMetaArgument = getArguments(node);
+ if (!pageMetaArgument) {
+ console.warn('[nuxt] Invalid definePageMeta call structure');
+ return;
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const pageMetaArgument = node.type !== 'ArrowFunctionExpression' | |
| ? ((node as ExpressionStatement).body as any).arguments[0] as ObjectExpression | |
| : ((node as ExpressionStatement).expression as CallExpression).arguments[0] as ObjectExpression | |
| const getArguments = (node: any): ObjectExpression | undefined => { | |
| if (node.type !== 'ArrowFunctionExpression') { | |
| return node?.body?.arguments?.[0]; | |
| } | |
| return node?.expression?.arguments?.[0]; | |
| }; | |
| const pageMetaArgument = getArguments(node); | |
| if (!pageMetaArgument) { | |
| console.warn('[nuxt] Invalid definePageMeta call structure'); | |
| return; | |
| } |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (2)
packages/nuxt/src/pages/utils.ts (2)
230-233: Consider using a more type-safe approach for AST parsing.While the TypeScript plugin integration is good, the double type assertion (
unknowntoProgram) could be made more type-safe.Consider this alternative:
- const ast = acorn.Parser.extend(tsPlugin()).parse(js.code, { + const parser = acorn.Parser.extend(tsPlugin()) + const ast = parser.parse(js.code, { sourceType: 'module', ecmaVersion: 'latest', locations: true, ranges: true, - }) as unknown as Program + }) as Program
245-248: Consider improving the readability of the node type checks.While splitting the conditions improves readability, it could be further enhanced by extracting them into a helper function.
Consider this approach:
+ function isPageMetaCall(node: any, type: string, bodyPath: string[]): boolean { + if (node.type !== type) return false + let current: any = node + for (const prop of bodyPath) { + current = current[prop] + if (!current) return false + } + return current.type === 'Identifier' && current.name === 'definePageMeta' + } + - const notExpressionStatement = node.type !== 'ExpressionStatement' || node.expression.type !== 'CallExpression' || node.expression.callee.type !== 'Identifier' || node.expression.callee.name !== 'definePageMeta' - const notArrowFunctionExpression = node.type !== 'ArrowFunctionExpression' || node.body.type !== 'CallExpression' || node.body.callee.type !== 'Identifier' || node.body.callee.name !== 'definePageMeta' - - if (notExpressionStatement && notArrowFunctionExpression) { return } + const isValidExpression = isPageMetaCall(node, 'ExpressionStatement', ['expression', 'callee']) || + isPageMetaCall(node, 'ArrowFunctionExpression', ['body', 'callee']) + + if (!isValidExpression) { return }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
packages/nuxt/src/pages/utils.ts(3 hunks)
🔇 Additional comments (2)
packages/nuxt/src/pages/utils.ts (2)
14-15: LGTM! Import changes align with TypeScript support requirements.
The switch to namespace import and addition of the TypeScript plugin provides the necessary foundation for parsing TypeScript code with decorators.
230-233: Verify TypeScript decorator parsing.
Let's ensure the TypeScript plugin correctly handles decorator syntax in Vue components.
✅ Verification successful
Based on the shell script results, I can now provide a final response:
TypeScript decorator support is properly implemented
The implementation in packages/nuxt/src/pages/utils.ts correctly uses acorn with the TypeScript plugin to parse both JavaScript and TypeScript code, including decorators. The evidence shows:
-
The parser is configured with proper settings:
const ast = acorn.Parser.extend(tsPlugin()).parse(js.code, { sourceType: 'module', ecmaVersion: 'latest', locations: true })
-
The same TypeScript-enabled parser configuration is consistently used across the codebase in multiple locations:
packages/nuxt/src/pages/route-rules.tspackages/nuxt/src/core/plugins/prehydrate.tspackages/nuxt/src/core/plugins/plugin-metadata.ts
-
The code is first transformed through esbuild before parsing, ensuring proper TypeScript handling:
const js = await transform(script.code, { loader: script.loader })
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for files using decorators with definePageMeta
ast-grep --pattern 'class $_ {
$$$
@$_($$$)
$$$
definePageMeta($$$)
$$$
}'
# Search for Vue components using vue-class-decorator
rg "@Component.*definePageMeta" -A 5
Length of output: 125
Script:
#!/bin/bash
# Let's try a different approach to verify decorator handling
# First, check if there are any TypeScript files with decorators in the test files
rg "@\w+" "test" -l --type ts
# Look for any existing decorator usage in the codebase
rg "@\w+" --type ts -l
# Check the test cases specifically testing the parser
fd "parser|utils.*test" -e ts -e js | xargs cat
# Look at the implementation to understand decorator handling
rg "tsPlugin|acorn.*parse" -A 5 -B 5
Length of output: 23605
|
this is great work - thank you ❤️ I think we can alternatively resolve this in #30066 by adopting |
🔗 Linked issue
resolves #29790
📚 Description
Ts code with decorators is passed to acorn.parse which can parse only js code.
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes