/** * @author Yosuke Ota * See LICENSE file in root directory for full license. */ 'use strict' const path = require('path') const utils = require('../utils') const casing = require('../utils/casing') /** * `casing.camelCase()` converts the beginning to lowercase, * but does not convert the case of the beginning character when converting with Vue3. * @see https://github.com/vuejs/core/blob/ae4b0783d78670b6e942ae2a4e3ec6efbbffa158/packages/shared/src/index.ts#L105 * @param {string} str */ function camelize(str) { return str.replace(/-(\w)/g, (_, c) => (c ? c.toUpperCase() : '')) } class DefinedInSetupComponents { constructor() { /** * Component names * @type {Set} */ this.names = new Set() } /** * @param {string[]} names */ addName(...names) { for (const name of names) { this.names.add(name) } } /** * @see https://github.com/vuejs/core/blob/ae4b0783d78670b6e942ae2a4e3ec6efbbffa158/packages/compiler-core/src/transforms/transformElement.ts#L334 * @param {string} rawName */ isDefinedComponent(rawName) { if (this.names.has(rawName)) { return true } const camelName = camelize(rawName) if (this.names.has(camelName)) { return true } const pascalName = casing.capitalize(camelName) if (this.names.has(pascalName)) { return true } // Check namespace // https://github.com/vuejs/core/blob/ae4b0783d78670b6e942ae2a4e3ec6efbbffa158/packages/compiler-core/src/transforms/transformElement.ts#L305 const dotIndex = rawName.indexOf('.') if (dotIndex > 0 && this.isDefinedComponent(rawName.slice(0, dotIndex))) { return true } return false } } class DefinedInOptionComponents { constructor() { /** * Component names * @type {Set} */ this.names = new Set() /** * Component names, transformed to kebab-case * @type {Set} */ this.kebabCaseNames = new Set() } /** * @param {string[]} names */ addName(...names) { for (const name of names) { this.names.add(name) this.kebabCaseNames.add(casing.kebabCase(name)) } } /** * @param {string} rawName */ isDefinedComponent(rawName) { if (this.names.has(rawName)) { return true } const kebabCaseName = casing.kebabCase(rawName) if ( this.kebabCaseNames.has(kebabCaseName) && !casing.isPascalCase(rawName) ) { // Component registered as `foo-bar` cannot be used as `FooBar` return true } return false } } module.exports = { meta: { type: 'suggestion', docs: { description: 'disallow use of undefined components in `