@fumadocs/cli 1.7.4 → 1.7.6

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 (114) hide show
  1. package/dist/{ai-BoUGzPvv.js → ai-CvrtLYh1.js} +8 -6
  2. package/dist/ai-CvrtLYh1.js.map +1 -0
  3. package/dist/all-bAINnjNQ.js +26 -0
  4. package/dist/{all-BmTB7dab.js.map → all-bAINnjNQ.js.map} +1 -1
  5. package/dist/codemod/index.d.ts +1 -1
  6. package/dist/codemod/index.js +1 -2
  7. package/dist/{codemod-auol-p4R.js → codemod-Wc9nRqrw.js} +60 -39
  8. package/dist/codemod-Wc9nRqrw.js.map +1 -0
  9. package/dist/{config-Bw0kmF01.js → config-BpiQyqBs.js} +13 -8
  10. package/dist/config-BpiQyqBs.js.map +1 -0
  11. package/dist/{config-Bfg4yG8S.d.ts → config-Z-4b_Y_C.d.ts} +1 -3
  12. package/dist/config-Z-4b_Y_C.d.ts.map +1 -0
  13. package/dist/config.d.ts +1 -1
  14. package/dist/config.js +1 -2
  15. package/dist/{docs-qRGwd9Yp.js → docs---dy-BSm.js} +286 -32
  16. package/dist/docs---dy-BSm.js.map +1 -0
  17. package/dist/{epub-DbOh5Q2D.js → epub-BKvZ4ppz.js} +12 -13
  18. package/dist/epub-BKvZ4ppz.js.map +1 -0
  19. package/dist/features/ai.d.ts +2 -3
  20. package/dist/features/ai.d.ts.map +1 -1
  21. package/dist/features/ai.js +1 -2
  22. package/dist/features/all.d.ts +1 -3
  23. package/dist/features/all.d.ts.map +1 -1
  24. package/dist/features/all.js +1 -2
  25. package/dist/features/docs/index.d.ts +2 -4
  26. package/dist/features/docs/index.d.ts.map +1 -1
  27. package/dist/features/docs/index.js +1 -2
  28. package/dist/features/epub.d.ts +1 -3
  29. package/dist/features/epub.d.ts.map +1 -1
  30. package/dist/features/epub.js +1 -2
  31. package/dist/features/feedback.d.ts +1 -3
  32. package/dist/features/feedback.d.ts.map +1 -1
  33. package/dist/features/feedback.js +1 -2
  34. package/dist/features/index.d.ts +1 -1
  35. package/dist/features/index.js +1 -2
  36. package/dist/features/lint.d.ts +1 -3
  37. package/dist/features/lint.d.ts.map +1 -1
  38. package/dist/features/lint.js +1 -2
  39. package/dist/features/llms.d.ts +6 -7
  40. package/dist/features/llms.d.ts.map +1 -1
  41. package/dist/features/llms.js +1 -2
  42. package/dist/features/mcp.d.ts +5 -7
  43. package/dist/features/mcp.d.ts.map +1 -1
  44. package/dist/features/mcp.js +1 -2
  45. package/dist/features/og.d.ts +2 -3
  46. package/dist/features/og.d.ts.map +1 -1
  47. package/dist/features/og.js +1 -2
  48. package/dist/features/search.d.ts +10 -10
  49. package/dist/features/search.d.ts.map +1 -1
  50. package/dist/features/search.js +1 -2
  51. package/dist/features/utils.d.ts +2 -2
  52. package/dist/features/utils.js +1 -2
  53. package/dist/features/webmcp.d.ts +2 -3
  54. package/dist/features/webmcp.d.ts.map +1 -1
  55. package/dist/features/webmcp.js +1 -2
  56. package/dist/{features-Do6x9Tsz.js → features-C_FG2WD0.js} +5 -6
  57. package/dist/{features-Do6x9Tsz.js.map → features-C_FG2WD0.js.map} +1 -1
  58. package/dist/{feedback-DpXYMKtX.js → feedback-7u1-eklc.js} +6 -7
  59. package/dist/feedback-7u1-eklc.js.map +1 -0
  60. package/dist/{fs-D6J9dOEx.js → fs-Dqr1VJSD.js} +2 -3
  61. package/dist/{fs-D6J9dOEx.js.map → fs-Dqr1VJSD.js.map} +1 -1
  62. package/dist/{index-Cs7hw2un.d.ts → index-CAIqrY1S.d.ts} +3 -5
  63. package/dist/index-CAIqrY1S.d.ts.map +1 -0
  64. package/dist/{index-DI66DoV8.d.ts → index-DCJbgkgf.d.ts} +4 -8
  65. package/dist/index-DCJbgkgf.d.ts.map +1 -0
  66. package/dist/{index-Ck0EPdgu.d.ts → index-w9FHKPPs.d.ts} +6 -16
  67. package/dist/index-w9FHKPPs.d.ts.map +1 -0
  68. package/dist/index.js +22 -31
  69. package/dist/index.js.map +1 -1
  70. package/dist/{installer-C4662Woc.js → installer-CEOV0fBv.js} +3 -5
  71. package/dist/{installer-C4662Woc.js.map → installer-CEOV0fBv.js.map} +1 -1
  72. package/dist/{lint-zkXUULgO.js → lint-AC2ClOfa.js} +3 -4
  73. package/dist/{lint-zkXUULgO.js.map → lint-AC2ClOfa.js.map} +1 -1
  74. package/dist/{llms-DQzAst6R.js → llms-Cge1uefC.js} +11 -12
  75. package/dist/llms-Cge1uefC.js.map +1 -0
  76. package/dist/{mcp-BpFZ_fdV.js → mcp-BVpVFl6G.js} +7 -9
  77. package/dist/mcp-BVpVFl6G.js.map +1 -0
  78. package/dist/{og-m0CwRlRz.js → og-DuPd9kNq.js} +12 -11
  79. package/dist/og-DuPd9kNq.js.map +1 -0
  80. package/dist/project/index.d.ts +2 -2
  81. package/dist/project/index.js +1 -2
  82. package/dist/{project-DwRVTm4p.js → project-D655VGTX.js} +19 -10
  83. package/dist/project-D655VGTX.js.map +1 -0
  84. package/dist/registry/installer.d.ts +1 -3
  85. package/dist/registry/installer.d.ts.map +1 -1
  86. package/dist/registry/installer.js +1 -2
  87. package/dist/{search-BCHEW0-K.js → search-B44II4bM.js} +39 -30
  88. package/dist/search-B44II4bM.js.map +1 -0
  89. package/dist/{utils-DbMe7h6c.js → utils-Btt-BJ53.js} +6 -12
  90. package/dist/utils-Btt-BJ53.js.map +1 -0
  91. package/dist/{utils-CxJ7kw39.d.ts → utils-DlGz_4va.d.ts} +6 -12
  92. package/dist/utils-DlGz_4va.d.ts.map +1 -0
  93. package/dist/{webmcp-I9L7xzmw.js → webmcp-lY3_RsR3.js} +6 -8
  94. package/dist/webmcp-lY3_RsR3.js.map +1 -0
  95. package/package.json +7 -7
  96. package/dist/ai-BoUGzPvv.js.map +0 -1
  97. package/dist/all-BmTB7dab.js +0 -27
  98. package/dist/codemod-auol-p4R.js.map +0 -1
  99. package/dist/config-Bfg4yG8S.d.ts.map +0 -1
  100. package/dist/config-Bw0kmF01.js.map +0 -1
  101. package/dist/docs-qRGwd9Yp.js.map +0 -1
  102. package/dist/epub-DbOh5Q2D.js.map +0 -1
  103. package/dist/feedback-DpXYMKtX.js.map +0 -1
  104. package/dist/index-Ck0EPdgu.d.ts.map +0 -1
  105. package/dist/index-Cs7hw2un.d.ts.map +0 -1
  106. package/dist/index-DI66DoV8.d.ts.map +0 -1
  107. package/dist/llms-DQzAst6R.js.map +0 -1
  108. package/dist/mcp-BpFZ_fdV.js.map +0 -1
  109. package/dist/og-m0CwRlRz.js.map +0 -1
  110. package/dist/project-DwRVTm4p.js.map +0 -1
  111. package/dist/search-BCHEW0-K.js.map +0 -1
  112. package/dist/utils-CxJ7kw39.d.ts.map +0 -1
  113. package/dist/utils-DbMe7h6c.js.map +0 -1
  114. package/dist/webmcp-I9L7xzmw.js.map +0 -1
