From 03abbdec0ce437af62310953cda4e7f30e461683 Mon Sep 17 00:00:00 2001 From: byronogis Date: Mon, 20 Jan 2025 19:42:03 +0800 Subject: [PATCH] feat: handle long extensions Close #820 --- src/core/options.ts | 18 +++++++++++------- src/core/utils.ts | 11 +++++++---- src/types.ts | 1 + test/utils.test.ts | 18 +++++++++++++++--- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/core/options.ts b/src/core/options.ts index ec2b5fb0..8693e643 100644 --- a/src/core/options.ts +++ b/src/core/options.ts @@ -33,26 +33,30 @@ function resolveGlobsExclude(root: string, glob: string) { export function resolveOptions(options: Options, root: string): ResolvedOptions { const resolved = Object.assign({}, defaultOptions, options) as ResolvedOptions resolved.resolvers = normalizeResolvers(resolved.resolvers) - resolved.extensions = toArray(resolved.extensions) + resolved.resolvedExtensions = toArray(resolved.extensions) + .map(i => i.startsWith('.') ? i : `.${i}`) + // sort extensions by length to ensure that the longest one is used first + // e.g. ['.vue', '.page.vue'] -> ['.page.vue', '.vue'] as both would match and order matters + .sort((a, b) => b.length - a.length) if (resolved.globs) { resolved.globs = toArray(resolved.globs).map((glob: string) => slash(resolveGlobsExclude(root, glob))) resolved.resolvedDirs = [] } else { - const extsGlob = resolved.extensions.length === 1 - ? resolved.extensions - : `{${resolved.extensions.join(',')}}` + const extsGlob = resolved.resolvedExtensions.length === 1 + ? resolved.resolvedExtensions + : `{${resolved.resolvedExtensions.join(',')}}` resolved.dirs = toArray(resolved.dirs) resolved.resolvedDirs = resolved.dirs.map(i => slash(resolveGlobsExclude(root, i))) resolved.globs = resolved.resolvedDirs.map(i => resolved.deep - ? slash(join(i, `**/*.${extsGlob}`)) - : slash(join(i, `*.${extsGlob}`)), + ? slash(join(i, `**/*${extsGlob}`)) + : slash(join(i, `*${extsGlob}`)), ) - if (!resolved.extensions.length) + if (!resolved.resolvedExtensions.length) throw new Error('[unplugin-vue-components] `extensions` option is required to search for components') } diff --git a/src/core/utils.ts b/src/core/utils.ts index eb5c8f3f..ea6693c6 100644 --- a/src/core/utils.ts +++ b/src/core/utils.ts @@ -1,7 +1,7 @@ import type { FilterPattern } from '@rollup/pluginutils' import type { ComponentInfo, ImportInfo, ImportInfoLegacy, Options, ResolvedOptions } from '../types' import type { Context } from './context' -import { parse } from 'node:path' +import { basename, parse } from 'node:path' import process from 'node:process' import { slash, toArray } from '@antfu/utils' import { @@ -114,7 +114,7 @@ export function stringifyComponentImport({ as: name, from: path, name: importNam } export function getNameFromFilePath(filePath: string, options: ResolvedOptions): string { - const { resolvedDirs, directoryAsNamespace, globalNamespaces, collapseSamePrefixes, root } = options + const { resolvedDirs, directoryAsNamespace, globalNamespaces, collapseSamePrefixes, root, resolvedExtensions } = options const parsedFilePath = parse(slash(filePath)) @@ -129,11 +129,14 @@ export function getNameFromFilePath(filePath: string, options: ResolvedOptions): } let folders = strippedPath.slice(1).split('/').filter(Boolean) - let filename = parsedFilePath.name + // when using `globs` option, `resolvedDirs` will always empty, and ignoring extensions is the expected behavior + let filename = isEmpty(resolvedDirs) + ? parsedFilePath.name + : basename(parsedFilePath.base, resolvedExtensions?.find(ext => parsedFilePath.base.endsWith(ext))) // set parent directory as filename if it is index if (filename === 'index' && !directoryAsNamespace) { - // when use `globs` option, `resolvedDirs` will always empty, and `folders` will also empty + // when using `globs` option, `resolvedDirs` will always empty, and `folders` will also empty if (isEmpty(folders)) folders = parsedFilePath.dir.slice(root.length + 1).split('/').filter(Boolean) diff --git a/src/types.ts b/src/types.ts index 69dceae1..b4348348 100644 --- a/src/types.ts +++ b/src/types.ts @@ -189,6 +189,7 @@ export type ResolvedOptions = Omit< > & { resolvers: ComponentResolverObject[] extensions: string[] + resolvedExtensions: string[] dirs: string[] resolvedDirs: string[] globs: string[] diff --git a/test/utils.test.ts b/test/utils.test.ts index cdabab87..c96ea341 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -1,14 +1,16 @@ import type { ResolvedOptions } from '../src' import { describe, expect, it } from 'vitest' +import { resolveOptions } from '../src/core/options' import { getNameFromFilePath } from '../src/core/utils' describe('getNameFromFilePath', () => { - const options: Partial = { + const options: Partial = resolveOptions({ directoryAsNamespace: true, globalNamespaces: [], collapseSamePrefixes: false, - resolvedDirs: ['/src/components'], - } + dirs: ['/src/components'], + extensions: ['vue', 'ce.vue'], + }, '/') it('normal name', () => { const inComponentFilePath = '/src/components/a/b.vue' @@ -19,4 +21,14 @@ describe('getNameFromFilePath', () => { const inComponentFilePath = '/src/components/[a1]/b_2/c 3/d.4/[...ef]/ghi.vue' expect(getNameFromFilePath(inComponentFilePath, options as ResolvedOptions)).toBe('a1-b2-c3-d4-ef-ghi') }) + + it(('long extensions'), () => { + const inComponentFilePath = '/src/components/b.ce.vue' + expect(getNameFromFilePath(inComponentFilePath, options as ResolvedOptions)).toBe('b') + }) + + it(('long extensions and nested'), () => { + const inComponentFilePath = '/src/components/a/b.ce.vue' + expect(getNameFromFilePath(inComponentFilePath, options as ResolvedOptions)).toBe('a-b') + }) }) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy