Skip to content

Commit

Permalink
Add support for props destructure to vue/require-default-prop rule (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
ota-meshi authored Sep 18, 2024
1 parent 05b7559 commit 4704ab6
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 22 deletions.
67 changes: 46 additions & 21 deletions lib/rules/require-default-prop.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
/**
* @typedef {import('../utils').ComponentProp} ComponentProp
* @typedef {import('../utils').ComponentObjectProp} ComponentObjectProp
* @typedef {import('../utils').ComponentTypeProp} ComponentTypeProp
* @typedef {ComponentObjectProp & { value: ObjectExpression} } ComponentObjectPropObject
*/

Expand Down Expand Up @@ -137,18 +138,23 @@ module.exports = {

/**
* @param {ComponentProp[]} props
* @param {boolean} [withDefaults]
* @param { { [key: string]: Expression | undefined } } [withDefaultsExpressions]
* @param {(prop: ComponentObjectProp|ComponentTypeProp)=>boolean} [ignore]
*/
function processProps(props, withDefaults, withDefaultsExpressions) {
function processProps(props, ignore) {
for (const prop of props) {
if (prop.type === 'object' && !prop.node.shorthand) {
if (prop.type === 'object') {
if (prop.node.shorthand) {
continue
}
if (!isWithoutDefaultValue(prop)) {
continue
}
if (isBooleanProp(prop)) {
continue
}
if (ignore?.(prop)) {
continue
}
const propName =
prop.propName == null
? `[${context.getSourceCode().getText(prop.node.key)}]`
Expand All @@ -161,38 +167,57 @@ module.exports = {
propName
}
})
} else if (
prop.type === 'type' &&
withDefaults &&
withDefaultsExpressions
) {
} else if (prop.type === 'type') {
if (prop.required) {
continue
}
if (prop.types.length === 1 && prop.types[0] === 'Boolean') {
continue
}
if (!withDefaultsExpressions[prop.propName]) {
context.report({
node: prop.node,
messageId: `missingDefault`,
data: {
propName: prop.propName
}
})
if (ignore?.(prop)) {
continue
}
context.report({
node: prop.node,
messageId: `missingDefault`,
data: {
propName: prop.propName
}
})
}
}
}

return utils.compositingVisitors(
utils.defineScriptSetupVisitor(context, {
onDefinePropsEnter(node, props) {
processProps(
props,
utils.hasWithDefaults(node),
const hasWithDefaults = utils.hasWithDefaults(node)
const defaultsByWithDefaults =
utils.getWithDefaultsPropExpressions(node)
)
const isUsingPropsDestructure = utils.isUsingPropsDestructure(node)
const defaultsByAssignmentPatterns =
utils.getDefaultPropExpressionsForPropsDestructure(node)

processProps(props, (prop) => {
if (prop.type === 'type') {
if (!hasWithDefaults) {
// If don't use withDefaults(), exclude it from the report.
return true
}
if (defaultsByWithDefaults[prop.propName]) {
return true
}
}
if (!isUsingPropsDestructure) {
return false
}
if (prop.propName == null) {
// If using Props Destructure but the property name cannot be determined,
// it will be ignored.
return true
}
return Boolean(defaultsByAssignmentPatterns[prop.propName])
})
}
}),
utils.executeOnVue(context, (obj) => {
Expand Down
79 changes: 78 additions & 1 deletion tests/lib/rules/require-default-prop.js
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,43 @@ ruleTester.run('require-default-prop', rule, {
...languageOptions,
parserOptions: { parser: require.resolve('@typescript-eslint/parser') }
}
},
{
filename: 'test.vue',
code: `
<script setup>
const {foo=42,bar=42} = defineProps({foo: Number, bar: {type: Number}})
</script>
`,
languageOptions: {
parser: require('vue-eslint-parser'),
...languageOptions
}
},
{
filename: 'test.vue',
code: `
<script setup>
const {foo,bar} = defineProps({foo: Boolean, bar: {type: Boolean}})
</script>
`,
languageOptions: {
parser: require('vue-eslint-parser'),
...languageOptions
}
},
{
filename: 'test.vue',
code: `
<script setup>
// ignore
const {bar = 42, foo = 42} = defineProps({[x]: Number, bar: {type: Number}})
</script>
`,
languageOptions: {
parser: require('vue-eslint-parser'),
...languageOptions
}
}
],

Expand Down Expand Up @@ -623,6 +660,46 @@ ruleTester.run('require-default-prop', rule, {
}
]
}
])
]),
{
filename: 'test.vue',
code: `
<script setup>
const {foo,bar} = defineProps({foo: Boolean, bar: {type: String}})
</script>
`,
languageOptions: {
parser: require('vue-eslint-parser'),
...languageOptions
},
errors: [
{
message: "Prop 'bar' requires default value to be set.",
line: 3
}
]
},
{
filename: 'test.vue',
code: `
<script setup>
const {foo,bar} = defineProps({foo: Number, bar: {type: Number}})
</script>
`,
languageOptions: {
parser: require('vue-eslint-parser'),
...languageOptions
},
errors: [
{
message: "Prop 'foo' requires default value to be set.",
line: 3
},
{
message: "Prop 'bar' requires default value to be set.",
line: 3
}
]
}
]
})

0 comments on commit 4704ab6

Please sign in to comment.