@fumadocs/cli 1.6.0 → 1.6.2

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.
Files changed (72) hide show
  1. package/dist/{ai-BVuNjYXU.js → ai-C19ZOP53.js} +2 -2
  2. package/dist/{ai-BVuNjYXU.js.map → ai-C19ZOP53.js.map} +1 -1
  3. package/dist/all-BBf7I8hG.js +27 -0
  4. package/dist/{all-aUHxtoXL.js.map → all-BBf7I8hG.js.map} +1 -1
  5. package/dist/{config-CT2jj39D.d.ts → config-Bfg4yG8S.d.ts} +3 -1
  6. package/dist/config-Bfg4yG8S.d.ts.map +1 -0
  7. package/dist/{config-D6uv73fs.js → config-Bw0kmF01.js} +6 -3
  8. package/dist/config-Bw0kmF01.js.map +1 -0
  9. package/dist/config.d.ts +1 -1
  10. package/dist/config.js +1 -1
  11. package/dist/{docs-DeIEl_Kt.js → docs--WqEHTyl.js} +2 -2
  12. package/dist/{docs-DeIEl_Kt.js.map → docs--WqEHTyl.js.map} +1 -1
  13. package/dist/{epub-CnQFJh09.js → epub-jc_2B886.js} +2 -2
  14. package/dist/{epub-CnQFJh09.js.map → epub-jc_2B886.js.map} +1 -1
  15. package/dist/features/ai.d.ts +1 -1
  16. package/dist/features/ai.js +1 -1
  17. package/dist/features/all.d.ts +1 -1
  18. package/dist/features/all.js +1 -1
  19. package/dist/features/docs/index.d.ts +2 -2
  20. package/dist/features/docs/index.js +1 -1
  21. package/dist/features/epub.d.ts +1 -1
  22. package/dist/features/epub.js +1 -1
  23. package/dist/features/feedback.d.ts +1 -1
  24. package/dist/features/feedback.js +1 -1
  25. package/dist/features/index.d.ts +1 -1
  26. package/dist/features/index.js +1 -1
  27. package/dist/features/lint.d.ts +1 -1
  28. package/dist/features/llms.d.ts +3 -3
  29. package/dist/features/llms.js +1 -1
  30. package/dist/features/mcp.d.ts +3 -3
  31. package/dist/features/mcp.js +1 -1
  32. package/dist/features/og.d.ts +1 -1
  33. package/dist/features/og.js +1 -1
  34. package/dist/features/search.d.ts +2 -2
  35. package/dist/features/search.js +1 -1
  36. package/dist/features/utils.d.ts +1 -1
  37. package/dist/features/webmcp.d.ts +1 -1
  38. package/dist/features/webmcp.js +1 -1
  39. package/dist/{features-C1kf2s8j.js → features-CXFCgOWD.js} +3 -3
  40. package/dist/{features-C1kf2s8j.js.map → features-CXFCgOWD.js.map} +1 -1
  41. package/dist/{feedback-COmWtc5C.js → feedback-Brj092vC.js} +2 -2
  42. package/dist/{feedback-COmWtc5C.js.map → feedback-Brj092vC.js.map} +1 -1
  43. package/dist/{index-CR9T40ox.d.ts → index-Cs7hw2un.d.ts} +2 -2
  44. package/dist/{index-CR9T40ox.d.ts.map → index-Cs7hw2un.d.ts.map} +1 -1
  45. package/dist/{index-BCVGQxn9.d.ts → index-DI66DoV8.d.ts} +2 -2
  46. package/dist/{index-BCVGQxn9.d.ts.map → index-DI66DoV8.d.ts.map} +1 -1
  47. package/dist/index.js +43 -36
  48. package/dist/index.js.map +1 -1
  49. package/dist/{installer-D0Obb2Md.js → installer-CzhVfs7i.js} +67 -4
  50. package/dist/installer-CzhVfs7i.js.map +1 -0
  51. package/dist/{llms-CONd8Vnn.js → llms-Br0RJXXg.js} +2 -2
  52. package/dist/{llms-CONd8Vnn.js.map → llms-Br0RJXXg.js.map} +1 -1
  53. package/dist/{mcp-BT8BLZZ-.js → mcp-Ce_W93we.js} +3 -3
  54. package/dist/{mcp-BT8BLZZ-.js.map → mcp-Ce_W93we.js.map} +1 -1
  55. package/dist/{og-DRDOyQ_t.js → og-LFlX1Bl4.js} +3 -3
  56. package/dist/{og-DRDOyQ_t.js.map → og-LFlX1Bl4.js.map} +1 -1
  57. package/dist/project/index.d.ts +1 -1
  58. package/dist/registry/installer.d.ts +1 -1
  59. package/dist/registry/installer.d.ts.map +1 -1
  60. package/dist/registry/installer.js +1 -1
  61. package/dist/schema.json +1 -1
  62. package/dist/{search-iphnSVVY.js → search-WfSdiGx-.js} +2 -2
  63. package/dist/{search-iphnSVVY.js.map → search-WfSdiGx-.js.map} +1 -1
  64. package/dist/{utils-B1Xy4l_a.d.ts → utils-CxJ7kw39.d.ts} +3 -3
  65. package/dist/{utils-B1Xy4l_a.d.ts.map → utils-CxJ7kw39.d.ts.map} +1 -1
  66. package/dist/{webmcp-C2PM_9md.js → webmcp-DyTLrsXL.js} +2 -2
  67. package/dist/{webmcp-C2PM_9md.js.map → webmcp-DyTLrsXL.js.map} +1 -1
  68. package/package.json +9 -8
  69. package/dist/all-aUHxtoXL.js +0 -27
  70. package/dist/config-CT2jj39D.d.ts.map +0 -1
  71. package/dist/config-D6uv73fs.js.map +0 -1
  72. package/dist/installer-D0Obb2Md.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { r as Feature } from "../index-CR9T40ox.js";
1
+ import { r as Feature } from "../index-Cs7hw2un.js";
2
2
  //#region src/features/webmcp.d.ts
