@fumadocs/cli 1.5.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/dist/ai-C19ZOP53.js +100 -0
  2. package/dist/ai-C19ZOP53.js.map +1 -0
  3. package/dist/all-BBf7I8hG.js +27 -0
  4. package/dist/all-BBf7I8hG.js.map +1 -0
  5. package/dist/codemod/index.d.ts +2 -0
  6. package/dist/codemod/index.js +2 -0
  7. package/dist/codemod-auol-p4R.js +404 -0
  8. package/dist/codemod-auol-p4R.js.map +1 -0
  9. package/dist/config-Bfg4yG8S.d.ts +54 -0
  10. package/dist/config-Bfg4yG8S.d.ts.map +1 -0
  11. package/dist/config-Bw0kmF01.js +97 -0
  12. package/dist/config-Bw0kmF01.js.map +1 -0
  13. package/dist/config.d.ts +2 -52
  14. package/dist/config.js +1 -72
  15. package/dist/docs--WqEHTyl.js +738 -0
  16. package/dist/docs--WqEHTyl.js.map +1 -0
  17. package/dist/epub-jc_2B886.js +52 -0
  18. package/dist/epub-jc_2B886.js.map +1 -0
  19. package/dist/features/ai.d.ts +25 -0
  20. package/dist/features/ai.d.ts.map +1 -0
  21. package/dist/features/ai.js +2 -0
  22. package/dist/features/all.d.ts +5 -0
  23. package/dist/features/all.d.ts.map +1 -0
  24. package/dist/features/all.js +2 -0
  25. package/dist/features/docs/index.d.ts +10 -0
  26. package/dist/features/docs/index.d.ts.map +1 -0
  27. package/dist/features/docs/index.js +2 -0
  28. package/dist/features/epub.d.ts +5 -0
  29. package/dist/features/epub.d.ts.map +1 -0
  30. package/dist/features/epub.js +2 -0
  31. package/dist/features/feedback.d.ts +5 -0
  32. package/dist/features/feedback.d.ts.map +1 -0
  33. package/dist/features/feedback.js +2 -0
  34. package/dist/features/index.d.ts +2 -0
  35. package/dist/features/index.js +2 -0
  36. package/dist/features/lint.d.ts +7 -0
  37. package/dist/features/lint.d.ts.map +1 -0
  38. package/dist/features/lint.js +2 -0
  39. package/dist/features/llms.d.ts +27 -0
  40. package/dist/features/llms.d.ts.map +1 -0
  41. package/dist/features/llms.js +2 -0
  42. package/dist/features/mcp.d.ts +9 -0
  43. package/dist/features/mcp.d.ts.map +1 -0
  44. package/dist/features/mcp.js +2 -0
  45. package/dist/features/og.d.ts +8 -0
  46. package/dist/features/og.d.ts.map +1 -0
  47. package/dist/features/og.js +2 -0
  48. package/dist/features/search.d.ts +84 -0
  49. package/dist/features/search.d.ts.map +1 -0
  50. package/dist/features/search.js +2 -0
  51. package/dist/features/utils.d.ts +2 -0
  52. package/dist/features/utils.js +2 -0
  53. package/dist/features/webmcp.d.ts +12 -0
  54. package/dist/features/webmcp.d.ts.map +1 -0
  55. package/dist/features/webmcp.js +2 -0
  56. package/dist/features-CXFCgOWD.js +132 -0
  57. package/dist/features-CXFCgOWD.js.map +1 -0
  58. package/dist/feedback-Brj092vC.js +37 -0
  59. package/dist/feedback-Brj092vC.js.map +1 -0
  60. package/dist/fs-D6J9dOEx.js +14 -0
  61. package/dist/fs-D6J9dOEx.js.map +1 -0
  62. package/dist/index-Ck0EPdgu.d.ts +126 -0
  63. package/dist/index-Ck0EPdgu.d.ts.map +1 -0
  64. package/dist/index-Cs7hw2un.d.ts +76 -0
  65. package/dist/index-Cs7hw2un.d.ts.map +1 -0
  66. package/dist/index-DI66DoV8.d.ts +64 -0
  67. package/dist/index-DI66DoV8.d.ts.map +1 -0
  68. package/dist/index.js +155 -139
  69. package/dist/index.js.map +1 -1
  70. package/dist/{installer-Ci3Hf9it.js → installer-CzhVfs7i.js} +81 -8
  71. package/dist/installer-CzhVfs7i.js.map +1 -0
  72. package/dist/lint-zkXUULgO.js +137 -0
  73. package/dist/lint-zkXUULgO.js.map +1 -0
  74. package/dist/llms-Br0RJXXg.js +228 -0
  75. package/dist/llms-Br0RJXXg.js.map +1 -0
  76. package/dist/mcp-Ce_W93we.js +67 -0
  77. package/dist/mcp-Ce_W93we.js.map +1 -0
  78. package/dist/og-LFlX1Bl4.js +142 -0
  79. package/dist/og-LFlX1Bl4.js.map +1 -0
  80. package/dist/project/index.d.ts +2 -0
  81. package/dist/project/index.js +2 -0
  82. package/dist/project-DwRVTm4p.js +110 -0
  83. package/dist/project-DwRVTm4p.js.map +1 -0
  84. package/dist/registry/installer.d.ts +4 -5
  85. package/dist/registry/installer.d.ts.map +1 -1
  86. package/dist/registry/installer.js +1 -1
  87. package/dist/schema.json +1 -1
  88. package/dist/search-WfSdiGx-.js +381 -0
  89. package/dist/search-WfSdiGx-.js.map +1 -0
  90. package/dist/utils-CxJ7kw39.d.ts +43 -0
  91. package/dist/utils-CxJ7kw39.d.ts.map +1 -0
  92. package/dist/utils-DbMe7h6c.js +98 -0
  93. package/dist/utils-DbMe7h6c.js.map +1 -0
  94. package/dist/webmcp-DyTLrsXL.js +135 -0
  95. package/dist/webmcp-DyTLrsXL.js.map +1 -0
  96. package/package.json +28 -7
  97. package/dist/config.d.ts.map +0 -1
  98. package/dist/config.js.map +0 -1
  99. package/dist/installer-Ci3Hf9it.js.map +0 -1
