Skip to content

Commit 99e2f3e

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

File tree

2 files changed

+80
-7
lines changed

2 files changed

+80
-7
lines changed

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

+30-7
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,8 @@ module.exports = {
8989
if (typeArgument === undefined) {
9090
return null
9191
}
92-
93-
const text = sourceCode.getText(typeArgument)
94-
95-
return text
92+
93+
return sourceCode.getText(typeArgument)
9694
}
9795
return optionGetType(typeProperty.value)
9896
}
@@ -113,6 +111,26 @@ module.exports = {
113111
return null
114112
}
115113

114+
/**
115+
* @param {Expression} node
116+
* @returns {boolean | undefined }
117+
*/
118+
function optionGetRequired(node) {
119+
if (node.type === 'ObjectExpression') {
120+
const requiredProperty = utils.findProperty(node, 'required')
121+
if (requiredProperty == null) {
122+
return undefined
123+
}
124+
125+
if (requiredProperty.value.type === 'Literal') {
126+
return Boolean(requiredProperty.value.value)
127+
}
128+
}
129+
130+
// Unknown
131+
return undefined
132+
}
133+
116134
const scriptSetup = utils.getScriptSetupElement(context)
117135
if (!scriptSetup || !utils.hasAttribute(scriptSetup, 'lang', 'ts')) {
118136
return {}
@@ -129,7 +147,7 @@ module.exports = {
129147
messageId: 'hasArg',
130148
*fix(fixer) {
131149
const propTypes = props.map((prop) => {
132-
const unknownType = { name: prop.propName, type: 'unknown' }
150+
const unknownType = { name: prop.propName, type: 'unknown', required: undefined }
133151

134152
if (prop.type !== 'object') {
135153
return unknownType
@@ -138,15 +156,20 @@ module.exports = {
138156
if (type === null) {
139157
return unknownType
140158
}
159+
const required = optionGetRequired(prop.value)
141160

142161
return {
143162
name: prop.propName,
144-
type: mapNativeType(type)
163+
type: mapNativeType(type),
164+
required
145165
}
146166
})
147167

148168
const definePropsType = `{ ${propTypes
149-
.map(({ name, type }) => `${name}: ${type}`)
169+
.map(
170+
({ name, type, required }) =>
171+
`${name}${required === false ? '?' : ''}: ${type}`
172+
)
150173
.join(', ')} }`
151174

152175
yield fixer.insertTextAfter(

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

+50
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,56 @@ tester.run('define-props-declaration', rule, {
386386
line: 3
387387
}
388388
]
389+
},
390+
// required
391+
{
392+
filename: 'test.vue',
393+
code: `
394+
<script setup lang="ts">
395+
const props = defineProps({
396+
kind: {
397+
type: String,
398+
required: true
399+
}
400+
})
401+
</script>
402+
`,
403+
output: `
404+
<script setup lang="ts">
405+
const props = defineProps<{ kind: string }>()
406+
</script>
407+
`,
408+
errors: [
409+
{
410+
message: 'Use type-based declaration instead of runtime declaration.',
411+
line: 3
412+
}
413+
]
414+
},
415+
// not required
416+
{
417+
filename: 'test.vue',
418+
code: `
419+
<script setup lang="ts">
420+
const props = defineProps({
421+
kind: {
422+
type: String,
423+
required: false
424+
}
425+
})
426+
</script>
427+
`,
428+
output: `
429+
<script setup lang="ts">
430+
const props = defineProps<{ kind?: string }>()
431+
</script>
432+
`,
433+
errors: [
434+
{
435+
message: 'Use type-based declaration instead of runtime declaration.',
436+
line: 3
437+
}
438+
]
389439
}
390440
]
391441
})

0 commit comments

Comments
 (0)