@fumadocs/cli 1.6.0 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ai-BVuNjYXU.js → ai-C19ZOP53.js} +2 -2
- package/dist/{ai-BVuNjYXU.js.map → ai-C19ZOP53.js.map} +1 -1
- package/dist/all-BBf7I8hG.js +27 -0
- package/dist/{all-aUHxtoXL.js.map → all-BBf7I8hG.js.map} +1 -1
- package/dist/{config-CT2jj39D.d.ts → config-Bfg4yG8S.d.ts} +3 -1
- package/dist/config-Bfg4yG8S.d.ts.map +1 -0
- package/dist/{config-D6uv73fs.js → config-Bw0kmF01.js} +6 -3
- package/dist/config-Bw0kmF01.js.map +1 -0
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/{docs-DeIEl_Kt.js → docs--WqEHTyl.js} +2 -2
- package/dist/{docs-DeIEl_Kt.js.map → docs--WqEHTyl.js.map} +1 -1
- package/dist/{epub-CnQFJh09.js → epub-jc_2B886.js} +2 -2
- package/dist/{epub-CnQFJh09.js.map → epub-jc_2B886.js.map} +1 -1
- package/dist/features/ai.d.ts +1 -1
- package/dist/features/ai.js +1 -1
- package/dist/features/all.d.ts +1 -1
- package/dist/features/all.js +1 -1
- package/dist/features/docs/index.d.ts +2 -2
- package/dist/features/docs/index.js +1 -1
- package/dist/features/epub.d.ts +1 -1
- package/dist/features/epub.js +1 -1
- package/dist/features/feedback.d.ts +1 -1
- package/dist/features/feedback.js +1 -1
- package/dist/features/index.d.ts +1 -1
- package/dist/features/index.js +1 -1
- package/dist/features/lint.d.ts +1 -1
- package/dist/features/llms.d.ts +3 -3
- package/dist/features/llms.js +1 -1
- package/dist/features/mcp.d.ts +3 -3
- package/dist/features/mcp.js +1 -1
- package/dist/features/og.d.ts +1 -1
- package/dist/features/og.js +1 -1
- package/dist/features/search.d.ts +2 -2
- package/dist/features/search.js +1 -1
- package/dist/features/utils.d.ts +1 -1
- package/dist/features/webmcp.d.ts +1 -1
- package/dist/features/webmcp.js +1 -1
- package/dist/{features-C1kf2s8j.js → features-CXFCgOWD.js} +3 -3
- package/dist/{features-C1kf2s8j.js.map → features-CXFCgOWD.js.map} +1 -1
- package/dist/{feedback-COmWtc5C.js → feedback-Brj092vC.js} +2 -2
- package/dist/{feedback-COmWtc5C.js.map → feedback-Brj092vC.js.map} +1 -1
- package/dist/{index-CR9T40ox.d.ts → index-Cs7hw2un.d.ts} +2 -2
- package/dist/{index-CR9T40ox.d.ts.map → index-Cs7hw2un.d.ts.map} +1 -1
- package/dist/{index-BCVGQxn9.d.ts → index-DI66DoV8.d.ts} +2 -2
- package/dist/{index-BCVGQxn9.d.ts.map → index-DI66DoV8.d.ts.map} +1 -1
- package/dist/index.js +43 -36
- package/dist/index.js.map +1 -1
- package/dist/{installer-D0Obb2Md.js → installer-CzhVfs7i.js} +67 -4
- package/dist/installer-CzhVfs7i.js.map +1 -0
- package/dist/{llms-CONd8Vnn.js → llms-Br0RJXXg.js} +2 -2
- package/dist/{llms-CONd8Vnn.js.map → llms-Br0RJXXg.js.map} +1 -1
- package/dist/{mcp-BT8BLZZ-.js → mcp-Ce_W93we.js} +3 -3
- package/dist/{mcp-BT8BLZZ-.js.map → mcp-Ce_W93we.js.map} +1 -1
- package/dist/{og-DRDOyQ_t.js → og-LFlX1Bl4.js} +3 -3
- package/dist/{og-DRDOyQ_t.js.map → og-LFlX1Bl4.js.map} +1 -1
- package/dist/project/index.d.ts +1 -1
- package/dist/registry/installer.d.ts +1 -1
- package/dist/registry/installer.d.ts.map +1 -1
- package/dist/registry/installer.js +1 -1
- package/dist/schema.json +1 -1
- package/dist/{search-iphnSVVY.js → search-WfSdiGx-.js} +2 -2
- package/dist/{search-iphnSVVY.js.map → search-WfSdiGx-.js.map} +1 -1
- package/dist/{utils-B1Xy4l_a.d.ts → utils-CxJ7kw39.d.ts} +3 -3
- package/dist/{utils-B1Xy4l_a.d.ts.map → utils-CxJ7kw39.d.ts.map} +1 -1
- package/dist/{webmcp-C2PM_9md.js → webmcp-DyTLrsXL.js} +2 -2
- package/dist/{webmcp-C2PM_9md.js.map → webmcp-DyTLrsXL.js.map} +1 -1
- package/package.json +9 -8
- package/dist/all-aUHxtoXL.js +0 -27
- package/dist/config-CT2jj39D.d.ts.map +0 -1
- package/dist/config-D6uv73fs.js.map +0 -1
- package/dist/installer-D0Obb2Md.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { E as prependJsxChildren, b as findJsxElement, p as addImport } from "./codemod-auol-p4R.js";
|
|
2
|
-
import { t as docs } from "./docs
|
|
2
|
+
import { t as docs } from "./docs--WqEHTyl.js";
|
|
3
3
|
import { r as findSource } from "./utils-DbMe7h6c.js";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
//#region src/features/ai.ts
|
|
@@ -97,4 +97,4 @@ async function readDynamicSource(ctx) {
|
|
|
97
97
|
//#endregion
|
|
98
98
|
export { ai as t };
|
|
99
99
|
|
|
100
|
-
//# sourceMappingURL=ai-
|
|
100
|
+
//# sourceMappingURL=ai-C19ZOP53.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-
|
|
1
|
+
{"version":3,"file":"ai-C19ZOP53.js","names":[],"sources":["../src/features/ai.ts"],"sourcesContent":["import path from 'node:path';\nimport type { Feature, FeatureContext } from '@/features';\nimport { findSource } from './utils';\nimport { addImport, findJsxElement, prependJsxChildren } from '@/codemod';\nimport { docs } from './docs';\n\nconst providers = {\n openrouter: { label: 'AI SDK', hint: 'default to OpenRouter', env: 'OPENROUTER_API_KEY' },\n llmgateway: {\n label: 'LLMGateway',\n hint: 'open-source LLM gateway, API key required',\n env: 'LLM_GATEWAY_API_KEY',\n },\n inkeep: { label: 'Inkeep AI', hint: 'API key required', env: 'INKEEP_API_KEY' },\n};\n\nexport type AIProvider = keyof typeof providers;\n\nexport const ai: Feature<{ provider: AIProvider }> = {\n id: 'ai',\n title: 'AI Chat',\n description: 'Ask AI dialog for your docs',\n requires: [docs],\n options: {\n provider: {\n message: 'Choose an AI provider',\n choices: Object.entries(providers).map(([value, { label, hint }]) => ({\n value: value as AIProvider,\n label,\n hint,\n })),\n },\n },\n supports: (project) =>\n project.static ? 'AI chat requires a server to run the chat route handler.' : true,\n async apply(ctx, { provider }) {\n await ctx.install(`ai/${provider}`);\n ctx.env(providers[provider].env, '');\n if (ctx.project.source.dynamic) await readDynamicSource(ctx);\n\n const { cwd, baseDir, info } = ctx.project;\n const layout = await findSource(cwd, path.join(baseDir, info.routesDir), '<DocsLayout');\n const edited =\n layout !== undefined &&\n (await ctx.source(layout, (file) => {\n if (file.code.includes('<AISearch')) return;\n const element = findJsxElement(file, 'DocsLayout');\n if (!element) return;\n\n prependJsxChildren(\n file,\n element,\n `<AISearch>\n <AISearchPanel />\n <AISearchTrigger\n position=\"float\"\n className={cn(\n buttonVariants({\n variant: 'secondary',\n className: 'text-fd-muted-foreground rounded-2xl',\n }),\n )}\n >\n <MessageCircleIcon className=\"size-4.5\" />\n Ask AI\n </AISearchTrigger>\n</AISearch>`,\n );\n addImport(file, {\n from: '@/components/ai/search',\n named: ['AISearch', 'AISearchPanel', 'AISearchTrigger'],\n });\n addImport(file, { from: 'lucide-react', named: ['MessageCircleIcon'] });\n addImport(file, { from: '@/lib/cn', named: ['cn'] });\n addImport(file, { from: 'fumadocs-ui/components/ui/button', named: ['buttonVariants'] });\n }));\n\n if (!edited) {\n ctx.note(\n 'Add `<AISearch>` from `@/components/ai/search` to your docs layout, see https://fumadocs.dev/docs/integrations/llms#ask-ai.',\n );\n }\n ctx.note(`Set ${providers[provider].env} in \\`.env.local\\`.`);\n },\n};\n\n/** the installed chat route indexes pages of a static `source`, runtime sources resolve on demand */\nasync function readDynamicSource(ctx: FeatureContext) {\n const { cwd, baseDir } = ctx.project;\n const route = await findSource(cwd, baseDir, 'createSearchServer');\n const edited =\n route !== undefined &&\n (await ctx.source(route, (file) => {\n file.s.replaceAll(\n \"import { source } from '@/lib/source';\",\n \"import { getSource } from '@/lib/source';\",\n );\n file.s.replaceAll('source.getPages()', '(await getSource()).getPages()');\n // every page of a runtime source carries its Markdown\n file.s.replaceAll(\" if (!('getText' in page.data)) return null;\\n\\n\", '');\n file.s.replaceAll(\"await page.data.getText('processed')\", 'page.data.content');\n }));\n\n if (!edited)\n ctx.note(\n 'Read pages from `getSource()` in the chat route, the search index is built from `page.data.content`.',\n );\n}\n"],"mappings":";;;;;AAMA,MAAM,YAAY;CAChB,YAAY;EAAE,OAAO;EAAU,MAAM;EAAyB,KAAK;CAAqB;CACxF,YAAY;EACV,OAAO;EACP,MAAM;EACN,KAAK;CACP;CACA,QAAQ;EAAE,OAAO;EAAa,MAAM;EAAoB,KAAK;CAAiB;AAChF;AAIA,MAAa,KAAwC;CACnD,IAAI;CACJ,OAAO;CACP,aAAa;CACb,UAAU,CAAC,IAAI;CACf,SAAS,EACP,UAAU;EACR,SAAS;EACT,SAAS,OAAO,QAAQ,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,aAAa;GAC7D;GACP;GACA;EACF,EAAE;CACJ,EACF;CACA,WAAW,YACT,QAAQ,SAAS,6DAA6D;CAChF,MAAM,MAAM,KAAK,EAAE,YAAY;EAC7B,MAAM,IAAI,QAAQ,MAAM,UAAU;EAClC,IAAI,IAAI,UAAU,SAAS,CAAC,KAAK,EAAE;EACnC,IAAI,IAAI,QAAQ,OAAO,SAAS,MAAM,kBAAkB,GAAG;EAE3D,MAAM,EAAE,KAAK,SAAS,SAAS,IAAI;EACnC,MAAM,SAAS,MAAM,WAAW,KAAK,KAAK,KAAK,SAAS,KAAK,SAAS,GAAG,aAAa;EAoCtF,IAAI,EAlCF,WAAW,KAAA,KACV,MAAM,IAAI,OAAO,SAAS,SAAS;GAClC,IAAI,KAAK,KAAK,SAAS,WAAW,GAAG;GACrC,MAAM,UAAU,eAAe,MAAM,YAAY;GACjD,IAAI,CAAC,SAAS;GAEd,mBACE,MACA,SACA;;;;;;;;;;;;;;YAeF;GACA,UAAU,MAAM;IACd,MAAM;IACN,OAAO;KAAC;KAAY;KAAiB;IAAiB;GACxD,CAAC;GACD,UAAU,MAAM;IAAE,MAAM;IAAgB,OAAO,CAAC,mBAAmB;GAAE,CAAC;GACtE,UAAU,MAAM;IAAE,MAAM;IAAY,OAAO,CAAC,IAAI;GAAE,CAAC;GACnD,UAAU,MAAM;IAAE,MAAM;IAAoC,OAAO,CAAC,gBAAgB;GAAE,CAAC;EACzF,CAAC,IAGD,IAAI,KACF,6HACF;EAEF,IAAI,KAAK,OAAO,UAAU,SAAS,CAAC,IAAI,oBAAoB;CAC9D;AACF;;AAGA,eAAe,kBAAkB,KAAqB;CACpD,MAAM,EAAE,KAAK,YAAY,IAAI;CAC7B,MAAM,QAAQ,MAAM,WAAW,KAAK,SAAS,oBAAoB;CAcjE,IAAI,EAZF,UAAU,KAAA,KACT,MAAM,IAAI,OAAO,QAAQ,SAAS;EACjC,KAAK,EAAE,WACL,0CACA,2CACF;EACA,KAAK,EAAE,WAAW,qBAAqB,gCAAgC;EAEvE,KAAK,EAAE,WAAW,yDAAyD,EAAE;EAC7E,KAAK,EAAE,WAAW,wCAAwC,mBAAmB;CAC/E,CAAC,IAGD,IAAI,KACF,sGACF;AACJ"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { t as docs } from "./docs--WqEHTyl.js";
|
|
2
|
+
import { t as ai } from "./ai-C19ZOP53.js";
|
|
3
|
+
import { r as llms } from "./llms-Br0RJXXg.js";
|
|
4
|
+
import { t as og } from "./og-LFlX1Bl4.js";
|
|
5
|
+
import { t as search } from "./search-WfSdiGx-.js";
|
|
6
|
+
import { t as mcp } from "./mcp-Ce_W93we.js";
|
|
7
|
+
import { n as webmcp } from "./webmcp-DyTLrsXL.js";
|
|
8
|
+
import { t as feedback } from "./feedback-Brj092vC.js";
|
|
9
|
+
import { t as epub } from "./epub-jc_2B886.js";
|
|
10
|
+
import { t as lint } from "./lint-zkXUULgO.js";
|
|
11
|
+
//#region src/features/all.ts
|
|
12
|
+
const features = [
|
|
13
|
+
docs,
|
|
14
|
+
ai,
|
|
15
|
+
llms,
|
|
16
|
+
mcp,
|
|
17
|
+
webmcp,
|
|
18
|
+
og,
|
|
19
|
+
search,
|
|
20
|
+
feedback,
|
|
21
|
+
epub,
|
|
22
|
+
lint
|
|
23
|
+
];
|
|
24
|
+
//#endregion
|
|
25
|
+
export { features as t };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=all-BBf7I8hG.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"all-
|
|
1
|
+
{"version":3,"file":"all-BBf7I8hG.js","names":[],"sources":["../src/features/all.ts"],"sourcesContent":["import type { AnyFeature } from '.';\nimport { docs } from './docs';\nimport { ai } from './ai';\nimport { llms } from './llms';\nimport { og } from './og';\nimport { search } from './search';\nimport { mcp } from './mcp';\nimport { webmcp } from './webmcp';\nimport { feedback } from './feedback';\nimport { epub } from './epub';\nimport { lint } from './lint';\n\nexport const features: AnyFeature[] = [\n docs,\n ai,\n llms,\n mcp,\n webmcp,\n og,\n search,\n feedback,\n epub,\n lint,\n];\n"],"mappings":";;;;;;;;;;;AAYA,MAAa,WAAyB;CACpC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
|
|
@@ -10,6 +10,7 @@ declare function createConfigSchema(cwd?: string): Promise<z.ZodObject<{
|
|
|
10
10
|
layoutDir: z.ZodDefault<z.ZodString>;
|
|
11
11
|
cssDir: z.ZodDefault<z.ZodString>;
|
|
12
12
|
libDir: z.ZodDefault<z.ZodString>;
|
|
13
|
+
utils: z.ZodDefault<z.ZodString> | z.ZodOptional<z.ZodString>;
|
|
13
14
|
}, z.core.$strip>>;
|
|
14
15
|
baseDir: z.ZodDefault<z.ZodString>;
|
|
15
16
|
uiLibrary: z.ZodDefault<z.ZodEnum<{
|
|
@@ -39,6 +40,7 @@ declare function getDefaultConfig(cwd?: string): Promise<{
|
|
|
39
40
|
layoutDir: string;
|
|
40
41
|
cssDir: string;
|
|
41
42
|
libDir: string;
|
|
43
|
+
utils: string | undefined;
|
|
42
44
|
};
|
|
43
45
|
baseDir: string;
|
|
44
46
|
uiLibrary: "base-ui" | "radix-ui";
|
|
@@ -49,4 +51,4 @@ declare function getDefaultConfig(cwd?: string): Promise<{
|
|
|
49
51
|
}>;
|
|
50
52
|
//#endregion
|
|
51
53
|
export { createOrLoadConfig as a, createConfigSchema as i, Framework as n, getDefaultConfig as o, LoadedConfig as r, initConfig as s, ConfigInput as t };
|
|
52
|
-
//# sourceMappingURL=config-
|
|
54
|
+
//# sourceMappingURL=config-Bfg4yG8S.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-Bfg4yG8S.d.ts","names":[],"sources":["../src/config.ts"],"mappings":";;cAMM;KACM,oBAAoB;iBAwBV,mBAAmB,eAAmB,QAAA,EAAA;;;;;;;;;;;;;;;;;;;GAgD3D,EAAA,KAAA;KAEI,eAAe,QAAQ,kBAAkB;KAElC,cAAc,EAAE,MAAM;KACtB,eAAe,EAAE,OAAO;iBAEd,mBAAmB,gBAAsB,QAAQ;;;;;;iBAejD,WAAW,gBAAsB,QAAQ;iBAezC,iBAAiB,eAAY"}
|
|
@@ -35,7 +35,8 @@ async function createConfigSchema(cwd = process.cwd()) {
|
|
|
35
35
|
componentsDir: shadcn.components ?? "./components",
|
|
36
36
|
layoutDir: "./layouts",
|
|
37
37
|
cssDir: "./styles",
|
|
38
|
-
libDir: shadcn.lib ?? "./lib"
|
|
38
|
+
libDir: shadcn.lib ?? "./lib",
|
|
39
|
+
utils: shadcn.utils
|
|
39
40
|
};
|
|
40
41
|
let framework = await detectFramework(cwd);
|
|
41
42
|
if (!isSupportedFramework(framework)) framework = "next";
|
|
@@ -46,7 +47,9 @@ async function createConfigSchema(cwd = process.cwd()) {
|
|
|
46
47
|
componentsDir: z.string().default(defaultAliases.componentsDir),
|
|
47
48
|
layoutDir: z.string().default(defaultAliases.layoutDir),
|
|
48
49
|
cssDir: z.string().default(defaultAliases.cssDir),
|
|
49
|
-
libDir: z.string().default(defaultAliases.libDir)
|
|
50
|
+
libDir: z.string().default(defaultAliases.libDir),
|
|
51
|
+
/** module exporting `cn`, installed components import it instead of `lib/cn.ts` */
|
|
52
|
+
utils: shadcn.utils ? z.string().default(shadcn.utils) : z.string().optional()
|
|
50
53
|
}).default(defaultAliases),
|
|
51
54
|
baseDir: z.string().default(() => {
|
|
52
55
|
if (framework === "react-router") return "app";
|
|
@@ -91,4 +94,4 @@ async function getDefaultConfig(cwd) {
|
|
|
91
94
|
//#endregion
|
|
92
95
|
export { initConfig as i, createOrLoadConfig as n, getDefaultConfig as r, createConfigSchema as t };
|
|
93
96
|
|
|
94
|
-
//# sourceMappingURL=config-
|
|
97
|
+
//# sourceMappingURL=config-Bw0kmF01.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-Bw0kmF01.js","names":[],"sources":["../src/config.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport { z } from 'zod';\nimport { existsSync } from 'node:fs';\nimport path from 'node:path';\nimport { detectFramework } from 'fuma-cli/detect';\n\nconst frameworks = ['next', 'astro', 'waku', 'react-router', 'tanstack-start'] as const;\nexport type Framework = (typeof frameworks)[number];\n\nfunction isSupportedFramework(v: string): v is Framework {\n return frameworks.includes(v as Framework);\n}\n\n/** directories from shadcn's `components.json`, so components are installed at the same place */\nasync function readShadcnAliases(cwd: string): Promise<Record<string, string>> {\n const content = await fs.readFile(path.join(cwd, 'components.json'), 'utf-8').catch(() => null);\n if (!content) return {};\n const out: Record<string, string> = {};\n let aliases: Record<string, unknown> = {};\n try {\n aliases = JSON.parse(content).aliases ?? {};\n } catch {\n return out;\n }\n for (const [key, alias] of Object.entries(aliases)) {\n // e.g. `@/components/ui` -> `./components/ui`\n if (typeof alias === 'string') out[key] = `.${alias.slice(alias.indexOf('/'))}`;\n }\n return out;\n}\n\nexport async function createConfigSchema(cwd = process.cwd()) {\n const shadcn = await readShadcnAliases(cwd);\n const defaultAliases = {\n uiDir: shadcn.ui ?? './components/ui',\n componentsDir: shadcn.components ?? './components',\n layoutDir: './layouts',\n cssDir: './styles',\n libDir: shadcn.lib ?? './lib',\n utils: shadcn.utils,\n };\n\n let framework = await detectFramework(cwd);\n if (!isSupportedFramework(framework)) framework = 'next';\n\n return z.object({\n $schema: z.string().default('node_modules/@fumadocs/cli/dist/schema.json').optional(),\n aliases: z\n .object({\n uiDir: z.string().default(defaultAliases.uiDir),\n componentsDir: z.string().default(defaultAliases.componentsDir),\n layoutDir: z.string().default(defaultAliases.layoutDir),\n cssDir: z.string().default(defaultAliases.cssDir),\n libDir: z.string().default(defaultAliases.libDir),\n /** module exporting `cn`, installed components import it instead of `lib/cn.ts` */\n utils: shadcn.utils ? z.string().default(shadcn.utils) : z.string().optional(),\n })\n .default(defaultAliases),\n\n baseDir: z.string().default(() => {\n if (framework === 'react-router') return 'app';\n // the routes directory of the framework decides whether app code lives in `src`\n const routes = { next: 'app', waku: 'pages', 'tanstack-start': 'routes' }[framework] ?? '';\n if (existsSync(path.resolve(cwd, 'src', routes))) return 'src';\n if (routes && existsSync(path.resolve(cwd, routes))) return '';\n return existsSync(path.resolve(cwd, 'src')) ? 'src' : '';\n }),\n uiLibrary: z.enum(['radix-ui', 'base-ui']).default('base-ui'),\n framework: z.literal(frameworks).default(framework),\n\n commands: z\n .object({\n /**\n * command to format output code automatically\n */\n format: z.string().optional(),\n })\n .default({}),\n });\n}\n\ntype ConfigSchema = Awaited<ReturnType<typeof createConfigSchema>>;\n\nexport type ConfigInput = z.input<ConfigSchema>;\nexport type LoadedConfig = z.output<ConfigSchema>;\n\nexport async function createOrLoadConfig(file = './cli.json'): Promise<LoadedConfig> {\n const inited = await initConfig(file);\n if (inited) return inited;\n\n const content = await fs.readFile(file, 'utf-8');\n const configSchema = await createConfigSchema();\n\n return configSchema.parse(JSON.parse(content));\n}\n\n/**\n * Write new config, skip if a config already exists\n *\n * @returns the created config, `undefined` if not created\n */\nexport async function initConfig(file = './cli.json'): Promise<LoadedConfig | undefined> {\n if (\n await fs\n .stat(file)\n .then(() => true)\n .catch(() => false)\n ) {\n return;\n }\n\n const defaultConfig = await getDefaultConfig();\n await fs.writeFile(file, JSON.stringify(defaultConfig, null, 2));\n return defaultConfig;\n}\n\nexport async function getDefaultConfig(cwd?: string) {\n const schema = await createConfigSchema(cwd);\n return schema.parse({} satisfies ConfigInput);\n}\n"],"mappings":";;;;;;AAMA,MAAM,aAAa;CAAC;CAAQ;CAAS;CAAQ;CAAgB;AAAgB;AAG7E,SAAS,qBAAqB,GAA2B;CACvD,OAAO,WAAW,SAAS,CAAc;AAC3C;;AAGA,eAAe,kBAAkB,KAA8C;CAC7E,MAAM,UAAU,MAAM,GAAG,SAAS,KAAK,KAAK,KAAK,iBAAiB,GAAG,OAAO,CAAC,CAAC,YAAY,IAAI;CAC9F,IAAI,CAAC,SAAS,OAAO,CAAC;CACtB,MAAM,MAA8B,CAAC;CACrC,IAAI,UAAmC,CAAC;CACxC,IAAI;EACF,UAAU,KAAK,MAAM,OAAO,CAAC,CAAC,WAAW,CAAC;CAC5C,QAAQ;EACN,OAAO;CACT;CACA,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,GAE/C,IAAI,OAAO,UAAU,UAAU,IAAI,OAAO,IAAI,MAAM,MAAM,MAAM,QAAQ,GAAG,CAAC;CAE9E,OAAO;AACT;AAEA,eAAsB,mBAAmB,MAAM,QAAQ,IAAI,GAAG;CAC5D,MAAM,SAAS,MAAM,kBAAkB,GAAG;CAC1C,MAAM,iBAAiB;EACrB,OAAO,OAAO,MAAM;EACpB,eAAe,OAAO,cAAc;EACpC,WAAW;EACX,QAAQ;EACR,QAAQ,OAAO,OAAO;EACtB,OAAO,OAAO;CAChB;CAEA,IAAI,YAAY,MAAM,gBAAgB,GAAG;CACzC,IAAI,CAAC,qBAAqB,SAAS,GAAG,YAAY;CAElD,OAAO,EAAE,OAAO;EACd,SAAS,EAAE,OAAO,CAAC,CAAC,QAAQ,6CAA6C,CAAC,CAAC,SAAS;EACpF,SAAS,EACN,OAAO;GACN,OAAO,EAAE,OAAO,CAAC,CAAC,QAAQ,eAAe,KAAK;GAC9C,eAAe,EAAE,OAAO,CAAC,CAAC,QAAQ,eAAe,aAAa;GAC9D,WAAW,EAAE,OAAO,CAAC,CAAC,QAAQ,eAAe,SAAS;GACtD,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,eAAe,MAAM;GAChD,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,eAAe,MAAM;;GAEhD,OAAO,OAAO,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,OAAO,KAAK,IAAI,EAAE,OAAO,CAAC,CAAC,SAAS;EAC/E,CAAC,CAAC,CACD,QAAQ,cAAc;EAEzB,SAAS,EAAE,OAAO,CAAC,CAAC,cAAc;GAChC,IAAI,cAAc,gBAAgB,OAAO;GAEzC,MAAM,SAAS;IAAE,MAAM;IAAO,MAAM;IAAS,kBAAkB;GAAS,EAAE,cAAc;GACxF,IAAI,WAAW,KAAK,QAAQ,KAAK,OAAO,MAAM,CAAC,GAAG,OAAO;GACzD,IAAI,UAAU,WAAW,KAAK,QAAQ,KAAK,MAAM,CAAC,GAAG,OAAO;GAC5D,OAAO,WAAW,KAAK,QAAQ,KAAK,KAAK,CAAC,IAAI,QAAQ;EACxD,CAAC;EACD,WAAW,EAAE,KAAK,CAAC,YAAY,SAAS,CAAC,CAAC,CAAC,QAAQ,SAAS;EAC5D,WAAW,EAAE,QAAQ,UAAU,CAAC,CAAC,QAAQ,SAAS;EAElD,UAAU,EACP,OAAO;;;;AAIN,QAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,EAC9B,CAAC,CAAC,CACD,QAAQ,CAAC,CAAC;CACf,CAAC;AACH;AAOA,eAAsB,mBAAmB,OAAO,cAAqC;CACnF,MAAM,SAAS,MAAM,WAAW,IAAI;CACpC,IAAI,QAAQ,OAAO;CAEnB,MAAM,UAAU,MAAM,GAAG,SAAS,MAAM,OAAO;CAG/C,QAAO,MAFoB,mBAAmB,EAAA,CAE1B,MAAM,KAAK,MAAM,OAAO,CAAC;AAC/C;;;;;;AAOA,eAAsB,WAAW,OAAO,cAAiD;CACvF,IACE,MAAM,GACH,KAAK,IAAI,CAAC,CACV,WAAW,IAAI,CAAC,CAChB,YAAY,KAAK,GAEpB;CAGF,MAAM,gBAAgB,MAAM,iBAAiB;CAC7C,MAAM,GAAG,UAAU,MAAM,KAAK,UAAU,eAAe,MAAM,CAAC,CAAC;CAC/D,OAAO;AACT;AAEA,eAAsB,iBAAiB,KAAc;CAEnD,QAAO,MADc,mBAAmB,GAAG,EAAA,CAC7B,MAAM,CAAC,CAAuB;AAC9C"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as createOrLoadConfig, i as createConfigSchema, n as Framework, o as getDefaultConfig, r as LoadedConfig, s as initConfig, t as ConfigInput } from "./config-
|
|
1
|
+
import { a as createOrLoadConfig, i as createConfigSchema, n as Framework, o as getDefaultConfig, r as LoadedConfig, s as initConfig, t as ConfigInput } from "./config-Bfg4yG8S.js";
|
|
2
2
|
export { ConfigInput, Framework, LoadedConfig, createConfigSchema, createOrLoadConfig, getDefaultConfig, initConfig };
|
package/dist/config.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as initConfig, n as createOrLoadConfig, r as getDefaultConfig, t as createConfigSchema } from "./config-
|
|
1
|
+
import { i as initConfig, n as createOrLoadConfig, r as getDefaultConfig, t as createConfigSchema } from "./config-Bw0kmF01.js";
|
|
2
2
|
export { createConfigSchema, createOrLoadConfig, getDefaultConfig, initConfig };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as exists } from "./fs-D6J9dOEx.js";
|
|
2
1
|
import { b as findJsxElement, d as wrapNextConfig, l as addVitePlugin, m as addJsxAttribute, p as addImport } from "./codemod-auol-p4R.js";
|
|
2
|
+
import { t as exists } from "./fs-D6J9dOEx.js";
|
|
3
3
|
import { a as reactFramework, o as reactOnly, s as registerReactRouterRoutes } from "./utils-DbMe7h6c.js";
|
|
4
4
|
import fs from "node:fs/promises";
|
|
5
5
|
import path from "node:path";
|
|
@@ -735,4 +735,4 @@ async function configureRoutes(ctx, i18n) {
|
|
|
735
735
|
//#endregion
|
|
736
736
|
export { routeModule as a, reactRouterTypes as i, findNextProxy as n, formatRoute as r, docs as t };
|
|
737
737
|
|
|
738
|
-
//# sourceMappingURL=docs
|
|
738
|
+
//# sourceMappingURL=docs--WqEHTyl.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docs-DeIEl_Kt.js","names":[],"sources":["../src/project/route.ts","../src/features/docs/templates.ts","../src/features/docs/index.ts"],"sourcesContent":["import type { I18nInfo, ReactFramework } from '@/project';\n\nexport type RouteSegment =\n /** static path, can contain multiple segments like `/llms.mdx/docs` */\n | string\n | {\n param: string;\n catchAll?: boolean;\n /** the catch-all also matches zero segments */\n optional?: boolean;\n /** static file name after the catch-all like `content.md`, part of the parameter when the framework can't express it */\n suffix?: string;\n };\n\nexport interface RouteDescriptor {\n segments: RouteSegment[];\n /** under the locale parameter when the project has i18n */\n locale?: boolean;\n}\n\nexport interface FormattedRoute {\n /** route file, relative to the base dir */\n file: string;\n /** route string of the framework, e.g. for `RouteContext<'...'>`, `createFileRoute('...')`, `route('...')` or `ApiContext<'...'>` */\n path: string;\n /** path-to-regexp pattern, for the Next.js proxy matcher and rewrites */\n pattern: string;\n}\n\ninterface Convention {\n locale: (optional: boolean) => string;\n param: (name: string, catchAll: boolean, optional: boolean, suffix?: string) => string;\n file: (segments: string[], ext: string) => string;\n path: (segments: string[]) => string;\n}\n\nconst conventions: Record<ReactFramework, Convention> = {\n next: {\n locale: () => '[lang]',\n param: (name, catchAll, optional) =>\n catchAll ? (optional ? `[[...${name}]]` : `[...${name}]`) : `[${name}]`,\n file: (segments, ext) => `app/${segments.join('/')}/route.${ext}`,\n path: (segments) => `/${segments.join('/')}`,\n },\n 'react-router': {\n locale: (optional) => (optional ? ':lang?' : ':lang'),\n param: (name, catchAll) => (catchAll ? '*' : `:${name}`),\n // `routes.ts` maps paths to files, name files after the static segments like flat routes\n file: (segments, ext) =>\n `routes/${segments.filter((segment) => !/^[:*]/.test(segment)).join('.')}.${ext}`,\n path: (segments) => segments.join('/'),\n },\n 'tanstack-start': {\n locale: (optional) => (optional ? '{-$lang}' : '$lang'),\n param: (name, catchAll) => (catchAll ? '$' : `$${name}`),\n file: (segments, ext) => `routes/${segments.join('/').replaceAll('.', '[.]')}.${ext}`,\n path: (segments) => `/${segments.join('/')}`,\n },\n waku: {\n locale: () => '[lang]',\n param: (name, catchAll, _optional, suffix) =>\n catchAll ? `[...${name}]${suffix ? `/${suffix}` : ''}` : `[${name}]`,\n file: (segments, ext) => `pages/_api/${segments.join('/')}.${ext}`,\n path: (segments) => `/${segments.join('/')}`,\n },\n};\n\n/** the locale segment of route files, with a trailing slash */\nexport function localeSegment(framework: ReactFramework, i18n: I18nInfo | null) {\n return i18n ? `${conventions[framework].locale(i18n.optionalLocale)}/` : '';\n}\n\nexport function formatRoute(\n route: RouteDescriptor,\n framework: ReactFramework,\n i18n: I18nInfo | null,\n ext = 'ts',\n): FormattedRoute {\n const convention = conventions[framework];\n const segments: string[] = [];\n const patterns: string[] = [];\n if (route.locale && i18n) {\n segments.push(convention.locale(i18n.optionalLocale));\n patterns.push(':lang');\n }\n\n for (const segment of route.segments) {\n if (typeof segment === 'string') {\n for (const part of segment.split('/')) {\n if (part.length === 0) continue;\n segments.push(part);\n patterns.push(part);\n }\n } else {\n const { param, catchAll = false, optional = false, suffix } = segment;\n segments.push(convention.param(param, catchAll, optional, suffix));\n patterns.push(catchAll ? `:${param}*` : `:${param}`);\n }\n }\n\n return {\n file: convention.file(segments, ext),\n path: convention.path(segments),\n pattern: `/${patterns.join('/')}`,\n };\n}\n\nexport interface RouteModule {\n /** import statements of the handler */\n imports: string;\n /** expression returning a `Response` */\n body: string;\n /** the handler reads `request` */\n request?: boolean;\n /** @defaultValue `['GET']` */\n methods?: string[];\n /** Next.js: never revalidate the route */\n revalidate?: boolean;\n /** Waku: prerender the route */\n static?: boolean;\n}\n\n/** the route module of a handler that only reads the request, per framework */\nexport function routeModule(\n framework: ReactFramework,\n route: FormattedRoute,\n mod: RouteModule,\n): string {\n const { imports, body, request, methods = ['GET'], revalidate, static: isStatic } = mod;\n const arg = request ? 'request: Request' : '';\n const head = `${imports.trim()}\\n\\n`;\n\n if (framework === 'react-router') {\n const out: string[] = [];\n // GET is the loader, every other method is the action\n out.push(handler('loader', 'Route.LoaderArgs'));\n if (methods.length > 1) out.push(handler('action', 'Route.ActionArgs'));\n\n return `${request ? `${reactRouterTypes(route)}\\n` : ''}${head}${out.join('\\n')}`;\n }\n\n if (framework === 'tanstack-start') {\n const out: string[] = [];\n for (const method of methods)\n out.push(` ${method}: async (${request ? '{ request }' : ''}) => ${body},`);\n\n return `import { createFileRoute } from '@tanstack/react-router';\n${head}export const Route = createFileRoute('${route.path}')({\n server: {\n handlers: {\n${out.join('\\n')}\n },\n },\n});\n`;\n }\n\n const out: string[] = [];\n if (framework === 'next' && revalidate) out.push('export const revalidate = false;\\n');\n for (const method of methods)\n out.push(`export async function ${method}(${arg}) {\n return ${body};\n}\n`);\n if (framework === 'waku' && isStatic)\n out.push(`export async function getConfig() {\n return {\n render: 'static' as const,\n } as const;\n}\n`);\n\n return `${head}${out.join('\\n')}`;\n\n function handler(name: string, type: string) {\n return `export async function ${name}(${request ? `{ request }: ${type}` : ''}) {\n return ${body};\n}\n`;\n }\n}\n\n/** import of the generated types of a React Router route module */\nexport const reactRouterTypes = (route: FormattedRoute) =>\n `import type { Route } from './+types/${route.file\n .split('/')\n .pop()!\n .replace(/\\.tsx?$/, '')}';`;\n","import type { I18nInfo, ReactFramework } from '@/project';\nimport { localeSegment } from '@/project/route';\n\nexport interface TemplateInput {\n static: boolean;\n i18n: I18nInfo | null;\n /** import specifier of `RootProvider` */\n provider: string;\n /** extra props of `RootProvider` */\n providerProps: string;\n}\n\n/** files relative to the base dir */\nexport type Template = (input: TemplateInput) => Record<string, string>;\n\nconst wrapper = (children: string) =>\n `<div className=\"flex flex-col min-h-screen\">${children}</div>`;\n\nconst i18nConfig = (optionalLocale: boolean) => `import { defineI18n } from 'fumadocs-core/i18n';\n\nexport const i18n = defineI18n({\n defaultLanguage: 'en',\n languages: ['en', 'cn'],${optionalLocale ? \"\\n hideLocale: 'default-locale',\" : ''}\n});\n`;\n\nconst sharedConstants = `export const docsRoute = '/docs';\n`;\n\nconst source = (async: boolean, i18n: boolean) => `import { loader } from 'fumadocs-core/source';\nimport { defineDocs } from 'fumadocs-mdx/macro';\nimport { docsRoute } from './shared';\n${i18n ? \"import { i18n } from '@/lib/i18n';\\n\" : ''}\nexport const docs = defineDocs({\n dir: 'content/docs',${async ? '\\n docs: {\\n async: true,\\n },' : ''}\n});\n\nexport const source = loader({\n baseUrl: docsRoute,\n source: docs.toFumadocsSource(),${i18n ? '\\n i18n,' : ''}\n});\n`;\n\nconst layoutShared = (i18n: boolean) =>\n i18n\n ? `import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';\nimport { uiTranslations } from 'fumadocs-ui/i18n';\nimport { i18n } from '@/lib/i18n';\n\nexport const translations = i18n.translations().extend(uiTranslations());\n\nexport function baseOptions(locale: string = i18n.defaultLanguage): BaseLayoutProps {\n return {\n nav: {\n title: 'My App',\n url: \\`/\\${locale}\\`,\n },\n };\n}\n`\n : `import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';\n\nexport function baseOptions(): BaseLayoutProps {\n return {\n nav: {\n title: 'My App',\n },\n };\n}\n`;\n\nconst mdx = `import defaultMdxComponents from 'fumadocs-ui/mdx';\nimport type { MDXComponents } from 'mdx/types';\n\nexport function getMDXComponents(components?: MDXComponents) {\n return {\n ...defaultMdxComponents,\n ...components,\n } satisfies MDXComponents;\n}\n\nexport const useMDXComponents = getMDXComponents;\n\ndeclare global {\n type MDXProvidedComponents = ReturnType<typeof getMDXComponents>;\n}\n`;\n\nconst search = (i18n: boolean) => `'use client';\nimport {\n SearchDialog,\n SearchDialogClose,\n SearchDialogContent,\n SearchDialogHeader,\n SearchDialogIcon,\n SearchDialogInput,\n SearchDialogList,\n SearchDialogOverlay,\n type SharedProps,\n} from 'fumadocs-ui/components/dialog/search';\nimport { useDocsSearch } from 'fumadocs-core/search/client';\nimport { staticClient } from 'fumadocs-core/search/client/orama-static';\n${i18n ? \"import { useI18n } from 'fumadocs-ui/contexts/i18n';\\n\" : ''}\nexport default function DefaultSearchDialog(props: SharedProps) {\n${i18n ? ' const { locale } = useI18n();\\n' : ''} const { search, setSearch, query } = useDocsSearch({\n client: staticClient(${i18n ? '{ locale }' : ''}),\n });\n\n return (\n <SearchDialog search={search} onSearchChange={setSearch} isLoading={query.isLoading} {...props}>\n <SearchDialogOverlay />\n <SearchDialogContent>\n <SearchDialogHeader>\n <SearchDialogIcon />\n <SearchDialogInput />\n <SearchDialogClose />\n </SearchDialogHeader>\n <SearchDialogList items={query.data !== 'empty' ? query.data : null} />\n </SearchDialogContent>\n </SearchDialog>\n );\n}\n`;\n\nfunction shared(input: TemplateInput, async: boolean): Record<string, string> {\n const i18n = input.i18n !== null;\n return {\n 'lib/shared.ts': sharedConstants,\n 'lib/source.ts': source(async, i18n),\n 'lib/layout.shared.tsx': layoutShared(i18n),\n 'components/mdx.tsx': mdx,\n ...(input.static ? { 'components/search.tsx': search(i18n) } : {}),\n ...(input.i18n ? { 'lib/i18n.ts': i18nConfig(input.i18n.optionalLocale) } : {}),\n };\n}\n\nconst searchImport = (input: TemplateInput) =>\n input.static ? `import SearchDialog from '@/components/search';\\n` : '';\n\n/** imports of the root provider, with the i18n provider */\nconst providerImports = (input: TemplateInput) =>\n `import { RootProvider } from '${input.provider}';\n${searchImport(input)}${\n input.i18n\n ? `import { i18nProvider } from 'fumadocs-ui/i18n';\nimport { translations } from '@/lib/layout.shared';\nimport { i18n } from '@/lib/i18n';\n`\n : ''\n }`;\n\nconst providerProps = (input: TemplateInput) =>\n `${input.i18n ? ' i18n={i18nProvider(translations, lang)}' : ''}${input.providerProps}`;\n\n/** the docs page for React Router & TanStack Start, where MDX content is loaded lazily on client */\nconst clientContent = `function Content({ path }: { path: string }) {\n const page = docs.getPage(path);\n if (!page) throw new Error(\\`unknown page: \\${path}\\`);\n\n const { toc } = use(page.load());\n const MDX = page.body;\n\n return (\n <DocsPage toc={toc}>\n <DocsTitle>{page.title}</DocsTitle>\n <DocsDescription>{page.description}</DocsDescription>\n <DocsBody>\n <MDX components={useMDXComponents()} />\n </DocsBody>\n </DocsPage>\n );\n}`;\n\nconst searchRoute = {\n next: (input: TemplateInput) => `import { source } from '@/lib/source';\nimport { createFromSource } from 'fumadocs-core/search/server';\n${input.static ? '\\nexport const revalidate = false;\\n' : ''}\nexport const { ${input.static ? 'staticGET: GET' : 'GET'} } = createFromSource(source);\n`,\n waku: `import { createFromSource } from 'fumadocs-core/search/server';\nimport { source } from '@/lib/source';\n\nexport const { GET } = createFromSource(source);\n`,\n};\n\nexport const templates: Record<ReactFramework, Template> = {\n next: (input) => {\n const i18n = input.i18n !== null;\n // route group with `[lang]` segment for i18n\n const dir = i18n ? 'app/(docs)/[lang]' : 'app/(docs)';\n const route = i18n ? '/[lang]' : '';\n const lang = i18n ? ', params.lang' : '';\n\n return {\n ...shared(input, false),\n [`${dir}/layout.tsx`]: input.static\n ? `'use client';\n${providerImports(input)}${i18n ? \"import { use } from 'react';\\n\" : ''}\nexport default function Layout({ ${i18n ? 'params, ' : ''}children }: LayoutProps<'${route || '/'}'>) {\n${i18n ? ' const { lang } = use(params);\\n\\n' : ''} return (\n <RootProvider${providerProps(input)}>\n ${wrapper('{children}')}\n </RootProvider>\n );\n}\n`\n : `${providerImports(input)}\nexport default ${i18n ? 'async ' : ''}function Layout({ ${i18n ? 'params, ' : ''}children }: LayoutProps<'${route || '/'}'>) {\n${i18n ? ' const { lang } = await params;\\n\\n' : ''} return (\n <RootProvider${providerProps(input)}>\n ${wrapper('{children}')}\n </RootProvider>\n );\n}\n`,\n [`${dir}/docs/layout.tsx`]: `import { source } from '@/lib/source';\nimport { DocsLayout } from 'fumadocs-ui/layouts/docs';\nimport { baseOptions } from '@/lib/layout.shared';\n\nexport default ${i18n ? 'async ' : ''}function Layout({ ${i18n ? 'params, ' : ''}children }: LayoutProps<'${route}/docs'>) {\n${i18n ? ' const { lang } = await params;\\n\\n' : ''} return (\n <DocsLayout tree={source.getPageTree(${i18n ? 'lang' : ''})} {...baseOptions(${i18n ? 'lang' : ''})}>\n {children}\n </DocsLayout>\n );\n}\n`,\n [`${dir}/docs/[[...slug]]/page.tsx`]: `import { source } from '@/lib/source';\nimport { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';\nimport { notFound } from 'next/navigation';\nimport { getMDXComponents } from '@/components/mdx';\nimport type { Metadata } from 'next';\nimport { createRelativeLink } from 'fumadocs-ui/mdx';\n\nexport default async function Page(props: PageProps<'${route}/docs/[[...slug]]'>) {\n const params = await props.params;\n const page = source.getPage(params.slug${lang});\n if (!page) notFound();\n\n const MDX = page.data.body;\n\n return (\n <DocsPage toc={page.data.toc} full={page.data.full}>\n <DocsTitle>{page.data.title}</DocsTitle>\n <DocsDescription>{page.data.description}</DocsDescription>\n <DocsBody>\n <MDX\n components={getMDXComponents({\n // this allows you to link to other pages with relative file paths\n a: createRelativeLink(source, page),\n })}\n />\n </DocsBody>\n </DocsPage>\n );\n}\n\nexport async function generateStaticParams() {\n return source.generateParams();\n}\n\nexport async function generateMetadata(props: PageProps<'${route}/docs/[[...slug]]'>): Promise<Metadata> {\n const params = await props.params;\n const page = source.getPage(params.slug${lang});\n if (!page) notFound();\n\n return {\n title: page.data.title,\n description: page.data.description,\n };\n}\n`,\n 'app/api/search/route.ts': searchRoute.next(input),\n };\n },\n\n 'react-router': (input) => {\n const i18n = input.i18n !== null;\n return {\n ...shared(input, true),\n 'routes/docs/layout.tsx': `import { Outlet${i18n ? ', useParams' : ''} } from 'react-router';\n${providerImports(input)}\nexport default function Layout() {\n${i18n ? ' const { lang = i18n.defaultLanguage } = useParams();\\n\\n' : ''} return (\n <RootProvider${providerProps(input)}>\n ${wrapper('\\n <Outlet />\\n ')}\n </RootProvider>\n );\n}\n`,\n 'routes/docs/page.tsx': `import type { Route } from './+types/page';\nimport { DocsLayout } from 'fumadocs-ui/layouts/docs';\nimport { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';\nimport { docs, source } from '@/lib/source';\nimport { baseOptions } from '@/lib/layout.shared';\nimport { useFumadocsLoader } from 'fumadocs-core/source/client';\nimport { useMDXComponents } from '@/components/mdx';\nimport { use } from 'react';\n\nexport async function loader({ params }: Route.LoaderArgs) {\n const slugs = params['*'].split('/').filter((v) => v.length > 0);\n const page = source.getPage(slugs${i18n ? ', params.lang' : ''});\n if (!page) throw new Response('Not found', { status: 404 });\n\n return {\n path: page.path,\n url: page.url,\n pageTree: await source.serializePageTree(source.getPageTree(${i18n ? 'params.lang' : ''})),\n };\n}\n\n${clientContent.replace('<DocsPage toc={toc}>', '<DocsPage toc={toc}>\\n <title>{page.title}</title>\\n <meta name=\"description\" content={page.description} />')}\n\nexport default function Page({ loaderData${i18n ? ', params' : ''} }: Route.ComponentProps) {\n const { path, pageTree } = useFumadocsLoader(loaderData);\n\n return (\n <DocsLayout {...baseOptions(${i18n ? 'params.lang' : ''})} tree={pageTree}>\n <Content path={path} />\n </DocsLayout>\n );\n}\n`,\n 'routes/docs/search.ts': `import type { Route } from './+types/search';\nimport { createFromSource } from 'fumadocs-core/search/server';\nimport { source } from '@/lib/source';\n\nconst server = createFromSource(source);\n\nexport async function loader(${input.static ? '' : '{ request }: Route.LoaderArgs'}) {\n return server.${input.static ? 'staticGET()' : 'GET(request)'};\n}\n`,\n };\n },\n\n 'tanstack-start': (input) => {\n const seg = localeSegment('tanstack-start', input.i18n);\n const i18n = input.i18n !== null;\n return {\n ...shared(input, true),\n 'routes/_docs.tsx': `import { createFileRoute, Outlet${i18n ? ', useParams' : ''} } from '@tanstack/react-router';\n${providerImports(input)}\nexport const Route = createFileRoute('/_docs')({\n component: Layout,\n});\n\nfunction Layout() {\n${i18n ? ' const { lang = i18n.defaultLanguage } = useParams({ strict: false });\\n\\n' : ''} return (\n <RootProvider${providerProps(input)}>\n ${wrapper('\\n <Outlet />\\n ')}\n </RootProvider>\n );\n}\n`,\n [`routes/_docs/${seg}docs/$.tsx`]: `import { createFileRoute, notFound } from '@tanstack/react-router';\nimport { DocsLayout } from 'fumadocs-ui/layouts/docs';\nimport { createServerFn } from '@tanstack/react-start';\nimport { docs, source } from '@/lib/source';\nimport { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';\nimport { baseOptions } from '@/lib/layout.shared';\nimport { useFumadocsLoader } from 'fumadocs-core/source/client';\nimport { Suspense, use } from 'react';\nimport { useMDXComponents } from '@/components/mdx';\n\nexport const Route = createFileRoute('/_docs/${seg}docs/$')({\n component: Page,\n loader: async ({ params }) => {\n const data = await serverLoader({\n data: {\n slugs: params._splat?.split('/') ?? [],${i18n ? '\\n lang: params.lang,' : ''}\n },\n });\n await docs.getPage(data.path)?.preload();\n return data;\n },\n});\n\nconst serverLoader = createServerFn({\n method: 'GET',\n})\n .validator((params: { slugs: string[]${i18n ? '; lang?: string' : ''} }) => params)\n .handler(async ({ data: { slugs${i18n ? ', lang' : ''} } }) => {\n const page = source.getPage(slugs${i18n ? ', lang' : ''});\n if (!page) throw notFound();\n\n return {\n path: page.path,\n pageTree: await source.serializePageTree(source.getPageTree(${i18n ? 'lang' : ''})),\n };\n });\n\n${clientContent}\n\nfunction Page() {\n${i18n ? ' const { lang } = Route.useParams();\\n' : ''} const data = useFumadocsLoader(Route.useLoaderData());\n\n return (\n <DocsLayout {...baseOptions(${i18n ? 'lang' : ''})} tree={data.pageTree}>\n <Suspense>\n <Content path={data.path} />\n </Suspense>\n </DocsLayout>\n );\n}\n`,\n 'routes/api/search.ts': `import { createFileRoute } from '@tanstack/react-router';\nimport { source } from '@/lib/source';\nimport { createFromSource } from 'fumadocs-core/search/server';\n\nconst server = createFromSource(source);\n\nexport const Route = createFileRoute('/api/search')({\n server: {\n handlers: {\n GET: ${input.static ? '() => server.staticGET()' : 'async ({ request }) => server.GET(request)'},\n },\n },\n});\n`,\n };\n },\n\n waku: (input) => {\n const i18n = input.i18n !== null;\n const page = `import { source } from '@/lib/source';\nimport type { PageProps } from 'waku/router';\nimport { unstable_notFound } from 'waku/router/server';\nimport { createRelativeLink } from 'fumadocs-ui/mdx';\nimport { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';\nimport { getMDXComponents } from '@/components/mdx';\n${i18n ? \"import { DocsLayout } from 'fumadocs-ui/layouts/docs';\\nimport { baseOptions } from '@/lib/layout.shared';\\n\" : ''}\nexport default function Page({ slug${i18n ? ', lang' : ''} }: PageProps<'${i18n ? '/[lang]' : ''}/docs/[...slug]'>) {\n const page = source.getPage(slug${i18n ? ', lang' : ''});\n if (!page) unstable_notFound();\n\n const MDX = page.data.body;\n const content = (\n <DocsPage toc={page.data.toc}>\n <DocsTitle>{page.data.title}</DocsTitle>\n <DocsDescription>{page.data.description}</DocsDescription>\n <DocsBody>\n <MDX\n components={getMDXComponents({\n // this allows you to link to other pages with relative file paths\n a: createRelativeLink(source, page),\n })}\n />\n </DocsBody>\n </DocsPage>\n );\n${\n i18n\n ? `\n // layouts don't receive the locale, render the docs layout here\n return (\n <DocsLayout {...baseOptions(lang)} tree={source.getPageTree(lang)}>\n {content}\n </DocsLayout>\n );`\n : `\n return content;`\n}\n}\n\nexport async function getConfig() {\n return {\n render: 'static',\n staticPaths: source.generateParams().map((item) => ${i18n ? '[item.lang, ...item.slug]' : 'item.slug'}),\n } as const;\n}\n`;\n\n return {\n ...shared(input, false),\n 'pages/(docs)/_layout.tsx': i18n\n ? `import type { ReactNode } from 'react';\nimport { Provider } from '@/components/provider';\n\nexport default function Layout({ children }: { children: ReactNode }) {\n return (\n <Provider>\n ${wrapper('{children}')}\n </Provider>\n );\n}\n`\n : `import type { ReactNode } from 'react';\n${providerImports(input)}\nexport default function Layout({ children }: { children: ReactNode }) {\n return (\n <RootProvider${providerProps(input)}>\n ${wrapper('{children}')}\n </RootProvider>\n );\n}\n`,\n ...(i18n\n ? {\n 'components/provider.tsx': `'use client';\nimport type { ReactNode } from 'react';\nimport { useRouter } from 'waku/router/client';\n${providerImports(input)}\nexport function Provider({ children }: { children: ReactNode }) {\n const router = useRouter();\n const lang = router.path.split('/')[1] || i18n.defaultLanguage;\n\n return <RootProvider${providerProps(input)}>{children}</RootProvider>;\n}\n`,\n 'pages/(docs)/[lang]/docs/[...slug].tsx': page,\n }\n : {\n 'pages/(docs)/docs/_layout.tsx': `import type { ReactNode } from 'react';\nimport { DocsLayout } from 'fumadocs-ui/layouts/docs';\nimport { source } from '@/lib/source';\nimport { baseOptions } from '@/lib/layout.shared';\n\nexport default function Layout({ children }: { children: ReactNode }) {\n return (\n <DocsLayout {...baseOptions()} tree={source.getPageTree()}>\n {children}\n </DocsLayout>\n );\n}\n`,\n 'pages/(docs)/docs/[...slug].tsx': page,\n }),\n 'pages/_api/api/search.ts': searchRoute.waku,\n };\n },\n};\n\nexport const nextProxy = `import { createI18nMiddleware } from 'fumadocs-core/i18n/middleware';\nimport { i18n } from '@/lib/i18n';\n\nexport default createI18nMiddleware(i18n);\n\nexport const config = {\n // only the docs routes, add the ones of other features here\n matcher: ['/docs/:path*', '/:lang/docs/:path*'],\n};\n`;\n\nexport const sampleContent = `---\ntitle: Hello World\ndescription: Your first document\n---\n\nWelcome to the docs! You can edit this page in \\`content/docs/index.mdx\\`.\n\n## Heading\n\n<Cards>\n <Card title=\"Learn more about Fumadocs\" href=\"https://fumadocs.dev\" />\n</Cards>\n`;\n\nexport const sampleContentCn = `---\ntitle: 你好,世界\ndescription: 你的第一份文檔\n---\n\n歡迎來到文檔!你可以在 \\`content/docs/index.cn.mdx\\` 編輯這個頁面。\n`;\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { Feature, FeatureContext } from '@/features';\nimport type { I18nInfo, Project } from '@/project';\nimport {\n addImport,\n addJsxAttribute,\n addVitePlugin,\n findJsxElement,\n wrapNextConfig,\n} from '@/codemod';\nimport { exists } from '@/utils/fs';\nimport { localeSegment } from '@/project/route';\nimport { nextProxy, sampleContent, sampleContentCn, templates } from './templates';\nimport { reactFramework, reactOnly, registerReactRouterRoutes } from '../utils';\n\nconst cssImports = (preset: string) => [\n `@import 'fumadocs-ui/css/${preset}.css';`,\n `@import 'fumadocs-ui/css/preset.css';`,\n];\n\nexport const docs: Feature<{ i18n: boolean }> = {\n id: 'docs',\n title: 'Docs',\n description: 'set up Fumadocs on your app, in a dedicated route group',\n supports: reactOnly,\n options: {\n i18n: { message: 'Enable internationalization?', initialValue: false },\n },\n async detect(project) {\n return exists(path.join(project.cwd, project.baseDir, 'lib/source.ts'));\n },\n async apply(ctx, options) {\n const { project } = ctx;\n const { baseDir, packageJson, config } = project;\n const framework = reactFramework(project);\n // Waku has no optional route segments, the locale is always in the URL\n const i18n = project.i18n ?? (options.i18n ? { optionalLocale: framework !== 'waku' } : null);\n const providerProps: string[] = [];\n if (project.static) providerProps.push('search={{ SearchDialog }}');\n if ('next-themes' in (packageJson.dependencies ?? {}))\n providerProps.push('theme={{ enabled: false }}');\n\n ctx.addDependencies({\n 'fumadocs-core': null,\n 'fumadocs-mdx': null,\n 'fumadocs-ui': config.uiLibrary === 'base-ui' ? 'npm:@fumadocs/base-ui' : null,\n });\n ctx.addDependencies({ '@types/mdx': null }, true);\n\n const files = templates[framework]({\n static: project.static,\n i18n,\n provider: project.info.provider,\n providerProps: providerProps.map((prop) => ` ${prop}`).join(''),\n });\n for (const [file, content] of Object.entries(files)) {\n await ctx.write(path.posix.join(baseDir, file), content);\n }\n await ctx.write('content/docs/index.mdx', sampleContent);\n if (i18n) await ctx.write('content/docs/index.cn.mdx', sampleContentCn);\n await ctx.append('.gitignore', ['.source']);\n if (i18n && framework === 'next') await configureProxy(ctx);\n\n await configureBundler(ctx);\n await configureCss(ctx);\n await suppressHydrationWarning(ctx);\n if (framework === 'react-router') await configureRoutes(ctx, i18n);\n\n const tsconfig = await fs\n .readFile(path.join(project.cwd, 'tsconfig.json'), 'utf-8')\n .catch(() => '');\n if (!tsconfig.includes('\"@/*\"')) {\n ctx.note(\n `Generated files import from the \\`@/*\\` alias, add it to \\`tsconfig.json\\`:\\n \"paths\": { \"@/*\": [\"./${baseDir ? `${baseDir}/` : ''}*\"] }`,\n );\n }\n if (project.static && framework === 'tanstack-start') {\n ctx.note(\n 'In SPA mode, prerender the docs pages and search index, see https://fumadocs.dev/docs/manual-installation/tanstack-start.',\n );\n }\n if (i18n && framework === 'react-router') {\n ctx.note(\n 'When prerendering, list the docs pages with `source.getPages().map((page) => page.url)` instead of globbing content files, see https://fumadocs.dev/docs/internationalization/react-router.',\n );\n }\n if (i18n) {\n ctx.note(\n `Languages are configured in \\`lib/i18n.ts\\`, translated content uses a locale suffix like \\`index.cn.mdx\\`.\\nUI translations: https://fumadocs.dev/docs/internationalization#translations`,\n );\n }\n ctx.note(\n `Start the dev server and open ${i18n && !i18n.optionalLocale ? '/en/docs' : '/docs'} to see your docs.`,\n );\n },\n};\n\n/** the Next.js proxy (middleware) file of the project, relative to cwd */\nexport async function findNextProxy({ cwd, baseDir }: Project) {\n for (const file of ['proxy.ts', 'middleware.ts']) {\n for (const dir of new Set([baseDir, ''])) {\n const target = path.join(dir, file);\n if (await exists(path.join(cwd, target))) return target;\n }\n }\n}\n\n/** the i18n middleware redirects & rewrites docs URLs without locale */\nasync function configureProxy(ctx: FeatureContext) {\n const existing = await findNextProxy(ctx.project);\n if (!existing) {\n await ctx.write(path.join(ctx.project.baseDir, 'proxy.ts'), nextProxy);\n return;\n }\n\n ctx.note(\n `A proxy already exists at ${existing}, handle the docs locale there. Fumadocs provides \\`createI18nMiddleware\\` from 'fumadocs-core/i18n/middleware', see https://fumadocs.dev/docs/internationalization/next.`,\n );\n}\n\nasync function configureBundler(ctx: FeatureContext) {\n const { framework, configFile } = ctx.project;\n const edited =\n configFile !== undefined &&\n (await ctx\n .source(configFile, (file) => {\n const ok =\n framework === 'next'\n ? wrapNextConfig(file)\n : addVitePlugin(\n file,\n { name: 'fumadocsMdx', from: 'fumadocs-mdx/vite' },\n framework === 'waku' ? ['vite', 'plugins'] : ['plugins'],\n );\n if (!ok) throw new Error(`cannot update ${configFile}`);\n })\n .catch(() => false));\n\n if (!edited) {\n ctx.note(\n framework === 'next'\n ? \"Wrap your Next.js config with `createMDX()` from 'fumadocs-mdx/next', see https://fumadocs.dev/docs/mdx/next.\"\n : \"Add `fumadocsMdx()` from 'fumadocs-mdx/vite' to the Vite plugins of your config file.\",\n );\n }\n}\n\n/** resolve the global CSS file imported by the root file */\nasync function findCssEntry({ cwd, baseDir, info }: Project): Promise<string | undefined> {\n const rootFile = path.join(baseDir, info.rootFile);\n const content = await fs.readFile(path.join(cwd, rootFile), 'utf-8').catch(() => '');\n const match = /import\\s+(?:\\w+\\s+from\\s+)?['\"]([^'\"]+\\.css)(?:\\?url)?['\"]/.exec(content);\n if (!match) return;\n const specifier = match[1];\n\n if (specifier.startsWith('@/')) return path.join(baseDir, specifier.slice(2));\n if (specifier.startsWith('.')) return path.join(path.dirname(rootFile), specifier);\n}\n\nasync function configureCss(ctx: FeatureContext) {\n const { cwd } = ctx.project;\n const preset = (await exists(path.join(cwd, 'components.json'))) ? 'shadcn' : 'neutral';\n const entry = await findCssEntry(ctx.project);\n if (entry && (await exists(path.join(cwd, entry)))) {\n await ctx.append(entry, cssImports(preset));\n return;\n }\n\n ctx.note(\n `Add the styles to your global CSS file (after \\`@import 'tailwindcss'\\`):\\n ${cssImports(preset).join('\\n ')}`,\n );\n}\n\n/** `next-themes` sets the theme class on `<html>`, React warns about the mismatch without this attribute */\nasync function suppressHydrationWarning(ctx: FeatureContext) {\n const { baseDir, info } = ctx.project;\n const edited = await ctx.source(path.join(baseDir, info.rootFile), (file) => {\n const html = findJsxElement(file, 'html')?.openingElement;\n if (!html || file.code.slice(html.start, html.end).includes('suppressHydrationWarning')) return;\n addJsxAttribute(file, html, 'suppressHydrationWarning');\n });\n\n if (!edited)\n ctx.note('Add `suppressHydrationWarning` to the `<html>` element of your root layout.');\n}\n\nasync function configureRoutes(ctx: FeatureContext, i18n: I18nInfo | null) {\n const added = await registerReactRouterRoutes(ctx, [\n `layout('routes/docs/layout.tsx', [route('${localeSegment('react-router', i18n)}docs/*', 'routes/docs/page.tsx')])`,\n { path: 'api/search', file: 'routes/docs/search.ts', pattern: '/api/search' },\n ]);\n if (!added) return;\n await ctx.source(path.join(ctx.project.baseDir, 'routes.ts'), (file) => {\n addImport(file, { from: '@react-router/dev/routes', named: ['layout', 'route'] });\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"docs--WqEHTyl.js","names":[],"sources":["../src/project/route.ts","../src/features/docs/templates.ts","../src/features/docs/index.ts"],"sourcesContent":["import type { I18nInfo, ReactFramework } from '@/project';\n\nexport type RouteSegment =\n /** static path, can contain multiple segments like `/llms.mdx/docs` */\n | string\n | {\n param: string;\n catchAll?: boolean;\n /** the catch-all also matches zero segments */\n optional?: boolean;\n /** static file name after the catch-all like `content.md`, part of the parameter when the framework can't express it */\n suffix?: string;\n };\n\nexport interface RouteDescriptor {\n segments: RouteSegment[];\n /** under the locale parameter when the project has i18n */\n locale?: boolean;\n}\n\nexport interface FormattedRoute {\n /** route file, relative to the base dir */\n file: string;\n /** route string of the framework, e.g. for `RouteContext<'...'>`, `createFileRoute('...')`, `route('...')` or `ApiContext<'...'>` */\n path: string;\n /** path-to-regexp pattern, for the Next.js proxy matcher and rewrites */\n pattern: string;\n}\n\ninterface Convention {\n locale: (optional: boolean) => string;\n param: (name: string, catchAll: boolean, optional: boolean, suffix?: string) => string;\n file: (segments: string[], ext: string) => string;\n path: (segments: string[]) => string;\n}\n\nconst conventions: Record<ReactFramework, Convention> = {\n next: {\n locale: () => '[lang]',\n param: (name, catchAll, optional) =>\n catchAll ? (optional ? `[[...${name}]]` : `[...${name}]`) : `[${name}]`,\n file: (segments, ext) => `app/${segments.join('/')}/route.${ext}`,\n path: (segments) => `/${segments.join('/')}`,\n },\n 'react-router': {\n locale: (optional) => (optional ? ':lang?' : ':lang'),\n param: (name, catchAll) => (catchAll ? '*' : `:${name}`),\n // `routes.ts` maps paths to files, name files after the static segments like flat routes\n file: (segments, ext) =>\n `routes/${segments.filter((segment) => !/^[:*]/.test(segment)).join('.')}.${ext}`,\n path: (segments) => segments.join('/'),\n },\n 'tanstack-start': {\n locale: (optional) => (optional ? '{-$lang}' : '$lang'),\n param: (name, catchAll) => (catchAll ? '$' : `$${name}`),\n file: (segments, ext) => `routes/${segments.join('/').replaceAll('.', '[.]')}.${ext}`,\n path: (segments) => `/${segments.join('/')}`,\n },\n waku: {\n locale: () => '[lang]',\n param: (name, catchAll, _optional, suffix) =>\n catchAll ? `[...${name}]${suffix ? `/${suffix}` : ''}` : `[${name}]`,\n file: (segments, ext) => `pages/_api/${segments.join('/')}.${ext}`,\n path: (segments) => `/${segments.join('/')}`,\n },\n};\n\n/** the locale segment of route files, with a trailing slash */\nexport function localeSegment(framework: ReactFramework, i18n: I18nInfo | null) {\n return i18n ? `${conventions[framework].locale(i18n.optionalLocale)}/` : '';\n}\n\nexport function formatRoute(\n route: RouteDescriptor,\n framework: ReactFramework,\n i18n: I18nInfo | null,\n ext = 'ts',\n): FormattedRoute {\n const convention = conventions[framework];\n const segments: string[] = [];\n const patterns: string[] = [];\n if (route.locale && i18n) {\n segments.push(convention.locale(i18n.optionalLocale));\n patterns.push(':lang');\n }\n\n for (const segment of route.segments) {\n if (typeof segment === 'string') {\n for (const part of segment.split('/')) {\n if (part.length === 0) continue;\n segments.push(part);\n patterns.push(part);\n }\n } else {\n const { param, catchAll = false, optional = false, suffix } = segment;\n segments.push(convention.param(param, catchAll, optional, suffix));\n patterns.push(catchAll ? `:${param}*` : `:${param}`);\n }\n }\n\n return {\n file: convention.file(segments, ext),\n path: convention.path(segments),\n pattern: `/${patterns.join('/')}`,\n };\n}\n\nexport interface RouteModule {\n /** import statements of the handler */\n imports: string;\n /** expression returning a `Response` */\n body: string;\n /** the handler reads `request` */\n request?: boolean;\n /** @defaultValue `['GET']` */\n methods?: string[];\n /** Next.js: never revalidate the route */\n revalidate?: boolean;\n /** Waku: prerender the route */\n static?: boolean;\n}\n\n/** the route module of a handler that only reads the request, per framework */\nexport function routeModule(\n framework: ReactFramework,\n route: FormattedRoute,\n mod: RouteModule,\n): string {\n const { imports, body, request, methods = ['GET'], revalidate, static: isStatic } = mod;\n const arg = request ? 'request: Request' : '';\n const head = `${imports.trim()}\\n\\n`;\n\n if (framework === 'react-router') {\n const out: string[] = [];\n // GET is the loader, every other method is the action\n out.push(handler('loader', 'Route.LoaderArgs'));\n if (methods.length > 1) out.push(handler('action', 'Route.ActionArgs'));\n\n return `${request ? `${reactRouterTypes(route)}\\n` : ''}${head}${out.join('\\n')}`;\n }\n\n if (framework === 'tanstack-start') {\n const out: string[] = [];\n for (const method of methods)\n out.push(` ${method}: async (${request ? '{ request }' : ''}) => ${body},`);\n\n return `import { createFileRoute } from '@tanstack/react-router';\n${head}export const Route = createFileRoute('${route.path}')({\n server: {\n handlers: {\n${out.join('\\n')}\n },\n },\n});\n`;\n }\n\n const out: string[] = [];\n if (framework === 'next' && revalidate) out.push('export const revalidate = false;\\n');\n for (const method of methods)\n out.push(`export async function ${method}(${arg}) {\n return ${body};\n}\n`);\n if (framework === 'waku' && isStatic)\n out.push(`export async function getConfig() {\n return {\n render: 'static' as const,\n } as const;\n}\n`);\n\n return `${head}${out.join('\\n')}`;\n\n function handler(name: string, type: string) {\n return `export async function ${name}(${request ? `{ request }: ${type}` : ''}) {\n return ${body};\n}\n`;\n }\n}\n\n/** import of the generated types of a React Router route module */\nexport const reactRouterTypes = (route: FormattedRoute) =>\n `import type { Route } from './+types/${route.file\n .split('/')\n .pop()!\n .replace(/\\.tsx?$/, '')}';`;\n","import type { I18nInfo, ReactFramework } from '@/project';\nimport { localeSegment } from '@/project/route';\n\nexport interface TemplateInput {\n static: boolean;\n i18n: I18nInfo | null;\n /** import specifier of `RootProvider` */\n provider: string;\n /** extra props of `RootProvider` */\n providerProps: string;\n}\n\n/** files relative to the base dir */\nexport type Template = (input: TemplateInput) => Record<string, string>;\n\nconst wrapper = (children: string) =>\n `<div className=\"flex flex-col min-h-screen\">${children}</div>`;\n\nconst i18nConfig = (optionalLocale: boolean) => `import { defineI18n } from 'fumadocs-core/i18n';\n\nexport const i18n = defineI18n({\n defaultLanguage: 'en',\n languages: ['en', 'cn'],${optionalLocale ? \"\\n hideLocale: 'default-locale',\" : ''}\n});\n`;\n\nconst sharedConstants = `export const docsRoute = '/docs';\n`;\n\nconst source = (async: boolean, i18n: boolean) => `import { loader } from 'fumadocs-core/source';\nimport { defineDocs } from 'fumadocs-mdx/macro';\nimport { docsRoute } from './shared';\n${i18n ? \"import { i18n } from '@/lib/i18n';\\n\" : ''}\nexport const docs = defineDocs({\n dir: 'content/docs',${async ? '\\n docs: {\\n async: true,\\n },' : ''}\n});\n\nexport const source = loader({\n baseUrl: docsRoute,\n source: docs.toFumadocsSource(),${i18n ? '\\n i18n,' : ''}\n});\n`;\n\nconst layoutShared = (i18n: boolean) =>\n i18n\n ? `import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';\nimport { uiTranslations } from 'fumadocs-ui/i18n';\nimport { i18n } from '@/lib/i18n';\n\nexport const translations = i18n.translations().extend(uiTranslations());\n\nexport function baseOptions(locale: string = i18n.defaultLanguage): BaseLayoutProps {\n return {\n nav: {\n title: 'My App',\n url: \\`/\\${locale}\\`,\n },\n };\n}\n`\n : `import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';\n\nexport function baseOptions(): BaseLayoutProps {\n return {\n nav: {\n title: 'My App',\n },\n };\n}\n`;\n\nconst mdx = `import defaultMdxComponents from 'fumadocs-ui/mdx';\nimport type { MDXComponents } from 'mdx/types';\n\nexport function getMDXComponents(components?: MDXComponents) {\n return {\n ...defaultMdxComponents,\n ...components,\n } satisfies MDXComponents;\n}\n\nexport const useMDXComponents = getMDXComponents;\n\ndeclare global {\n type MDXProvidedComponents = ReturnType<typeof getMDXComponents>;\n}\n`;\n\nconst search = (i18n: boolean) => `'use client';\nimport {\n SearchDialog,\n SearchDialogClose,\n SearchDialogContent,\n SearchDialogHeader,\n SearchDialogIcon,\n SearchDialogInput,\n SearchDialogList,\n SearchDialogOverlay,\n type SharedProps,\n} from 'fumadocs-ui/components/dialog/search';\nimport { useDocsSearch } from 'fumadocs-core/search/client';\nimport { staticClient } from 'fumadocs-core/search/client/orama-static';\n${i18n ? \"import { useI18n } from 'fumadocs-ui/contexts/i18n';\\n\" : ''}\nexport default function DefaultSearchDialog(props: SharedProps) {\n${i18n ? ' const { locale } = useI18n();\\n' : ''} const { search, setSearch, query } = useDocsSearch({\n client: staticClient(${i18n ? '{ locale }' : ''}),\n });\n\n return (\n <SearchDialog search={search} onSearchChange={setSearch} isLoading={query.isLoading} {...props}>\n <SearchDialogOverlay />\n <SearchDialogContent>\n <SearchDialogHeader>\n <SearchDialogIcon />\n <SearchDialogInput />\n <SearchDialogClose />\n </SearchDialogHeader>\n <SearchDialogList items={query.data !== 'empty' ? query.data : null} />\n </SearchDialogContent>\n </SearchDialog>\n );\n}\n`;\n\nfunction shared(input: TemplateInput, async: boolean): Record<string, string> {\n const i18n = input.i18n !== null;\n return {\n 'lib/shared.ts': sharedConstants,\n 'lib/source.ts': source(async, i18n),\n 'lib/layout.shared.tsx': layoutShared(i18n),\n 'components/mdx.tsx': mdx,\n ...(input.static ? { 'components/search.tsx': search(i18n) } : {}),\n ...(input.i18n ? { 'lib/i18n.ts': i18nConfig(input.i18n.optionalLocale) } : {}),\n };\n}\n\nconst searchImport = (input: TemplateInput) =>\n input.static ? `import SearchDialog from '@/components/search';\\n` : '';\n\n/** imports of the root provider, with the i18n provider */\nconst providerImports = (input: TemplateInput) =>\n `import { RootProvider } from '${input.provider}';\n${searchImport(input)}${\n input.i18n\n ? `import { i18nProvider } from 'fumadocs-ui/i18n';\nimport { translations } from '@/lib/layout.shared';\nimport { i18n } from '@/lib/i18n';\n`\n : ''\n }`;\n\nconst providerProps = (input: TemplateInput) =>\n `${input.i18n ? ' i18n={i18nProvider(translations, lang)}' : ''}${input.providerProps}`;\n\n/** the docs page for React Router & TanStack Start, where MDX content is loaded lazily on client */\nconst clientContent = `function Content({ path }: { path: string }) {\n const page = docs.getPage(path);\n if (!page) throw new Error(\\`unknown page: \\${path}\\`);\n\n const { toc } = use(page.load());\n const MDX = page.body;\n\n return (\n <DocsPage toc={toc}>\n <DocsTitle>{page.title}</DocsTitle>\n <DocsDescription>{page.description}</DocsDescription>\n <DocsBody>\n <MDX components={useMDXComponents()} />\n </DocsBody>\n </DocsPage>\n );\n}`;\n\nconst searchRoute = {\n next: (input: TemplateInput) => `import { source } from '@/lib/source';\nimport { createFromSource } from 'fumadocs-core/search/server';\n${input.static ? '\\nexport const revalidate = false;\\n' : ''}\nexport const { ${input.static ? 'staticGET: GET' : 'GET'} } = createFromSource(source);\n`,\n waku: `import { createFromSource } from 'fumadocs-core/search/server';\nimport { source } from '@/lib/source';\n\nexport const { GET } = createFromSource(source);\n`,\n};\n\nexport const templates: Record<ReactFramework, Template> = {\n next: (input) => {\n const i18n = input.i18n !== null;\n // route group with `[lang]` segment for i18n\n const dir = i18n ? 'app/(docs)/[lang]' : 'app/(docs)';\n const route = i18n ? '/[lang]' : '';\n const lang = i18n ? ', params.lang' : '';\n\n return {\n ...shared(input, false),\n [`${dir}/layout.tsx`]: input.static\n ? `'use client';\n${providerImports(input)}${i18n ? \"import { use } from 'react';\\n\" : ''}\nexport default function Layout({ ${i18n ? 'params, ' : ''}children }: LayoutProps<'${route || '/'}'>) {\n${i18n ? ' const { lang } = use(params);\\n\\n' : ''} return (\n <RootProvider${providerProps(input)}>\n ${wrapper('{children}')}\n </RootProvider>\n );\n}\n`\n : `${providerImports(input)}\nexport default ${i18n ? 'async ' : ''}function Layout({ ${i18n ? 'params, ' : ''}children }: LayoutProps<'${route || '/'}'>) {\n${i18n ? ' const { lang } = await params;\\n\\n' : ''} return (\n <RootProvider${providerProps(input)}>\n ${wrapper('{children}')}\n </RootProvider>\n );\n}\n`,\n [`${dir}/docs/layout.tsx`]: `import { source } from '@/lib/source';\nimport { DocsLayout } from 'fumadocs-ui/layouts/docs';\nimport { baseOptions } from '@/lib/layout.shared';\n\nexport default ${i18n ? 'async ' : ''}function Layout({ ${i18n ? 'params, ' : ''}children }: LayoutProps<'${route}/docs'>) {\n${i18n ? ' const { lang } = await params;\\n\\n' : ''} return (\n <DocsLayout tree={source.getPageTree(${i18n ? 'lang' : ''})} {...baseOptions(${i18n ? 'lang' : ''})}>\n {children}\n </DocsLayout>\n );\n}\n`,\n [`${dir}/docs/[[...slug]]/page.tsx`]: `import { source } from '@/lib/source';\nimport { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';\nimport { notFound } from 'next/navigation';\nimport { getMDXComponents } from '@/components/mdx';\nimport type { Metadata } from 'next';\nimport { createRelativeLink } from 'fumadocs-ui/mdx';\n\nexport default async function Page(props: PageProps<'${route}/docs/[[...slug]]'>) {\n const params = await props.params;\n const page = source.getPage(params.slug${lang});\n if (!page) notFound();\n\n const MDX = page.data.body;\n\n return (\n <DocsPage toc={page.data.toc} full={page.data.full}>\n <DocsTitle>{page.data.title}</DocsTitle>\n <DocsDescription>{page.data.description}</DocsDescription>\n <DocsBody>\n <MDX\n components={getMDXComponents({\n // this allows you to link to other pages with relative file paths\n a: createRelativeLink(source, page),\n })}\n />\n </DocsBody>\n </DocsPage>\n );\n}\n\nexport async function generateStaticParams() {\n return source.generateParams();\n}\n\nexport async function generateMetadata(props: PageProps<'${route}/docs/[[...slug]]'>): Promise<Metadata> {\n const params = await props.params;\n const page = source.getPage(params.slug${lang});\n if (!page) notFound();\n\n return {\n title: page.data.title,\n description: page.data.description,\n };\n}\n`,\n 'app/api/search/route.ts': searchRoute.next(input),\n };\n },\n\n 'react-router': (input) => {\n const i18n = input.i18n !== null;\n return {\n ...shared(input, true),\n 'routes/docs/layout.tsx': `import { Outlet${i18n ? ', useParams' : ''} } from 'react-router';\n${providerImports(input)}\nexport default function Layout() {\n${i18n ? ' const { lang = i18n.defaultLanguage } = useParams();\\n\\n' : ''} return (\n <RootProvider${providerProps(input)}>\n ${wrapper('\\n <Outlet />\\n ')}\n </RootProvider>\n );\n}\n`,\n 'routes/docs/page.tsx': `import type { Route } from './+types/page';\nimport { DocsLayout } from 'fumadocs-ui/layouts/docs';\nimport { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';\nimport { docs, source } from '@/lib/source';\nimport { baseOptions } from '@/lib/layout.shared';\nimport { useFumadocsLoader } from 'fumadocs-core/source/client';\nimport { useMDXComponents } from '@/components/mdx';\nimport { use } from 'react';\n\nexport async function loader({ params }: Route.LoaderArgs) {\n const slugs = params['*'].split('/').filter((v) => v.length > 0);\n const page = source.getPage(slugs${i18n ? ', params.lang' : ''});\n if (!page) throw new Response('Not found', { status: 404 });\n\n return {\n path: page.path,\n url: page.url,\n pageTree: await source.serializePageTree(source.getPageTree(${i18n ? 'params.lang' : ''})),\n };\n}\n\n${clientContent.replace('<DocsPage toc={toc}>', '<DocsPage toc={toc}>\\n <title>{page.title}</title>\\n <meta name=\"description\" content={page.description} />')}\n\nexport default function Page({ loaderData${i18n ? ', params' : ''} }: Route.ComponentProps) {\n const { path, pageTree } = useFumadocsLoader(loaderData);\n\n return (\n <DocsLayout {...baseOptions(${i18n ? 'params.lang' : ''})} tree={pageTree}>\n <Content path={path} />\n </DocsLayout>\n );\n}\n`,\n 'routes/docs/search.ts': `import type { Route } from './+types/search';\nimport { createFromSource } from 'fumadocs-core/search/server';\nimport { source } from '@/lib/source';\n\nconst server = createFromSource(source);\n\nexport async function loader(${input.static ? '' : '{ request }: Route.LoaderArgs'}) {\n return server.${input.static ? 'staticGET()' : 'GET(request)'};\n}\n`,\n };\n },\n\n 'tanstack-start': (input) => {\n const seg = localeSegment('tanstack-start', input.i18n);\n const i18n = input.i18n !== null;\n return {\n ...shared(input, true),\n 'routes/_docs.tsx': `import { createFileRoute, Outlet${i18n ? ', useParams' : ''} } from '@tanstack/react-router';\n${providerImports(input)}\nexport const Route = createFileRoute('/_docs')({\n component: Layout,\n});\n\nfunction Layout() {\n${i18n ? ' const { lang = i18n.defaultLanguage } = useParams({ strict: false });\\n\\n' : ''} return (\n <RootProvider${providerProps(input)}>\n ${wrapper('\\n <Outlet />\\n ')}\n </RootProvider>\n );\n}\n`,\n [`routes/_docs/${seg}docs/$.tsx`]: `import { createFileRoute, notFound } from '@tanstack/react-router';\nimport { DocsLayout } from 'fumadocs-ui/layouts/docs';\nimport { createServerFn } from '@tanstack/react-start';\nimport { docs, source } from '@/lib/source';\nimport { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';\nimport { baseOptions } from '@/lib/layout.shared';\nimport { useFumadocsLoader } from 'fumadocs-core/source/client';\nimport { Suspense, use } from 'react';\nimport { useMDXComponents } from '@/components/mdx';\n\nexport const Route = createFileRoute('/_docs/${seg}docs/$')({\n component: Page,\n loader: async ({ params }) => {\n const data = await serverLoader({\n data: {\n slugs: params._splat?.split('/') ?? [],${i18n ? '\\n lang: params.lang,' : ''}\n },\n });\n await docs.getPage(data.path)?.preload();\n return data;\n },\n});\n\nconst serverLoader = createServerFn({\n method: 'GET',\n})\n .validator((params: { slugs: string[]${i18n ? '; lang?: string' : ''} }) => params)\n .handler(async ({ data: { slugs${i18n ? ', lang' : ''} } }) => {\n const page = source.getPage(slugs${i18n ? ', lang' : ''});\n if (!page) throw notFound();\n\n return {\n path: page.path,\n pageTree: await source.serializePageTree(source.getPageTree(${i18n ? 'lang' : ''})),\n };\n });\n\n${clientContent}\n\nfunction Page() {\n${i18n ? ' const { lang } = Route.useParams();\\n' : ''} const data = useFumadocsLoader(Route.useLoaderData());\n\n return (\n <DocsLayout {...baseOptions(${i18n ? 'lang' : ''})} tree={data.pageTree}>\n <Suspense>\n <Content path={data.path} />\n </Suspense>\n </DocsLayout>\n );\n}\n`,\n 'routes/api/search.ts': `import { createFileRoute } from '@tanstack/react-router';\nimport { source } from '@/lib/source';\nimport { createFromSource } from 'fumadocs-core/search/server';\n\nconst server = createFromSource(source);\n\nexport const Route = createFileRoute('/api/search')({\n server: {\n handlers: {\n GET: ${input.static ? '() => server.staticGET()' : 'async ({ request }) => server.GET(request)'},\n },\n },\n});\n`,\n };\n },\n\n waku: (input) => {\n const i18n = input.i18n !== null;\n const page = `import { source } from '@/lib/source';\nimport type { PageProps } from 'waku/router';\nimport { unstable_notFound } from 'waku/router/server';\nimport { createRelativeLink } from 'fumadocs-ui/mdx';\nimport { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';\nimport { getMDXComponents } from '@/components/mdx';\n${i18n ? \"import { DocsLayout } from 'fumadocs-ui/layouts/docs';\\nimport { baseOptions } from '@/lib/layout.shared';\\n\" : ''}\nexport default function Page({ slug${i18n ? ', lang' : ''} }: PageProps<'${i18n ? '/[lang]' : ''}/docs/[...slug]'>) {\n const page = source.getPage(slug${i18n ? ', lang' : ''});\n if (!page) unstable_notFound();\n\n const MDX = page.data.body;\n const content = (\n <DocsPage toc={page.data.toc}>\n <DocsTitle>{page.data.title}</DocsTitle>\n <DocsDescription>{page.data.description}</DocsDescription>\n <DocsBody>\n <MDX\n components={getMDXComponents({\n // this allows you to link to other pages with relative file paths\n a: createRelativeLink(source, page),\n })}\n />\n </DocsBody>\n </DocsPage>\n );\n${\n i18n\n ? `\n // layouts don't receive the locale, render the docs layout here\n return (\n <DocsLayout {...baseOptions(lang)} tree={source.getPageTree(lang)}>\n {content}\n </DocsLayout>\n );`\n : `\n return content;`\n}\n}\n\nexport async function getConfig() {\n return {\n render: 'static',\n staticPaths: source.generateParams().map((item) => ${i18n ? '[item.lang, ...item.slug]' : 'item.slug'}),\n } as const;\n}\n`;\n\n return {\n ...shared(input, false),\n 'pages/(docs)/_layout.tsx': i18n\n ? `import type { ReactNode } from 'react';\nimport { Provider } from '@/components/provider';\n\nexport default function Layout({ children }: { children: ReactNode }) {\n return (\n <Provider>\n ${wrapper('{children}')}\n </Provider>\n );\n}\n`\n : `import type { ReactNode } from 'react';\n${providerImports(input)}\nexport default function Layout({ children }: { children: ReactNode }) {\n return (\n <RootProvider${providerProps(input)}>\n ${wrapper('{children}')}\n </RootProvider>\n );\n}\n`,\n ...(i18n\n ? {\n 'components/provider.tsx': `'use client';\nimport type { ReactNode } from 'react';\nimport { useRouter } from 'waku/router/client';\n${providerImports(input)}\nexport function Provider({ children }: { children: ReactNode }) {\n const router = useRouter();\n const lang = router.path.split('/')[1] || i18n.defaultLanguage;\n\n return <RootProvider${providerProps(input)}>{children}</RootProvider>;\n}\n`,\n 'pages/(docs)/[lang]/docs/[...slug].tsx': page,\n }\n : {\n 'pages/(docs)/docs/_layout.tsx': `import type { ReactNode } from 'react';\nimport { DocsLayout } from 'fumadocs-ui/layouts/docs';\nimport { source } from '@/lib/source';\nimport { baseOptions } from '@/lib/layout.shared';\n\nexport default function Layout({ children }: { children: ReactNode }) {\n return (\n <DocsLayout {...baseOptions()} tree={source.getPageTree()}>\n {children}\n </DocsLayout>\n );\n}\n`,\n 'pages/(docs)/docs/[...slug].tsx': page,\n }),\n 'pages/_api/api/search.ts': searchRoute.waku,\n };\n },\n};\n\nexport const nextProxy = `import { createI18nMiddleware } from 'fumadocs-core/i18n/middleware';\nimport { i18n } from '@/lib/i18n';\n\nexport default createI18nMiddleware(i18n);\n\nexport const config = {\n // only the docs routes, add the ones of other features here\n matcher: ['/docs/:path*', '/:lang/docs/:path*'],\n};\n`;\n\nexport const sampleContent = `---\ntitle: Hello World\ndescription: Your first document\n---\n\nWelcome to the docs! You can edit this page in \\`content/docs/index.mdx\\`.\n\n## Heading\n\n<Cards>\n <Card title=\"Learn more about Fumadocs\" href=\"https://fumadocs.dev\" />\n</Cards>\n`;\n\nexport const sampleContentCn = `---\ntitle: 你好,世界\ndescription: 你的第一份文檔\n---\n\n歡迎來到文檔!你可以在 \\`content/docs/index.cn.mdx\\` 編輯這個頁面。\n`;\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { Feature, FeatureContext } from '@/features';\nimport type { I18nInfo, Project } from '@/project';\nimport {\n addImport,\n addJsxAttribute,\n addVitePlugin,\n findJsxElement,\n wrapNextConfig,\n} from '@/codemod';\nimport { exists } from '@/utils/fs';\nimport { localeSegment } from '@/project/route';\nimport { nextProxy, sampleContent, sampleContentCn, templates } from './templates';\nimport { reactFramework, reactOnly, registerReactRouterRoutes } from '../utils';\n\nconst cssImports = (preset: string) => [\n `@import 'fumadocs-ui/css/${preset}.css';`,\n `@import 'fumadocs-ui/css/preset.css';`,\n];\n\nexport const docs: Feature<{ i18n: boolean }> = {\n id: 'docs',\n title: 'Docs',\n description: 'set up Fumadocs on your app, in a dedicated route group',\n supports: reactOnly,\n options: {\n i18n: { message: 'Enable internationalization?', initialValue: false },\n },\n async detect(project) {\n return exists(path.join(project.cwd, project.baseDir, 'lib/source.ts'));\n },\n async apply(ctx, options) {\n const { project } = ctx;\n const { baseDir, packageJson, config } = project;\n const framework = reactFramework(project);\n // Waku has no optional route segments, the locale is always in the URL\n const i18n = project.i18n ?? (options.i18n ? { optionalLocale: framework !== 'waku' } : null);\n const providerProps: string[] = [];\n if (project.static) providerProps.push('search={{ SearchDialog }}');\n if ('next-themes' in (packageJson.dependencies ?? {}))\n providerProps.push('theme={{ enabled: false }}');\n\n ctx.addDependencies({\n 'fumadocs-core': null,\n 'fumadocs-mdx': null,\n 'fumadocs-ui': config.uiLibrary === 'base-ui' ? 'npm:@fumadocs/base-ui' : null,\n });\n ctx.addDependencies({ '@types/mdx': null }, true);\n\n const files = templates[framework]({\n static: project.static,\n i18n,\n provider: project.info.provider,\n providerProps: providerProps.map((prop) => ` ${prop}`).join(''),\n });\n for (const [file, content] of Object.entries(files)) {\n await ctx.write(path.posix.join(baseDir, file), content);\n }\n await ctx.write('content/docs/index.mdx', sampleContent);\n if (i18n) await ctx.write('content/docs/index.cn.mdx', sampleContentCn);\n await ctx.append('.gitignore', ['.source']);\n if (i18n && framework === 'next') await configureProxy(ctx);\n\n await configureBundler(ctx);\n await configureCss(ctx);\n await suppressHydrationWarning(ctx);\n if (framework === 'react-router') await configureRoutes(ctx, i18n);\n\n const tsconfig = await fs\n .readFile(path.join(project.cwd, 'tsconfig.json'), 'utf-8')\n .catch(() => '');\n if (!tsconfig.includes('\"@/*\"')) {\n ctx.note(\n `Generated files import from the \\`@/*\\` alias, add it to \\`tsconfig.json\\`:\\n \"paths\": { \"@/*\": [\"./${baseDir ? `${baseDir}/` : ''}*\"] }`,\n );\n }\n if (project.static && framework === 'tanstack-start') {\n ctx.note(\n 'In SPA mode, prerender the docs pages and search index, see https://fumadocs.dev/docs/manual-installation/tanstack-start.',\n );\n }\n if (i18n && framework === 'react-router') {\n ctx.note(\n 'When prerendering, list the docs pages with `source.getPages().map((page) => page.url)` instead of globbing content files, see https://fumadocs.dev/docs/internationalization/react-router.',\n );\n }\n if (i18n) {\n ctx.note(\n `Languages are configured in \\`lib/i18n.ts\\`, translated content uses a locale suffix like \\`index.cn.mdx\\`.\\nUI translations: https://fumadocs.dev/docs/internationalization#translations`,\n );\n }\n ctx.note(\n `Start the dev server and open ${i18n && !i18n.optionalLocale ? '/en/docs' : '/docs'} to see your docs.`,\n );\n },\n};\n\n/** the Next.js proxy (middleware) file of the project, relative to cwd */\nexport async function findNextProxy({ cwd, baseDir }: Project) {\n for (const file of ['proxy.ts', 'middleware.ts']) {\n for (const dir of new Set([baseDir, ''])) {\n const target = path.join(dir, file);\n if (await exists(path.join(cwd, target))) return target;\n }\n }\n}\n\n/** the i18n middleware redirects & rewrites docs URLs without locale */\nasync function configureProxy(ctx: FeatureContext) {\n const existing = await findNextProxy(ctx.project);\n if (!existing) {\n await ctx.write(path.join(ctx.project.baseDir, 'proxy.ts'), nextProxy);\n return;\n }\n\n ctx.note(\n `A proxy already exists at ${existing}, handle the docs locale there. Fumadocs provides \\`createI18nMiddleware\\` from 'fumadocs-core/i18n/middleware', see https://fumadocs.dev/docs/internationalization/next.`,\n );\n}\n\nasync function configureBundler(ctx: FeatureContext) {\n const { framework, configFile } = ctx.project;\n const edited =\n configFile !== undefined &&\n (await ctx\n .source(configFile, (file) => {\n const ok =\n framework === 'next'\n ? wrapNextConfig(file)\n : addVitePlugin(\n file,\n { name: 'fumadocsMdx', from: 'fumadocs-mdx/vite' },\n framework === 'waku' ? ['vite', 'plugins'] : ['plugins'],\n );\n if (!ok) throw new Error(`cannot update ${configFile}`);\n })\n .catch(() => false));\n\n if (!edited) {\n ctx.note(\n framework === 'next'\n ? \"Wrap your Next.js config with `createMDX()` from 'fumadocs-mdx/next', see https://fumadocs.dev/docs/mdx/next.\"\n : \"Add `fumadocsMdx()` from 'fumadocs-mdx/vite' to the Vite plugins of your config file.\",\n );\n }\n}\n\n/** resolve the global CSS file imported by the root file */\nasync function findCssEntry({ cwd, baseDir, info }: Project): Promise<string | undefined> {\n const rootFile = path.join(baseDir, info.rootFile);\n const content = await fs.readFile(path.join(cwd, rootFile), 'utf-8').catch(() => '');\n const match = /import\\s+(?:\\w+\\s+from\\s+)?['\"]([^'\"]+\\.css)(?:\\?url)?['\"]/.exec(content);\n if (!match) return;\n const specifier = match[1];\n\n if (specifier.startsWith('@/')) return path.join(baseDir, specifier.slice(2));\n if (specifier.startsWith('.')) return path.join(path.dirname(rootFile), specifier);\n}\n\nasync function configureCss(ctx: FeatureContext) {\n const { cwd } = ctx.project;\n const preset = (await exists(path.join(cwd, 'components.json'))) ? 'shadcn' : 'neutral';\n const entry = await findCssEntry(ctx.project);\n if (entry && (await exists(path.join(cwd, entry)))) {\n await ctx.append(entry, cssImports(preset));\n return;\n }\n\n ctx.note(\n `Add the styles to your global CSS file (after \\`@import 'tailwindcss'\\`):\\n ${cssImports(preset).join('\\n ')}`,\n );\n}\n\n/** `next-themes` sets the theme class on `<html>`, React warns about the mismatch without this attribute */\nasync function suppressHydrationWarning(ctx: FeatureContext) {\n const { baseDir, info } = ctx.project;\n const edited = await ctx.source(path.join(baseDir, info.rootFile), (file) => {\n const html = findJsxElement(file, 'html')?.openingElement;\n if (!html || file.code.slice(html.start, html.end).includes('suppressHydrationWarning')) return;\n addJsxAttribute(file, html, 'suppressHydrationWarning');\n });\n\n if (!edited)\n ctx.note('Add `suppressHydrationWarning` to the `<html>` element of your root layout.');\n}\n\nasync function configureRoutes(ctx: FeatureContext, i18n: I18nInfo | null) {\n const added = await registerReactRouterRoutes(ctx, [\n `layout('routes/docs/layout.tsx', [route('${localeSegment('react-router', i18n)}docs/*', 'routes/docs/page.tsx')])`,\n { path: 'api/search', file: 'routes/docs/search.ts', pattern: '/api/search' },\n ]);\n if (!added) return;\n await ctx.source(path.join(ctx.project.baseDir, 'routes.ts'), (file) => {\n addImport(file, { from: '@react-router/dev/routes', named: ['layout', 'route'] });\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as addReactRouterPrerenderArray, n as enableProcessedMarkdown } from "./codemod-auol-p4R.js";
|
|
2
|
-
import { a as routeModule, r as formatRoute, t as docs } from "./docs
|
|
2
|
+
import { a as routeModule, r as formatRoute, t as docs } from "./docs--WqEHTyl.js";
|
|
3
3
|
import { a as reactFramework, c as requiresMarkdown, d as sourceRef, s as registerReactRouterRoutes } from "./utils-DbMe7h6c.js";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
//#region src/features/epub.ts
|
|
@@ -49,4 +49,4 @@ const epub = {
|
|
|
49
49
|
//#endregion
|
|
50
50
|
export { epub as t };
|
|
51
51
|
|
|
52
|
-
//# sourceMappingURL=epub-
|
|
52
|
+
//# sourceMappingURL=epub-jc_2B886.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"epub-
|
|
1
|
+
{"version":3,"file":"epub-jc_2B886.js","names":[],"sources":["../src/features/epub.ts"],"sourcesContent":["import path from 'node:path';\nimport type { Feature } from '@/features';\nimport type { ReactFramework } from '@/project';\nimport { type FormattedRoute, formatRoute, routeModule } from '@/project/route';\nimport { addReactRouterPrerenderArray, enableProcessedMarkdown } from '@/codemod';\nimport { docs } from './docs';\nimport {\n reactFramework,\n registerReactRouterRoutes,\n requiresMarkdown,\n type SourceRef,\n sourceRef,\n} from './utils';\n\nconst api = ({ dynamic, ref }: SourceRef) => `import { ${ref} } from '@/lib/source';\nimport { createEpubExportAPI } from 'fumadocs-epub';\n\nconst api = createEpubExportAPI({\n ${ref === 'source' ? 'source' : `source: ${ref}`},${dynamic ? '\\n getMarkdown: (page) => page.data.content,' : ''}\n title: 'Documentation',\n author: 'Your Team',\n description: 'Exported documentation',\n // guards the route, requests must send \\`Authorization: Bearer <secret>\\`\n secret: process.env.EXPORT_SECRET,\n});\n`;\n\nconst templates = (framework: ReactFramework, route: FormattedRoute, src: SourceRef) =>\n routeModule(framework, route, {\n imports: api(src),\n body: 'api.GET(request)',\n request: true,\n revalidate: true,\n });\n\nexport const epub: Feature = {\n id: 'epub',\n title: 'EPUB Export',\n description: 'a route to export docs as an EPUB file, protected by EXPORT_SECRET',\n requires: [docs],\n supports: (project) =>\n project.static ? 'the export route needs a server at runtime' : requiresMarkdown(project),\n async apply(ctx) {\n const { baseDir, source } = ctx.project;\n const framework = reactFramework(ctx.project);\n ctx.addDependencies({ 'fumadocs-epub': null });\n\n if (source.collections) {\n await ctx.source(source.collections, (file) => {\n if (!enableProcessedMarkdown(file))\n throw new Error(`cannot find \\`defineDocs()\\` in ${source.collections}`);\n });\n }\n\n const route = formatRoute({ segments: ['export/epub'] }, framework, null);\n await ctx.write(\n path.join(baseDir, route.file),\n templates(framework, route, sourceRef(ctx.project.source.dynamic)),\n );\n if (framework === 'react-router') {\n await registerReactRouterRoutes(ctx, [route]);\n // the route needs a secret at runtime\n await ctx.source('react-router.config.ts', (file) => {\n addReactRouterPrerenderArray(file, 'excluded', [`/${route.path}`]);\n });\n }\n\n ctx.env('EXPORT_SECRET', '');\n ctx.note(\n 'Set EXPORT_SECRET in `.env.local`, then export with `fumadocs export epub` after a production build.',\n );\n },\n};\n"],"mappings":";;;;;AAcA,MAAM,OAAO,EAAE,SAAS,UAAqB,YAAY,IAAI;;;;IAIzD,QAAQ,WAAW,WAAW,WAAW,MAAM,GAAG,UAAU,kDAAkD,GAAG;;;;;;;;AASrH,MAAM,aAAa,WAA2B,OAAuB,QACnE,YAAY,WAAW,OAAO;CAC5B,SAAS,IAAI,GAAG;CAChB,MAAM;CACN,SAAS;CACT,YAAY;AACd,CAAC;AAEH,MAAa,OAAgB;CAC3B,IAAI;CACJ,OAAO;CACP,aAAa;CACb,UAAU,CAAC,IAAI;CACf,WAAW,YACT,QAAQ,SAAS,+CAA+C,iBAAiB,OAAO;CAC1F,MAAM,MAAM,KAAK;EACf,MAAM,EAAE,SAAS,WAAW,IAAI;EAChC,MAAM,YAAY,eAAe,IAAI,OAAO;EAC5C,IAAI,gBAAgB,EAAE,iBAAiB,KAAK,CAAC;EAE7C,IAAI,OAAO,aACT,MAAM,IAAI,OAAO,OAAO,cAAc,SAAS;GAC7C,IAAI,CAAC,wBAAwB,IAAI,GAC/B,MAAM,IAAI,MAAM,mCAAmC,OAAO,aAAa;EAC3E,CAAC;EAGH,MAAM,QAAQ,YAAY,EAAE,UAAU,CAAC,aAAa,EAAE,GAAG,WAAW,IAAI;EACxE,MAAM,IAAI,MACR,KAAK,KAAK,SAAS,MAAM,IAAI,GAC7B,UAAU,WAAW,OAAO,UAAU,IAAI,QAAQ,OAAO,OAAO,CAAC,CACnE;EACA,IAAI,cAAc,gBAAgB;GAChC,MAAM,0BAA0B,KAAK,CAAC,KAAK,CAAC;GAE5C,MAAM,IAAI,OAAO,2BAA2B,SAAS;IACnD,6BAA6B,MAAM,YAAY,CAAC,IAAI,MAAM,MAAM,CAAC;GACnE,CAAC;EACH;EAEA,IAAI,IAAI,iBAAiB,EAAE;EAC3B,IAAI,KACF,sGACF;CACF;AACF"}
|
package/dist/features/ai.d.ts
CHANGED
package/dist/features/ai.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as ai } from "../ai-
|
|
1
|
+
import { t as ai } from "../ai-C19ZOP53.js";
|
|
2
2
|
export { ai };
|
package/dist/features/all.d.ts
CHANGED
package/dist/features/all.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as features } from "../all-
|
|
1
|
+
import { t as features } from "../all-BBf7I8hG.js";
|
|
2
2
|
export { features };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as Project } from "../../index-
|
|
2
|
-
import { r as Feature } from "../../index-
|
|
1
|
+
import { a as Project } from "../../index-DI66DoV8.js";
|
|
2
|
+
import { r as Feature } from "../../index-Cs7hw2un.js";
|
|
3
3
|
//#region src/features/docs/index.d.ts
|
|
4
4
|
export declare const docs: Feature<{
|
|
5
5
|
i18n: boolean;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as findNextProxy, t as docs } from "../../docs
|
|
1
|
+
import { n as findNextProxy, t as docs } from "../../docs--WqEHTyl.js";
|
|
2
2
|
export { docs, findNextProxy };
|
package/dist/features/epub.d.ts
CHANGED
package/dist/features/epub.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as epub } from "../epub-
|
|
1
|
+
import { t as epub } from "../epub-jc_2B886.js";
|
|
2
2
|
export { epub };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as feedback } from "../feedback-
|
|
1
|
+
import { t as feedback } from "../feedback-Brj092vC.js";
|
|
2
2
|
export { feedback };
|
package/dist/features/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as FeatureIO, c as RunOptions, i as FeatureContext, l as SelectOption, n as ConfirmOption, o as FeatureOption, r as Feature, s as PackageJson, t as AnyFeature, u as runFeature } from "../index-
|
|
1
|
+
import { a as FeatureIO, c as RunOptions, i as FeatureContext, l as SelectOption, n as ConfirmOption, o as FeatureOption, r as Feature, s as PackageJson, t as AnyFeature, u as runFeature } from "../index-Cs7hw2un.js";
|
|
2
2
|
export { AnyFeature, ConfirmOption, Feature, FeatureContext, FeatureIO, FeatureOption, PackageJson, RunOptions, SelectOption, runFeature };
|
package/dist/features/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as runFeature } from "../features-
|
|
1
|
+
import { t as runFeature } from "../features-CXFCgOWD.js";
|
|
2
2
|
export { runFeature };
|
package/dist/features/lint.d.ts
CHANGED
package/dist/features/llms.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { o as ReactFramework, r as I18nInfo } from "../index-
|
|
2
|
-
import { i as FeatureContext, r as Feature } from "../index-
|
|
3
|
-
import { p as FormattedRoute, t as SourceRef } from "../utils-
|
|
1
|
+
import { o as ReactFramework, r as I18nInfo } from "../index-DI66DoV8.js";
|
|
2
|
+
import { i as FeatureContext, r as Feature } from "../index-Cs7hw2un.js";
|
|
3
|
+
import { p as FormattedRoute, t as SourceRef } from "../utils-CxJ7kw39.js";
|
|
4
4
|
//#region src/features/llms.d.ts
|
|
5
5
|
/** runtime content sources expose raw Markdown as `page.data.content`, Fumadocs MDX processes it */
|
|
6
6
|
export declare const docsLlms: ({ dynamic, ref }: SourceRef) => string;
|
package/dist/features/llms.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as markdownRewrite, c as templates, i as llmsRoutes, n as extendNextProxy, o as markdownUrl, r as llms, s as tanstackMarkdownUrl, t as docsLlms } from "../llms-
|
|
1
|
+
import { a as markdownRewrite, c as templates, i as llmsRoutes, n as extendNextProxy, o as markdownUrl, r as llms, s as tanstackMarkdownUrl, t as docsLlms } from "../llms-Br0RJXXg.js";
|
|
2
2
|
export { docsLlms, extendNextProxy, llms, llmsRoutes, markdownRewrite, markdownUrl, tanstackMarkdownUrl, templates };
|
package/dist/features/mcp.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { o as ReactFramework } from "../index-
|
|
2
|
-
import { r as Feature } from "../index-
|
|
3
|
-
import { p as FormattedRoute, t as SourceRef } from "../utils-
|
|
1
|
+
import { o as ReactFramework } from "../index-DI66DoV8.js";
|
|
2
|
+
import { r as Feature } from "../index-Cs7hw2un.js";
|
|
3
|
+
import { p as FormattedRoute, t as SourceRef } from "../utils-CxJ7kw39.js";
|
|
4
4
|
//#region src/features/mcp.d.ts
|
|
5
5
|
export declare const templates: (framework: ReactFramework, route: FormattedRoute, src: SourceRef) => string;
|
|
6
6
|
export declare const mcpRoute: (framework: ReactFramework) => FormattedRoute;
|
package/dist/features/mcp.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as mcpRoute, r as templates, t as mcp } from "../mcp-
|
|
1
|
+
import { n as mcpRoute, r as templates, t as mcp } from "../mcp-Ce_W93we.js";
|
|
2
2
|
export { mcp, mcpRoute, templates };
|
package/dist/features/og.d.ts
CHANGED
package/dist/features/og.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as og } from "../og-
|
|
1
|
+
import { t as og } from "../og-LFlX1Bl4.js";
|
|
2
2
|
export { og };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as Feature } from "../index-
|
|
2
|
-
import { t as SourceRef } from "../utils-
|
|
1
|
+
import { r as Feature } from "../index-Cs7hw2un.js";
|
|
2
|
+
import { t as SourceRef } from "../utils-CxJ7kw39.js";
|
|
3
3
|
//#region src/features/search.d.ts
|
|
4
4
|
/** how client code reads public env variables */
|
|
5
5
|
interface Env {
|
package/dist/features/search.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as search } from "../search-
|
|
1
|
+
import { t as search } from "../search-WfSdiGx-.js";
|
|
2
2
|
export { search };
|
package/dist/features/utils.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as posix, c as registerReactRouterRoutes, d as sharedRoute, f as sourceRef, i as findSource, l as requiresMarkdown, n as addExport, o as reactFramework, r as addPageUrl, s as reactOnly, t as SourceRef, u as scripts } from "../utils-
|
|
1
|
+
import { a as posix, c as registerReactRouterRoutes, d as sharedRoute, f as sourceRef, i as findSource, l as requiresMarkdown, n as addExport, o as reactFramework, r as addPageUrl, s as reactOnly, t as SourceRef, u as scripts } from "../utils-CxJ7kw39.js";
|
|
2
2
|
export { SourceRef, addExport, addPageUrl, findSource, posix, reactFramework, reactOnly, registerReactRouterRoutes, requiresMarkdown, scripts, sharedRoute, sourceRef };
|