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.
157 lines
3.8 KiB
157 lines
3.8 KiB
/** |
|
* @author ItMaga <https://github.com/ItMaga> |
|
* See LICENSE file in root directory for full license. |
|
*/ |
|
'use strict' |
|
|
|
const utils = require('../utils') |
|
const casing = require('../utils/casing') |
|
const { isRegExp, toRegExp } = require('../utils/regexp') |
|
|
|
/** |
|
* @typedef {object} OptionParsed |
|
* @property { (name: string) => boolean } test |
|
* @property {string|undefined} [message] |
|
* @property {string|undefined} [suggest] |
|
*/ |
|
|
|
/** |
|
* @param {string} str |
|
* @returns {(str: string) => boolean} |
|
* @private |
|
*/ |
|
function buildMatcher(str) { |
|
if (isRegExp(str)) { |
|
const regex = toRegExp(str) |
|
return (s) => regex.test(s) |
|
} |
|
return (s) => s === casing.pascalCase(str) || s === casing.kebabCase(str) |
|
} |
|
|
|
/** |
|
* @param {string|{name: string, message?: string, suggest?: string}} option |
|
* @returns {OptionParsed} |
|
* @private |
|
* */ |
|
function parseOption(option) { |
|
if (typeof option === 'string') { |
|
const matcher = buildMatcher(option) |
|
return { test: matcher } |
|
} |
|
const parsed = parseOption(option.name) |
|
parsed.message = option.message |
|
parsed.suggest = option.suggest |
|
return parsed |
|
} |
|
|
|
/** |
|
* @param {Property | AssignmentProperty} property |
|
* @param {string | undefined} suggest |
|
* @returns {Rule.SuggestionReportDescriptor[]} |
|
* @private |
|
* */ |
|
function createSuggest(property, suggest) { |
|
if (!suggest) { |
|
return [] |
|
} |
|
|
|
return [ |
|
{ |
|
fix(fixer) { |
|
return fixer.replaceText(property.value, JSON.stringify(suggest)) |
|
}, |
|
messageId: 'suggest', |
|
data: { suggest } |
|
} |
|
] |
|
} |
|
|
|
module.exports = { |
|
meta: { |
|
type: 'suggestion', |
|
docs: { |
|
description: 'disallow specific component names', |
|
categories: undefined, |
|
url: 'https://eslint.vuejs.org/rules/no-restricted-component-names.html' |
|
}, |
|
fixable: null, |
|
hasSuggestions: true, |
|
schema: { |
|
type: 'array', |
|
items: { |
|
oneOf: [ |
|
{ type: 'string' }, |
|
{ |
|
type: 'object', |
|
properties: { |
|
name: { type: 'string' }, |
|
message: { type: 'string', minLength: 1 }, |
|
suggest: { type: 'string' } |
|
}, |
|
required: ['name'], |
|
additionalProperties: false |
|
} |
|
] |
|
}, |
|
uniqueItems: true, |
|
minItems: 0 |
|
}, |
|
messages: { |
|
// eslint-disable-next-line eslint-plugin/report-message-format |
|
disallow: '{{message}}', |
|
suggest: 'Instead, change to `{{suggest}}`.' |
|
} |
|
}, |
|
/** @param {RuleContext} context */ |
|
create(context) { |
|
/** @type {OptionParsed[]} */ |
|
const options = context.options.map(parseOption) |
|
|
|
/** |
|
* @param {ObjectExpression} node |
|
*/ |
|
function verify(node) { |
|
const property = utils.findProperty(node, 'name') |
|
if (!property) return |
|
|
|
const propertyName = utils.getStaticPropertyName(property) |
|
if (propertyName === 'name' && property.value.type === 'Literal') { |
|
const componentName = property.value.value?.toString() |
|
if (!componentName) { |
|
return |
|
} |
|
|
|
for (const option of options) { |
|
if (option.test(componentName)) { |
|
context.report({ |
|
node: property.value, |
|
messageId: 'disallow', |
|
data: { |
|
message: |
|
option.message || |
|
`Using component name \`${componentName}\` is not allowed.` |
|
}, |
|
suggest: createSuggest(property, option.suggest) |
|
}) |
|
} |
|
} |
|
} |
|
} |
|
|
|
return utils.compositingVisitors( |
|
utils.defineVueVisitor(context, { |
|
onVueObjectEnter(node) { |
|
verify(node) |
|
} |
|
}), |
|
utils.defineScriptSetupVisitor(context, { |
|
onDefineOptionsEnter(node) { |
|
const expression = node.arguments[0] |
|
if (expression.type === 'ObjectExpression') { |
|
verify(expression) |
|
} |
|
} |
|
}) |
|
) |
|
} |
|
}
|
|
|