@fumadocs/cli 1.5.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/dist/ai-C19ZOP53.js +100 -0
  2. package/dist/ai-C19ZOP53.js.map +1 -0
  3. package/dist/all-BBf7I8hG.js +27 -0
  4. package/dist/all-BBf7I8hG.js.map +1 -0
  5. package/dist/codemod/index.d.ts +2 -0
  6. package/dist/codemod/index.js +2 -0
  7. package/dist/codemod-auol-p4R.js +404 -0
  8. package/dist/codemod-auol-p4R.js.map +1 -0
  9. package/dist/config-Bfg4yG8S.d.ts +54 -0
  10. package/dist/config-Bfg4yG8S.d.ts.map +1 -0
  11. package/dist/config-Bw0kmF01.js +97 -0
  12. package/dist/config-Bw0kmF01.js.map +1 -0
  13. package/dist/config.d.ts +2 -52
  14. package/dist/config.js +1 -72
  15. package/dist/docs--WqEHTyl.js +738 -0
  16. package/dist/docs--WqEHTyl.js.map +1 -0
  17. package/dist/epub-jc_2B886.js +52 -0
  18. package/dist/epub-jc_2B886.js.map +1 -0
  19. package/dist/features/ai.d.ts +25 -0
  20. package/dist/features/ai.d.ts.map +1 -0
  21. package/dist/features/ai.js +2 -0
  22. package/dist/features/all.d.ts +5 -0
  23. package/dist/features/all.d.ts.map +1 -0
  24. package/dist/features/all.js +2 -0
  25. package/dist/features/docs/index.d.ts +10 -0
  26. package/dist/features/docs/index.d.ts.map +1 -0
  27. package/dist/features/docs/index.js +2 -0
  28. package/dist/features/epub.d.ts +5 -0
  29. package/dist/features/epub.d.ts.map +1 -0
  30. package/dist/features/epub.js +2 -0
  31. package/dist/features/feedback.d.ts +5 -0
  32. package/dist/features/feedback.d.ts.map +1 -0
  33. package/dist/features/feedback.js +2 -0
  34. package/dist/features/index.d.ts +2 -0
  35. package/dist/features/index.js +2 -0
  36. package/dist/features/lint.d.ts +7 -0
  37. package/dist/features/lint.d.ts.map +1 -0
  38. package/dist/features/lint.js +2 -0
  39. package/dist/features/llms.d.ts +27 -0
  40. package/dist/features/llms.d.ts.map +1 -0
  41. package/dist/features/llms.js +2 -0
  42. package/dist/features/mcp.d.ts +9 -0
  43. package/dist/features/mcp.d.ts.map +1 -0
  44. package/dist/features/mcp.js +2 -0
  45. package/dist/features/og.d.ts +8 -0
  46. package/dist/features/og.d.ts.map +1 -0
  47. package/dist/features/og.js +2 -0
  48. package/dist/features/search.d.ts +84 -0
  49. package/dist/features/search.d.ts.map +1 -0
  50. package/dist/features/search.js +2 -0
  51. package/dist/features/utils.d.ts +2 -0
  52. package/dist/features/utils.js +2 -0
  53. package/dist/features/webmcp.d.ts +12 -0
  54. package/dist/features/webmcp.d.ts.map +1 -0
  55. package/dist/features/webmcp.js +2 -0
  56. package/dist/features-CXFCgOWD.js +132 -0
  57. package/dist/features-CXFCgOWD.js.map +1 -0
  58. package/dist/feedback-Brj092vC.js +37 -0
  59. package/dist/feedback-Brj092vC.js.map +1 -0
  60. package/dist/fs-D6J9dOEx.js +14 -0
  61. package/dist/fs-D6J9dOEx.js.map +1 -0
  62. package/dist/index-Ck0EPdgu.d.ts +126 -0
  63. package/dist/index-Ck0EPdgu.d.ts.map +1 -0
  64. package/dist/index-Cs7hw2un.d.ts +76 -0
  65. package/dist/index-Cs7hw2un.d.ts.map +1 -0
  66. package/dist/index-DI66DoV8.d.ts +64 -0
  67. package/dist/index-DI66DoV8.d.ts.map +1 -0
  68. package/dist/index.js +155 -139
  69. package/dist/index.js.map +1 -1
  70. package/dist/{installer-Ci3Hf9it.js → installer-CzhVfs7i.js} +81 -8
  71. package/dist/installer-CzhVfs7i.js.map +1 -0
  72. package/dist/lint-zkXUULgO.js +137 -0
  73. package/dist/lint-zkXUULgO.js.map +1 -0
  74. package/dist/llms-Br0RJXXg.js +228 -0
  75. package/dist/llms-Br0RJXXg.js.map +1 -0
  76. package/dist/mcp-Ce_W93we.js +67 -0
  77. package/dist/mcp-Ce_W93we.js.map +1 -0
  78. package/dist/og-LFlX1Bl4.js +142 -0
  79. package/dist/og-LFlX1Bl4.js.map +1 -0
  80. package/dist/project/index.d.ts +2 -0
  81. package/dist/project/index.js +2 -0
  82. package/dist/project-DwRVTm4p.js +110 -0
  83. package/dist/project-DwRVTm4p.js.map +1 -0
  84. package/dist/registry/installer.d.ts +4 -5
  85. package/dist/registry/installer.d.ts.map +1 -1
  86. package/dist/registry/installer.js +1 -1
  87. package/dist/schema.json +1 -1
  88. package/dist/search-WfSdiGx-.js +381 -0
  89. package/dist/search-WfSdiGx-.js.map +1 -0
  90. package/dist/utils-CxJ7kw39.d.ts +43 -0
  91. package/dist/utils-CxJ7kw39.d.ts.map +1 -0
  92. package/dist/utils-DbMe7h6c.js +98 -0
  93. package/dist/utils-DbMe7h6c.js.map +1 -0
  94. package/dist/webmcp-DyTLrsXL.js +135 -0
  95. package/dist/webmcp-DyTLrsXL.js.map +1 -0
  96. package/package.json +28 -7
  97. package/dist/config.d.ts.map +0 -1
  98. package/dist/config.js.map +0 -1
  99. package/dist/installer-Ci3Hf9it.js.map +0 -1
