123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- /**
- * @fileoverview disallow the use of reserved names in component definitions
- * @author Jake Hassel <https://github.com/shadskii>
- */
- 'use strict'
- const utils = require('../utils')
- const casing = require('../utils/casing')
- const htmlElements = require('../utils/html-elements.json')
- const deprecatedHtmlElements = require('../utils/deprecated-html-elements.json')
- const svgElements = require('../utils/svg-elements.json')
- const RESERVED_NAMES_IN_VUE = new Set(
- require('../utils/vue2-builtin-components')
- )
- const RESERVED_NAMES_IN_VUE3 = new Set(
- require('../utils/vue3-builtin-components')
- )
- const kebabCaseElements = [
- 'annotation-xml',
- 'color-profile',
- 'font-face',
- 'font-face-src',
- 'font-face-uri',
- 'font-face-format',
- 'font-face-name',
- 'missing-glyph'
- ]
- /** @param {string} word */
- function isLowercase(word) {
- return /^[a-z]*$/.test(word)
- }
- const RESERVED_NAMES_IN_HTML = new Set([
- ...htmlElements,
- ...htmlElements.map(casing.capitalize)
- ])
- const RESERVED_NAMES_IN_OTHERS = new Set([
- ...deprecatedHtmlElements,
- ...deprecatedHtmlElements.map(casing.capitalize),
- ...kebabCaseElements,
- ...kebabCaseElements.map(casing.pascalCase),
- ...svgElements,
- ...svgElements.filter(isLowercase).map(casing.capitalize)
- ])
- /**
- * @param {Expression | SpreadElement} node
- * @returns {node is (Literal | TemplateLiteral)}
- */
- function canVerify(node) {
- return (
- node.type === 'Literal' ||
- (node.type === 'TemplateLiteral' &&
- node.expressions.length === 0 &&
- node.quasis.length === 1)
- )
- }
- /**
- * @param {string} name
- * @returns {string}
- */
- function getMessageId(name) {
- if (RESERVED_NAMES_IN_HTML.has(name)) return 'reservedInHtml'
- if (RESERVED_NAMES_IN_VUE.has(name)) return 'reservedInVue'
- if (RESERVED_NAMES_IN_VUE3.has(name)) return 'reservedInVue3'
- return 'reserved'
- }
- module.exports = {
- meta: {
- type: 'suggestion',
- docs: {
- description:
- 'disallow the use of reserved names in component definitions',
- categories: ['vue3-essential', 'vue2-essential'],
- url: 'https://eslint.vuejs.org/rules/no-reserved-component-names.html'
- },
- fixable: null,
- schema: [
- {
- type: 'object',
- properties: {
- disallowVueBuiltInComponents: {
- type: 'boolean'
- },
- disallowVue3BuiltInComponents: {
- type: 'boolean'
- }
- },
- additionalProperties: false
- }
- ],
- messages: {
- reserved: 'Name "{{name}}" is reserved.',
- reservedInHtml: 'Name "{{name}}" is reserved in HTML.',
- reservedInVue: 'Name "{{name}}" is reserved in Vue.js.',
- reservedInVue3: 'Name "{{name}}" is reserved in Vue.js 3.x.'
- }
- },
- /** @param {RuleContext} context */
- create(context) {
- const options = context.options[0] || {}
- const disallowVueBuiltInComponents =
- options.disallowVueBuiltInComponents === true
- const disallowVue3BuiltInComponents =
- options.disallowVue3BuiltInComponents === true
- const reservedNames = new Set([
- ...RESERVED_NAMES_IN_HTML,
- ...(disallowVueBuiltInComponents ? RESERVED_NAMES_IN_VUE : []),
- ...(disallowVue3BuiltInComponents ? RESERVED_NAMES_IN_VUE3 : []),
- ...RESERVED_NAMES_IN_OTHERS
- ])
- /**
- * @param {Literal | TemplateLiteral} node
- */
- function reportIfInvalid(node) {
- let name
- if (node.type === 'TemplateLiteral') {
- const quasis = node.quasis[0]
- name = quasis.value.cooked
- } else {
- name = `${node.value}`
- }
- if (reservedNames.has(name)) {
- report(node, name)
- }
- }
- /**
- * @param {ESNode} node
- * @param {string} name
- */
- function report(node, name) {
- context.report({
- node,
- messageId: getMessageId(name),
- data: {
- name
- }
- })
- }
- return utils.compositingVisitors(
- utils.executeOnCallVueComponent(context, (node) => {
- if (node.arguments.length === 2) {
- const argument = node.arguments[0]
- if (canVerify(argument)) {
- reportIfInvalid(argument)
- }
- }
- }),
- utils.executeOnVue(context, (obj) => {
- // Report if a component has been registered locally with a reserved name.
- for (const { node, name } of utils.getRegisteredComponents(obj)) {
- if (reservedNames.has(name)) {
- report(node, name)
- }
- }
- const node = utils.findProperty(obj, 'name')
- if (!node) return
- if (!canVerify(node.value)) return
- reportIfInvalid(node.value)
- }),
- utils.defineScriptSetupVisitor(context, {
- onDefineOptionsEnter(node) {
- if (node.arguments.length === 0) return
- const define = node.arguments[0]
- if (define.type !== 'ObjectExpression') return
- const nameNode = utils.findProperty(define, 'name')
- if (!nameNode) return
- if (!canVerify(nameNode.value)) return
- reportIfInvalid(nameNode.value)
- }
- })
- )
- }
- }
|