@@ -0,0 +1,100 @@
1
+ import { E as prependJsxChildren, b as findJsxElement, p as addImport } from "./codemod-auol-p4R.js";
2
+ import { t as docs } from "./docs--WqEHTyl.js";
3
+ import { r as findSource } from "./utils-DbMe7h6c.js";
4
+ import path from "node:path";
5
+ //#region src/features/ai.ts
6
+ const providers = {
7
+ openrouter: {
8
+ label: "AI SDK",
9
+ hint: "default to OpenRouter",
10
+ env: "OPENROUTER_API_KEY"
11
+ },
12
+ llmgateway: {
13
+ label: "LLMGateway",
14
+ hint: "open-source LLM gateway, API key required",
15
+ env: "LLM_GATEWAY_API_KEY"
16
+ },
17
+ inkeep: {
18
+ label: "Inkeep AI",
19
+ hint: "API key required",
20
+ env: "INKEEP_API_KEY"
21
+ }
22
+ };
23
+ const ai = {
24
+ id: "ai",
25
+ title: "AI Chat",
26
+ description: "Ask AI dialog for your docs",
27
+ requires: [docs],
28
+ options: { provider: {
29
+ message: "Choose an AI provider",
30
+ choices: Object.entries(providers).map(([value, { label, hint }]) => ({
31
+ value,
32
+ label,
33
+ hint
34
+ }))
35
+ } },
36
+ supports: (project) => project.static ? "AI chat requires a server to run the chat route handler." : true,
37
+ async apply(ctx, { provider }) {
38
+ await ctx.install(`ai/${provider}`);
39
+ ctx.env(providers[provider].env, "");
40
+ if (ctx.project.source.dynamic) await readDynamicSource(ctx);
41
+ const { cwd, baseDir, info } = ctx.project;
42
+ const layout = await findSource(cwd, path.join(baseDir, info.routesDir), "<DocsLayout");
43
+ if (!(layout !== void 0 && await ctx.source(layout, (file) => {
44
+ if (file.code.includes("<AISearch")) return;
45
+ const element = findJsxElement(file, "DocsLayout");
46
+ if (!element) return;
47
+ prependJsxChildren(file, element, `<AISearch>
48
+ <AISearchPanel />
49
+ <AISearchTrigger
50
+ position="float"
51
+ className={cn(
52
+ buttonVariants({
53
+ variant: 'secondary',
54
+ className: 'text-fd-muted-foreground rounded-2xl',
55
+ }),
56
+ )}
57
+ >
58
+ <MessageCircleIcon className="size-4.5" />
59
+ Ask AI
60
+ </AISearchTrigger>
61
+ </AISearch>`);
62
+ addImport(file, {
63
+ from: "@/components/ai/search",
64
+ named: [
65
+ "AISearch",
66
+ "AISearchPanel",
67
+ "AISearchTrigger"
68
+ ]
69
+ });
70
+ addImport(file, {
71
+ from: "lucide-react",
72
+ named: ["MessageCircleIcon"]
73
+ });
74
+ addImport(file, {
75
+ from: "@/lib/cn",
76
+ named: ["cn"]
77
+ });
78
+ addImport(file, {
79
+ from: "fumadocs-ui/components/ui/button",
80
+ named: ["buttonVariants"]
81
+ });
82
+ }))) ctx.note("Add `<AISearch>` from `@/components/ai/search` to your docs layout, see https://fumadocs.dev/docs/integrations/llms#ask-ai.");
83
+ ctx.note(`Set ${providers[provider].env} in \`.env.local\`.`);
84
+ }
85
+ };
86
+ /** the installed chat route indexes pages of a static `source`, runtime sources resolve on demand */
87
+ async function readDynamicSource(ctx) {
88
+ const { cwd, baseDir } = ctx.project;
89
+ const route = await findSource(cwd, baseDir, "createSearchServer");
90
+ if (!(route !== void 0 && await ctx.source(route, (file) => {
91
+ file.s.replaceAll("import { source } from '@/lib/source';", "import { getSource } from '@/lib/source';");
92
+ file.s.replaceAll("source.getPages()", "(await getSource()).getPages()");
93
+ file.s.replaceAll(" if (!('getText' in page.data)) return null;\n\n", "");
94
+ file.s.replaceAll("await page.data.getText('processed')", "page.data.content");
95
+ }))) ctx.note("Read pages from `getSource()` in the chat route, the search index is built from `page.data.content`.");
96
+ }
97
+ //#endregion
98
+ export { ai as t };
99
+
100
+ //# sourceMappingURL=ai-C19ZOP53.js.map
@@ -0,0 +1 @@
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
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,2 @@
1
+ import { C as getDefaultExport, D as parseSourceFile, E as lineIndent, O as prependJsxChildren, S as findJsxElement, T as getStringValue, _ as appendJsxChildren, a as addReactRouterRoute, b as filterElements, c as addNextRewrites, d as wrapNextConfig, f as NodeOfType, g as addJsxAttribute, h as addImport, i as addReactRouterPrerenderArray, l as addVitePlugin, m as addElements, n as enableProcessedMarkdown, o as filterReactRouterPrerenderArray, p as SourceFile, r as addTanstackPrerender, s as filterReactRouterRoute, t as addProxyMatcher, u as getConfigObject, v as createSourceFile, w as getProperty, x as find, y as descendants } from "../index-Ck0EPdgu.js";
2
+ export { NodeOfType, SourceFile, addElements, addImport, addJsxAttribute, addNextRewrites, addProxyMatcher, addReactRouterPrerenderArray, addReactRouterRoute, addTanstackPrerender, addVitePlugin, appendJsxChildren, createSourceFile, descendants, enableProcessedMarkdown, filterElements, filterReactRouterPrerenderArray, filterReactRouterRoute, find, findJsxElement, getConfigObject, getDefaultExport, getProperty, getStringValue, lineIndent, parseSourceFile, prependJsxChildren, wrapNextConfig };
@@ -0,0 +1,2 @@
1
+ import { C as getStringValue, E as prependJsxChildren, S as getProperty, T as parseSourceFile, _ as descendants, a as addReactRouterRoute, b as findJsxElement, c as addNextRewrites, d as wrapNextConfig, f as addElements, g as createSourceFile, h as appendJsxChildren, i as addReactRouterPrerenderArray, l as addVitePlugin, m as addJsxAttribute, n as enableProcessedMarkdown, o as filterReactRouterPrerenderArray, p as addImport, r as addTanstackPrerender, s as filterReactRouterRoute, t as addProxyMatcher, u as getConfigObject, v as filterElements, w as lineIndent, x as getDefaultExport, y as find } from "../codemod-auol-p4R.js";
2
+ export { addElements, addImport, addJsxAttribute, addNextRewrites, addProxyMatcher, addReactRouterPrerenderArray, addReactRouterRoute, addTanstackPrerender, addVitePlugin, appendJsxChildren, createSourceFile, descendants, enableProcessedMarkdown, filterElements, filterReactRouterPrerenderArray, filterReactRouterRoute, find, findJsxElement, getConfigObject, getDefaultExport, getProperty, getStringValue, lineIndent, parseSourceFile, prependJsxChildren, wrapNextConfig };
@@ -0,0 +1,404 @@
1
+ import fs from "node:fs/promises";
2
+ import { parseSync } from "oxc-parser";
3
+ import MagicString from "magic-string";
4
+ //#region src/codemod/shared.ts
5
+ function parseSourceFile(path, code) {
6
+ const { program, errors } = parseSync(path, code);
7
+ if (errors.length > 0) throw new Error(`Failed to parse ${path}: ${errors[0].message}`);
8
+ const s = new MagicString(code);
9
+ return {
10
+ path,
11
+ code,
12
+ program,
13
+ s,
14
+ save: () => fs.writeFile(path, s.toString())
15
+ };
16
+ }
17
+ async function createSourceFile(path) {
18
+ return parseSourceFile(path, await fs.readFile(path, "utf-8"));
19
+ }
20
+ /** the value of a string literal, or a template literal without expressions */
21
+ function getStringValue(node) {
22
+ if (node.type === "Literal" && typeof node.value === "string") return node.value;
23
+ if (node.type === "TemplateLiteral" && node.expressions.length === 0) return node.quasis[0].value.cooked ?? void 0;
24
+ }
25
+ function* descendants(node) {
26
+ for (const key in node) {
27
+ if (key === "parent") continue;
28
+ const value = node[key];
29
+ for (const child of Array.isArray(value) ? value : [value]) if (child && typeof child === "object" && "type" in child) {
30
+ yield child;
31
+ yield* descendants(child);
32
+ }
33
+ }
34
+ }
35
+ function find(node, type, predicate) {
36
+ for (const child of descendants(node)) if (child.type === type && (!predicate || predicate(child))) return child;
37
+ }
38
+ function getDefaultExport(file) {
39
+ return file.program.body.find((node) => node.type === "ExportDefaultDeclaration");
40
+ }
41
+ function findJsxElement(file, tagName) {
42
+ return find(file.program, "JSXElement", ({ openingElement: { name } }) => {
43
+ return name.type === "JSXIdentifier" && name.name === tagName;
44
+ });
45
+ }
46
+ function addJsxAttribute(file, element, attribute) {
47
+ const { code, s } = file;
48
+ const anchor = element.attributes.at(-1) ?? element.name;
49
+ const multiline = code.slice(element.start, element.end).includes("\n");
50
+ s.appendLeft(anchor.end, `${multiline ? `\n${lineIndent(code, anchor.start)}` : " "}${attribute}`);
51
+ }
52
+ /**
53
+ * Insert JSX before the children of the element, re-indenting the children
54
+ */
55
+ function prependJsxChildren(file, element, jsx) {
56
+ const { closingElement, openingElement } = element;
57
+ if (!closingElement) return;
58
+ const { code, s } = file;
59
+ const indent = lineIndent(code, element.start);
60
+ const body = `${jsx}\n\n${dedent(code.slice(openingElement.end, closingElement.start))}`.replaceAll(/^(?=.)/gm, `${indent} `);
61
+ s.overwrite(openingElement.end, closingElement.start, `\n${body}\n${indent}`);
62
+ }
63
+ /**
64
+ * Insert JSX after the children of the element
65
+ */
66
+ function appendJsxChildren(file, element, jsx) {
67
+ const { closingElement } = element;
68
+ if (!closingElement) return;
69
+ const { code, s } = file;
70
+ const indent = lineIndent(code, element.start);
71
+ const body = jsx.replaceAll(/^(?=.)/gm, `${indent} `);
72
+ s.appendLeft(closingElement.start - indent.length, `${body}\n`);
73
+ }
74
+ /** trim, and remove the common indentation */
75
+ function dedent(text) {
76
+ const lines = text.trim().split("\n");
77
+ let indent;
78
+ for (const line of lines.slice(1)) {
79
+ if (line.trim().length === 0) continue;
80
+ const current = /^[ \t]*/.exec(line)[0];
81
+ if (indent === void 0 || current.length < indent.length) indent = current;
82
+ }
83
+ if (!indent) return lines.join("\n");
84
+ return lines.map((line, i) => i > 0 && line.startsWith(indent) ? line.slice(indent.length) : line).join("\n");
85
+ }
86
+ function getProperty(object, name) {
87
+ for (const property of object.properties) {
88
+ if (property.type !== "Property") continue;
89
+ const { key } = property;
90
+ if (key.type === "Identifier" ? key.name === name : key.type === "Literal" && key.value === name) return property;
91
+ }
92
+ }
93
+ /** indentation of the line containing `index` */
94
+ function lineIndent(code, index) {
95
+ const start = code.lastIndexOf("\n", index - 1) + 1;
96
+ return /^[ \t]*/.exec(code.slice(start, index))[0];
97
+ }
98
+ function addImport(file, declaration) {
99
+ const { s, program } = file;
100
+ const existing = program.body.find((node) => node.type === "ImportDeclaration" && node.importKind !== "type" && node.source.value === declaration.from);
101
+ if (existing && !declaration.default && declaration.named) {
102
+ const imported = /* @__PURE__ */ new Set();
103
+ let last;
104
+ for (const spec of existing.specifiers) {
105
+ if (spec.type !== "ImportSpecifier") continue;
106
+ imported.add(spec.local.name);
107
+ last = spec;
108
+ }
109
+ const missing = declaration.named.filter((name) => !imported.has(name));
110
+ if (last && missing.length > 0) s.appendLeft(last.end, `, ${missing.join(", ")}`);
111
+ if (last) return;
112
+ }
113
+ const parts = [];
114
+ if (declaration.default) parts.push(declaration.default);
115
+ if (declaration.named?.length) parts.push(`{ ${declaration.named.join(", ")} }`);
116
+ const statement = `import ${parts.join(", ")} from '${declaration.from}';`;
117
+ const last = program.body.findLast((node) => node.type === "ImportDeclaration");
118
+ if (last) s.appendLeft(last.end, `\n${statement}`);
119
+ else s.prepend(`${statement}\n\n`);
120
+ }
121
+ function getElements(container) {
122
+ return (container.type === "ArrayExpression" ? container.elements : container.properties).filter((element) => element !== null);
123
+ }
124
+ /**
125
+ * Append items to an array or object literal, following its formatting
126
+ */
127
+ function addElements(file, container, items) {
128
+ if (items.length === 0) return;
129
+ const { code, s } = file;
130
+ const last = getElements(container).at(-1);
131
+ const multiline = code.slice(container.start, container.end).includes("\n");
132
+ if (!last) {
133
+ if (container.end - container.start === 2) s.appendLeft(container.end - 1, items.join(", "));
134
+ else s.overwrite(container.start + 1, container.end - 1, items.join(", "));
135
+ return;
136
+ }
137
+ if (!multiline) {
138
+ s.appendLeft(last.end, items.map((item) => `, ${item}`).join(""));
139
+ return;
140
+ }
141
+ const indent = lineIndent(code, last.start);
142
+ s.appendLeft(last.end, items.map((item) => `,\n${indent}${item.replaceAll("\n", `\n${indent}`)}`).join(""));
143
+ }
144
+ /**
145
+ * Remove the items of an array or object literal that don't pass the filter
146
+ */
147
+ function filterElements(file, container, keep) {
148
+ const { s } = file;
149
+ const elements = getElements(container);
150
+ const keeps = elements.map(keep);
151
+ let kept = 0;
152
+ for (const keep of keeps) if (keep) kept++;
153
+ if (kept === elements.length) return;
154
+ if (kept === 0) {
155
+ s.remove(container.start + 1, container.end - 1);
156
+ return;
157
+ }
158
+ let lastKept;
159
+ for (let i = 0; i < elements.length; i++) {
160
+ const element = elements[i];
161
+ if (keeps[i]) {
162
+ lastKept = element;
163
+ continue;
164
+ }
165
+ const next = elements[i + 1];
166
+ if (next) s.remove(element.start, next.start);
167
+ else s.remove(lastKept.end, element.end);
168
+ }
169
+ }
170
+ //#endregion
171
+ //#region src/codemod/config.ts
172
+ /**
173
+ * The options object of a config file, e.g. the argument of `defineConfig({ ... })`, or the object in `export default { ... }`
174
+ */
175
+ function getConfigObject(file) {
176
+ const exported = getDefaultExport(file);
177
+ if (!exported) return;
178
+ let expr = exported.declaration;
179
+ while (true) {
180
+ if (expr.type === "ObjectExpression") return expr;
181
+ if (expr.type === "TSSatisfiesExpression" || expr.type === "TSAsExpression") expr = expr.expression;
182
+ else if (expr.type === "CallExpression" && expr.arguments.length > 0) {
183
+ const arg = expr.arguments[0];
184
+ if (arg.type === "SpreadElement") return;
185
+ expr = arg;
186
+ } else if (expr.type === "Identifier") {
187
+ const { name } = expr;
188
+ const init = find(file.program, "VariableDeclarator", (node) => node.id.type === "Identifier" && node.id.name === name)?.init;
189
+ if (!init) return;
190
+ expr = init;
191
+ } else return;
192
+ }
193
+ }
194
+ /**
195
+ * Add a plugin call to the `plugins` array of a Vite config, skip if the same plugin is already added.
196
+ *
197
+ * @param path - property path to the plugins array, e.g. `['vite', 'plugins']` for Waku
198
+ */
199
+ function addVitePlugin(file, plugin, path = ["plugins"]) {
200
+ let object = getConfigObject(file);
201
+ for (let i = 0; object && i < path.length - 1; i++) {
202
+ let value = getProperty(object, path[i])?.value;
203
+ while (value?.type === "TSSatisfiesExpression" || value?.type === "TSAsExpression") value = value.expression;
204
+ object = value?.type === "ObjectExpression" ? value : void 0;
205
+ }
206
+ if (!object) return false;
207
+ const call = plugin.call ?? `${plugin.name}()`;
208
+ const plugins = getProperty(object, path[path.length - 1])?.value;
209
+ if (!plugins) addElements(file, object, [`${path[path.length - 1]}: [${call}]`]);
210
+ else if (plugins.type === "ArrayExpression") {
211
+ for (const element of plugins.elements) if (element?.type === "CallExpression" && element.callee.type === "Identifier" && element.callee.name === plugin.name) return true;
212
+ addElements(file, plugins, [call]);
213
+ } else return false;
214
+ addImport(file, {
215
+ from: plugin.from,
216
+ named: [plugin.name]
217
+ });
218
+ return true;
219
+ }
220
+ /**
221
+ * Wrap the default export of `next.config.*` with `createMDX()`
222
+ */
223
+ function wrapNextConfig(file) {
224
+ if (file.code.includes("fumadocs-mdx/next")) return true;
225
+ const exported = getDefaultExport(file);
226
+ if (!exported) return false;
227
+ const { declaration, start } = exported;
228
+ if (declaration.type === "FunctionDeclaration" || declaration.type === "ClassDeclaration") return false;
229
+ file.s.prependLeft(start, `const withMDX = createMDX();\n\n`);
230
+ file.s.appendLeft(declaration.start, "withMDX(");
231
+ file.s.appendRight(declaration.end, ")");
232
+ addImport(file, {
233
+ from: "fumadocs-mdx/next",
234
+ named: ["createMDX"]
235
+ });
236
+ return true;
237
+ }
238
+ /**
239
+ * Add rewrites to a Next.js config, skip if `rewrites` is already defined
240
+ */
241
+ function addNextRewrites(file, rewrites) {
242
+ const config = getConfigObject(file);
243
+ if (!config) return false;
244
+ if (getProperty(config, "rewrites")) return false;
245
+ addElements(file, config, [`async rewrites() {\n return [\n${rewrites.map(({ source, destination }) => ` {\n source: '${source}',\n destination: '${destination}',\n },`).join("\n")}\n ];\n}`]);
246
+ return true;
247
+ }
248
+ //#endregion
249
+ //#region src/codemod/react-router.ts
250
+ /**
251
+ * filter items in a specific array initializer in the prerender function
252
+ */
253
+ function filterReactRouterPrerenderArray(file, array, filter) {
254
+ const initializer = getPrerenderArray(file, array);
255
+ if (!initializer) return;
256
+ filterElements(file, initializer, (element) => {
257
+ const value = getStringValue(element);
258
+ return value === void 0 || filter(value);
259
+ });
260
+ }
261
+ /**
262
+ * add items to a specific array initializer in the prerender function, skip existing ones
263
+ */
264
+ function addReactRouterPrerenderArray(file, array, items) {
265
+ const initializer = getPrerenderArray(file, array);
266
+ if (!initializer) return;
267
+ const existing = /* @__PURE__ */ new Set();
268
+ for (const element of initializer.elements) {
269
+ const value = element ? getStringValue(element) : void 0;
270
+ if (value !== void 0) existing.add(value);
271
+ }
272
+ addElements(file, initializer, items.filter((item) => !existing.has(item)).map((item) => `'${item}'`));
273
+ }
274
+ function getPrerenderArray(file, array) {
275
+ const method = getPrerenderMethod(file);
276
+ if (!method) return;
277
+ const initializer = find(method.value, "VariableDeclarator", (item) => item.id.type === "Identifier" && item.id.name === array)?.init;
278
+ if (initializer?.type === "ArrayExpression") return initializer;
279
+ }
280
+ /**
281
+ * Add new routes to route config, an item can be raw code (e.g. `layout(...)`)
282
+ */
283
+ function addReactRouterRoute(file, routes) {
284
+ return modifyReactRouterRoutes(file, (arr) => {
285
+ addElements(file, arr, routes.map((item) => typeof item === "string" ? item : `route('${item.path}', '${item.entry}')`));
286
+ });
287
+ }
288
+ /**
289
+ * Remove routes from route config (root level only)
290
+ */
291
+ function filterReactRouterRoute(file, filter) {
292
+ modifyReactRouterRoutes(file, (arr) => {
293
+ filterElements(file, arr, (element) => {
294
+ if (element.type !== "CallExpression") return true;
295
+ const { callee, arguments: args } = element;
296
+ if (callee.type !== "Identifier" || callee.name !== "route") return true;
297
+ const path = getStringValue(args[0]);
298
+ const entry = getStringValue(args[1]);
299
+ return path === void 0 || entry === void 0 || filter({
300
+ path,
301
+ entry
302
+ });
303
+ });
304
+ });
305
+ }
306
+ /** @returns `false` if the route config isn't an array literal (e.g. file-based routes) */
307
+ function modifyReactRouterRoutes(file, mod) {
308
+ const exported = getDefaultExport(file);
309
+ const initializer = exported && find(exported, "ArrayExpression");
310
+ if (!initializer) return false;
311
+ mod(initializer);
312
+ return true;
313
+ }
314
+ /**
315
+ * Find the prerender method from the config
316
+ */
317
+ function getPrerenderMethod(file) {
318
+ const exported = getDefaultExport(file);
319
+ const options = exported && find(exported, "ObjectExpression");
320
+ const property = options && getProperty(options, "prerender");
321
+ if (property?.method) return property;
322
+ }
323
+ //#endregion
324
+ //#region src/codemod/tanstack-start.ts
325
+ /**
326
+ * Add path to the `pages` array in tanstack start vite config.
327
+ *
328
+ * If the `pages` property doesn't exist, create one.
329
+ */
330
+ function addTanstackPrerender(file, paths) {
331
+ const options = getTanstackStartCall(file)?.arguments[0];
332
+ if (options?.type !== "ObjectExpression") return;
333
+ const toItem = (path) => `{ path: '${path}' }`;
334
+ const pages = getProperty(options, "pages")?.value;
335
+ if (!pages) {
336
+ addElements(file, options, [`pages: [\n${paths.map((path) => ` ${toItem(path)}`).join(",\n")}\n]`]);
337
+ return;
338
+ }
339
+ if (pages.type !== "ArrayExpression") return;
340
+ const existingPaths = /* @__PURE__ */ new Set();
341
+ for (const element of pages.elements) {
342
+ const value = element?.type === "ObjectExpression" && getProperty(element, "path")?.value;
343
+ const path = value ? getStringValue(value) : void 0;
344
+ if (path !== void 0) existingPaths.add(path);
345
+ }
346
+ addElements(file, pages, paths.filter((path) => !existingPaths.has(path)).map(toItem));
347
+ }
348
+ /**
349
+ * Find the tanstackStart call expression
350
+ */
351
+ function getTanstackStartCall(file) {
352
+ const exported = getDefaultExport(file);
353
+ const options = exported && find(exported, "ObjectExpression");
354
+ const plugins = options && getProperty(options, "plugins")?.value;
355
+ if (plugins?.type !== "ArrayExpression") return;
356
+ for (const element of plugins.elements) if (element?.type === "CallExpression" && element.callee.type === "Identifier" && element.callee.name === "tanstackStart") return element;
357
+ }
358
+ //#endregion
359
+ //#region src/codemod/source.ts
360
+ /**
361
+ * Enable `includeProcessedMarkdown` on the `defineDocs()` call
362
+ *
363
+ * @returns `false` if the call cannot be found
364
+ */
365
+ function enableProcessedMarkdown(file) {
366
+ const options = find(file.program, "CallExpression", (node) => node.callee.type === "Identifier" && node.callee.name === "defineDocs")?.arguments[0];
367
+ if (options?.type !== "ObjectExpression") return false;
368
+ const flag = "includeProcessedMarkdown: true";
369
+ const docs = getProperty(options, "docs")?.value;
370
+ if (!docs) {
371
+ addElements(file, options, [`docs: {\n postprocess: {\n ${flag},\n },\n}`]);
372
+ return true;
373
+ }
374
+ if (docs.type !== "ObjectExpression") return false;
375
+ const postprocess = getProperty(docs, "postprocess")?.value;
376
+ if (!postprocess) {
377
+ addElements(file, docs, [`postprocess: {\n ${flag},\n}`]);
378
+ return true;
379
+ }
380
+ if (postprocess.type !== "ObjectExpression") return false;
381
+ const existing = getProperty(postprocess, "includeProcessedMarkdown")?.value;
382
+ if (!existing) addElements(file, postprocess, [flag]);
383
+ else if (existing.type === "Literal" && existing.value === false) file.s.overwrite(existing.start, existing.end, "true");
384
+ return true;
385
+ }
386
+ //#endregion
387
+ //#region src/codemod/next-proxy.ts
388
+ /**
389
+ * Add patterns to the `matcher` of `export const config` in a Next.js proxy (middleware) file
390
+ */
391
+ function addProxyMatcher(file, patterns) {
392
+ const config = find(file.program, "VariableDeclarator", (node) => node.id.type === "Identifier" && node.id.name === "config")?.init;
393
+ if (config?.type !== "ObjectExpression") return false;
394
+ const matcher = getProperty(config, "matcher")?.value;
395
+ if (matcher?.type !== "ArrayExpression") return false;
396
+ const existing = /* @__PURE__ */ new Set();
397
+ for (const element of matcher.elements) if (element?.type === "Literal" && typeof element.value === "string") existing.add(element.value);
398
+ addElements(file, matcher, patterns.filter((pattern) => !existing.has(pattern)).map((pattern) => `'${pattern}'`));
399
+ return true;
400
+ }
401
+ //#endregion
402
+ export { getStringValue as C, prependJsxChildren as E, getProperty as S, parseSourceFile as T, descendants as _, addReactRouterRoute as a, findJsxElement as b, addNextRewrites as c, wrapNextConfig as d, addElements as f, createSourceFile as g, appendJsxChildren as h, addReactRouterPrerenderArray as i, addVitePlugin as l, addJsxAttribute as m, enableProcessedMarkdown as n, filterReactRouterPrerenderArray as o, addImport as p, addTanstackPrerender as r, filterReactRouterRoute as s, addProxyMatcher as t, getConfigObject as u, filterElements as v, lineIndent as w, getDefaultExport as x, find as y };
403
+
404
+ //# sourceMappingURL=codemod-auol-p4R.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codemod-auol-p4R.js","names":[],"sources":["../src/codemod/shared.ts","../src/codemod/config.ts","../src/codemod/react-router.ts","../src/codemod/tanstack-start.ts","../src/codemod/source.ts","../src/codemod/next-proxy.ts"],"sourcesContent":["import {\n parseSync,\n type ArrayExpression,\n type ExportDefaultDeclaration,\n type ImportDeclaration,\n type JSXElement,\n type JSXOpeningElement,\n type Node,\n type ObjectExpression,\n type ObjectProperty,\n type Program,\n type Span,\n} from 'oxc-parser';\nimport MagicString from 'magic-string';\nimport fs from 'node:fs/promises';\n\nexport type NodeOfType<T extends Node['type']> = Extract<Node, { type: T }>;\n\nexport interface SourceFile {\n path: string;\n /** the original content */\n code: string;\n program: Program;\n /** the edited content */\n s: MagicString;\n save(): Promise<void>;\n}\n\nexport function parseSourceFile(path: string, code: string): SourceFile {\n const { program, errors } = parseSync(path, code);\n if (errors.length > 0) throw new Error(`Failed to parse ${path}: ${errors[0].message}`);\n const s = new MagicString(code);\n\n return {\n path,\n code,\n program,\n s,\n save: () => fs.writeFile(path, s.toString()),\n };\n}\n\nexport async function createSourceFile(path: string): Promise<SourceFile> {\n return parseSourceFile(path, await fs.readFile(path, 'utf-8'));\n}\n\n/** the value of a string literal, or a template literal without expressions */\nexport function getStringValue(node: Node): string | undefined {\n if (node.type === 'Literal' && typeof node.value === 'string') return node.value;\n if (node.type === 'TemplateLiteral' && node.expressions.length === 0)\n return node.quasis[0].value.cooked ?? undefined;\n}\n\nexport function* descendants(node: Node): Generator<Node> {\n for (const key in node) {\n if (key === 'parent') continue;\n const value = (node as unknown as Record<string, unknown>)[key];\n for (const child of Array.isArray(value) ? value : [value]) {\n if (child && typeof child === 'object' && 'type' in child) {\n yield child as Node;\n yield* descendants(child as Node);\n }\n }\n }\n}\n\nexport function find<T extends Node['type']>(\n node: Node,\n type: T,\n predicate?: (node: NodeOfType<T>) => boolean,\n): NodeOfType<T> | undefined {\n for (const child of descendants(node)) {\n if (child.type === type && (!predicate || predicate(child as NodeOfType<T>)))\n return child as NodeOfType<T>;\n }\n}\n\nexport function getDefaultExport(file: SourceFile): ExportDefaultDeclaration | undefined {\n return file.program.body.find((node) => node.type === 'ExportDefaultDeclaration');\n}\n\nexport function findJsxElement(file: SourceFile, tagName: string): JSXElement | undefined {\n return find(file.program, 'JSXElement', ({ openingElement: { name } }) => {\n return name.type === 'JSXIdentifier' && name.name === tagName;\n });\n}\n\nexport function addJsxAttribute(file: SourceFile, element: JSXOpeningElement, attribute: string) {\n const { code, s } = file;\n const anchor = element.attributes.at(-1) ?? element.name;\n const multiline = code.slice(element.start, element.end).includes('\\n');\n s.appendLeft(\n anchor.end,\n `${multiline ? `\\n${lineIndent(code, anchor.start)}` : ' '}${attribute}`,\n );\n}\n\n/**\n * Insert JSX before the children of the element, re-indenting the children\n */\nexport function prependJsxChildren(file: SourceFile, element: JSXElement, jsx: string) {\n const { closingElement, openingElement } = element;\n if (!closingElement) return;\n const { code, s } = file;\n const indent = lineIndent(code, element.start);\n const prior = dedent(code.slice(openingElement.end, closingElement.start));\n const body = `${jsx}\\n\\n${prior}`.replaceAll(/^(?=.)/gm, `${indent} `);\n s.overwrite(openingElement.end, closingElement.start, `\\n${body}\\n${indent}`);\n}\n\n/**\n * Insert JSX after the children of the element\n */\nexport function appendJsxChildren(file: SourceFile, element: JSXElement, jsx: string) {\n const { closingElement } = element;\n if (!closingElement) return;\n const { code, s } = file;\n const indent = lineIndent(code, element.start);\n const body = jsx.replaceAll(/^(?=.)/gm, `${indent} `);\n // children end with the indentation of the closing tag\n s.appendLeft(closingElement.start - indent.length, `${body}\\n`);\n}\n\n/** trim, and remove the common indentation */\nfunction dedent(text: string): string {\n const lines = text.trim().split('\\n');\n let indent: string | undefined;\n for (const line of lines.slice(1)) {\n if (line.trim().length === 0) continue;\n const current = /^[ \\t]*/.exec(line)![0];\n if (indent === undefined || current.length < indent.length) indent = current;\n }\n if (!indent) return lines.join('\\n');\n return lines\n .map((line, i) => (i > 0 && line.startsWith(indent) ? line.slice(indent.length) : line))\n .join('\\n');\n}\n\nexport function getProperty(object: ObjectExpression, name: string): ObjectProperty | undefined {\n for (const property of object.properties) {\n if (property.type !== 'Property') continue;\n const { key } = property;\n if (\n key.type === 'Identifier' ? key.name === name : key.type === 'Literal' && key.value === name\n )\n return property;\n }\n}\n\n/** indentation of the line containing `index` */\nexport function lineIndent(code: string, index: number): string {\n const start = code.lastIndexOf('\\n', index - 1) + 1;\n return /^[ \\t]*/.exec(code.slice(start, index))![0];\n}\n\nexport function addImport(\n file: SourceFile,\n declaration: { from: string; default?: string; named?: string[] },\n) {\n const { s, program } = file;\n const existing = program.body.find(\n (node): node is ImportDeclaration =>\n node.type === 'ImportDeclaration' &&\n node.importKind !== 'type' &&\n node.source.value === declaration.from,\n );\n\n if (existing && !declaration.default && declaration.named) {\n const imported = new Set<string>();\n let last: Span | undefined;\n for (const spec of existing.specifiers) {\n if (spec.type !== 'ImportSpecifier') continue;\n imported.add(spec.local.name);\n last = spec;\n }\n\n const missing = declaration.named.filter((name) => !imported.has(name));\n if (last && missing.length > 0) s.appendLeft(last.end, `, ${missing.join(', ')}`);\n if (last) return;\n }\n\n const parts: string[] = [];\n if (declaration.default) parts.push(declaration.default);\n if (declaration.named?.length) parts.push(`{ ${declaration.named.join(', ')} }`);\n const statement = `import ${parts.join(', ')} from '${declaration.from}';`;\n\n const last = program.body.findLast((node) => node.type === 'ImportDeclaration');\n if (last) s.appendLeft(last.end, `\\n${statement}`);\n else s.prepend(`${statement}\\n\\n`);\n}\n\ntype Container = ArrayExpression | ObjectExpression;\ntype ElementOf<C extends Container> = C extends ArrayExpression\n ? NonNullable<ArrayExpression['elements'][number]>\n : ObjectExpression['properties'][number];\n\nfunction getElements<C extends Container>(container: C): ElementOf<C>[] {\n const elements = container.type === 'ArrayExpression' ? container.elements : container.properties;\n return elements.filter((element) => element !== null) as ElementOf<C>[];\n}\n\n/**\n * Append items to an array or object literal, following its formatting\n */\nexport function addElements(file: SourceFile, container: Container, items: string[]) {\n if (items.length === 0) return;\n const { code, s } = file;\n const last = getElements(container).at(-1);\n const multiline = code.slice(container.start, container.end).includes('\\n');\n\n if (!last) {\n // `[]` is a zero-length range which cannot be overwritten\n if (container.end - container.start === 2) s.appendLeft(container.end - 1, items.join(', '));\n else s.overwrite(container.start + 1, container.end - 1, items.join(', '));\n return;\n }\n\n if (!multiline) {\n s.appendLeft(last.end, items.map((item) => `, ${item}`).join(''));\n return;\n }\n\n const indent = lineIndent(code, last.start);\n s.appendLeft(\n last.end,\n items.map((item) => `,\\n${indent}${item.replaceAll('\\n', `\\n${indent}`)}`).join(''),\n );\n}\n\n/**\n * Remove the items of an array or object literal that don't pass the filter\n */\nexport function filterElements<C extends Container>(\n file: SourceFile,\n container: C,\n keep: (element: ElementOf<C>) => boolean,\n) {\n const { s } = file;\n const elements = getElements(container);\n const keeps = elements.map(keep);\n let kept = 0;\n for (const keep of keeps) if (keep) kept++;\n if (kept === elements.length) return;\n if (kept === 0) {\n s.remove(container.start + 1, container.end - 1);\n return;\n }\n\n let lastKept: ElementOf<C> | undefined;\n for (let i = 0; i < elements.length; i++) {\n const element = elements[i];\n if (keeps[i]) {\n lastKept = element;\n continue;\n }\n const next = elements[i + 1];\n // remove along with the separator: up to the next item, or from the last kept item\n if (next) s.remove(element.start, next.start);\n else s.remove(lastKept!.end, element.end);\n }\n}\n","import type { Expression, ObjectExpression } from 'oxc-parser';\nimport {\n addElements,\n addImport,\n find,\n getDefaultExport,\n getProperty,\n type SourceFile,\n} from './shared';\n\n/**\n * The options object of a config file, e.g. the argument of `defineConfig({ ... })`, or the object in `export default { ... }`\n */\nexport function getConfigObject(file: SourceFile): ObjectExpression | undefined {\n const exported = getDefaultExport(file);\n if (!exported) return;\n let expr = exported.declaration as Expression;\n\n while (true) {\n if (expr.type === 'ObjectExpression') return expr;\n if (expr.type === 'TSSatisfiesExpression' || expr.type === 'TSAsExpression') {\n expr = expr.expression;\n } else if (expr.type === 'CallExpression' && expr.arguments.length > 0) {\n const arg = expr.arguments[0];\n if (arg.type === 'SpreadElement') return;\n expr = arg;\n } else if (expr.type === 'Identifier') {\n const { name } = expr;\n const init = find(\n file.program,\n 'VariableDeclarator',\n (node) => node.id.type === 'Identifier' && node.id.name === name,\n )?.init;\n if (!init) return;\n expr = init;\n } else {\n return;\n }\n }\n}\n\n/**\n * Add a plugin call to the `plugins` array of a Vite config, skip if the same plugin is already added.\n *\n * @param path - property path to the plugins array, e.g. `['vite', 'plugins']` for Waku\n */\nexport function addVitePlugin(\n file: SourceFile,\n plugin: { name: string; from: string; call?: string },\n path: string[] = ['plugins'],\n): boolean {\n let object = getConfigObject(file);\n for (let i = 0; object && i < path.length - 1; i++) {\n let value = getProperty(object, path[i])?.value;\n // e.g. `vite: { ... } satisfies UserConfig as Config['vite']`\n while (value?.type === 'TSSatisfiesExpression' || value?.type === 'TSAsExpression')\n value = value.expression;\n object = value?.type === 'ObjectExpression' ? value : undefined;\n }\n if (!object) return false;\n\n const call = plugin.call ?? `${plugin.name}()`;\n const plugins = getProperty(object, path[path.length - 1])?.value;\n if (!plugins) {\n addElements(file, object, [`${path[path.length - 1]}: [${call}]`]);\n } else if (plugins.type === 'ArrayExpression') {\n for (const element of plugins.elements) {\n if (\n element?.type === 'CallExpression' &&\n element.callee.type === 'Identifier' &&\n element.callee.name === plugin.name\n )\n return true;\n }\n addElements(file, plugins, [call]);\n } else {\n return false;\n }\n\n addImport(file, { from: plugin.from, named: [plugin.name] });\n return true;\n}\n\n/**\n * Wrap the default export of `next.config.*` with `createMDX()`\n */\nexport function wrapNextConfig(file: SourceFile): boolean {\n if (file.code.includes('fumadocs-mdx/next')) return true;\n const exported = getDefaultExport(file);\n if (!exported) return false;\n const { declaration, start } = exported;\n if (declaration.type === 'FunctionDeclaration' || declaration.type === 'ClassDeclaration')\n return false;\n\n file.s.prependLeft(start, `const withMDX = createMDX();\\n\\n`);\n file.s.appendLeft(declaration.start, 'withMDX(');\n file.s.appendRight(declaration.end, ')');\n addImport(file, { from: 'fumadocs-mdx/next', named: ['createMDX'] });\n return true;\n}\n\n/**\n * Add rewrites to a Next.js config, skip if `rewrites` is already defined\n */\nexport function addNextRewrites(\n file: SourceFile,\n rewrites: { source: string; destination: string }[],\n): boolean {\n const config = getConfigObject(file);\n if (!config) return false;\n if (getProperty(config, 'rewrites')) return false;\n\n const items = rewrites.map(\n ({ source, destination }) =>\n ` {\\n source: '${source}',\\n destination: '${destination}',\\n },`,\n );\n addElements(file, config, [`async rewrites() {\\n return [\\n${items.join('\\n')}\\n ];\\n}`]);\n return true;\n}\n","import type { ArrayExpression, ObjectProperty } from 'oxc-parser';\nimport {\n addElements,\n filterElements,\n find,\n getStringValue,\n getDefaultExport,\n getProperty,\n type SourceFile,\n} from '@/codemod/shared';\n\n/**\n * filter items in a specific array initializer in the prerender function\n */\nexport function filterReactRouterPrerenderArray(\n file: SourceFile,\n array: 'paths' | 'excluded',\n filter: (item: string) => boolean,\n) {\n const initializer = getPrerenderArray(file, array);\n if (!initializer) return;\n\n filterElements(file, initializer, (element) => {\n const value = getStringValue(element);\n return value === undefined || filter(value);\n });\n}\n\n/**\n * add items to a specific array initializer in the prerender function, skip existing ones\n */\nexport function addReactRouterPrerenderArray(\n file: SourceFile,\n array: 'paths' | 'excluded',\n items: string[],\n) {\n const initializer = getPrerenderArray(file, array);\n if (!initializer) return;\n\n const existing = new Set<string>();\n for (const element of initializer.elements) {\n const value = element ? getStringValue(element) : undefined;\n if (value !== undefined) existing.add(value);\n }\n addElements(\n file,\n initializer,\n items.filter((item) => !existing.has(item)).map((item) => `'${item}'`),\n );\n}\n\nfunction getPrerenderArray(file: SourceFile, array: string): ArrayExpression | undefined {\n const method = getPrerenderMethod(file);\n if (!method) return;\n\n const initializer = find(\n method.value,\n 'VariableDeclarator',\n (item) => item.id.type === 'Identifier' && item.id.name === array,\n )?.init;\n if (initializer?.type === 'ArrayExpression') return initializer;\n}\n\n/**\n * Add new routes to route config, an item can be raw code (e.g. `layout(...)`)\n */\nexport function addReactRouterRoute(\n file: SourceFile,\n routes: ({ path: string; entry: string } | string)[],\n): boolean {\n return modifyReactRouterRoutes(file, (arr) => {\n addElements(\n file,\n arr,\n routes.map((item) =>\n typeof item === 'string' ? item : `route('${item.path}', '${item.entry}')`,\n ),\n );\n });\n}\n\n/**\n * Remove routes from route config (root level only)\n */\nexport function filterReactRouterRoute(\n file: SourceFile,\n filter: (item: { path: string; entry: string }) => boolean,\n) {\n modifyReactRouterRoutes(file, (arr) => {\n filterElements(file, arr, (element) => {\n if (element.type !== 'CallExpression') return true;\n const { callee, arguments: args } = element;\n if (callee.type !== 'Identifier' || callee.name !== 'route') return true;\n\n const path = getStringValue(args[0]);\n const entry = getStringValue(args[1]);\n return path === undefined || entry === undefined || filter({ path, entry });\n });\n });\n}\n\n/** @returns `false` if the route config isn't an array literal (e.g. file-based routes) */\nfunction modifyReactRouterRoutes(file: SourceFile, mod: (array: ArrayExpression) => void): boolean {\n const exported = getDefaultExport(file);\n const initializer = exported && find(exported, 'ArrayExpression');\n if (!initializer) return false;\n mod(initializer);\n return true;\n}\n\n/**\n * Find the prerender method from the config\n */\nfunction getPrerenderMethod(file: SourceFile): ObjectProperty | undefined {\n const exported = getDefaultExport(file);\n const options = exported && find(exported, 'ObjectExpression');\n const property = options && getProperty(options, 'prerender');\n if (property?.method) return property;\n}\n","import type { CallExpression } from 'oxc-parser';\nimport {\n addElements,\n find,\n getStringValue,\n getDefaultExport,\n getProperty,\n type SourceFile,\n} from '@/codemod/shared';\n\n/**\n * Add path to the `pages` array in tanstack start vite config.\n *\n * If the `pages` property doesn't exist, create one.\n */\nexport function addTanstackPrerender(file: SourceFile, paths: string[]) {\n const options = getTanstackStartCall(file)?.arguments[0];\n if (options?.type !== 'ObjectExpression') return;\n\n const toItem = (path: string) => `{ path: '${path}' }`;\n const pages = getProperty(options, 'pages')?.value;\n if (!pages) {\n addElements(file, options, [\n `pages: [\\n${paths.map((path) => ` ${toItem(path)}`).join(',\\n')}\\n]`,\n ]);\n return;\n }\n if (pages.type !== 'ArrayExpression') return;\n\n const existingPaths = new Set<string>();\n for (const element of pages.elements) {\n const value = element?.type === 'ObjectExpression' && getProperty(element, 'path')?.value;\n const path = value ? getStringValue(value) : undefined;\n if (path !== undefined) existingPaths.add(path);\n }\n addElements(file, pages, paths.filter((path) => !existingPaths.has(path)).map(toItem));\n}\n\n/**\n * Find the tanstackStart call expression\n */\nfunction getTanstackStartCall(file: SourceFile): CallExpression | undefined {\n const exported = getDefaultExport(file);\n const options = exported && find(exported, 'ObjectExpression');\n const plugins = options && getProperty(options, 'plugins')?.value;\n if (plugins?.type !== 'ArrayExpression') return;\n\n for (const element of plugins.elements) {\n if (\n element?.type === 'CallExpression' &&\n element.callee.type === 'Identifier' &&\n element.callee.name === 'tanstackStart'\n )\n return element;\n }\n}\n","import { addElements, find, getProperty, type SourceFile } from './shared';\n\n/**\n * Enable `includeProcessedMarkdown` on the `defineDocs()` call\n *\n * @returns `false` if the call cannot be found\n */\nexport function enableProcessedMarkdown(file: SourceFile): boolean {\n const call = find(\n file.program,\n 'CallExpression',\n (node) => node.callee.type === 'Identifier' && node.callee.name === 'defineDocs',\n );\n const options = call?.arguments[0];\n if (options?.type !== 'ObjectExpression') return false;\n const flag = 'includeProcessedMarkdown: true';\n\n const docs = getProperty(options, 'docs')?.value;\n if (!docs) {\n addElements(file, options, [`docs: {\\n postprocess: {\\n ${flag},\\n },\\n}`]);\n return true;\n }\n if (docs.type !== 'ObjectExpression') return false;\n\n const postprocess = getProperty(docs, 'postprocess')?.value;\n if (!postprocess) {\n addElements(file, docs, [`postprocess: {\\n ${flag},\\n}`]);\n return true;\n }\n if (postprocess.type !== 'ObjectExpression') return false;\n\n const existing = getProperty(postprocess, 'includeProcessedMarkdown')?.value;\n if (!existing) addElements(file, postprocess, [flag]);\n else if (existing.type === 'Literal' && existing.value === false)\n file.s.overwrite(existing.start, existing.end, 'true');\n return true;\n}\n","import { addElements, find, getProperty, type SourceFile } from './shared';\n\n/**\n * Add patterns to the `matcher` of `export const config` in a Next.js proxy (middleware) file\n */\nexport function addProxyMatcher(file: SourceFile, patterns: string[]): boolean {\n const config = find(\n file.program,\n 'VariableDeclarator',\n (node) => node.id.type === 'Identifier' && node.id.name === 'config',\n )?.init;\n if (config?.type !== 'ObjectExpression') return false;\n const matcher = getProperty(config, 'matcher')?.value;\n if (matcher?.type !== 'ArrayExpression') return false;\n\n const existing = new Set<string>();\n for (const element of matcher.elements) {\n if (element?.type === 'Literal' && typeof element.value === 'string')\n existing.add(element.value);\n }\n addElements(\n file,\n matcher,\n patterns.filter((pattern) => !existing.has(pattern)).map((pattern) => `'${pattern}'`),\n );\n return true;\n}\n"],"mappings":"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"}