diff --git a/docs/rules/require-default-prop.md b/docs/rules/require-default-prop.md index 93fc6b5a9..3fb467b7a 100644 --- a/docs/rules/require-default-prop.md +++ b/docs/rules/require-default-prop.md @@ -2,7 +2,7 @@ - :gear: This rule is included in `"plugin:vue/strongly-recommended"` and `"plugin:vue/recommended"`. -This rule requires default value to be set for each props that are not marked as `required`. +This rule requires default value to be set for each props that are not marked as `required` (except `Boolean` props). ## Rule Details @@ -12,10 +12,11 @@ Examples of **incorrect** code for this rule: props: { a: Number, b: [Number, String], - c: { + c: [Boolean, Number], + d: { type: Number }, - d: { + e: { type: Number, required: false } @@ -38,6 +39,9 @@ props: { type: Number, default: 0, required: false + }, + d: { + type: Boolean, // Boolean is the only type that doesn't require default } } ``` diff --git a/lib/rules/require-default-prop.js b/lib/rules/require-default-prop.js index f7f2e3da7..ac4cddb34 100644 --- a/lib/rules/require-default-prop.js +++ b/lib/rules/require-default-prop.js @@ -61,7 +61,7 @@ module.exports = { /** * Finds all props that don't have a default value set * @param {Property} propsNode - Vue component's "props" node - * @return {boolean} + * @return {Array} Array of props without "default" value */ function findPropsWithoutDefaultValue (propsNode) { return propsNode.value.properties @@ -75,6 +75,50 @@ module.exports = { }) } + /** + * Detects whether given value node is a Boolean type + * @param {Node} value + * @return {Boolean} + */ + function isValueNodeOfBooleanType (value) { + return ( + value.type === 'Identifier' && + value.name === 'Boolean' + ) || ( + value.type === 'ArrayExpression' && + value.elements.length === 1 && + value.elements[0].type === 'Identifier' && + value.elements[0].name === 'Boolean' + ) + } + + /** + * Detects whether given prop node is a Boolean + * @param {Node} prop + * @return {Boolean} + */ + function isBooleanProp (prop) { + const value = prop.value + + return isValueNodeOfBooleanType(value) || ( + value.type === 'ObjectExpression' && + value.properties.find(p => + p.key.type === 'Identifier' && + p.key.name === 'type' && + isValueNodeOfBooleanType(p.value) + ) + ) + } + + /** + * Excludes purely Boolean props from the Array + * @param {Array} props - Array with props + * @return {Array} + */ + function excludeBooleanProps (props) { + return props.filter(prop => !isBooleanProp(prop)) + } + // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- @@ -91,8 +135,9 @@ module.exports = { if (!propsNode) return const propsWithoutDefault = findPropsWithoutDefaultValue(propsNode) + const propsToReport = excludeBooleanProps(propsWithoutDefault) - propsWithoutDefault.forEach(prop => { + propsToReport.forEach(prop => { context.report({ node: prop, message: `Prop '{{propName}}' requires default value to be set.`, diff --git a/tests/lib/rules/require-default-prop.js b/tests/lib/rules/require-default-prop.js index efc714410..e5f2f3462 100644 --- a/tests/lib/rules/require-default-prop.js +++ b/tests/lib/rules/require-default-prop.js @@ -19,7 +19,7 @@ const parserOptions = { // Tests // ------------------------------------------------------------------------------ -const ruleTester = new RuleTester() +const ruleTester = new RuleTester({ parserOptions }) ruleTester.run('require-default-prop', rule, { valid: [ @@ -46,12 +46,27 @@ ruleTester.run('require-default-prop', rule, { required: false, 'default': 'lorem' }, + e: { + type: Boolean + }, + f: { + type: Boolean, + required: false + }, + g: { + type: Boolean, + default: true + }, + h: { + type: [Boolean] + }, + i: Boolean, + j: [Boolean], // eslint-disable-next-line require-default-prop - e: Number + k: Number } } - `, - parserOptions + ` }, { filename: 'test.vue', @@ -70,8 +85,7 @@ ruleTester.run('require-default-prop', rule, { } } } - `, - parserOptions + ` }, { filename: 'test.vue', @@ -98,8 +112,7 @@ ruleTester.run('require-default-prop', rule, { } } } - `, - parserOptions + ` } ], @@ -117,11 +130,14 @@ ruleTester.run('require-default-prop', rule, { d: { type: Number, required: false + }, + e: [Boolean, String], + f: { + type: [Boolean, String], } } } `, - parserOptions, errors: [{ message: `Prop 'a' requires default value to be set.`, line: 4 @@ -134,6 +150,12 @@ ruleTester.run('require-default-prop', rule, { }, { message: `Prop 'd' requires default value to be set.`, line: 9 + }, { + message: `Prop 'e' requires default value to be set.`, + line: 13 + }, { + message: `Prop 'f' requires default value to be set.`, + line: 14 }] } ]