From eed69762e175066e1b8fb1e2ca02ca1b70025f03 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Fri, 2 Jul 2021 08:50:02 +0800 Subject: [PATCH] feat(declaration): preserve previous declartions and sort the result --- examples/vue3/components.d.ts | 20 +++++------ src/declaration.ts | 62 ++++++++++++++++++++++------------- 2 files changed, 50 insertions(+), 32 deletions(-) diff --git a/examples/vue3/components.d.ts b/examples/vue3/components.d.ts index 699a619b..3b8c4d7e 100644 --- a/examples/vue3/components.d.ts +++ b/examples/vue3/components.d.ts @@ -3,27 +3,27 @@ declare module 'vue' { export interface GlobalComponents { + Avatar: typeof import('./src/components/global/avatar.vue')['default'] + Book: typeof import('./src/components/book/index.vue')['default'] CarbonSvg: typeof import('./src/components/CarbonSvg.svg')['default'] ComponentA: typeof import('./src/components/ComponentA.vue')['default'] ComponentB: typeof import('./src/components/ComponentB.vue')['default'] + ComponentC: typeof import('./src/components/component-c.vue')['default'] ComponentD: typeof import('./src/components/ComponentD.vue')['default'] + IFaSolidDiceFive: typeof import('virtual:vite-icons/fa-solid/dice-five')['default'] + IHeroiconsOutlineMenuAlt2: typeof import('virtual:vite-icons/heroicons-outline/menu-alt2')['default'] + 'IMdi:diceD12': typeof import('virtual:vite-icons/mdi/dice-d12')['default'] + IMdiLightAlarm: typeof import('virtual:vite-icons/mdi-light/alarm')['default'] + IRiApps2Line: typeof import('virtual:vite-icons/ri/apps2-line')['default'] MarkdownA: typeof import('./src/components/MarkdownA.md')['default'] MarkdownB: typeof import('./src/components/MarkdownB.md')['default'] + MyCustom: typeof import('./src/CustomResolved.vue')['default'] Recursive: typeof import('./src/components/Recursive.vue')['default'] - ComponentC: typeof import('./src/components/component-c.vue')['default'] - Book: typeof import('./src/components/book/index.vue')['default'] - Avatar: typeof import('./src/components/global/avatar.vue')['default'] UiButton: typeof import('./src/components/ui/button.vue')['default'] UiNestedCheckbox: typeof import('./src/components/ui/nested/checkbox.vue')['default'] - MyCustom: typeof import('./src/CustomResolved.vue')['default'] - VanRate: typeof import('vant/es')['Rate'] VanRadio: typeof import('vant/es')['Radio'] VanRadioGroup: typeof import('vant/es')['RadioGroup'] - IFaSolidDiceFive: typeof import('virtual:vite-icons/fa-solid/dice-five')['default'] - IHeroiconsOutlineMenuAlt2: typeof import('virtual:vite-icons/heroicons-outline/menu-alt2')['default'] - IRiApps2Line: typeof import('virtual:vite-icons/ri/apps2-line')['default'] - 'IMdi:diceD12': typeof import('virtual:vite-icons/mdi/dice-d12')['default'] - IMdiLightAlarm: typeof import('virtual:vite-icons/mdi-light/alarm')['default'] + VanRate: typeof import('vant/es')['Rate'] } } diff --git a/src/declaration.ts b/src/declaration.ts index df15e005..5b9826a1 100644 --- a/src/declaration.ts +++ b/src/declaration.ts @@ -1,36 +1,54 @@ import { resolve, dirname, relative } from 'path' -import { promises as fs } from 'fs' +import { promises as fs, existsSync } from 'fs' import { notNullish } from '@antfu/utils' import { Context } from './context' import { slash } from './utils' +export function parseDeclaration(code: string): Record { + return Object.fromEntries(Array.from(code.matchAll(/\s+['"]?(.+?)['"]?:\s(.+?)\n/g)).map(i => [i[1], i[2]])) +} + export async function generateDeclaration(ctx: Context, root: string, filepath: string) { - const lines = Object.values({ - ...ctx.componentNameMap, - ...ctx.componentCustomMap, - }) - .map(({ path, name, importName }) => { - if (!name) - return undefined + const imports: Record = Object.fromEntries( + Object.values({ + ...ctx.componentNameMap, + ...ctx.componentCustomMap, + }) + .map(({ path, name, importName }) => { + if (!name) + return undefined + + const related = slash(path).startsWith('/') + ? `./${relative(dirname(filepath), resolve(root, path.slice(1)))}` + : path + + let entry = `typeof import('${slash(related)}')` + if (importName) + entry += `['${importName}']` + else + entry += '[\'default\']' + return [name, entry] + }) + .filter(notNullish), + ) - const related = slash(path).startsWith('/') - ? `./${relative(dirname(filepath), resolve(root, path.slice(1)))}` - : path + if (!Object.keys(imports).length) + return + + const originalImports = existsSync(filepath) + ? parseDeclaration(await fs.readFile(filepath, 'utf-8')) + : {} + const lines = Object.entries({ + ...originalImports, + ...imports, + }) + .sort((a, b) => a[0].localeCompare(b[0])) + .map(([name, v]) => { if (!/^\w+$/.test(name)) name = `'${name}'` - - let entry = `${name}: typeof import('${slash(related)}')` - if (importName) - entry += `['${importName}']` - else - entry += '[\'default\']' - return entry + return `${name}: ${v}` }) - .filter(notNullish) - - if (!lines.length) - return const code = `// generated by vite-plugin-components // read more https://github.com/vuejs/vue-next/pull/3399