3
3
  interface Input {
4
4
  static: boolean;
@@ -1,2 +1,2 @@
1
- import { n as webmcp, t as component } from "../webmcp-C2PM_9md.js";
1
+ import { n as webmcp, t as component } from "../webmcp-DyTLrsXL.js";
2
2
  export { component, webmcp };
@@ -1,6 +1,6 @@
1
- import { t as FumadocsComponentInstaller } from "./installer-D0Obb2Md.js";
2
- import { t as exists } from "./fs-D6J9dOEx.js";
3
1
  import { g as createSourceFile } from "./codemod-auol-p4R.js";
2
+ import { t as exists } from "./fs-D6J9dOEx.js";
3
+ import { t as FumadocsComponentInstaller } from "./installer-CzhVfs7i.js";
4
4
  import fs from "node:fs/promises";
5
5
  import path from "node:path";
6
6
  import { x } from "tinyexec";
@@ -129,4 +129,4 @@ async function installDependencies(project, deps, devDeps, io, versions = {}) {
129
129
  //#endregion
130
130
  export { runFeature as t };
131
131
 
132
- //# sourceMappingURL=features-C1kf2s8j.js.map
132
+ //# sourceMappingURL=features-CXFCgOWD.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"features-C1kf2s8j.js","names":[],"sources":["../src/features/index.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { x } from 'tinyexec';\nimport type { RegistryConnector } from 'fuma-cli/registry/connector';\nimport type { Project } from '@/project';\nimport { createSourceFile, type SourceFile } from '@/codemod';\nimport { FumadocsComponentInstaller } from '@/registry/installer';\nimport { exists } from '@/utils/fs';\n\nexport interface SelectOption<T> {\n message: string;\n choices: { value: T; label: string; hint?: string }[];\n}\n\nexport interface ConfirmOption {\n message: string;\n initialValue?: boolean;\n}\n\nexport type FeatureOption<T> = [T] extends [boolean] ? ConfirmOption : SelectOption<T>;\n\nexport interface Feature<Options extends object = Record<never, never>> {\n id: string;\n title: string;\n description: string;\n options?: { [K in keyof Options]: FeatureOption<Options[K]> };\n /** features that must be applied first */\n requires?: AnyFeature[];\n /** whether the feature is already applied to the project */\n detect?: (project: Project) => Promise<boolean>;\n /** @returns `true` if supported, otherwise the reason */\n supports?: (project: Project) => true | string;\n apply(ctx: FeatureContext, options: Options): Promise<void>;\n}\n\nexport type AnyFeature = Omit<Feature<Record<string, unknown>>, 'options'> & {\n options?: Record<string, SelectOption<unknown> | ConfirmOption>;\n};\n\nexport interface PackageJson {\n scripts?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nexport interface FeatureContext {\n project: Project;\n /** write a file (relative to project root), asks before overwriting */\n write: (file: string, content: string) => Promise<void>;\n /** edit a file with codemods, `false` if the file doesn't exist */\n source: (file: string, edit: (file: SourceFile) => void) => Promise<boolean>;\n /** append lines to a text file, skip lines already present */\n append: (file: string, lines: string[]) => Promise<void>;\n remove: (file: string) => Promise<void>;\n packageJson: (edit: (data: PackageJson) => void) => Promise<void>;\n /** install a registry component */\n install: (name: string, subRegistry?: string) => Promise<void>;\n /** `null` to install the latest version */\n addDependencies: (deps: Record<string, string | null>, dev?: boolean) => void;\n env: (key: string, value: string) => void;\n /** instructions to show after the feature is applied */\n note: (text: string) => void;\n log: (message: string) => void;\n}\n\nexport interface FeatureIO {\n log: (message: string) => void;\n confirmOverwrite: (file: string) => Promise<boolean>;\n /** run package manager to install dependencies, otherwise only write them into `package.json` */\n installDependencies: boolean;\n}\n\nexport interface RunOptions {\n project: Project;\n connector: RegistryConnector;\n io: FeatureIO;\n /** preferred versions of dependencies, when a feature doesn't specify one */\n versions?: Record<string, string>;\n}\n\nexport async function runFeature<O extends object>(\n feature: Omit<Feature<O>, 'options'>,\n options: O,\n { project, connector, io, versions }: RunOptions,\n): Promise<{ notes: string[] }> {\n for (const dep of feature.requires ?? []) {\n if (dep.detect && !(await dep.detect(project)))\n throw new Error(\n `\"${feature.id}\" requires \"${dep.id}\", run \\`fumadocs feature ${dep.id}\\` first.`,\n );\n }\n const supported = feature.supports?.(project) ?? true;\n if (supported !== true) throw new Error(`\"${feature.id}\" is unavailable: ${supported}`);\n\n const { cwd } = project;\n const deps: Record<string, string | null> = {};\n const devDeps: Record<string, string | null> = {};\n const env: string[] = [];\n const notes: string[] = [];\n const installer = new FumadocsComponentInstaller(connector, project.config, cwd, {\n onWarn: io.log,\n confirmFileOverride: ({ path: file }) => io.confirmOverwrite(path.relative(cwd, file)),\n onFileDownloaded: ({ path: file }) => io.log(`installed ${path.relative(cwd, file)}`),\n });\n\n const ctx: FeatureContext = {\n project,\n log: io.log,\n note: (text) => notes.push(text),\n env: (key, value) => env.push(`${key}=${value}`),\n addDependencies(input, dev) {\n Object.assign(dev ? devDeps : deps, input);\n },\n async write(file, content) {\n const target = path.join(cwd, file);\n const current = await fs.readFile(target, 'utf-8').catch(() => null);\n if (current !== null) {\n if (current.trim() === content.trim()) return;\n if (!(await io.confirmOverwrite(file))) return;\n }\n await fs.mkdir(path.dirname(target), { recursive: true });\n await fs.writeFile(target, content);\n io.log(`${current === null ? 'created' : 'updated'} ${file}`);\n },\n async source(file, edit) {\n const target = path.join(cwd, file);\n if (!(await exists(target))) return false;\n const source = await createSourceFile(target);\n edit(source);\n if (source.s.hasChanged()) {\n await source.save();\n io.log(`updated ${file}`);\n }\n return true;\n },\n async append(file, lines) {\n const target = path.join(cwd, file);\n const current = await fs.readFile(target, 'utf-8').catch(() => '');\n const missing = lines.filter((line) => !current.includes(line));\n if (missing.length === 0) return;\n const separator = current.length === 0 || current.endsWith('\\n') ? '' : '\\n';\n await fs.mkdir(path.dirname(target), { recursive: true });\n await fs.writeFile(target, `${current}${separator}${missing.join('\\n')}\\n`);\n io.log(`updated ${file}`);\n },\n async remove(file) {\n await fs.rm(path.join(cwd, file), { force: true });\n io.log(`removed ${file}`);\n },\n async packageJson(edit) {\n const target = path.join(cwd, 'package.json');\n const data = JSON.parse(await fs.readFile(target, 'utf-8'));\n edit(data);\n await fs.writeFile(target, `${JSON.stringify(data, null, 2)}\\n`);\n io.log('updated package.json');\n },\n async install(name, subRegistry) {\n const result = await installer.install(name, subRegistry);\n const manager = await result.deps();\n // encoded as `name` or `name@version`\n const decode = (target: Record<string, string | null>, dep: string) => {\n const at = dep.indexOf('@', 1);\n if (at === -1) target[dep] = null;\n else target[dep.slice(0, at)] = dep.slice(at + 1);\n };\n for (const dep of manager.dependencies) decode(deps, dep);\n for (const dep of manager.devDependencies) decode(devDeps, dep);\n },\n };\n\n await feature.apply(ctx, options);\n\n if (env.length > 0) await ctx.append('.env.local', env);\n await installDependencies(project, deps, devDeps, io, versions);\n return { notes };\n}\n\nasync function installDependencies(\n project: Project,\n deps: Record<string, string | null>,\n devDeps: Record<string, string | null>,\n io: FeatureIO,\n versions: Record<string, string> = {},\n) {\n const { dependencies = {}, devDependencies = {} } = project.packageJson;\n const filter = (input: Record<string, string | null>) =>\n Object.entries(input).filter(([name]) => !(name in dependencies) && !(name in devDependencies));\n const missing = filter(deps);\n const missingDev = filter(devDeps);\n if (missing.length === 0 && missingDev.length === 0) return;\n\n if (io.installDependencies) {\n const pm = project.packageManager;\n const run = async (flags: string[], entries: [string, string | null][]) => {\n if (entries.length === 0) return;\n const args = [\n 'add',\n ...flags,\n ...entries.map(([name, version]) => (version ? `${name}@${version}` : name)),\n ];\n io.log(`${pm} ${args.join(' ')}`);\n await x(pm, args, {\n nodeOptions: { cwd: project.cwd, stdio: 'inherit' },\n throwOnError: true,\n });\n };\n await run([], missing);\n await run(['-D'], missingDev);\n return;\n }\n\n const file = path.join(project.cwd, 'package.json');\n const json = JSON.parse(await fs.readFile(file, 'utf-8'));\n const write = (field: string, entries: [string, string | null][]) => {\n if (entries.length === 0) return;\n const target = (json[field] ??= {});\n for (const [name, version] of entries) target[name] = version ?? versions[name] ?? 'latest';\n };\n write('dependencies', missing);\n write('devDependencies', missingDev);\n await fs.writeFile(file, `${JSON.stringify(json, null, 2)}\\n`);\n io.log('updated package.json');\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"features-CXFCgOWD.js","names":[],"sources":["../src/features/index.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { x } from 'tinyexec';\nimport type { RegistryConnector } from 'fuma-cli/registry/connector';\nimport type { Project } from '@/project';\nimport { createSourceFile, type SourceFile } from '@/codemod';\nimport { FumadocsComponentInstaller } from '@/registry/installer';\nimport { exists } from '@/utils/fs';\n\nexport interface SelectOption<T> {\n message: string;\n choices: { value: T; label: string; hint?: string }[];\n}\n\nexport interface ConfirmOption {\n message: string;\n initialValue?: boolean;\n}\n\nexport type FeatureOption<T> = [T] extends [boolean] ? ConfirmOption : SelectOption<T>;\n\nexport interface Feature<Options extends object = Record<never, never>> {\n id: string;\n title: string;\n description: string;\n options?: { [K in keyof Options]: FeatureOption<Options[K]> };\n /** features that must be applied first */\n requires?: AnyFeature[];\n /** whether the feature is already applied to the project */\n detect?: (project: Project) => Promise<boolean>;\n /** @returns `true` if supported, otherwise the reason */\n supports?: (project: Project) => true | string;\n apply(ctx: FeatureContext, options: Options): Promise<void>;\n}\n\nexport type AnyFeature = Omit<Feature<Record<string, unknown>>, 'options'> & {\n options?: Record<string, SelectOption<unknown> | ConfirmOption>;\n};\n\nexport interface PackageJson {\n scripts?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nexport interface FeatureContext {\n project: Project;\n /** write a file (relative to project root), asks before overwriting */\n write: (file: string, content: string) => Promise<void>;\n /** edit a file with codemods, `false` if the file doesn't exist */\n source: (file: string, edit: (file: SourceFile) => void) => Promise<boolean>;\n /** append lines to a text file, skip lines already present */\n append: (file: string, lines: string[]) => Promise<void>;\n remove: (file: string) => Promise<void>;\n packageJson: (edit: (data: PackageJson) => void) => Promise<void>;\n /** install a registry component */\n install: (name: string, subRegistry?: string) => Promise<void>;\n /** `null` to install the latest version */\n addDependencies: (deps: Record<string, string | null>, dev?: boolean) => void;\n env: (key: string, value: string) => void;\n /** instructions to show after the feature is applied */\n note: (text: string) => void;\n log: (message: string) => void;\n}\n\nexport interface FeatureIO {\n log: (message: string) => void;\n confirmOverwrite: (file: string) => Promise<boolean>;\n /** run package manager to install dependencies, otherwise only write them into `package.json` */\n installDependencies: boolean;\n}\n\nexport interface RunOptions {\n project: Project;\n connector: RegistryConnector;\n io: FeatureIO;\n /** preferred versions of dependencies, when a feature doesn't specify one */\n versions?: Record<string, string>;\n}\n\nexport async function runFeature<O extends object>(\n feature: Omit<Feature<O>, 'options'>,\n options: O,\n { project, connector, io, versions }: RunOptions,\n): Promise<{ notes: string[] }> {\n for (const dep of feature.requires ?? []) {\n if (dep.detect && !(await dep.detect(project)))\n throw new Error(\n `\"${feature.id}\" requires \"${dep.id}\", run \\`fumadocs feature ${dep.id}\\` first.`,\n );\n }\n const supported = feature.supports?.(project) ?? true;\n if (supported !== true) throw new Error(`\"${feature.id}\" is unavailable: ${supported}`);\n\n const { cwd } = project;\n const deps: Record<string, string | null> = {};\n const devDeps: Record<string, string | null> = {};\n const env: string[] = [];\n const notes: string[] = [];\n const installer = new FumadocsComponentInstaller(connector, project.config, cwd, {\n onWarn: io.log,\n confirmFileOverride: ({ path: file }) => io.confirmOverwrite(path.relative(cwd, file)),\n onFileDownloaded: ({ path: file }) => io.log(`installed ${path.relative(cwd, file)}`),\n });\n\n const ctx: FeatureContext = {\n project,\n log: io.log,\n note: (text) => notes.push(text),\n env: (key, value) => env.push(`${key}=${value}`),\n addDependencies(input, dev) {\n Object.assign(dev ? devDeps : deps, input);\n },\n async write(file, content) {\n const target = path.join(cwd, file);\n const current = await fs.readFile(target, 'utf-8').catch(() => null);\n if (current !== null) {\n if (current.trim() === content.trim()) return;\n if (!(await io.confirmOverwrite(file))) return;\n }\n await fs.mkdir(path.dirname(target), { recursive: true });\n await fs.writeFile(target, content);\n io.log(`${current === null ? 'created' : 'updated'} ${file}`);\n },\n async source(file, edit) {\n const target = path.join(cwd, file);\n if (!(await exists(target))) return false;\n const source = await createSourceFile(target);\n edit(source);\n if (source.s.hasChanged()) {\n await source.save();\n io.log(`updated ${file}`);\n }\n return true;\n },\n async append(file, lines) {\n const target = path.join(cwd, file);\n const current = await fs.readFile(target, 'utf-8').catch(() => '');\n const missing = lines.filter((line) => !current.includes(line));\n if (missing.length === 0) return;\n const separator = current.length === 0 || current.endsWith('\\n') ? '' : '\\n';\n await fs.mkdir(path.dirname(target), { recursive: true });\n await fs.writeFile(target, `${current}${separator}${missing.join('\\n')}\\n`);\n io.log(`updated ${file}`);\n },\n async remove(file) {\n await fs.rm(path.join(cwd, file), { force: true });\n io.log(`removed ${file}`);\n },\n async packageJson(edit) {\n const target = path.join(cwd, 'package.json');\n const data = JSON.parse(await fs.readFile(target, 'utf-8'));\n edit(data);\n await fs.writeFile(target, `${JSON.stringify(data, null, 2)}\\n`);\n io.log('updated package.json');\n },\n async install(name, subRegistry) {\n const result = await installer.install(name, subRegistry);\n const manager = await result.deps();\n // encoded as `name` or `name@version`\n const decode = (target: Record<string, string | null>, dep: string) => {\n const at = dep.indexOf('@', 1);\n if (at === -1) target[dep] = null;\n else target[dep.slice(0, at)] = dep.slice(at + 1);\n };\n for (const dep of manager.dependencies) decode(deps, dep);\n for (const dep of manager.devDependencies) decode(devDeps, dep);\n },\n };\n\n await feature.apply(ctx, options);\n\n if (env.length > 0) await ctx.append('.env.local', env);\n await installDependencies(project, deps, devDeps, io, versions);\n return { notes };\n}\n\nasync function installDependencies(\n project: Project,\n deps: Record<string, string | null>,\n devDeps: Record<string, string | null>,\n io: FeatureIO,\n versions: Record<string, string> = {},\n) {\n const { dependencies = {}, devDependencies = {} } = project.packageJson;\n const filter = (input: Record<string, string | null>) =>\n Object.entries(input).filter(([name]) => !(name in dependencies) && !(name in devDependencies));\n const missing = filter(deps);\n const missingDev = filter(devDeps);\n if (missing.length === 0 && missingDev.length === 0) return;\n\n if (io.installDependencies) {\n const pm = project.packageManager;\n const run = async (flags: string[], entries: [string, string | null][]) => {\n if (entries.length === 0) return;\n const args = [\n 'add',\n ...flags,\n ...entries.map(([name, version]) => (version ? `${name}@${version}` : name)),\n ];\n io.log(`${pm} ${args.join(' ')}`);\n await x(pm, args, {\n nodeOptions: { cwd: project.cwd, stdio: 'inherit' },\n throwOnError: true,\n });\n };\n await run([], missing);\n await run(['-D'], missingDev);\n return;\n }\n\n const file = path.join(project.cwd, 'package.json');\n const json = JSON.parse(await fs.readFile(file, 'utf-8'));\n const write = (field: string, entries: [string, string | null][]) => {\n if (entries.length === 0) return;\n const target = (json[field] ??= {});\n for (const [name, version] of entries) target[name] = version ?? versions[name] ?? 'latest';\n };\n write('dependencies', missing);\n write('devDependencies', missingDev);\n await fs.writeFile(file, `${JSON.stringify(json, null, 2)}\\n`);\n io.log('updated package.json');\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { b as findJsxElement, h as appendJsxChildren, p as addImport } from "./codemod-auol-p4R.js";
2
- import { t as docs } from "./docs-DeIEl_Kt.js";
2
+ import { t as docs } from "./docs--WqEHTyl.js";
3
3
  import { r as findSource } from "./utils-DbMe7h6c.js";
4
4
  import path from "node:path";
5
5
  //#region src/features/feedback.ts
@@ -34,4 +34,4 @@ const feedback = {
34
34
  //#endregion
35
35
  export { feedback as t };
36
36
 
37
- //# sourceMappingURL=feedback-COmWtc5C.js.map
37
+ //# sourceMappingURL=feedback-Brj092vC.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"feedback-COmWtc5C.js","names":[],"sources":["../src/features/feedback.ts"],"sourcesContent":["import path from 'node:path';\nimport type { Feature } from '@/features';\nimport { addImport, appendJsxChildren, findJsxElement } from '@/codemod';\nimport { docs } from './docs';\nimport { findSource } from './utils';\n\nexport const feedback: Feature = {\n id: 'feedback',\n title: 'Feedback',\n description: 'let readers rate docs pages, with a component to send feedback',\n requires: [docs],\n async apply(ctx) {\n const { cwd, baseDir, info, framework, static: isStatic } = ctx.project;\n await ctx.install('feedback');\n\n // server actions are only available on RSC frameworks, static export has none\n const serverAction = framework === 'next' || framework === 'waku';\n const page = await findSource(cwd, path.join(baseDir, info.routesDir), '<DocsPage');\n const edited =\n page !== undefined &&\n !(serverAction && isStatic) &&\n (await ctx.source(page, (file) => {\n if (file.code.includes('<Feedback')) return;\n const element = findJsxElement(file, 'DocsPage');\n if (!element) return;\n\n appendJsxChildren(\n file,\n element,\n `<Feedback\n onSendAction={async (feedback) => {${serverAction ? \"\\n 'use server';\\n\" : ''}\n console.log(feedback);\n return {};\n }}\n/>`,\n );\n addImport(file, { from: '@/components/feedback/client', named: ['Feedback'] });\n }));\n\n if (!edited) {\n ctx.note(\n serverAction && isStatic\n ? 'Static export has no server actions, render `<Feedback />` from `@/components/feedback/client` in a client component and send the feedback to your API in `onSendAction`.'\n : 'Add `<Feedback />` from `@/components/feedback/client` to the bottom of your docs page.',\n );\n }\n ctx.note(\n 'Handle the feedback in `onSendAction`, e.g. report it to GitHub Discussions: https://fumadocs.dev/docs/integrations/feedback.',\n );\n },\n};\n"],"mappings":";;;;;AAMA,MAAa,WAAoB;CAC/B,IAAI;CACJ,OAAO;CACP,aAAa;CACb,UAAU,CAAC,IAAI;CACf,MAAM,MAAM,KAAK;EACf,MAAM,EAAE,KAAK,SAAS,MAAM,WAAW,QAAQ,aAAa,IAAI;EAChE,MAAM,IAAI,QAAQ,UAAU;EAG5B,MAAM,eAAe,cAAc,UAAU,cAAc;EAC3D,MAAM,OAAO,MAAM,WAAW,KAAK,KAAK,KAAK,SAAS,KAAK,SAAS,GAAG,WAAW;EAsBlF,IAAI,EApBF,SAAS,KAAA,KACT,EAAE,gBAAgB,aACjB,MAAM,IAAI,OAAO,OAAO,SAAS;GAChC,IAAI,KAAK,KAAK,SAAS,WAAW,GAAG;GACrC,MAAM,UAAU,eAAe,MAAM,UAAU;GAC/C,IAAI,CAAC,SAAS;GAEd,kBACE,MACA,SACA;uCAC6B,eAAe,0BAA0B,GAAG;;;;GAK3E;GACA,UAAU,MAAM;IAAE,MAAM;IAAgC,OAAO,CAAC,UAAU;GAAE,CAAC;EAC/E,CAAC,IAGD,IAAI,KACF,gBAAgB,WACZ,8KACA,yFACN;EAEF,IAAI,KACF,+HACF;CACF;AACF"}
1
+ {"version":3,"file":"feedback-Brj092vC.js","names":[],"sources":["../src/features/feedback.ts"],"sourcesContent":["import path from 'node:path';\nimport type { Feature } from '@/features';\nimport { addImport, appendJsxChildren, findJsxElement } from '@/codemod';\nimport { docs } from './docs';\nimport { findSource } from './utils';\n\nexport const feedback: Feature = {\n id: 'feedback',\n title: 'Feedback',\n description: 'let readers rate docs pages, with a component to send feedback',\n requires: [docs],\n async apply(ctx) {\n const { cwd, baseDir, info, framework, static: isStatic } = ctx.project;\n await ctx.install('feedback');\n\n // server actions are only available on RSC frameworks, static export has none\n const serverAction = framework === 'next' || framework === 'waku';\n const page = await findSource(cwd, path.join(baseDir, info.routesDir), '<DocsPage');\n const edited =\n page !== undefined &&\n !(serverAction && isStatic) &&\n (await ctx.source(page, (file) => {\n if (file.code.includes('<Feedback')) return;\n const element = findJsxElement(file, 'DocsPage');\n if (!element) return;\n\n appendJsxChildren(\n file,\n element,\n `<Feedback\n onSendAction={async (feedback) => {${serverAction ? \"\\n 'use server';\\n\" : ''}\n console.log(feedback);\n return {};\n }}\n/>`,\n );\n addImport(file, { from: '@/components/feedback/client', named: ['Feedback'] });\n }));\n\n if (!edited) {\n ctx.note(\n serverAction && isStatic\n ? 'Static export has no server actions, render `<Feedback />` from `@/components/feedback/client` in a client component and send the feedback to your API in `onSendAction`.'\n : 'Add `<Feedback />` from `@/components/feedback/client` to the bottom of your docs page.',\n );\n }\n ctx.note(\n 'Handle the feedback in `onSendAction`, e.g. report it to GitHub Discussions: https://fumadocs.dev/docs/integrations/feedback.',\n );\n },\n};\n"],"mappings":";;;;;AAMA,MAAa,WAAoB;CAC/B,IAAI;CACJ,OAAO;CACP,aAAa;CACb,UAAU,CAAC,IAAI;CACf,MAAM,MAAM,KAAK;EACf,MAAM,EAAE,KAAK,SAAS,MAAM,WAAW,QAAQ,aAAa,IAAI;EAChE,MAAM,IAAI,QAAQ,UAAU;EAG5B,MAAM,eAAe,cAAc,UAAU,cAAc;EAC3D,MAAM,OAAO,MAAM,WAAW,KAAK,KAAK,KAAK,SAAS,KAAK,SAAS,GAAG,WAAW;EAsBlF,IAAI,EApBF,SAAS,KAAA,KACT,EAAE,gBAAgB,aACjB,MAAM,IAAI,OAAO,OAAO,SAAS;GAChC,IAAI,KAAK,KAAK,SAAS,WAAW,GAAG;GACrC,MAAM,UAAU,eAAe,MAAM,UAAU;GAC/C,IAAI,CAAC,SAAS;GAEd,kBACE,MACA,SACA;uCAC6B,eAAe,0BAA0B,GAAG;;;;GAK3E;GACA,UAAU,MAAM;IAAE,MAAM;IAAgC,OAAO,CAAC,UAAU;GAAE,CAAC;EAC/E,CAAC,IAGD,IAAI,KACF,gBAAgB,WACZ,8KACA,yFACN;EAEF,IAAI,KACF,+HACF;CACF;AACF"}
@@ -1,5 +1,5 @@
1
1
  import { p as SourceFile } from "./index-Ck0EPdgu.js";
2
- import { a as Project } from "./index-BCVGQxn9.js";
2
+ import { a as Project } from "./index-DI66DoV8.js";
3
3
  import { RegistryConnector } from "fuma-cli/registry/connector";
4
4
  //#region src/features/index.d.ts
5
5
  interface SelectOption<T> {
@@ -73,4 +73,4 @@ declare function runFeature<O extends object>(feature: Omit<Feature<O>, 'options
73
73
  }>;
74
74
  //#endregion
75
75
  export { FeatureIO as a, RunOptions as c, FeatureContext as i, SelectOption as l, ConfirmOption as n, FeatureOption as o, Feature as r, PackageJson as s, AnyFeature as t, runFeature as u };
76
- //# sourceMappingURL=index-CR9T40ox.d.ts.map
76
+ //# sourceMappingURL=index-Cs7hw2un.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-CR9T40ox.d.ts","names":[],"sources":["../src/features/index.ts"],"mappings":";;;;UASiB,aAAa;EAC5B;EACA;IAAW,OAAO;IAAG;IAAe;;;UAGrB;EACf;EACA;;KAGU,cAAc,MAAM,uBAAuB,gBAAgB,aAAa;UAEnE,QAAQ,yBAAyB;EAChD;EACA;EACA;EACA,aAAa,WAAW,UAAU,cAAc,QAAQ;;EAExD,WAAW;;EAEX,UAAU,SAAS,YAAY;;EAE/B,YAAY,SAAS;EACrB,MAAM,KAAK,gBAAgB,SAAS,UAAU;;KAGpC,aAAa,KAAK,QAAQ;EACpC,UAAU,eAAe,wBAAwB;;UAGlC;EACf,UAAU;EACV,eAAe;EACf,kBAAkB;;UAGH;EACf,SAAS;;EAET,QAAQ,cAAc,oBAAoB;;EAE1C,SAAS,cAAc,OAAO,MAAM,wBAAwB;;EAE5D,SAAS,cAAc,oBAAoB;EAC3C,SAAS,iBAAiB;EAC1B,cAAc,OAAO,MAAM,yBAAyB;;EAEpD,UAAU,cAAc,yBAAyB;;EAEjD,kBAAkB,MAAM,+BAA+B;EACvD,MAAM,aAAa;;EAEnB,OAAO;EACP,MAAM;;UAGS;EACf,MAAM;EACN,mBAAmB,iBAAiB;;EAEpC;;UAGe;EACf,SAAS;EACT,WAAW;EACX,IAAI;;EAEJ,WAAW;;iBAGS,WAAW,kBAC/B,SAAS,KAAK,QAAQ,gBACtB,SAAS,KACP,SAAS,WAAW,IAAI,YAAY,aACrC;EAAU"}
1
+ {"version":3,"file":"index-Cs7hw2un.d.ts","names":[],"sources":["../src/features/index.ts"],"mappings":";;;;UASiB,aAAa;EAC5B;EACA;IAAW,OAAO;IAAG;IAAe;;;UAGrB;EACf;EACA;;KAGU,cAAc,MAAM,uBAAuB,gBAAgB,aAAa;UAEnE,QAAQ,yBAAyB;EAChD;EACA;EACA;EACA,aAAa,WAAW,UAAU,cAAc,QAAQ;;EAExD,WAAW;;EAEX,UAAU,SAAS,YAAY;;EAE/B,YAAY,SAAS;EACrB,MAAM,KAAK,gBAAgB,SAAS,UAAU;;KAGpC,aAAa,KAAK,QAAQ;EACpC,UAAU,eAAe,wBAAwB;;UAGlC;EACf,UAAU;EACV,eAAe;EACf,kBAAkB;;UAGH;EACf,SAAS;;EAET,QAAQ,cAAc,oBAAoB;;EAE1C,SAAS,cAAc,OAAO,MAAM,wBAAwB;;EAE5D,SAAS,cAAc,oBAAoB;EAC3C,SAAS,iBAAiB;EAC1B,cAAc,OAAO,MAAM,yBAAyB;;EAEpD,UAAU,cAAc,yBAAyB;;EAEjD,kBAAkB,MAAM,+BAA+B;EACvD,MAAM,aAAa;;EAEnB,OAAO;EACP,MAAM;;UAGS;EACf,MAAM;EACN,mBAAmB,iBAAiB;;EAEpC;;UAGe;EACf,SAAS;EACT,WAAW;EACX,IAAI;;EAEJ,WAAW;;iBAGS,WAAW,kBAC/B,SAAS,KAAK,QAAQ,gBACtB,SAAS,KACP,SAAS,WAAW,IAAI,YAAY,aACrC;EAAU"}
@@ -1,4 +1,4 @@
1
- import { r as LoadedConfig } from "./config-CT2jj39D.js";
1
+ import { r as LoadedConfig } from "./config-Bfg4yG8S.js";
2
2
  import { detectFramework as detectFramework$1, detectPackageManager } from "fuma-cli/detect";
3
3
  //#region src/project/index.d.ts
4
4
  type PackageManager = NonNullable<Awaited<ReturnType<typeof detectPackageManager>>>['name'];
@@ -61,4 +61,4 @@ declare function isSupportedFramework(v: string): v is Framework;
61
61
  declare function loadProject(config: LoadedConfig, cwd?: string, framework?: Framework): Promise<Project>;
62
62
  //#endregion
63
63
  export { Project as a, detectFramework$1 as c, loadProject as d, PackageManager as i, frameworks as l, FrameworkInfo as n, ReactFramework as o, I18nInfo as r, SourceInfo as s, Framework as t, isSupportedFramework as u };
64
- //# sourceMappingURL=index-BCVGQxn9.d.ts.map
64
+ //# sourceMappingURL=index-DI66DoV8.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-BCVGQxn9.d.ts","names":[],"sources":["../src/project/index.ts"],"mappings":";;;KAMY,iBAAiB,YAAY,QAAQ,kBAAkB;KAEvD;;KAEA,iBAAiB,QAAQ;UAEpB;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA,YAAY;;cAGD,YAAY,OAAO,WAAW;;UAoC1B;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;UAGe;;EAEf;;UAGe;EACf;EACA,WAAW;EACX,MAAM;;EAEN;;EAEA,MAAM;EACN,QAAQ;EACR,gBAAgB;;EAEhB;EACA,QAAQ;;EAER;EACA;IACE,eAAe;IACf,kBAAkB;;;iBAIN,qBAAqB,YAAY,KAAK;iBAIhC,YACpB,QAAQ,cACR,cACA,YAAW,YACV,QAAQ"}
1
+ {"version":3,"file":"index-DI66DoV8.d.ts","names":[],"sources":["../src/project/index.ts"],"mappings":";;;KAMY,iBAAiB,YAAY,QAAQ,kBAAkB;KAEvD;;KAEA,iBAAiB,QAAQ;UAEpB;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA,YAAY;;cAGD,YAAY,OAAO,WAAW;;UAoC1B;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;UAGe;;EAEf;;UAGe;EACf;EACA,WAAW;EACX,MAAM;;EAEN;;EAEA,MAAM;EACN,QAAQ;EACR,gBAAgB;;EAEhB;EACA,QAAQ;;EAER;EACA;IACE,eAAe;IACf,kBAAkB;;;iBAIN,qBAAqB,YAAY,KAAK;iBAIhC,YACpB,QAAQ,cACR,cACA,YAAW,YACV,QAAQ"}
package/dist/index.js CHANGED
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import { i as initConfig, n as createOrLoadConfig } from "./config-D6uv73fs.js";
3
- import { n as isCancel$1, t as FumadocsComponentInstaller } from "./installer-D0Obb2Md.js";
2
+ import { i as initConfig, n as createOrLoadConfig } from "./config-Bw0kmF01.js";
3
+ import { T as parseSourceFile } from "./codemod-auol-p4R.js";
4
4
  import { t as exists } from "./fs-D6J9dOEx.js";
5
- import { i as loadProject } from "./project-DwRVTm4p.js";
6
- import { t as runFeature } from "./features-C1kf2s8j.js";
7
- import { t as features } from "./all-aUHxtoXL.js";
5
+ import { i as loadProject, n as frameworks } from "./project-DwRVTm4p.js";
6
+ import { n as isCancel$1, r as UIRegistries, t as FumadocsComponentInstaller } from "./installer-CzhVfs7i.js";
7
+ import { t as runFeature } from "./features-CXFCgOWD.js";
8
+ import { t as features } from "./all-BBf7I8hG.js";
8
9
  import fs from "node:fs/promises";
9
10
  import path from "node:path";
10
11
  import { cac } from "cac";
@@ -65,13 +66,7 @@ async function runTree(args) {
65
66
  }
66
67
  //#endregion
67
68
  //#region package.json
68
- var version = "1.6.0";
69
- //#endregion
70
- //#region src/commands/shared.ts
71
- const UIRegistries = {
72
- "base-ui": "fumadocs/base-ui",
73
- "radix-ui": "fumadocs/radix-ui"
74
- };
69
+ var version = "1.6.2";
75
70
  //#endregion
76
71
  //#region src/commands/customise.ts
77
72
  async function customise(config, connector) {
@@ -91,9 +86,7 @@ async function customise(config, connector) {
91
86
  subRegistry,
92
87
  name: "layouts/docs"
93
88
  }],
94
- print() {
95
- printLayout(["fumadocs-ui/layouts/docs", "@/layouts/docs"], ["fumadocs-ui/layouts/docs/page", "@/layouts/docs/page"]);
96
- }
89
+ print: () => printLayout(config, ["fumadocs-ui/layouts/docs", "@/layouts/docs"], ["fumadocs-ui/layouts/docs/page", "@/layouts/docs/page"])
97
90
  },
98
91
  hint: "the default docs layout"
99
92
  },
@@ -105,9 +98,7 @@ async function customise(config, connector) {
105
98
  subRegistry,
106
99
  name: "layouts/notebook"
107
100
  }],
108
- print() {
109
- printLayout(["fumadocs-ui/layouts/notebook", "@/layouts/notebook"], ["fumadocs-ui/layouts/notebook/page", "@/layouts/notebook/page"]);
110
- }
101
+ print: () => printLayout(config, ["fumadocs-ui/layouts/notebook", "@/layouts/notebook"], ["fumadocs-ui/layouts/notebook/page", "@/layouts/notebook/page"])
111
102
  },