@@ -1,10 +1,7 @@
1
- import { r as LoadedConfig } from "./config-Bfg4yG8S.js";
1
+ import { r as LoadedConfig } from "./config-Z-4b_Y_C.js";
2
2
  import { detectFramework as detectFramework$1, detectPackageManager } from "fuma-cli/detect";
3
- //#region src/project/index.d.ts
4
3
  type PackageManager = NonNullable<Awaited<ReturnType<typeof detectPackageManager>>>['name'];
5
4
  type Framework = 'next' | 'react-router' | 'tanstack-start' | 'waku' | 'astro';
6
- /** frameworks supported by features that generate routes */
7
- type ReactFramework = Exclude<Framework, 'astro'>;
8
5
  interface FrameworkInfo {
9
6
  /** import specifier of `RootProvider` */
10
7
  provider: string;
@@ -24,7 +21,7 @@ interface SourceInfo {
24
21
  loader: boolean;
25
22
  /** `lib/source.ts` exports `getSource()`, a runtime content source resolved on demand */
26
23
  dynamic: boolean;
27
- /** file defining the Fumadocs MDX collections, relative to cwd: `lib/source.ts` (macro) or `source.config.ts`; `null` for other content sources */
24
+ /** file configuring the collections, relative to cwd: `lib/source.ts` (Fumadocs MDX macro), `source.config.ts` or the Astro config; `null` for other content sources */
28
25
  collections: string | null;
29
26
  /** collections are loaded lazily, `structuredData` is a function */
30
27
  async: boolean;
@@ -59,6 +56,5 @@ interface Project {
59
56
  }
60
57
  declare function isSupportedFramework(v: string): v is Framework;
61
58
  declare function loadProject(config: LoadedConfig, cwd?: string, framework?: Framework): Promise<Project>;
62
- //#endregion
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-DI66DoV8.d.ts.map
59
+ export { Project as a, frameworks as c, PackageManager as i, isSupportedFramework as l, FrameworkInfo as n, SourceInfo as o, I18nInfo as r, detectFramework$1 as s, Framework as t, loadProject as u };
60
+ //# sourceMappingURL=index-DCJbgkgf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-DCJbgkgf.d.ts","names":[],"sources":["../src/project/index.ts"],"mappings":";;KAMY,iBAAiB,YAAY,QAAQ,kBAAkB;KAEvD;UAEK;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA,YAAY;;cAGD,YAAY,OAAO,WAAW;;UAqC1B;;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,6 +1,5 @@
1
1
  import { ArrayExpression, ExportDefaultDeclaration, JSXElement, JSXOpeningElement, Node, ObjectExpression, ObjectProperty, Program } from "oxc-parser";
2
2
  import MagicString from "magic-string";
3
- //#region src/codemod/shared.d.ts
4
3
  type NodeOfType<T extends Node['type']> = Extract<Node, {
5
4
  type: T;
6
5
  }>;
@@ -48,21 +47,21 @@ declare function addElements(file: SourceFile, container: Container, items: stri
48
47
  * Remove the items of an array or object literal that don't pass the filter
49
48
  */
50
49
  declare function filterElements<C extends Container>(file: SourceFile, container: C, keep: (element: ElementOf<C>) => boolean): void;
51
- //#endregion
52
- //#region src/codemod/config.d.ts
53
50
  /**
54
51
  * The options object of a config file, e.g. the argument of `defineConfig({ ... })`, or the object in `export default { ... }`
55
52
  */
56
53
  declare function getConfigObject(file: SourceFile): ObjectExpression | undefined;
57
54
  /**
58
- * Add a plugin call to the `plugins` array of a Vite config, skip if the same plugin is already added.
55
+ * Add a plugin call to an array of a config file, like the `plugins` of Vite or the `integrations` of Astro, skip if the same plugin is already added.
59
56
  *
60
- * @param path - property path to the plugins array, e.g. `['vite', 'plugins']` for Waku
57
+ * @param path - property path to the array, e.g. `['vite', 'plugins']` for Waku, missing objects on it are created
61
58
  */
62
59
  declare function addVitePlugin(file: SourceFile, plugin: {
63
60
  name: string;
64
61
  from: string;
65
62
  call?: string;
63
+ /** imported as the default export */
64
+ default?: boolean;
66
65
  }, path?: string[]): boolean;
67
66
  /**
68
67
  * Wrap the default export of `next.config.*` with `createMDX()`
@@ -75,8 +74,6 @@ declare function addNextRewrites(file: SourceFile, rewrites: {
75
74
  source: string;
76
75
  destination: string;
77
76
  }[]): boolean;
78
- //#endregion
79
- //#region src/codemod/react-router.d.ts
80
77
  /**
81
78
  * filter items in a specific array initializer in the prerender function
82
79
  */
@@ -99,28 +96,21 @@ declare function filterReactRouterRoute(file: SourceFile, filter: (item: {
99
96
  path: string;
100
97
  entry: string;
101
98
  }) => boolean): void;
102
- //#endregion
103
- //#region src/codemod/tanstack-start.d.ts
104
99
  /**
105
100
  * Add path to the `pages` array in tanstack start vite config.
106
101
  *
107
102
  * If the `pages` property doesn't exist, create one.
108
103
  */
109
104
  declare function addTanstackPrerender(file: SourceFile, paths: string[]): void;
110
- //#endregion
111
- //#region src/codemod/source.d.ts
112
105
  /**
113
- * Enable `includeProcessedMarkdown` on the `defineDocs()` call
106
+ * Enable `includeProcessedMarkdown` on the `defineDocs()` call, or on the Fumadocs integration of an Astro config
114
107
  *
115
108
  * @returns `false` if the call cannot be found
116
109
  */
117
110
  declare function enableProcessedMarkdown(file: SourceFile): boolean;
118
- //#endregion
119
- //#region src/codemod/next-proxy.d.ts
120
111
  /**
121
112
  * Add patterns to the `matcher` of `export const config` in a Next.js proxy (middleware) file
122
113
  */
123
114
  declare function addProxyMatcher(file: SourceFile, patterns: string[]): boolean;
124
- //#endregion
125
115
  export { getDefaultExport as C, parseSourceFile as D, lineIndent as E, prependJsxChildren as O, findJsxElement as S, getStringValue as T, appendJsxChildren as _, addReactRouterRoute as a, filterElements as b, addNextRewrites as c, wrapNextConfig as d, NodeOfType as f, addJsxAttribute as g, addImport as h, addReactRouterPrerenderArray as i, addVitePlugin as l, addElements as m, enableProcessedMarkdown as n, filterReactRouterPrerenderArray as o, SourceFile as p, addTanstackPrerender as r, filterReactRouterRoute as s, addProxyMatcher as t, getConfigObject as u, createSourceFile as v, getProperty as w, find as x, descendants as y };
126
- //# sourceMappingURL=index-Ck0EPdgu.d.ts.map
116
+ //# sourceMappingURL=index-w9FHKPPs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-w9FHKPPs.d.ts","names":[],"sources":["../src/codemod/shared.ts","../src/codemod/config.ts","../src/codemod/react-router.ts","../src/codemod/tanstack-start.ts","../src/codemod/source.ts","../src/codemod/next-proxy.ts"],"mappings":";;KAgBY,WAAW,UAAU,gBAAgB,QAAQ;EAAQ,MAAM;;UAEtD;EACf;;EAEA;EACA,SAAS;;EAET,GAAG;EACH,QAAQ;;iBAGM,gBAAgB,cAAc,eAAe;iBAcvC,iBAAiB,eAAe,QAAQ;;iBAK9C,eAAe,MAAM;iBAMpB,YAAY,MAAM,OAAO,UAAU;iBAapC,KAAK,UAAU,cAC7B,MAAM,MACN,MAAM,GACN,aAAa,MAAM,WAAW,iBAC7B,WAAW;iBAOE,iBAAiB,MAAM,aAAa;iBAIpC,eAAe,MAAM,YAAY,kBAAkB;iBAMnD,gBAAgB,MAAM,YAAY,SAAS,mBAAmB;;;;iBAa9D,mBAAmB,MAAM,YAAY,SAAS,YAAY;;;;iBAa1D,kBAAkB,MAAM,YAAY,SAAS,YAAY;iBAyBzD,YAAY,QAAQ,kBAAkB,eAAe;;iBAYrD,WAAW,cAAc;iBAKzB,UACd,MAAM,YACN;EAAe;EAAc;EAAkB;;KAkC5C,YAAY,kBAAkB;KAC9B,UAAU,UAAU,aAAa,UAAU,kBAC5C,YAAY,uCACZ;;;;iBAUY,YAAY,MAAM,YAAY,WAAW,WAAW;;;;iBAkCpD,eAAe,UAAU,WACvC,MAAM,YACN,WAAW,GACX,OAAO,SAAS,UAAU;;;;iBCpOZ,gBAAgB,MAAM,aAAa;;;;;;iBAiCnC,cACd,MAAM,YACN;EACE;EACA;EACA;;EAEA;GAEF;;;;iBA+Cc,eAAe,MAAM;;;;iBAkBrB,gBACd,MAAM,YACN;EAAY;EAAgB;;;;;iBC5Gd,gCACd,MAAM,YACN,6BACA,SAAS;;;;iBAcK,6BACd,MAAM,YACN,6BACA;;;;iBAgCc,oBACd,MAAM,YACN;EAAW;EAAc;;;;;iBAgBX,uBACd,MAAM,YACN,SAAS;EAAQ;EAAc;;;;;;;iBCvEjB,qBAAqB,MAAM,YAAY;;;;;;iBCRvC,wBAAwB,MAAM;;;;iBCF9B,gBAAgB,MAAM,YAAY"}
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import { i as initConfig, n as createOrLoadConfig } from "./config-Bw0kmF01.js";
3
- import { T as parseSourceFile } from "./codemod-auol-p4R.js";
4
- import { t as exists } from "./fs-D6J9dOEx.js";
5
- import { i as loadProject, n as frameworks } from "./project-DwRVTm4p.js";
6
- import { n as UIRegistries, t as FumadocsComponentInstaller } from "./installer-C4662Woc.js";
7
- import { t as runFeature } from "./features-Do6x9Tsz.js";
8
- import { t as features } from "./all-BmTB7dab.js";
2
+ import { i as initConfig, n as createOrLoadConfig } from "./config-BpiQyqBs.js";
3
+ import { T as parseSourceFile } from "./codemod-Wc9nRqrw.js";
4
+ import { t as exists } from "./fs-Dqr1VJSD.js";
5
+ import { i as loadProject, n as frameworks } from "./project-D655VGTX.js";
6
+ import { n as UIRegistries, t as FumadocsComponentInstaller } from "./installer-CEOV0fBv.js";
7
+ import { t as runFeature } from "./features-C_FG2WD0.js";
8
+ import { t as features } from "./all-bAINnjNQ.js";
9
9
  import fs from "node:fs/promises";
10
10
  import path from "node:path";
11
11
  import { cac } from "cac";
@@ -15,7 +15,7 @@ import { autocompleteMultiselect, cancel, confirm, group, intro, isCancel, log,
15
15
  import { exec } from "node:child_process";
16
16
  import { promisify } from "node:util";
17
17
  import { HttpRegistryConnector, LocalRegistryConnector } from "fuma-cli/registry/connector";
18
- //#region src/commands/file-tree.ts
18
+ // src/commands/file-tree.ts
19
19
  const scanned = [
20
20
  "file",
21
21
  "directory",
@@ -49,8 +49,7 @@ function treeToJavaScript(input, noRoot, importName = "fumadocs-ui/components/fi
49
49
 
50
50
  export default (${treeToMdx(input, noRoot)})`;
51
51
  }
52
- //#endregion
53
- //#region src/utils/file-tree/run-tree.ts
52
+ // src/utils/file-tree/run-tree.ts
54
53
  async function runTree(args) {
55
54
  const out = await x("tree", [
56
55
  args,
@@ -64,11 +63,9 @@ async function runTree(args) {
64
63
  throw new Error("failed to run `tree` command", { cause: e });
65
64
  }
66
65
  }
67
- //#endregion
68
- //#region package.json
69
- var version = "1.7.4";
70
- //#endregion
71
- //#region src/commands/customise.ts
66
+ // package.json
67
+ var version = "1.7.6";
68
+ // src/commands/customise.ts
72
69
  async function customise(config, connector) {
73
70
  intro(picocolors.bgBlack(picocolors.whiteBright("Customize Fumadocs UI")));
74
71
  const installer = new FumadocsComponentInstaller(connector, config);
@@ -333,8 +330,7 @@ function getSlot({ layoutId, name, isPage, uiLibrary }) {
333
330
  default: return;
334
331
  }
335
332
  }
336
- //#endregion
337
- //#region src/utils/prompt.ts
333
+ // src/utils/prompt.ts
338
334
  /**
339
335
  * `@clack/core` narrows to its own `unique symbol`, which can't exclude the wider `symbol` that
340
336
  * `@clack/prompts` returns, so a prompt result never narrows without this.
@@ -342,8 +338,7 @@ function getSlot({ layoutId, name, isPage, uiLibrary }) {
342
338
  function isCancel$1(value) {
343
339
  return isCancel(value);
344
340
  }
345
- //#endregion
346
- //#region src/commands/add.ts
341
+ // src/commands/add.ts
347
342
  async function add(input, connector, config) {
348
343
  let targets;
349
344
  const installer = new FumadocsComponentInstaller(connector, config);
@@ -395,8 +390,7 @@ async function add(input, connector, config) {
395
390
  for (const target of targets) await installer.installInteractive(target.name, target.subRegistry);
396
391
  outro(picocolors.bold(picocolors.greenBright("Successful")));
397
392
  }
398
- //#endregion
399
- //#region src/commands/export-epub.ts
393
+ // src/commands/export-epub.ts
400
394
  const execAsync = promisify(exec);
401
395
  async function readPackageJson(cwd) {
402
396
  try {
@@ -406,10 +400,10 @@ async function readPackageJson(cwd) {
406
400
  return null;
407
401
  }
408
402
  }
409
- /** Path of pre-rendered EPUB, choose one according to your React framework. Next.js fetches from the running server instead. */
403
+ /** Path of pre-rendered EPUB, choose one according to your React framework. Next.js and Astro fetch from the running server instead. */
410
404
  const EPUB_BUILD_PATHS = {
411
405
  next: "",
412
- astro: "dist/export/epub",
406
+ astro: "",
413
407
  "tanstack-start": ".output/public/export/epub",
414
408
  "tanstack-start-spa": "dist/client/export/epub",
415
409
  "react-router": "build/client/export/epub",
@@ -447,13 +441,13 @@ async function exportEpub(options) {
447
441
  process.exit(1);
448
442
  }
449
443
  }
450
- if (framework === "next") {
444
+ if (!buildPath) {
451
445
  const secret = process.env.EXPORT_SECRET;
452
446
  if (!secret) {
453
- console.error(picocolors.red("EXPORT_SECRET is required for Next.js export. Set it in your environment."));
447
+ console.error(picocolors.red("EXPORT_SECRET is required to fetch the EPUB. Set it in your environment."));
454
448
  process.exit(1);
455
449
  }
456
- const port = process.env.PORT || "3000";
450
+ const port = process.env.PORT || (framework === "astro" ? "4321" : "3000");
457
451
  const url = `http://localhost:${port}/export/epub`;
458
452
  spin.start("Fetching EPUB from server");
459
453
  const controller = new AbortController();
@@ -496,8 +490,7 @@ async function exportEpub(options) {
496
490
  await fs.copyFile(fullBuildPath, outputPath);
497
491
  spin.stop(picocolors.green(`EPUB saved to ${outputPath}`));
498
492
  }
499
- //#endregion
500
- //#region src/commands/feature.ts
493
+ // src/commands/feature.ts
501
494
  function registerFeatureCommands(cli, createConnector) {
502
495
  const ids = features.map((feature) => feature.id).join(", ");
503
496
  register(cli.command("feature <id>", `configure a feature on your project (${ids})`), features).action(async (id, options) => {
@@ -586,8 +579,7 @@ async function run(feature, options, connector) {
586
579
  }
587
580
  outro(picocolors.bold(picocolors.greenBright("Done")));
588
581
  }
589
- //#endregion
590
- //#region src/index.ts
582
+ // src/index.ts
591
583
  const cli = cac("fumadocs");
592
584
  cli.option("--config <string>", "path to the config file");
593
585
  cli.command("", "init a `cli.json` config file").action(async () => {
@@ -646,7 +638,6 @@ try {
646
638
  console.error(picocolors.redBright(e instanceof Error ? e.message : String(e)));
647
639
  process.exit(1);
648
640
  }
649
- //#endregion
650
641
  export {};
651
642
 
652
643
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["isCancel","isCancelSymbol","isCancel","isCancel","packageJson.version"],"sources":["../src/commands/file-tree.ts","../src/utils/file-tree/run-tree.ts","../package.json","../src/commands/customise.ts","../src/utils/prompt.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, type Option } 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 manifest = await installer.fetchManifest(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 ...(config.uiLibrary === 'base-ui'\n ? [\n {\n label: 'Spacious Layout',\n value: {\n id: 'spacious',\n targets: [{ subRegistry, name: 'layouts/spacious' }],\n print: () =>\n printLayout(\n config,\n ['fumadocs-ui/layouts/spacious', '@/layouts/spacious'],\n ['fumadocs-ui/layouts/spacious/page', '@/layouts/spacious/page'],\n ),\n },\n hint: 'a docs layout with the page in an inset panel, Base UI only',\n },\n ]\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 const slots: Option<TargetInfo>[] = [];\n const prefix = `layouts/${selected.id}/`;\n for (const { name: id } of manifest.components) {\n // <layout>/slots/<name> or <layout>/page/slots/<name>\n const [dir, name] = id.startsWith(prefix) ? id.slice(prefix.length).split('slots/') : [];\n if (name === undefined) continue;\n const isPage = dir === 'page/';\n\n slots.push({\n label: `${isPage ? 'Page' : 'Layout'}: ${name}`,\n hint: `only replace a part of layout${isPage ? \"'s page\" : ''}, useful for adjusting details`,\n value: {\n id,\n targets: [{ subRegistry, name: id }],\n print() {\n printSlot({\n at: `@/${id}`,\n layoutId: selected.id,\n name,\n isPage,\n uiLibrary: config.uiLibrary,\n });\n },\n },\n });\n }\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 ...slots,\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 slot = getSlot({ layoutId, name, isPage, uiLibrary });\n if (!slot) return;\n\n const [imports, value] = slot;\n // every layout names its components `DocsLayout` and `DocsPage`\n const component = isPage ? 'DocsPage' : 'DocsLayout';\n log.info(`${picocolors.bold(`At your <${component} /> component, update your \"slots\" prop:`)}\n\nimport { ${imports} } from '${at}';\n\nreturn (\n <${component}\n slots={{\n ${value},\n }}\n >\n ...\n </${component}>\n);`);\n}\n\n/** the names to import from slot file, and the entry of `slots` prop */\nfunction getSlot({\n layoutId,\n name,\n isPage,\n uiLibrary,\n}: Omit<SlotPrintInfo, 'at'>): [imports: string, value: string] | undefined {\n if (isPage) {\n // Glass layout wires its page slots directly, only layout-level slots are swappable.\n if (layoutId === 'glass') return;\n\n switch (name) {\n case 'toc':\n if (layoutId === 'flux')\n return [\n 'TOCProvider, TOC',\n `toc: {\n provider: TOCProvider,\n main: TOC,\n }`,\n ];\n if (layoutId === 'spacious')\n return [\n 'TOCProvider, TOC, TOCPopover, TOCDropdown',\n `toc: {\n provider: TOCProvider,\n main: TOC,\n popover: TOCPopover,\n dropdown: TOCDropdown,\n }`,\n ];\n return [\n 'TOCProvider, TOC, TOCPopover',\n `toc: {\n provider: TOCProvider,\n main: TOC,\n popover: TOCPopover,\n }`,\n ];\n case 'container':\n return ['Container', 'container: Container'];\n case 'footer':\n return ['Footer', 'footer: Footer'];\n case 'breadcrumb':\n return ['Breadcrumb', 'breadcrumb: Breadcrumb'];\n default:\n return;\n }\n }\n\n switch (name) {\n case 'sidebar':\n if (layoutId === 'glass') {\n // the slot file holds the whole sidebar system, Base UI additionally exposes a `drawerHandle` for its swipeable drawer\n const drawerHandle = uiLibrary === 'base-ui';\n return [\n `Sidebar, SidebarDrawer, SidebarProvider, useSidebar${drawerHandle ? ', drawerHandle' : ''}`,\n `sidebar: {\n main: Sidebar,\n provider: SidebarProvider,\n use: useSidebar,\n drawer: SidebarDrawer,${drawerHandle ? '\\n drawerHandle,' : ''}\n }`,\n ];\n }\n if (layoutId === 'spacious')\n return [\n 'Sidebar, SidebarDrawer, SidebarProvider',\n `sidebar: {\n provider: SidebarProvider,\n main: Sidebar,\n drawer: SidebarDrawer,\n }`,\n ];\n if (layoutId === 'notebook')\n return [\n 'SidebarProvider, Sidebar, SidebarTrigger, SidebarCollapseTrigger, useSidebar',\n `sidebar: {\n provider: SidebarProvider,\n root: Sidebar,\n trigger: SidebarTrigger,\n collapseTrigger: SidebarCollapseTrigger,\n useSidebar: useSidebar,\n }`,\n ];\n return [\n 'SidebarProvider, Sidebar, SidebarTrigger, useSidebar',\n `sidebar: {\n provider: SidebarProvider,\n root: Sidebar,\n trigger: SidebarTrigger,\n useSidebar: useSidebar,\n }`,\n ];\n case 'header':\n return ['Header', 'header: Header'];\n case 'container':\n return ['Container', 'container: Container'];\n case 'tab-dropdown':\n return ['TabDropdown', 'tabDropdown: TabDropdown'];\n case 'actions':\n return ['HeaderActions', 'actions: HeaderActions'];\n default:\n return;\n }\n}\n","import { isCancel as isCancelSymbol } from '@clack/prompts';\n\n/**\n * `@clack/core` narrows to its own `unique symbol`, which can't exclude the wider `symbol` that\n * `@clack/prompts` returns, so a prompt result never narrows without this.\n */\nexport function isCancel<T>(value: T | symbol): value is symbol {\n return isCancelSymbol(value);\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 manifest = await installer.fetchManifest(subRegistry);\n const options: AddOption[] = [];\n\n for (const item of manifest.components) {\n if (item.unlisted) continue;\n options.push({\n label: `${prefix ? `${picocolors.bold(prefix)} - ` : ''}${item.title ?? item.name}`,\n value: { name: item.name, subRegistry },\n hint: item.description,\n });\n }\n return options;\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 const root = new Set<string>();\n for (const item of (await installer.fetchManifest()).components) root.add(item.name);\n targets = input.map((name) => (root.has(name) ? { name } : { subRegistry, name }));\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","isCancelSymbol","isCancel","isCancel","packageJson.version"],"sources":["../src/commands/file-tree.ts","../src/utils/file-tree/run-tree.ts","../package.json","../src/commands/customise.ts","../src/utils/prompt.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, type Option } 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 manifest = await installer.fetchManifest(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 ...(config.uiLibrary === 'base-ui'\n ? [\n {\n label: 'Spacious Layout',\n value: {\n id: 'spacious',\n targets: [{ subRegistry, name: 'layouts/spacious' }],\n print: () =>\n printLayout(\n config,\n ['fumadocs-ui/layouts/spacious', '@/layouts/spacious'],\n ['fumadocs-ui/layouts/spacious/page', '@/layouts/spacious/page'],\n ),\n },\n hint: 'a docs layout with the page in an inset panel, Base UI only',\n },\n ]\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 const slots: Option<TargetInfo>[] = [];\n const prefix = `layouts/${selected.id}/`;\n for (const { name: id } of manifest.components) {\n // <layout>/slots/<name> or <layout>/page/slots/<name>\n const [dir, name] = id.startsWith(prefix) ? id.slice(prefix.length).split('slots/') : [];\n if (name === undefined) continue;\n const isPage = dir === 'page/';\n\n slots.push({\n label: `${isPage ? 'Page' : 'Layout'}: ${name}`,\n hint: `only replace a part of layout${isPage ? \"'s page\" : ''}, useful for adjusting details`,\n value: {\n id,\n targets: [{ subRegistry, name: id }],\n print() {\n printSlot({\n at: `@/${id}`,\n layoutId: selected.id,\n name,\n isPage,\n uiLibrary: config.uiLibrary,\n });\n },\n },\n });\n }\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 ...slots,\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 slot = getSlot({ layoutId, name, isPage, uiLibrary });\n if (!slot) return;\n\n const [imports, value] = slot;\n // every layout names its components `DocsLayout` and `DocsPage`\n const component = isPage ? 'DocsPage' : 'DocsLayout';\n log.info(`${picocolors.bold(`At your <${component} /> component, update your \"slots\" prop:`)}\n\nimport { ${imports} } from '${at}';\n\nreturn (\n <${component}\n slots={{\n ${value},\n }}\n >\n ...\n </${component}>\n);`);\n}\n\n/** the names to import from slot file, and the entry of `slots` prop */\nfunction getSlot({\n layoutId,\n name,\n isPage,\n uiLibrary,\n}: Omit<SlotPrintInfo, 'at'>): [imports: string, value: string] | undefined {\n if (isPage) {\n // Glass layout wires its page slots directly, only layout-level slots are swappable.\n if (layoutId === 'glass') return;\n\n switch (name) {\n case 'toc':\n if (layoutId === 'flux')\n return [\n 'TOCProvider, TOC',\n `toc: {\n provider: TOCProvider,\n main: TOC,\n }`,\n ];\n if (layoutId === 'spacious')\n return [\n 'TOCProvider, TOC, TOCPopover, TOCDropdown',\n `toc: {\n provider: TOCProvider,\n main: TOC,\n popover: TOCPopover,\n dropdown: TOCDropdown,\n }`,\n ];\n return [\n 'TOCProvider, TOC, TOCPopover',\n `toc: {\n provider: TOCProvider,\n main: TOC,\n popover: TOCPopover,\n }`,\n ];\n case 'container':\n return ['Container', 'container: Container'];\n case 'footer':\n return ['Footer', 'footer: Footer'];\n case 'breadcrumb':\n return ['Breadcrumb', 'breadcrumb: Breadcrumb'];\n default:\n return;\n }\n }\n\n switch (name) {\n case 'sidebar':\n if (layoutId === 'glass') {\n // the slot file holds the whole sidebar system, Base UI additionally exposes a `drawerHandle` for its swipeable drawer\n const drawerHandle = uiLibrary === 'base-ui';\n return [\n `Sidebar, SidebarDrawer, SidebarProvider, useSidebar${drawerHandle ? ', drawerHandle' : ''}`,\n `sidebar: {\n main: Sidebar,\n provider: SidebarProvider,\n use: useSidebar,\n drawer: SidebarDrawer,${drawerHandle ? '\\n drawerHandle,' : ''}\n }`,\n ];\n }\n if (layoutId === 'spacious')\n return [\n 'Sidebar, SidebarDrawer, SidebarProvider',\n `sidebar: {\n provider: SidebarProvider,\n main: Sidebar,\n drawer: SidebarDrawer,\n }`,\n ];\n if (layoutId === 'notebook')\n return [\n 'SidebarProvider, Sidebar, SidebarTrigger, SidebarCollapseTrigger, useSidebar',\n `sidebar: {\n provider: SidebarProvider,\n root: Sidebar,\n trigger: SidebarTrigger,\n collapseTrigger: SidebarCollapseTrigger,\n useSidebar: useSidebar,\n }`,\n ];\n return [\n 'SidebarProvider, Sidebar, SidebarTrigger, useSidebar',\n `sidebar: {\n provider: SidebarProvider,\n root: Sidebar,\n trigger: SidebarTrigger,\n useSidebar: useSidebar,\n }`,\n ];\n case 'header':\n return ['Header', 'header: Header'];\n case 'container':\n return ['Container', 'container: Container'];\n case 'tab-dropdown':\n return ['TabDropdown', 'tabDropdown: TabDropdown'];\n case 'actions':\n return ['HeaderActions', 'actions: HeaderActions'];\n default:\n return;\n }\n}\n","import { isCancel as isCancelSymbol } from '@clack/prompts';\n\n/**\n * `@clack/core` narrows to its own `unique symbol`, which can't exclude the wider `symbol` that\n * `@clack/prompts` returns, so a prompt result never narrows without this.\n */\nexport function isCancel<T>(value: T | symbol): value is symbol {\n return isCancelSymbol(value);\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 manifest = await installer.fetchManifest(subRegistry);\n const options: AddOption[] = [];\n\n for (const item of manifest.components) {\n if (item.unlisted) continue;\n options.push({\n label: `${prefix ? `${picocolors.bold(prefix)} - ` : ''}${item.title ?? item.name}`,\n value: { name: item.name, subRegistry },\n hint: item.description,\n });\n }\n return options;\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 const root = new Set<string>();\n for (const item of (await installer.fetchManifest()).components) root.add(item.name);\n targets = input.map((name) => (root.has(name) ? { name } : { subRegistry, name }));\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 and Astro fetch 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: '', // the route renders on demand\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 (!buildPath) {\n const secret = process.env.EXPORT_SECRET;\n if (!secret) {\n console.error(\n picocolors.red('EXPORT_SECRET is required to fetch the EPUB. Set it in your environment.'),\n );\n process.exit(1);\n }\n const port = process.env.PORT || (framework === 'astro' ? '4321' : '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,12 +1,11 @@
1
1
  import { InteractiveInstaller } from "@fuma-cli/interactive";
2
2
  import { reuseUI } from "fuma-cli/registry/installer";
3
- //#region src/commands/shared.ts
3
+ // src/commands/shared.ts
4
4
  const UIRegistries = {
5
5
  "base-ui": "fumadocs/base-ui",
6
6
  "radix-ui": "fumadocs/radix-ui"
7
7
  };
8
- //#endregion
9
- //#region src/registry/installer.ts
8
+ // src/registry/installer.ts
10
9
  var FumadocsComponentInstaller = class extends InteractiveInstaller {
11
10
  constructor(connector, config, cwd, io) {
12
11
  const { aliases } = config;
@@ -27,7 +26,6 @@ var FumadocsComponentInstaller = class extends InteractiveInstaller {
27
26
  });
28
27
  }
29
28
  };
30
- //#endregion
31
29
  export { UIRegistries as n, FumadocsComponentInstaller as t };
32
30
 
33
- //# sourceMappingURL=installer-C4662Woc.js.map
31
+ //# sourceMappingURL=installer-CEOV0fBv.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"installer-C4662Woc.js","names":[],"sources":["../src/commands/shared.ts","../src/registry/installer.ts"],"sourcesContent":["export const UIRegistries = {\n 'base-ui': 'fumadocs/base-ui',\n 'radix-ui': 'fumadocs/radix-ui',\n};\n","import { InteractiveInstaller } from '@fuma-cli/interactive';\nimport { reuseUI, type IOInterface } from 'fuma-cli/registry/installer';\nimport type { RegistryConnector } from 'fuma-cli/registry/connector';\nimport { UIRegistries } from '@/commands/shared';\nimport type { LoadedConfig } from '@/config';\n\nexport class FumadocsComponentInstaller extends InteractiveInstaller {\n constructor(\n connector: RegistryConnector,\n config: LoadedConfig,\n cwd?: string,\n io?: Partial<IOInterface>,\n ) {\n const { aliases } = config;\n\n super(connector, {\n cwd,\n io,\n framework: config.framework === 'astro' ? 'none' : config.framework,\n outDir: {\n base: config.baseDir,\n components: aliases.componentsDir,\n css: aliases.cssDir,\n layout: aliases.layoutDir,\n lib: aliases.libDir,\n ui: aliases.uiDir,\n },\n // other registries are compiled against Radix UI\n registryAliases: { [UIRegistries['radix-ui']]: UIRegistries[config.uiLibrary] },\n // `components/ui/*` follow the API of Shadcn UI, reuse the ones of project along with its `cn`\n plugins: [reuseUI({ files: aliases.utils ? { 'utils/cn.ts': aliases.utils } : undefined })],\n });\n }\n}\n"],"mappings":";;;AAAA,MAAa,eAAe;CAC1B,WAAW;CACX,YAAY;AACd;;;ACGA,IAAa,6BAAb,cAAgD,qBAAqB;CACnE,YACE,WACA,QACA,KACA,IACA;EACA,MAAM,EAAE,YAAY;EAEpB,MAAM,WAAW;GACf;GACA;GACA,WAAW,OAAO,cAAc,UAAU,SAAS,OAAO;GAC1D,QAAQ;IACN,MAAM,OAAO;IACb,YAAY,QAAQ;IACpB,KAAK,QAAQ;IACb,QAAQ,QAAQ;IAChB,KAAK,QAAQ;IACb,IAAI,QAAQ;GACd;GAEA,iBAAiB,GAAG,aAAa,cAAc,aAAa,OAAO,WAAW;GAE9E,SAAS,CAAC,QAAQ,EAAE,OAAO,QAAQ,QAAQ,EAAE,eAAe,QAAQ,MAAM,IAAI,KAAA,EAAU,CAAC,CAAC;EAC5F,CAAC;CACH;AACF"}
1
+ {"version":3,"file":"installer-CEOV0fBv.js","names":[],"sources":["../src/commands/shared.ts","../src/registry/installer.ts"],"sourcesContent":["export const UIRegistries = {\n 'base-ui': 'fumadocs/base-ui',\n 'radix-ui': 'fumadocs/radix-ui',\n};\n","import { InteractiveInstaller } from '@fuma-cli/interactive';\nimport { reuseUI, type IOInterface } from 'fuma-cli/registry/installer';\nimport type { RegistryConnector } from 'fuma-cli/registry/connector';\nimport { UIRegistries } from '@/commands/shared';\nimport type { LoadedConfig } from '@/config';\n\nexport class FumadocsComponentInstaller extends InteractiveInstaller {\n constructor(\n connector: RegistryConnector,\n config: LoadedConfig,\n cwd?: string,\n io?: Partial<IOInterface>,\n ) {\n const { aliases } = config;\n\n super(connector, {\n cwd,\n io,\n framework: config.framework === 'astro' ? 'none' : config.framework,\n outDir: {\n base: config.baseDir,\n components: aliases.componentsDir,\n css: aliases.cssDir,\n layout: aliases.layoutDir,\n lib: aliases.libDir,\n ui: aliases.uiDir,\n },\n // other registries are compiled against Radix UI\n registryAliases: { [UIRegistries['radix-ui']]: UIRegistries[config.uiLibrary] },\n // `components/ui/*` follow the API of Shadcn UI, reuse the ones of project along with its `cn`\n plugins: [reuseUI({ files: aliases.utils ? { 'utils/cn.ts': aliases.utils } : undefined })],\n });\n }\n}\n"],"mappings":";;;AAAA,MAAa,eAAe;CAC1B,WAAW;CACX,YAAY;AACd;;ACGA,IAAa,6BAAb,cAAgD,qBAAqB;CACnE,YACE,WACA,QACA,KACA,IACA;EACA,MAAM,EAAE,YAAY;EAEpB,MAAM,WAAW;GACf;GACA;GACA,WAAW,OAAO,cAAc,UAAU,SAAS,OAAO;GAC1D,QAAQ;IACN,MAAM,OAAO;IACb,YAAY,QAAQ;IACpB,KAAK,QAAQ;IACb,QAAQ,QAAQ;IAChB,KAAK,QAAQ;IACb,IAAI,QAAQ;GACd;GAEA,iBAAiB,GAAG,aAAa,cAAc,aAAa,OAAO,WAAW;GAE9E,SAAS,CAAC,QAAQ,EAAE,OAAO,QAAQ,QAAQ,EAAE,eAAe,QAAQ,MAAM,IAAI,KAAA,EAAU,CAAC,CAAC;EAC5F,CAAC;CACH;AACF"}
@@ -1,5 +1,5 @@
1
- import { l as scripts } from "./utils-DbMe7h6c.js";
2
- //#region src/features/lint.ts
1
+ import { s as scripts } from "./utils-Btt-BJ53.js";
2
+ // src/features/lint.ts
3
3
  const eslintConfig = `import { defineConfig, globalIgnores } from 'eslint/config';
4
4
  import nextVitals from 'eslint-config-next/core-web-vitals';
5
5
 
@@ -131,7 +131,6 @@ const lint = {
131
131
  }
132
132
  }
133
133
  };
134
- //#endregion
135
134
  export { lint as t };
136
135
 
137
- //# sourceMappingURL=lint-zkXUULgO.js.map
136
+ //# sourceMappingURL=lint-AC2ClOfa.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lint-zkXUULgO.js","names":[],"sources":["../src/features/lint.ts"],"sourcesContent":["import type { Feature } from '@/features';\nimport { scripts } from './utils';\n\nconst eslintConfig = `import { defineConfig, globalIgnores } from 'eslint/config';\nimport nextVitals from 'eslint-config-next/core-web-vitals';\n\nconst eslintConfig = defineConfig([\n ...nextVitals,\n globalIgnores([\n '.next/**',\n 'out/**',\n 'build/**',\n 'next-env.d.ts',\n '.source/**',\n ]),\n]);\n\nexport default eslintConfig;\n`;\n\nconst biomeConfig = (next: boolean) => ({\n $schema: 'https://biomejs.dev/schemas/2.2.0/schema.json',\n vcs: {\n enabled: true,\n clientKind: 'git',\n useIgnoreFile: true,\n },\n files: {\n ignoreUnknown: true,\n includes: next\n ? ['**', '!node_modules', '!.next', '!dist', '!build', '!.source']\n : ['**', '!node_modules', '!.source'],\n },\n formatter: {\n enabled: true,\n indentStyle: 'space',\n indentWidth: 2,\n },\n linter: {\n enabled: true,\n rules: {\n recommended: true,\n },\n domains: next ? { next: 'recommended', react: 'recommended' } : { react: 'recommended' },\n },\n assist: {\n actions: {\n source: {\n organizeImports: 'on',\n },\n },\n },\n});\n\nconst oxlintConfig = (next: boolean, reactVersion: string) => ({\n $schema: './node_modules/oxlint/configuration_schema.json',\n plugins: next ? ['typescript', 'react', 'import', 'nextjs'] : ['typescript', 'react', 'import'],\n categories: {},\n env: {\n builtin: true,\n },\n settings: {\n react: {\n version: reactVersion,\n },\n tailwindcss: {\n callees: ['clsx', 'cva', 'cn'],\n },\n },\n ignorePatterns: ['node_modules/', 'dist/'],\n});\n\nexport const lint: Feature<{ linter: 'eslint' | 'biome' | 'oxlint' }> = {\n id: 'lint',\n title: 'Linter',\n description: 'configure a linter',\n options: {\n linter: {\n message: 'Choose a linter',\n choices: [\n { value: 'eslint', label: 'ESLint', hint: 'Next.js only' },\n { value: 'biome', label: 'Biome' },\n { value: 'oxlint', label: 'Oxlint' },\n ],\n },\n },\n async apply(ctx, { linter }) {\n const { framework, packageJson } = ctx.project;\n const next = framework === 'next';\n const json = (content: object) => `${JSON.stringify(content, null, 2)}\\n`;\n\n switch (linter) {\n case 'eslint':\n if (!next) throw new Error('ESLint is only supported on Next.js');\n ctx.addDependencies(\n { eslint: '^9.39.4', 'eslint-config-next': packageJson.dependencies?.next ?? null },\n true,\n );\n await ctx.write('eslint.config.mjs', eslintConfig);\n await ctx.packageJson((data) => scripts(data, { lint: 'eslint' }));\n break;\n case 'biome':\n ctx.addDependencies({ '@biomejs/biome': null }, true);\n await ctx.write('biome.json', json(biomeConfig(next)));\n await ctx.packageJson((data) =>\n scripts(data, { lint: 'biome check', format: 'biome format --write' }),\n );\n break;\n case 'oxlint': {\n const react = packageJson.dependencies?.react?.replace('^', '') ?? '19.2.0';\n ctx.addDependencies({ oxlint: null }, true);\n await ctx.write('.oxlintrc.json', json(oxlintConfig(next, react)));\n await ctx.packageJson((data) => scripts(data, { lint: 'oxlint' }));\n break;\n }\n }\n },\n};\n"],"mappings":";;AAGA,MAAM,eAAe;;;;;;;;;;;;;;;;AAiBrB,MAAM,eAAe,UAAmB;CACtC,SAAS;CACT,KAAK;EACH,SAAS;EACT,YAAY;EACZ,eAAe;CACjB;CACA,OAAO;EACL,eAAe;EACf,UAAU,OACN;GAAC;GAAM;GAAiB;GAAU;GAAS;GAAU;EAAU,IAC/D;GAAC;GAAM;GAAiB;EAAU;CACxC;CACA,WAAW;EACT,SAAS;EACT,aAAa;EACb,aAAa;CACf;CACA,QAAQ;EACN,SAAS;EACT,OAAO,EACL,aAAa,KACf;EACA,SAAS,OAAO;GAAE,MAAM;GAAe,OAAO;EAAc,IAAI,EAAE,OAAO,cAAc;CACzF;CACA,QAAQ,EACN,SAAS,EACP,QAAQ,EACN,iBAAiB,KACnB,EACF,EACF;AACF;AAEA,MAAM,gBAAgB,MAAe,kBAA0B;CAC7D,SAAS;CACT,SAAS,OAAO;EAAC;EAAc;EAAS;EAAU;CAAQ,IAAI;EAAC;EAAc;EAAS;CAAQ;CAC9F,YAAY,CAAC;CACb,KAAK,EACH,SAAS,KACX;CACA,UAAU;EACR,OAAO,EACL,SAAS,aACX;EACA,aAAa,EACX,SAAS;GAAC;GAAQ;GAAO;EAAI,EAC/B;CACF;CACA,gBAAgB,CAAC,iBAAiB,OAAO;AAC3C;AAEA,MAAa,OAA2D;CACtE,IAAI;CACJ,OAAO;CACP,aAAa;CACb,SAAS,EACP,QAAQ;EACN,SAAS;EACT,SAAS;GACP;IAAE,OAAO;IAAU,OAAO;IAAU,MAAM;GAAe;GACzD;IAAE,OAAO;IAAS,OAAO;GAAQ;GACjC;IAAE,OAAO;IAAU,OAAO;GAAS;EACrC;CACF,EACF;CACA,MAAM,MAAM,KAAK,EAAE,UAAU;EAC3B,MAAM,EAAE,WAAW,gBAAgB,IAAI;EACvC,MAAM,OAAO,cAAc;EAC3B,MAAM,QAAQ,YAAoB,GAAG,KAAK,UAAU,SAAS,MAAM,CAAC,EAAE;EAEtE,QAAQ,QAAR;GACE,KAAK;IACH,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,qCAAqC;IAChE,IAAI,gBACF;KAAE,QAAQ;KAAW,sBAAsB,YAAY,cAAc,QAAQ;IAAK,GAClF,IACF;IACA,MAAM,IAAI,MAAM,qBAAqB,YAAY;IACjD,MAAM,IAAI,aAAa,SAAS,QAAQ,MAAM,EAAE,MAAM,SAAS,CAAC,CAAC;IACjE;GACF,KAAK;IACH,IAAI,gBAAgB,EAAE,kBAAkB,KAAK,GAAG,IAAI;IACpD,MAAM,IAAI,MAAM,cAAc,KAAK,YAAY,IAAI,CAAC,CAAC;IACrD,MAAM,IAAI,aAAa,SACrB,QAAQ,MAAM;KAAE,MAAM;KAAe,QAAQ;IAAuB,CAAC,CACvE;IACA;GACF,KAAK,UAAU;IACb,MAAM,QAAQ,YAAY,cAAc,OAAO,QAAQ,KAAK,EAAE,KAAK;IACnE,IAAI,gBAAgB,EAAE,QAAQ,KAAK,GAAG,IAAI;IAC1C,MAAM,IAAI,MAAM,kBAAkB,KAAK,aAAa,MAAM,KAAK,CAAC,CAAC;IACjE,MAAM,IAAI,aAAa,SAAS,QAAQ,MAAM,EAAE,MAAM,SAAS,CAAC,CAAC;IACjE;GACF;EACF;CACF;AACF"}
1
+ {"version":3,"file":"lint-AC2ClOfa.js","names":[],"sources":["../src/features/lint.ts"],"sourcesContent":["import type { Feature } from '@/features';\nimport { scripts } from './utils';\n\nconst eslintConfig = `import { defineConfig, globalIgnores } from 'eslint/config';\nimport nextVitals from 'eslint-config-next/core-web-vitals';\n\nconst eslintConfig = defineConfig([\n ...nextVitals,\n globalIgnores([\n '.next/**',\n 'out/**',\n 'build/**',\n 'next-env.d.ts',\n '.source/**',\n ]),\n]);\n\nexport default eslintConfig;\n`;\n\nconst biomeConfig = (next: boolean) => ({\n $schema: 'https://biomejs.dev/schemas/2.2.0/schema.json',\n vcs: {\n enabled: true,\n clientKind: 'git',\n useIgnoreFile: true,\n },\n files: {\n ignoreUnknown: true,\n includes: next\n ? ['**', '!node_modules', '!.next', '!dist', '!build', '!.source']\n : ['**', '!node_modules', '!.source'],\n },\n formatter: {\n enabled: true,\n indentStyle: 'space',\n indentWidth: 2,\n },\n linter: {\n enabled: true,\n rules: {\n recommended: true,\n },\n domains: next ? { next: 'recommended', react: 'recommended' } : { react: 'recommended' },\n },\n assist: {\n actions: {\n source: {\n organizeImports: 'on',\n },\n },\n },\n});\n\nconst oxlintConfig = (next: boolean, reactVersion: string) => ({\n $schema: './node_modules/oxlint/configuration_schema.json',\n plugins: next ? ['typescript', 'react', 'import', 'nextjs'] : ['typescript', 'react', 'import'],\n categories: {},\n env: {\n builtin: true,\n },\n settings: {\n react: {\n version: reactVersion,\n },\n tailwindcss: {\n callees: ['clsx', 'cva', 'cn'],\n },\n },\n ignorePatterns: ['node_modules/', 'dist/'],\n});\n\nexport const lint: Feature<{ linter: 'eslint' | 'biome' | 'oxlint' }> = {\n id: 'lint',\n title: 'Linter',\n description: 'configure a linter',\n options: {\n linter: {\n message: 'Choose a linter',\n choices: [\n { value: 'eslint', label: 'ESLint', hint: 'Next.js only' },\n { value: 'biome', label: 'Biome' },\n { value: 'oxlint', label: 'Oxlint' },\n ],\n },\n },\n async apply(ctx, { linter }) {\n const { framework, packageJson } = ctx.project;\n const next = framework === 'next';\n const json = (content: object) => `${JSON.stringify(content, null, 2)}\\n`;\n\n switch (linter) {\n case 'eslint':\n if (!next) throw new Error('ESLint is only supported on Next.js');\n ctx.addDependencies(\n { eslint: '^9.39.4', 'eslint-config-next': packageJson.dependencies?.next ?? null },\n true,\n );\n await ctx.write('eslint.config.mjs', eslintConfig);\n await ctx.packageJson((data) => scripts(data, { lint: 'eslint' }));\n break;\n case 'biome':\n ctx.addDependencies({ '@biomejs/biome': null }, true);\n await ctx.write('biome.json', json(biomeConfig(next)));\n await ctx.packageJson((data) =>\n scripts(data, { lint: 'biome check', format: 'biome format --write' }),\n );\n break;\n case 'oxlint': {\n const react = packageJson.dependencies?.react?.replace('^', '') ?? '19.2.0';\n ctx.addDependencies({ oxlint: null }, true);\n await ctx.write('.oxlintrc.json', json(oxlintConfig(next, react)));\n await ctx.packageJson((data) => scripts(data, { lint: 'oxlint' }));\n break;\n }\n }\n },\n};\n"],"mappings":";;AAGA,MAAM,eAAe;;;;;;;;;;;;;;;;AAiBrB,MAAM,eAAe,UAAmB;CACtC,SAAS;CACT,KAAK;EACH,SAAS;EACT,YAAY;EACZ,eAAe;CACjB;CACA,OAAO;EACL,eAAe;EACf,UAAU,OACN;GAAC;GAAM;GAAiB;GAAU;GAAS;GAAU;EAAU,IAC/D;GAAC;GAAM;GAAiB;EAAU;CACxC;CACA,WAAW;EACT,SAAS;EACT,aAAa;EACb,aAAa;CACf;CACA,QAAQ;EACN,SAAS;EACT,OAAO,EACL,aAAa,KACf;EACA,SAAS,OAAO;GAAE,MAAM;GAAe,OAAO;EAAc,IAAI,EAAE,OAAO,cAAc;CACzF;CACA,QAAQ,EACN,SAAS,EACP,QAAQ,EACN,iBAAiB,KACnB,EACF,EACF;AACF;AAEA,MAAM,gBAAgB,MAAe,kBAA0B;CAC7D,SAAS;CACT,SAAS,OAAO;EAAC;EAAc;EAAS;EAAU;CAAQ,IAAI;EAAC;EAAc;EAAS;CAAQ;CAC9F,YAAY,CAAC;CACb,KAAK,EACH,SAAS,KACX;CACA,UAAU;EACR,OAAO,EACL,SAAS,aACX;EACA,aAAa,EACX,SAAS;GAAC;GAAQ;GAAO;EAAI,EAC/B;CACF;CACA,gBAAgB,CAAC,iBAAiB,OAAO;AAC3C;AAEA,MAAa,OAA2D;CACtE,IAAI;CACJ,OAAO;CACP,aAAa;CACb,SAAS,EACP,QAAQ;EACN,SAAS;EACT,SAAS;GACP;IAAE,OAAO;IAAU,OAAO;IAAU,MAAM;GAAe;GACzD;IAAE,OAAO;IAAS,OAAO;GAAQ;GACjC;IAAE,OAAO;IAAU,OAAO;GAAS;EACrC;CACF,EACF;CACA,MAAM,MAAM,KAAK,EAAE,UAAU;EAC3B,MAAM,EAAE,WAAW,gBAAgB,IAAI;EACvC,MAAM,OAAO,cAAc;EAC3B,MAAM,QAAQ,YAAoB,GAAG,KAAK,UAAU,SAAS,MAAM,CAAC,EAAE;EAEtE,QAAQ,QAAR;GACE,KAAK;IACH,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,qCAAqC;IAChE,IAAI,gBACF;KAAE,QAAQ;KAAW,sBAAsB,YAAY,cAAc,QAAQ;IAAK,GAClF,IACF;IACA,MAAM,IAAI,MAAM,qBAAqB,YAAY;IACjD,MAAM,IAAI,aAAa,SAAS,QAAQ,MAAM,EAAE,MAAM,SAAS,CAAC,CAAC;IACjE;GACF,KAAK;IACH,IAAI,gBAAgB,EAAE,kBAAkB,KAAK,GAAG,IAAI;IACpD,MAAM,IAAI,MAAM,cAAc,KAAK,YAAY,IAAI,CAAC,CAAC;IACrD,MAAM,IAAI,aAAa,SACrB,QAAQ,MAAM;KAAE,MAAM;KAAe,QAAQ;IAAuB,CAAC,CACvE;IACA;GACF,KAAK,UAAU;IACb,MAAM,QAAQ,YAAY,cAAc,OAAO,QAAQ,KAAK,EAAE,KAAK;IACnE,IAAI,gBAAgB,EAAE,QAAQ,KAAK,GAAG,IAAI;IAC1C,MAAM,IAAI,MAAM,kBAAkB,KAAK,aAAa,MAAM,KAAK,CAAC,CAAC;IACjE,MAAM,IAAI,aAAa,SAAS,QAAQ,MAAM,EAAE,MAAM,SAAS,CAAC,CAAC;IACjE;GACF;EACF;CACF;AACF"}