@@ -36,6 +36,127 @@ const mapNativeType = (/** @type {string} */ nativeType) => {
3636 }
3737}
3838
39+ /**
40+ * @param {ComponentProp } prop
41+ * @param {SourceCode } sourceCode
42+ */
43+ function getComponentPropData ( prop , sourceCode ) {
44+ const unknownType = {
45+ name : prop . propName ,
46+ type : 'unknown' ,
47+ required : undefined ,
48+ defaultValue : undefined
49+ }
50+
51+ if ( prop . type !== 'object' ) {
52+ return unknownType
53+ }
54+ const type = optionGetType ( prop . value , sourceCode )
55+ if ( type === null ) {
56+ return unknownType
57+ }
58+ const required = optionGetRequired ( prop . value )
59+ const defaultValue = optionGetDefault ( prop . value )
60+
61+ return {
62+ name : prop . propName ,
63+ type : mapNativeType ( type ) ,
64+ required,
65+ defaultValue
66+ }
67+ }
68+
69+ /**
70+ * @param {Expression } node
71+ * @param {SourceCode } sourceCode
72+ * @returns {string | null }
73+ */
74+ function optionGetType ( node , sourceCode ) {
75+ switch ( node . type ) {
76+ case 'Identifier' : {
77+ return node . name
78+ }
79+ case 'ObjectExpression' : {
80+ // foo: {
81+ const typeProperty = utils . findProperty ( node , 'type' )
82+ if ( typeProperty == null ) {
83+ return null
84+ }
85+ if ( typeProperty . value . type === 'TSAsExpression' ) {
86+ const typeAnnotation = typeProperty . value . typeAnnotation
87+ if ( typeAnnotation . typeName . name !== 'PropType' ) {
88+ return null
89+ }
90+
91+ // in some project configuration parser populates deprecated field `typeParameters` instead of `typeArguments`
92+ const typeArguments =
93+ 'typeArguments' in typeProperty . value
94+ ? typeAnnotation . typeArguments
95+ : typeAnnotation . typeParameters
96+
97+ const typeArgument = Array . isArray ( typeArguments )
98+ ? typeArguments [ 0 ] . params [ 0 ]
99+ : typeArguments . params [ 0 ]
100+
101+ if ( typeArgument === undefined ) {
102+ return null
103+ }
104+
105+ return sourceCode . getText ( typeArgument )
106+ }
107+ return optionGetType ( typeProperty . value , sourceCode )
108+ }
109+ case 'ArrayExpression' : {
110+ return null
111+ }
112+ case 'FunctionExpression' :
113+ case 'ArrowFunctionExpression' : {
114+ return null
115+ }
116+ }
117+
118+ // Unknown
119+ return null
120+ }
121+
122+ /**
123+ * @param {Expression } node
124+ * @returns {boolean | undefined }
125+ */
126+ function optionGetRequired ( node ) {
127+ if ( node . type === 'ObjectExpression' ) {
128+ const requiredProperty = utils . findProperty ( node , 'required' )
129+ if ( requiredProperty == null ) {
130+ return undefined
131+ }
132+
133+ if ( requiredProperty . value . type === 'Literal' ) {
134+ return Boolean ( requiredProperty . value . value )
135+ }
136+ }
137+
138+ // Unknown
139+ return undefined
140+ }
141+
142+ /**
143+ * @param {Expression } node
144+ * @returns {Expression | undefined }
145+ */
146+ function optionGetDefault ( node ) {
147+ if ( node . type === 'ObjectExpression' ) {
148+ const defaultProperty = utils . findProperty ( node , 'default' )
149+ if ( defaultProperty == null ) {
150+ return undefined
151+ }
152+
153+ return defaultProperty . value
154+ }
155+
156+ // Unknown
157+ return undefined
158+ }
159+
39160/**
40161 * @typedef {import('../utils').ComponentProp } ComponentProp
41162 */
@@ -72,93 +193,6 @@ module.exports = {
72193 create ( context ) {
73194 const sourceCode = context . getSourceCode ( )
74195
75- /**
76- * @param {Expression } node
77- * @returns {string | null }
78- */
79- function optionGetType ( node ) {
80- switch ( node . type ) {
81- case 'Identifier' : {
82- return node . name
83- }
84- case 'ObjectExpression' : {
85- // foo: {
86- const typeProperty = utils . findProperty ( node , 'type' )
87- if ( typeProperty == null ) {
88- return null
89- }
90- if ( typeProperty . value . type === 'TSAsExpression' ) {
91- if (
92- typeProperty . value . typeAnnotation . typeName . name !== 'PropType'
93- ) {
94- return null
95- }
96-
97- const typeArgument =
98- typeProperty . value . typeAnnotation . typeArguments . params [ 0 ]
99- if ( typeArgument === undefined ) {
100- return null
101- }
102-
103- return sourceCode . getText ( typeArgument )
104- }
105- return optionGetType ( typeProperty . value )
106- }
107- case 'ArrayExpression' : {
108- // foo: [
109- return null
110- // return node.elements.map((arrayElement) =>
111- // optionGetType(arrayElement)
112- // )
113- }
114- case 'FunctionExpression' :
115- case 'ArrowFunctionExpression' : {
116- return null
117- }
118- }
119-
120- // Unknown
121- return null
122- }
123-
124- /**
125- * @param {Expression } node
126- * @returns {boolean | undefined }
127- */
128- function optionGetRequired ( node ) {
129- if ( node . type === 'ObjectExpression' ) {
130- const requiredProperty = utils . findProperty ( node , 'required' )
131- if ( requiredProperty == null ) {
132- return undefined
133- }
134-
135- if ( requiredProperty . value . type === 'Literal' ) {
136- return Boolean ( requiredProperty . value . value )
137- }
138- }
139-
140- // Unknown
141- return undefined
142- }
143-
144- /**
145- * @param {Expression } node
146- * @returns {Expression | undefined }
147- */
148- function optionGetDefault ( node ) {
149- if ( node . type === 'ObjectExpression' ) {
150- const defaultProperty = utils . findProperty ( node , 'default' )
151- if ( defaultProperty == null ) {
152- return undefined
153- }
154-
155- return defaultProperty . value
156- }
157-
158- // Unknown
159- return undefined
160- }
161-
162196 const scriptSetup = utils . getScriptSetupElement ( context )
163197 if ( ! scriptSetup || ! utils . hasAttribute ( scriptSetup , 'lang' , 'ts' ) ) {
164198 return { }
@@ -176,31 +210,9 @@ module.exports = {
176210 node,
177211 messageId : 'hasArg' ,
178212 * fix ( fixer ) {
179- const propTypes = props . map ( ( prop ) => {
180- const unknownType = {
181- name : prop . propName ,
182- type : 'unknown' ,
183- required : undefined ,
184- defaultValue : undefined
185- }
186-
187- if ( prop . type !== 'object' ) {
188- return unknownType
189- }
190- const type = optionGetType ( prop . value )
191- if ( type === null ) {
192- return unknownType
193- }
194- const required = optionGetRequired ( prop . value )
195- const defaultValue = optionGetDefault ( prop . value )
196-
197- return {
198- name : prop . propName ,
199- type : mapNativeType ( type ) ,
200- required,
201- defaultValue
202- }
203- } )
213+ const propTypes = props . map ( ( prop ) =>
214+ getComponentPropData ( prop , sourceCode )
215+ )
204216
205217 const definePropsType = `{ ${ propTypes
206218 . map (
@@ -209,8 +221,10 @@ module.exports = {
209221 )
210222 . join ( ', ' ) } }`
211223
224+ // remove defineProps function parameters
212225 yield fixer . replaceText ( node . arguments [ 0 ] , '' )
213226
227+ // add type annotation
214228 if ( separateInterface ) {
215229 const variableDeclarationNode = node . parent . parent
216230 if ( ! variableDeclarationNode ) return
@@ -227,6 +241,7 @@ module.exports = {
227241 )
228242 }
229243
244+ // add defaults if needed
230245 const defaults = propTypes . filter (
231246 ( { defaultValue } ) => defaultValue
232247 )
0 commit comments