112
103
  hint: "a more compact version of docs layout"
113
104
  },
@@ -119,9 +110,7 @@ async function customise(config, connector) {
119
110
  subRegistry,
120
111
  name: "layouts/flux"
121
112
  }],
122
- print() {
123
- printLayout(["fumadocs-ui/layouts/flux", "@/layouts/flux"], ["fumadocs-ui/layouts/flux/page", "@/layouts/flux/page"]);
124
- }
113
+ print: () => printLayout(config, ["fumadocs-ui/layouts/flux", "@/layouts/flux"], ["fumadocs-ui/layouts/flux/page", "@/layouts/flux/page"])
125
114
  },
126
115
  hint: "the experimental variant of docs layout"
127
116
  },
@@ -133,9 +122,7 @@ async function customise(config, connector) {
133
122
  subRegistry,
134
123
  name: "layouts/glass"
135
124
  }],
136
- print() {
137
- printLayout(["fumadocs-ui/layouts/glass", "@/layouts/glass"], ["fumadocs-ui/layouts/glass/page", "@/layouts/glass/page"]);
138
- }
125
+ print: () => printLayout(config, ["fumadocs-ui/layouts/glass", "@/layouts/glass"], ["fumadocs-ui/layouts/glass/page", "@/layouts/glass/page"])
139
126
  },
