Skip to content

Commit

Permalink
feat: autofix in define-props-declaration: runtime syntax to type-b…
Browse files Browse the repository at this point in the history
…ased syntax (vuejs#2465)

handle default option
  • Loading branch information
mpiniarski committed May 27, 2024
1 parent 99e2f3e commit f0294e8
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 7 deletions.
50 changes: 45 additions & 5 deletions lib/rules/define-props-declaration.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ module.exports = {
/** @param {RuleContext} context */
create(context) {
const sourceCode = context.getSourceCode()

/**
* @param {Expression} node
* @returns {string | null}
Expand Down Expand Up @@ -131,6 +132,24 @@ module.exports = {
return undefined
}

/**
* @param {Expression} node
* @returns {Expression | undefined }
*/
function optionGetDefault(node) {
if (node.type === 'ObjectExpression') {
const defaultProperty = utils.findProperty(node, 'default')
if (defaultProperty == null) {
return undefined
}

return defaultProperty.value
}

// Unknown
return undefined
}

const scriptSetup = utils.getScriptSetupElement(context)
if (!scriptSetup || !utils.hasAttribute(scriptSetup, 'lang', 'ts')) {
return {}
Expand All @@ -147,7 +166,12 @@ module.exports = {
messageId: 'hasArg',
*fix(fixer) {
const propTypes = props.map((prop) => {
const unknownType = { name: prop.propName, type: 'unknown', required: undefined }
const unknownType = {
name: prop.propName,
type: 'unknown',
required: undefined,
defaultValue: undefined
}

if (prop.type !== 'object') {
return unknownType
Expand All @@ -157,26 +181,42 @@ module.exports = {
return unknownType
}
const required = optionGetRequired(prop.value)
const defaultValue = optionGetDefault(prop.value)

return {
name: prop.propName,
type: mapNativeType(type),
required
required,
defaultValue
}
})

const definePropsType = `{ ${propTypes
.map(
({ name, type, required }) =>
`${name}${required === false ? '?' : ''}: ${type}`
({ name, type, required, defaultValue }) =>
`${name}${(required === false || defaultValue) ? '?' : ''}: ${type}`
)
.join(', ')} }`

yield fixer.replaceText(node.arguments[0], '')
yield fixer.insertTextAfter(
node.callee,
`<${definePropsType}>`
)
yield fixer.replaceText(node.arguments[0], '')
const defaults = propTypes.filter(
({ defaultValue }) => defaultValue
)
if (defaults.length > 0) {
const defaultsCode = defaults
.map(
({ name, defaultValue }) =>
`${name}: ${sourceCode.getText(defaultValue)}`
)
.join(', ')

yield fixer.insertTextBefore(node, `withDefaults(`)
yield fixer.insertTextAfter(node, `, { ${defaultsCode} })`)
}
}
})
}
Expand Down
28 changes: 26 additions & 2 deletions tests/lib/rules/define-props-declaration.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,7 @@ tester.run('define-props-declaration', rule, {
<script setup lang="ts">
const props = defineProps({
kind: {
type: Array as PropType<string[]>,
default: () => []
type: Array as PropType<string[]>
}
})
</script>
Expand Down Expand Up @@ -436,6 +435,31 @@ tester.run('define-props-declaration', rule, {
line: 3
}
]
},
// default value
{
filename: 'test.vue',
code: `
<script setup lang="ts">
const props = defineProps({
kind: {
type: String,
default: 'foo'
}
})
</script>
`,
output: `
<script setup lang="ts">
const props = withDefaults(defineProps<{ kind?: string }>(), { kind: 'foo' })
</script>
`,
errors: [
{
message: 'Use type-based declaration instead of runtime declaration.',
line: 3
}
]
}
]
})

0 comments on commit f0294e8

Please sign in to comment.