fix(nuxt): ensure all dir parts are present in component name (#20779)

This commit is contained in:
白雾三语 2023-05-15 20:34:04 +08:00 committed by GitHub
parent 1f30cf18e3
commit ce84c9b44f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 72 additions and 19 deletions

View File

@ -72,24 +72,8 @@ export async function scanComponents (dirs: ComponentsDir[], srcDir: string): Pr
fileName = dir.pathPrefix === false ? basename(dirname(filePath)) : '' /* inherits from path */
}
/**
* Array of fileName parts splitted by case, / or -
*
* @example third-component -> ['third', 'component']
* @example AwesomeComponent -> ['Awesome', 'Component']
*/
const fileNameParts = splitByCase(fileName)
const componentNameParts: string[] = []
while (prefixParts.length &&
(prefixParts[0] || '').toLowerCase() !== (fileNameParts[0] || '').toLowerCase()
) {
componentNameParts.push(prefixParts.shift()!)
}
const componentName = pascalCase(componentNameParts) + pascalCase(fileNameParts)
const suffix = (mode !== 'all' ? `-${mode}` : '')
const componentName = resolveComponentName(fileName, prefixParts)
if (resolvedNames.has(componentName + suffix) || resolvedNames.has(componentName)) {
console.warn(`Two component files resolving to the same name \`${componentName}\`:\n` +
@ -137,3 +121,30 @@ export async function scanComponents (dirs: ComponentsDir[], srcDir: string): Pr
return components
}
export function resolveComponentName (fileName: string, prefixParts: string[]) {
/**
* Array of fileName parts splitted by case, / or -
*
* @example third-component -> ['third', 'component']
* @example AwesomeComponent -> ['Awesome', 'Component']
*/
const fileNameParts = splitByCase(fileName)
const fileNamePartsContent = fileNameParts.join('').toLowerCase()
const componentNameParts: string[] = [...prefixParts]
let index = prefixParts.length - 1
const matchedSuffix:string[] = []
while (index >= 0) {
matchedSuffix.unshift((prefixParts[index] || '').toLowerCase())
if (fileNamePartsContent.startsWith(matchedSuffix.join('')) ||
// e.g Item/Item/Item.vue -> Item
(prefixParts[index].toLowerCase() === fileNamePartsContent &&
prefixParts[index + 1] &&
prefixParts[index] === prefixParts[index + 1])) {
componentNameParts.length = index
}
index--
}
return pascalCase(componentNameParts) + pascalCase(fileNameParts)
}

View File

@ -0,0 +1,7 @@
<template>
<div>
This is Same name component!
</div>
</template>
<script setup>
</script>

View File

@ -1,8 +1,8 @@
import { resolve } from 'node:path'
import { expect, it, vi } from 'vitest'
import { describe, expect, it, vi } from 'vitest'
import type { ComponentsDir } from 'nuxt/schema'
import { scanComponents } from '../src/components/scan'
import { resolveComponentName, scanComponents } from '../src/components/scan'
const fixtureDir = resolve(__dirname, 'fixture')
const rFixture = (...p: string[]) => resolve(fixtureDir, ...p)
@ -192,6 +192,19 @@ const expectedComponents = [
preload: false,
priority: 1
},
{
chunkName: 'components/same-name-same',
export: 'default',
global: undefined,
island: undefined,
kebabName: 'same-name-same',
mode: 'all',
pascalName: 'SameNameSame',
prefetch: false,
preload: false,
priority: 1,
shortPath: 'components/same-name/same/Same.vue'
},
{
chunkName: 'components/some-glob',
export: 'default',
@ -230,3 +243,25 @@ it('components:scanComponents', async () => {
}
expect(scannedComponents).deep.eq(expectedComponents)
})
const tests: Array<[string, string[], string]> = [
['WithClientOnlySetup', ['Client'], 'ClientWithClientOnlySetup'],
['ItemHolderItem', ['Item', 'Holder', 'Item'], 'ItemHolderItem'],
['Item', ['Item'], 'Item'],
['Item', ['Item', 'Item'], 'Item'],
['ItemTest', ['Item', 'Test'], 'ItemTest'],
['ThingItemTest', ['Item', 'Thing'], 'ItemThingItemTest'],
['Item', ['Thing', 'Item'], 'ThingItem'],
['Item', ['Item', 'Holder', 'Item'], 'ItemHolderItem'],
['ItemHolder', ['Item', 'Holder', 'Item'], 'ItemHolderItemHolder'],
['ThingItemTest', ['Item', 'Thing', 'Foo'], 'ItemThingFooThingItemTest'],
['ItemIn', ['Item', 'Holder', 'Item', 'In'], 'ItemHolderItemIn'],
['Item', ['Item', 'Holder', 'Test'], 'ItemHolderTestItem'],
['ItemHolderItem', ['Item', 'Holder', 'Item', 'Holder'], 'ItemHolderItemHolderItem']
]
describe('components:resolveComponentName', () => {
it.each(tests)('resolves %s with prefix parts %s and filename %s', (fileName, prefixParts: string[], result) => {
expect(resolveComponentName(fileName, prefixParts)).toBe(result)
})
})