140
127
  hint: "a docs layout with floating, translucent panels"
141
128
  },
@@ -147,9 +134,7 @@ async function customise(config, connector) {
147
134
  subRegistry,
148
135
  name: "layouts/home"
149
136
  }],
150
- print() {
151
- printLayout(["fumadocs-ui/layouts/home", `@/layouts/home`]);
152
- }
137
+ print: () => printLayout(config, ["fumadocs-ui/layouts/home", "@/layouts/home"])
153
138
  },
154
139
  hint: "the layout for other non-docs pages"
155
140
  }
@@ -172,9 +157,7 @@ async function customise(config, connector) {
172
157
  value: {
173
158
  id: "docs-min",
174
159
  targets: [{ name: "layouts/docs-min" }],
175
- print() {
176
- printLayout(["fumadocs-ui/layouts/docs", "@/layouts/docs"], ["fumadocs-ui/layouts/docs/page", "@/layouts/docs/page"]);
177
- }
160
+ print: () => printLayout(config, ["fumadocs-ui/layouts/docs", "@/layouts/docs"], ["fumadocs-ui/layouts/docs/page", "@/layouts/docs/page"])
178
161
  }
179
162
  },
180
163
  ...info.unlistedIndexes.flatMap((index) => {
@@ -233,15 +216,39 @@ async function customise(config, connector) {
233
216
  process.exit(0);
234
217
  } })).target;
235
218
  for (const target of targetInfo.targets) await installer.installInteractive(target.name, target.subRegistry);
236
- targetInfo.print?.();
219
+ await targetInfo.print?.();
237
220
  outro(picocolors.bold("Have fun!"));
238
221
  }
