@fumadocs/cli 1.2.6 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/index.d.ts +1 -1
- package/dist/build/index.d.ts.map +1 -1
- package/dist/build/index.js.map +1 -1
- package/dist/{config-DH5Ggyir.js → config-BYrMmXOw.js} +3 -3
- package/dist/{config-DH5Ggyir.js.map → config-BYrMmXOw.js.map} +1 -1
- package/dist/{config-ndMKrpJz.d.ts → config-Dyass4D9.d.ts} +3 -3
- package/dist/{config-ndMKrpJz.d.ts.map → config-Dyass4D9.d.ts.map} +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/index.js +53 -6
- package/dist/index.js.map +1 -1
- package/dist/{installer-DQzu7o9x.js → installer-B3-my9zN.js} +93 -54
- package/dist/installer-B3-my9zN.js.map +1 -0
- package/dist/registry/client.d.ts +6 -6
- package/dist/registry/client.d.ts.map +1 -1
- package/dist/registry/installer/index.d.ts +41 -12
- package/dist/registry/installer/index.d.ts.map +1 -1
- package/dist/registry/installer/index.js +1 -1
- package/dist/registry/schema.d.ts +1 -1
- package/dist/registry/schema.js +4 -6
- package/dist/registry/schema.js.map +1 -1
- package/dist/schema/default.json +1 -1
- package/dist/schema/src.json +1 -1
- package/dist/{schema-DADC22m_.d.ts → schema-80shuzWO.d.ts} +5 -5
- package/dist/{schema-DADC22m_.d.ts.map → schema-80shuzWO.d.ts.map} +1 -1
- package/package.json +7 -7
- package/dist/installer-DQzu7o9x.js.map +0 -1
package/dist/build/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { p as registryInfoSchema, s as NamespaceType, t as CompiledComponent } from "../schema-
|
|
1
|
+
import { p as registryInfoSchema, s as NamespaceType, t as CompiledComponent } from "../schema-80shuzWO.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { ResolverFactory } from "oxc-resolver";
|
|
4
4
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/build/compiler.ts","../../src/build/index.ts"],"mappings":";;;;;KAgBY,SAAA,IACV,SAAA,EAAW,eAAA,EACX,IAAA;EAAQ,SAAA,EAAW,SAAA;EAAW,IAAA,EAAM,aAAA;AAAA,MACjC,SAAA;AAAA,UAEY,gBAAA;EACf,IAAA;EACA,UAAA,EAAY,iBAAA;EACZ,IAAA,EAAM,CAAA,CAAE,MAAA,QAAc,kBAAA;AAAA;AAAA,UAGP,aAAA;EACf,IAAA,EAAM,aAAA;EACN,IAAA;EACA,MAAA;AAAA;AAAA,UAGe,SAAA;EACf,IAAA;EACA,KAAA;EACA,WAAA;EACA,KAAA,EAAO,aAAA;EACP,YAAA,GAAe,MAAA;EACf,eAAA,GAAkB,MAAA;EAlBH;;;EAuBf,QAAA;EApBsB;;;EAyBtB,SAAA,GAAY,SAAA;AAAA;AAAA,UAGG,WAAA;EACf,YAAA,GAAe,MAAA;EACf,eAAA,GAAkB,MAAA;AAAA;AAAA,UAGH,QAAA,SAAiB,IAAA,CAAK,CAAA,CAAE,KAAA,QAAa,kBAAA;EACpD,IAAA;EACA,WAAA,WAAsB,WAAA;EACtB,YAAA;EACA,UAAA,EAAY,SAAA;EAlCgB;;;EAuC5B,GAAA;EAtCM;;;EA2CN,SAAA,GAAY,SAAA;EAzCN;AAGR;;;EA2CE,aAAA,IAAiB,YAAA,aAAyB,aAAA;EAE1C,YAAA,GAAe,MAAA;EACf,eAAA,GAAkB,MAAA;AAAA;AAAA,cAGP,gBAAA;EAAA,SACF,GAAA,EAAK,QAAA;EACd,QAAA,EAAW,gBAAA;cAEC,QAAA,EAAU,QAAA;EAAA,QAIR,eAAA;EASR,OAAA,CAAA,GAAW,OAAA,CAAQ,gBAAA;AAAA;AAAA,cAqCrB,gBAAA;EAAA,iBAOe,QAAA;EAAA,iBANF,IAAA;EAAA,iBACA,OAAA;EAAA,iBACA,eAAA;EAAA,SACR,GAAA,EAAK,eAAA;cAGK,QAAA,EAAU,gBAAA,EAC3B,WAAA,GAAa,WAAA;EAkCf,mBAAA,CAAoB,SAAA;EAMpB,UAAA,CAAW,IAAA;IAEL,IAAA;IACA,IAAA;IACA,OAAA;EAAA;EAoBN,kBAAA,CAAmB,IAAA,WAAe,SAAA;EAIlC,eAAA,CAAgB,IAAA;;;;;KAYN,eAAA;EAEN,IAAA;;;;EAIA,IAAA;AAAA;EAGA,IAAA;EACA,GAAA;EACA,SAAA;AAAA;EAGA,IAAA;EACA,QAAA;IAEM,IAAA;IACA,SAAA,EAAW,SAAA;IACX,IAAA,EAAM,aAAA;EAAA;IAGN,IAAA;IACA,SAAA,EAAW,SAAA;IACX,IAAA,EAAM,aAAA;IACN,YAAA;EAAA;AAAA;EAIN,IAAA;EACA,SAAA;AAAA;AAAA,KAGM,SAAA,GACR,eAAA;EAEE,IAAA;EACA,SAAA;AAAA;AAAA,cAGO,iBAAA;EAAA,iBAQQ,QAAA;EAAA,iBACA,SAAA;EAAA,iBARF,cAAA;EAAA,iBACA,QAAA;EAAA,iBACA,aAAA;EAAA,iBACA,eAAA;EAAA,iBACA,YAAA;cAGE,QAAA,EAAU,gBAAA,EACV,SAAA,EAAW,SAAA;EAAA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/build/compiler.ts","../../src/build/index.ts"],"mappings":";;;;;KAgBY,SAAA,IACV,SAAA,EAAW,eAAA,EACX,IAAA;EAAQ,SAAA,EAAW,SAAA;EAAW,IAAA,EAAM,aAAA;AAAA,MACjC,SAAA;AAAA,UAEY,gBAAA;EACf,IAAA;EACA,UAAA,EAAY,iBAAA;EACZ,IAAA,EAAM,CAAA,CAAE,MAAA,QAAc,kBAAA;AAAA;AAAA,UAGP,aAAA;EACf,IAAA,EAAM,aAAA;EACN,IAAA;EACA,MAAA;AAAA;AAAA,UAGe,SAAA;EACf,IAAA;EACA,KAAA;EACA,WAAA;EACA,KAAA,EAAO,aAAA;EACP,YAAA,GAAe,MAAA;EACf,eAAA,GAAkB,MAAA;EAlBH;;;EAuBf,QAAA;EApBsB;;;EAyBtB,SAAA,GAAY,SAAA;AAAA;AAAA,UAGG,WAAA;EACf,YAAA,GAAe,MAAA;EACf,eAAA,GAAkB,MAAA;AAAA;AAAA,UAGH,QAAA,SAAiB,IAAA,CAAK,CAAA,CAAE,KAAA,QAAa,kBAAA;EACpD,IAAA;EACA,WAAA,WAAsB,WAAA;EACtB,YAAA;EACA,UAAA,EAAY,SAAA;EAlCgB;;;EAuC5B,GAAA;EAtCM;;;EA2CN,SAAA,GAAY,SAAA;EAzCN;AAGR;;;EA2CE,aAAA,IAAiB,YAAA,aAAyB,aAAA;EAE1C,YAAA,GAAe,MAAA;EACf,eAAA,GAAkB,MAAA;AAAA;AAAA,cAGP,gBAAA;EAAA,SACF,GAAA,EAAK,QAAA;EACd,QAAA,EAAW,gBAAA;cAEC,QAAA,EAAU,QAAA;EAAA,QAIR,eAAA;EASR,OAAA,CAAA,GAAW,OAAA,CAAQ,gBAAA;AAAA;AAAA,cAqCrB,gBAAA;EAAA,iBAOe,QAAA;EAAA,iBANF,IAAA;EAAA,iBACA,OAAA;EAAA,iBACA,eAAA;EAAA,SACR,GAAA,EAAK,eAAA;cAGK,QAAA,EAAU,gBAAA,EAC3B,WAAA,GAAa,WAAA;EAkCf,mBAAA,CAAoB,SAAA;EAMpB,UAAA,CAAW,IAAA;IAEL,IAAA;IACA,IAAA;IACA,OAAA;EAAA;EAoBN,kBAAA,CAAmB,IAAA,WAAe,SAAA;EAIlC,eAAA,CAAgB,IAAA;;;;;KAYN,eAAA;EAEN,IAAA;;;;EAIA,IAAA;AAAA;EAGA,IAAA;EACA,GAAA;EACA,SAAA;AAAA;EAGA,IAAA;EACA,QAAA;IAEM,IAAA;IACA,SAAA,EAAW,SAAA;IACX,IAAA,EAAM,aAAA;EAAA;IAGN,IAAA;IACA,SAAA,EAAW,SAAA;IACX,IAAA,EAAM,aAAA;IACN,YAAA;EAAA;AAAA;EAIN,IAAA;EACA,SAAA;AAAA;AAAA,KAGM,SAAA,GACR,eAAA;EAEE,IAAA;EACA,SAAA;AAAA;AAAA,cAGO,iBAAA;EAAA,iBAQQ,QAAA;EAAA,iBACA,SAAA;EAAA,iBARF,cAAA;EAAA,iBACA,QAAA;EAAA,iBACA,aAAA;EAAA,iBACA,eAAA;EAAA,iBACA,YAAA;cAGE,QAAA,EAAU,gBAAA,EACV,SAAA,EAAW,SAAA;EAAA,QAKtB,YAAA;EAQF,KAAA,CAAA,GAAS,OAAA,CAAQ,iBAAA;EAAA,QAyBT,WAAA;EAAA,QA2DA,SAAA;AAAA;AAAA,iBAyFA,iBAAA,CACd,CAAA,EAAG,QAAA,EACH,SAAA,UACA,UAAA,GAAa,IAAA,EAAM,aAAA,eAClB,SAAA;;;UCxcc,YAAA,SAAqB,gBAAA;EACpC,UAAA,EAAY,gBAAA;AAAA;AAAA,iBAGE,eAAA,CACd,IAAA,EAAM,gBAAA,KACH,KAAA,EAAO,gBAAA,KACT,YAAA;AAAA,iBAWmB,qBAAA,CACpB,GAAA,EAAK,gBAAA,GAAmB,YAAA,EACxB,OAAA;EACE,GAAA;EDXS;;;;;ECkBT,QAAA;EAEA,GAAA;AAAA,IAED,OAAA"}
|
package/dist/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["fs","path","fs","path"],"sources":["../../src/build/compiler.ts","../../src/build/index.ts"],"sourcesContent":["import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type {\n CompiledComponent,\n CompiledFile,\n httpSubComponent,\n NamespaceType,\n registryInfoSchema,\n} from '@/registry/schema';\nimport type { z } from 'zod';\nimport { parse } from 'oxc-parser';\nimport { ResolverFactory } from 'oxc-resolver';\nimport MagicString from 'magic-string';\nimport { transformSpecifiers } from '@/utils/ast';\nimport { isRelative } from '@/utils/fs';\n\nexport type OnResolve = (\n reference: SourceReference,\n from: { component: Component; file: ComponentFile },\n) => Reference;\n\nexport interface CompiledRegistry {\n name: string;\n components: CompiledComponent[];\n info: z.output<typeof registryInfoSchema>;\n}\n\nexport interface ComponentFile {\n type: NamespaceType;\n path: string;\n target?: string;\n}\n\nexport interface Component {\n name: string;\n title?: string;\n description?: string;\n files: ComponentFile[];\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n\n /**\n * Don't list the component in registry index file\n */\n unlisted?: boolean;\n\n /**\n * Map imported file paths, inherit from registry if not defined.\n */\n onResolve?: OnResolve;\n}\n\nexport interface PackageJson {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nexport interface Registry extends Omit<z.input<typeof registryInfoSchema>, 'indexes'> {\n name: string;\n packageJson: string | PackageJson;\n tsconfigPath: string;\n components: Component[];\n\n /**\n * The directory of registry, used to resolve relative paths\n */\n dir: string;\n\n /**\n * Map import paths of components\n */\n onResolve?: OnResolve;\n /**\n * When a referenced file is not found in component files, this function is called.\n * @returns file, or `false` to mark as external.\n */\n onUnknownFile?: (absolutePath: string) => ComponentFile | false | undefined;\n\n dependencies?: Record<string, string | null>;\n devDependencies?: Record<string, string | null>;\n}\n\nexport class RegistryCompiler {\n readonly raw: Registry;\n resolver!: RegistryResolver;\n\n constructor(registry: Registry) {\n this.raw = registry;\n }\n\n private async readPackageJson(): Promise<PackageJson | undefined> {\n if (typeof this.raw.packageJson !== 'string') return this.raw.packageJson;\n\n return fs\n .readFile(path.join(this.raw.dir, this.raw.packageJson))\n .then((res) => JSON.parse(res.toString()) as PackageJson)\n .catch(() => undefined);\n }\n\n async compile(): Promise<CompiledRegistry> {\n const registry = this.raw;\n this.resolver = new RegistryResolver(this, await this.readPackageJson());\n const output: CompiledRegistry = {\n name: registry.name,\n info: {\n indexes: [],\n env: registry.env,\n variables: registry.variables,\n },\n components: [],\n };\n\n const builtComps = await Promise.all(\n registry.components.map(async (component) => {\n const compiler = new ComponentCompiler(this, component);\n\n return [component, await compiler.build()] as [Component, CompiledComponent];\n }),\n );\n\n for (const [input, comp] of builtComps) {\n if (!input.unlisted) {\n output.info.indexes.push({\n name: input.name,\n title: input.title,\n description: input.description,\n });\n }\n\n output.components.push(comp);\n }\n\n return output;\n }\n}\n\nclass RegistryResolver {\n private readonly deps: Record<string, string | null>;\n private readonly devDeps: Record<string, string | null>;\n private readonly fileToComponent = new Map<string, [Component, ComponentFile]>();\n readonly oxc: ResolverFactory;\n\n constructor(\n private readonly compiler: RegistryCompiler,\n packageJson: PackageJson = {},\n ) {\n const registry = compiler.raw;\n\n for (const comp of registry.components) {\n for (const file of comp.files) {\n if (this.fileToComponent.has(file.path))\n console.warn(\n `the same file ${file.path} exists in multiple component, you should make the shared file a separate component.`,\n );\n this.fileToComponent.set(file.path, [comp, file]);\n }\n }\n\n this.deps = {\n ...packageJson?.dependencies,\n ...registry.dependencies,\n };\n\n this.devDeps = {\n ...packageJson?.devDependencies,\n ...registry.devDependencies,\n };\n\n // resolve anything possible\n this.oxc = new ResolverFactory({\n extensions: ['.js', '.jsx', '.ts', '.tsx', '.node'],\n conditionNames: ['node', 'import', 'require', 'default', 'types'],\n tsconfig: {\n configFile: path.join(registry.dir, registry.tsconfigPath),\n },\n });\n }\n\n getDepFromSpecifier(specifier: string) {\n return specifier.startsWith('@')\n ? specifier.split('/').slice(0, 2).join('/')\n : specifier.split('/')[0];\n }\n\n getDepInfo(name: string):\n | {\n type: 'runtime' | 'dev';\n name: string;\n version: string | null;\n }\n | undefined {\n if (name in this.deps)\n return {\n name,\n type: 'runtime',\n version: this.deps[name],\n };\n\n if (name in this.devDeps)\n return {\n name,\n type: 'dev',\n version: this.devDeps[name],\n };\n\n console.warn(`dep info for ${name} cannot be found`);\n }\n\n getComponentByName(name: string): Component | undefined {\n return this.compiler.raw.components.find((comp) => comp.name === name);\n }\n\n getSubComponent(file: string) {\n const relativeFile = path.relative(this.compiler.raw.dir, file);\n const comp = this.fileToComponent.get(relativeFile);\n\n if (!comp) return;\n return {\n component: comp[0],\n file: comp[1],\n };\n }\n}\n\nexport type SourceReference =\n | {\n type: 'file';\n /**\n * Absolute path\n */\n file: string;\n }\n | {\n type: 'dependency';\n dep: string;\n specifier: string;\n }\n | {\n type: 'sub-component';\n resolved:\n | {\n type: 'local';\n component: Component;\n file: ComponentFile;\n }\n | {\n type: 'remote';\n component: Component;\n file: ComponentFile;\n registryName: string;\n };\n }\n | {\n type: 'unknown-specifier';\n specifier: string;\n };\n\nexport type Reference =\n | SourceReference\n | {\n type: 'custom';\n specifier: string;\n };\n\nexport class ComponentCompiler {\n private readonly processedFiles = new Set<string>();\n private readonly registry: Registry;\n private readonly subComponents = new Map<string, string | z.input<typeof httpSubComponent>>();\n private readonly devDependencies = new Map<string, string | null>();\n private readonly dependencies = new Map<string, string | null>();\n\n constructor(\n private readonly compiler: RegistryCompiler,\n private readonly component: Component,\n ) {\n this.registry = compiler.raw;\n }\n\n // see https://github.com/shadcn-ui/ui/blob/396275e46a58333caa1fa0a991bd9bc5237d2ee3/packages/shadcn/src/utils/updaters/update-files.ts#L585\n // to hit the fast-path step, we need to import `target` path first because it's detected from `fileSet`, a set of output file paths\n private toImportPath(file: ComponentFile): string {\n let filePath = file.target ?? file.path;\n\n if (filePath.startsWith('./')) filePath = filePath.slice(2);\n\n return `@/${filePath.replaceAll(path.sep, '/')}`;\n }\n\n async build(): Promise<CompiledComponent> {\n const files = (\n await Promise.all(this.component.files.map((file) => this.onBuildFile(file)))\n ).flat();\n const dependencies = Object.fromEntries(this.dependencies);\n const devDependencies = Object.fromEntries(this.devDependencies);\n\n if (this.component.dependencies) {\n Object.assign(dependencies, this.component.dependencies);\n }\n if (this.component.devDependencies) {\n Object.assign(devDependencies, this.component.devDependencies);\n }\n\n return {\n name: this.component.name,\n title: this.component.title,\n description: this.component.description,\n files,\n subComponents: Array.from(this.subComponents.values()),\n dependencies,\n devDependencies,\n };\n }\n\n private async onBuildFile(file: ComponentFile): Promise<CompiledFile[]> {\n if (this.processedFiles.has(file.path)) return [];\n this.processedFiles.add(file.path);\n const resolver = this.compiler.resolver;\n\n const queue: ComponentFile[] = [];\n const result = await this.buildFile(file, (reference) => {\n if (reference.type === 'unknown-specifier') {\n if (!reference.specifier.startsWith('node:')) {\n console.warn(`Unknown specifier ${reference.specifier}, skipping for now`);\n }\n\n return reference.specifier;\n }\n\n if (reference.type === 'custom') return reference.specifier;\n\n if (reference.type === 'file') {\n const refFile = this.registry.onUnknownFile?.(reference.file);\n if (refFile) {\n queue.push(refFile);\n return this.toImportPath(refFile);\n }\n\n if (refFile === false) return;\n\n throw new Error(`Unknown file ${reference.file} referenced by ${file.path}`);\n }\n\n if (reference.type === 'sub-component') {\n const resolved = reference.resolved;\n if (resolved.component.name === this.component.name)\n return this.toImportPath(resolved.file);\n\n if (resolved.type === 'remote') {\n this.subComponents.set(`${resolved.registryName}:${resolved.component.name}`, {\n type: 'http',\n baseUrl: resolved.registryName,\n component: resolved.component.name,\n });\n } else {\n this.subComponents.set(resolved.component.name, resolved.component.name);\n }\n\n return this.toImportPath(resolved.file);\n }\n\n const dep = resolver.getDepInfo(reference.dep);\n if (dep) {\n const map = dep.type === 'dev' ? this.devDependencies : this.dependencies;\n map.set(dep.name, dep.version);\n }\n\n return reference.specifier;\n });\n\n return [result, ...(await Promise.all(queue.map((file) => this.onBuildFile(file)))).flat()];\n }\n\n private async buildFile(\n file: ComponentFile,\n /**\n * write references back to import specifiers\n *\n * keep original one if `undefined`\n */\n writeReference: (reference: Reference) => string | undefined,\n ): Promise<CompiledFile> {\n const sourceFilePath = path.join(this.registry.dir, file.path);\n const astTypes: Record<string, 'js' | 'ts' | undefined> = {\n '.ts': 'ts',\n '.tsx': 'ts',\n '.js': 'js',\n '.jsx': 'js',\n };\n const astType = astTypes[path.extname(file.path)];\n const content = (await fs.readFile(sourceFilePath)).toString();\n\n if (!astType)\n return {\n content,\n path: file.path,\n type: file.type,\n target: file.target,\n };\n\n const resolver = this.compiler.resolver;\n\n const ast = await parse(sourceFilePath, content, {\n astType,\n });\n\n if (ast.errors.length > 0) {\n throw new Error(`failed to parse file ${sourceFilePath}: \\n${ast.errors.join('\\n')}`);\n }\n\n const s = new MagicString(content);\n const ctx = { component: this.component, file };\n // Process import paths\n transformSpecifiers(ast.program, s, (specifier) => {\n let resolved: Reference = {\n type: 'unknown-specifier',\n specifier: specifier,\n };\n const onResolve = this.component.onResolve ?? this.registry.onResolve;\n const resolvedSpecifier = resolver.oxc.resolveFileSync(sourceFilePath, specifier);\n if (resolvedSpecifier.error || !resolvedSpecifier.path) {\n return writeReference(onResolve ? onResolve(resolved, ctx) : resolved);\n }\n\n resolved = {\n type: 'file',\n file: resolvedSpecifier.path,\n };\n\n // outside of registry dir\n if (!isRelative(this.registry.dir, resolvedSpecifier.path)) {\n resolved = {\n type: 'dependency',\n dep: resolver.getDepFromSpecifier(specifier),\n specifier,\n };\n } else {\n const sub = resolver.getSubComponent(resolvedSpecifier.path);\n if (sub) {\n resolved = {\n type: 'sub-component',\n resolved: {\n type: 'local',\n component: sub.component,\n file: sub.file,\n },\n };\n }\n }\n\n return writeReference(onResolve ? onResolve(resolved, ctx) : resolved);\n });\n\n return {\n content: s.toString(),\n type: file.type,\n path: file.path,\n target: file.target,\n };\n }\n}\n\nexport function resolveFromRemote(\n r: Registry,\n component: string,\n selectFile: (file: ComponentFile) => boolean,\n): Reference | undefined {\n const comp = r.components.find((comp) => comp.name === component);\n if (!comp) return;\n const file = comp.files.find(selectFile);\n if (!file) return;\n\n return {\n type: 'sub-component',\n resolved: {\n type: 'remote',\n registryName: r.name,\n component: comp,\n file,\n },\n };\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport picocolors from 'picocolors';\nimport type { CompiledRegistry } from '@/build/compiler';\n\nexport * from './compiler';\n\nexport interface MonoRegistry extends CompiledRegistry {\n registries: CompiledRegistry[];\n}\n\nexport function combineRegistry(\n root: CompiledRegistry,\n ...items: CompiledRegistry[]\n): MonoRegistry {\n return {\n ...root,\n info: {\n ...root.info,\n registries: items.map((item) => item.name),\n },\n registries: items,\n };\n}\n\nexport async function writeFumadocsRegistry(\n out: CompiledRegistry | MonoRegistry,\n options: {\n dir: string;\n\n /**\n * Remove previous outputs\n *\n * @defaultValue false\n */\n cleanDir?: boolean;\n\n log?: boolean;\n },\n): Promise<void> {\n const { dir, cleanDir = false, log = true } = options;\n\n if (cleanDir) {\n await fs.rm(dir, {\n recursive: true,\n force: true,\n });\n console.log(picocolors.bold(picocolors.greenBright('Cleaned directory')));\n }\n\n async function writeInfo() {\n const file = path.join(dir, '_registry.json');\n const json = JSON.stringify(out.info, null, 2);\n\n await writeFile(file, json, log);\n }\n\n const write = out.components.map(async (comp) => {\n const file = path.join(dir, `${comp.name}.json`);\n const json = JSON.stringify(comp, null, 2);\n\n await writeFile(file, json, log);\n });\n\n write.push(writeInfo());\n if ('registries' in out) {\n for (const child of out.registries) {\n write.push(\n writeFumadocsRegistry(child, {\n dir: path.join(dir, child.name),\n log: options.log,\n }),\n );\n }\n }\n\n await Promise.all(write);\n}\n\nasync function writeFile(file: string, content: string, log = true): Promise<void> {\n await fs.mkdir(path.dirname(file), { recursive: true });\n await fs.writeFile(file, content);\n\n if (log) {\n const size = (Buffer.byteLength(content) / 1024).toFixed(2);\n\n console.log(\n `${picocolors.greenBright('+')} ${path.relative(process.cwd(), file)} ${picocolors.dim(`${size} KB`)}`,\n );\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["fs","path","fs","path"],"sources":["../../src/build/compiler.ts","../../src/build/index.ts"],"sourcesContent":["import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type {\n CompiledComponent,\n CompiledFile,\n httpSubComponent,\n NamespaceType,\n registryInfoSchema,\n} from '@/registry/schema';\nimport type { z } from 'zod';\nimport { parse } from 'oxc-parser';\nimport { ResolverFactory } from 'oxc-resolver';\nimport MagicString from 'magic-string';\nimport { transformSpecifiers } from '@/utils/ast';\nimport { isRelative } from '@/utils/fs';\n\nexport type OnResolve = (\n reference: SourceReference,\n from: { component: Component; file: ComponentFile },\n) => Reference;\n\nexport interface CompiledRegistry {\n name: string;\n components: CompiledComponent[];\n info: z.output<typeof registryInfoSchema>;\n}\n\nexport interface ComponentFile {\n type: NamespaceType;\n path: string;\n target?: string;\n}\n\nexport interface Component {\n name: string;\n title?: string;\n description?: string;\n files: ComponentFile[];\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n\n /**\n * Don't list the component in registry index file\n */\n unlisted?: boolean;\n\n /**\n * Map imported file paths, inherit from registry if not defined.\n */\n onResolve?: OnResolve;\n}\n\nexport interface PackageJson {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nexport interface Registry extends Omit<z.input<typeof registryInfoSchema>, 'indexes'> {\n name: string;\n packageJson: string | PackageJson;\n tsconfigPath: string;\n components: Component[];\n\n /**\n * The directory of registry, used to resolve relative paths\n */\n dir: string;\n\n /**\n * Map import paths of components\n */\n onResolve?: OnResolve;\n /**\n * When a referenced file is not found in component files, this function is called.\n * @returns file, or `false` to mark as external.\n */\n onUnknownFile?: (absolutePath: string) => ComponentFile | false | undefined;\n\n dependencies?: Record<string, string | null>;\n devDependencies?: Record<string, string | null>;\n}\n\nexport class RegistryCompiler {\n readonly raw: Registry;\n resolver!: RegistryResolver;\n\n constructor(registry: Registry) {\n this.raw = registry;\n }\n\n private async readPackageJson(): Promise<PackageJson | undefined> {\n if (typeof this.raw.packageJson !== 'string') return this.raw.packageJson;\n\n return fs\n .readFile(path.join(this.raw.dir, this.raw.packageJson))\n .then((res) => JSON.parse(res.toString()) as PackageJson)\n .catch(() => undefined);\n }\n\n async compile(): Promise<CompiledRegistry> {\n const registry = this.raw;\n this.resolver = new RegistryResolver(this, await this.readPackageJson());\n const output: CompiledRegistry = {\n name: registry.name,\n info: {\n indexes: [],\n env: registry.env,\n variables: registry.variables,\n },\n components: [],\n };\n\n const builtComps = await Promise.all(\n registry.components.map(async (component) => {\n const compiler = new ComponentCompiler(this, component);\n\n return [component, await compiler.build()] as [Component, CompiledComponent];\n }),\n );\n\n for (const [input, comp] of builtComps) {\n if (!input.unlisted) {\n output.info.indexes.push({\n name: input.name,\n title: input.title,\n description: input.description,\n });\n }\n\n output.components.push(comp);\n }\n\n return output;\n }\n}\n\nclass RegistryResolver {\n private readonly deps: Record<string, string | null>;\n private readonly devDeps: Record<string, string | null>;\n private readonly fileToComponent = new Map<string, [Component, ComponentFile]>();\n readonly oxc: ResolverFactory;\n\n constructor(\n private readonly compiler: RegistryCompiler,\n packageJson: PackageJson = {},\n ) {\n const registry = compiler.raw;\n\n for (const comp of registry.components) {\n for (const file of comp.files) {\n if (this.fileToComponent.has(file.path))\n console.warn(\n `the same file ${file.path} exists in multiple component, you should make the shared file a separate component.`,\n );\n this.fileToComponent.set(file.path, [comp, file]);\n }\n }\n\n this.deps = {\n ...packageJson?.dependencies,\n ...registry.dependencies,\n };\n\n this.devDeps = {\n ...packageJson?.devDependencies,\n ...registry.devDependencies,\n };\n\n // resolve anything possible\n this.oxc = new ResolverFactory({\n extensions: ['.js', '.jsx', '.ts', '.tsx', '.node'],\n conditionNames: ['node', 'import', 'require', 'default', 'types'],\n tsconfig: {\n configFile: path.join(registry.dir, registry.tsconfigPath),\n },\n });\n }\n\n getDepFromSpecifier(specifier: string) {\n return specifier.startsWith('@')\n ? specifier.split('/').slice(0, 2).join('/')\n : specifier.split('/')[0];\n }\n\n getDepInfo(name: string):\n | {\n type: 'runtime' | 'dev';\n name: string;\n version: string | null;\n }\n | undefined {\n if (name in this.deps)\n return {\n name,\n type: 'runtime',\n version: this.deps[name],\n };\n\n if (name in this.devDeps)\n return {\n name,\n type: 'dev',\n version: this.devDeps[name],\n };\n\n console.warn(`dep info for ${name} cannot be found`);\n }\n\n getComponentByName(name: string): Component | undefined {\n return this.compiler.raw.components.find((comp) => comp.name === name);\n }\n\n getSubComponent(file: string) {\n const relativeFile = path.relative(this.compiler.raw.dir, file);\n const comp = this.fileToComponent.get(relativeFile);\n\n if (!comp) return;\n return {\n component: comp[0],\n file: comp[1],\n };\n }\n}\n\nexport type SourceReference =\n | {\n type: 'file';\n /**\n * Absolute path\n */\n file: string;\n }\n | {\n type: 'dependency';\n dep: string;\n specifier: string;\n }\n | {\n type: 'sub-component';\n resolved:\n | {\n type: 'local';\n component: Component;\n file: ComponentFile;\n }\n | {\n type: 'remote';\n component: Component;\n file: ComponentFile;\n registryName: string;\n };\n }\n | {\n type: 'unknown-specifier';\n specifier: string;\n };\n\nexport type Reference =\n | SourceReference\n | {\n type: 'custom';\n specifier: string;\n };\n\nexport class ComponentCompiler {\n private readonly processedFiles = new Set<string>();\n private readonly registry: Registry;\n private readonly subComponents = new Map<string, string | z.input<typeof httpSubComponent>>();\n private readonly devDependencies = new Map<string, string | null>();\n private readonly dependencies = new Map<string, string | null>();\n\n constructor(\n private readonly compiler: RegistryCompiler,\n private readonly component: Component,\n ) {\n this.registry = compiler.raw;\n }\n\n private toImportPath(file: ComponentFile): string {\n let filePath = file.target ?? file.path;\n\n if (filePath.startsWith('./')) filePath = filePath.slice(2);\n\n return `@/${filePath.replaceAll(path.sep, '/')}`;\n }\n\n async build(): Promise<CompiledComponent> {\n const files = (\n await Promise.all(this.component.files.map((file) => this.onBuildFile(file)))\n ).flat();\n const dependencies = Object.fromEntries(this.dependencies);\n const devDependencies = Object.fromEntries(this.devDependencies);\n\n if (this.component.dependencies) {\n Object.assign(dependencies, this.component.dependencies);\n }\n if (this.component.devDependencies) {\n Object.assign(devDependencies, this.component.devDependencies);\n }\n\n return {\n name: this.component.name,\n title: this.component.title,\n description: this.component.description,\n files,\n subComponents: Array.from(this.subComponents.values()),\n dependencies,\n devDependencies,\n };\n }\n\n private async onBuildFile(file: ComponentFile): Promise<CompiledFile[]> {\n if (this.processedFiles.has(file.path)) return [];\n this.processedFiles.add(file.path);\n const resolver = this.compiler.resolver;\n\n const queue: ComponentFile[] = [];\n const result = await this.buildFile(file, (reference) => {\n if (reference.type === 'unknown-specifier') {\n if (!reference.specifier.startsWith('node:')) {\n console.warn(`Unknown specifier ${reference.specifier}, skipping for now`);\n }\n\n return reference.specifier;\n }\n\n if (reference.type === 'custom') return reference.specifier;\n\n if (reference.type === 'file') {\n const refFile = this.registry.onUnknownFile?.(reference.file);\n if (refFile) {\n queue.push(refFile);\n return this.toImportPath(refFile);\n }\n\n if (refFile === false) return;\n\n throw new Error(`Unknown file ${reference.file} referenced by ${file.path}`);\n }\n\n if (reference.type === 'sub-component') {\n const resolved = reference.resolved;\n if (resolved.component.name === this.component.name)\n return this.toImportPath(resolved.file);\n\n if (resolved.type === 'remote') {\n this.subComponents.set(`${resolved.registryName}:${resolved.component.name}`, {\n type: 'http',\n baseUrl: resolved.registryName,\n component: resolved.component.name,\n });\n } else {\n this.subComponents.set(resolved.component.name, resolved.component.name);\n }\n\n return this.toImportPath(resolved.file);\n }\n\n const dep = resolver.getDepInfo(reference.dep);\n if (dep) {\n const map = dep.type === 'dev' ? this.devDependencies : this.dependencies;\n map.set(dep.name, dep.version);\n }\n\n return reference.specifier;\n });\n\n return [result, ...(await Promise.all(queue.map((file) => this.onBuildFile(file)))).flat()];\n }\n\n private async buildFile(\n file: ComponentFile,\n /**\n * write references back to import specifiers\n *\n * keep original one if `undefined`\n */\n writeReference: (reference: Reference) => string | undefined,\n ): Promise<CompiledFile> {\n const sourceFilePath = path.join(this.registry.dir, file.path);\n const astTypes: Record<string, 'js' | 'ts' | undefined> = {\n '.ts': 'ts',\n '.tsx': 'ts',\n '.js': 'js',\n '.jsx': 'js',\n };\n const astType = astTypes[path.extname(file.path)];\n const content = (await fs.readFile(sourceFilePath)).toString();\n\n if (!astType)\n return {\n content,\n path: file.path,\n type: file.type,\n target: file.target,\n };\n\n const resolver = this.compiler.resolver;\n\n const ast = await parse(sourceFilePath, content, {\n astType,\n });\n\n if (ast.errors.length > 0) {\n throw new Error(`failed to parse file ${sourceFilePath}: \\n${ast.errors.join('\\n')}`);\n }\n\n const s = new MagicString(content);\n const ctx = { component: this.component, file };\n // Process import paths\n transformSpecifiers(ast.program, s, (specifier) => {\n let resolved: Reference = {\n type: 'unknown-specifier',\n specifier: specifier,\n };\n const onResolve = this.component.onResolve ?? this.registry.onResolve;\n const resolvedSpecifier = resolver.oxc.resolveFileSync(sourceFilePath, specifier);\n if (resolvedSpecifier.error || !resolvedSpecifier.path) {\n return writeReference(onResolve ? onResolve(resolved, ctx) : resolved);\n }\n\n resolved = {\n type: 'file',\n file: resolvedSpecifier.path,\n };\n\n // outside of registry dir\n if (!isRelative(this.registry.dir, resolvedSpecifier.path)) {\n resolved = {\n type: 'dependency',\n dep: resolver.getDepFromSpecifier(specifier),\n specifier,\n };\n } else {\n const sub = resolver.getSubComponent(resolvedSpecifier.path);\n if (sub) {\n resolved = {\n type: 'sub-component',\n resolved: {\n type: 'local',\n component: sub.component,\n file: sub.file,\n },\n };\n }\n }\n\n return writeReference(onResolve ? onResolve(resolved, ctx) : resolved);\n });\n\n return {\n content: s.toString(),\n type: file.type,\n path: file.path,\n target: file.target,\n };\n }\n}\n\nexport function resolveFromRemote(\n r: Registry,\n component: string,\n selectFile: (file: ComponentFile) => boolean,\n): Reference | undefined {\n const comp = r.components.find((comp) => comp.name === component);\n if (!comp) return;\n const file = comp.files.find(selectFile);\n if (!file) return;\n\n return {\n type: 'sub-component',\n resolved: {\n type: 'remote',\n registryName: r.name,\n component: comp,\n file,\n },\n };\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport picocolors from 'picocolors';\nimport type { CompiledRegistry } from '@/build/compiler';\n\nexport * from './compiler';\n\nexport interface MonoRegistry extends CompiledRegistry {\n registries: CompiledRegistry[];\n}\n\nexport function combineRegistry(\n root: CompiledRegistry,\n ...items: CompiledRegistry[]\n): MonoRegistry {\n return {\n ...root,\n info: {\n ...root.info,\n registries: items.map((item) => item.name),\n },\n registries: items,\n };\n}\n\nexport async function writeFumadocsRegistry(\n out: CompiledRegistry | MonoRegistry,\n options: {\n dir: string;\n\n /**\n * Remove previous outputs\n *\n * @defaultValue false\n */\n cleanDir?: boolean;\n\n log?: boolean;\n },\n): Promise<void> {\n const { dir, cleanDir = false, log = true } = options;\n\n if (cleanDir) {\n await fs.rm(dir, {\n recursive: true,\n force: true,\n });\n console.log(picocolors.bold(picocolors.greenBright('Cleaned directory')));\n }\n\n async function writeInfo() {\n const file = path.join(dir, '_registry.json');\n const json = JSON.stringify(out.info, null, 2);\n\n await writeFile(file, json, log);\n }\n\n const write = out.components.map(async (comp) => {\n const file = path.join(dir, `${comp.name}.json`);\n const json = JSON.stringify(comp, null, 2);\n\n await writeFile(file, json, log);\n });\n\n write.push(writeInfo());\n if ('registries' in out) {\n for (const child of out.registries) {\n write.push(\n writeFumadocsRegistry(child, {\n dir: path.join(dir, child.name),\n log: options.log,\n }),\n );\n }\n }\n\n await Promise.all(write);\n}\n\nasync function writeFile(file: string, content: string, log = true): Promise<void> {\n await fs.mkdir(path.dirname(file), { recursive: true });\n await fs.writeFile(file, content);\n\n if (log) {\n const size = (Buffer.byteLength(content) / 1024).toFixed(2);\n\n console.log(\n `${picocolors.greenBright('+')} ${path.relative(process.cwd(), file)} ${picocolors.dim(`${size} KB`)}`,\n );\n }\n}\n"],"mappings":"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"}
|
|
@@ -11,7 +11,7 @@ function createConfigSchema(isSrc) {
|
|
|
11
11
|
const defaultAliases = {
|
|
12
12
|
uiDir: "./components/ui",
|
|
13
13
|
componentsDir: "./components",
|
|
14
|
-
|
|
14
|
+
layoutDir: "./layouts",
|
|
15
15
|
cssDir: "./styles",
|
|
16
16
|
libDir: "./lib"
|
|
17
17
|
};
|
|
@@ -20,7 +20,7 @@ function createConfigSchema(isSrc) {
|
|
|
20
20
|
aliases: z.object({
|
|
21
21
|
uiDir: z.string().default(defaultAliases.uiDir),
|
|
22
22
|
componentsDir: z.string().default(defaultAliases.uiDir),
|
|
23
|
-
|
|
23
|
+
layoutDir: z.string().default(defaultAliases.layoutDir),
|
|
24
24
|
cssDir: z.string().default(defaultAliases.componentsDir),
|
|
25
25
|
libDir: z.string().default(defaultAliases.libDir)
|
|
26
26
|
}).default(defaultAliases),
|
|
@@ -52,4 +52,4 @@ async function getDefaultConfig(src) {
|
|
|
52
52
|
//#endregion
|
|
53
53
|
export { initConfig as i, createOrLoadConfig as n, getDefaultConfig as r, createConfigSchema as t };
|
|
54
54
|
|
|
55
|
-
//# sourceMappingURL=config-
|
|
55
|
+
//# sourceMappingURL=config-BYrMmXOw.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-
|
|
1
|
+
{"version":3,"file":"config-BYrMmXOw.js","names":[],"sources":["../src/utils/is-src.ts","../src/config.ts"],"sourcesContent":["import { exists } from '@/utils/fs';\n\nexport async function isSrc(): Promise<boolean> {\n return exists('./src');\n}\n","import fs from 'node:fs/promises';\nimport { isSrc } from '@/utils/is-src';\nimport { z } from 'zod';\n\nexport function createConfigSchema(isSrc: boolean) {\n const defaultAliases = {\n uiDir: './components/ui',\n componentsDir: './components',\n layoutDir: './layouts',\n cssDir: './styles',\n libDir: './lib',\n };\n\n return z.object({\n $schema: z\n .string()\n .default(\n isSrc\n ? 'node_modules/@fumadocs/cli/dist/schema/src.json'\n : 'node_modules/@fumadocs/cli/dist/schema/default.json',\n )\n .optional(),\n aliases: z\n .object({\n uiDir: z.string().default(defaultAliases.uiDir),\n componentsDir: z.string().default(defaultAliases.uiDir),\n layoutDir: z.string().default(defaultAliases.layoutDir),\n cssDir: z.string().default(defaultAliases.componentsDir),\n libDir: z.string().default(defaultAliases.libDir),\n })\n .default(defaultAliases),\n\n baseDir: z.string().default(isSrc ? 'src' : ''),\n uiLibrary: z.enum(['radix-ui', 'base-ui']).default('radix-ui'),\n\n commands: z\n .object({\n /**\n * command to format output code automatically\n */\n format: z.string().optional(),\n })\n .default({}),\n });\n}\n\ntype ConfigSchema = ReturnType<typeof createConfigSchema>;\n\nexport type ConfigInput = z.input<ConfigSchema>;\nexport type LoadedConfig = z.output<ConfigSchema>;\n\nexport async function createOrLoadConfig(file = './cli.json'): Promise<LoadedConfig> {\n const inited = await initConfig(file);\n if (inited) return inited;\n\n const content = (await fs.readFile(file)).toString();\n const src = await isSrc();\n const configSchema = createConfigSchema(src);\n\n return configSchema.parse(JSON.parse(content));\n}\n\n/**\n * Write new config, skip if a config already exists\n *\n * @returns the created config, `undefined` if not created\n */\nexport async function initConfig(\n file = './cli.json',\n src?: boolean,\n): Promise<LoadedConfig | undefined> {\n if (\n await fs\n .stat(file)\n .then(() => true)\n .catch(() => false)\n ) {\n return;\n }\n\n const defaultConfig = await getDefaultConfig(src);\n await fs.writeFile(file, JSON.stringify(defaultConfig, null, 2));\n return defaultConfig;\n}\n\nexport async function getDefaultConfig(src?: boolean) {\n return createConfigSchema(src ?? (await isSrc())).parse({} satisfies ConfigInput);\n}\n"],"mappings":";;;;AAEA,eAAsB,QAA0B;AAC9C,QAAO,OAAO,QAAQ;;;;ACCxB,SAAgB,mBAAmB,OAAgB;CACjD,MAAM,iBAAiB;EACrB,OAAO;EACP,eAAe;EACf,WAAW;EACX,QAAQ;EACR,QAAQ;EACT;AAED,QAAO,EAAE,OAAO;EACd,SAAS,EACN,QAAQ,CACR,QACC,QACI,oDACA,sDACL,CACA,UAAU;EACb,SAAS,EACN,OAAO;GACN,OAAO,EAAE,QAAQ,CAAC,QAAQ,eAAe,MAAM;GAC/C,eAAe,EAAE,QAAQ,CAAC,QAAQ,eAAe,MAAM;GACvD,WAAW,EAAE,QAAQ,CAAC,QAAQ,eAAe,UAAU;GACvD,QAAQ,EAAE,QAAQ,CAAC,QAAQ,eAAe,cAAc;GACxD,QAAQ,EAAE,QAAQ,CAAC,QAAQ,eAAe,OAAO;GAClD,CAAC,CACD,QAAQ,eAAe;EAE1B,SAAS,EAAE,QAAQ,CAAC,QAAQ,QAAQ,QAAQ,GAAG;EAC/C,WAAW,EAAE,KAAK,CAAC,YAAY,UAAU,CAAC,CAAC,QAAQ,WAAW;EAE9D,UAAU,EACP,OAAO,EAIN,QAAQ,EAAE,QAAQ,CAAC,UAAU,EAC9B,CAAC,CACD,QAAQ,EAAE,CAAC;EACf,CAAC;;AAQJ,eAAsB,mBAAmB,OAAO,cAAqC;CACnF,MAAM,SAAS,MAAM,WAAW,KAAK;AACrC,KAAI,OAAQ,QAAO;CAEnB,MAAM,WAAW,MAAM,GAAG,SAAS,KAAK,EAAE,UAAU;AAIpD,QAFqB,mBADT,MAAM,OAAO,CACmB,CAExB,MAAM,KAAK,MAAM,QAAQ,CAAC;;;;;;;AAQhD,eAAsB,WACpB,OAAO,cACP,KACmC;AACnC,KACE,MAAM,GACH,KAAK,KAAK,CACV,WAAW,KAAK,CAChB,YAAY,MAAM,CAErB;CAGF,MAAM,gBAAgB,MAAM,iBAAiB,IAAI;AACjD,OAAM,GAAG,UAAU,MAAM,KAAK,UAAU,eAAe,MAAM,EAAE,CAAC;AAChE,QAAO;;AAGT,eAAsB,iBAAiB,KAAe;AACpD,QAAO,mBAAmB,OAAQ,MAAM,OAAO,CAAE,CAAC,MAAM,EAAE,CAAuB"}
|
|
@@ -6,7 +6,7 @@ declare function createConfigSchema(isSrc: boolean): z.ZodObject<{
|
|
|
6
6
|
aliases: z.ZodDefault<z.ZodObject<{
|
|
7
7
|
uiDir: z.ZodDefault<z.ZodString>;
|
|
8
8
|
componentsDir: z.ZodDefault<z.ZodString>;
|
|
9
|
-
|
|
9
|
+
layoutDir: z.ZodDefault<z.ZodString>;
|
|
10
10
|
cssDir: z.ZodDefault<z.ZodString>;
|
|
11
11
|
libDir: z.ZodDefault<z.ZodString>;
|
|
12
12
|
}, z.core.$strip>>;
|
|
@@ -33,7 +33,7 @@ declare function getDefaultConfig(src?: boolean): Promise<{
|
|
|
33
33
|
aliases: {
|
|
34
34
|
uiDir: string;
|
|
35
35
|
componentsDir: string;
|
|
36
|
-
|
|
36
|
+
layoutDir: string;
|
|
37
37
|
cssDir: string;
|
|
38
38
|
libDir: string;
|
|
39
39
|
};
|
|
@@ -46,4 +46,4 @@ declare function getDefaultConfig(src?: boolean): Promise<{
|
|
|
46
46
|
}>;
|
|
47
47
|
//#endregion
|
|
48
48
|
export { getDefaultConfig as a, createOrLoadConfig as i, LoadedConfig as n, initConfig as o, createConfigSchema as r, ConfigInput as t };
|
|
49
|
-
//# sourceMappingURL=config-
|
|
49
|
+
//# sourceMappingURL=config-Dyass4D9.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-
|
|
1
|
+
{"version":3,"file":"config-Dyass4D9.d.ts","names":[],"sources":["../src/config.ts"],"mappings":";;;iBAIgB,kBAAA,CAAmB,KAAA,YAAc,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;KA0C5C,YAAA,GAAe,UAAA,QAAkB,kBAAA;AAAA,KAE1B,WAAA,GAAc,CAAA,CAAE,KAAA,CAAM,YAAA;AAAA,KACtB,YAAA,GAAe,CAAA,CAAE,MAAA,CAAO,YAAA;AAAA,iBAEd,kBAAA,CAAmB,IAAA,YAAsB,OAAA,CAAQ,YAAA;;;;;;iBAgBjD,UAAA,CACpB,IAAA,WACA,GAAA,aACC,OAAA,CAAQ,YAAA;AAAA,iBAeW,gBAAA,CAAiB,GAAA,aAAa,OAAA"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as getDefaultConfig, i as createOrLoadConfig, n as LoadedConfig, o as initConfig, r as createConfigSchema, t as ConfigInput } from "./config-
|
|
1
|
+
import { a as getDefaultConfig, i as createOrLoadConfig, n as LoadedConfig, o as initConfig, r as createConfigSchema, t as ConfigInput } from "./config-Dyass4D9.js";
|
|
2
2
|
export { ConfigInput, LoadedConfig, createConfigSchema, createOrLoadConfig, getDefaultConfig, initConfig };
|
package/dist/config.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as initConfig, n as createOrLoadConfig, r as getDefaultConfig, t as createConfigSchema } from "./config-
|
|
1
|
+
import { i as initConfig, n as createOrLoadConfig, r as getDefaultConfig, t as createConfigSchema } from "./config-BYrMmXOw.js";
|
|
2
2
|
export { createConfigSchema, createOrLoadConfig, getDefaultConfig, initConfig };
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { t as exists } from "./fs-CigSthjp.js";
|
|
3
|
-
import { i as initConfig, n as createOrLoadConfig } from "./config-
|
|
4
|
-
import "./ast-BRNdmLn5.js";
|
|
3
|
+
import { i as initConfig, n as createOrLoadConfig } from "./config-BYrMmXOw.js";
|
|
4
|
+
import { n as transformSpecifiers } from "./ast-BRNdmLn5.js";
|
|
5
5
|
import { n as LocalRegistryClient, t as HttpRegistryClient } from "./client-YTcWP1iz.js";
|
|
6
|
-
import { t as ComponentInstaller } from "./installer-
|
|
6
|
+
import { t as ComponentInstaller } from "./installer-B3-my9zN.js";
|
|
7
7
|
import fs from "node:fs/promises";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import { Command } from "commander";
|
|
@@ -63,7 +63,7 @@ async function runTree(args) {
|
|
|
63
63
|
}
|
|
64
64
|
//#endregion
|
|
65
65
|
//#region package.json
|
|
66
|
-
var version = "1.
|
|
66
|
+
var version = "1.3.1";
|
|
67
67
|
//#endregion
|
|
68
68
|
//#region src/commands/shared.ts
|
|
69
69
|
const UIRegistries = {
|
|
@@ -71,11 +71,58 @@ const UIRegistries = {
|
|
|
71
71
|
"radix-ui": "fumadocs/radix-ui"
|
|
72
72
|
};
|
|
73
73
|
//#endregion
|
|
74
|
+
//#region src/registry/plugins/preserve.ts
|
|
75
|
+
/**
|
|
76
|
+
* keep references to `fumadocs-ui/layouts/*` components as original, unless the user is installing them directly.
|
|
77
|
+
*/
|
|
78
|
+
function pluginPreserveLayouts() {
|
|
79
|
+
const layoutNames = [
|
|
80
|
+
"layouts/home",
|
|
81
|
+
"layouts/flux",
|
|
82
|
+
"layouts/notebook",
|
|
83
|
+
"layouts/docs",
|
|
84
|
+
"layouts/shared"
|
|
85
|
+
];
|
|
86
|
+
const layoutComps = {
|
|
87
|
+
"@/<dir>/home/index.tsx": "layouts/home",
|
|
88
|
+
"@/<dir>/shared/index.tsx": "layouts/shared",
|
|
89
|
+
"@/<dir>/shared/client.tsx": "layouts/shared",
|
|
90
|
+
"@/<dir>/notebook/index.tsx": "layouts/notebook",
|
|
91
|
+
"@/<dir>/notebook/client.tsx": "layouts/notebook",
|
|
92
|
+
"@/<dir>/notebook/page/index.tsx": "layouts/notebook/page",
|
|
93
|
+
"@/<dir>/notebook/page/client.tsx": "layouts/notebook/page",
|
|
94
|
+
"@/<dir>/docs/index.tsx": "layouts/docs",
|
|
95
|
+
"@/<dir>/docs/client.tsx": "layouts/docs",
|
|
96
|
+
"@/<dir>/docs/page/index.tsx": "layouts/docs/page",
|
|
97
|
+
"@/<dir>/docs/page/client.tsx": "layouts/docs/page",
|
|
98
|
+
"@/<dir>/flux/index.tsx": "layouts/flux",
|
|
99
|
+
"@/<dir>/flux/page/index.tsx": "layouts/flux/page",
|
|
100
|
+
"@/<dir>/flux/page/client.tsx": "layouts/flux/page"
|
|
101
|
+
};
|
|
102
|
+
const layoutNameSet = new Set(layoutNames);
|
|
103
|
+
return {
|
|
104
|
+
beforeInstall(comp, { stack }) {
|
|
105
|
+
if (layoutNameSet.has(stack[0].name)) return;
|
|
106
|
+
return {
|
|
107
|
+
...comp,
|
|
108
|
+
$subComponents: comp.$subComponents.filter((child) => !layoutNameSet.has(child.name))
|
|
109
|
+
};
|
|
110
|
+
},
|
|
111
|
+
beforeTransform({ parsed, s, stack }) {
|
|
112
|
+
if (layoutNameSet.has(stack[0].name)) return;
|
|
113
|
+
transformSpecifiers(parsed.program, s, (specifier) => {
|
|
114
|
+
if (!(specifier in layoutComps)) return specifier;
|
|
115
|
+
return `fumadocs-ui/${layoutComps[specifier]}`;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
//#endregion
|
|
74
121
|
//#region src/commands/add.ts
|
|
75
122
|
async function add(input, client) {
|
|
76
123
|
const config = client.config;
|
|
77
124
|
let target;
|
|
78
|
-
const installer = new ComponentInstaller(client);
|
|
125
|
+
const installer = new ComponentInstaller(client, { plugins: [pluginPreserveLayouts()] });
|
|
79
126
|
const registry = UIRegistries[config.uiLibrary];
|
|
80
127
|
if (input.length === 0) {
|
|
81
128
|
const spin = spinner();
|
|
@@ -162,7 +209,7 @@ async function install(target, installer) {
|
|
|
162
209
|
async function customise(client) {
|
|
163
210
|
intro(picocolors.bgBlack(picocolors.whiteBright("Customise Fumadocs UI")));
|
|
164
211
|
const config = client.config;
|
|
165
|
-
const installer = new ComponentInstaller(client);
|
|
212
|
+
const installer = new ComponentInstaller(client, { plugins: [pluginPreserveLayouts()] });
|
|
166
213
|
const registry = UIRegistries[config.uiLibrary];
|
|
167
214
|
const target = (await group({
|
|
168
215
|
layout: () => select({
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["packageJson.version"],"sources":["../src/commands/file-tree.ts","../src/utils/file-tree/run-tree.ts","../package.json","../src/commands/shared.ts","../src/commands/add.ts","../src/commands/customise.ts","../src/commands/export-epub.ts","../src/index.ts"],"sourcesContent":["export type JsonTreeNode =\n | {\n type: 'file';\n name: string;\n }\n | {\n type: 'directory';\n name: string;\n contents: JsonTreeNode[];\n }\n | {\n type: 'report';\n }\n | {\n type: 'link';\n name: string;\n };\n\nconst scanned = ['file', 'directory', 'link'];\n\nexport function treeToMdx(input: JsonTreeNode[], noRoot = false): string {\n function toNode(item: JsonTreeNode): string {\n if (item.type === 'file' || item.type === 'link') {\n return `<File name=${JSON.stringify(item.name)} />`;\n }\n\n if (item.type === 'directory') {\n if (item.contents.length === 1 && 'name' in item.contents[0]) {\n const child = item.contents[0];\n\n return toNode({\n ...child,\n name: `${item.name}/${child.name}`,\n });\n }\n\n return `<Folder name=${JSON.stringify(item.name)}>\n${item.contents.map(toNode).filter(Boolean).join('\\n')}\n</Folder>`;\n }\n\n return '';\n }\n\n let children = input.filter((v) => scanned.includes(v.type));\n\n if (noRoot && children.length === 1 && input[0].type === 'directory') {\n children = input[0].contents;\n }\n\n return `<Files>\n${children.map(toNode).filter(Boolean).join('\\n')}\n</Files>`;\n}\n\nexport function treeToJavaScript(\n input: JsonTreeNode[],\n noRoot?: boolean,\n importName = 'fumadocs-ui/components/files',\n): string {\n return `import { File, Files, Folder } from ${JSON.stringify(importName)}\n\nexport default (${treeToMdx(input, noRoot)})`;\n}\n","import { x } from 'tinyexec';\nimport type { JsonTreeNode } from '@/commands/file-tree';\n\nexport async function runTree(args: string): Promise<JsonTreeNode[]> {\n const out = await x('tree', [args, '--gitignore', '--prune', '-J']);\n\n try {\n return JSON.parse(out.stdout) as JsonTreeNode[];\n } catch (e) {\n throw new Error('failed to run `tree` command', {\n cause: e,\n });\n }\n}\n","","export const UIRegistries = {\n 'base-ui': 'fumadocs/base-ui',\n 'radix-ui': 'fumadocs/radix-ui',\n};\n","import {\n isCancel,\n autocompleteMultiselect,\n outro,\n spinner,\n confirm,\n box,\n log,\n} from '@clack/prompts';\nimport picocolors from 'picocolors';\nimport { ComponentInstaller } from '@/registry/installer';\nimport type { RegistryClient } from '@/registry/client';\nimport { UIRegistries } from '@/commands/shared';\n\nexport async function add(input: string[], client: RegistryClient) {\n const config = client.config;\n let target: string[];\n const installer = new ComponentInstaller(client);\n const registry = UIRegistries[config.uiLibrary];\n\n if (input.length === 0) {\n const spin = spinner();\n spin.start('fetching registry');\n const info = await client.fetchRegistryInfo();\n const options: {\n label: string;\n value: string;\n hint?: string;\n }[] = [];\n\n for (const item of info.indexes) {\n options.push({\n label: item.title ?? item.name,\n value: item.name,\n hint: item.description,\n });\n }\n const { indexes } = await client.createLinkedRegistryClient(registry).fetchRegistryInfo();\n\n for (const item of indexes) {\n options.push({\n label: item.title ?? item.name,\n value: `${registry}/${item.name}`,\n hint: item.description,\n });\n }\n\n spin.stop(picocolors.bold(picocolors.greenBright('registry fetched')));\n const value = await autocompleteMultiselect({\n message: 'Select components to install',\n options,\n });\n\n if (isCancel(value)) {\n outro('Ended');\n return;\n }\n\n target = value;\n } else {\n target = await Promise.all(\n input.map(async (item) => ((await client.hasComponent(item)) ? item : `${registry}/${item}`)),\n );\n }\n\n await install(target, installer);\n}\n\nexport async function install(target: string[], installer: ComponentInstaller) {\n for (const name of target) {\n const spin = spinner();\n spin.start(picocolors.bold(picocolors.cyanBright(`Installing ${name}`)));\n\n try {\n await installer.install(name, {\n onWarn(message) {\n spin.message(message);\n },\n async confirmFileOverride(options) {\n spin.clear();\n const value = await confirm({\n message: `Do you want to override ${options.path}?`,\n initialValue: false,\n });\n if (isCancel(value)) {\n outro('Installation terminated');\n process.exit(0);\n }\n spin.start(picocolors.bold(picocolors.cyanBright(`Installing ${name}`)));\n return value;\n },\n onFileDownloaded(options) {\n spin.message(options.path);\n },\n });\n spin.stop(picocolors.bold(picocolors.greenBright(`${name} installed`)));\n } catch (e) {\n spin.error(e instanceof Error ? e.message : String(e));\n process.exit(-1);\n }\n }\n\n const deps = await installer.deps();\n if (deps.hasRequired()) {\n log.message();\n box([...deps.dependencies, ...deps.devDependencies].join('\\n'), 'New Dependencies');\n const value = await confirm({\n message: `Do you want to install with ${deps.packageManager}?`,\n });\n\n if (isCancel(value)) {\n outro('Installation terminated');\n process.exit(0);\n }\n\n if (value) {\n const spin = spinner({\n errorMessage: 'Failed to install dependencies',\n });\n spin.start('Installing dependencies');\n await deps.installRequired();\n spin.stop('Dependencies installed');\n }\n }\n\n await installer.onEnd();\n outro(picocolors.bold(picocolors.greenBright('Successful')));\n}\n","import { cancel, group, intro, log, outro, select } from '@clack/prompts';\nimport picocolors from 'picocolors';\nimport { install } from '@/commands/add';\nimport type { RegistryClient } from '@/registry/client';\nimport { ComponentInstaller } from '@/registry/installer';\nimport { UIRegistries } from '@/commands/shared';\n\ninterface TargetInfo {\n target: string[];\n replace: [string, string][];\n}\n\nexport async function customise(client: RegistryClient) {\n intro(picocolors.bgBlack(picocolors.whiteBright('Customise Fumadocs UI')));\n const config = client.config;\n const installer = new ComponentInstaller(client);\n const registry = UIRegistries[config.uiLibrary];\n\n const result = await group(\n {\n layout: () =>\n select({\n message: 'What do you want to customise?',\n options: [\n {\n label: 'Docs Layout',\n value: 'docs',\n hint: 'main UI of your docs',\n },\n {\n label: 'Home Layout',\n value: 'home',\n hint: 'the navbar for your other pages',\n },\n ],\n }),\n target: (v): Promise<TargetInfo | symbol> => {\n if (v.results.layout !== 'docs')\n return Promise.resolve({\n target: [`${registry}/layouts/home`],\n replace: [['fumadocs-ui/layouts/home', `@/components/layout/home`]],\n });\n\n return select<TargetInfo>({\n message: 'Which variant do you want to start from?',\n options: [\n {\n label: 'Start from minimal styles',\n hint: 'for those who want to build their own variant from ground up.',\n value: {\n target: ['layouts/docs-min'],\n replace: [\n ['fumadocs-ui/layouts/docs', '@/components/layout/docs'],\n ['fumadocs-ui/layouts/docs/page', '@/components/layout/docs/page'],\n ],\n },\n },\n {\n label: 'Start from default layout',\n value: {\n target: [`${registry}/layouts/docs`],\n replace: [\n ['fumadocs-ui/layouts/docs', '@/components/layout/docs'],\n ['fumadocs-ui/layouts/docs/page', '@/components/layout/docs/page'],\n ],\n },\n hint: 'useful for adjusting small details.',\n },\n {\n label: 'Start from Notebook layout',\n value: {\n target: [`${registry}/layouts/notebook`],\n replace: [\n ['fumadocs-ui/layouts/notebook', '@/components/layout/notebook'],\n ['fumadocs-ui/layouts/notebook/page', '@/components/layout/notebook/page'],\n ],\n },\n hint: 'useful for adjusting small details.',\n },\n {\n label: 'Start from Flux layout',\n value: {\n target: [`${registry}/layouts/flux`],\n replace: [\n ['fumadocs-ui/layouts/flux', '@/components/layout/flux'],\n ['fumadocs-ui/layouts/flux/page', '@/components/layout/flux/page'],\n ],\n },\n hint: 'useful for adjusting small details.',\n },\n ],\n });\n },\n },\n {\n onCancel: () => {\n cancel('Installation Stopped.');\n process.exit(0);\n },\n },\n );\n\n const target = result.target as TargetInfo;\n await install(target.target, installer);\n printNext(...target.replace);\n\n outro(picocolors.bold('Have fun!'));\n}\n\nfunction printNext(...maps: [from: string, to: string][]) {\n intro(picocolors.bold('What is Next?'));\n\n log.info(\n [\n 'You can check the installed components in `components`.',\n picocolors.dim('---'),\n 'Open your `layout.tsx` files, replace the imports of components:',\n ...maps.map(([from, to]) => picocolors.greenBright(`\"${from}\" -> \"${to}\"`)),\n ].join('\\n'),\n );\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { exists } from '@/utils/fs';\nimport picocolors from 'picocolors';\nimport { spinner } from '@clack/prompts';\nimport { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\n\ninterface PackageJson {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n}\n\nasync function readPackageJson(cwd: string): Promise<PackageJson | null> {\n try {\n const raw = await fs.readFile(path.join(cwd, 'package.json'), 'utf-8');\n return JSON.parse(raw) as PackageJson;\n } catch {\n return null;\n }\n}\n\n/** Path of pre-rendered EPUB, choose one according to your React framework. Next.js fetches from the running server instead. */\nconst EPUB_BUILD_PATHS: Record<string, string> = {\n next: '', // Fetched from /export/epub at runtime; route handlers don't produce static files\n 'tanstack-start': '.output/public/export/epub',\n 'tanstack-start-spa': 'dist/client/export/epub',\n 'react-router': 'build/client/export/epub',\n 'react-router-spa': 'build/client/export/epub',\n waku: 'dist/public/export/epub',\n};\n\nconst API_ROUTE_TEMPLATE = `import { source } from '@/lib/source';\nimport { exportEpub } from 'fumadocs-epub';\n\nexport const revalidate = false;\n\nexport async function GET(request: Request): Promise<Response> {\n // Require EXPORT_SECRET to prevent unauthenticated abuse. Pass via Authorization: Bearer <secret>\n const secret = process.env.EXPORT_SECRET;\n if (!secret) {\n return new Response('EXPORT_SECRET is not configured. Set it in your environment to protect this endpoint.', { status: 503 });\n }\n const authHeader = request.headers.get('authorization');\n const token = authHeader?.replace(/^Bearer\\\\s+/i, '') ?? '';\n if (token !== secret) {\n return new Response('Unauthorized', { status: authHeader ? 403 : 401 });\n }\n const buffer = await exportEpub({\n source,\n title: 'Documentation',\n author: 'Your Team',\n description: 'Exported documentation',\n cover: '/cover.png',\n });\n return new Response(new Uint8Array(buffer), {\n headers: {\n 'Content-Type': 'application/epub+zip',\n 'Content-Disposition': 'attachment; filename=\"docs.epub\"',\n },\n });\n}\n`;\n\nasync function findAppDir(cwd: string): Promise<string | null> {\n const appPaths = ['app', 'src/app'];\n for (const appPath of appPaths) {\n const fullPath = path.join(cwd, appPath);\n if (await exists(fullPath)) {\n return fullPath;\n }\n }\n return null;\n}\n\nasync function scaffoldEpubRoute(cwd: string): Promise<boolean> {\n const appDir = await findAppDir(cwd);\n if (!appDir) {\n console.error(picocolors.red('Could not find app directory (app/ or src/app/)'));\n return false;\n }\n\n const routePath = path.join(appDir, 'export', 'epub', 'route.ts');\n if (await exists(routePath)) {\n console.log(picocolors.yellow('EPUB route already exists at'), routePath);\n return true;\n }\n\n await fs.mkdir(path.dirname(routePath), { recursive: true });\n await fs.writeFile(routePath, API_ROUTE_TEMPLATE);\n console.log(picocolors.green('Created EPUB route at'), routePath);\n return true;\n}\n\nexport async function exportEpub(options: {\n output?: string;\n framework: string;\n scaffoldOnly?: boolean;\n}) {\n const cwd = process.cwd();\n const outputPath = path.resolve(cwd, options.output ?? 'docs.epub');\n const framework = options.framework;\n\n const spin = spinner();\n\n const buildPath = EPUB_BUILD_PATHS[framework];\n if (!(framework in EPUB_BUILD_PATHS)) {\n const valid = Object.keys(EPUB_BUILD_PATHS).join(', ');\n console.error(picocolors.red(`Invalid --framework \"${framework}\". Must be one of: ${valid}`));\n process.exit(1);\n }\n\n // Check for Next.js when scaffolding (only Next.js scaffold is implemented)\n const pkg = await readPackageJson(cwd);\n const hasNextConfig =\n (await exists(path.join(cwd, 'next.config.js'))) ||\n (await exists(path.join(cwd, 'next.config.ts'))) ||\n (await exists(path.join(cwd, 'next.config.mjs')));\n const nextDeps = pkg\n ? { ...pkg.dependencies, ...pkg.devDependencies, ...pkg.peerDependencies }\n : {};\n const hasNextInPkg = !!nextDeps?.next;\n const hasAppOrPages =\n (await exists(path.join(cwd, 'app'))) ||\n (await exists(path.join(cwd, 'pages'))) ||\n (await exists(path.join(cwd, 'src', 'app'))) ||\n (await exists(path.join(cwd, 'src', 'pages')));\n const hasNext = hasNextConfig || (hasNextInPkg && hasAppOrPages);\n\n if (!hasNext && framework === 'next') {\n console.error(\n picocolors.red(\n 'Next.js project not found. Run this command from a Fumadocs Next.js project root.',\n ),\n );\n process.exit(1);\n }\n\n // Scaffold EPUB route (Next.js only for now)\n if (framework === 'next') {\n spin.start('Scaffolding EPUB route');\n const scaffolded = await scaffoldEpubRoute(cwd);\n spin.stop(scaffolded ? 'EPUB route ready' : 'Scaffolding failed');\n\n if (!scaffolded) {\n process.exit(1);\n }\n }\n\n if (options.scaffoldOnly) {\n console.log(picocolors.cyan('\\nTo export:'));\n console.log(' 1. Add fumadocs-epub to your dependencies: pnpm add fumadocs-epub');\n console.log(' 2. Ensure includeProcessedMarkdown: true in your docs collection config');\n if (framework === 'next') {\n console.log(\n ' 3. Set EXPORT_SECRET in your environment to protect the /export/epub endpoint',\n );\n console.log(' 4. Run production build: pnpm build');\n console.log(' 5. Start the server (e.g. pnpm start) and keep it running');\n console.log(' 6. Run: fumadocs export epub --framework next');\n } else {\n console.log(` 3. Add a prerender route that outputs EPUB to ${buildPath}`);\n console.log(' 4. Run production build: pnpm build');\n console.log(` 5. Run: fumadocs export epub --framework ${framework}`);\n }\n return;\n }\n\n // Check for fumadocs-epub dependency\n if (!pkg) {\n console.error(\n picocolors.red('Cannot read or parse package.json. Ensure it exists and is valid JSON.'),\n );\n process.exit(1);\n }\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n if (!deps['fumadocs-epub']) {\n console.log(picocolors.yellow('\\nInstalling fumadocs-epub...'));\n const packageManager = process.env.npm_execpath?.includes('pnpm')\n ? 'pnpm'\n : process.env.npm_execpath?.includes('bun')\n ? 'bun'\n : 'npm';\n const installCmd = `${packageManager} add fumadocs-epub`;\n try {\n await execAsync(installCmd, { cwd });\n } catch (err: unknown) {\n const stderr =\n err && typeof err === 'object' && 'stderr' in err\n ? String((err as { stderr?: string }).stderr)\n : '';\n console.error(picocolors.red(`Failed to install fumadocs-epub. Command: ${installCmd}`));\n if (stderr) console.error(stderr);\n process.exit(1);\n }\n }\n\n if (framework === 'next') {\n const secret = process.env.EXPORT_SECRET;\n if (!secret) {\n console.error(\n picocolors.red('EXPORT_SECRET is required for Next.js export. Set it in your environment.'),\n );\n process.exit(1);\n }\n const port = process.env.PORT || '3000';\n const url = `http://localhost:${port}/export/epub`;\n spin.start('Fetching EPUB from server');\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 30_000);\n try {\n const res = await fetch(url, {\n headers: { Authorization: `Bearer ${secret}` },\n signal: controller.signal,\n });\n if (!res.ok) {\n if (res.status === 401 || res.status === 403) {\n console.error(\n picocolors.red('Auth failed. Check that EXPORT_SECRET matches the value in your app.'),\n );\n } else {\n console.error(\n picocolors.red(\n `Server returned ${res.status}. Ensure the app is running (e.g. pnpm start) on port ${port}.`,\n ),\n );\n }\n process.exit(1);\n }\n const buffer = Buffer.from(await res.arrayBuffer());\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n await fs.writeFile(outputPath, buffer);\n spin.stop(picocolors.green(`EPUB saved to ${outputPath}`));\n } catch (err: unknown) {\n if (err instanceof Error && err.name === 'AbortError') {\n console.error(picocolors.red('Request timed out after 30 seconds.'));\n } else {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(picocolors.red(`Could not fetch EPUB: ${msg}`));\n }\n console.error(\n picocolors.yellow(`Ensure the server is running (e.g. pnpm start) on port ${port}.`),\n );\n process.exit(1);\n } finally {\n clearTimeout(timeoutId);\n }\n return;\n }\n\n const fullBuildPath = path.join(cwd, buildPath);\n if (!(await exists(fullBuildPath))) {\n console.error(\n picocolors.red(\n `EPUB not found at ${buildPath}. Run production build first (e.g. pnpm build).`,\n ),\n );\n process.exit(1);\n }\n\n spin.start('Copying EPUB');\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n await fs.copyFile(fullBuildPath, outputPath);\n spin.stop(picocolors.green(`EPUB saved to ${outputPath}`));\n}\n","#!/usr/bin/env node\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { Command } from 'commander';\nimport picocolors from 'picocolors';\nimport { createOrLoadConfig, initConfig, type LoadedConfig } from '@/config';\nimport { type JsonTreeNode, treeToJavaScript, treeToMdx } from '@/commands/file-tree';\nimport { runTree } from '@/utils/file-tree/run-tree';\nimport packageJson from '../package.json';\nimport { customise } from '@/commands/customise';\nimport { add } from '@/commands/add';\nimport { exportEpub } from '@/commands/export-epub';\nimport { HttpRegistryClient, LocalRegistryClient } from '@/registry/client';\n\nconst program = new Command().option('--config <string>');\n\nprogram\n .name('fumadocs')\n .description('CLI to setup Fumadocs, init a config')\n .version(packageJson.version)\n .action(async () => {\n if (await initConfig()) {\n console.log(picocolors.green('Initialized a `./cli.json` config file.'));\n } else {\n console.log(picocolors.redBright('A config file already exists.'));\n }\n });\n\nprogram\n .command('customise')\n .alias('customize')\n .description('simple way to customise layouts with Fumadocs UI')\n .option('--dir <string>', 'the root url or directory to resolve registry')\n .action(async (options: { config?: string; dir?: string }) => {\n await customise(createClientFromDir(options.dir, await createOrLoadConfig(options.config)));\n });\n\nconst dirShortcuts: Record<string, string> = {\n ':preview': 'https://preview.fumadocs.dev/registry',\n ':dev': 'http://localhost:3000/registry',\n};\n\nprogram\n .command('add')\n .description('add a new component to your docs')\n .argument('[components...]', 'components to download')\n .option('--dir <string>', 'the root url or directory to resolve registry')\n .action(async (input: string[], options: { config?: string; dir?: string }) => {\n const client = createClientFromDir(options.dir, await createOrLoadConfig(options.config));\n await add(input, client);\n });\n\nconst exportCmd = program.command('export').description('export documentation to various formats');\n\nexportCmd\n .command('epub')\n .description('export documentation to EPUB format (run after production build)')\n .requiredOption('--framework <name>', 'React framework: next, tanstack-start, react-router, waku')\n .option('--output <path>', 'output file path', 'docs.epub')\n .option('--scaffold-only', 'only scaffold the EPUB route, do not copy')\n .action(async (options: { output?: string; framework: string; scaffoldOnly?: boolean }) => {\n await exportEpub({\n output: options.output,\n framework: options.framework,\n scaffoldOnly: options.scaffoldOnly,\n });\n });\n\nprogram\n .command('tree')\n .argument('[json_or_args]', 'JSON output of `tree` command or arguments for the `tree` command')\n .argument('[output]', 'output path of file')\n .option('--js', 'output as JavaScript file')\n .option('--no-root', 'remove the root node')\n .option('--import-name <name>', 'where to import components (JS only)')\n .action(\n async (\n str: string | undefined,\n output: string | undefined,\n { js, root, importName }: { js: boolean; root: boolean; importName?: string },\n ) => {\n const jsExtensions = ['.js', '.tsx', '.jsx'];\n const noRoot = !root;\n let nodes: JsonTreeNode[];\n\n try {\n nodes = JSON.parse(str ?? '') as JsonTreeNode[];\n } catch {\n nodes = await runTree(str ?? './');\n }\n\n const out =\n js || (output && jsExtensions.includes(path.extname(output)))\n ? treeToJavaScript(nodes, noRoot, importName)\n : treeToMdx(nodes, noRoot);\n\n if (output) {\n await fs.mkdir(path.dirname(output), { recursive: true });\n await fs.writeFile(output, out);\n } else {\n console.log(out);\n }\n },\n );\n\nfunction createClientFromDir(dir = 'https://fumadocs.dev/registry', config: LoadedConfig) {\n if (dir in dirShortcuts) dir = dirShortcuts[dir];\n\n return dir.startsWith('http://') || dir.startsWith('https://')\n ? new HttpRegistryClient(dir, config)\n : new LocalRegistryClient(dir, config);\n}\n\nprogram.parse();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["packageJson.version"],"sources":["../src/commands/file-tree.ts","../src/utils/file-tree/run-tree.ts","../package.json","../src/commands/shared.ts","../src/registry/plugins/preserve.ts","../src/commands/add.ts","../src/commands/customise.ts","../src/commands/export-epub.ts","../src/index.ts"],"sourcesContent":["export type JsonTreeNode =\n | {\n type: 'file';\n name: string;\n }\n | {\n type: 'directory';\n name: string;\n contents: JsonTreeNode[];\n }\n | {\n type: 'report';\n }\n | {\n type: 'link';\n name: string;\n };\n\nconst scanned = ['file', 'directory', 'link'];\n\nexport function treeToMdx(input: JsonTreeNode[], noRoot = false): string {\n function toNode(item: JsonTreeNode): string {\n if (item.type === 'file' || item.type === 'link') {\n return `<File name=${JSON.stringify(item.name)} />`;\n }\n\n if (item.type === 'directory') {\n if (item.contents.length === 1 && 'name' in item.contents[0]) {\n const child = item.contents[0];\n\n return toNode({\n ...child,\n name: `${item.name}/${child.name}`,\n });\n }\n\n return `<Folder name=${JSON.stringify(item.name)}>\n${item.contents.map(toNode).filter(Boolean).join('\\n')}\n</Folder>`;\n }\n\n return '';\n }\n\n let children = input.filter((v) => scanned.includes(v.type));\n\n if (noRoot && children.length === 1 && input[0].type === 'directory') {\n children = input[0].contents;\n }\n\n return `<Files>\n${children.map(toNode).filter(Boolean).join('\\n')}\n</Files>`;\n}\n\nexport function treeToJavaScript(\n input: JsonTreeNode[],\n noRoot?: boolean,\n importName = 'fumadocs-ui/components/files',\n): string {\n return `import { File, Files, Folder } from ${JSON.stringify(importName)}\n\nexport default (${treeToMdx(input, noRoot)})`;\n}\n","import { x } from 'tinyexec';\nimport type { JsonTreeNode } from '@/commands/file-tree';\n\nexport async function runTree(args: string): Promise<JsonTreeNode[]> {\n const out = await x('tree', [args, '--gitignore', '--prune', '-J']);\n\n try {\n return JSON.parse(out.stdout) as JsonTreeNode[];\n } catch (e) {\n throw new Error('failed to run `tree` command', {\n cause: e,\n });\n }\n}\n","","export const UIRegistries = {\n 'base-ui': 'fumadocs/base-ui',\n 'radix-ui': 'fumadocs/radix-ui',\n};\n","import { transformSpecifiers } from '@/utils/ast';\nimport type { ComponentInstallerPlugin } from '../installer';\n\n/**\n * keep references to `fumadocs-ui/layouts/*` components as original, unless the user is installing them directly.\n */\nexport function pluginPreserveLayouts(): ComponentInstallerPlugin {\n const layoutNames = [\n 'layouts/home',\n 'layouts/flux',\n 'layouts/notebook',\n 'layouts/docs',\n 'layouts/shared',\n ];\n // original specifier -> new specifier\n const layoutComps: Record<string, string> = {\n '@/<dir>/home/index.tsx': 'layouts/home',\n '@/<dir>/shared/index.tsx': 'layouts/shared',\n '@/<dir>/shared/client.tsx': 'layouts/shared',\n '@/<dir>/notebook/index.tsx': 'layouts/notebook',\n '@/<dir>/notebook/client.tsx': 'layouts/notebook',\n '@/<dir>/notebook/page/index.tsx': 'layouts/notebook/page',\n '@/<dir>/notebook/page/client.tsx': 'layouts/notebook/page',\n '@/<dir>/docs/index.tsx': 'layouts/docs',\n '@/<dir>/docs/client.tsx': 'layouts/docs',\n '@/<dir>/docs/page/index.tsx': 'layouts/docs/page',\n '@/<dir>/docs/page/client.tsx': 'layouts/docs/page',\n '@/<dir>/flux/index.tsx': 'layouts/flux',\n '@/<dir>/flux/page/index.tsx': 'layouts/flux/page',\n '@/<dir>/flux/page/client.tsx': 'layouts/flux/page',\n };\n const layoutNameSet = new Set(layoutNames);\n\n return {\n beforeInstall(comp, { stack }) {\n const isDirectInstall = layoutNameSet.has(stack[0].name);\n if (isDirectInstall) return;\n\n return {\n ...comp,\n $subComponents: comp.$subComponents.filter((child) => !layoutNameSet.has(child.name)),\n };\n },\n beforeTransform({ parsed, s, stack }) {\n const isDirectInstall = layoutNameSet.has(stack[0].name);\n if (isDirectInstall) return;\n\n transformSpecifiers(parsed.program, s, (specifier) => {\n // skip if unrelated to layout component\n if (!(specifier in layoutComps)) return specifier;\n\n return `fumadocs-ui/${layoutComps[specifier]}`;\n });\n },\n };\n}\n","import {\n isCancel,\n autocompleteMultiselect,\n outro,\n spinner,\n confirm,\n box,\n log,\n} from '@clack/prompts';\nimport picocolors from 'picocolors';\nimport { ComponentInstaller } from '@/registry/installer';\nimport type { RegistryClient } from '@/registry/client';\nimport { UIRegistries } from '@/commands/shared';\nimport { pluginPreserveLayouts } from '@/registry/plugins/preserve';\n\nexport async function add(input: string[], client: RegistryClient) {\n const config = client.config;\n let target: string[];\n const installer = new ComponentInstaller(client, {\n plugins: [pluginPreserveLayouts()],\n });\n const registry = UIRegistries[config.uiLibrary];\n\n if (input.length === 0) {\n const spin = spinner();\n spin.start('fetching registry');\n const info = await client.fetchRegistryInfo();\n const options: {\n label: string;\n value: string;\n hint?: string;\n }[] = [];\n\n for (const item of info.indexes) {\n options.push({\n label: item.title ?? item.name,\n value: item.name,\n hint: item.description,\n });\n }\n const { indexes } = await client.createLinkedRegistryClient(registry).fetchRegistryInfo();\n\n for (const item of indexes) {\n options.push({\n label: item.title ?? item.name,\n value: `${registry}/${item.name}`,\n hint: item.description,\n });\n }\n\n spin.stop(picocolors.bold(picocolors.greenBright('registry fetched')));\n const value = await autocompleteMultiselect({\n message: 'Select components to install',\n options,\n });\n\n if (isCancel(value)) {\n outro('Ended');\n return;\n }\n\n target = value;\n } else {\n target = await Promise.all(\n input.map(async (item) => ((await client.hasComponent(item)) ? item : `${registry}/${item}`)),\n );\n }\n\n await install(target, installer);\n}\n\nexport async function install(target: string[], installer: ComponentInstaller) {\n for (const name of target) {\n const spin = spinner();\n spin.start(picocolors.bold(picocolors.cyanBright(`Installing ${name}`)));\n\n try {\n await installer.install(name, {\n onWarn(message) {\n spin.message(message);\n },\n async confirmFileOverride(options) {\n spin.clear();\n const value = await confirm({\n message: `Do you want to override ${options.path}?`,\n initialValue: false,\n });\n if (isCancel(value)) {\n outro('Installation terminated');\n process.exit(0);\n }\n spin.start(picocolors.bold(picocolors.cyanBright(`Installing ${name}`)));\n return value;\n },\n onFileDownloaded(options) {\n spin.message(options.path);\n },\n });\n spin.stop(picocolors.bold(picocolors.greenBright(`${name} installed`)));\n } catch (e) {\n spin.error(e instanceof Error ? e.message : String(e));\n process.exit(-1);\n }\n }\n\n const deps = await installer.deps();\n if (deps.hasRequired()) {\n log.message();\n box([...deps.dependencies, ...deps.devDependencies].join('\\n'), 'New Dependencies');\n const value = await confirm({\n message: `Do you want to install with ${deps.packageManager}?`,\n });\n\n if (isCancel(value)) {\n outro('Installation terminated');\n process.exit(0);\n }\n\n if (value) {\n const spin = spinner({\n errorMessage: 'Failed to install dependencies',\n });\n spin.start('Installing dependencies');\n await deps.installRequired();\n spin.stop('Dependencies installed');\n }\n }\n\n await installer.onEnd();\n outro(picocolors.bold(picocolors.greenBright('Successful')));\n}\n","import { cancel, group, intro, log, outro, select } from '@clack/prompts';\nimport picocolors from 'picocolors';\nimport { install } from '@/commands/add';\nimport type { RegistryClient } from '@/registry/client';\nimport { ComponentInstaller } from '@/registry/installer';\nimport { UIRegistries } from '@/commands/shared';\nimport { pluginPreserveLayouts } from '@/registry/plugins/preserve';\n\ninterface TargetInfo {\n target: string[];\n replace: [string, string][];\n}\n\nexport async function customise(client: RegistryClient) {\n intro(picocolors.bgBlack(picocolors.whiteBright('Customise Fumadocs UI')));\n const config = client.config;\n const installer = new ComponentInstaller(client, {\n plugins: [pluginPreserveLayouts()],\n });\n const registry = UIRegistries[config.uiLibrary];\n\n const result = await group(\n {\n layout: () =>\n select({\n message: 'What do you want to customise?',\n options: [\n {\n label: 'Docs Layout',\n value: 'docs',\n hint: 'main UI of your docs',\n },\n {\n label: 'Home Layout',\n value: 'home',\n hint: 'the navbar for your other pages',\n },\n ],\n }),\n target: (v): Promise<TargetInfo | symbol> => {\n if (v.results.layout !== 'docs')\n return Promise.resolve({\n target: [`${registry}/layouts/home`],\n replace: [['fumadocs-ui/layouts/home', `@/components/layout/home`]],\n });\n\n return select<TargetInfo>({\n message: 'Which variant do you want to start from?',\n options: [\n {\n label: 'Start from minimal styles',\n hint: 'for those who want to build their own variant from ground up.',\n value: {\n target: ['layouts/docs-min'],\n replace: [\n ['fumadocs-ui/layouts/docs', '@/components/layout/docs'],\n ['fumadocs-ui/layouts/docs/page', '@/components/layout/docs/page'],\n ],\n },\n },\n {\n label: 'Start from default layout',\n value: {\n target: [`${registry}/layouts/docs`],\n replace: [\n ['fumadocs-ui/layouts/docs', '@/components/layout/docs'],\n ['fumadocs-ui/layouts/docs/page', '@/components/layout/docs/page'],\n ],\n },\n hint: 'useful for adjusting small details.',\n },\n {\n label: 'Start from Notebook layout',\n value: {\n target: [`${registry}/layouts/notebook`],\n replace: [\n ['fumadocs-ui/layouts/notebook', '@/components/layout/notebook'],\n ['fumadocs-ui/layouts/notebook/page', '@/components/layout/notebook/page'],\n ],\n },\n hint: 'useful for adjusting small details.',\n },\n {\n label: 'Start from Flux layout',\n value: {\n target: [`${registry}/layouts/flux`],\n replace: [\n ['fumadocs-ui/layouts/flux', '@/components/layout/flux'],\n ['fumadocs-ui/layouts/flux/page', '@/components/layout/flux/page'],\n ],\n },\n hint: 'useful for adjusting small details.',\n },\n ],\n });\n },\n },\n {\n onCancel: () => {\n cancel('Installation Stopped.');\n process.exit(0);\n },\n },\n );\n\n const target = result.target as TargetInfo;\n await install(target.target, installer);\n printNext(...target.replace);\n\n outro(picocolors.bold('Have fun!'));\n}\n\nfunction printNext(...maps: [from: string, to: string][]) {\n intro(picocolors.bold('What is Next?'));\n\n log.info(\n [\n 'You can check the installed components in `components`.',\n picocolors.dim('---'),\n 'Open your `layout.tsx` files, replace the imports of components:',\n ...maps.map(([from, to]) => picocolors.greenBright(`\"${from}\" -> \"${to}\"`)),\n ].join('\\n'),\n );\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { exists } from '@/utils/fs';\nimport picocolors from 'picocolors';\nimport { spinner } from '@clack/prompts';\nimport { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\n\ninterface PackageJson {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n}\n\nasync function readPackageJson(cwd: string): Promise<PackageJson | null> {\n try {\n const raw = await fs.readFile(path.join(cwd, 'package.json'), 'utf-8');\n return JSON.parse(raw) as PackageJson;\n } catch {\n return null;\n }\n}\n\n/** Path of pre-rendered EPUB, choose one according to your React framework. Next.js fetches from the running server instead. */\nconst EPUB_BUILD_PATHS: Record<string, string> = {\n next: '', // Fetched from /export/epub at runtime; route handlers don't produce static files\n 'tanstack-start': '.output/public/export/epub',\n 'tanstack-start-spa': 'dist/client/export/epub',\n 'react-router': 'build/client/export/epub',\n 'react-router-spa': 'build/client/export/epub',\n waku: 'dist/public/export/epub',\n};\n\nconst API_ROUTE_TEMPLATE = `import { source } from '@/lib/source';\nimport { exportEpub } from 'fumadocs-epub';\n\nexport const revalidate = false;\n\nexport async function GET(request: Request): Promise<Response> {\n // Require EXPORT_SECRET to prevent unauthenticated abuse. Pass via Authorization: Bearer <secret>\n const secret = process.env.EXPORT_SECRET;\n if (!secret) {\n return new Response('EXPORT_SECRET is not configured. Set it in your environment to protect this endpoint.', { status: 503 });\n }\n const authHeader = request.headers.get('authorization');\n const token = authHeader?.replace(/^Bearer\\\\s+/i, '') ?? '';\n if (token !== secret) {\n return new Response('Unauthorized', { status: authHeader ? 403 : 401 });\n }\n const buffer = await exportEpub({\n source,\n title: 'Documentation',\n author: 'Your Team',\n description: 'Exported documentation',\n cover: '/cover.png',\n });\n return new Response(new Uint8Array(buffer), {\n headers: {\n 'Content-Type': 'application/epub+zip',\n 'Content-Disposition': 'attachment; filename=\"docs.epub\"',\n },\n });\n}\n`;\n\nasync function findAppDir(cwd: string): Promise<string | null> {\n const appPaths = ['app', 'src/app'];\n for (const appPath of appPaths) {\n const fullPath = path.join(cwd, appPath);\n if (await exists(fullPath)) {\n return fullPath;\n }\n }\n return null;\n}\n\nasync function scaffoldEpubRoute(cwd: string): Promise<boolean> {\n const appDir = await findAppDir(cwd);\n if (!appDir) {\n console.error(picocolors.red('Could not find app directory (app/ or src/app/)'));\n return false;\n }\n\n const routePath = path.join(appDir, 'export', 'epub', 'route.ts');\n if (await exists(routePath)) {\n console.log(picocolors.yellow('EPUB route already exists at'), routePath);\n return true;\n }\n\n await fs.mkdir(path.dirname(routePath), { recursive: true });\n await fs.writeFile(routePath, API_ROUTE_TEMPLATE);\n console.log(picocolors.green('Created EPUB route at'), routePath);\n return true;\n}\n\nexport async function exportEpub(options: {\n output?: string;\n framework: string;\n scaffoldOnly?: boolean;\n}) {\n const cwd = process.cwd();\n const outputPath = path.resolve(cwd, options.output ?? 'docs.epub');\n const framework = options.framework;\n\n const spin = spinner();\n\n const buildPath = EPUB_BUILD_PATHS[framework];\n if (!(framework in EPUB_BUILD_PATHS)) {\n const valid = Object.keys(EPUB_BUILD_PATHS).join(', ');\n console.error(picocolors.red(`Invalid --framework \"${framework}\". Must be one of: ${valid}`));\n process.exit(1);\n }\n\n // Check for Next.js when scaffolding (only Next.js scaffold is implemented)\n const pkg = await readPackageJson(cwd);\n const hasNextConfig =\n (await exists(path.join(cwd, 'next.config.js'))) ||\n (await exists(path.join(cwd, 'next.config.ts'))) ||\n (await exists(path.join(cwd, 'next.config.mjs')));\n const nextDeps = pkg\n ? { ...pkg.dependencies, ...pkg.devDependencies, ...pkg.peerDependencies }\n : {};\n const hasNextInPkg = !!nextDeps?.next;\n const hasAppOrPages =\n (await exists(path.join(cwd, 'app'))) ||\n (await exists(path.join(cwd, 'pages'))) ||\n (await exists(path.join(cwd, 'src', 'app'))) ||\n (await exists(path.join(cwd, 'src', 'pages')));\n const hasNext = hasNextConfig || (hasNextInPkg && hasAppOrPages);\n\n if (!hasNext && framework === 'next') {\n console.error(\n picocolors.red(\n 'Next.js project not found. Run this command from a Fumadocs Next.js project root.',\n ),\n );\n process.exit(1);\n }\n\n // Scaffold EPUB route (Next.js only for now)\n if (framework === 'next') {\n spin.start('Scaffolding EPUB route');\n const scaffolded = await scaffoldEpubRoute(cwd);\n spin.stop(scaffolded ? 'EPUB route ready' : 'Scaffolding failed');\n\n if (!scaffolded) {\n process.exit(1);\n }\n }\n\n if (options.scaffoldOnly) {\n console.log(picocolors.cyan('\\nTo export:'));\n console.log(' 1. Add fumadocs-epub to your dependencies: pnpm add fumadocs-epub');\n console.log(' 2. Ensure includeProcessedMarkdown: true in your docs collection config');\n if (framework === 'next') {\n console.log(\n ' 3. Set EXPORT_SECRET in your environment to protect the /export/epub endpoint',\n );\n console.log(' 4. Run production build: pnpm build');\n console.log(' 5. Start the server (e.g. pnpm start) and keep it running');\n console.log(' 6. Run: fumadocs export epub --framework next');\n } else {\n console.log(` 3. Add a prerender route that outputs EPUB to ${buildPath}`);\n console.log(' 4. Run production build: pnpm build');\n console.log(` 5. Run: fumadocs export epub --framework ${framework}`);\n }\n return;\n }\n\n // Check for fumadocs-epub dependency\n if (!pkg) {\n console.error(\n picocolors.red('Cannot read or parse package.json. Ensure it exists and is valid JSON.'),\n );\n process.exit(1);\n }\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n if (!deps['fumadocs-epub']) {\n console.log(picocolors.yellow('\\nInstalling fumadocs-epub...'));\n const packageManager = process.env.npm_execpath?.includes('pnpm')\n ? 'pnpm'\n : process.env.npm_execpath?.includes('bun')\n ? 'bun'\n : 'npm';\n const installCmd = `${packageManager} add fumadocs-epub`;\n try {\n await execAsync(installCmd, { cwd });\n } catch (err: unknown) {\n const stderr =\n err && typeof err === 'object' && 'stderr' in err\n ? String((err as { stderr?: string }).stderr)\n : '';\n console.error(picocolors.red(`Failed to install fumadocs-epub. Command: ${installCmd}`));\n if (stderr) console.error(stderr);\n process.exit(1);\n }\n }\n\n if (framework === 'next') {\n const secret = process.env.EXPORT_SECRET;\n if (!secret) {\n console.error(\n picocolors.red('EXPORT_SECRET is required for Next.js export. Set it in your environment.'),\n );\n process.exit(1);\n }\n const port = process.env.PORT || '3000';\n const url = `http://localhost:${port}/export/epub`;\n spin.start('Fetching EPUB from server');\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 30_000);\n try {\n const res = await fetch(url, {\n headers: { Authorization: `Bearer ${secret}` },\n signal: controller.signal,\n });\n if (!res.ok) {\n if (res.status === 401 || res.status === 403) {\n console.error(\n picocolors.red('Auth failed. Check that EXPORT_SECRET matches the value in your app.'),\n );\n } else {\n console.error(\n picocolors.red(\n `Server returned ${res.status}. Ensure the app is running (e.g. pnpm start) on port ${port}.`,\n ),\n );\n }\n process.exit(1);\n }\n const buffer = Buffer.from(await res.arrayBuffer());\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n await fs.writeFile(outputPath, buffer);\n spin.stop(picocolors.green(`EPUB saved to ${outputPath}`));\n } catch (err: unknown) {\n if (err instanceof Error && err.name === 'AbortError') {\n console.error(picocolors.red('Request timed out after 30 seconds.'));\n } else {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(picocolors.red(`Could not fetch EPUB: ${msg}`));\n }\n console.error(\n picocolors.yellow(`Ensure the server is running (e.g. pnpm start) on port ${port}.`),\n );\n process.exit(1);\n } finally {\n clearTimeout(timeoutId);\n }\n return;\n }\n\n const fullBuildPath = path.join(cwd, buildPath);\n if (!(await exists(fullBuildPath))) {\n console.error(\n picocolors.red(\n `EPUB not found at ${buildPath}. Run production build first (e.g. pnpm build).`,\n ),\n );\n process.exit(1);\n }\n\n spin.start('Copying EPUB');\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n await fs.copyFile(fullBuildPath, outputPath);\n spin.stop(picocolors.green(`EPUB saved to ${outputPath}`));\n}\n","#!/usr/bin/env node\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { Command } from 'commander';\nimport picocolors from 'picocolors';\nimport { createOrLoadConfig, initConfig, type LoadedConfig } from '@/config';\nimport { type JsonTreeNode, treeToJavaScript, treeToMdx } from '@/commands/file-tree';\nimport { runTree } from '@/utils/file-tree/run-tree';\nimport packageJson from '../package.json';\nimport { customise } from '@/commands/customise';\nimport { add } from '@/commands/add';\nimport { exportEpub } from '@/commands/export-epub';\nimport { HttpRegistryClient, LocalRegistryClient } from '@/registry/client';\n\nconst program = new Command().option('--config <string>');\n\nprogram\n .name('fumadocs')\n .description('CLI to setup Fumadocs, init a config')\n .version(packageJson.version)\n .action(async () => {\n if (await initConfig()) {\n console.log(picocolors.green('Initialized a `./cli.json` config file.'));\n } else {\n console.log(picocolors.redBright('A config file already exists.'));\n }\n });\n\nprogram\n .command('customise')\n .alias('customize')\n .description('simple way to customise layouts with Fumadocs UI')\n .option('--dir <string>', 'the root url or directory to resolve registry')\n .action(async (options: { config?: string; dir?: string }) => {\n await customise(createClientFromDir(options.dir, await createOrLoadConfig(options.config)));\n });\n\nconst dirShortcuts: Record<string, string> = {\n ':preview': 'https://preview.fumadocs.dev/registry',\n ':dev': 'http://localhost:3000/registry',\n};\n\nprogram\n .command('add')\n .description('add a new component to your docs')\n .argument('[components...]', 'components to download')\n .option('--dir <string>', 'the root url or directory to resolve registry')\n .action(async (input: string[], options: { config?: string; dir?: string }) => {\n const client = createClientFromDir(options.dir, await createOrLoadConfig(options.config));\n await add(input, client);\n });\n\nconst exportCmd = program.command('export').description('export documentation to various formats');\n\nexportCmd\n .command('epub')\n .description('export documentation to EPUB format (run after production build)')\n .requiredOption('--framework <name>', 'React framework: next, tanstack-start, react-router, waku')\n .option('--output <path>', 'output file path', 'docs.epub')\n .option('--scaffold-only', 'only scaffold the EPUB route, do not copy')\n .action(async (options: { output?: string; framework: string; scaffoldOnly?: boolean }) => {\n await exportEpub({\n output: options.output,\n framework: options.framework,\n scaffoldOnly: options.scaffoldOnly,\n });\n });\n\nprogram\n .command('tree')\n .argument('[json_or_args]', 'JSON output of `tree` command or arguments for the `tree` command')\n .argument('[output]', 'output path of file')\n .option('--js', 'output as JavaScript file')\n .option('--no-root', 'remove the root node')\n .option('--import-name <name>', 'where to import components (JS only)')\n .action(\n async (\n str: string | undefined,\n output: string | undefined,\n { js, root, importName }: { js: boolean; root: boolean; importName?: string },\n ) => {\n const jsExtensions = ['.js', '.tsx', '.jsx'];\n const noRoot = !root;\n let nodes: JsonTreeNode[];\n\n try {\n nodes = JSON.parse(str ?? '') as JsonTreeNode[];\n } catch {\n nodes = await runTree(str ?? './');\n }\n\n const out =\n js || (output && jsExtensions.includes(path.extname(output)))\n ? treeToJavaScript(nodes, noRoot, importName)\n : treeToMdx(nodes, noRoot);\n\n if (output) {\n await fs.mkdir(path.dirname(output), { recursive: true });\n await fs.writeFile(output, out);\n } else {\n console.log(out);\n }\n },\n );\n\nfunction createClientFromDir(dir = 'https://fumadocs.dev/registry', config: LoadedConfig) {\n if (dir in dirShortcuts) dir = dirShortcuts[dir];\n\n return dir.startsWith('http://') || dir.startsWith('https://')\n ? new HttpRegistryClient(dir, config)\n : new LocalRegistryClient(dir, config);\n}\n\nprogram.parse();\n"],"mappings":"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"}
|
|
@@ -86,43 +86,78 @@ var ComponentInstaller = class {
|
|
|
86
86
|
this.downloadCache = createCache();
|
|
87
87
|
this.dependencies = {};
|
|
88
88
|
this.devDependencies = {};
|
|
89
|
-
this.pathToFileCache = createCache();
|
|
90
89
|
this.cwd = options.cwd ?? process.cwd();
|
|
91
90
|
this.plugins = options.plugins ?? [];
|
|
92
91
|
}
|
|
93
|
-
async
|
|
94
|
-
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
Object.assign(this.devDependencies, item.devDependencies);
|
|
104
|
-
}
|
|
105
|
-
for (const comp of downloaded) for (const file of comp.files) {
|
|
92
|
+
async installComponent(comp, ctx) {
|
|
93
|
+
if (ctx.stack.indexOf(comp) !== ctx.stack.length - 1) return;
|
|
94
|
+
const pluginCtx = {
|
|
95
|
+
installer: this,
|
|
96
|
+
...ctx
|
|
97
|
+
};
|
|
98
|
+
for (const plugin of this.plugins) comp = await plugin.beforeInstall?.(comp, pluginCtx) ?? comp;
|
|
99
|
+
Object.assign(this.dependencies, comp.dependencies);
|
|
100
|
+
Object.assign(this.devDependencies, comp.devDependencies);
|
|
101
|
+
for (const file of comp.files) {
|
|
106
102
|
const outPath = this.resolveOutputPath(file);
|
|
107
103
|
if (this.installedFiles.has(outPath)) continue;
|
|
108
104
|
this.installedFiles.add(outPath);
|
|
109
|
-
const output = typescriptExtensions.includes(path.extname(outPath)) ? await this.transform(
|
|
105
|
+
const output = typescriptExtensions.includes(path.extname(outPath)) ? await this.transform(file, comp, ctx) : file.content;
|
|
110
106
|
const status = await fs.readFile(outPath).then((res) => {
|
|
111
107
|
if (res.toString().trim() === output.trim()) return "ignore";
|
|
112
108
|
return "need-update";
|
|
113
109
|
}).catch(() => "write");
|
|
114
110
|
if (status === "ignore") continue;
|
|
115
111
|
if (status === "need-update") {
|
|
116
|
-
if (!await io.confirmFileOverride({ path: outPath })) continue;
|
|
112
|
+
if (!await ctx.io.confirmFileOverride({ path: outPath })) continue;
|
|
117
113
|
}
|
|
118
114
|
await fs.mkdir(path.dirname(outPath), { recursive: true });
|
|
119
115
|
await fs.writeFile(outPath, output);
|
|
120
|
-
io.onFileDownloaded({
|
|
116
|
+
ctx.io.onFileDownloaded({
|
|
121
117
|
path: outPath,
|
|
122
118
|
file,
|
|
123
119
|
component: comp
|
|
124
120
|
});
|
|
125
121
|
}
|
|
122
|
+
for (const child of comp.$subComponents) {
|
|
123
|
+
const stack = [...ctx.stack, child];
|
|
124
|
+
const variables = { ...ctx.$variables };
|
|
125
|
+
if (child.$registry.registryId !== comp.$registry.registryId) {
|
|
126
|
+
const info = await child.$registry.fetchRegistryInfo();
|
|
127
|
+
Object.assign(variables, info.variables);
|
|
128
|
+
}
|
|
129
|
+
Object.assign(variables, child.variables);
|
|
130
|
+
await this.installComponent(child, {
|
|
131
|
+
...ctx,
|
|
132
|
+
stack,
|
|
133
|
+
$variables: variables
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
async install(name, io) {
|
|
138
|
+
let downloaded;
|
|
139
|
+
const registry = (await this.rootClient.fetchRegistryInfo()).registries?.find((registry) => name.startsWith(`${registry}/`));
|
|
140
|
+
if (registry) downloaded = await this.download(name.slice(registry.length + 1), this.rootClient.createLinkedRegistryClient(registry));
|
|
141
|
+
else downloaded = await this.download(name, this.rootClient);
|
|
142
|
+
const allComponents = /* @__PURE__ */ new Set();
|
|
143
|
+
function scan(comp) {
|
|
144
|
+
if (allComponents.has(comp)) return;
|
|
145
|
+
allComponents.add(comp);
|
|
146
|
+
for (const child of comp.$subComponents) scan(child);
|
|
147
|
+
}
|
|
148
|
+
scan(downloaded);
|
|
149
|
+
const pathToFile = /* @__PURE__ */ new Map();
|
|
150
|
+
for (const comp of allComponents) for (const file of comp.files) pathToFile.set(file.target ?? file.path, file);
|
|
151
|
+
const info = await downloaded.$registry.fetchRegistryInfo();
|
|
152
|
+
await this.installComponent(downloaded, {
|
|
153
|
+
pathToFile,
|
|
154
|
+
io,
|
|
155
|
+
$variables: {
|
|
156
|
+
...info.env,
|
|
157
|
+
...downloaded.variables
|
|
158
|
+
},
|
|
159
|
+
stack: [downloaded]
|
|
160
|
+
});
|
|
126
161
|
}
|
|
127
162
|
async deps() {
|
|
128
163
|
const manager = new DependencyManager(this.cwd);
|
|
@@ -134,69 +169,73 @@ var ComponentInstaller = class {
|
|
|
134
169
|
if (config.commands.format) await x(config.commands.format);
|
|
135
170
|
}
|
|
136
171
|
/**
|
|
137
|
-
*
|
|
172
|
+
* download component & its sub components
|
|
138
173
|
*/
|
|
139
|
-
async download(name, client
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
};
|
|
146
|
-
for (const [k, v] of Object.entries(info.variables ?? {})) variables[k] ??= v.default;
|
|
147
|
-
return (await this.downloadCache.cached(hash, async (presolve) => {
|
|
174
|
+
async download(name, client) {
|
|
175
|
+
return this.downloadCache.cached(JSON.stringify([client.registryId, name]), async (presolve) => {
|
|
176
|
+
for (const plugin of this.plugins) await plugin.beforeDownload?.({
|
|
177
|
+
installer: this,
|
|
178
|
+
name
|
|
179
|
+
});
|
|
148
180
|
const comp = await client.fetchComponent(name);
|
|
149
|
-
const result =
|
|
181
|
+
const result = {
|
|
182
|
+
...comp,
|
|
183
|
+
$registry: client,
|
|
184
|
+
$subComponents: []
|
|
185
|
+
};
|
|
150
186
|
presolve(result);
|
|
151
|
-
|
|
187
|
+
result.$subComponents = await Promise.all(comp.subComponents.map((sub) => {
|
|
152
188
|
if (typeof sub === "string") return this.download(sub, client);
|
|
153
|
-
|
|
154
|
-
|
|
189
|
+
let subClient;
|
|
190
|
+
if (this.rootClient instanceof HttpRegistryClient) {
|
|
191
|
+
const baseUrl = new URL(sub.baseUrl, `${this.rootClient.baseUrl}/`).href;
|
|
192
|
+
subClient = client instanceof HttpRegistryClient && client.baseUrl === baseUrl ? client : new HttpRegistryClient(baseUrl, client.config);
|
|
193
|
+
} else subClient = new HttpRegistryClient(sub.baseUrl, client.config);
|
|
194
|
+
return this.download(sub.component, subClient);
|
|
155
195
|
}));
|
|
156
|
-
for (const
|
|
196
|
+
for (const plugin of this.plugins) await plugin.afterDownload?.({
|
|
197
|
+
installer: this,
|
|
198
|
+
name,
|
|
199
|
+
result
|
|
200
|
+
});
|
|
157
201
|
return result;
|
|
158
|
-
})
|
|
159
|
-
...file,
|
|
160
|
-
variables
|
|
161
|
-
}));
|
|
202
|
+
});
|
|
162
203
|
}
|
|
163
|
-
async transform(
|
|
204
|
+
async transform(file, component, ctx) {
|
|
164
205
|
const filePath = this.resolveOutputPath(file);
|
|
165
206
|
const parsed = await parse(filePath, file.content);
|
|
166
207
|
const s = new MagicString(file.content);
|
|
208
|
+
const transformCtx = {
|
|
209
|
+
installer: this,
|
|
210
|
+
s,
|
|
211
|
+
file,
|
|
212
|
+
component,
|
|
213
|
+
parsed,
|
|
214
|
+
...ctx
|
|
215
|
+
};
|
|
216
|
+
for (const plugin of this.plugins) await plugin.beforeTransform?.(transformCtx);
|
|
167
217
|
const prefix = "@/";
|
|
168
|
-
const variables = Object.entries(component.variables ?? {});
|
|
169
|
-
const pathToFile = await this.pathToFileCache.cached(taskId, () => {
|
|
170
|
-
const map = /* @__PURE__ */ new Map();
|
|
171
|
-
for (const comp of allComponents) for (const file of comp.files) map.set(file.target ?? file.path, file);
|
|
172
|
-
return map;
|
|
173
|
-
});
|
|
174
218
|
transformSpecifiers(parsed.program, s, (specifier) => {
|
|
175
|
-
for (const [k, v] of variables) specifier = specifier.replaceAll(`<${k}>`, v);
|
|
219
|
+
for (const [k, v] of Object.entries(ctx.$variables)) if (typeof v === "string") specifier = specifier.replaceAll(`<${k}>`, v);
|
|
176
220
|
if (specifier.startsWith(prefix)) {
|
|
177
221
|
const lookup = specifier.substring(2);
|
|
178
|
-
const target = pathToFile.get(lookup);
|
|
222
|
+
const target = ctx.pathToFile.get(lookup);
|
|
179
223
|
if (target) specifier = toImportSpecifier(filePath, this.resolveOutputPath(target));
|
|
180
|
-
else io.onWarn(`cannot find the referenced file of ${specifier}`);
|
|
224
|
+
else ctx.io.onWarn(`cannot find the referenced file of ${specifier}`);
|
|
181
225
|
}
|
|
182
226
|
return specifier;
|
|
183
227
|
});
|
|
184
|
-
for (const plugin of this.plugins) await plugin.
|
|
185
|
-
s,
|
|
186
|
-
parsed,
|
|
187
|
-
file,
|
|
188
|
-
component
|
|
189
|
-
});
|
|
228
|
+
for (const plugin of this.plugins) await plugin.afterTransform?.(transformCtx);
|
|
190
229
|
return s.toString();
|
|
191
230
|
}
|
|
192
231
|
resolveOutputPath(file) {
|
|
193
232
|
const config = this.rootClient.config;
|
|
194
233
|
const dir = {
|
|
195
234
|
components: config.aliases.componentsDir,
|
|
196
|
-
block: config.aliases.blockDir,
|
|
197
235
|
ui: config.aliases.uiDir,
|
|
198
236
|
css: config.aliases.cssDir,
|
|
199
237
|
lib: config.aliases.libDir,
|
|
238
|
+
layout: config.aliases.layoutDir,
|
|
200
239
|
route: "./"
|
|
201
240
|
}[file.type];
|
|
202
241
|
if (file.target) return path.resolve(this.cwd, config.baseDir, file.target.replace("<dir>", dir));
|
|
@@ -206,4 +245,4 @@ var ComponentInstaller = class {
|
|
|
206
245
|
//#endregion
|
|
207
246
|
export { ComponentInstaller as t };
|
|
208
247
|
|
|
209
|
-
//# sourceMappingURL=installer-
|
|
248
|
+
//# sourceMappingURL=installer-B3-my9zN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installer-B3-my9zN.js","names":[],"sources":["../src/utils/get-package-manager.ts","../src/registry/installer/dep-manager.ts","../src/registry/installer/index.ts"],"sourcesContent":["import { detect, type AgentName } from 'package-manager-detector';\n\nexport type PackageManager = AgentName;\n\nexport async function getPackageManager(): Promise<PackageManager> {\n const result = await detect();\n\n return result?.name ?? 'npm';\n}\n","import fs from 'node:fs/promises';\nimport { getPackageManager, PackageManager } from '@/utils/get-package-manager';\nimport { x } from 'tinyexec';\nimport path from 'node:path';\n\ninterface PackageJsonType {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nexport class DependencyManager {\n private installedDeps = new Map<string, string>();\n dependencies: string[] = [];\n devDependencies: string[] = [];\n packageManager: PackageManager = 'npm';\n\n constructor(private readonly cwd: string) {}\n\n async init(deps: Record<string, string | null>, devDeps: Record<string, string | null>) {\n this.installedDeps.clear();\n const packageJsonPath = path.join(this.cwd, 'package.json');\n const content = await fs\n .readFile(packageJsonPath)\n .then((res) => res.toString())\n .catch(() => null);\n\n if (content !== null) {\n const parsed = JSON.parse(content) as PackageJsonType;\n\n for (const [k, v] of Object.entries(parsed?.dependencies ?? {})) {\n this.installedDeps.set(k, v);\n }\n\n for (const [k, v] of Object.entries(parsed?.devDependencies ?? {})) {\n this.installedDeps.set(k, v);\n }\n }\n\n this.dependencies = this.resolveRequiredDependencies(deps);\n this.devDependencies = this.resolveRequiredDependencies(devDeps);\n this.packageManager = await getPackageManager();\n }\n\n private resolveRequiredDependencies(deps: Record<string, string | null>): string[] {\n return Object.entries(deps)\n .filter(([k]) => !this.installedDeps.has(k))\n .map(([k, v]) => (v === null || v.length === 0 ? k : `${k}@${v}`));\n }\n\n hasRequired() {\n return this.dependencies.length > 0 || this.devDependencies.length > 0;\n }\n\n async writeRequired() {\n const packageJsonPath = path.join(this.cwd, 'package.json');\n const content = await fs.readFile(packageJsonPath).catch(() => null);\n if (content === null) return false;\n\n const parsed = JSON.parse(content.toString()) as PackageJsonType;\n if (!parsed) return false;\n\n for (const dep of this.dependencies) {\n const { name, version } = parseDep(dep);\n parsed.dependencies ??= {};\n parsed.dependencies[name] ??= version;\n }\n\n for (const dep of this.devDependencies) {\n const { name, version } = parseDep(dep);\n parsed.devDependencies ??= {};\n parsed.devDependencies[name] ??= version;\n }\n\n await fs.writeFile(packageJsonPath, JSON.stringify(parsed, null, 2));\n }\n\n async installRequired() {\n if (this.dependencies.length > 0)\n await x(this.packageManager, ['install', ...this.dependencies]);\n if (this.devDependencies.length > 0)\n await x(this.packageManager, ['install', ...this.devDependencies, '-D']);\n }\n}\n\nfunction parseDep(dep: string) {\n const idx = dep.indexOf('@', 1);\n if (idx === -1) {\n return { name: dep, version: 'latest' };\n } else {\n return { name: dep.slice(0, idx), version: dep.slice(idx + 1) };\n }\n}\n","import path from 'node:path';\nimport fs from 'node:fs/promises';\nimport { typescriptExtensions } from '@/constants';\nimport { toImportSpecifier, transformSpecifiers } from '@/utils/ast';\nimport type { Component, File } from '@/registry/schema';\nimport { HttpRegistryClient, type RegistryClient } from '@/registry/client';\nimport { x } from 'tinyexec';\nimport { DependencyManager } from '@/registry/installer/dep-manager';\nimport { createCache } from '@/utils/cache';\nimport { parse, type ParseResult } from 'oxc-parser';\nimport MagicString from 'magic-string';\n\ninterface PluginContext {\n installer: ComponentInstaller;\n}\n\ninterface TransformContext extends PluginContext, InstallContext {\n s: MagicString;\n parsed: ParseResult;\n file: File;\n component: DownloadedComponent;\n}\n\ninterface InstallContext {\n pathToFile: Map<string, File>;\n io: IOInterface;\n /** full variables of the current component. */\n $variables: Record<string, unknown>;\n /** the last item is always the current component. */\n stack: DownloadedComponent[];\n}\n\ninterface DownloadedComponent extends Component {\n $subComponents: DownloadedComponent[];\n $registry: RegistryClient;\n}\n\ntype Awaitable<T> = T | Promise<T>;\n\nexport interface ComponentInstallerPlugin {\n /**\n * transform file before writing (before default transformation)\n */\n beforeTransform?: (context: TransformContext) => Awaitable<void>;\n\n /**\n * transform file before writing (after default transformation)\n */\n afterTransform?: (context: TransformContext) => Awaitable<void>;\n\n /**\n * transform component before install\n */\n beforeInstall?: (\n comp: DownloadedComponent,\n context: InstallContext & PluginContext,\n ) => Awaitable<DownloadedComponent | undefined>;\n\n beforeDownload?: (\n context: PluginContext & {\n name: string;\n },\n ) => void | Promise<void>;\n\n afterDownload?: (\n context: PluginContext & {\n name: string;\n result: DownloadedComponent;\n },\n ) => void | Promise<void>;\n}\n\nexport interface IOInterface {\n onWarn: (message: string) => void;\n confirmFileOverride: (options: { path: string }) => Promise<boolean>;\n onFileDownloaded: (options: { path: string; file: File; component: Component }) => void;\n}\n\nexport interface ComponentInstallerOptions {\n plugins?: ComponentInstallerPlugin[];\n cwd?: string;\n}\n\nexport class ComponentInstaller {\n private readonly installedFiles = new Set<string>();\n private readonly downloadCache = createCache<DownloadedComponent>();\n private readonly cwd: string;\n private readonly plugins: ComponentInstallerPlugin[];\n readonly dependencies: Record<string, string | null> = {};\n readonly devDependencies: Record<string, string | null> = {};\n\n constructor(\n private readonly rootClient: RegistryClient,\n options: ComponentInstallerOptions = {},\n ) {\n this.cwd = options.cwd ?? process.cwd();\n this.plugins = options.plugins ?? [];\n }\n\n private async installComponent(comp: DownloadedComponent, ctx: InstallContext) {\n // avoid circular refs\n if (ctx.stack.indexOf(comp) !== ctx.stack.length - 1) return;\n\n const pluginCtx = { installer: this, ...ctx };\n for (const plugin of this.plugins) {\n comp = (await plugin.beforeInstall?.(comp, pluginCtx)) ?? comp;\n }\n\n Object.assign(this.dependencies, comp.dependencies);\n Object.assign(this.devDependencies, comp.devDependencies);\n\n for (const file of comp.files) {\n const outPath = this.resolveOutputPath(file);\n if (this.installedFiles.has(outPath)) continue;\n this.installedFiles.add(outPath);\n\n const output = typescriptExtensions.includes(path.extname(outPath))\n ? await this.transform(file, comp, ctx)\n : file.content;\n\n const status = await fs\n .readFile(outPath)\n .then((res) => {\n if (res.toString().trim() === output.trim()) return 'ignore';\n return 'need-update';\n })\n .catch(() => 'write');\n\n if (status === 'ignore') continue;\n\n if (status === 'need-update') {\n const override = await ctx.io.confirmFileOverride({ path: outPath });\n if (!override) continue;\n }\n\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, output);\n ctx.io.onFileDownloaded({ path: outPath, file, component: comp });\n }\n\n for (const child of comp.$subComponents) {\n const stack = [...ctx.stack, child];\n const variables = { ...ctx.$variables };\n if (child.$registry.registryId !== comp.$registry.registryId) {\n const info = await child.$registry.fetchRegistryInfo();\n Object.assign(variables, info.variables);\n }\n Object.assign(variables, child.variables);\n\n await this.installComponent(child, { ...ctx, stack, $variables: variables });\n }\n }\n\n async install(name: string, io: IOInterface) {\n let downloaded: DownloadedComponent;\n // detect linked registry\n const rootInfo = await this.rootClient.fetchRegistryInfo();\n const registry = rootInfo.registries?.find((registry) => name.startsWith(`${registry}/`));\n\n if (registry) {\n downloaded = await this.download(\n name.slice(registry.length + 1),\n this.rootClient.createLinkedRegistryClient(registry),\n );\n } else {\n downloaded = await this.download(name, this.rootClient);\n }\n\n const allComponents = new Set<DownloadedComponent>();\n function scan(comp: DownloadedComponent) {\n if (allComponents.has(comp)) return;\n\n allComponents.add(comp);\n for (const child of comp.$subComponents) scan(child);\n }\n\n scan(downloaded);\n\n const pathToFile = new Map<string, File>();\n for (const comp of allComponents) {\n for (const file of comp.files) pathToFile.set(file.target ?? file.path, file);\n }\n\n const info = await downloaded.$registry.fetchRegistryInfo();\n await this.installComponent(downloaded, {\n pathToFile,\n io,\n $variables: { ...info.env, ...downloaded.variables },\n stack: [downloaded],\n });\n }\n\n async deps() {\n const manager = new DependencyManager(this.cwd);\n await manager.init(this.dependencies, this.devDependencies);\n return manager;\n }\n\n async onEnd() {\n const config = this.rootClient.config;\n if (config.commands.format) {\n await x(config.commands.format);\n }\n }\n\n /**\n * download component & its sub components\n */\n private async download(name: string, client: RegistryClient): Promise<DownloadedComponent> {\n return this.downloadCache.cached(\n JSON.stringify([client.registryId, name]),\n async (presolve) => {\n for (const plugin of this.plugins) {\n await plugin.beforeDownload?.({\n installer: this,\n name,\n });\n }\n\n const comp = await client.fetchComponent(name);\n const result: DownloadedComponent = {\n ...comp,\n $registry: client,\n $subComponents: [],\n };\n // place it before downloading child components to avoid recursive downloads\n presolve(result);\n\n result.$subComponents = await Promise.all(\n comp.subComponents.map((sub) => {\n if (typeof sub === 'string') return this.download(sub, client);\n\n let subClient: RegistryClient;\n if (this.rootClient instanceof HttpRegistryClient) {\n const baseUrl = new URL(sub.baseUrl, `${this.rootClient.baseUrl}/`).href;\n subClient =\n client instanceof HttpRegistryClient && client.baseUrl === baseUrl\n ? client\n : new HttpRegistryClient(baseUrl, client.config);\n } else {\n subClient = new HttpRegistryClient(sub.baseUrl, client.config);\n }\n\n return this.download(sub.component, subClient);\n }),\n );\n\n for (const plugin of this.plugins) {\n await plugin.afterDownload?.({\n installer: this,\n name,\n result,\n });\n }\n\n return result;\n },\n );\n }\n\n private async transform(\n file: File,\n component: DownloadedComponent,\n ctx: InstallContext,\n ): Promise<string> {\n const filePath = this.resolveOutputPath(file);\n const parsed = await parse(filePath, file.content);\n const s = new MagicString(file.content);\n const transformCtx: TransformContext = { installer: this, s, file, component, parsed, ...ctx };\n\n for (const plugin of this.plugins) {\n await plugin.beforeTransform?.(transformCtx);\n }\n\n // transform alias\n const prefix = '@/';\n\n transformSpecifiers(parsed.program, s, (specifier) => {\n for (const [k, v] of Object.entries(ctx.$variables)) {\n if (typeof v === 'string') specifier = specifier.replaceAll(`<${k}>`, v);\n }\n\n if (specifier.startsWith(prefix)) {\n const lookup = specifier.substring(prefix.length);\n const target = ctx.pathToFile.get(lookup);\n\n if (target) {\n specifier = toImportSpecifier(filePath, this.resolveOutputPath(target));\n } else {\n ctx.io.onWarn(`cannot find the referenced file of ${specifier}`);\n }\n }\n\n return specifier;\n });\n\n for (const plugin of this.plugins) {\n await plugin.afterTransform?.(transformCtx);\n }\n\n return s.toString();\n }\n\n private resolveOutputPath(file: File): string {\n const config = this.rootClient.config;\n const dir = (\n {\n components: config.aliases.componentsDir,\n ui: config.aliases.uiDir,\n css: config.aliases.cssDir,\n lib: config.aliases.libDir,\n layout: config.aliases.layoutDir,\n route: './',\n } as const\n )[file.type];\n if (file.target) {\n return path.resolve(this.cwd, config.baseDir, file.target.replace('<dir>', dir));\n }\n\n return path.resolve(this.cwd, config.baseDir, dir, path.basename(file.path));\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as DownloadedRegistryInfo, i as Component } from "../schema-
|
|
2
|
-
import { n as LoadedConfig } from "../config-
|
|
1
|
+
import { a as DownloadedRegistryInfo, i as Component } from "../schema-80shuzWO.js";
|
|
2
|
+
import { n as LoadedConfig } from "../config-Dyass4D9.js";
|
|
3
3
|
|
|
4
4
|
//#region src/registry/client.d.ts
|
|
5
5
|
interface RegistryClient {
|
|
@@ -23,7 +23,6 @@ declare class HttpRegistryClient implements RegistryClient {
|
|
|
23
23
|
}[];
|
|
24
24
|
variables?: Record<string, {
|
|
25
25
|
description?: string | undefined;
|
|
26
|
-
default?: unknown;
|
|
27
26
|
}> | undefined;
|
|
28
27
|
env?: Record<string, unknown> | undefined;
|
|
29
28
|
registries?: string[] | undefined;
|
|
@@ -31,7 +30,7 @@ declare class HttpRegistryClient implements RegistryClient {
|
|
|
31
30
|
fetchComponent(name: string): Promise<{
|
|
32
31
|
name: string;
|
|
33
32
|
files: {
|
|
34
|
-
type: "components" | "lib" | "css" | "route" | "ui" | "
|
|
33
|
+
type: "components" | "lib" | "css" | "route" | "ui" | "layout";
|
|
35
34
|
path: string;
|
|
36
35
|
content: string;
|
|
37
36
|
target?: string | undefined;
|
|
@@ -45,6 +44,7 @@ declare class HttpRegistryClient implements RegistryClient {
|
|
|
45
44
|
})[];
|
|
46
45
|
title?: string | undefined;
|
|
47
46
|
description?: string | undefined;
|
|
47
|
+
variables?: Record<string, unknown> | undefined;
|
|
48
48
|
}>;
|
|
49
49
|
hasComponent(name: string): Promise<boolean>;
|
|
50
50
|
createLinkedRegistryClient(name: string): HttpRegistryClient;
|
|
@@ -63,7 +63,6 @@ declare class LocalRegistryClient implements RegistryClient {
|
|
|
63
63
|
}[];
|
|
64
64
|
variables?: Record<string, {
|
|
65
65
|
description?: string | undefined;
|
|
66
|
-
default?: unknown;
|
|
67
66
|
}> | undefined;
|
|
68
67
|
env?: Record<string, unknown> | undefined;
|
|
69
68
|
registries?: string[] | undefined;
|
|
@@ -71,7 +70,7 @@ declare class LocalRegistryClient implements RegistryClient {
|
|
|
71
70
|
fetchComponent(name: string): Promise<{
|
|
72
71
|
name: string;
|
|
73
72
|
files: {
|
|
74
|
-
type: "components" | "lib" | "css" | "route" | "ui" | "
|
|
73
|
+
type: "components" | "lib" | "css" | "route" | "ui" | "layout";
|
|
75
74
|
path: string;
|
|
76
75
|
content: string;
|
|
77
76
|
target?: string | undefined;
|
|
@@ -85,6 +84,7 @@ declare class LocalRegistryClient implements RegistryClient {
|
|
|
85
84
|
})[];
|
|
86
85
|
title?: string | undefined;
|
|
87
86
|
description?: string | undefined;
|
|
87
|
+
variables?: Record<string, unknown> | undefined;
|
|
88
88
|
}>;
|
|
89
89
|
hasComponent(name: string): Promise<boolean>;
|
|
90
90
|
createLinkedRegistryClient(name: string): LocalRegistryClient;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","names":[],"sources":["../../src/registry/client.ts"],"mappings":";;;;UAWiB,cAAA;EAAA,SACN,UAAA;EAAA,SACA,MAAA,EAAQ,YAAA;EACjB,iBAAA,QAAyB,OAAA,CAAQ,sBAAA;EACjC,cAAA,GAAiB,IAAA,aAAiB,OAAA,CAAQ,SAAA;EAC1C,YAAA,GAAe,IAAA,aAAiB,OAAA;EAChC,0BAAA,GAA6B,YAAA,aAAyB,cAAA;AAAA;AAAA,cAK3C,kBAAA,YAA8B,cAAA;EAAA,SAI9B,OAAA;EAAA,SACA,MAAA,EAAQ,YAAA;EAAA,SAJV,UAAA;cAGE,OAAA,UACA,MAAA,EAAQ,YAAA;EAKb,iBAAA,CAAkB,OAAA,YAAsB,OAAA
|
|
1
|
+
{"version":3,"file":"client.d.ts","names":[],"sources":["../../src/registry/client.ts"],"mappings":";;;;UAWiB,cAAA;EAAA,SACN,UAAA;EAAA,SACA,MAAA,EAAQ,YAAA;EACjB,iBAAA,QAAyB,OAAA,CAAQ,sBAAA;EACjC,cAAA,GAAiB,IAAA,aAAiB,OAAA,CAAQ,SAAA;EAC1C,YAAA,GAAe,IAAA,aAAiB,OAAA;EAChC,0BAAA,GAA6B,YAAA,aAAyB,cAAA;AAAA;AAAA,cAK3C,kBAAA,YAA8B,cAAA;EAAA,SAI9B,OAAA;EAAA,SACA,MAAA,EAAQ,YAAA;EAAA,SAJV,UAAA;cAGE,OAAA,UACA,MAAA,EAAQ,YAAA;EAKb,iBAAA,CAAkB,OAAA,YAAsB,OAAA;;;;;;;;;;;;EAaxC,cAAA,CAAe,IAAA,WAAY,OAAA;;;;;;;;;;;;;;;;;;;EAgB3B,YAAA,CAAa,IAAA,WAAY,OAAA;EAM/B,0BAAA,CAA2B,IAAA,WAAY,kBAAA;AAAA;AAAA,cAK5B,mBAAA,YAA+B,cAAA;EAAA,iBAKvB,GAAA;EAAA,SACR,MAAA,EAAQ,YAAA;EAAA,SALV,UAAA;EAAA,QACD,YAAA;cAGW,GAAA,UACR,MAAA,EAAQ,YAAA;EAKb,iBAAA,CAAkB,GAAA,YAAc,OAAA;;;;;;;;;;;;EAgBhC,cAAA,CAAe,IAAA,WAAY,OAAA;;;;;;;;;;;;;;;;;;;EAY3B,YAAA,CAAa,IAAA,WAAY,OAAA;EAU/B,0BAAA,CAA2B,IAAA,WAAY,mBAAA;AAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as Component, o as File } from "../../schema-
|
|
1
|
+
import { i as Component, o as File } from "../../schema-80shuzWO.js";
|
|
2
2
|
import { RegistryClient } from "../client.js";
|
|
3
3
|
import { ParseResult } from "oxc-parser";
|
|
4
4
|
import { AgentName } from "package-manager-detector";
|
|
@@ -23,18 +23,47 @@ declare class DependencyManager {
|
|
|
23
23
|
}
|
|
24
24
|
//#endregion
|
|
25
25
|
//#region src/registry/installer/index.d.ts
|
|
26
|
-
interface
|
|
27
|
-
|
|
26
|
+
interface PluginContext {
|
|
27
|
+
installer: ComponentInstaller;
|
|
28
28
|
}
|
|
29
|
+
interface TransformContext extends PluginContext, InstallContext {
|
|
30
|
+
s: MagicString;
|
|
31
|
+
parsed: ParseResult;
|
|
32
|
+
file: File;
|
|
33
|
+
component: DownloadedComponent;
|
|
34
|
+
}
|
|
35
|
+
interface InstallContext {
|
|
36
|
+
pathToFile: Map<string, File>;
|
|
37
|
+
io: IOInterface;
|
|
38
|
+
/** full variables of the current component. */
|
|
39
|
+
$variables: Record<string, unknown>;
|
|
40
|
+
/** the last item is always the current component. */
|
|
41
|
+
stack: DownloadedComponent[];
|
|
42
|
+
}
|
|
43
|
+
interface DownloadedComponent extends Component {
|
|
44
|
+
$subComponents: DownloadedComponent[];
|
|
45
|
+
$registry: RegistryClient;
|
|
46
|
+
}
|
|
47
|
+
type Awaitable<T> = T | Promise<T>;
|
|
29
48
|
interface ComponentInstallerPlugin {
|
|
30
49
|
/**
|
|
31
|
-
* transform file
|
|
50
|
+
* transform file before writing (before default transformation)
|
|
32
51
|
*/
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
52
|
+
beforeTransform?: (context: TransformContext) => Awaitable<void>;
|
|
53
|
+
/**
|
|
54
|
+
* transform file before writing (after default transformation)
|
|
55
|
+
*/
|
|
56
|
+
afterTransform?: (context: TransformContext) => Awaitable<void>;
|
|
57
|
+
/**
|
|
58
|
+
* transform component before install
|
|
59
|
+
*/
|
|
60
|
+
beforeInstall?: (comp: DownloadedComponent, context: InstallContext & PluginContext) => Awaitable<DownloadedComponent | undefined>;
|
|
61
|
+
beforeDownload?: (context: PluginContext & {
|
|
62
|
+
name: string;
|
|
63
|
+
}) => void | Promise<void>;
|
|
64
|
+
afterDownload?: (context: PluginContext & {
|
|
65
|
+
name: string;
|
|
66
|
+
result: DownloadedComponent;
|
|
38
67
|
}) => void | Promise<void>;
|
|
39
68
|
}
|
|
40
69
|
interface IOInterface {
|
|
@@ -45,7 +74,7 @@ interface IOInterface {
|
|
|
45
74
|
onFileDownloaded: (options: {
|
|
46
75
|
path: string;
|
|
47
76
|
file: File;
|
|
48
|
-
component:
|
|
77
|
+
component: Component;
|
|
49
78
|
}) => void;
|
|
50
79
|
}
|
|
51
80
|
interface ComponentInstallerOptions {
|
|
@@ -61,14 +90,14 @@ declare class ComponentInstaller {
|
|
|
61
90
|
readonly dependencies: Record<string, string | null>;
|
|
62
91
|
readonly devDependencies: Record<string, string | null>;
|
|
63
92
|
constructor(rootClient: RegistryClient, options?: ComponentInstallerOptions);
|
|
93
|
+
private installComponent;
|
|
64
94
|
install(name: string, io: IOInterface): Promise<void>;
|
|
65
95
|
deps(): Promise<DependencyManager>;
|
|
66
96
|
onEnd(): Promise<void>;
|
|
67
97
|
/**
|
|
68
|
-
*
|
|
98
|
+
* download component & its sub components
|
|
69
99
|
*/
|
|
70
100
|
private download;
|
|
71
|
-
private readonly pathToFileCache;
|
|
72
101
|
private transform;
|
|
73
102
|
private resolveOutputPath;
|
|
74
103
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/utils/get-package-manager.ts","../../../src/registry/installer/dep-manager.ts","../../../src/registry/installer/index.ts"],"mappings":";;;;;;;KAEY,cAAA,GAAiB,SAAA;;;cCQhB,iBAAA;EAAA,iBAMkB,GAAA;EAAA,QALrB,aAAA;EACR,YAAA;EACA,eAAA;EACA,cAAA,EAAgB,cAAA;cAEa,GAAA;EAEvB,IAAA,CAAK,IAAA,EAAM,MAAA,yBAA+B,OAAA,EAAS,MAAA,0BAA6B,OAAA;EAAA,QAyB9E,2BAAA;EAMR,WAAA,CAAA;EAIM,aAAA,CAAA,GAAa,OAAA;EAuBb,eAAA,CAAA,GAAe,OAAA;AAAA;;;UChEb,mBAAA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/utils/get-package-manager.ts","../../../src/registry/installer/dep-manager.ts","../../../src/registry/installer/index.ts"],"mappings":";;;;;;;KAEY,cAAA,GAAiB,SAAA;;;cCQhB,iBAAA;EAAA,iBAMkB,GAAA;EAAA,QALrB,aAAA;EACR,YAAA;EACA,eAAA;EACA,cAAA,EAAgB,cAAA;cAEa,GAAA;EAEvB,IAAA,CAAK,IAAA,EAAM,MAAA,yBAA+B,OAAA,EAAS,MAAA,0BAA6B,OAAA;EAAA,QAyB9E,2BAAA;EAMR,WAAA,CAAA;EAIM,aAAA,CAAA,GAAa,OAAA;EAuBb,eAAA,CAAA,GAAe,OAAA;AAAA;;;UChEb,aAAA;EACR,SAAA,EAAW,kBAAA;AAAA;AAAA,UAGH,gBAAA,SAAyB,aAAA,EAAe,cAAA;EAChD,CAAA,EAAG,WAAA;EACH,MAAA,EAAQ,WAAA;EACR,IAAA,EAAM,IAAA;EACN,SAAA,EAAW,mBAAA;AAAA;AAAA,UAGH,cAAA;EACR,UAAA,EAAY,GAAA,SAAY,IAAA;EACxB,EAAA,EAAI,WAAA;EDfwB;ECiB5B,UAAA,EAAY,MAAA;EDbI;ECehB,KAAA,EAAO,mBAAA;AAAA;AAAA,UAGC,mBAAA,SAA4B,SAAA;EACpC,cAAA,EAAgB,mBAAA;EAChB,SAAA,EAAW,cAAA;AAAA;AAAA,KAGR,SAAA,MAAe,CAAA,GAAI,OAAA,CAAQ,CAAA;AAAA,UAEf,wBAAA;ED5BP;;;ECgCR,eAAA,IAAmB,OAAA,EAAS,gBAAA,KAAqB,SAAA;ED7BjC;;;ECkChB,cAAA,IAAkB,OAAA,EAAS,gBAAA,KAAqB,SAAA;ED9B/B;;;ECmCjB,aAAA,IACE,IAAA,EAAM,mBAAA,EACN,OAAA,EAAS,cAAA,GAAiB,aAAA,KACvB,SAAA,CAAU,mBAAA;EAEf,cAAA,IACE,OAAA,EAAS,aAAA;IACP,IAAA;EAAA,aAEQ,OAAA;EAEZ,aAAA,IACE,OAAA,EAAS,aAAA;IACP,IAAA;IACA,MAAA,EAAQ,mBAAA;EAAA,aAEA,OAAA;AAAA;AAAA,UAGG,WAAA;EACf,MAAA,GAAS,OAAA;EACT,mBAAA,GAAsB,OAAA;IAAW,IAAA;EAAA,MAAmB,OAAA;EACpD,gBAAA,GAAmB,OAAA;IAAW,IAAA;IAAc,IAAA,EAAM,IAAA;IAAM,SAAA,EAAW,SAAA;EAAA;AAAA;AAAA,UAGpD,yBAAA;EACf,OAAA,GAAU,wBAAA;EACV,GAAA;AAAA;AAAA,cAGW,kBAAA;EAAA,iBASQ,UAAA;EAAA,iBARF,cAAA;EAAA,iBACA,aAAA;EAAA,iBACA,GAAA;EAAA,iBACA,OAAA;EAAA,SACR,YAAA,EAAc,MAAA;EAAA,SACd,eAAA,EAAiB,MAAA;cAGP,UAAA,EAAY,cAAA,EAC7B,OAAA,GAAS,yBAAA;EAAA,QAMG,gBAAA;EAsDR,OAAA,CAAQ,IAAA,UAAc,EAAA,EAAI,WAAA,GAAW,OAAA;EAuCrC,IAAA,CAAA,GAAI,OAAA,CAAA,iBAAA;EAMJ,KAAA,CAAA,GAAK,OAAA;EAlLX;;;EAAA,QA4Lc,QAAA;EAAA,QAoDA,SAAA;EAAA,QA2CN,iBAAA;AAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as DownloadedRegistryInfo, c as componentSchema, d as indexSchema, f as namespaces, i as Component, l as fileSchema, n as CompiledFile, o as File, p as registryInfoSchema, r as CompiledRegistryInfo, s as NamespaceType, t as CompiledComponent, u as httpSubComponent } from "../schema-
|
|
1
|
+
import { a as DownloadedRegistryInfo, c as componentSchema, d as indexSchema, f as namespaces, i as Component, l as fileSchema, n as CompiledFile, o as File, p as registryInfoSchema, r as CompiledRegistryInfo, s as NamespaceType, t as CompiledComponent, u as httpSubComponent } from "../schema-80shuzWO.js";
|
|
2
2
|
export { CompiledComponent, CompiledFile, CompiledRegistryInfo, Component, DownloadedRegistryInfo, File, NamespaceType, componentSchema, fileSchema, httpSubComponent, indexSchema, namespaces, registryInfoSchema };
|
package/dist/registry/schema.js
CHANGED
|
@@ -6,7 +6,7 @@ const namespaces = [
|
|
|
6
6
|
"css",
|
|
7
7
|
"route",
|
|
8
8
|
"ui",
|
|
9
|
-
"
|
|
9
|
+
"layout"
|
|
10
10
|
];
|
|
11
11
|
const indexSchema = z.object({
|
|
12
12
|
name: z.string(),
|
|
@@ -31,13 +31,11 @@ const componentSchema = z.object({
|
|
|
31
31
|
files: z.array(fileSchema),
|
|
32
32
|
dependencies: z.record(z.string(), z.string().or(z.null())),
|
|
33
33
|
devDependencies: z.record(z.string(), z.string().or(z.null())),
|
|
34
|
-
subComponents: z.array(z.string().or(httpSubComponent)).default([])
|
|
34
|
+
subComponents: z.array(z.string().or(httpSubComponent)).default([]),
|
|
35
|
+
variables: z.record(z.string(), z.unknown()).optional()
|
|
35
36
|
});
|
|
36
37
|
const registryInfoSchema = z.object({
|
|
37
|
-
variables: z.record(z.string(), z.object({
|
|
38
|
-
description: z.string().optional(),
|
|
39
|
-
default: z.unknown().optional()
|
|
40
|
-
})).optional(),
|
|
38
|
+
variables: z.record(z.string(), z.object({ description: z.string().optional() })).optional(),
|
|
41
39
|
env: z.record(z.string(), z.unknown()).optional(),
|
|
42
40
|
indexes: z.array(indexSchema).default([]),
|
|
43
41
|
registries: z.array(z.string()).optional()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","names":[],"sources":["../../src/registry/schema.ts"],"sourcesContent":["import { z } from 'zod';\n\nexport type NamespaceType = (typeof namespaces)[number];\nexport type CompiledFile = z.input<typeof fileSchema>;\nexport type CompiledComponent = z.input<typeof componentSchema>;\nexport type CompiledRegistryInfo = z.input<typeof registryInfoSchema>;\nexport type DownloadedRegistryInfo = z.output<typeof registryInfoSchema>;\nexport type File = z.output<typeof fileSchema>;\nexport type Component = z.output<typeof componentSchema>;\n\nexport const namespaces = ['components', 'lib', 'css', 'route', 'ui', '
|
|
1
|
+
{"version":3,"file":"schema.js","names":[],"sources":["../../src/registry/schema.ts"],"sourcesContent":["import { z } from 'zod';\n\nexport type NamespaceType = (typeof namespaces)[number];\nexport type CompiledFile = z.input<typeof fileSchema>;\nexport type CompiledComponent = z.input<typeof componentSchema>;\nexport type CompiledRegistryInfo = z.input<typeof registryInfoSchema>;\nexport type DownloadedRegistryInfo = z.output<typeof registryInfoSchema>;\nexport type File = z.output<typeof fileSchema>;\nexport type Component = z.output<typeof componentSchema>;\n\nexport const namespaces = ['components', 'lib', 'css', 'route', 'ui', 'layout'] as const;\n\nexport const indexSchema = z.object({\n name: z.string(),\n title: z.string().optional(),\n description: z.string().optional(),\n});\n\nexport const fileSchema = z.object({\n type: z.literal(namespaces),\n path: z.string(),\n target: z.string().optional(),\n content: z.string(),\n});\n\nexport const httpSubComponent = z.object({\n type: z.literal('http'),\n baseUrl: z.string(),\n component: z.string(),\n});\n\nexport const componentSchema = z.object({\n name: z.string(),\n title: z.string().optional(),\n description: z.string().optional(),\n files: z.array(fileSchema),\n dependencies: z.record(z.string(), z.string().or(z.null())),\n devDependencies: z.record(z.string(), z.string().or(z.null())),\n /**\n * list of sub components, either local (component name) or remote (registry info & component name)\n */\n subComponents: z.array(z.string().or(httpSubComponent)).default([]),\n\n /**\n * override variables for the current component & its sub components.\n *\n * this is powerful to customise how sub components are installed vs. installing them directly.\n */\n variables: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport const registryInfoSchema = z.object({\n /**\n * define metadata for variables, variables can be referenced in the target path of component files, or in plugins.\n */\n variables: z\n .record(\n z.string(),\n z.object({\n description: z.string().optional(),\n }),\n )\n .optional(),\n /**\n * override variables for all components.\n */\n env: z.record(z.string(), z.unknown()).optional(),\n indexes: z.array(indexSchema).default([]),\n\n registries: z.array(z.string()).optional(),\n});\n"],"mappings":";;AAUA,MAAa,aAAa;CAAC;CAAc;CAAO;CAAO;CAAS;CAAM;CAAS;AAE/E,MAAa,cAAc,EAAE,OAAO;CAClC,MAAM,EAAE,QAAQ;CAChB,OAAO,EAAE,QAAQ,CAAC,UAAU;CAC5B,aAAa,EAAE,QAAQ,CAAC,UAAU;CACnC,CAAC;AAEF,MAAa,aAAa,EAAE,OAAO;CACjC,MAAM,EAAE,QAAQ,WAAW;CAC3B,MAAM,EAAE,QAAQ;CAChB,QAAQ,EAAE,QAAQ,CAAC,UAAU;CAC7B,SAAS,EAAE,QAAQ;CACpB,CAAC;AAEF,MAAa,mBAAmB,EAAE,OAAO;CACvC,MAAM,EAAE,QAAQ,OAAO;CACvB,SAAS,EAAE,QAAQ;CACnB,WAAW,EAAE,QAAQ;CACtB,CAAC;AAEF,MAAa,kBAAkB,EAAE,OAAO;CACtC,MAAM,EAAE,QAAQ;CAChB,OAAO,EAAE,QAAQ,CAAC,UAAU;CAC5B,aAAa,EAAE,QAAQ,CAAC,UAAU;CAClC,OAAO,EAAE,MAAM,WAAW;CAC1B,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;CAC3D,iBAAiB,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;CAI9D,eAAe,EAAE,MAAM,EAAE,QAAQ,CAAC,GAAG,iBAAiB,CAAC,CAAC,QAAQ,EAAE,CAAC;CAOnE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC,UAAU;CACxD,CAAC;AAEF,MAAa,qBAAqB,EAAE,OAAO;CAIzC,WAAW,EACR,OACC,EAAE,QAAQ,EACV,EAAE,OAAO,EACP,aAAa,EAAE,QAAQ,CAAC,UAAU,EACnC,CAAC,CACH,CACA,UAAU;CAIb,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC,UAAU;CACjD,SAAS,EAAE,MAAM,YAAY,CAAC,QAAQ,EAAE,CAAC;CAEzC,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU;CAC3C,CAAC"}
|
package/dist/schema/default.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"$schema":{"default":"node_modules/@fumadocs/cli/dist/schema/default.json","type":"string"},"aliases":{"default":{"uiDir":"./components/ui","componentsDir":"./components","
|
|
1
|
+
{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"$schema":{"default":"node_modules/@fumadocs/cli/dist/schema/default.json","type":"string"},"aliases":{"default":{"uiDir":"./components/ui","componentsDir":"./components","layoutDir":"./layouts","cssDir":"./styles","libDir":"./lib"},"type":"object","properties":{"uiDir":{"default":"./components/ui","type":"string"},"componentsDir":{"default":"./components/ui","type":"string"},"layoutDir":{"default":"./layouts","type":"string"},"cssDir":{"default":"./components","type":"string"},"libDir":{"default":"./lib","type":"string"}}},"baseDir":{"default":"","type":"string"},"uiLibrary":{"default":"radix-ui","type":"string","enum":["radix-ui","base-ui"]},"commands":{"default":{},"type":"object","properties":{"format":{"type":"string"}}}}}
|
package/dist/schema/src.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"$schema":{"default":"node_modules/@fumadocs/cli/dist/schema/src.json","type":"string"},"aliases":{"default":{"uiDir":"./components/ui","componentsDir":"./components","
|
|
1
|
+
{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"$schema":{"default":"node_modules/@fumadocs/cli/dist/schema/src.json","type":"string"},"aliases":{"default":{"uiDir":"./components/ui","componentsDir":"./components","layoutDir":"./layouts","cssDir":"./styles","libDir":"./lib"},"type":"object","properties":{"uiDir":{"default":"./components/ui","type":"string"},"componentsDir":{"default":"./components/ui","type":"string"},"layoutDir":{"default":"./layouts","type":"string"},"cssDir":{"default":"./components","type":"string"},"libDir":{"default":"./lib","type":"string"}}},"baseDir":{"default":"src","type":"string"},"uiLibrary":{"default":"radix-ui","type":"string","enum":["radix-ui","base-ui"]},"commands":{"default":{},"type":"object","properties":{"format":{"type":"string"}}}}}
|
|
@@ -8,14 +8,14 @@ type CompiledRegistryInfo = z.input<typeof registryInfoSchema>;
|
|
|
8
8
|
type DownloadedRegistryInfo = z.output<typeof registryInfoSchema>;
|
|
9
9
|
type File = z.output<typeof fileSchema>;
|
|
10
10
|
type Component = z.output<typeof componentSchema>;
|
|
11
|
-
declare const namespaces: readonly ["components", "lib", "css", "route", "ui", "
|
|
11
|
+
declare const namespaces: readonly ["components", "lib", "css", "route", "ui", "layout"];
|
|
12
12
|
declare const indexSchema: z.ZodObject<{
|
|
13
13
|
name: z.ZodString;
|
|
14
14
|
title: z.ZodOptional<z.ZodString>;
|
|
15
15
|
description: z.ZodOptional<z.ZodString>;
|
|
16
16
|
}, z.core.$strip>;
|
|
17
17
|
declare const fileSchema: z.ZodObject<{
|
|
18
|
-
type: z.ZodLiteral<"components" | "lib" | "css" | "route" | "ui" | "
|
|
18
|
+
type: z.ZodLiteral<"components" | "lib" | "css" | "route" | "ui" | "layout">;
|
|
19
19
|
path: z.ZodString;
|
|
20
20
|
target: z.ZodOptional<z.ZodString>;
|
|
21
21
|
content: z.ZodString;
|
|
@@ -30,7 +30,7 @@ declare const componentSchema: z.ZodObject<{
|
|
|
30
30
|
title: z.ZodOptional<z.ZodString>;
|
|
31
31
|
description: z.ZodOptional<z.ZodString>;
|
|
32
32
|
files: z.ZodArray<z.ZodObject<{
|
|
33
|
-
type: z.ZodLiteral<"components" | "lib" | "css" | "route" | "ui" | "
|
|
33
|
+
type: z.ZodLiteral<"components" | "lib" | "css" | "route" | "ui" | "layout">;
|
|
34
34
|
path: z.ZodString;
|
|
35
35
|
target: z.ZodOptional<z.ZodString>;
|
|
36
36
|
content: z.ZodString;
|
|
@@ -42,11 +42,11 @@ declare const componentSchema: z.ZodObject<{
|
|
|
42
42
|
baseUrl: z.ZodString;
|
|
43
43
|
component: z.ZodString;
|
|
44
44
|
}, z.core.$strip>]>>>;
|
|
45
|
+
variables: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
45
46
|
}, z.core.$strip>;
|
|
46
47
|
declare const registryInfoSchema: z.ZodObject<{
|
|
47
48
|
variables: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
48
49
|
description: z.ZodOptional<z.ZodString>;
|
|
49
|
-
default: z.ZodOptional<z.ZodUnknown>;
|
|
50
50
|
}, z.core.$strip>>>;
|
|
51
51
|
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
52
52
|
indexes: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
@@ -58,4 +58,4 @@ declare const registryInfoSchema: z.ZodObject<{
|
|
|
58
58
|
}, z.core.$strip>;
|
|
59
59
|
//#endregion
|
|
60
60
|
export { DownloadedRegistryInfo as a, componentSchema as c, indexSchema as d, namespaces as f, Component as i, fileSchema as l, CompiledFile as n, File as o, registryInfoSchema as p, CompiledRegistryInfo as r, NamespaceType as s, CompiledComponent as t, httpSubComponent as u };
|
|
61
|
-
//# sourceMappingURL=schema-
|
|
61
|
+
//# sourceMappingURL=schema-80shuzWO.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-
|
|
1
|
+
{"version":3,"file":"schema-80shuzWO.d.ts","names":[],"sources":["../src/registry/schema.ts"],"mappings":";;;KAEY,aAAA,WAAwB,UAAA;AAAA,KACxB,YAAA,GAAe,CAAA,CAAE,KAAA,QAAa,UAAA;AAAA,KAC9B,iBAAA,GAAoB,CAAA,CAAE,KAAA,QAAa,eAAA;AAAA,KACnC,oBAAA,GAAuB,CAAA,CAAE,KAAA,QAAa,kBAAA;AAAA,KACtC,sBAAA,GAAyB,CAAA,CAAE,MAAA,QAAc,kBAAA;AAAA,KACzC,IAAA,GAAO,CAAA,CAAE,MAAA,QAAc,UAAA;AAAA,KACvB,SAAA,GAAY,CAAA,CAAE,MAAA,QAAc,eAAA;AAAA,cAE3B,UAAA;AAAA,cAEA,WAAA,EAAW,CAAA,CAAA,SAAA;;;;;cAMX,UAAA,EAAU,CAAA,CAAA,SAAA;;;;;;cAOV,gBAAA,EAAgB,CAAA,CAAA,SAAA;;;;;cAMhB,eAAA,EAAe,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;cAoBf,kBAAA,EAAkB,CAAA,CAAA,SAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fumadocs/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "The CLI tool for Fumadocs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Docs",
|
|
@@ -32,18 +32,18 @@
|
|
|
32
32
|
"@clack/prompts": "^1.1.0",
|
|
33
33
|
"commander": "^14.0.3",
|
|
34
34
|
"magic-string": "^0.30.21",
|
|
35
|
-
"oxc-parser": "^0.
|
|
35
|
+
"oxc-parser": "^0.121.0",
|
|
36
36
|
"oxc-resolver": "^11.19.1",
|
|
37
37
|
"package-manager-detector": "^1.6.0",
|
|
38
38
|
"picocolors": "^1.1.1",
|
|
39
|
-
"tinyexec": "^1.0.
|
|
39
|
+
"tinyexec": "^1.0.4",
|
|
40
40
|
"zod": "^4.3.6"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@oxc-project/types": "^0.
|
|
44
|
-
"@types/node": "25.
|
|
45
|
-
"shadcn": "4.0.
|
|
46
|
-
"tsdown": "0.21.
|
|
43
|
+
"@oxc-project/types": "^0.121.0",
|
|
44
|
+
"@types/node": "25.5.0",
|
|
45
|
+
"shadcn": "4.0.8",
|
|
46
|
+
"tsdown": "0.21.4",
|
|
47
47
|
"eslint-config-custom": "0.0.0",
|
|
48
48
|
"tsconfig": "0.0.0"
|
|
49
49
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"installer-DQzu7o9x.js","names":[],"sources":["../src/utils/get-package-manager.ts","../src/registry/installer/dep-manager.ts","../src/registry/installer/index.ts"],"sourcesContent":["import { detect, type AgentName } from 'package-manager-detector';\n\nexport type PackageManager = AgentName;\n\nexport async function getPackageManager(): Promise<PackageManager> {\n const result = await detect();\n\n return result?.name ?? 'npm';\n}\n","import fs from 'node:fs/promises';\nimport { getPackageManager, PackageManager } from '@/utils/get-package-manager';\nimport { x } from 'tinyexec';\nimport path from 'node:path';\n\ninterface PackageJsonType {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nexport class DependencyManager {\n private installedDeps = new Map<string, string>();\n dependencies: string[] = [];\n devDependencies: string[] = [];\n packageManager: PackageManager = 'npm';\n\n constructor(private readonly cwd: string) {}\n\n async init(deps: Record<string, string | null>, devDeps: Record<string, string | null>) {\n this.installedDeps.clear();\n const packageJsonPath = path.join(this.cwd, 'package.json');\n const content = await fs\n .readFile(packageJsonPath)\n .then((res) => res.toString())\n .catch(() => null);\n\n if (content !== null) {\n const parsed = JSON.parse(content) as PackageJsonType;\n\n for (const [k, v] of Object.entries(parsed?.dependencies ?? {})) {\n this.installedDeps.set(k, v);\n }\n\n for (const [k, v] of Object.entries(parsed?.devDependencies ?? {})) {\n this.installedDeps.set(k, v);\n }\n }\n\n this.dependencies = this.resolveRequiredDependencies(deps);\n this.devDependencies = this.resolveRequiredDependencies(devDeps);\n this.packageManager = await getPackageManager();\n }\n\n private resolveRequiredDependencies(deps: Record<string, string | null>): string[] {\n return Object.entries(deps)\n .filter(([k]) => !this.installedDeps.has(k))\n .map(([k, v]) => (v === null || v.length === 0 ? k : `${k}@${v}`));\n }\n\n hasRequired() {\n return this.dependencies.length > 0 || this.devDependencies.length > 0;\n }\n\n async writeRequired() {\n const packageJsonPath = path.join(this.cwd, 'package.json');\n const content = await fs.readFile(packageJsonPath).catch(() => null);\n if (content === null) return false;\n\n const parsed = JSON.parse(content.toString()) as PackageJsonType;\n if (!parsed) return false;\n\n for (const dep of this.dependencies) {\n const { name, version } = parseDep(dep);\n parsed.dependencies ??= {};\n parsed.dependencies[name] ??= version;\n }\n\n for (const dep of this.devDependencies) {\n const { name, version } = parseDep(dep);\n parsed.devDependencies ??= {};\n parsed.devDependencies[name] ??= version;\n }\n\n await fs.writeFile(packageJsonPath, JSON.stringify(parsed, null, 2));\n }\n\n async installRequired() {\n if (this.dependencies.length > 0)\n await x(this.packageManager, ['install', ...this.dependencies]);\n if (this.devDependencies.length > 0)\n await x(this.packageManager, ['install', ...this.devDependencies, '-D']);\n }\n}\n\nfunction parseDep(dep: string) {\n const idx = dep.indexOf('@', 1);\n if (idx === -1) {\n return { name: dep, version: 'latest' };\n } else {\n return { name: dep.slice(0, idx), version: dep.slice(idx + 1) };\n }\n}\n","import path from 'node:path';\nimport fs from 'node:fs/promises';\nimport { typescriptExtensions } from '@/constants';\nimport { toImportSpecifier, transformSpecifiers } from '@/utils/ast';\nimport type { Component, File } from '@/registry/schema';\nimport { HttpRegistryClient, type RegistryClient } from '@/registry/client';\nimport { x } from 'tinyexec';\nimport { DependencyManager } from '@/registry/installer/dep-manager';\nimport { createCache } from '@/utils/cache';\nimport { parse, type ParseResult } from 'oxc-parser';\nimport MagicString from 'magic-string';\n\ninterface DownloadedComponent extends Omit<Component, 'subComponents'> {\n variables?: Record<string, unknown>;\n}\n\nexport interface ComponentInstallerPlugin {\n /**\n * transform file downloaded from components\n */\n transformFile?: (context: {\n s: MagicString;\n parsed: ParseResult;\n\n file: File;\n component: DownloadedComponent;\n }) => void | Promise<void>;\n}\n\nexport interface IOInterface {\n onWarn: (message: string) => void;\n confirmFileOverride: (options: { path: string }) => Promise<boolean>;\n onFileDownloaded: (options: { path: string; file: File; component: DownloadedComponent }) => void;\n}\n\nexport interface ComponentInstallerOptions {\n plugins?: ComponentInstallerPlugin[];\n cwd?: string;\n}\n\nexport class ComponentInstaller {\n private readonly installedFiles = new Set<string>();\n private readonly downloadCache = createCache<DownloadedComponent[]>();\n private readonly cwd: string;\n private readonly plugins: ComponentInstallerPlugin[];\n readonly dependencies: Record<string, string | null> = {};\n readonly devDependencies: Record<string, string | null> = {};\n\n constructor(\n private readonly rootClient: RegistryClient,\n options: ComponentInstallerOptions = {},\n ) {\n this.cwd = options.cwd ?? process.cwd();\n this.plugins = options.plugins ?? [];\n }\n\n async install(name: string, io: IOInterface) {\n let downloaded: DownloadedComponent[];\n // detect linked registry\n const info = await this.rootClient.fetchRegistryInfo();\n\n for (const registry of info.registries ?? []) {\n if (name.startsWith(`${registry}/`)) {\n downloaded = await this.download(\n name.slice(registry.length + 1),\n this.rootClient.createLinkedRegistryClient(registry),\n );\n break;\n }\n }\n\n downloaded ??= await this.download(name, this.rootClient);\n\n for (const item of downloaded) {\n Object.assign(this.dependencies, item.dependencies);\n Object.assign(this.devDependencies, item.devDependencies);\n }\n\n for (const comp of downloaded) {\n for (const file of comp.files) {\n const outPath = this.resolveOutputPath(file);\n if (this.installedFiles.has(outPath)) continue;\n this.installedFiles.add(outPath);\n\n const output = typescriptExtensions.includes(path.extname(outPath))\n ? await this.transform(io, name, file, comp, downloaded)\n : file.content;\n\n const status = await fs\n .readFile(outPath)\n .then((res) => {\n if (res.toString().trim() === output.trim()) return 'ignore';\n return 'need-update';\n })\n .catch(() => 'write');\n\n if (status === 'ignore') continue;\n\n if (status === 'need-update') {\n const override = await io.confirmFileOverride({ path: outPath });\n if (!override) continue;\n }\n\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, output);\n io.onFileDownloaded({ path: outPath, file, component: comp });\n }\n }\n }\n\n async deps() {\n const manager = new DependencyManager(this.cwd);\n await manager.init(this.dependencies, this.devDependencies);\n return manager;\n }\n\n async onEnd() {\n const config = this.rootClient.config;\n if (config.commands.format) {\n await x(config.commands.format);\n }\n }\n\n /**\n * return a list of components, merged with child components & variables.\n */\n private async download(\n name: string,\n client: RegistryClient,\n contextVariables?: Record<string, unknown>,\n ): Promise<DownloadedComponent[]> {\n const hash = `${client.registryId} ${name}`;\n const info = await client.fetchRegistryInfo();\n const variables = { ...contextVariables, ...info.env };\n for (const [k, v] of Object.entries(info.variables ?? {})) {\n variables[k] ??= v.default;\n }\n\n const out = await this.downloadCache.cached(hash, async (presolve) => {\n const comp = await client.fetchComponent(name);\n const result: DownloadedComponent[] = [comp];\n // place it before downloading child components to avoid recursive downloads\n presolve(result);\n\n const child = await Promise.all(\n comp.subComponents.map((sub) => {\n if (typeof sub === 'string') return this.download(sub, client);\n const baseUrl =\n this.rootClient instanceof HttpRegistryClient\n ? new URL(sub.baseUrl, `${this.rootClient.baseUrl}/`).href\n : sub.baseUrl;\n\n return this.download(\n sub.component,\n new HttpRegistryClient(baseUrl, client.config),\n variables,\n );\n }),\n );\n for (const sub of child) result.push(...sub);\n return result;\n });\n\n return out.map((file) => ({ ...file, variables }));\n }\n\n private readonly pathToFileCache = createCache<Map<string, File>>();\n private async transform(\n io: IOInterface,\n taskId: string,\n file: File,\n component: DownloadedComponent,\n allComponents: DownloadedComponent[],\n ): Promise<string> {\n const filePath = this.resolveOutputPath(file);\n const parsed = await parse(filePath, file.content);\n const s = new MagicString(file.content);\n\n // transform alias\n const prefix = '@/';\n const variables = Object.entries(component.variables ?? {});\n const pathToFile = await this.pathToFileCache.cached(taskId, () => {\n const map = new Map<string, File>();\n for (const comp of allComponents) {\n for (const file of comp.files) map.set(file.target ?? file.path, file);\n }\n return map;\n });\n\n transformSpecifiers(parsed.program, s, (specifier) => {\n for (const [k, v] of variables) {\n specifier = specifier.replaceAll(`<${k}>`, v as string);\n }\n\n if (specifier.startsWith(prefix)) {\n const lookup = specifier.substring(prefix.length);\n const target = pathToFile.get(lookup);\n\n if (target) {\n specifier = toImportSpecifier(filePath, this.resolveOutputPath(target));\n } else {\n io.onWarn(`cannot find the referenced file of ${specifier}`);\n }\n }\n\n return specifier;\n });\n\n for (const plugin of this.plugins) {\n await plugin.transformFile?.({\n s,\n parsed,\n file,\n component,\n });\n }\n\n return s.toString();\n }\n\n private resolveOutputPath(file: File): string {\n const config = this.rootClient.config;\n const dir = (\n {\n components: config.aliases.componentsDir,\n block: config.aliases.blockDir,\n ui: config.aliases.uiDir,\n css: config.aliases.cssDir,\n lib: config.aliases.libDir,\n route: './',\n } as const\n )[file.type];\n if (file.target) {\n return path.resolve(this.cwd, config.baseDir, file.target.replace('<dir>', dir));\n }\n\n return path.resolve(this.cwd, config.baseDir, dir, path.basename(file.path));\n }\n}\n"],"mappings":"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"}
|