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.
148 lines
4.0 KiB
148 lines
4.0 KiB
/** |
|
* @fileoverview Prevents boolean defaults from being set |
|
* @author Hiroki Osame |
|
*/ |
|
'use strict' |
|
|
|
const utils = require('../utils') |
|
|
|
/** |
|
* @typedef {import('../utils').ComponentProp} ComponentProp |
|
* @typedef {import('../utils').ComponentObjectProp} ComponentObjectProp |
|
*/ |
|
|
|
/** |
|
* @param {Expression|undefined} node |
|
*/ |
|
function isBooleanIdentifier(node) { |
|
return Boolean(node && node.type === 'Identifier' && node.name === 'Boolean') |
|
} |
|
|
|
/** |
|
* Detects whether given prop node is a Boolean |
|
* @param {ComponentObjectProp} prop |
|
* @return {Boolean} |
|
*/ |
|
function isBooleanProp(prop) { |
|
const value = utils.skipTSAsExpression(prop.value) |
|
return ( |
|
isBooleanIdentifier(value) || |
|
(value.type === 'ObjectExpression' && |
|
isBooleanIdentifier(utils.findProperty(value, 'type')?.value)) |
|
) |
|
} |
|
|
|
/** |
|
* @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: null, |
|
schema: [ |
|
{ |
|
enum: ['default-false', 'no-default'] |
|
} |
|
], |
|
messages: { |
|
noBooleanDefault: |
|
'Boolean prop should not set a default (Vue defaults it to false).', |
|
defaultFalse: 'Boolean prop should only be defaulted to false.' |
|
} |
|
}, |
|
/** @param {RuleContext} context */ |
|
create(context) { |
|
const booleanType = context.options[0] || 'no-default' |
|
/** |
|
* @param {ComponentProp} prop |
|
* @param {(propName: string) => Expression[]} otherDefaultProvider |
|
*/ |
|
function processProp(prop, otherDefaultProvider) { |
|
if (prop.type === 'object') { |
|
if (!isBooleanProp(prop)) { |
|
return |
|
} |
|
if (prop.value.type === 'ObjectExpression') { |
|
const defaultNode = getDefaultNode(prop.value) |
|
if (defaultNode) { |
|
verifyDefaultExpression(defaultNode.value) |
|
} |
|
} |
|
if (prop.propName != null) { |
|
for (const defaultNode of otherDefaultProvider(prop.propName)) { |
|
verifyDefaultExpression(defaultNode) |
|
} |
|
} |
|
} else if (prop.type === 'type') { |
|
if (prop.types.length !== 1 || prop.types[0] !== 'Boolean') { |
|
return |
|
} |
|
for (const defaultNode of otherDefaultProvider(prop.propName)) { |
|
verifyDefaultExpression(defaultNode) |
|
} |
|
} |
|
} |
|
/** |
|
* @param {ComponentProp[]} props |
|
* @param {(propName: string) => Expression[]} otherDefaultProvider |
|
*/ |
|
function processProps(props, otherDefaultProvider) { |
|
for (const prop of props) { |
|
processProp(prop, otherDefaultProvider) |
|
} |
|
} |
|
|
|
/** |
|
* @param {Expression} defaultNode |
|
*/ |
|
function verifyDefaultExpression(defaultNode) { |
|
switch (booleanType) { |
|
case 'no-default': { |
|
context.report({ |
|
node: defaultNode, |
|
messageId: 'noBooleanDefault' |
|
}) |
|
break |
|
} |
|
|
|
case 'default-false': { |
|
if (defaultNode.type !== 'Literal' || defaultNode.value !== false) { |
|
context.report({ |
|
node: defaultNode, |
|
messageId: 'defaultFalse' |
|
}) |
|
} |
|
break |
|
} |
|
} |
|
} |
|
return utils.compositingVisitors( |
|
utils.executeOnVueComponent(context, (obj) => { |
|
processProps(utils.getComponentPropsFromOptions(obj), () => []) |
|
}), |
|
utils.defineScriptSetupVisitor(context, { |
|
onDefinePropsEnter(node, props) { |
|
const defaultsByWithDefaults = |
|
utils.getWithDefaultsPropExpressions(node) |
|
const defaultsByAssignmentPatterns = |
|
utils.getDefaultPropExpressionsForPropsDestructure(node) |
|
processProps(props, (propName) => |
|
[ |
|
defaultsByWithDefaults[propName], |
|
defaultsByAssignmentPatterns[propName]?.expression |
|
].filter(utils.isDef) |
|
) |
|
} |
|
}) |
|
) |
|
} |
|
}
|
|
|