diff --git a/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-props/access-props-27.input.tsx b/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-props/access-props-27.input.tsx
new file mode 100644
index 0000000000000..b48cfeedc80f1
--- /dev/null
+++ b/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-props/access-props-27.input.tsx
@@ -0,0 +1,28 @@
+interface Props {
+ params: {
+ slug: string;
+ }
+}
+
+export function generateMetadata(props: Props, parent: any) {
+ console.log({ ...parent })
+}
+
+export default async function Page(props: Props) {
+ const config = { ...props }
+ return (
+
+ )
+}
+
+export function GET(req, ctx) {
+ console.log(
+ { ...ctx }
+ )
+}
+
+export function POST(req, ctx) {
+ console.log(
+ { ...req }
+ )
+}
diff --git a/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-props/access-props-27.output.tsx b/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-props/access-props-27.output.tsx
new file mode 100644
index 0000000000000..1ff3c160564c3
--- /dev/null
+++ b/packages/next-codemod/transforms/__testfixtures__/next-async-request-api-dynamic-props/access-props-27.output.tsx
@@ -0,0 +1,31 @@
+interface Props {
+ params: Promise<{
+ slug: string;
+ }>
+}
+
+export function generateMetadata(props: Props, parent: any) {
+ console.log({ ...parent })
+}
+
+export default async function Page(props: Props) {
+ const config = { /* Next.js Dynamic Async API Codemod: 'props' is used with spread syntax (...). Any asynchronous properties of 'props' must be awaited when accessed. */
+ ...props }
+ return (
+ ()
+ );
+}
+
+export function GET(req, ctx) {
+ console.log(
+ { /* Next.js Dynamic Async API Codemod: 'ctx' is used with spread syntax (...). Any asynchronous properties of 'ctx' must be awaited when accessed. */
+ ...ctx }
+ )
+}
+
+export function POST(req, ctx) {
+ console.log(
+ { ...req }
+ )
+}
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 f720e9217ea0a..98a68e0cb4548 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
@@ -433,6 +433,13 @@ export function transformDynamicProps(
// Override the first param to `props`
params[propsArgumentIndex] = propsIdentifier
+ modified = true
+ }
+ } else {
+ // When the prop argument is not destructured, we need to add comments to the spread properties
+ if (j.Identifier.check(currentParam)) {
+ commentSpreadProps(path, currentParam.name, j)
+ modifyTypes(currentParam.typeAnnotation, propsIdentifier, root, j)
modified = true
}
}
@@ -812,3 +819,30 @@ function findAllTypes(
return types
}
+
+function commentSpreadProps(
+ path: ASTPath,
+ propsIdentifierName: string,
+ j: API['jscodeshift']
+) {
+ const functionBody = findFunctionBody(path)
+ const functionBodyCollection = j(functionBody)
+ // Find all the usage of spreading properties of `props`
+ const jsxSpreadProperties = functionBodyCollection.find(
+ j.JSXSpreadAttribute,
+ { argument: { name: propsIdentifierName } }
+ )
+ const objSpreadProperties = functionBodyCollection.find(j.SpreadElement, {
+ argument: { name: propsIdentifierName },
+ })
+ const comment = ` Next.js Dynamic Async API Codemod: '${propsIdentifierName}' is used with spread syntax (...). Any asynchronous properties of '${propsIdentifierName}' must be awaited when accessed. `
+
+ // Add comment before it
+ jsxSpreadProperties.forEach((spread) => {
+ insertCommentOnce(spread.value, j, comment)
+ })
+
+ objSpreadProperties.forEach((spread) => {
+ insertCommentOnce(spread.value, j, comment)
+ })
+}