Skip to content

Commit

Permalink
Update vue/no-restricted-props rule to support <script setup> (#1552
Browse files Browse the repository at this point in the history
)

* Update `vue/no-restricted-props` rule to support `<script setup>`

* fix

* fix
  • Loading branch information
ota-meshi committed Jul 6, 2021
1 parent b132191 commit c8d284b
Show file tree
Hide file tree
Showing 3 changed files with 359 additions and 39 deletions.
79 changes: 57 additions & 22 deletions lib/rules/no-restricted-props.js
Expand Up @@ -7,6 +7,12 @@
const utils = require('../utils')
const regexp = require('../utils/regexp')

/**
* @typedef {import('../utils').ComponentArrayProp} ComponentArrayProp
* @typedef {import('../utils').ComponentObjectProp} ComponentObjectProp
* @typedef {import('../utils').ComponentTypeProp} ComponentTypeProp
*/

/**
* @typedef {object} ParsedOption
* @property { (name: string) => boolean } test
Expand Down Expand Up @@ -88,39 +94,58 @@ module.exports = {
/** @type {ParsedOption[]} */
const options = context.options.map(parseOption)

return utils.defineVueVisitor(context, {
onVueObjectEnter(node) {
for (const prop of utils.getComponentProps(node)) {
if (!prop.propName) {
continue
}
/**
* @param {(ComponentArrayProp | ComponentObjectProp | ComponentTypeProp)[]} props
* @param { { [key: string]: Property | undefined } } [withDefaultsProps]
*/
function processProps(props, withDefaultsProps) {
for (const prop of props) {
if (!prop.propName) {
continue
}

for (const option of options) {
if (option.test(prop.propName)) {
const message =
option.message ||
`Using \`${prop.propName}\` props is not allowed.`
context.report({
node: prop.key,
messageId: 'restrictedProp',
data: { message },
suggest: createSuggest(prop.key, option)
})
break
}
for (const option of options) {
if (option.test(prop.propName)) {
const message =
option.message ||
`Using \`${prop.propName}\` props is not allowed.`
context.report({
node: prop.key,
messageId: 'restrictedProp',
data: { message },
suggest: createSuggest(
prop.key,
option,
withDefaultsProps && withDefaultsProps[prop.propName]
)
})
break
}
}
}
})
}
return utils.compositingVisitors(
utils.defineScriptSetupVisitor(context, {
onDefinePropsEnter(node, props) {
processProps(props, utils.getWithDefaultsProps(node))
}
}),
utils.defineVueVisitor(context, {
onVueObjectEnter(node) {
processProps(utils.getComponentProps(node))
}
})
)
}
}

/**
* @param {Expression} node
* @param {ParsedOption} option
* @param {Property} [withDefault]
* @returns {Rule.SuggestionReportDescriptor[]}
*/
function createSuggest(node, option) {
function createSuggest(node, option, withDefault) {
if (!option.suggest) {
return []
}
Expand All @@ -140,7 +165,17 @@ function createSuggest(node, option) {
return [
{
fix(fixer) {
return fixer.replaceText(node, replaceText)
const fixes = [fixer.replaceText(node, replaceText)]
if (withDefault) {
if (withDefault.shorthand) {
fixes.push(
fixer.insertTextBefore(withDefault.value, `${replaceText}:`)
)
} else {
fixes.push(fixer.replaceText(withDefault.key, replaceText))
}
}
return fixes.sort((a, b) => a.range[0] - b.range[0])
},
messageId: 'instead',
data: { suggest: option.suggest }
Expand Down
57 changes: 41 additions & 16 deletions lib/utils/index.js
Expand Up @@ -1152,29 +1152,24 @@ module.exports = {
* @returns { { [key: string]: Expression | undefined } }
*/
getWithDefaultsPropExpressions(node) {
if (!hasWithDefaults(node)) {
return {}
}
const param = node.parent.arguments[1]
if (!param || param.type !== 'ObjectExpression') {
return {}
}
const map = getWithDefaultsProps(node)

/** @type {Record<string, Expression>} */
/** @type {Record<string, Expression | undefined>} */
const result = {}

for (const prop of param.properties) {
if (prop.type !== 'Property') {
return {}
}
const name = getStaticPropertyName(prop)
if (name != null) {
result[name] = prop.value
}
for (const key of Object.keys(map)) {
const prop = map[key]
result[key] = prop && prop.value
}

return result
},
/**
* Gets a map of the property nodes defined in withDefaults.
* @param {CallExpression} node The node of defineProps
* @returns { { [key: string]: Property | undefined } }
*/
getWithDefaultsProps,

getVueObjectType,
/**
Expand Down Expand Up @@ -2400,6 +2395,36 @@ function hasWithDefaults(node) {
)
}

/**
* Gets a map of the property nodes defined in withDefaults.
* @param {CallExpression} node The node of defineProps
* @returns { { [key: string]: Property | undefined } }
*/
function getWithDefaultsProps(node) {
if (!hasWithDefaults(node)) {
return {}
}
const param = node.parent.arguments[1]
if (!param || param.type !== 'ObjectExpression') {
return {}
}

/** @type {Record<string, Property>} */
const result = {}

for (const prop of param.properties) {
if (prop.type !== 'Property') {
return {}
}
const name = getStaticPropertyName(prop)
if (name != null) {
result[name] = prop
}
}

return result
}

/**
* Get all props by looking at all component's properties
* @param {ObjectExpression|ArrayExpression} propsNode Object with props definition
Expand Down

0 comments on commit c8d284b

Please sign in to comment.