text: /**
   * @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)
  ])
  
  // ------------------------------------------------------------------------------
  // Rule Definition
  // ------------------------------------------------------------------------------
  
  module.exports = {
    meta: {
      type: 'suggestion',
      docs: {
        description:
          'disallow the use of reserved names in component definitions',
        categories: undefined,
        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 {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 {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: RESERVED_NAMES_IN_HTML.has(name)
            ? 'reservedInHtml'
            : RESERVED_NAMES_IN_VUE.has(name)
            ? 'reservedInVue'
            : RESERVED_NAMES_IN_VUE3.has(name)
            ? 'reservedInVue3'
            : 'reserved',
          data: {
            name
          }
        })
      }
  
      return Object.assign(
        {},
        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.
          utils
            .getRegisteredComponents(obj)
            .filter(({ name }) => reservedNames.has(name))
            .forEach(({ node, name }) => report(node, name))
  
          const node = utils.findProperty(obj, 'name')
  
          if (!node) return
          if (!canVerify(node.value)) return
          reportIfInvalid(node.value)
        })
      )
    }
  }
  