@@ -7,16 +7,20 @@ import type {
77 MemberExpression ,
88 ObjectProperty ,
99 Property ,
10+ VariableDeclaration ,
11+ RestElement ,
1012} from "jscodeshift" ;
1113
12- import { getFunctionName } from "@codemod.com/codemod-utils/dist/jscodeshift/function.js" ;
13- import { getFunctionComponents } from "@codemod.com/codemod-utils/dist/jscodeshift/react.js" ;
14+ import {
15+ getFunctionName ,
16+ getFunctionComponents ,
17+ } from "@codemod.com/codemod-utils" ;
1418
1519const getComponentStaticPropValue = (
1620 j : JSCodeshift ,
1721 root : Collection < any > ,
1822 componentName : string ,
19- name : string ,
23+ name : string
2024) : ASTPath < MemberExpression > | null => {
2125 return (
2226 root
@@ -38,9 +42,8 @@ const getComponentStaticPropValue = (
3842const buildPropertyWithDefaultValue = (
3943 j : JSCodeshift ,
4044 property : ObjectProperty | Property ,
41- defaultValue : any ,
45+ defaultValue : any
4246) => {
43- // Special handling for nested destructuring patterns
4447 if ( property . value . type === "ObjectPattern" ) {
4548 return j . assignmentPattern ( property . value , defaultValue ) ;
4649 }
@@ -55,7 +58,7 @@ const buildPropertyWithDefaultValue = (
5558
5659export default function transform (
5760 file : FileInfo ,
58- api : API ,
61+ api : API
5962) : string | undefined {
6063 const j = api . jscodeshift ;
6164 const root = j ( file . source ) ;
@@ -68,11 +71,21 @@ export default function transform(
6871 return ;
6972 }
7073
74+ const componentFunction = j . functionDeclaration (
75+ j . identifier ( componentName ) ,
76+ path . value . params ,
77+ path . value . body
78+ ) ;
79+
80+ if ( componentFunction === null ) {
81+ return ;
82+ }
83+
7184 const defaultProps = getComponentStaticPropValue (
7285 j ,
7386 root ,
7487 componentName ,
75- "defaultProps" ,
88+ "defaultProps"
7689 ) ;
7790
7891 const defaultPropsRight = defaultProps ?. parent ?. value ?. right ?? null ;
@@ -82,17 +95,46 @@ export default function transform(
8295 }
8396
8497 const defaultPropsMap = new Map ( ) ;
98+ const defaultPropsConstants : VariableDeclaration [ ] = [ ] ;
8599
86100 defaultPropsRight . properties ?. forEach ( ( property ) => {
87101 if (
88102 ( j . Property . check ( property ) || j . ObjectProperty . check ( property ) ) &&
89103 j . Identifier . check ( property . key )
90104 ) {
91- defaultPropsMap . set ( property . key . name , property . value ) ;
105+ if (
106+ property . value . type === "ObjectExpression" ||
107+ property . value . type === "ArrayExpression" ||
108+ property . value . type === "ArrowFunctionExpression"
109+ ) {
110+ const constName = `${ componentName [ 0 ] ?. toLowerCase ( ) } ${ componentName . slice (
111+ 1
112+ ) } DefaultProp${
113+ property . key . name [ 0 ] ?. toUpperCase ( ) + property . key . name . slice ( 1 )
114+ } `;
115+ const constNamePath = root
116+ . find ( j . Identifier , {
117+ name : constName ,
118+ } )
119+ . paths ( ) ;
120+ if ( constNamePath . length ) {
121+ return defaultPropsMap . set ( property . key . name , property . value ) ;
122+ }
123+ defaultPropsConstants . push (
124+ j . variableDeclaration ( "const" , [
125+ j . variableDeclarator ( j . identifier ( constName ) , property . value ) ,
126+ ] )
127+ ) ;
128+ defaultPropsMap . set ( property . key . name , j . identifier ( constName ) ) ;
129+ } else {
130+ defaultPropsMap . set ( property . key . name , property . value ) ;
131+ }
92132 }
93133 } ) ;
94134
95135 const propsArg = path . value . params . at ( 0 ) ;
136+ let inlineDefaultProps : { key : string ; value : any } [ ] = [ ] ;
137+ let propsArgName : string | undefined ;
96138
97139 if ( j . ObjectPattern . check ( propsArg ) ) {
98140 propsArg . properties . forEach ( ( property ) => {
@@ -105,11 +147,62 @@ export default function transform(
105147 property . value = buildPropertyWithDefaultValue (
106148 j ,
107149 property ,
108- defaultPropsMap . get ( property . key . name ) ,
150+ defaultPropsMap . get ( property . key . name )
151+ ) ;
152+ defaultPropsMap . delete ( property . key . name ) ;
153+ }
154+ } else if ( j . RestElement . check ( property ) ) {
155+ const restElement = property as RestElement ;
156+ if ( j . Identifier . check ( restElement . argument ) ) {
157+ propsArgName = restElement . argument . name ;
158+ inlineDefaultProps = Array . from ( defaultPropsMap . entries ( ) ) . map (
159+ ( [ key , value ] ) => ( { key, value } )
109160 ) ;
110161 }
111162 }
112163 } ) ;
164+ } else if ( j . Identifier . check ( propsArg ) ) {
165+ propsArgName = propsArg . name ;
166+ inlineDefaultProps = Array . from ( defaultPropsMap . entries ( ) ) . map (
167+ ( [ key , value ] ) => ( { key, value } )
168+ ) ;
169+ }
170+
171+ if ( propsArgName && inlineDefaultProps . length ) {
172+ componentFunction . body . body . unshift (
173+ j . expressionStatement (
174+ j . assignmentExpression (
175+ "=" ,
176+ j . identifier ( propsArgName ) ,
177+ j . objectExpression ( [
178+ j . spreadElement ( j . identifier ( propsArgName ) ) ,
179+ ...inlineDefaultProps . map ( ( { key, value } ) =>
180+ j . objectProperty (
181+ j . identifier ( key ) ,
182+ j . conditionalExpression (
183+ j . binaryExpression (
184+ "===" ,
185+ j . unaryExpression (
186+ "typeof" ,
187+ j . identifier ( `${ propsArgName } .${ key } ` )
188+ ) ,
189+ j . literal ( "undefined" )
190+ ) ,
191+ value ,
192+ j . identifier ( `${ propsArgName } .${ key } ` )
193+ )
194+ )
195+ ) ,
196+ ] )
197+ )
198+ )
199+ ) ;
200+ }
201+
202+ if ( defaultPropsConstants . length && path . parent ) {
203+ for ( let defaultPropsConstant of defaultPropsConstants ) {
204+ path . parent . parent . insertBefore ( defaultPropsConstant ) ;
205+ }
113206 }
114207
115208 j ( defaultProps ) . closest ( j . ExpressionStatement ) . remove ( ) ;
0 commit comments