From db78f55b01271312ca7cfdec2f53328e5721171e Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 10 Oct 2024 01:50:47 +0200 Subject: [PATCH] codemod: if params is awaited then skip (#71060) --- .../access-props-31.input.tsx | 12 ++++++ .../access-props-31.output.tsx | 12 ++++++ .../next-async-dynamic-prop.ts | 41 +++++++++++++++---- 3 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-props/access-props-31.input.tsx create mode 100644 packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-props/access-props-31.output.tsx diff --git a/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-props/access-props-31.input.tsx b/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-props/access-props-31.input.tsx new file mode 100644 index 0000000000000..a7a63c5753594 --- /dev/null +++ b/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-props/access-props-31.input.tsx @@ -0,0 +1,12 @@ +export async function GET( + req: NextRequest, + { + params, + }: { + params: Promise<{ + slug: string; + }>; + }, +): Promise { + const { slug } = await params; +} diff --git a/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-props/access-props-31.output.tsx b/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-props/access-props-31.output.tsx new file mode 100644 index 0000000000000..a7a63c5753594 --- /dev/null +++ b/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-props/access-props-31.output.tsx @@ -0,0 +1,12 @@ +export async function GET( + req: NextRequest, + { + params, + }: { + params: Promise<{ + slug: string; + }>; + }, +): Promise { + const { slug } = await params; +} diff --git a/packages/next-codemod/transforms/lib/async-request-api/next-async-dynamic-prop.ts b/packages/next-codemod/transforms/lib/async-request-api/next-async-dynamic-prop.ts index 94faa530df5d9..df62c81754629 100644 --- a/packages/next-codemod/transforms/lib/async-request-api/next-async-dynamic-prop.ts +++ b/packages/next-codemod/transforms/lib/async-request-api/next-async-dynamic-prop.ts @@ -653,10 +653,10 @@ export function transformDynamicProps( } } - const propRenamedId = j.Identifier.check(paramsProperty) + const paramsPropertyName = j.Identifier.check(paramsProperty) ? paramsProperty.name : null - const propName = propRenamedId || matchedPropName + const paramPropertyName = paramsPropertyName || matchedPropName // if propName is not used in lower scope, and it stars with unused prefix `_`, // also skip the transformation @@ -665,11 +665,36 @@ export function transformDynamicProps( const hasUsedInBody = j(functionBodyPath) .find(j.Identifier, { - name: propName, + name: paramPropertyName, }) .size() > 0 - if (!hasUsedInBody && propName.startsWith('_')) continue + if (!hasUsedInBody && paramPropertyName.startsWith('_')) continue + + // Search the usage of propName in the function body, + // if they're all awaited or wrapped with use(), skip the transformation + const propUsages = j(functionBodyPath).find(j.Identifier, { + name: paramPropertyName, + }) + + // if there's usage of the propName, then do the check + if (propUsages.size()) { + let hasMissingAwaited = false + propUsages.forEach((propUsage) => { + // If the parent is not AwaitExpression, it's not awaited + const isAwaited = + propUsage.parentPath?.value.type === 'AwaitExpression' + const isAwaitedByUse = isParentUseCallExpression(propUsage, j) + if (!isAwaited && !isAwaitedByUse) { + hasMissingAwaited = true + return + } + }) + // If all the usages of parm are awaited, skip the transformation + if (!hasMissingAwaited) { + continue + } + } modifiedPropertyCount++ @@ -683,7 +708,7 @@ export function transformDynamicProps( // e.g. // input: Page({ params: { slug } }) // output: const { slug } = await props.params; rather than const props = await props.params; - const uid = functionName + ':' + propName + const uid = functionName + ':' + paramPropertyName if (paramsProperty?.type === 'ObjectPattern') { const objectPattern = paramsProperty @@ -720,7 +745,7 @@ export function transformDynamicProps( // If it's async function, add await to the async props. const paramAssignment = j.variableDeclaration('const', [ j.variableDeclarator( - j.identifier(propName), + j.identifier(paramPropertyName), j.awaitExpression(accessedPropIdExpr) ), ]) @@ -742,7 +767,7 @@ export function transformDynamicProps( // Insert `const = await props.;` at the beginning of the function body const paramAssignment = j.variableDeclaration('const', [ j.variableDeclarator( - j.identifier(propName), + j.identifier(paramPropertyName), j.awaitExpression(accessedPropIdExpr) ), ]) @@ -755,7 +780,7 @@ export function transformDynamicProps( } else { const paramAssignment = j.variableDeclaration('const', [ j.variableDeclarator( - j.identifier(propName), + j.identifier(paramPropertyName), j.callExpression(j.identifier('use'), [accessedPropIdExpr]) ), ])