| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- /**
- * @author Marton Csordas
- * See LICENSE file in root directory for full license.
- */
- 'use strict'
- // ------------------------------------------------------------------------------
- // Requirements
- // ------------------------------------------------------------------------------
- const casing = require('../utils/casing')
- const utils = require('../utils')
- const RESERVED_NAMES_IN_VUE3 = new Set(
- require('../utils/vue3-builtin-components')
- )
- // ------------------------------------------------------------------------------
- // Helpers
- // ------------------------------------------------------------------------------
- /**
- * Returns true if the given component name is valid, otherwise false.
- * @param {string} name
- * */
- function isValidComponentName(name) {
- if (name.toLowerCase() === 'app' || RESERVED_NAMES_IN_VUE3.has(name)) {
- return true
- } else {
- const elements = casing.kebabCase(name).split('-')
- return elements.length > 1
- }
- }
- // ------------------------------------------------------------------------------
- // Rule Definition
- // ------------------------------------------------------------------------------
- module.exports = {
- meta: {
- type: 'suggestion',
- docs: {
- description: 'require component names to be always multi-word',
- categories: undefined,
- url: 'https://eslint.vuejs.org/rules/multi-word-component-names.html'
- },
- schema: [],
- messages: {
- unexpected: 'Component name "{{value}}" should always be multi-word.'
- }
- },
- /** @param {RuleContext} context */
- create(context) {
- const fileName = context.getFilename()
- let componentName = fileName.replace(/\.[^/.]+$/, '')
- return utils.compositingVisitors(
- {
- /** @param {Program} node */
- Program(node) {
- if (
- !node.body.length &&
- utils.isVueFile(fileName) &&
- !isValidComponentName(componentName)
- ) {
- context.report({
- messageId: 'unexpected',
- data: {
- value: componentName
- },
- loc: { line: 1, column: 0 }
- })
- }
- }
- },
- utils.executeOnVue(context, (obj) => {
- const node = utils.findProperty(obj, 'name')
- /** @type {SourceLocation | null} */
- let loc = null
- // Check if the component has a name property.
- if (node) {
- const valueNode = node.value
- if (valueNode.type !== 'Literal') return
- componentName = `${valueNode.value}`
- loc = node.loc
- } else if (
- obj.parent.type === 'CallExpression' &&
- obj.parent.arguments.length === 2
- ) {
- // The component is registered globally with 'Vue.component', where
- // the first paremter is the component name.
- const argument = obj.parent.arguments[0]
- if (argument.type !== 'Literal') return
- componentName = `${argument.value}`
- loc = argument.loc
- }
- if (!isValidComponentName(componentName)) {
- context.report({
- messageId: 'unexpected',
- data: {
- value: componentName
- },
- loc: loc || { line: 1, column: 0 }
- })
- }
- })
- )
- }
- }
|