feat: extend require-default-prop and require-valid-default-prop to check defineModel#3032
feat: extend require-default-prop and require-valid-default-prop to check defineModel#3032seanogdev wants to merge 9 commits intovuejs:masterfrom
require-default-prop and require-valid-default-prop to check defineModel#3032Conversation
🦋 Changeset detectedLatest commit: e03f692 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
FloEdelmann
left a comment
There was a problem hiding this comment.
Sorry for the late review!
In general the code looks good, but I have a few remarks, see below.
There was a problem hiding this comment.
Pull request overview
Extends the existing prop-default enforcement rules to also analyze <script setup> defineModel() macro usage, treating models similarly to props for default requirements and default-type validity.
Changes:
- Add
defineModel()support tovue/require-default-prop(missing default detection) andvue/require-valid-default-prop(default value type validation). - Expand rule documentation with
defineModel()examples. - Add test cases covering valid/invalid
defineModel()patterns (runtime types and TypeScript generics).
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
lib/rules/require-default-prop.js |
Adds onDefineModelEnter reporting for missing defaults on defineModel() where applicable. |
lib/rules/require-valid-default-prop.ts |
Adds defineModel() default-type validation, including TS-generic type inference via ts-types. |
tests/lib/rules/require-default-prop.test.ts |
Adds valid/invalid defineModel() coverage for missing-default behavior. |
tests/lib/rules/require-valid-default-prop.test.ts |
Adds valid/invalid defineModel() coverage for default-type validation behavior. |
docs/rules/require-default-prop.md |
Documents defineModel() examples for missing-default rule. |
docs/rules/require-valid-default-prop.md |
Documents defineModel() examples for default-type validation rule. |
.changeset/lucky-waves-obey.md |
Adds a patch changeset entry for the new defineModel() support. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| onDefineModelEnter(node, model) { | ||
| if (model.options && model.options.type === 'ObjectExpression') { | ||
| if ( | ||
| propIsRequired(model.options) || | ||
| propHasDefault(model.options) || | ||
| model.options.properties.some( | ||
| (p) => | ||
| p.type === 'Property' && | ||
| utils.getStaticPropertyName(p) === 'type' && | ||
| isValueNodeOfBooleanType(p.value) | ||
| ) | ||
| ) { | ||
| return | ||
| } | ||
| context.report({ | ||
| node: model.options, | ||
| messageId: 'missingDefault', | ||
| data: { propName: model.name.modelName } | ||
| }) | ||
| } else { | ||
| context.report({ | ||
| node: model.options || node, | ||
| messageId: 'missingDefault', | ||
| data: { propName: model.name.modelName } | ||
| }) | ||
| } |
There was a problem hiding this comment.
onDefineModelEnter ignores model.typeNode (TypeScript generic) when deciding whether a default is required. This causes false positives for cases like defineModel<boolean>() / defineModel<boolean>({}), where Boolean models should be exempt from the default requirement (same as Boolean props elsewhere in this rule). Consider inferring runtime types from model.typeNode (e.g. via the existing ts-utils inference) and skipping the report when the inferred type is only Boolean (and still honoring required/default when provided).
| parser: vueEslintParser, | ||
| ...languageOptions, | ||
| parserOptions: { parser: require.resolve('@typescript-eslint/parser') } | ||
| } |
There was a problem hiding this comment.
The new defineModel TypeScript valid cases don't include a Boolean-generic scenario (e.g. defineModel<boolean>() or defineModel<boolean>({})). Adding this would guard the rule behavior that Boolean models should not require a default, and would prevent regressions once model.typeNode handling is added/fixed.
| } | |
| } | |
| }, | |
| { | |
| filename: 'test.vue', | |
| code: ` | |
| <script setup lang="ts"> | |
| defineModel<boolean>() | |
| </script> | |
| `, | |
| languageOptions: { | |
| parser: vueEslintParser, | |
| ...languageOptions, | |
| parserOptions: { parser: require.resolve('@typescript-eslint/parser') } | |
| } | |
| }, | |
| { | |
| filename: 'test.vue', | |
| code: ` | |
| <script setup lang="ts"> | |
| defineModel<boolean>({}) | |
| </script> | |
| `, | |
| languageOptions: { | |
| parser: vueEslintParser, | |
| ...languageOptions, | |
| parserOptions: { parser: require.resolve('@typescript-eslint/parser') } | |
| } |
Closes #2369.
Changes
Extends require-default-prop and require-valid-default-prop to check defineModel calls.
Since defineModel is effectively a prop+emit pair, both rules now enforce the same constraints they apply to defineProps: non-required, non-Boolean props must have a default value, and any provided default must be valid for the declared type.
Tests should validate the change.