You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
3.4 KiB
128 lines
3.4 KiB
/** |
|
* @fileoverview Prevents boolean defaults from being set |
|
* @author Hiroki Osame |
|
*/ |
|
'use strict' |
|
|
|
const utils = require('../utils') |
|
|
|
/** |
|
* @typedef {import('../utils').ComponentProp} ComponentProp |
|
*/ |
|
|
|
// ------------------------------------------------------------------------------ |
|
// Rule Definition |
|
// ------------------------------------------------------------------------------ |
|
|
|
/** |
|
* @param {Property | SpreadElement} prop |
|
*/ |
|
function isBooleanProp(prop) { |
|
return ( |
|
prop.type === 'Property' && |
|
prop.key.type === 'Identifier' && |
|
prop.key.name === 'type' && |
|
prop.value.type === 'Identifier' && |
|
prop.value.name === 'Boolean' |
|
) |
|
} |
|
|
|
/** |
|
* @param {ObjectExpression} propDefValue |
|
*/ |
|
function getDefaultNode(propDefValue) { |
|
return utils.findProperty(propDefValue, 'default') |
|
} |
|
|
|
module.exports = { |
|
meta: { |
|
type: 'suggestion', |
|
docs: { |
|
description: 'disallow boolean defaults', |
|
categories: undefined, |
|
url: 'https://eslint.vuejs.org/rules/no-boolean-default.html' |
|
}, |
|
fixable: 'code', |
|
schema: [ |
|
{ |
|
enum: ['default-false', 'no-default'] |
|
} |
|
] |
|
}, |
|
/** @param {RuleContext} context */ |
|
create(context) { |
|
const booleanType = context.options[0] || 'no-default' |
|
/** |
|
* @param {ComponentProp} prop |
|
* @param { { [key: string]: Expression | undefined } } [withDefaultsExpressions] |
|
*/ |
|
function processProp(prop, withDefaultsExpressions) { |
|
if (prop.type === 'object') { |
|
if (prop.value.type !== 'ObjectExpression') { |
|
return |
|
} |
|
if (!prop.value.properties.some(isBooleanProp)) { |
|
return |
|
} |
|
const defaultNode = getDefaultNode(prop.value) |
|
if (!defaultNode) { |
|
return |
|
} |
|
verifyDefaultExpression(defaultNode.value) |
|
} else if (prop.type === 'type') { |
|
if (prop.types.length !== 1 || prop.types[0] !== 'Boolean') { |
|
return |
|
} |
|
const defaultNode = |
|
withDefaultsExpressions && withDefaultsExpressions[prop.propName] |
|
if (!defaultNode) { |
|
return |
|
} |
|
verifyDefaultExpression(defaultNode) |
|
} |
|
} |
|
/** |
|
* @param {ComponentProp[]} props |
|
* @param { { [key: string]: Expression | undefined } } [withDefaultsExpressions] |
|
*/ |
|
function processProps(props, withDefaultsExpressions) { |
|
for (const prop of props) { |
|
processProp(prop, withDefaultsExpressions) |
|
} |
|
} |
|
|
|
/** |
|
* @param {Expression} defaultNode |
|
*/ |
|
function verifyDefaultExpression(defaultNode) { |
|
switch (booleanType) { |
|
case 'no-default': |
|
context.report({ |
|
node: defaultNode, |
|
message: |
|
'Boolean prop should not set a default (Vue defaults it to false).' |
|
}) |
|
break |
|
|
|
case 'default-false': |
|
if (defaultNode.type !== 'Literal' || defaultNode.value !== false) { |
|
context.report({ |
|
node: defaultNode, |
|
message: 'Boolean prop should only be defaulted to false.' |
|
}) |
|
} |
|
break |
|
} |
|
} |
|
return utils.compositingVisitors( |
|
utils.executeOnVueComponent(context, (obj) => { |
|
processProps(utils.getComponentPropsFromOptions(obj)) |
|
}), |
|
utils.defineScriptSetupVisitor(context, { |
|
onDefinePropsEnter(node, props) { |
|
processProps(props, utils.getWithDefaultsPropExpressions(node)) |
|
} |
|
}) |
|
) |
|
} |
|
}
|
|
|