239
- function printLayout(...maps) {
222
+ /** point the imports of route files at the installed layouts */
223
+ async function rewriteLayoutImports(config, map) {
224
+ const dir = path.join(config.baseDir, frameworks[config.framework].routesDir);
225
+ const entries = await fs.readdir(dir, {
226
+ recursive: true,
227
+ withFileTypes: true
228
+ }).catch(() => []);
229
+ const updated = [];
230
+ for (const entry of entries) {
231
+ if (!entry.isFile() || !entry.name.endsWith(".tsx")) continue;
232
+ const file = path.join(entry.parentPath, entry.name);
233
+ const source = parseSourceFile(file, await fs.readFile(file, "utf-8"));
234
+ for (const node of source.program.body) {
235
+ if (node.type !== "ImportDeclaration") continue;
236
+ const to = map.get(node.source.value);
237
+ if (to) source.s.overwrite(node.source.start + 1, node.source.end - 1, to);
238
+ }
239
+ if (!source.s.hasChanged()) continue;
240
+ await source.save();
241
+ updated.push(file);
242
+ }
243
+ return updated;
244
+ }
245
+ async function printLayout(config, ...maps) {
240
246
  intro(picocolors.bold("What is Next?"));
247
+ const updated = await rewriteLayoutImports(config, new Map(maps));
241
248
  log.info([
242
249
  "You can check the installed layouts in `layouts` folder.",
243
250
  picocolors.dim("---"),
244
- "Open your `layout.tsx` files, replace the imports of components:",
251
+ updated.length > 0 ? `Updated the imports of ${updated.join(", ")}.` : "Open your `layout.tsx` files, replace the imports of components:",
245
252
  ...maps.map(([from, to]) => picocolors.greenBright(`"${from}" -> "${to}"`))
246
253
  ].join("\n"));
247
254
  }
@@ -468,9 +475,9 @@ async function add(input, connector, config) {
468
475
  }
469
476
  const groups = await Promise.all([
470
477
  scan(void 0, "common"),
471
- scan("fumadocs/sanity", "sanity"),
472
- scan("fumadocs/openapi", "openapi"),
473
- scan("fumadocs/api-docs", "api-docs"),
478
+ scan("sanity", "sanity"),
479
+ scan("openapi", "openapi"),
480
+ scan("api-docs", "api-docs"),
474
481
  scan(subRegistry, "ui")
475
482
  ]);
476
483
  spin.stop(picocolors.bold(picocolors.greenBright("registry fetched")));
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["isCancel","isCancel","packageJson.version"],"sources":["../src/commands/file-tree.ts","../src/utils/file-tree/run-tree.ts","../package.json","../src/commands/shared.ts","../src/commands/customise.ts","../src/commands/add.ts","../src/commands/export-epub.ts","../src/commands/feature.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 { cancel, group, intro, log, outro, select } from '@clack/prompts';\nimport picocolors from 'picocolors';\nimport type { Target } from '@/commands/add';\nimport { UIRegistries } from '@/commands/shared';\nimport { LoadedConfig } from '@/config';\nimport { RegistryConnector } from 'fuma-cli/registry/connector';\nimport { FumadocsComponentInstaller } from '@/registry/installer';\n\ninterface TargetInfo {\n targets: Target[];\n id: string;\n print?: () => void;\n}\n\ninterface SlotPrintInfo {\n at: string;\n layoutId: string;\n name: string;\n isPage: boolean;\n uiLibrary: LoadedConfig['uiLibrary'];\n}\n\nexport async function customise(config: LoadedConfig, connector: RegistryConnector) {\n intro(picocolors.bgBlack(picocolors.whiteBright('Customize Fumadocs UI')));\n\n const installer = new FumadocsComponentInstaller(connector, config);\n const subRegistry = UIRegistries[config.uiLibrary];\n const info = await connector.fetchRegistryInfo(subRegistry);\n\n const result = await group(\n {\n layout: (): Promise<TargetInfo | symbol> =>\n select({\n message: 'What do you want to customize?',\n options: [\n {\n label: 'Docs Layout',\n value: {\n id: 'docs',\n targets: [{ subRegistry, name: 'layouts/docs' }],\n print() {\n printLayout(\n ['fumadocs-ui/layouts/docs', '@/layouts/docs'],\n ['fumadocs-ui/layouts/docs/page', '@/layouts/docs/page'],\n );\n },\n },\n hint: 'the default docs layout',\n },\n {\n label: 'Notebook Layout',\n value: {\n id: 'notebook',\n targets: [{ subRegistry, name: 'layouts/notebook' }],\n print() {\n printLayout(\n ['fumadocs-ui/layouts/notebook', '@/layouts/notebook'],\n ['fumadocs-ui/layouts/notebook/page', '@/layouts/notebook/page'],\n );\n },\n },\n hint: 'a more compact version of docs layout',\n },\n {\n label: 'Flux Layout',\n value: {\n id: 'flux',\n targets: [{ subRegistry, name: 'layouts/flux' }],\n print() {\n printLayout(\n ['fumadocs-ui/layouts/flux', '@/layouts/flux'],\n ['fumadocs-ui/layouts/flux/page', '@/layouts/flux/page'],\n );\n },\n },\n hint: 'the experimental variant of docs layout',\n },\n {\n label: 'Glass Layout',\n value: {\n id: 'glass',\n targets: [{ subRegistry, name: 'layouts/glass' }],\n print() {\n printLayout(\n ['fumadocs-ui/layouts/glass', '@/layouts/glass'],\n ['fumadocs-ui/layouts/glass/page', '@/layouts/glass/page'],\n );\n },\n },\n hint: 'a docs layout with floating, translucent panels',\n },\n {\n label: 'Home Layout',\n value: {\n id: 'home',\n targets: [{ subRegistry, name: 'layouts/home' }],\n print() {\n printLayout(['fumadocs-ui/layouts/home', `@/layouts/home`]);\n },\n },\n hint: 'the layout for other non-docs pages',\n },\n ],\n }),\n target: (v): Promise<TargetInfo | symbol> => {\n const selected = v.results.layout!;\n if (selected.id === 'home') return Promise.resolve(selected);\n\n return select<TargetInfo>({\n message: 'Which part do you want to customize?',\n options: [\n {\n label: 'All',\n hint: 'install the entire layout',\n value: selected,\n },\n {\n label: 'Replace & rewrite from minimal styles',\n hint: 'for those who want to build their own UI from ground up',\n value: {\n id: 'docs-min',\n targets: [{ name: 'layouts/docs-min' }],\n print() {\n printLayout(\n ['fumadocs-ui/layouts/docs', '@/layouts/docs'],\n ['fumadocs-ui/layouts/docs/page', '@/layouts/docs/page'],\n );\n },\n },\n },\n ...info.unlistedIndexes.flatMap((index) => {\n const prefix = `slots/${selected.id}`;\n if (!index.name.startsWith(prefix)) return [];\n let name = index.name.slice(prefix.length + 1);\n\n if (name.startsWith('page/')) {\n name = name.slice('page/'.length);\n\n return {\n label: `Page: ${name}`,\n hint: \"only replace a part of layout's page, useful for adjusting details\",\n value: {\n id: index.name,\n targets: [{ subRegistry, name: index.name }],\n print() {\n printSlot({\n at: `@/layouts/${selected.id}/page/slots/${name}`,\n layoutId: selected.id,\n name,\n isPage: true,\n uiLibrary: config.uiLibrary,\n });\n },\n } as TargetInfo,\n };\n }\n\n return {\n label: `Layout: ${name}`,\n hint: 'only replace a part of layout, useful for adjusting details',\n value: {\n id: index.name,\n targets: [{ subRegistry, name: index.name }],\n print() {\n printSlot({\n at: `@/layouts/${selected.id}/slots/${name}`,\n layoutId: selected.id,\n name,\n isPage: false,\n uiLibrary: config.uiLibrary,\n });\n },\n } as TargetInfo,\n };\n }),\n ],\n });\n },\n },\n {\n onCancel: () => {\n cancel('Installation Stopped.');\n process.exit(0);\n },\n },\n );\n\n const targetInfo = result.target as TargetInfo;\n for (const target of targetInfo.targets) {\n await installer.installInteractive(target.name, target.subRegistry);\n }\n\n targetInfo.print?.();\n\n outro(picocolors.bold('Have fun!'));\n}\n\nfunction printLayout(...maps: [from: string, to: string][]) {\n intro(picocolors.bold('What is Next?'));\n\n log.info(\n [\n 'You can check the installed layouts in `layouts` folder.',\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\nfunction printSlot({ at, layoutId, name, isPage, uiLibrary }: SlotPrintInfo) {\n intro(picocolors.bold('What is Next?'));\n\n log.info(`You can check the installed layout slot in \"${at}\".`);\n\n const code = getSlotCode({ at, layoutId, name, isPage, uiLibrary });\n\n if (code) {\n const layoutComponent = layoutId === 'glass' ? '<GlassLayout />' : '<DocsLayout />';\n\n if (isPage) {\n log.info(\n `${picocolors.bold('At your <DocsPage /> component, update your \"slots\" prop:')}\\n\\n${code}`,\n );\n } else {\n log.info(\n `${picocolors.bold(`At your ${layoutComponent} component, update your \"slots\" prop:`)}\\n\\n${code}`,\n );\n }\n }\n}\n\nfunction getSlotCode({ at, layoutId, name, isPage, uiLibrary }: SlotPrintInfo): string | undefined {\n if (layoutId === 'glass') {\n // Glass layout wires its page slots directly, only layout-level slots are swappable.\n if (isPage) return;\n\n switch (name) {\n case 'header':\n return `import { Header } from '${at}';\n\nreturn (\n <GlassLayout\n slots={{\n header: Header,\n }}\n >\n ...\n </GlassLayout>\n);`;\n case 'sidebar': {\n // `sidebar` slot file holds the whole sidebar system (desktop, mobile drawer, provider).\n // Base UI additionally exposes a `drawerHandle` for its swipeable drawer.\n const imports = ['Sidebar', 'SidebarDrawer', 'SidebarProvider', 'useSidebar'];\n if (uiLibrary === 'base-ui') imports.push('drawerHandle');\n\n return `import { ${imports.join(', ')} } from '${at}';\n\nreturn (\n <GlassLayout\n slots={{\n sidebar: {\n main: Sidebar,\n provider: SidebarProvider,\n use: useSidebar,\n drawer: SidebarDrawer,${uiLibrary === 'base-ui' ? '\\n drawerHandle,' : ''}\n },\n }}\n >\n ...\n </GlassLayout>\n);`;\n }\n default:\n return;\n }\n }\n\n if (isPage) {\n switch (name) {\n case 'toc':\n if (layoutId === 'flux') {\n return `import { TOCProvider, TOC } from '${at}';\n\nreturn (\n <DocsPage\n slots={{\n toc: {\n provider: TOCProvider,\n main: TOC,\n },\n }}\n >\n ...\n </DocsPage>\n);`;\n }\n\n return `import { TOCProvider, TOC, TOCPopover } from '${at}';\n\nreturn (\n <DocsPage\n slots={{\n toc: {\n provider: TOCProvider,\n main: TOC,\n popover: TOCPopover,\n },\n }}\n >\n ...\n </DocsPage>\n);`;\n case 'container': {\n return `import { Container } from '${at}';\n\nreturn (\n <DocsPage\n slots={{\n container: Container,\n }}\n >\n ...\n </DocsPage>\n);`;\n }\n case 'footer': {\n return `import { Footer } from '${at}';\n\nreturn (\n <DocsPage\n slots={{\n footer: Footer,\n }}\n >\n ...\n </DocsPage>\n);`;\n }\n case 'breadcrumb': {\n return `import { Breadcrumb } from '${at}';\n\nreturn (\n <DocsPage\n slots={{\n breadcrumb: Breadcrumb,\n }}\n >\n ...\n </DocsPage>\n);`;\n }\n default:\n return;\n }\n }\n\n switch (name) {\n case 'sidebar': {\n if (layoutId === 'notebook') {\n return `import {\n SidebarProvider,\n Sidebar,\n SidebarTrigger,\n SidebarCollapseTrigger,\n useSidebar,\n} from '${at}';\n\nreturn (\n <DocsLayout\n slots={{\n sidebar: {\n provider: SidebarProvider,\n root: Sidebar,\n trigger: SidebarTrigger,\n collapseTrigger: SidebarCollapseTrigger,\n useSidebar: useSidebar,\n },\n }}\n >\n ...\n </DocsLayout>\n);`;\n }\n\n return `import { SidebarProvider, Sidebar, SidebarTrigger, useSidebar } from '${at}';\n\nreturn (\n <DocsLayout\n slots={{\n sidebar: {\n provider: SidebarProvider,\n root: Sidebar,\n trigger: SidebarTrigger,\n useSidebar: useSidebar,\n },\n }}\n >\n ...\n </DocsLayout>\n);`;\n }\n case 'container': {\n return `import { Container } from '${at}';\n\nreturn (\n <DocsLayout\n slots={{\n container: Container,\n }}\n >\n ...\n </DocsLayout>\n);`;\n }\n case 'header': {\n return `import { Header } from '${at}';\n\nreturn (\n <DocsLayout\n slots={{\n header: Header,\n }}\n >\n ...\n </DocsLayout>\n);`;\n }\n case 'tab-dropdown': {\n return `import { TabDropdown } from '${at}';\n\nreturn (\n <DocsLayout\n slots={{\n tabDropdown: TabDropdown,\n }}\n >\n ...\n </DocsLayout>\n);`;\n }\n default:\n return;\n }\n}\n","import { autocompleteMultiselect, outro, spinner } from '@clack/prompts';\nimport { isCancel } from '@/utils/prompt';\nimport picocolors from 'picocolors';\nimport { UIRegistries } from '@/commands/shared';\nimport { RegistryConnector } from 'fuma-cli/registry/connector';\nimport { LoadedConfig } from '@/config';\nimport { FumadocsComponentInstaller } from '@/registry/installer';\n\ninterface AddOption {\n label: string;\n value: Target;\n hint?: string;\n}\n\nexport interface Target {\n name: string;\n subRegistry?: string;\n}\n\nexport async function add(input: string[], connector: RegistryConnector, config: LoadedConfig) {\n let targets: Target[];\n const installer = new FumadocsComponentInstaller(connector, config);\n const subRegistry = UIRegistries[config.uiLibrary];\n\n if (input.length === 0) {\n const spin = spinner();\n spin.start('fetching registry');\n\n async function scan(subRegistry?: string, prefix?: string): Promise<AddOption[]> {\n const info = await connector.fetchRegistryInfo(subRegistry);\n\n return info.indexes.map((item) => ({\n label: `${prefix ? `${picocolors.bold(prefix)} - ` : ''}${item.title ?? item.name}`,\n value: { name: item.name, subRegistry },\n hint: item.description,\n }));\n }\n\n const groups = await Promise.all([\n scan(undefined, 'common'),\n scan('fumadocs/sanity', 'sanity'),\n scan('fumadocs/openapi', 'openapi'),\n scan('fumadocs/api-docs', 'api-docs'),\n scan(subRegistry, 'ui'),\n ]);\n\n spin.stop(picocolors.bold(picocolors.greenBright('registry fetched')));\n const value = await autocompleteMultiselect({\n message: 'Select components to install',\n options: groups.flat().sort((a, b) => a.label.localeCompare(b.label)),\n });\n\n if (isCancel(value)) {\n outro('Ended');\n return;\n }\n\n targets = value;\n } else {\n targets = await Promise.all(\n input.map(async (item) =>\n (await connector.hasComponent(item)) ? { name: item } : { subRegistry, name: item },\n ),\n );\n }\n\n for (const target of targets) {\n await installer.installInteractive(target.name, target.subRegistry);\n }\n\n outro(picocolors.bold(picocolors.greenBright('Successful')));\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 astro: 'dist/export/epub',\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\nexport async function exportEpub(options: { output?: string; framework: string }) {\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 const pkg = await readPackageJson(cwd);\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 if (res.status === 404) {\n console.error(\n picocolors.red('Export route not found, run `fumadocs feature epub` to create it.'),\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","import type { CAC, Command } from 'cac';\nimport { cancel, confirm, intro, log, note, outro, select, spinner } from '@clack/prompts';\nimport { isCancel } from '@/utils/prompt';\nimport picocolors from 'picocolors';\nimport type { RegistryConnector } from 'fuma-cli/registry/connector';\nimport { createOrLoadConfig } from '@/config';\nimport { loadProject } from '@/project';\nimport { type AnyFeature, type FeatureIO, runFeature } from '@/features';\nimport { features } from '@/features/all';\n\ninterface CommandOptions extends Record<string, string | boolean | undefined> {\n config?: string;\n dir?: string;\n yes?: boolean;\n install?: boolean;\n}\n\nexport function registerFeatureCommands(\n cli: CAC,\n createConnector: (dir?: string) => RegistryConnector,\n) {\n const ids = features.map((feature) => feature.id).join(', ');\n\n register(\n cli.command('feature <id>', `configure a feature on your project (${ids})`),\n features,\n ).action(async (id: string, options: CommandOptions) => {\n const feature = features.find((item) => item.id === id);\n if (!feature) throw new Error(`unknown feature: ${id}, available: ${ids}`);\n\n await run(feature, options, createConnector(options.dir));\n });\n\n register(cli.command('init', 'set up Fumadocs on an existing app, same as `feature docs`'), [\n features[0],\n ]).action(async (options: CommandOptions) => {\n await run(features[0], options, createConnector(options.dir));\n });\n}\n\nfunction register(command: Command, list: AnyFeature[]) {\n command\n .option('--dir <string>', 'the root url or directory to resolve registry')\n .option('-y, --yes', 'skip prompts, overwrite existing files')\n .option('--no-install', 'write dependencies to package.json without installing');\n\n for (const feature of list) {\n for (const [key, option] of Object.entries(feature.options ?? {})) {\n if ('choices' in option) {\n command.option(\n `--${key} <value>`,\n `${option.message} (${option.choices.map((choice) => choice.value).join(', ')})`,\n );\n } else {\n command.option(`--${key}`, option.message);\n }\n }\n }\n\n return command;\n}\n\nasync function run(feature: AnyFeature, options: CommandOptions, connector: RegistryConnector) {\n intro(picocolors.bgBlack(picocolors.whiteBright(feature.title)));\n const config = await createOrLoadConfig(options.config);\n const project = await loadProject(config);\n log.info(`${project.framework}${project.static ? ' (static)' : ''}, ${project.packageManager}`);\n\n const values: Record<string, unknown> = {};\n for (const [key, option] of Object.entries(feature.options ?? {})) {\n const given = options[key];\n if ('choices' in option) {\n if (given !== undefined) {\n if (!option.choices.some((choice) => choice.value === given))\n throw new Error(`invalid value for --${key}: ${given}`);\n values[key] = given;\n continue;\n }\n\n const value = await select({ message: option.message, options: option.choices });\n if (isCancel(value)) {\n cancel('Stopped.');\n process.exit(0);\n }\n values[key] = value;\n } else if (given !== undefined) {\n values[key] = given === true;\n } else if (options.yes) {\n values[key] = option.initialValue ?? false;\n } else {\n const value = await confirm({ message: option.message, initialValue: option.initialValue });\n if (isCancel(value)) {\n cancel('Stopped.');\n process.exit(0);\n }\n values[key] = value;\n }\n }\n\n const spin = spinner();\n const io: FeatureIO = {\n installDependencies: options.install !== false,\n log: (message) => spin.message(message),\n async confirmOverwrite(file) {\n if (options.yes) return true;\n spin.clear();\n const value = await confirm({ message: `Overwrite ${file}?`, initialValue: false });\n if (isCancel(value)) {\n cancel('Stopped.');\n process.exit(0);\n }\n spin.start();\n return value;\n },\n };\n\n spin.start(`Applying ${feature.title}`);\n try {\n const { notes } = await runFeature(feature, values, { project, connector, io });\n spin.stop(`${feature.title} applied`);\n if (notes.length > 0) note(notes.join('\\n\\n'), 'What is Next?');\n } catch (e) {\n spin.error(e instanceof Error ? e.message : String(e));\n process.exit(1);\n }\n outro(picocolors.bold(picocolors.greenBright('Done')));\n}\n","#!/usr/bin/env node\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { cac } from 'cac';\nimport picocolors from 'picocolors';\nimport { createOrLoadConfig, initConfig } 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 { registerFeatureCommands } from '@/commands/feature';\nimport { HttpRegistryConnector, LocalRegistryConnector } from 'fuma-cli/registry/connector';\n\nconst cli = cac('fumadocs');\ncli.option('--config <string>', 'path to the config file');\n\ncli.command('', 'init a `cli.json` config file').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\ncli\n .command('customise', 'simple way to customize layouts with Fumadocs UI')\n .alias('customize')\n .option('--dir <string>', 'the root url or directory to resolve registry')\n .action(async (options: { config?: string; dir?: string }) => {\n const config = await createOrLoadConfig(options.config);\n await customise(config, createClientFromDir(options.dir));\n });\n\nconst dirShortcuts: Record<string, string> = {\n ':preview': 'https://preview.fumadocs.dev/registry',\n ':dev': 'http://localhost:3000/registry',\n};\n\ncli\n .command('add [...components]', 'add a new component to your docs')\n .option('--dir <string>', 'the root url or directory to resolve registry')\n .action(async (input: string[], options: { config?: string; dir?: string }) => {\n const config = await createOrLoadConfig(options.config);\n const client = createClientFromDir(options.dir);\n await add(input, client, config);\n });\n\nregisterFeatureCommands(cli, createClientFromDir);\n\ncli\n .command(\n 'export <format>',\n 'export documentation to various formats (run after production build)',\n )\n .option('--framework <name>', 'framework: next, astro, tanstack-start, react-router, waku')\n .option('--output <path>', 'output file path', { default: 'docs.epub' })\n .action(async (format: string, options: { framework?: string; output: string }) => {\n if (format !== 'epub')\n throw new Error(`unsupported format: ${format}, only \\`epub\\` is supported.`);\n if (!options.framework) throw new Error('option `--framework <name>` is required.');\n\n await exportEpub({ framework: options.framework, output: options.output });\n });\n\ncli\n .command(\n 'tree [json_or_args] [output]',\n 'generate a file tree for the Files component, from a directory or JSON output of `tree`',\n )\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') {\n if (dir in dirShortcuts) dir = dirShortcuts[dir];\n\n return dir.startsWith('http://') || dir.startsWith('https://')\n ? new HttpRegistryConnector(dir)\n : new LocalRegistryConnector(dir);\n}\n\ncli.help();\ncli.version(packageJson.version);\n\ntry {\n cli.parse(process.argv, { run: false });\n await cli.runMatchedCommand();\n} catch (e) {\n console.error(picocolors.redBright(e instanceof Error ? e.message : String(e)));\n process.exit(1);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["isCancel","isCancel","packageJson.version"],"sources":["../src/commands/file-tree.ts","../src/utils/file-tree/run-tree.ts","../package.json","../src/commands/customise.ts","../src/commands/add.ts","../src/commands/export-epub.ts","../src/commands/feature.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","","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { cancel, group, intro, log, outro, select } from '@clack/prompts';\nimport picocolors from 'picocolors';\nimport { parseSourceFile } from '@/codemod';\nimport { frameworks } from '@/project';\nimport type { Target } from '@/commands/add';\nimport { UIRegistries } from '@/commands/shared';\nimport { LoadedConfig } from '@/config';\nimport { RegistryConnector } from 'fuma-cli/registry/connector';\nimport { FumadocsComponentInstaller } from '@/registry/installer';\n\ninterface TargetInfo {\n targets: Target[];\n id: string;\n print?: () => void | Promise<void>;\n}\n\ninterface SlotPrintInfo {\n at: string;\n layoutId: string;\n name: string;\n isPage: boolean;\n uiLibrary: LoadedConfig['uiLibrary'];\n}\n\nexport async function customise(config: LoadedConfig, connector: RegistryConnector) {\n intro(picocolors.bgBlack(picocolors.whiteBright('Customize Fumadocs UI')));\n\n const installer = new FumadocsComponentInstaller(connector, config);\n const subRegistry = UIRegistries[config.uiLibrary];\n const info = await connector.fetchRegistryInfo(subRegistry);\n\n const result = await group(\n {\n layout: (): Promise<TargetInfo | symbol> =>\n select({\n message: 'What do you want to customize?',\n options: [\n {\n label: 'Docs Layout',\n value: {\n id: 'docs',\n targets: [{ subRegistry, name: 'layouts/docs' }],\n print: () =>\n printLayout(\n config,\n ['fumadocs-ui/layouts/docs', '@/layouts/docs'],\n ['fumadocs-ui/layouts/docs/page', '@/layouts/docs/page'],\n ),\n },\n hint: 'the default docs layout',\n },\n {\n label: 'Notebook Layout',\n value: {\n id: 'notebook',\n targets: [{ subRegistry, name: 'layouts/notebook' }],\n print: () =>\n printLayout(\n config,\n ['fumadocs-ui/layouts/notebook', '@/layouts/notebook'],\n ['fumadocs-ui/layouts/notebook/page', '@/layouts/notebook/page'],\n ),\n },\n hint: 'a more compact version of docs layout',\n },\n {\n label: 'Flux Layout',\n value: {\n id: 'flux',\n targets: [{ subRegistry, name: 'layouts/flux' }],\n print: () =>\n printLayout(\n config,\n ['fumadocs-ui/layouts/flux', '@/layouts/flux'],\n ['fumadocs-ui/layouts/flux/page', '@/layouts/flux/page'],\n ),\n },\n hint: 'the experimental variant of docs layout',\n },\n {\n label: 'Glass Layout',\n value: {\n id: 'glass',\n targets: [{ subRegistry, name: 'layouts/glass' }],\n print: () =>\n printLayout(\n config,\n ['fumadocs-ui/layouts/glass', '@/layouts/glass'],\n ['fumadocs-ui/layouts/glass/page', '@/layouts/glass/page'],\n ),\n },\n hint: 'a docs layout with floating, translucent panels',\n },\n {\n label: 'Home Layout',\n value: {\n id: 'home',\n targets: [{ subRegistry, name: 'layouts/home' }],\n print: () => printLayout(config, ['fumadocs-ui/layouts/home', '@/layouts/home']),\n },\n hint: 'the layout for other non-docs pages',\n },\n ],\n }),\n target: (v): Promise<TargetInfo | symbol> => {\n const selected = v.results.layout!;\n if (selected.id === 'home') return Promise.resolve(selected);\n\n return select<TargetInfo>({\n message: 'Which part do you want to customize?',\n options: [\n {\n label: 'All',\n hint: 'install the entire layout',\n value: selected,\n },\n {\n label: 'Replace & rewrite from minimal styles',\n hint: 'for those who want to build their own UI from ground up',\n value: {\n id: 'docs-min',\n targets: [{ name: 'layouts/docs-min' }],\n print: () =>\n printLayout(\n config,\n ['fumadocs-ui/layouts/docs', '@/layouts/docs'],\n ['fumadocs-ui/layouts/docs/page', '@/layouts/docs/page'],\n ),\n },\n },\n ...info.unlistedIndexes.flatMap((index) => {\n const prefix = `slots/${selected.id}`;\n if (!index.name.startsWith(prefix)) return [];\n let name = index.name.slice(prefix.length + 1);\n\n if (name.startsWith('page/')) {\n name = name.slice('page/'.length);\n\n return {\n label: `Page: ${name}`,\n hint: \"only replace a part of layout's page, useful for adjusting details\",\n value: {\n id: index.name,\n targets: [{ subRegistry, name: index.name }],\n print() {\n printSlot({\n at: `@/layouts/${selected.id}/page/slots/${name}`,\n layoutId: selected.id,\n name,\n isPage: true,\n uiLibrary: config.uiLibrary,\n });\n },\n } as TargetInfo,\n };\n }\n\n return {\n label: `Layout: ${name}`,\n hint: 'only replace a part of layout, useful for adjusting details',\n value: {\n id: index.name,\n targets: [{ subRegistry, name: index.name }],\n print() {\n printSlot({\n at: `@/layouts/${selected.id}/slots/${name}`,\n layoutId: selected.id,\n name,\n isPage: false,\n uiLibrary: config.uiLibrary,\n });\n },\n } as TargetInfo,\n };\n }),\n ],\n });\n },\n },\n {\n onCancel: () => {\n cancel('Installation Stopped.');\n process.exit(0);\n },\n },\n );\n\n const targetInfo = result.target as TargetInfo;\n for (const target of targetInfo.targets) {\n await installer.installInteractive(target.name, target.subRegistry);\n }\n\n await targetInfo.print?.();\n\n outro(picocolors.bold('Have fun!'));\n}\n\n/** point the imports of route files at the installed layouts */\nexport async function rewriteLayoutImports(config: LoadedConfig, map: Map<string, string>) {\n const dir = path.join(config.baseDir, frameworks[config.framework].routesDir);\n const entries = await fs.readdir(dir, { recursive: true, withFileTypes: true }).catch(() => []);\n const updated: string[] = [];\n\n for (const entry of entries) {\n if (!entry.isFile() || !entry.name.endsWith('.tsx')) continue;\n const file = path.join(entry.parentPath, entry.name);\n const source = parseSourceFile(file, await fs.readFile(file, 'utf-8'));\n for (const node of source.program.body) {\n if (node.type !== 'ImportDeclaration') continue;\n const to = map.get(node.source.value);\n if (to) source.s.overwrite(node.source.start + 1, node.source.end - 1, to);\n }\n if (!source.s.hasChanged()) continue;\n await source.save();\n updated.push(file);\n }\n\n return updated;\n}\n\nasync function printLayout(config: LoadedConfig, ...maps: [from: string, to: string][]) {\n intro(picocolors.bold('What is Next?'));\n const updated = await rewriteLayoutImports(config, new Map(maps));\n\n log.info(\n [\n 'You can check the installed layouts in `layouts` folder.',\n picocolors.dim('---'),\n updated.length > 0\n ? `Updated the imports of ${updated.join(', ')}.`\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\nfunction printSlot({ at, layoutId, name, isPage, uiLibrary }: SlotPrintInfo) {\n intro(picocolors.bold('What is Next?'));\n\n log.info(`You can check the installed layout slot in \"${at}\".`);\n\n const code = getSlotCode({ at, layoutId, name, isPage, uiLibrary });\n\n if (code) {\n const layoutComponent = layoutId === 'glass' ? '<GlassLayout />' : '<DocsLayout />';\n\n if (isPage) {\n log.info(\n `${picocolors.bold('At your <DocsPage /> component, update your \"slots\" prop:')}\\n\\n${code}`,\n );\n } else {\n log.info(\n `${picocolors.bold(`At your ${layoutComponent} component, update your \"slots\" prop:`)}\\n\\n${code}`,\n );\n }\n }\n}\n\nfunction getSlotCode({ at, layoutId, name, isPage, uiLibrary }: SlotPrintInfo): string | undefined {\n if (layoutId === 'glass') {\n // Glass layout wires its page slots directly, only layout-level slots are swappable.\n if (isPage) return;\n\n switch (name) {\n case 'header':\n return `import { Header } from '${at}';\n\nreturn (\n <GlassLayout\n slots={{\n header: Header,\n }}\n >\n ...\n </GlassLayout>\n);`;\n case 'sidebar': {\n // `sidebar` slot file holds the whole sidebar system (desktop, mobile drawer, provider).\n // Base UI additionally exposes a `drawerHandle` for its swipeable drawer.\n const imports = ['Sidebar', 'SidebarDrawer', 'SidebarProvider', 'useSidebar'];\n if (uiLibrary === 'base-ui') imports.push('drawerHandle');\n\n return `import { ${imports.join(', ')} } from '${at}';\n\nreturn (\n <GlassLayout\n slots={{\n sidebar: {\n main: Sidebar,\n provider: SidebarProvider,\n use: useSidebar,\n drawer: SidebarDrawer,${uiLibrary === 'base-ui' ? '\\n drawerHandle,' : ''}\n },\n }}\n >\n ...\n </GlassLayout>\n);`;\n }\n default:\n return;\n }\n }\n\n if (isPage) {\n switch (name) {\n case 'toc':\n if (layoutId === 'flux') {\n return `import { TOCProvider, TOC } from '${at}';\n\nreturn (\n <DocsPage\n slots={{\n toc: {\n provider: TOCProvider,\n main: TOC,\n },\n }}\n >\n ...\n </DocsPage>\n);`;\n }\n\n return `import { TOCProvider, TOC, TOCPopover } from '${at}';\n\nreturn (\n <DocsPage\n slots={{\n toc: {\n provider: TOCProvider,\n main: TOC,\n popover: TOCPopover,\n },\n }}\n >\n ...\n </DocsPage>\n);`;\n case 'container': {\n return `import { Container } from '${at}';\n\nreturn (\n <DocsPage\n slots={{\n container: Container,\n }}\n >\n ...\n </DocsPage>\n);`;\n }\n case 'footer': {\n return `import { Footer } from '${at}';\n\nreturn (\n <DocsPage\n slots={{\n footer: Footer,\n }}\n >\n ...\n </DocsPage>\n);`;\n }\n case 'breadcrumb': {\n return `import { Breadcrumb } from '${at}';\n\nreturn (\n <DocsPage\n slots={{\n breadcrumb: Breadcrumb,\n }}\n >\n ...\n </DocsPage>\n);`;\n }\n default:\n return;\n }\n }\n\n switch (name) {\n case 'sidebar': {\n if (layoutId === 'notebook') {\n return `import {\n SidebarProvider,\n Sidebar,\n SidebarTrigger,\n SidebarCollapseTrigger,\n useSidebar,\n} from '${at}';\n\nreturn (\n <DocsLayout\n slots={{\n sidebar: {\n provider: SidebarProvider,\n root: Sidebar,\n trigger: SidebarTrigger,\n collapseTrigger: SidebarCollapseTrigger,\n useSidebar: useSidebar,\n },\n }}\n >\n ...\n </DocsLayout>\n);`;\n }\n\n return `import { SidebarProvider, Sidebar, SidebarTrigger, useSidebar } from '${at}';\n\nreturn (\n <DocsLayout\n slots={{\n sidebar: {\n provider: SidebarProvider,\n root: Sidebar,\n trigger: SidebarTrigger,\n useSidebar: useSidebar,\n },\n }}\n >\n ...\n </DocsLayout>\n);`;\n }\n case 'container': {\n return `import { Container } from '${at}';\n\nreturn (\n <DocsLayout\n slots={{\n container: Container,\n }}\n >\n ...\n </DocsLayout>\n);`;\n }\n case 'header': {\n return `import { Header } from '${at}';\n\nreturn (\n <DocsLayout\n slots={{\n header: Header,\n }}\n >\n ...\n </DocsLayout>\n);`;\n }\n case 'tab-dropdown': {\n return `import { TabDropdown } from '${at}';\n\nreturn (\n <DocsLayout\n slots={{\n tabDropdown: TabDropdown,\n }}\n >\n ...\n </DocsLayout>\n);`;\n }\n default:\n return;\n }\n}\n","import { autocompleteMultiselect, outro, spinner } from '@clack/prompts';\nimport { isCancel } from '@/utils/prompt';\nimport picocolors from 'picocolors';\nimport { UIRegistries } from '@/commands/shared';\nimport { RegistryConnector } from 'fuma-cli/registry/connector';\nimport { LoadedConfig } from '@/config';\nimport { FumadocsComponentInstaller } from '@/registry/installer';\n\ninterface AddOption {\n label: string;\n value: Target;\n hint?: string;\n}\n\nexport interface Target {\n name: string;\n subRegistry?: string;\n}\n\nexport async function add(input: string[], connector: RegistryConnector, config: LoadedConfig) {\n let targets: Target[];\n const installer = new FumadocsComponentInstaller(connector, config);\n const subRegistry = UIRegistries[config.uiLibrary];\n\n if (input.length === 0) {\n const spin = spinner();\n spin.start('fetching registry');\n\n async function scan(subRegistry?: string, prefix?: string): Promise<AddOption[]> {\n const info = await connector.fetchRegistryInfo(subRegistry);\n\n return info.indexes.map((item) => ({\n label: `${prefix ? `${picocolors.bold(prefix)} - ` : ''}${item.title ?? item.name}`,\n value: { name: item.name, subRegistry },\n hint: item.description,\n }));\n }\n\n const groups = await Promise.all([\n scan(undefined, 'common'),\n scan('sanity', 'sanity'),\n scan('openapi', 'openapi'),\n scan('api-docs', 'api-docs'),\n scan(subRegistry, 'ui'),\n ]);\n\n spin.stop(picocolors.bold(picocolors.greenBright('registry fetched')));\n const value = await autocompleteMultiselect({\n message: 'Select components to install',\n options: groups.flat().sort((a, b) => a.label.localeCompare(b.label)),\n });\n\n if (isCancel(value)) {\n outro('Ended');\n return;\n }\n\n targets = value;\n } else {\n targets = await Promise.all(\n input.map(async (item) =>\n (await connector.hasComponent(item)) ? { name: item } : { subRegistry, name: item },\n ),\n );\n }\n\n for (const target of targets) {\n await installer.installInteractive(target.name, target.subRegistry);\n }\n\n outro(picocolors.bold(picocolors.greenBright('Successful')));\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 astro: 'dist/export/epub',\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\nexport async function exportEpub(options: { output?: string; framework: string }) {\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 const pkg = await readPackageJson(cwd);\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 if (res.status === 404) {\n console.error(\n picocolors.red('Export route not found, run `fumadocs feature epub` to create it.'),\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","import type { CAC, Command } from 'cac';\nimport { cancel, confirm, intro, log, note, outro, select, spinner } from '@clack/prompts';\nimport { isCancel } from '@/utils/prompt';\nimport picocolors from 'picocolors';\nimport type { RegistryConnector } from 'fuma-cli/registry/connector';\nimport { createOrLoadConfig } from '@/config';\nimport { loadProject } from '@/project';\nimport { type AnyFeature, type FeatureIO, runFeature } from '@/features';\nimport { features } from '@/features/all';\n\ninterface CommandOptions extends Record<string, string | boolean | undefined> {\n config?: string;\n dir?: string;\n yes?: boolean;\n install?: boolean;\n}\n\nexport function registerFeatureCommands(\n cli: CAC,\n createConnector: (dir?: string) => RegistryConnector,\n) {\n const ids = features.map((feature) => feature.id).join(', ');\n\n register(\n cli.command('feature <id>', `configure a feature on your project (${ids})`),\n features,\n ).action(async (id: string, options: CommandOptions) => {\n const feature = features.find((item) => item.id === id);\n if (!feature) throw new Error(`unknown feature: ${id}, available: ${ids}`);\n\n await run(feature, options, createConnector(options.dir));\n });\n\n register(cli.command('init', 'set up Fumadocs on an existing app, same as `feature docs`'), [\n features[0],\n ]).action(async (options: CommandOptions) => {\n await run(features[0], options, createConnector(options.dir));\n });\n}\n\nfunction register(command: Command, list: AnyFeature[]) {\n command\n .option('--dir <string>', 'the root url or directory to resolve registry')\n .option('-y, --yes', 'skip prompts, overwrite existing files')\n .option('--no-install', 'write dependencies to package.json without installing');\n\n for (const feature of list) {\n for (const [key, option] of Object.entries(feature.options ?? {})) {\n if ('choices' in option) {\n command.option(\n `--${key} <value>`,\n `${option.message} (${option.choices.map((choice) => choice.value).join(', ')})`,\n );\n } else {\n command.option(`--${key}`, option.message);\n }\n }\n }\n\n return command;\n}\n\nasync function run(feature: AnyFeature, options: CommandOptions, connector: RegistryConnector) {\n intro(picocolors.bgBlack(picocolors.whiteBright(feature.title)));\n const config = await createOrLoadConfig(options.config);\n const project = await loadProject(config);\n log.info(`${project.framework}${project.static ? ' (static)' : ''}, ${project.packageManager}`);\n\n const values: Record<string, unknown> = {};\n for (const [key, option] of Object.entries(feature.options ?? {})) {\n const given = options[key];\n if ('choices' in option) {\n if (given !== undefined) {\n if (!option.choices.some((choice) => choice.value === given))\n throw new Error(`invalid value for --${key}: ${given}`);\n values[key] = given;\n continue;\n }\n\n const value = await select({ message: option.message, options: option.choices });\n if (isCancel(value)) {\n cancel('Stopped.');\n process.exit(0);\n }\n values[key] = value;\n } else if (given !== undefined) {\n values[key] = given === true;\n } else if (options.yes) {\n values[key] = option.initialValue ?? false;\n } else {\n const value = await confirm({ message: option.message, initialValue: option.initialValue });\n if (isCancel(value)) {\n cancel('Stopped.');\n process.exit(0);\n }\n values[key] = value;\n }\n }\n\n const spin = spinner();\n const io: FeatureIO = {\n installDependencies: options.install !== false,\n log: (message) => spin.message(message),\n async confirmOverwrite(file) {\n if (options.yes) return true;\n spin.clear();\n const value = await confirm({ message: `Overwrite ${file}?`, initialValue: false });\n if (isCancel(value)) {\n cancel('Stopped.');\n process.exit(0);\n }\n spin.start();\n return value;\n },\n };\n\n spin.start(`Applying ${feature.title}`);\n try {\n const { notes } = await runFeature(feature, values, { project, connector, io });\n spin.stop(`${feature.title} applied`);\n if (notes.length > 0) note(notes.join('\\n\\n'), 'What is Next?');\n } catch (e) {\n spin.error(e instanceof Error ? e.message : String(e));\n process.exit(1);\n }\n outro(picocolors.bold(picocolors.greenBright('Done')));\n}\n","#!/usr/bin/env node\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { cac } from 'cac';\nimport picocolors from 'picocolors';\nimport { createOrLoadConfig, initConfig } 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 { registerFeatureCommands } from '@/commands/feature';\nimport { HttpRegistryConnector, LocalRegistryConnector } from 'fuma-cli/registry/connector';\n\nconst cli = cac('fumadocs');\ncli.option('--config <string>', 'path to the config file');\n\ncli.command('', 'init a `cli.json` config file').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\ncli\n .command('customise', 'simple way to customize layouts with Fumadocs UI')\n .alias('customize')\n .option('--dir <string>', 'the root url or directory to resolve registry')\n .action(async (options: { config?: string; dir?: string }) => {\n const config = await createOrLoadConfig(options.config);\n await customise(config, createClientFromDir(options.dir));\n });\n\nconst dirShortcuts: Record<string, string> = {\n ':preview': 'https://preview.fumadocs.dev/registry',\n ':dev': 'http://localhost:3000/registry',\n};\n\ncli\n .command('add [...components]', 'add a new component to your docs')\n .option('--dir <string>', 'the root url or directory to resolve registry')\n .action(async (input: string[], options: { config?: string; dir?: string }) => {\n const config = await createOrLoadConfig(options.config);\n const client = createClientFromDir(options.dir);\n await add(input, client, config);\n });\n\nregisterFeatureCommands(cli, createClientFromDir);\n\ncli\n .command(\n 'export <format>',\n 'export documentation to various formats (run after production build)',\n )\n .option('--framework <name>', 'framework: next, astro, tanstack-start, react-router, waku')\n .option('--output <path>', 'output file path', { default: 'docs.epub' })\n .action(async (format: string, options: { framework?: string; output: string }) => {\n if (format !== 'epub')\n throw new Error(`unsupported format: ${format}, only \\`epub\\` is supported.`);\n if (!options.framework) throw new Error('option `--framework <name>` is required.');\n\n await exportEpub({ framework: options.framework, output: options.output });\n });\n\ncli\n .command(\n 'tree [json_or_args] [output]',\n 'generate a file tree for the Files component, from a directory or JSON output of `tree`',\n )\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') {\n if (dir in dirShortcuts) dir = dirShortcuts[dir];\n\n return dir.startsWith('http://') || dir.startsWith('https://')\n ? new HttpRegistryConnector(dir)\n : new LocalRegistryConnector(dir);\n}\n\ncli.help();\ncli.version(packageJson.version);\n\ntry {\n cli.parse(process.argv, { run: false });\n await cli.runMatchedCommand();\n} catch (e) {\n console.error(picocolors.redBright(e instanceof Error ? e.message : String(e)));\n process.exit(1);\n}\n"],"mappings":"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"}