2021-09-27 12:49:36 +00:00
|
|
|
import { basename, extname, join, dirname, relative } from 'pathe'
|
2021-06-18 16:50:03 +00:00
|
|
|
import globby from 'globby'
|
|
|
|
import { pascalCase, splitByCase } from 'scule'
|
2021-10-18 12:49:02 +00:00
|
|
|
import type { ScanDir, Component } from '@nuxt/kit'
|
2021-06-18 16:50:03 +00:00
|
|
|
|
|
|
|
export function sortDirsByPathLength ({ path: pathA }: ScanDir, { path: pathB }: ScanDir): number {
|
|
|
|
return pathB.split(/[\\/]/).filter(Boolean).length - pathA.split(/[\\/]/).filter(Boolean).length
|
|
|
|
}
|
|
|
|
|
|
|
|
// vue@2 src/shared/util.js
|
|
|
|
// TODO: update to vue3?
|
|
|
|
function hyphenate (str: string):string {
|
|
|
|
return str.replace(/\B([A-Z])/g, '-$1').toLowerCase()
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function scanComponents (dirs: ScanDir[], srcDir: string): Promise<Component[]> {
|
|
|
|
const components: Component[] = []
|
|
|
|
const filePaths = new Set<string>()
|
|
|
|
const scannedPaths: string[] = []
|
|
|
|
|
2021-10-29 11:36:55 +00:00
|
|
|
for (const dir of dirs.sort(sortDirsByPathLength)) {
|
2021-06-18 16:50:03 +00:00
|
|
|
const resolvedNames = new Map<string, string>()
|
|
|
|
|
2021-10-29 11:36:55 +00:00
|
|
|
for (const _file of await globby(dir.pattern!, { cwd: dir.path, ignore: dir.ignore })) {
|
|
|
|
const filePath = join(dir.path, _file)
|
2021-06-18 16:50:03 +00:00
|
|
|
|
|
|
|
if (scannedPaths.find(d => filePath.startsWith(d))) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if (filePaths.has(filePath)) { continue }
|
|
|
|
filePaths.add(filePath)
|
|
|
|
|
|
|
|
// Resolve componentName
|
|
|
|
const prefixParts = ([] as string[]).concat(
|
2021-10-29 11:36:55 +00:00
|
|
|
dir.prefix ? splitByCase(dir.prefix) : [],
|
|
|
|
(dir.pathPrefix !== false) ? splitByCase(relative(dir.path, dirname(filePath))) : []
|
2021-06-18 16:50:03 +00:00
|
|
|
)
|
|
|
|
let fileName = basename(filePath, extname(filePath))
|
|
|
|
if (fileName.toLowerCase() === 'index') {
|
2021-10-29 11:36:55 +00:00
|
|
|
fileName = dir.pathPrefix === false ? basename(dirname(filePath)) : '' /* inherits from path */
|
2021-06-18 16:50:03 +00:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
|
|
|
|
if (resolvedNames.has(componentName)) {
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
console.warn(`Two component files resolving to the same name \`${componentName}\`:\n` +
|
|
|
|
`\n - ${filePath}` +
|
|
|
|
`\n - ${resolvedNames.get(componentName)}`
|
|
|
|
)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
resolvedNames.set(componentName, filePath)
|
|
|
|
|
2021-06-22 10:03:47 +00:00
|
|
|
const pascalName = pascalCase(componentName).replace(/["']/g, '')
|
2021-06-18 16:50:03 +00:00
|
|
|
const kebabName = hyphenate(componentName)
|
|
|
|
const shortPath = relative(srcDir, filePath)
|
|
|
|
const chunkName = 'components/' + kebabName
|
|
|
|
|
|
|
|
let component: Component = {
|
|
|
|
filePath,
|
|
|
|
pascalName,
|
|
|
|
kebabName,
|
|
|
|
chunkName,
|
|
|
|
shortPath,
|
|
|
|
export: 'default',
|
2021-10-29 11:36:55 +00:00
|
|
|
global: dir.global,
|
|
|
|
level: Number(dir.level),
|
|
|
|
prefetch: Boolean(dir.prefetch),
|
|
|
|
preload: Boolean(dir.preload)
|
2021-06-18 16:50:03 +00:00
|
|
|
}
|
|
|
|
|
2021-10-29 11:36:55 +00:00
|
|
|
if (typeof dir.extendComponent === 'function') {
|
|
|
|
component = (await dir.extendComponent(component)) || component
|
2021-06-18 16:50:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check if component is already defined, used to overwite if level is inferiour
|
|
|
|
const definedComponent = components.find(c => c.pascalName === component.pascalName)
|
|
|
|
if (definedComponent && component.level < definedComponent.level) {
|
|
|
|
Object.assign(definedComponent, component)
|
|
|
|
} else if (!definedComponent) {
|
|
|
|
components.push(component)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-29 11:36:55 +00:00
|
|
|
scannedPaths.push(dir.path)
|
2021-06-18 16:50:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return components
|
|
|
|
}
|