@@ -0,0 +1 @@
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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"}
@@ -0,0 +1,37 @@
1
+ import { b as findJsxElement, h as appendJsxChildren, p as addImport } from "./codemod-auol-p4R.js";
2
+ import { t as docs } from "./docs--WqEHTyl.js";
3
+ import { r as findSource } from "./utils-DbMe7h6c.js";
4
+ import path from "node:path";
5
+ //#region src/features/feedback.ts
6
+ const feedback = {
7
+ id: "feedback",
8
+ title: "Feedback",
9
+ description: "let readers rate docs pages, with a component to send feedback",
10
+ requires: [docs],
11
+ async apply(ctx) {
12
+ const { cwd, baseDir, info, framework, static: isStatic } = ctx.project;
13
+ await ctx.install("feedback");
14
+ const serverAction = framework === "next" || framework === "waku";
15
+ const page = await findSource(cwd, path.join(baseDir, info.routesDir), "<DocsPage");
16
+ if (!(page !== void 0 && !(serverAction && isStatic) && await ctx.source(page, (file) => {
17
+ if (file.code.includes("<Feedback")) return;
18
+ const element = findJsxElement(file, "DocsPage");
19
+ if (!element) return;
20
+ appendJsxChildren(file, element, `<Feedback
21
+ onSendAction={async (feedback) => {${serverAction ? "\n 'use server';\n" : ""}
22
+ console.log(feedback);
23
+ return {};
24
+ }}
25
+ />`);
26
+ addImport(file, {
27
+ from: "@/components/feedback/client",
28
+ named: ["Feedback"]
29
+ });
30
+ }))) ctx.note(serverAction && isStatic ? "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`." : "Add `<Feedback />` from `@/components/feedback/client` to the bottom of your docs page.");
31
+ ctx.note("Handle the feedback in `onSendAction`, e.g. report it to GitHub Discussions: https://fumadocs.dev/docs/integrations/feedback.");
32
+ }
33
+ };
34
+ //#endregion
35
+ export { feedback as t };
36
+
37
+ //# sourceMappingURL=feedback-Brj092vC.js.map
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,14 @@
1
+ import fs from "node:fs/promises";
2
+ //#region src/utils/fs.ts
3
+ async function exists(pathLike) {
4
+ try {
5
+ await fs.access(pathLike);
6
+ return true;
7
+ } catch {
8
+ return false;
9
+ }
10
+ }
11
+ //#endregion
12
+ export { exists as t };
13
+
14
+ //# sourceMappingURL=fs-D6J9dOEx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-D6J9dOEx.js","names":[],"sources":["../src/utils/fs.ts"],"sourcesContent":["import fs from 'node:fs/promises';\n\nexport async function exists(pathLike: string): Promise<boolean> {\n try {\n await fs.access(pathLike);\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":";;AAEA,eAAsB,OAAO,UAAoC;CAC/D,IAAI;EACF,MAAM,GAAG,OAAO,QAAQ;EACxB,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF"}
@@ -0,0 +1,126 @@
1
+ import { ArrayExpression, ExportDefaultDeclaration, JSXElement, JSXOpeningElement, Node, ObjectExpression, ObjectProperty, Program } from "oxc-parser";
2
+ import MagicString from "magic-string";
3
+ //#region src/codemod/shared.d.ts
4
+ type NodeOfType<T extends Node['type']> = Extract<Node, {
5
+ type: T;
6
+ }>;
7
+ interface SourceFile {
8
+ path: string;
9
+ /** the original content */
10
+ code: string;
11
+ program: Program;
12
+ /** the edited content */
13
+ s: MagicString;
14
+ save(): Promise<void>;
15
+ }
16
+ declare function parseSourceFile(path: string, code: string): SourceFile;
17
+ declare function createSourceFile(path: string): Promise<SourceFile>;
18
+ /** the value of a string literal, or a template literal without expressions */
19
+ declare function getStringValue(node: Node): string | undefined;
20
+ declare function descendants(node: Node): Generator<Node>;
21
+ declare function find<T extends Node['type']>(node: Node, type: T, predicate?: (node: NodeOfType<T>) => boolean): NodeOfType<T> | undefined;
22
+ declare function getDefaultExport(file: SourceFile): ExportDefaultDeclaration | undefined;
23
+ declare function findJsxElement(file: SourceFile, tagName: string): JSXElement | undefined;
24
+ declare function addJsxAttribute(file: SourceFile, element: JSXOpeningElement, attribute: string): void;
25
+ /**
26
+ * Insert JSX before the children of the element, re-indenting the children
27
+ */
28
+ declare function prependJsxChildren(file: SourceFile, element: JSXElement, jsx: string): void;
29
+ /**
30
+ * Insert JSX after the children of the element
31
+ */
32
+ declare function appendJsxChildren(file: SourceFile, element: JSXElement, jsx: string): void;
33
+ declare function getProperty(object: ObjectExpression, name: string): ObjectProperty | undefined;
34
+ /** indentation of the line containing `index` */
35
+ declare function lineIndent(code: string, index: number): string;
36
+ declare function addImport(file: SourceFile, declaration: {
37
+ from: string;
38
+ default?: string;
39
+ named?: string[];
40
+ }): void;
41
+ type Container = ArrayExpression | ObjectExpression;
42
+ type ElementOf<C extends Container> = C extends ArrayExpression ? NonNullable<ArrayExpression['elements'][number]> : ObjectExpression['properties'][number];
43
+ /**
44
+ * Append items to an array or object literal, following its formatting
45
+ */
46
+ declare function addElements(file: SourceFile, container: Container, items: string[]): void;
47
+ /**
48
+ * Remove the items of an array or object literal that don't pass the filter
49
+ */
50
+ 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
+ /**
54
+ * The options object of a config file, e.g. the argument of `defineConfig({ ... })`, or the object in `export default { ... }`
55
+ */
56
+ declare function getConfigObject(file: SourceFile): ObjectExpression | undefined;
57
+ /**
58
+ * Add a plugin call to the `plugins` array of a Vite config, skip if the same plugin is already added.
59
+ *
60
+ * @param path - property path to the plugins array, e.g. `['vite', 'plugins']` for Waku
61
+ */
62
+ declare function addVitePlugin(file: SourceFile, plugin: {
63
+ name: string;
64
+ from: string;
65
+ call?: string;
66
+ }, path?: string[]): boolean;
67
+ /**
68
+ * Wrap the default export of `next.config.*` with `createMDX()`
69
+ */
70
+ declare function wrapNextConfig(file: SourceFile): boolean;
71
+ /**
72
+ * Add rewrites to a Next.js config, skip if `rewrites` is already defined
73
+ */
74
+ declare function addNextRewrites(file: SourceFile, rewrites: {
75
+ source: string;
76
+ destination: string;
77
+ }[]): boolean;
78
+ //#endregion
79
+ //#region src/codemod/react-router.d.ts
80
+ /**
81
+ * filter items in a specific array initializer in the prerender function
82
+ */
83
+ declare function filterReactRouterPrerenderArray(file: SourceFile, array: 'paths' | 'excluded', filter: (item: string) => boolean): void;
84
+ /**
85
+ * add items to a specific array initializer in the prerender function, skip existing ones
86
+ */
87
+ declare function addReactRouterPrerenderArray(file: SourceFile, array: 'paths' | 'excluded', items: string[]): void;
88
+ /**
89
+ * Add new routes to route config, an item can be raw code (e.g. `layout(...)`)
90
+ */
91
+ declare function addReactRouterRoute(file: SourceFile, routes: ({
92
+ path: string;
93
+ entry: string;
94
+ } | string)[]): boolean;
95
+ /**
96
+ * Remove routes from route config (root level only)
97
+ */
98
+ declare function filterReactRouterRoute(file: SourceFile, filter: (item: {
99
+ path: string;
100
+ entry: string;
101
+ }) => boolean): void;
102
+ //#endregion
103
+ //#region src/codemod/tanstack-start.d.ts
104
+ /**
105
+ * Add path to the `pages` array in tanstack start vite config.
106
+ *
107
+ * If the `pages` property doesn't exist, create one.
108
+ */
109
+ declare function addTanstackPrerender(file: SourceFile, paths: string[]): void;
110
+ //#endregion
111
+ //#region src/codemod/source.d.ts
112
+ /**
113
+ * Enable `includeProcessedMarkdown` on the `defineDocs()` call
114
+ *
115
+ * @returns `false` if the call cannot be found
116
+ */
117
+ declare function enableProcessedMarkdown(file: SourceFile): boolean;
118
+ //#endregion
119
+ //#region src/codemod/next-proxy.d.ts
120
+ /**
121
+ * Add patterns to the `matcher` of `export const config` in a Next.js proxy (middleware) file
122
+ */
123
+ declare function addProxyMatcher(file: SourceFile, patterns: string[]): boolean;
124
+ //#endregion
125
+ 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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-Ck0EPdgu.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;;;;iBA4BpD,eAAe,UAAU,WACvC,MAAM,YACN,WAAW,GACX,OAAO,SAAS,UAAU;;;;;;iBC9NZ,gBAAgB,MAAM,aAAa;;;;;;iBAiCnC,cACd,MAAM,YACN;EAAU;EAAc;EAAc;GACtC;;;;iBAqCc,eAAe,MAAM;;;;iBAkBrB,gBACd,MAAM,YACN;EAAY;EAAgB;;;;;;;iBC5Fd,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"}
@@ -0,0 +1,76 @@
1
+ import { p as SourceFile } from "./index-Ck0EPdgu.js";
2
+ import { a as Project } from "./index-DI66DoV8.js";
3
+ import { RegistryConnector } from "fuma-cli/registry/connector";
4
+ //#region src/features/index.d.ts
5
+ interface SelectOption<T> {
6
+ message: string;
7
+ choices: {
8
+ value: T;
9
+ label: string;
10
+ hint?: string;
11
+ }[];
12
+ }
13
+ interface ConfirmOption {
14
+ message: string;
15
+ initialValue?: boolean;
16
+ }
17
+ type FeatureOption<T> = [T] extends [boolean] ? ConfirmOption : SelectOption<T>;
18
+ interface Feature<Options extends object = Record<never, never>> {
19
+ id: string;
20
+ title: string;
21
+ description: string;
22
+ options?: { [K in keyof Options]: FeatureOption<Options[K]>; };
23
+ /** features that must be applied first */
24
+ requires?: AnyFeature[];
25
+ /** whether the feature is already applied to the project */
26
+ detect?: (project: Project) => Promise<boolean>;
27
+ /** @returns `true` if supported, otherwise the reason */
28
+ supports?: (project: Project) => true | string;
29
+ apply(ctx: FeatureContext, options: Options): Promise<void>;
30
+ }
31
+ type AnyFeature = Omit<Feature<Record<string, unknown>>, 'options'> & {
32
+ options?: Record<string, SelectOption<unknown> | ConfirmOption>;
33
+ };
34
+ interface PackageJson {
35
+ scripts?: Record<string, string>;
36
+ dependencies?: Record<string, string>;
37
+ devDependencies?: Record<string, string>;
38
+ }
39
+ interface FeatureContext {
40
+ project: Project;
41
+ /** write a file (relative to project root), asks before overwriting */
42
+ write: (file: string, content: string) => Promise<void>;
43
+ /** edit a file with codemods, `false` if the file doesn't exist */
44
+ source: (file: string, edit: (file: SourceFile) => void) => Promise<boolean>;
45
+ /** append lines to a text file, skip lines already present */
46
+ append: (file: string, lines: string[]) => Promise<void>;
47
+ remove: (file: string) => Promise<void>;
48
+ packageJson: (edit: (data: PackageJson) => void) => Promise<void>;
49
+ /** install a registry component */
50
+ install: (name: string, subRegistry?: string) => Promise<void>;
51
+ /** `null` to install the latest version */
52
+ addDependencies: (deps: Record<string, string | null>, dev?: boolean) => void;
53
+ env: (key: string, value: string) => void;
54
+ /** instructions to show after the feature is applied */
55
+ note: (text: string) => void;
56
+ log: (message: string) => void;
57
+ }
58
+ interface FeatureIO {
59
+ log: (message: string) => void;
60
+ confirmOverwrite: (file: string) => Promise<boolean>;
61
+ /** run package manager to install dependencies, otherwise only write them into `package.json` */
62
+ installDependencies: boolean;
63
+ }
64
+ interface RunOptions {
65
+ project: Project;
66
+ connector: RegistryConnector;
67
+ io: FeatureIO;
68
+ /** preferred versions of dependencies, when a feature doesn't specify one */
69
+ versions?: Record<string, string>;
70
+ }
71
+ declare function runFeature<O extends object>(feature: Omit<Feature<O>, 'options'>, options: O, { project, connector, io, versions }: RunOptions): Promise<{
72
+ notes: string[];
73
+ }>;
74
+ //#endregion
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-Cs7hw2un.d.ts.map
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,64 @@
1
+ import { r as LoadedConfig } from "./config-Bfg4yG8S.js";
2
+ import { detectFramework as detectFramework$1, detectPackageManager } from "fuma-cli/detect";
3
+ //#region src/project/index.d.ts
4
+ type PackageManager = NonNullable<Awaited<ReturnType<typeof detectPackageManager>>>['name'];
5
+ type Framework = 'next' | 'react-router' | 'tanstack-start' | 'waku' | 'astro';
6
+ /** frameworks supported by features that generate routes */
7
+ type ReactFramework = Exclude<Framework, 'astro'>;
8
+ interface FrameworkInfo {
9
+ /** import specifier of `RootProvider` */
10
+ provider: string;
11
+ /** root file that imports the global CSS, relative to base dir */
12
+ rootFile: string;
13
+ /** routes directory, relative to base dir */
14
+ routesDir: string;
15
+ /** config file candidates (relative to cwd) that register bundler plugins */
16
+ configFiles: string[];
17
+ /** how to detect `static` mode from the config file */
18
+ isStatic?: (config: string) => boolean;
19
+ }
20
+ declare const frameworks: Record<Framework, FrameworkInfo>;
21
+ /** how docs content is loaded, detected from `lib/source.ts` */
22
+ interface SourceInfo {
23
+ /** `lib/source.ts` exports a `source` loader */
24
+ loader: boolean;
25
+ /** `lib/source.ts` exports `getSource()`, a runtime content source resolved on demand */
26
+ 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 */
28
+ collections: string | null;
29
+ /** collections are loaded lazily, `structuredData` is a function */
30
+ async: boolean;
31
+ /** base URL of docs pages */
32
+ baseUrl: string;
33
+ /** content directory */
34
+ dir: string;
35
+ }
36
+ interface I18nInfo {
37
+ /** the default locale is hidden from URLs (`hideLocale: 'default-locale'`) */
38
+ optionalLocale: boolean;
39
+ }
40
+ interface Project {
41
+ cwd: string;
42
+ framework: Framework;
43
+ info: FrameworkInfo;
44
+ /** prerendered to static HTML, no server at runtime */
45
+ static: boolean;
46
+ /** `lib/i18n.ts` exists */
47
+ i18n: I18nInfo | null;
48
+ source: SourceInfo;
49
+ packageManager: PackageManager;
50
+ /** directory of app code, relative to `cwd` */
51
+ baseDir: string;
52
+ config: LoadedConfig;
53
+ /** config file that registers bundler plugins, relative to `cwd` */
54
+ configFile?: string;
55
+ packageJson: {
56
+ dependencies?: Record<string, string>;
57
+ devDependencies?: Record<string, string>;
58
+ };
59
+ }
60
+ declare function isSupportedFramework(v: string): v is Framework;
61
+ 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
@@ -0,0 +1 @@
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"}