diff --git a/src/parser/index.ts b/src/parser/index.ts index 9326951..b818b42 100644 --- a/src/parser/index.ts +++ b/src/parser/index.ts @@ -5,6 +5,7 @@ import { isAbsolute, join } from "pathe" import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs' import { withBase } from "ufo" import { hash } from "crypto" +import { defu } from 'defu' export interface Options { rootDir: string @@ -66,7 +67,18 @@ function _getComponentMeta(fullPath: string, opts: Options) { exclude: [] }, ) - return refineMeta( + + const baseMeta = refineMeta( checker.getComponentMeta(fullPath) ) -} \ No newline at end of file + + // Apply extendComponentMeta(...) overrides from the component source + try { + const code = readFileSync(fullPath, 'utf-8') + const extendComponentMetaMatch = code.match(/extendComponentMeta\((\{[\s\S]*?\})\)/) + const extendedComponentMeta = extendComponentMetaMatch?.length ? eval(`(${extendComponentMetaMatch[1]})`) : null + return defu(baseMeta, extendedComponentMeta) as ComponentMeta + } catch { + return baseMeta + } +} diff --git a/test/fixtures/basic/components/ExtendMetaComponent.vue b/test/fixtures/basic/components/ExtendMetaComponent.vue new file mode 100644 index 0000000..caf69d2 --- /dev/null +++ b/test/fixtures/basic/components/ExtendMetaComponent.vue @@ -0,0 +1,34 @@ + + + diff --git a/test/get-component-meta.test.ts b/test/get-component-meta.test.ts index 053a6ae..a9b58bb 100644 --- a/test/get-component-meta.test.ts +++ b/test/get-component-meta.test.ts @@ -38,4 +38,57 @@ describe("get-component-meta", () => { expect(meta.props.length).toEqual(4); expect((meta as unknown as Record).cachedAt).toBeDefined(); }); + + test("parse ExtendMetaComponent with extendComponentMeta", { timeout: 10000 }, () => { + const meta = getComponentMeta("components/ExtendMetaComponent.vue", { + rootDir, + }) + + // Check basic component metadata from defineProps/defineEmits + expect(meta.props.length).toEqual(2); // title, enabled + expect(meta.props.find(p => p.name === 'title')).toBeDefined(); + expect(meta.props.find(p => p.name === 'enabled')).toBeDefined(); + expect(meta.events.length).toEqual(1); + expect(meta.events[0].name).toEqual('updated'); + + // Check that extendComponentMeta adds custom metadata fields + const extendedMeta = meta as unknown as Record; + expect(extendedMeta.description).toEqual('A component that demonstrates extendComponentMeta functionality'); + expect(extendedMeta.version).toEqual('1.0.0'); + expect(extendedMeta.tags).toEqual(['test', 'meta']); + expect(extendedMeta.customData).toEqual({ + for: 'Test Suite', + category: 'utility' + }); + }); + + test("parse ExtendMetaComponent with extendComponentMeta (cached)", { timeout: 10000 }, () => { + const meta = getComponentMeta("components/ExtendMetaComponent.vue", { + rootDir, + cache: true + }) + + // Check that extendComponentMeta custom fields persist through caching + const extendedMeta = meta as unknown as Record; + expect(extendedMeta.description).toEqual('A component that demonstrates extendComponentMeta functionality'); + expect(extendedMeta.version).toEqual('1.0.0'); + expect(extendedMeta.tags).toEqual(['test', 'meta']); + expect(extendedMeta.customData).toEqual({ + for: 'Test Suite', + category: 'utility' + }); + expect(extendedMeta.cachedAt).toBeUndefined(); + }); + + test("parse ExtendMetaComponent cached retrieval", { timeout: 10000 }, () => { + const meta = getComponentMeta("components/ExtendMetaComponent.vue", { + rootDir, + cache: true + }) + + // Check that extendComponentMeta custom fields are preserved in cached version + const extendedMeta = meta as unknown as Record; + expect(extendedMeta.description).toEqual('A component that demonstrates extendComponentMeta functionality'); + expect(extendedMeta.cachedAt).toBeDefined(); + }); });