Skip to content

Commit f0294e8

Browse files
committed
feat: autofix in define-props-declaration: runtime syntax to type-based syntax (vuejs#2465)
handle default option
1 parent 99e2f3e commit f0294e8

File tree

2 files changed

+71
-7
lines changed

2 files changed

+71
-7
lines changed

Diff for: lib/rules/define-props-declaration.js

+45-5
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ module.exports = {
6262
/** @param {RuleContext} context */
6363
create(context) {
6464
const sourceCode = context.getSourceCode()
65+
6566
/**
6667
* @param {Expression} node
6768
* @returns {string | null}
@@ -131,6 +132,24 @@ module.exports = {
131132
return undefined
132133
}
133134

135+
/**
136+
* @param {Expression} node
137+
* @returns {Expression | undefined }
138+
*/
139+
function optionGetDefault(node) {
140+
if (node.type === 'ObjectExpression') {
141+
const defaultProperty = utils.findProperty(node, 'default')
142+
if (defaultProperty == null) {
143+
return undefined
144+
}
145+
146+
return defaultProperty.value
147+
}
148+
149+
// Unknown
150+
return undefined
151+
}
152+
134153
const scriptSetup = utils.getScriptSetupElement(context)
135154
if (!scriptSetup || !utils.hasAttribute(scriptSetup, 'lang', 'ts')) {
136155
return {}
@@ -147,7 +166,12 @@ module.exports = {
147166
messageId: 'hasArg',
148167
*fix(fixer) {
149168
const propTypes = props.map((prop) => {
150-
const unknownType = { name: prop.propName, type: 'unknown', required: undefined }
169+
const unknownType = {
170+
name: prop.propName,
171+
type: 'unknown',
172+
required: undefined,
173+
defaultValue: undefined
174+
}
151175

152176
if (prop.type !== 'object') {
153177
return unknownType
@@ -157,26 +181,42 @@ module.exports = {
157181
return unknownType
158182
}
159183
const required = optionGetRequired(prop.value)
184+
const defaultValue = optionGetDefault(prop.value)
160185

161186
return {
162187
name: prop.propName,
163188
type: mapNativeType(type),
164-
required
189+
required,
190+
defaultValue
165191
}
166192
})
167193

168194
const definePropsType = `{ ${propTypes
169195
.map(
170-
({ name, type, required }) =>
171-
`${name}${required === false ? '?' : ''}: ${type}`
196+
({ name, type, required, defaultValue }) =>
197+
`${name}${(required === false || defaultValue) ? '?' : ''}: ${type}`
172198
)
173199
.join(', ')} }`
174200

201+
yield fixer.replaceText(node.arguments[0], '')
175202
yield fixer.insertTextAfter(
176203
node.callee,
177204
`<${definePropsType}>`
178205
)
179-
yield fixer.replaceText(node.arguments[0], '')
206+
const defaults = propTypes.filter(
207+
({ defaultValue }) => defaultValue
208+
)
209+
if (defaults.length > 0) {
210+
const defaultsCode = defaults
211+
.map(
212+
({ name, defaultValue }) =>
213+
`${name}: ${sourceCode.getText(defaultValue)}`
214+
)
215+
.join(', ')
216+
217+
yield fixer.insertTextBefore(node, `withDefaults(`)
218+
yield fixer.insertTextAfter(node, `, { ${defaultsCode} })`)
219+
}
180220
}
181221
})
182222
}

Diff for: tests/lib/rules/define-props-declaration.js

+26-2
Original file line numberDiff line numberDiff line change
@@ -344,8 +344,7 @@ tester.run('define-props-declaration', rule, {
344344
<script setup lang="ts">
345345
const props = defineProps({
346346
kind: {
347-
type: Array as PropType<string[]>,
348-
default: () => []
347+
type: Array as PropType<string[]>
349348
}
350349
})
351350
</script>
@@ -436,6 +435,31 @@ tester.run('define-props-declaration', rule, {
436435
line: 3
437436
}
438437
]
438+
},
439+
// default value
440+
{
441+
filename: 'test.vue',
442+
code: `
443+
<script setup lang="ts">
444+
const props = defineProps({
445+
kind: {
446+
type: String,
447+
default: 'foo'
448+
}
449+
})
450+
</script>
451+
`,
452+
output: `
453+
<script setup lang="ts">
454+
const props = withDefaults(defineProps<{ kind?: string }>(), { kind: 'foo' })
455+
</script>
456+
`,
457+
errors: [
458+
{
459+
message: 'Use type-based declaration instead of runtime declaration.',
460+
line: 3
461+
}
462+
]
439463
}
440464
]
441465
})

0 commit comments

Comments
 (0)