Skip to content

Commit

Permalink
fix(nuxt): ensure all dir parts are present in component name (#20779)
Browse files Browse the repository at this point in the history
  • Loading branch information
baiwusanyu-c committed May 15, 2023
1 parent 1f30cf1 commit ce84c9b
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 19 deletions.
45 changes: 28 additions & 17 deletions packages/nuxt/src/components/scan.ts
Expand Up @@ -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` +
Expand Down Expand Up @@ -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)
}
7 changes: 7 additions & 0 deletions packages/nuxt/test/fixture/components/same-name/same/Same.vue
@@ -0,0 +1,7 @@
<template>
<div>
This is Same name component!
</div>
</template>
<script setup>
</script>
39 changes: 37 additions & 2 deletions packages/nuxt/test/scan-components.test.ts
@@ -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)
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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)
})
})

0 comments on commit ce84c9b

Please sign in to comment.