123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- /**
- * @fileoverview Require default value for props
- * @author Michał Sajnóg <msajnog93@gmail.com> (https://github.com/michalsnik)
- */
- 'use strict'
- const utils = require('../utils')
- const NATIVE_TYPES = new Set([
- 'String',
- 'Number',
- 'Boolean',
- 'Function',
- 'Object',
- 'Array',
- 'Symbol'
- ])
- // ------------------------------------------------------------------------------
- // Rule Definition
- // ------------------------------------------------------------------------------
- module.exports = {
- meta: {
- type: 'suggestion',
- docs: {
- description: 'require default value for props',
- category: 'strongly-recommended',
- url: 'https://eslint.vuejs.org/rules/require-default-prop.html'
- },
- fixable: null, // or "code" or "whitespace"
- schema: []
- },
- create (context) {
- // ----------------------------------------------------------------------
- // Helpers
- // ----------------------------------------------------------------------
- /**
- * Checks if the passed prop is required
- * @param {Property} prop - Property AST node for a single prop
- * @return {boolean}
- */
- function propIsRequired (prop) {
- const propRequiredNode = prop.value.properties
- .find(p =>
- p.type === 'Property' &&
- p.key.name === 'required' &&
- p.value.type === 'Literal' &&
- p.value.value === true
- )
- return Boolean(propRequiredNode)
- }
- /**
- * Checks if the passed prop has a default value
- * @param {Property} prop - Property AST node for a single prop
- * @return {boolean}
- */
- function propHasDefault (prop) {
- const propDefaultNode = prop.value.properties
- .find(p =>
- p.key &&
- (p.key.name === 'default' || p.key.value === 'default')
- )
- return Boolean(propDefaultNode)
- }
- /**
- * Finds all props that don't have a default value set
- * @param {Array} props - Vue component's "props" node
- * @return {Array} Array of props without "default" value
- */
- function findPropsWithoutDefaultValue (props) {
- return props
- .filter(prop => {
- if (prop.value.type !== 'ObjectExpression') {
- return (prop.value.type !== 'CallExpression' && prop.value.type !== 'Identifier') || NATIVE_TYPES.has(prop.value.name)
- }
- return !propIsRequired(prop) && !propHasDefault(prop)
- })
- }
- /**
- * 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 = utils.unwrapTypes(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
- // ----------------------------------------------------------------------
- return utils.executeOnVue(context, (obj) => {
- const props = utils.getComponentProps(obj)
- .filter(prop => prop.key && prop.value && !prop.node.shorthand)
- const propsWithoutDefault = findPropsWithoutDefaultValue(props)
- const propsToReport = excludeBooleanProps(propsWithoutDefault)
- for (const prop of propsToReport) {
- const propName = prop.propName != null ? prop.propName : `[${context.getSourceCode().getText(prop.key)}]`
- context.report({
- node: prop.node,
- message: `Prop '{{propName}}' requires default value to be set.`,
- data: {
- propName
- }
- })
- }
- })
- }
- }
|