@intlayer/chokidar 9.0.0-canary.2 → 9.0.0-canary.4

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 (97) hide show
  1. package/dist/cjs/init/frameworkSetup/index.cjs +27 -0
  2. package/dist/cjs/init/frameworkSetup/index.cjs.map +1 -0
  3. package/dist/cjs/init/frameworkSetup/nextAppRouter/detect.cjs +56 -0
  4. package/dist/cjs/init/frameworkSetup/nextAppRouter/detect.cjs.map +1 -0
  5. package/dist/cjs/init/frameworkSetup/nextAppRouter/index.cjs +103 -0
  6. package/dist/cjs/init/frameworkSetup/nextAppRouter/index.cjs.map +1 -0
  7. package/dist/cjs/init/frameworkSetup/nextAppRouter/restructure.cjs +147 -0
  8. package/dist/cjs/init/frameworkSetup/nextAppRouter/restructure.cjs.map +1 -0
  9. package/dist/cjs/init/frameworkSetup/nextAppRouter/templates.cjs +122 -0
  10. package/dist/cjs/init/frameworkSetup/nextAppRouter/templates.cjs.map +1 -0
  11. package/dist/cjs/init/frameworkSetup/nextAppRouter/transforms.cjs +211 -0
  12. package/dist/cjs/init/frameworkSetup/nextAppRouter/transforms.cjs.map +1 -0
  13. package/dist/cjs/init/frameworkSetup/tanstackStart/detect.cjs +31 -0
  14. package/dist/cjs/init/frameworkSetup/tanstackStart/detect.cjs.map +1 -0
  15. package/dist/cjs/init/frameworkSetup/tanstackStart/index.cjs +74 -0
  16. package/dist/cjs/init/frameworkSetup/tanstackStart/index.cjs.map +1 -0
  17. package/dist/cjs/init/frameworkSetup/tanstackStart/restructure.cjs +79 -0
  18. package/dist/cjs/init/frameworkSetup/tanstackStart/restructure.cjs.map +1 -0
  19. package/dist/cjs/init/frameworkSetup/tanstackStart/templates.cjs +104 -0
  20. package/dist/cjs/init/frameworkSetup/tanstackStart/templates.cjs.map +1 -0
  21. package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs +128 -0
  22. package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs.map +1 -0
  23. package/dist/cjs/init/frameworkSetup/types.cjs +0 -0
  24. package/dist/cjs/init/index.cjs +51 -21
  25. package/dist/cjs/init/index.cjs.map +1 -1
  26. package/dist/cjs/init/utils/configManipulation.cjs +2 -1
  27. package/dist/cjs/init/utils/configManipulation.cjs.map +1 -1
  28. package/dist/cjs/init/utils/fileSystem.cjs +45 -0
  29. package/dist/cjs/init/utils/fileSystem.cjs.map +1 -1
  30. package/dist/cjs/init/utils/index.cjs +7 -1
  31. package/dist/cjs/init/utils/packageManager.cjs +84 -1
  32. package/dist/cjs/init/utils/packageManager.cjs.map +1 -1
  33. package/dist/esm/init/frameworkSetup/index.mjs +26 -0
  34. package/dist/esm/init/frameworkSetup/index.mjs.map +1 -0
  35. package/dist/esm/init/frameworkSetup/nextAppRouter/detect.mjs +52 -0
  36. package/dist/esm/init/frameworkSetup/nextAppRouter/detect.mjs.map +1 -0
  37. package/dist/esm/init/frameworkSetup/nextAppRouter/index.mjs +100 -0
  38. package/dist/esm/init/frameworkSetup/nextAppRouter/index.mjs.map +1 -0
  39. package/dist/esm/init/frameworkSetup/nextAppRouter/restructure.mjs +142 -0
  40. package/dist/esm/init/frameworkSetup/nextAppRouter/restructure.mjs.map +1 -0
  41. package/dist/esm/init/frameworkSetup/nextAppRouter/templates.mjs +113 -0
  42. package/dist/esm/init/frameworkSetup/nextAppRouter/templates.mjs.map +1 -0
  43. package/dist/esm/init/frameworkSetup/nextAppRouter/transforms.mjs +208 -0
  44. package/dist/esm/init/frameworkSetup/nextAppRouter/transforms.mjs.map +1 -0
  45. package/dist/esm/init/frameworkSetup/tanstackStart/detect.mjs +28 -0
  46. package/dist/esm/init/frameworkSetup/tanstackStart/detect.mjs.map +1 -0
  47. package/dist/esm/init/frameworkSetup/tanstackStart/index.mjs +71 -0
  48. package/dist/esm/init/frameworkSetup/tanstackStart/index.mjs.map +1 -0
  49. package/dist/esm/init/frameworkSetup/tanstackStart/restructure.mjs +74 -0
  50. package/dist/esm/init/frameworkSetup/tanstackStart/restructure.mjs.map +1 -0
  51. package/dist/esm/init/frameworkSetup/tanstackStart/templates.mjs +100 -0
  52. package/dist/esm/init/frameworkSetup/tanstackStart/templates.mjs.map +1 -0
  53. package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs +126 -0
  54. package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs.map +1 -0
  55. package/dist/esm/init/frameworkSetup/types.mjs +0 -0
  56. package/dist/esm/init/index.mjs +52 -22
  57. package/dist/esm/init/index.mjs.map +1 -1
  58. package/dist/esm/init/utils/configManipulation.mjs +2 -1
  59. package/dist/esm/init/utils/configManipulation.mjs.map +1 -1
  60. package/dist/esm/init/utils/fileSystem.mjs +46 -2
  61. package/dist/esm/init/utils/fileSystem.mjs.map +1 -1
  62. package/dist/esm/init/utils/index.mjs +3 -3
  63. package/dist/esm/init/utils/packageManager.mjs +81 -3
  64. package/dist/esm/init/utils/packageManager.mjs.map +1 -1
  65. package/dist/types/init/frameworkSetup/index.d.ts +13 -0
  66. package/dist/types/init/frameworkSetup/index.d.ts.map +1 -0
  67. package/dist/types/init/frameworkSetup/nextAppRouter/detect.d.ts +25 -0
  68. package/dist/types/init/frameworkSetup/nextAppRouter/detect.d.ts.map +1 -0
  69. package/dist/types/init/frameworkSetup/nextAppRouter/index.d.ts +12 -0
  70. package/dist/types/init/frameworkSetup/nextAppRouter/index.d.ts.map +1 -0
  71. package/dist/types/init/frameworkSetup/nextAppRouter/restructure.d.ts +44 -0
  72. package/dist/types/init/frameworkSetup/nextAppRouter/restructure.d.ts.map +1 -0
  73. package/dist/types/init/frameworkSetup/nextAppRouter/templates.d.ts +26 -0
  74. package/dist/types/init/frameworkSetup/nextAppRouter/templates.d.ts.map +1 -0
  75. package/dist/types/init/frameworkSetup/nextAppRouter/transforms.d.ts +23 -0
  76. package/dist/types/init/frameworkSetup/nextAppRouter/transforms.d.ts.map +1 -0
  77. package/dist/types/init/frameworkSetup/tanstackStart/detect.d.ts +19 -0
  78. package/dist/types/init/frameworkSetup/tanstackStart/detect.d.ts.map +1 -0
  79. package/dist/types/init/frameworkSetup/tanstackStart/index.d.ts +13 -0
  80. package/dist/types/init/frameworkSetup/tanstackStart/index.d.ts.map +1 -0
  81. package/dist/types/init/frameworkSetup/tanstackStart/restructure.d.ts +35 -0
  82. package/dist/types/init/frameworkSetup/tanstackStart/restructure.d.ts.map +1 -0
  83. package/dist/types/init/frameworkSetup/tanstackStart/templates.d.ts +20 -0
  84. package/dist/types/init/frameworkSetup/tanstackStart/templates.d.ts.map +1 -0
  85. package/dist/types/init/frameworkSetup/tanstackStart/transforms.d.ts +17 -0
  86. package/dist/types/init/frameworkSetup/tanstackStart/transforms.d.ts.map +1 -0
  87. package/dist/types/init/frameworkSetup/types.d.ts +35 -0
  88. package/dist/types/init/frameworkSetup/types.d.ts.map +1 -0
  89. package/dist/types/init/index.d.ts +17 -0
  90. package/dist/types/init/index.d.ts.map +1 -1
  91. package/dist/types/init/utils/configManipulation.d.ts.map +1 -1
  92. package/dist/types/init/utils/fileSystem.d.ts +30 -1
  93. package/dist/types/init/utils/fileSystem.d.ts.map +1 -1
  94. package/dist/types/init/utils/index.d.ts +3 -3
  95. package/dist/types/init/utils/packageManager.d.ts +52 -1
  96. package/dist/types/init/utils/packageManager.d.ts.map +1 -1
  97. package/package.json +9 -9
@@ -0,0 +1,211 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_runtime = require('../../../_virtual/_rolldown/runtime.cjs');
3
+ let recast = require("recast");
4
+ recast = require_runtime.__toESM(recast);
5
+
6
+ //#region src/init/frameworkSetup/nextAppRouter/transforms.ts
7
+ const { builders: b } = recast.types;
8
+ /** babel-ts parser handles TypeScript *and* JSX (the `typescript` parser does not). */
9
+ const parseTsx = (code) => recast.parse(code, { parser: require("recast/parsers/babel-ts") });
10
+ /** Detects a top-level `'use client'` directive (client components can't be async server providers). */
11
+ const isClientComponent = (ast) => {
12
+ if ((ast.program.directives ?? []).some((directive) => directive.value?.value === "use client")) return true;
13
+ return ast.program.body.some((stmt) => stmt.type === "ExpressionStatement" && stmt.expression?.type === "StringLiteral" && stmt.expression.value === "use client");
14
+ };
15
+ /** Finds the function node behind `export default`, following an identifier reference if needed. */
16
+ const findDefaultExportFunction = (ast) => {
17
+ const body = ast.program.body;
18
+ const asFunction = (node) => node && (node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression" || node.type === "FunctionDeclaration") ? node : null;
19
+ for (const stmt of body) {
20
+ if (stmt.type !== "ExportDefaultDeclaration") continue;
21
+ const direct = asFunction(stmt.declaration);
22
+ if (direct) return direct;
23
+ if (stmt.declaration?.type === "Identifier") {
24
+ const name = stmt.declaration.name;
25
+ for (const candidate of body) {
26
+ if (candidate.type === "VariableDeclaration") {
27
+ for (const declarator of candidate.declarations) if (declarator.id?.type === "Identifier" && declarator.id.name === name) {
28
+ const fn = asFunction(declarator.init);
29
+ if (fn) return fn;
30
+ }
31
+ }
32
+ if (candidate.type === "FunctionDeclaration" && candidate.id?.name === name) return candidate;
33
+ }
34
+ }
35
+ }
36
+ return null;
37
+ };
38
+ /** Index just past the leading directives + import declarations, where new top-level code is safe to insert. */
39
+ const firstInsertIndex = (ast) => {
40
+ const body = ast.program.body;
41
+ let index = 0;
42
+ while (index < body.length && (body[index].type === "ExpressionStatement" && body[index].expression?.type === "StringLiteral" || body[index].type === "ImportDeclaration")) index++;
43
+ return index;
44
+ };
45
+ /** Ensures `import { importName } from source`, merging into an existing import from the same source. */
46
+ const ensureNamedImport = (ast, importName, source) => {
47
+ for (const stmt of ast.program.body) if (stmt.type === "ImportDeclaration" && stmt.source.value === source) {
48
+ if (!stmt.specifiers.some((spec) => spec.type === "ImportSpecifier" && spec.imported?.name === importName)) stmt.specifiers.push(b.importSpecifier(b.identifier(importName)));
49
+ return;
50
+ }
51
+ const declaration = b.importDeclaration([b.importSpecifier(b.identifier(importName))], b.stringLiteral(source));
52
+ ast.program.body.splice(firstInsertIndex(ast), 0, declaration);
53
+ };
54
+ /** Ensures `export { exportedName } from source`, skipping when already declared/re-exported. */
55
+ const ensureExportFrom = (ast, exportedName, source) => {
56
+ if (ast.program.body.some((stmt) => {
57
+ if (stmt.type === "ExportNamedDeclaration" && stmt.source?.value === source) return stmt.specifiers.some((spec) => spec.exported?.name === exportedName);
58
+ if (stmt.type === "ExportNamedDeclaration" && stmt.declaration) {
59
+ const decl = stmt.declaration;
60
+ if (decl.type === "FunctionDeclaration" && decl.id?.name === exportedName) return true;
61
+ if (decl.type === "VariableDeclaration") return decl.declarations.some((d) => d.id?.type === "Identifier" && d.id.name === exportedName);
62
+ }
63
+ return false;
64
+ })) return;
65
+ const exportNode = parseTsx(`export { ${exportedName} } from "${source}";`).program.body[0];
66
+ ast.program.body.splice(firstInsertIndex(ast), 0, exportNode);
67
+ };
68
+ /** Makes the function async and inserts `const locale = await getLocale();` once, at the top of its body. */
69
+ const ensureAwaitedLocale = (funcNode) => {
70
+ funcNode.async = true;
71
+ if (funcNode.body.type !== "BlockStatement") funcNode.body = b.blockStatement([b.returnStatement(funcNode.body)]);
72
+ if (!funcNode.body.body.some((stmt) => stmt.type === "VariableDeclaration" && stmt.declarations.some((d) => d.id?.type === "Identifier" && d.id.name === "locale"))) {
73
+ const localeStatement = parseTsx("const locale = await getLocale();").program.body[0];
74
+ funcNode.body.body.unshift(localeStatement);
75
+ }
76
+ };
77
+ /** Builds `<providerName locale={locale}>{child}</providerName>` around an existing JSX child node. */
78
+ const buildProviderElement = (providerName, childNode) => {
79
+ const providerElement = parseTsx(`const __wrap = <${providerName} locale={locale}>{__child__}</${providerName}>;`).program.body[0].declarations[0].init;
80
+ providerElement.children = [childNode];
81
+ return providerElement;
82
+ };
83
+ /** Sets `lang={locale}` on the first `<html>` element, if present. */
84
+ const setHtmlLang = (ast) => {
85
+ recast.visit(ast, { visitJSXOpeningElement(path) {
86
+ const node = path.node;
87
+ if (node.name?.type === "JSXIdentifier" && node.name.name === "html") {
88
+ const langAttr = node.attributes?.find((attr) => attr.type === "JSXAttribute" && attr.name?.name === "lang");
89
+ const localeExpression = b.jsxExpressionContainer(b.identifier("locale"));
90
+ if (langAttr) langAttr.value = localeExpression;
91
+ else node.attributes.push(b.jsxAttribute(b.jsxIdentifier("lang"), localeExpression));
92
+ return false;
93
+ }
94
+ this.traverse(path);
95
+ } });
96
+ };
97
+ /**
98
+ * Wraps the `{children}` of a Next.js App Router **layout** with
99
+ * `IntlayerClientProvider`, deriving the locale via `getLocale()`. Safe and
100
+ * idempotent: bails (returns the original code) for client components, when no
101
+ * `{children}` placeholder is found, or when there is no default export.
102
+ */
103
+ const wrapLayoutWithProvider = (code) => {
104
+ const ast = parseTsx(code);
105
+ if (isClientComponent(ast)) return {
106
+ code,
107
+ status: "skipped-client"
108
+ };
109
+ if (code.includes("IntlayerClientProvider")) return {
110
+ code,
111
+ status: "already"
112
+ };
113
+ const funcNode = findDefaultExportFunction(ast);
114
+ if (!funcNode) return {
115
+ code,
116
+ status: "skipped"
117
+ };
118
+ let wrapped = false;
119
+ recast.visit(funcNode, { visitJSXExpressionContainer(path) {
120
+ if (wrapped) return false;
121
+ const expression = path.node.expression;
122
+ if (expression?.type === "Identifier" && expression.name === "children") {
123
+ path.replace(buildProviderElement("IntlayerClientProvider", path.node));
124
+ wrapped = true;
125
+ return false;
126
+ }
127
+ this.traverse(path);
128
+ } });
129
+ if (!wrapped) return {
130
+ code,
131
+ status: "skipped"
132
+ };
133
+ ensureNamedImport(ast, "IntlayerClientProvider", "next-intlayer");
134
+ ensureNamedImport(ast, "getLocale", "next-intlayer/server");
135
+ ensureExportFrom(ast, "generateStaticParams", "next-intlayer");
136
+ ensureAwaitedLocale(funcNode);
137
+ setHtmlLang(ast);
138
+ return {
139
+ code: recast.print(ast).code,
140
+ status: "wrapped"
141
+ };
142
+ };
143
+ /** Returns the single top-level JSX return of a function, or the JSX of an expression-bodied arrow. */
144
+ const findSingleJsxReturn = (funcNode) => {
145
+ if (funcNode.type === "ArrowFunctionExpression" && funcNode.body.type !== "BlockStatement") return (funcNode.body.type === "JSXElement" || funcNode.body.type === "JSXFragment" ? funcNode.body : null) ? {
146
+ kind: "arrow",
147
+ node: funcNode
148
+ } : null;
149
+ if (funcNode.body.type !== "BlockStatement") return null;
150
+ const jsxReturns = [];
151
+ let functionDepth = 0;
152
+ recast.visit(funcNode, {
153
+ visitFunction(path) {
154
+ functionDepth++;
155
+ if (functionDepth === 1) this.traverse(path);
156
+ functionDepth--;
157
+ return false;
158
+ },
159
+ visitReturnStatement(path) {
160
+ const argument = path.node.argument;
161
+ if (argument?.type === "JSXElement" || argument?.type === "JSXFragment") jsxReturns.push(path.node);
162
+ this.traverse(path);
163
+ }
164
+ });
165
+ if (jsxReturns.length !== 1) return null;
166
+ return {
167
+ kind: "return",
168
+ node: jsxReturns[0]
169
+ };
170
+ };
171
+ /**
172
+ * Wraps the returned JSX of a Next.js App Router **page** with
173
+ * `IntlayerServerProvider`, deriving the locale via `getLocale()`. Safe and
174
+ * idempotent: bails for client components, when the page has no single
175
+ * top-level JSX return, or when there is no default export.
176
+ */
177
+ const wrapPageWithProvider = (code) => {
178
+ const ast = parseTsx(code);
179
+ if (isClientComponent(ast)) return {
180
+ code,
181
+ status: "skipped-client"
182
+ };
183
+ if (code.includes("IntlayerServerProvider")) return {
184
+ code,
185
+ status: "already"
186
+ };
187
+ const funcNode = findDefaultExportFunction(ast);
188
+ if (!funcNode) return {
189
+ code,
190
+ status: "skipped"
191
+ };
192
+ const jsxReturn = findSingleJsxReturn(funcNode);
193
+ if (!jsxReturn) return {
194
+ code,
195
+ status: "skipped"
196
+ };
197
+ if (jsxReturn.kind === "return") jsxReturn.node.argument = buildProviderElement("IntlayerServerProvider", jsxReturn.node.argument);
198
+ else jsxReturn.node.body = buildProviderElement("IntlayerServerProvider", jsxReturn.node.body);
199
+ ensureNamedImport(ast, "IntlayerServerProvider", "next-intlayer/server");
200
+ ensureNamedImport(ast, "getLocale", "next-intlayer/server");
201
+ ensureAwaitedLocale(funcNode);
202
+ return {
203
+ code: recast.print(ast).code,
204
+ status: "wrapped"
205
+ };
206
+ };
207
+
208
+ //#endregion
209
+ exports.wrapLayoutWithProvider = wrapLayoutWithProvider;
210
+ exports.wrapPageWithProvider = wrapPageWithProvider;
211
+ //# sourceMappingURL=transforms.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transforms.cjs","names":[],"sources":["../../../../../src/init/frameworkSetup/nextAppRouter/transforms.ts"],"sourcesContent":["import * as recast from 'recast';\n\nconst { builders: b } = recast.types;\n\n/** babel-ts parser handles TypeScript *and* JSX (the `typescript` parser does not). */\nconst parseTsx = (code: string): any =>\n recast.parse(code, { parser: require('recast/parsers/babel-ts') });\n\n/** Result of a source transform. `code` is unchanged for any non-`wrapped` status. */\nexport type TransformResult = {\n code: string;\n status: 'wrapped' | 'already' | 'skipped-client' | 'skipped';\n};\n\n/** Detects a top-level `'use client'` directive (client components can't be async server providers). */\nconst isClientComponent = (ast: any): boolean => {\n const directives = ast.program.directives ?? [];\n if (\n directives.some((directive: any) => directive.value?.value === 'use client')\n ) {\n return true;\n }\n return ast.program.body.some(\n (stmt: any) =>\n stmt.type === 'ExpressionStatement' &&\n stmt.expression?.type === 'StringLiteral' &&\n stmt.expression.value === 'use client'\n );\n};\n\n/** Finds the function node behind `export default`, following an identifier reference if needed. */\nconst findDefaultExportFunction = (ast: any): any => {\n const body = ast.program.body;\n\n const asFunction = (node: any): any =>\n node &&\n (node.type === 'ArrowFunctionExpression' ||\n node.type === 'FunctionExpression' ||\n node.type === 'FunctionDeclaration')\n ? node\n : null;\n\n for (const stmt of body) {\n if (stmt.type !== 'ExportDefaultDeclaration') continue;\n\n const direct = asFunction(stmt.declaration);\n if (direct) return direct;\n\n if (stmt.declaration?.type === 'Identifier') {\n const name = stmt.declaration.name;\n for (const candidate of body) {\n if (candidate.type === 'VariableDeclaration') {\n for (const declarator of candidate.declarations) {\n if (\n declarator.id?.type === 'Identifier' &&\n declarator.id.name === name\n ) {\n const fn = asFunction(declarator.init);\n if (fn) return fn;\n }\n }\n }\n if (\n candidate.type === 'FunctionDeclaration' &&\n candidate.id?.name === name\n ) {\n return candidate;\n }\n }\n }\n }\n\n return null;\n};\n\n/** Index just past the leading directives + import declarations, where new top-level code is safe to insert. */\nconst firstInsertIndex = (ast: any): number => {\n const body = ast.program.body;\n let index = 0;\n while (\n index < body.length &&\n ((body[index].type === 'ExpressionStatement' &&\n body[index].expression?.type === 'StringLiteral') ||\n body[index].type === 'ImportDeclaration')\n ) {\n index++;\n }\n return index;\n};\n\n/** Ensures `import { importName } from source`, merging into an existing import from the same source. */\nconst ensureNamedImport = (\n ast: any,\n importName: string,\n source: string\n): void => {\n for (const stmt of ast.program.body) {\n if (stmt.type === 'ImportDeclaration' && stmt.source.value === source) {\n const hasSpecifier = stmt.specifiers.some(\n (spec: any) =>\n spec.type === 'ImportSpecifier' && spec.imported?.name === importName\n );\n if (!hasSpecifier) {\n stmt.specifiers.push(b.importSpecifier(b.identifier(importName)));\n }\n return;\n }\n }\n\n const declaration = b.importDeclaration(\n [b.importSpecifier(b.identifier(importName))],\n b.stringLiteral(source)\n );\n ast.program.body.splice(firstInsertIndex(ast), 0, declaration);\n};\n\n/** Ensures `export { exportedName } from source`, skipping when already declared/re-exported. */\nconst ensureExportFrom = (\n ast: any,\n exportedName: string,\n source: string\n): void => {\n const body = ast.program.body;\n\n const alreadyPresent = body.some((stmt: any) => {\n if (\n stmt.type === 'ExportNamedDeclaration' &&\n stmt.source?.value === source\n ) {\n return stmt.specifiers.some(\n (spec: any) => spec.exported?.name === exportedName\n );\n }\n // Locally declared `export const/function generateStaticParams`\n if (stmt.type === 'ExportNamedDeclaration' && stmt.declaration) {\n const decl = stmt.declaration;\n if (decl.type === 'FunctionDeclaration' && decl.id?.name === exportedName)\n return true;\n if (decl.type === 'VariableDeclaration') {\n return decl.declarations.some(\n (d: any) => d.id?.type === 'Identifier' && d.id.name === exportedName\n );\n }\n }\n return false;\n });\n\n if (alreadyPresent) return;\n\n const exportNode = parseTsx(`export { ${exportedName} } from \"${source}\";`)\n .program.body[0];\n ast.program.body.splice(firstInsertIndex(ast), 0, exportNode);\n};\n\n/** Makes the function async and inserts `const locale = await getLocale();` once, at the top of its body. */\nconst ensureAwaitedLocale = (funcNode: any): void => {\n funcNode.async = true;\n\n if (funcNode.body.type !== 'BlockStatement') {\n funcNode.body = b.blockStatement([b.returnStatement(funcNode.body)]);\n }\n\n const hasLocale = funcNode.body.body.some(\n (stmt: any) =>\n stmt.type === 'VariableDeclaration' &&\n stmt.declarations.some(\n (d: any) => d.id?.type === 'Identifier' && d.id.name === 'locale'\n )\n );\n\n if (!hasLocale) {\n const localeStatement = parseTsx('const locale = await getLocale();')\n .program.body[0];\n funcNode.body.body.unshift(localeStatement);\n }\n};\n\n/** Builds `<providerName locale={locale}>{child}</providerName>` around an existing JSX child node. */\nconst buildProviderElement = (providerName: string, childNode: any): any => {\n const template = parseTsx(\n `const __wrap = <${providerName} locale={locale}>{__child__}</${providerName}>;`\n );\n const providerElement = template.program.body[0].declarations[0].init;\n providerElement.children = [childNode];\n return providerElement;\n};\n\n/** Sets `lang={locale}` on the first `<html>` element, if present. */\nconst setHtmlLang = (ast: any): void => {\n recast.visit(ast, {\n visitJSXOpeningElement(path) {\n const node = path.node;\n if (node.name?.type === 'JSXIdentifier' && node.name.name === 'html') {\n const langAttr = node.attributes?.find(\n (attr: any) =>\n attr.type === 'JSXAttribute' && attr.name?.name === 'lang'\n ) as any;\n const localeExpression = b.jsxExpressionContainer(\n b.identifier('locale')\n );\n if (langAttr) {\n langAttr.value = localeExpression;\n } else {\n node.attributes.push(\n b.jsxAttribute(b.jsxIdentifier('lang'), localeExpression)\n );\n }\n return false;\n }\n this.traverse(path);\n },\n });\n};\n\n/**\n * Wraps the `{children}` of a Next.js App Router **layout** with\n * `IntlayerClientProvider`, deriving the locale via `getLocale()`. Safe and\n * idempotent: bails (returns the original code) for client components, when no\n * `{children}` placeholder is found, or when there is no default export.\n */\nexport const wrapLayoutWithProvider = (code: string): TransformResult => {\n const ast = parseTsx(code);\n\n if (isClientComponent(ast)) return { code, status: 'skipped-client' };\n if (code.includes('IntlayerClientProvider'))\n return { code, status: 'already' };\n\n const funcNode = findDefaultExportFunction(ast);\n if (!funcNode) return { code, status: 'skipped' };\n\n let wrapped = false;\n recast.visit(funcNode, {\n visitJSXExpressionContainer(path) {\n if (wrapped) return false;\n const expression = path.node.expression;\n if (expression?.type === 'Identifier' && expression.name === 'children') {\n path.replace(buildProviderElement('IntlayerClientProvider', path.node));\n wrapped = true;\n return false;\n }\n this.traverse(path);\n },\n });\n\n if (!wrapped) return { code, status: 'skipped' };\n\n ensureNamedImport(ast, 'IntlayerClientProvider', 'next-intlayer');\n ensureNamedImport(ast, 'getLocale', 'next-intlayer/server');\n ensureExportFrom(ast, 'generateStaticParams', 'next-intlayer');\n ensureAwaitedLocale(funcNode);\n setHtmlLang(ast);\n\n return { code: recast.print(ast).code, status: 'wrapped' };\n};\n\n/** Returns the single top-level JSX return of a function, or the JSX of an expression-bodied arrow. */\nconst findSingleJsxReturn = (\n funcNode: any\n): { kind: 'return'; node: any } | { kind: 'arrow'; node: any } | null => {\n if (\n funcNode.type === 'ArrowFunctionExpression' &&\n funcNode.body.type !== 'BlockStatement'\n ) {\n const body =\n funcNode.body.type === 'JSXElement' ||\n funcNode.body.type === 'JSXFragment'\n ? funcNode.body\n : null;\n return body ? { kind: 'arrow', node: funcNode } : null;\n }\n\n if (funcNode.body.type !== 'BlockStatement') return null;\n\n // Collect every JSX-returning `return` inside this function, but do not\n // descend into nested function scopes (e.g. an inner component defined in the\n // same file). More than one top-level JSX return is ambiguous — bail.\n const jsxReturns: any[] = [];\n let functionDepth = 0;\n recast.visit(funcNode, {\n visitFunction(path) {\n functionDepth++;\n if (functionDepth === 1) {\n this.traverse(path);\n }\n functionDepth--;\n return false;\n },\n visitReturnStatement(path) {\n const argument = path.node.argument;\n if (argument?.type === 'JSXElement' || argument?.type === 'JSXFragment') {\n jsxReturns.push(path.node);\n }\n this.traverse(path);\n },\n });\n\n if (jsxReturns.length !== 1) return null;\n return { kind: 'return', node: jsxReturns[0] };\n};\n\n/**\n * Wraps the returned JSX of a Next.js App Router **page** with\n * `IntlayerServerProvider`, deriving the locale via `getLocale()`. Safe and\n * idempotent: bails for client components, when the page has no single\n * top-level JSX return, or when there is no default export.\n */\nexport const wrapPageWithProvider = (code: string): TransformResult => {\n const ast = parseTsx(code);\n\n if (isClientComponent(ast)) return { code, status: 'skipped-client' };\n if (code.includes('IntlayerServerProvider'))\n return { code, status: 'already' };\n\n const funcNode = findDefaultExportFunction(ast);\n if (!funcNode) return { code, status: 'skipped' };\n\n const jsxReturn = findSingleJsxReturn(funcNode);\n if (!jsxReturn) return { code, status: 'skipped' };\n\n if (jsxReturn.kind === 'return') {\n jsxReturn.node.argument = buildProviderElement(\n 'IntlayerServerProvider',\n jsxReturn.node.argument\n );\n } else {\n jsxReturn.node.body = buildProviderElement(\n 'IntlayerServerProvider',\n jsxReturn.node.body\n );\n }\n\n ensureNamedImport(ast, 'IntlayerServerProvider', 'next-intlayer/server');\n ensureNamedImport(ast, 'getLocale', 'next-intlayer/server');\n ensureAwaitedLocale(funcNode);\n\n return { code: recast.print(ast).code, status: 'wrapped' };\n};\n"],"mappings":";;;;;;AAEA,MAAM,EAAE,UAAU,MAAM,OAAO;;AAG/B,MAAM,YAAY,SAChB,OAAO,MAAM,MAAM,EAAE,QAAQ,QAAQ,0BAA0B,EAAE,CAAC;;AASpE,MAAM,qBAAqB,QAAsB;AAE/C,MADmB,IAAI,QAAQ,cAAc,EAAE,EAElC,MAAM,cAAmB,UAAU,OAAO,UAAU,aAAa,CAE5E,QAAO;AAET,QAAO,IAAI,QAAQ,KAAK,MACrB,SACC,KAAK,SAAS,yBACd,KAAK,YAAY,SAAS,mBAC1B,KAAK,WAAW,UAAU,aAC7B;;;AAIH,MAAM,6BAA6B,QAAkB;CACnD,MAAM,OAAO,IAAI,QAAQ;CAEzB,MAAM,cAAc,SAClB,SACC,KAAK,SAAS,6BACb,KAAK,SAAS,wBACd,KAAK,SAAS,yBACZ,OACA;AAEN,MAAK,MAAM,QAAQ,MAAM;AACvB,MAAI,KAAK,SAAS,2BAA4B;EAE9C,MAAM,SAAS,WAAW,KAAK,YAAY;AAC3C,MAAI,OAAQ,QAAO;AAEnB,MAAI,KAAK,aAAa,SAAS,cAAc;GAC3C,MAAM,OAAO,KAAK,YAAY;AAC9B,QAAK,MAAM,aAAa,MAAM;AAC5B,QAAI,UAAU,SAAS,uBACrB;UAAK,MAAM,cAAc,UAAU,aACjC,KACE,WAAW,IAAI,SAAS,gBACxB,WAAW,GAAG,SAAS,MACvB;MACA,MAAM,KAAK,WAAW,WAAW,KAAK;AACtC,UAAI,GAAI,QAAO;;;AAIrB,QACE,UAAU,SAAS,yBACnB,UAAU,IAAI,SAAS,KAEvB,QAAO;;;;AAMf,QAAO;;;AAIT,MAAM,oBAAoB,QAAqB;CAC7C,MAAM,OAAO,IAAI,QAAQ;CACzB,IAAI,QAAQ;AACZ,QACE,QAAQ,KAAK,WACX,KAAK,OAAO,SAAS,yBACrB,KAAK,OAAO,YAAY,SAAS,mBACjC,KAAK,OAAO,SAAS,qBAEvB;AAEF,QAAO;;;AAIT,MAAM,qBACJ,KACA,YACA,WACS;AACT,MAAK,MAAM,QAAQ,IAAI,QAAQ,KAC7B,KAAI,KAAK,SAAS,uBAAuB,KAAK,OAAO,UAAU,QAAQ;AAKrE,MAAI,CAJiB,KAAK,WAAW,MAClC,SACC,KAAK,SAAS,qBAAqB,KAAK,UAAU,SAAS,WAE9C,CACf,MAAK,WAAW,KAAK,EAAE,gBAAgB,EAAE,WAAW,WAAW,CAAC,CAAC;AAEnE;;CAIJ,MAAM,cAAc,EAAE,kBACpB,CAAC,EAAE,gBAAgB,EAAE,WAAW,WAAW,CAAC,CAAC,EAC7C,EAAE,cAAc,OAAO,CACxB;AACD,KAAI,QAAQ,KAAK,OAAO,iBAAiB,IAAI,EAAE,GAAG,YAAY;;;AAIhE,MAAM,oBACJ,KACA,cACA,WACS;AA0BT,KAzBa,IAAI,QAAQ,KAEG,MAAM,SAAc;AAC9C,MACE,KAAK,SAAS,4BACd,KAAK,QAAQ,UAAU,OAEvB,QAAO,KAAK,WAAW,MACpB,SAAc,KAAK,UAAU,SAAS,aACxC;AAGH,MAAI,KAAK,SAAS,4BAA4B,KAAK,aAAa;GAC9D,MAAM,OAAO,KAAK;AAClB,OAAI,KAAK,SAAS,yBAAyB,KAAK,IAAI,SAAS,aAC3D,QAAO;AACT,OAAI,KAAK,SAAS,sBAChB,QAAO,KAAK,aAAa,MACtB,MAAW,EAAE,IAAI,SAAS,gBAAgB,EAAE,GAAG,SAAS,aAC1D;;AAGL,SAAO;GAGS,CAAE;CAEpB,MAAM,aAAa,SAAS,YAAY,aAAa,WAAW,OAAO,IAAI,CACxE,QAAQ,KAAK;AAChB,KAAI,QAAQ,KAAK,OAAO,iBAAiB,IAAI,EAAE,GAAG,WAAW;;;AAI/D,MAAM,uBAAuB,aAAwB;AACnD,UAAS,QAAQ;AAEjB,KAAI,SAAS,KAAK,SAAS,iBACzB,UAAS,OAAO,EAAE,eAAe,CAAC,EAAE,gBAAgB,SAAS,KAAK,CAAC,CAAC;AAWtE,KAAI,CARc,SAAS,KAAK,KAAK,MAClC,SACC,KAAK,SAAS,yBACd,KAAK,aAAa,MACf,MAAW,EAAE,IAAI,SAAS,gBAAgB,EAAE,GAAG,SAAS,SAC1D,CAGS,EAAE;EACd,MAAM,kBAAkB,SAAS,oCAAoC,CAClE,QAAQ,KAAK;AAChB,WAAS,KAAK,KAAK,QAAQ,gBAAgB;;;;AAK/C,MAAM,wBAAwB,cAAsB,cAAwB;CAI1E,MAAM,kBAHW,SACf,mBAAmB,aAAa,gCAAgC,aAAa,IAE/C,CAAC,QAAQ,KAAK,GAAG,aAAa,GAAG;AACjE,iBAAgB,WAAW,CAAC,UAAU;AACtC,QAAO;;;AAIT,MAAM,eAAe,QAAmB;AACtC,QAAO,MAAM,KAAK,EAChB,uBAAuB,MAAM;EAC3B,MAAM,OAAO,KAAK;AAClB,MAAI,KAAK,MAAM,SAAS,mBAAmB,KAAK,KAAK,SAAS,QAAQ;GACpE,MAAM,WAAW,KAAK,YAAY,MAC/B,SACC,KAAK,SAAS,kBAAkB,KAAK,MAAM,SAAS,OACvD;GACD,MAAM,mBAAmB,EAAE,uBACzB,EAAE,WAAW,SAAS,CACvB;AACD,OAAI,SACF,UAAS,QAAQ;OAEjB,MAAK,WAAW,KACd,EAAE,aAAa,EAAE,cAAc,OAAO,EAAE,iBAAiB,CAC1D;AAEH,UAAO;;AAET,OAAK,SAAS,KAAK;IAEtB,CAAC;;;;;;;;AASJ,MAAa,0BAA0B,SAAkC;CACvE,MAAM,MAAM,SAAS,KAAK;AAE1B,KAAI,kBAAkB,IAAI,CAAE,QAAO;EAAE;EAAM,QAAQ;EAAkB;AACrE,KAAI,KAAK,SAAS,yBAAyB,CACzC,QAAO;EAAE;EAAM,QAAQ;EAAW;CAEpC,MAAM,WAAW,0BAA0B,IAAI;AAC/C,KAAI,CAAC,SAAU,QAAO;EAAE;EAAM,QAAQ;EAAW;CAEjD,IAAI,UAAU;AACd,QAAO,MAAM,UAAU,EACrB,4BAA4B,MAAM;AAChC,MAAI,QAAS,QAAO;EACpB,MAAM,aAAa,KAAK,KAAK;AAC7B,MAAI,YAAY,SAAS,gBAAgB,WAAW,SAAS,YAAY;AACvE,QAAK,QAAQ,qBAAqB,0BAA0B,KAAK,KAAK,CAAC;AACvE,aAAU;AACV,UAAO;;AAET,OAAK,SAAS,KAAK;IAEtB,CAAC;AAEF,KAAI,CAAC,QAAS,QAAO;EAAE;EAAM,QAAQ;EAAW;AAEhD,mBAAkB,KAAK,0BAA0B,gBAAgB;AACjE,mBAAkB,KAAK,aAAa,uBAAuB;AAC3D,kBAAiB,KAAK,wBAAwB,gBAAgB;AAC9D,qBAAoB,SAAS;AAC7B,aAAY,IAAI;AAEhB,QAAO;EAAE,MAAM,OAAO,MAAM,IAAI,CAAC;EAAM,QAAQ;EAAW;;;AAI5D,MAAM,uBACJ,aACwE;AACxE,KACE,SAAS,SAAS,6BAClB,SAAS,KAAK,SAAS,iBAOvB,SAJE,SAAS,KAAK,SAAS,gBACvB,SAAS,KAAK,SAAS,gBACnB,SAAS,OACT,QACQ;EAAE,MAAM;EAAS,MAAM;EAAU,GAAG;AAGpD,KAAI,SAAS,KAAK,SAAS,iBAAkB,QAAO;CAKpD,MAAM,aAAoB,EAAE;CAC5B,IAAI,gBAAgB;AACpB,QAAO,MAAM,UAAU;EACrB,cAAc,MAAM;AAClB;AACA,OAAI,kBAAkB,EACpB,MAAK,SAAS,KAAK;AAErB;AACA,UAAO;;EAET,qBAAqB,MAAM;GACzB,MAAM,WAAW,KAAK,KAAK;AAC3B,OAAI,UAAU,SAAS,gBAAgB,UAAU,SAAS,cACxD,YAAW,KAAK,KAAK,KAAK;AAE5B,QAAK,SAAS,KAAK;;EAEtB,CAAC;AAEF,KAAI,WAAW,WAAW,EAAG,QAAO;AACpC,QAAO;EAAE,MAAM;EAAU,MAAM,WAAW;EAAI;;;;;;;;AAShD,MAAa,wBAAwB,SAAkC;CACrE,MAAM,MAAM,SAAS,KAAK;AAE1B,KAAI,kBAAkB,IAAI,CAAE,QAAO;EAAE;EAAM,QAAQ;EAAkB;AACrE,KAAI,KAAK,SAAS,yBAAyB,CACzC,QAAO;EAAE;EAAM,QAAQ;EAAW;CAEpC,MAAM,WAAW,0BAA0B,IAAI;AAC/C,KAAI,CAAC,SAAU,QAAO;EAAE;EAAM,QAAQ;EAAW;CAEjD,MAAM,YAAY,oBAAoB,SAAS;AAC/C,KAAI,CAAC,UAAW,QAAO;EAAE;EAAM,QAAQ;EAAW;AAElD,KAAI,UAAU,SAAS,SACrB,WAAU,KAAK,WAAW,qBACxB,0BACA,UAAU,KAAK,SAChB;KAED,WAAU,KAAK,OAAO,qBACpB,0BACA,UAAU,KAAK,KAChB;AAGH,mBAAkB,KAAK,0BAA0B,uBAAuB;AACxE,mBAAkB,KAAK,aAAa,uBAAuB;AAC3D,qBAAoB,SAAS;AAE7B,QAAO;EAAE,MAAM,OAAO,MAAM,IAAI,CAAC;EAAM,QAAQ;EAAW"}
@@ -0,0 +1,31 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_runtime = require('../../../_virtual/_rolldown/runtime.cjs');
3
+ const require_init_utils_fileSystem = require('../../utils/fileSystem.cjs');
4
+ let node_path = require("node:path");
5
+
6
+ //#region src/init/frameworkSetup/tanstackStart/detect.ts
7
+ /**
8
+ * Detects the TanStack Router routes directory, preferring `src/routes` over
9
+ * `routes`. Returns `null` when neither exists.
10
+ */
11
+ const detectTanStackRoutesDir = async (rootDir) => {
12
+ if (await require_init_utils_fileSystem.exists(rootDir, (0, node_path.join)("src", "routes"))) return {
13
+ routesDir: (0, node_path.join)("src", "routes"),
14
+ srcDir: "src"
15
+ };
16
+ if (await require_init_utils_fileSystem.exists(rootDir, "routes")) return {
17
+ routesDir: "routes",
18
+ srcDir: ""
19
+ };
20
+ return null;
21
+ };
22
+ /**
23
+ * Returns true when the project depends on TanStack Start (`@tanstack/react-start`)
24
+ * or, failing that, on `@tanstack/react-router` (file-based routing).
25
+ */
26
+ const hasTanStackStartDeps = (allDeps) => Boolean(allDeps["@tanstack/react-start"] || allDeps["@tanstack/react-router"]);
27
+
28
+ //#endregion
29
+ exports.detectTanStackRoutesDir = detectTanStackRoutesDir;
30
+ exports.hasTanStackStartDeps = hasTanStackStartDeps;
31
+ //# sourceMappingURL=detect.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.cjs","names":["exists"],"sources":["../../../../../src/init/frameworkSetup/tanstackStart/detect.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { exists } from '../../utils/fileSystem';\n\n/** Location of the TanStack Router file-based routes directory. */\nexport type TanStackRoutesInfo = {\n /** Routes directory relative to the root, e.g. `src/routes` or `routes`. */\n routesDir: string;\n /** `src` when the project uses a `src/` directory, otherwise `''`. */\n srcDir: string;\n};\n\n/**\n * Detects the TanStack Router routes directory, preferring `src/routes` over\n * `routes`. Returns `null` when neither exists.\n */\nexport const detectTanStackRoutesDir = async (\n rootDir: string\n): Promise<TanStackRoutesInfo | null> => {\n if (await exists(rootDir, join('src', 'routes'))) {\n return { routesDir: join('src', 'routes'), srcDir: 'src' };\n }\n if (await exists(rootDir, 'routes')) {\n return { routesDir: 'routes', srcDir: '' };\n }\n return null;\n};\n\n/**\n * Returns true when the project depends on TanStack Start (`@tanstack/react-start`)\n * or, failing that, on `@tanstack/react-router` (file-based routing).\n */\nexport const hasTanStackStartDeps = (\n allDeps: Record<string, string>\n): boolean =>\n Boolean(\n allDeps['@tanstack/react-start'] || allDeps['@tanstack/react-router']\n );\n"],"mappings":";;;;;;;;;;AAeA,MAAa,0BAA0B,OACrC,YACuC;AACvC,KAAI,MAAMA,qCAAO,6BAAc,OAAO,SAAS,CAAC,CAC9C,QAAO;EAAE,+BAAgB,OAAO,SAAS;EAAE,QAAQ;EAAO;AAE5D,KAAI,MAAMA,qCAAO,SAAS,SAAS,CACjC,QAAO;EAAE,WAAW;EAAU,QAAQ;EAAI;AAE5C,QAAO;;;;;;AAOT,MAAa,wBACX,YAEA,QACE,QAAQ,4BAA4B,QAAQ,0BAC7C"}
@@ -0,0 +1,74 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_runtime = require('../../../_virtual/_rolldown/runtime.cjs');
3
+ const require_init_utils_fileSystem = require('../../utils/fileSystem.cjs');
4
+ const require_init_frameworkSetup_nextAppRouter_detect = require('../nextAppRouter/detect.cjs');
5
+ const require_init_frameworkSetup_tanstackStart_detect = require('./detect.cjs');
6
+ const require_init_frameworkSetup_tanstackStart_restructure = require('./restructure.cjs');
7
+ const require_init_frameworkSetup_tanstackStart_templates = require('./templates.cjs');
8
+ const require_init_frameworkSetup_tanstackStart_transforms = require('./transforms.cjs');
9
+ let node_path = require("node:path");
10
+ let _intlayer_config_logger = require("@intlayer/config/logger");
11
+ let _intlayer_config_colors = require("@intlayer/config/colors");
12
+ _intlayer_config_colors = require_runtime.__toESM(_intlayer_config_colors);
13
+
14
+ //#region src/init/frameworkSetup/tanstackStart/index.ts
15
+ /** Logs the outcome of the root-document provider-wrap transform. */
16
+ const logTransformOutcome = (filePath, result) => {
17
+ switch (result.status) {
18
+ case "wrapped":
19
+ (0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} Added Intlayer provider to ${(0, _intlayer_config_logger.colorizePath)(filePath)}`);
20
+ break;
21
+ case "already":
22
+ (0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} ${(0, _intlayer_config_logger.colorizePath)(filePath)} already wraps the Intlayer provider`);
23
+ break;
24
+ case "skipped":
25
+ (0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.x} Could not safely add the Intlayer provider to ${(0, _intlayer_config_logger.colorizePath)(filePath)} — please wrap the document's {children} with <IntlayerProvider locale={locale}> manually.`, { level: "warn" });
26
+ break;
27
+ }
28
+ };
29
+ /** Transforms an existing file in place, writing it back only when changed. */
30
+ const transformExistingFile = async (rootDir, filePath, transform) => {
31
+ const result = transform(await require_init_utils_fileSystem.readFileFromRoot(rootDir, filePath));
32
+ if (result.status === "wrapped") await require_init_utils_fileSystem.writeFileToRoot(rootDir, filePath, result.code);
33
+ logTransformOutcome(filePath, result);
34
+ };
35
+ /** Creates a file from a template only when it does not already exist. */
36
+ const createIfMissing = async (rootDir, filePath, content, description) => {
37
+ if (await require_init_utils_fileSystem.exists(rootDir, filePath)) return false;
38
+ await require_init_utils_fileSystem.writeFileToRoot(rootDir, filePath, content);
39
+ (0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} Created ${description} ${(0, _intlayer_config_logger.colorizePath)(filePath)}`);
40
+ return true;
41
+ };
42
+ /**
43
+ * TanStack Start adapter. Restructures the file-based routes under a `{-$locale}`
44
+ * segment, scaffolds the locale segment route, and wraps the root document with
45
+ * the Intlayer provider — all idempotently and without overwriting user code it
46
+ * cannot confidently transform.
47
+ */
48
+ const tanStackStartAdapter = {
49
+ name: "TanStack Start",
50
+ detect: async ({ rootDir, allDeps }) => {
51
+ if (!require_init_frameworkSetup_tanstackStart_detect.hasTanStackStartDeps(allDeps)) return false;
52
+ return await require_init_frameworkSetup_tanstackStart_detect.detectTanStackRoutesDir(rootDir) !== null;
53
+ },
54
+ setup: async ({ rootDir, useTypeScript }) => {
55
+ const routesInfo = await require_init_frameworkSetup_tanstackStart_detect.detectTanStackRoutesDir(rootDir);
56
+ if (!routesInfo) return;
57
+ const { routesDir } = routesInfo;
58
+ const scriptExtension = useTypeScript ? "tsx" : "jsx";
59
+ (0, _intlayer_config_logger.logger)((0, _intlayer_config_logger.colorize)("Setting up TanStack Start integration...", _intlayer_config_colors.CYAN));
60
+ const restructureResult = await require_init_frameworkSetup_tanstackStart_restructure.restructureRoutesIntoLocale(rootDir, routesDir);
61
+ if (restructureResult.status === "moved") (0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} Restructured routes under ${(0, _intlayer_config_logger.colorizePath)((0, node_path.join)(routesDir, require_init_frameworkSetup_tanstackStart_restructure.LOCALE_SEGMENT))}: ${restructureResult.movedEntries.map((entry) => (0, _intlayer_config_logger.colorize)(entry, _intlayer_config_colors.MAGENTA)).join(", ")}`);
62
+ else if (restructureResult.status === "already-structured") (0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} ${(0, _intlayer_config_logger.colorizePath)((0, node_path.join)(routesDir, require_init_frameworkSetup_tanstackStart_restructure.LOCALE_SEGMENT))} already exists, skipping restructure`);
63
+ const localeDir = (0, node_path.join)(routesDir, require_init_frameworkSetup_tanstackStart_restructure.LOCALE_SEGMENT);
64
+ await require_init_utils_fileSystem.ensureDirectory(rootDir, localeDir);
65
+ await createIfMissing(rootDir, (0, node_path.join)(localeDir, `route.${scriptExtension}`), require_init_frameworkSetup_tanstackStart_templates.LOCALE_ROUTE_TEMPLATE, "locale route");
66
+ const existingRoot = await require_init_frameworkSetup_nextAppRouter_detect.findAppFile(rootDir, routesDir, "__root");
67
+ if (existingRoot) await transformExistingFile(rootDir, existingRoot, require_init_frameworkSetup_tanstackStart_transforms.wrapRootWithProvider);
68
+ else await createIfMissing(rootDir, (0, node_path.join)(routesDir, `__root.${scriptExtension}`), useTypeScript ? require_init_frameworkSetup_tanstackStart_templates.ROOT_TEMPLATE_TS : require_init_frameworkSetup_tanstackStart_templates.ROOT_TEMPLATE_JS, "root document");
69
+ }
70
+ };
71
+
72
+ //#endregion
73
+ exports.tanStackStartAdapter = tanStackStartAdapter;
74
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["v","x","readFileFromRoot","writeFileToRoot","exists","hasTanStackStartDeps","detectTanStackRoutesDir","ANSIColors","restructureRoutesIntoLocale","LOCALE_SEGMENT","ensureDirectory","LOCALE_ROUTE_TEMPLATE","findAppFile","wrapRootWithProvider","ROOT_TEMPLATE_TS","ROOT_TEMPLATE_JS"],"sources":["../../../../../src/init/frameworkSetup/tanstackStart/index.ts"],"sourcesContent":["import { join } from 'node:path';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizePath, logger, v, x } from '@intlayer/config/logger';\nimport {\n ensureDirectory,\n exists,\n readFileFromRoot,\n writeFileToRoot,\n} from '../../utils/fileSystem';\nimport { findAppFile } from '../nextAppRouter/detect';\nimport type { FrameworkAdapter, FrameworkSetupContext } from '../types';\nimport { detectTanStackRoutesDir, hasTanStackStartDeps } from './detect';\nimport { LOCALE_SEGMENT, restructureRoutesIntoLocale } from './restructure';\nimport {\n LOCALE_ROUTE_TEMPLATE,\n ROOT_TEMPLATE_JS,\n ROOT_TEMPLATE_TS,\n} from './templates';\nimport { type TransformResult, wrapRootWithProvider } from './transforms';\n\n/** Logs the outcome of the root-document provider-wrap transform. */\nconst logTransformOutcome = (\n filePath: string,\n result: TransformResult\n): void => {\n switch (result.status) {\n case 'wrapped':\n logger(`${v} Added Intlayer provider to ${colorizePath(filePath)}`);\n break;\n case 'already':\n logger(\n `${v} ${colorizePath(filePath)} already wraps the Intlayer provider`\n );\n break;\n case 'skipped':\n logger(\n `${x} Could not safely add the Intlayer provider to ${colorizePath(filePath)} — please wrap the document's {children} with <IntlayerProvider locale={locale}> manually.`,\n { level: 'warn' }\n );\n break;\n }\n};\n\n/** Transforms an existing file in place, writing it back only when changed. */\nconst transformExistingFile = async (\n rootDir: string,\n filePath: string,\n transform: (code: string) => TransformResult\n): Promise<void> => {\n const code = await readFileFromRoot(rootDir, filePath);\n const result = transform(code);\n if (result.status === 'wrapped') {\n await writeFileToRoot(rootDir, filePath, result.code);\n }\n logTransformOutcome(filePath, result);\n};\n\n/** Creates a file from a template only when it does not already exist. */\nconst createIfMissing = async (\n rootDir: string,\n filePath: string,\n content: string,\n description: string\n): Promise<boolean> => {\n if (await exists(rootDir, filePath)) return false;\n await writeFileToRoot(rootDir, filePath, content);\n logger(`${v} Created ${description} ${colorizePath(filePath)}`);\n return true;\n};\n\n/**\n * TanStack Start adapter. Restructures the file-based routes under a `{-$locale}`\n * segment, scaffolds the locale segment route, and wraps the root document with\n * the Intlayer provider — all idempotently and without overwriting user code it\n * cannot confidently transform.\n */\nexport const tanStackStartAdapter: FrameworkAdapter = {\n name: 'TanStack Start',\n\n detect: async ({ rootDir, allDeps }) => {\n if (!hasTanStackStartDeps(allDeps)) return false;\n return (await detectTanStackRoutesDir(rootDir)) !== null;\n },\n\n setup: async ({ rootDir, useTypeScript }: FrameworkSetupContext) => {\n const routesInfo = await detectTanStackRoutesDir(rootDir);\n if (!routesInfo) return;\n\n const { routesDir } = routesInfo;\n const scriptExtension = useTypeScript ? 'tsx' : 'jsx';\n\n logger(\n colorize('Setting up TanStack Start integration...', ANSIColors.CYAN)\n );\n\n // 1. Move routable route entries under a `{-$locale}` segment (idempotent).\n const restructureResult = await restructureRoutesIntoLocale(\n rootDir,\n routesDir\n );\n if (restructureResult.status === 'moved') {\n logger(\n `${v} Restructured routes under ${colorizePath(join(routesDir, LOCALE_SEGMENT))}: ${restructureResult.movedEntries\n .map((entry) => colorize(entry, ANSIColors.MAGENTA))\n .join(', ')}`\n );\n } else if (restructureResult.status === 'already-structured') {\n logger(\n `${v} ${colorizePath(join(routesDir, LOCALE_SEGMENT))} already exists, skipping restructure`\n );\n }\n\n const localeDir = join(routesDir, LOCALE_SEGMENT);\n await ensureDirectory(rootDir, localeDir);\n\n // 2. Locale segment route (`{-$locale}/route.tsx`) — create only when absent.\n await createIfMissing(\n rootDir,\n join(localeDir, `route.${scriptExtension}`),\n LOCALE_ROUTE_TEMPLATE,\n 'locale route'\n );\n\n // 3. Root document — transform an existing `__root`, else scaffold one.\n const existingRoot = await findAppFile(rootDir, routesDir, '__root');\n if (existingRoot) {\n await transformExistingFile(rootDir, existingRoot, wrapRootWithProvider);\n } else {\n await createIfMissing(\n rootDir,\n join(routesDir, `__root.${scriptExtension}`),\n useTypeScript ? ROOT_TEMPLATE_TS : ROOT_TEMPLATE_JS,\n 'root document'\n );\n }\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;AAqBA,MAAM,uBACJ,UACA,WACS;AACT,SAAQ,OAAO,QAAf;EACE,KAAK;AACH,uCAAO,GAAGA,0BAAE,wEAA2C,SAAS,GAAG;AACnE;EACF,KAAK;AACH,uCACE,GAAGA,0BAAE,6CAAgB,SAAS,CAAC,sCAChC;AACD;EACF,KAAK;AACH,uCACE,GAAGC,0BAAE,2FAA8D,SAAS,CAAC,6FAC7E,EAAE,OAAO,QAAQ,CAClB;AACD;;;;AAKN,MAAM,wBAAwB,OAC5B,SACA,UACA,cACkB;CAElB,MAAM,SAAS,UAAU,MADNC,+CAAiB,SAAS,SAAS,CACxB;AAC9B,KAAI,OAAO,WAAW,UACpB,OAAMC,8CAAgB,SAAS,UAAU,OAAO,KAAK;AAEvD,qBAAoB,UAAU,OAAO;;;AAIvC,MAAM,kBAAkB,OACtB,SACA,UACA,SACA,gBACqB;AACrB,KAAI,MAAMC,qCAAO,SAAS,SAAS,CAAE,QAAO;AAC5C,OAAMD,8CAAgB,SAAS,UAAU,QAAQ;AACjD,qCAAO,GAAGH,0BAAE,WAAW,YAAY,6CAAgB,SAAS,GAAG;AAC/D,QAAO;;;;;;;;AAST,MAAa,uBAAyC;CACpD,MAAM;CAEN,QAAQ,OAAO,EAAE,SAAS,cAAc;AACtC,MAAI,CAACK,sEAAqB,QAAQ,CAAE,QAAO;AAC3C,SAAQ,MAAMC,yEAAwB,QAAQ,KAAM;;CAGtD,OAAO,OAAO,EAAE,SAAS,oBAA2C;EAClE,MAAM,aAAa,MAAMA,yEAAwB,QAAQ;AACzD,MAAI,CAAC,WAAY;EAEjB,MAAM,EAAE,cAAc;EACtB,MAAM,kBAAkB,gBAAgB,QAAQ;AAEhD,4EACW,4CAA4CC,wBAAW,KAAK,CACtE;EAGD,MAAM,oBAAoB,MAAMC,kFAC9B,SACA,UACD;AACD,MAAI,kBAAkB,WAAW,QAC/B,qCACE,GAAGR,0BAAE,2FAA+C,WAAWS,qEAAe,CAAC,CAAC,IAAI,kBAAkB,aACnG,KAAK,gDAAmB,OAAOF,wBAAW,QAAQ,CAAC,CACnD,KAAK,KAAK,GACd;WACQ,kBAAkB,WAAW,qBACtC,qCACE,GAAGP,0BAAE,iEAAqB,WAAWS,qEAAe,CAAC,CAAC,uCACvD;EAGH,MAAM,gCAAiB,WAAWA,qEAAe;AACjD,QAAMC,8CAAgB,SAAS,UAAU;AAGzC,QAAM,gBACJ,6BACK,WAAW,SAAS,kBAAkB,EAC3CC,2EACA,eACD;EAGD,MAAM,eAAe,MAAMC,6DAAY,SAAS,WAAW,SAAS;AACpE,MAAI,aACF,OAAM,sBAAsB,SAAS,cAAcC,0EAAqB;MAExE,OAAM,gBACJ,6BACK,WAAW,UAAU,kBAAkB,EAC5C,gBAAgBC,uEAAmBC,sEACnC,gBACD;;CAGN"}
@@ -0,0 +1,79 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_runtime = require('../../../_virtual/_rolldown/runtime.cjs');
3
+ const require_init_frameworkSetup_nextAppRouter_restructure = require('../nextAppRouter/restructure.cjs');
4
+ let node_fs_promises = require("node:fs/promises");
5
+ let node_path = require("node:path");
6
+ let fast_glob = require("fast-glob");
7
+ fast_glob = require_runtime.__toESM(fast_glob);
8
+ let node_fs = require("node:fs");
9
+
10
+ //#region src/init/frameworkSetup/tanstackStart/restructure.ts
11
+ /** Source file extensions whose relative imports must be rewritten after a move. */
12
+ const SCRIPT_GLOB = "**/*.{ts,tsx,js,jsx,mjs,cjs}";
13
+ /** The TanStack Router locale segment directory (optional `{-$locale}` param). */
14
+ const LOCALE_SEGMENT = "{-$locale}";
15
+ /** Strips a known script extension from a file name, e.g. `index.tsx` -> `index`. */
16
+ const stripScriptExtension = (fileName) => fileName.replace(/\.(tsx|ts|jsx|js|mjs|cjs)$/, "");
17
+ /**
18
+ * Routes-directory entries that must stay at the root and never be moved under
19
+ * `{-$locale}`:
20
+ * - `__root` (the root route document),
21
+ * - `routeTree.gen` (generated route tree),
22
+ * - `api` (server / API routes — these are not locale-prefixed),
23
+ * - TanStack-ignored entries prefixed with `-` (e.g. `-components`, `-utils`),
24
+ * - stylesheets.
25
+ *
26
+ * Everything else (route files and nested route folders) is moved so it becomes
27
+ * locale-aware.
28
+ */
29
+ const shouldKeepRouteAtRoot = (entryName) => {
30
+ if (entryName.startsWith("-")) return true;
31
+ if (entryName.toLowerCase().endsWith(".css")) return true;
32
+ const base = stripScriptExtension(entryName);
33
+ return new Set([
34
+ "__root",
35
+ "routeTree.gen",
36
+ "api"
37
+ ]).has(base);
38
+ };
39
+ /**
40
+ * Moves the routable entries of `routesDir` under a new `{-$locale}` segment and
41
+ * rewrites relative imports in the moved files. Idempotent: a no-op when
42
+ * `{-$locale}` already exists. Root-only files (see {@link shouldKeepRouteAtRoot})
43
+ * are left in place.
44
+ */
45
+ const restructureRoutesIntoLocale = async (rootDir, routesDir) => {
46
+ const routesDirAbs = (0, node_path.join)(rootDir, routesDir);
47
+ const localeDirAbs = (0, node_path.join)(routesDirAbs, LOCALE_SEGMENT);
48
+ if ((0, node_fs.existsSync)(localeDirAbs)) return { status: "already-structured" };
49
+ const movedTopLevelNames = (await (0, node_fs_promises.readdir)(routesDirAbs, { withFileTypes: true })).map((entry) => entry.name).filter((name) => !shouldKeepRouteAtRoot(name));
50
+ if (movedTopLevelNames.length === 0) return { status: "nothing-to-move" };
51
+ await (0, node_fs_promises.mkdir)(localeDirAbs, { recursive: true });
52
+ for (const name of movedTopLevelNames) await (0, node_fs_promises.rename)((0, node_path.join)(routesDirAbs, name), (0, node_path.join)(localeDirAbs, name));
53
+ const movedFiles = await (0, fast_glob.default)(SCRIPT_GLOB, {
54
+ cwd: localeDirAbs,
55
+ absolute: true,
56
+ onlyFiles: true
57
+ });
58
+ const rewriteContext = {
59
+ appDirAbs: routesDirAbs,
60
+ localeDirAbs,
61
+ movedTopLevelNames
62
+ };
63
+ for (const newAbs of movedFiles) {
64
+ const oldAbs = (0, node_path.join)(routesDirAbs, (0, node_path.relative)(localeDirAbs, newAbs));
65
+ const code = await (0, node_fs_promises.readFile)(newAbs, "utf8");
66
+ const rewritten = require_init_frameworkSetup_nextAppRouter_restructure.rewriteRelativeImports(code, oldAbs, newAbs, rewriteContext);
67
+ if (rewritten !== code) await (0, node_fs_promises.writeFile)(newAbs, rewritten, "utf8");
68
+ }
69
+ return {
70
+ status: "moved",
71
+ movedEntries: movedTopLevelNames
72
+ };
73
+ };
74
+
75
+ //#endregion
76
+ exports.LOCALE_SEGMENT = LOCALE_SEGMENT;
77
+ exports.restructureRoutesIntoLocale = restructureRoutesIntoLocale;
78
+ exports.shouldKeepRouteAtRoot = shouldKeepRouteAtRoot;
79
+ //# sourceMappingURL=restructure.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restructure.cjs","names":["rewriteRelativeImports"],"sources":["../../../../../src/init/frameworkSetup/tanstackStart/restructure.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { mkdir, readdir, readFile, rename, writeFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport fg from 'fast-glob';\nimport { rewriteRelativeImports } from '../nextAppRouter/restructure';\n\n/** Source file extensions whose relative imports must be rewritten after a move. */\nconst SCRIPT_GLOB = '**/*.{ts,tsx,js,jsx,mjs,cjs}';\n\n/** The TanStack Router locale segment directory (optional `{-$locale}` param). */\nexport const LOCALE_SEGMENT = '{-$locale}';\n\n/** Strips a known script extension from a file name, e.g. `index.tsx` -> `index`. */\nconst stripScriptExtension = (fileName: string): string =>\n fileName.replace(/\\.(tsx|ts|jsx|js|mjs|cjs)$/, '');\n\n/**\n * Routes-directory entries that must stay at the root and never be moved under\n * `{-$locale}`:\n * - `__root` (the root route document),\n * - `routeTree.gen` (generated route tree),\n * - `api` (server / API routes — these are not locale-prefixed),\n * - TanStack-ignored entries prefixed with `-` (e.g. `-components`, `-utils`),\n * - stylesheets.\n *\n * Everything else (route files and nested route folders) is moved so it becomes\n * locale-aware.\n */\nexport const shouldKeepRouteAtRoot = (entryName: string): boolean => {\n if (entryName.startsWith('-')) return true;\n if (entryName.toLowerCase().endsWith('.css')) return true;\n\n const base = stripScriptExtension(entryName);\n const keepExactBases = new Set(['__root', 'routeTree.gen', 'api']);\n return keepExactBases.has(base);\n};\n\n/** Outcome of an attempted `{-$locale}` restructure. */\nexport type RestructureResult =\n | { status: 'already-structured' }\n | { status: 'nothing-to-move' }\n | { status: 'moved'; movedEntries: string[] };\n\n/**\n * Moves the routable entries of `routesDir` under a new `{-$locale}` segment and\n * rewrites relative imports in the moved files. Idempotent: a no-op when\n * `{-$locale}` already exists. Root-only files (see {@link shouldKeepRouteAtRoot})\n * are left in place.\n */\nexport const restructureRoutesIntoLocale = async (\n rootDir: string,\n routesDir: string\n): Promise<RestructureResult> => {\n const routesDirAbs = join(rootDir, routesDir);\n const localeDirAbs = join(routesDirAbs, LOCALE_SEGMENT);\n\n if (existsSync(localeDirAbs)) {\n return { status: 'already-structured' };\n }\n\n const entries = await readdir(routesDirAbs, { withFileTypes: true });\n const movedTopLevelNames = entries\n .map((entry) => entry.name)\n .filter((name) => !shouldKeepRouteAtRoot(name));\n\n if (movedTopLevelNames.length === 0) {\n return { status: 'nothing-to-move' };\n }\n\n await mkdir(localeDirAbs, { recursive: true });\n\n for (const name of movedTopLevelNames) {\n await rename(join(routesDirAbs, name), join(localeDirAbs, name));\n }\n\n const movedFiles = await fg(SCRIPT_GLOB, {\n cwd: localeDirAbs,\n absolute: true,\n onlyFiles: true,\n });\n\n const rewriteContext = {\n appDirAbs: routesDirAbs,\n localeDirAbs,\n movedTopLevelNames,\n };\n\n for (const newAbs of movedFiles) {\n const relFromLocale = relative(localeDirAbs, newAbs);\n const oldAbs = join(routesDirAbs, relFromLocale);\n const code = await readFile(newAbs, 'utf8');\n const rewritten = rewriteRelativeImports(\n code,\n oldAbs,\n newAbs,\n rewriteContext\n );\n if (rewritten !== code) {\n await writeFile(newAbs, rewritten, 'utf8');\n }\n }\n\n return { status: 'moved', movedEntries: movedTopLevelNames };\n};\n"],"mappings":";;;;;;;;;;;AAOA,MAAM,cAAc;;AAGpB,MAAa,iBAAiB;;AAG9B,MAAM,wBAAwB,aAC5B,SAAS,QAAQ,8BAA8B,GAAG;;;;;;;;;;;;;AAcpD,MAAa,yBAAyB,cAA+B;AACnE,KAAI,UAAU,WAAW,IAAI,CAAE,QAAO;AACtC,KAAI,UAAU,aAAa,CAAC,SAAS,OAAO,CAAE,QAAO;CAErD,MAAM,OAAO,qBAAqB,UAAU;AAE5C,QAAO,IADoB,IAAI;EAAC;EAAU;EAAiB;EAAM,CAC5C,CAAC,IAAI,KAAK;;;;;;;;AAejC,MAAa,8BAA8B,OACzC,SACA,cAC+B;CAC/B,MAAM,mCAAoB,SAAS,UAAU;CAC7C,MAAM,mCAAoB,cAAc,eAAe;AAEvD,6BAAe,aAAa,CAC1B,QAAO,EAAE,QAAQ,sBAAsB;CAIzC,MAAM,sBAAqB,oCADG,cAAc,EAAE,eAAe,MAAM,CAAC,EAEjE,KAAK,UAAU,MAAM,KAAK,CAC1B,QAAQ,SAAS,CAAC,sBAAsB,KAAK,CAAC;AAEjD,KAAI,mBAAmB,WAAW,EAChC,QAAO,EAAE,QAAQ,mBAAmB;AAGtC,mCAAY,cAAc,EAAE,WAAW,MAAM,CAAC;AAE9C,MAAK,MAAM,QAAQ,mBACjB,wDAAkB,cAAc,KAAK,sBAAO,cAAc,KAAK,CAAC;CAGlE,MAAM,aAAa,6BAAS,aAAa;EACvC,KAAK;EACL,UAAU;EACV,WAAW;EACZ,CAAC;CAEF,MAAM,iBAAiB;EACrB,WAAW;EACX;EACA;EACD;AAED,MAAK,MAAM,UAAU,YAAY;EAE/B,MAAM,6BAAc,sCADW,cAAc,OACE,CAAC;EAChD,MAAM,OAAO,qCAAe,QAAQ,OAAO;EAC3C,MAAM,YAAYA,6EAChB,MACA,QACA,QACA,eACD;AACD,MAAI,cAAc,KAChB,uCAAgB,QAAQ,WAAW,OAAO;;AAI9C,QAAO;EAAE,QAAQ;EAAS,cAAc;EAAoB"}
@@ -0,0 +1,104 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ //#region src/init/frameworkSetup/tanstackStart/templates.ts
4
+ /**
5
+ * File templates for a fresh TanStack Start integration. These are only written
6
+ * when the target file does not exist — they never overwrite user code.
7
+ */
8
+ /**
9
+ * Locale segment route (`routes/{-$locale}/route.tsx`). The optional `{-$locale}`
10
+ * param makes the default locale prefix-free; `validatePrefix` redirects unknown
11
+ * prefixes to a valid one. Identical for TypeScript and JavaScript projects.
12
+ */
13
+ const LOCALE_ROUTE_TEMPLATE = `import { createFileRoute, Outlet, redirect } from "@tanstack/react-router";
14
+ import { validatePrefix } from "intlayer";
15
+
16
+ export const Route = createFileRoute("/{-$locale}")({
17
+ beforeLoad: ({ params }) => {
18
+ // beforeLoad runs on both client and server, so resolve the locale from the
19
+ // route params rather than from request headers.
20
+ const { isValid, localePrefix } = validatePrefix(params.locale);
21
+
22
+ // A valid (or absent, i.e. default) locale prefix is fine as-is.
23
+ if (isValid) return;
24
+
25
+ // Otherwise redirect to the same route with a valid locale prefix.
26
+ throw redirect({
27
+ params: { locale: localePrefix },
28
+ to: "/{-$locale}",
29
+ });
30
+ },
31
+ component: Outlet,
32
+ });
33
+ `;
34
+ /**
35
+ * Root route document (`routes/__root.tsx`) providing `<html>` + the Intlayer
36
+ * provider, with the locale read from the `{-$locale}` route param.
37
+ */
38
+ const ROOT_TEMPLATE_TS = `import {
39
+ createRootRoute,
40
+ HeadContent,
41
+ Scripts,
42
+ useParams,
43
+ } from "@tanstack/react-router";
44
+ import { defaultLocale, getHTMLTextDir } from "intlayer";
45
+ import type { ReactNode } from "react";
46
+ import { IntlayerProvider } from "react-intlayer";
47
+
48
+ export const Route = createRootRoute({
49
+ shellComponent: RootDocument,
50
+ });
51
+
52
+ function RootDocument({ children }: { children: ReactNode }) {
53
+ const params = useParams({ strict: false });
54
+ const locale = params.locale ?? defaultLocale;
55
+
56
+ return (
57
+ <html dir={getHTMLTextDir(locale)} lang={locale}>
58
+ <head>
59
+ <HeadContent />
60
+ </head>
61
+ <body>
62
+ <IntlayerProvider locale={locale}>{children}</IntlayerProvider>
63
+ <Scripts />
64
+ </body>
65
+ </html>
66
+ );
67
+ }
68
+ `;
69
+ const ROOT_TEMPLATE_JS = `import {
70
+ createRootRoute,
71
+ HeadContent,
72
+ Scripts,
73
+ useParams,
74
+ } from "@tanstack/react-router";
75
+ import { defaultLocale, getHTMLTextDir } from "intlayer";
76
+ import { IntlayerProvider } from "react-intlayer";
77
+
78
+ export const Route = createRootRoute({
79
+ shellComponent: RootDocument,
80
+ });
81
+
82
+ function RootDocument({ children }) {
83
+ const params = useParams({ strict: false });
84
+ const locale = params.locale ?? defaultLocale;
85
+
86
+ return (
87
+ <html dir={getHTMLTextDir(locale)} lang={locale}>
88
+ <head>
89
+ <HeadContent />
90
+ </head>
91
+ <body>
92
+ <IntlayerProvider locale={locale}>{children}</IntlayerProvider>
93
+ <Scripts />
94
+ </body>
95
+ </html>
96
+ );
97
+ }
98
+ `;
99
+
100
+ //#endregion
101
+ exports.LOCALE_ROUTE_TEMPLATE = LOCALE_ROUTE_TEMPLATE;
102
+ exports.ROOT_TEMPLATE_JS = ROOT_TEMPLATE_JS;
103
+ exports.ROOT_TEMPLATE_TS = ROOT_TEMPLATE_TS;
104
+ //# sourceMappingURL=templates.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.cjs","names":[],"sources":["../../../../../src/init/frameworkSetup/tanstackStart/templates.ts"],"sourcesContent":["/**\n * File templates for a fresh TanStack Start integration. These are only written\n * when the target file does not exist — they never overwrite user code.\n */\n\n/**\n * Locale segment route (`routes/{-$locale}/route.tsx`). The optional `{-$locale}`\n * param makes the default locale prefix-free; `validatePrefix` redirects unknown\n * prefixes to a valid one. Identical for TypeScript and JavaScript projects.\n */\nexport const LOCALE_ROUTE_TEMPLATE = `import { createFileRoute, Outlet, redirect } from \"@tanstack/react-router\";\nimport { validatePrefix } from \"intlayer\";\n\nexport const Route = createFileRoute(\"/{-$locale}\")({\n beforeLoad: ({ params }) => {\n // beforeLoad runs on both client and server, so resolve the locale from the\n // route params rather than from request headers.\n const { isValid, localePrefix } = validatePrefix(params.locale);\n\n // A valid (or absent, i.e. default) locale prefix is fine as-is.\n if (isValid) return;\n\n // Otherwise redirect to the same route with a valid locale prefix.\n throw redirect({\n params: { locale: localePrefix },\n to: \"/{-$locale}\",\n });\n },\n component: Outlet,\n});\n`;\n\n/**\n * Root route document (`routes/__root.tsx`) providing `<html>` + the Intlayer\n * provider, with the locale read from the `{-$locale}` route param.\n */\nexport const ROOT_TEMPLATE_TS = `import {\n createRootRoute,\n HeadContent,\n Scripts,\n useParams,\n} from \"@tanstack/react-router\";\nimport { defaultLocale, getHTMLTextDir } from \"intlayer\";\nimport type { ReactNode } from \"react\";\nimport { IntlayerProvider } from \"react-intlayer\";\n\nexport const Route = createRootRoute({\n shellComponent: RootDocument,\n});\n\nfunction RootDocument({ children }: { children: ReactNode }) {\n const params = useParams({ strict: false });\n const locale = params.locale ?? defaultLocale;\n\n return (\n <html dir={getHTMLTextDir(locale)} lang={locale}>\n <head>\n <HeadContent />\n </head>\n <body>\n <IntlayerProvider locale={locale}>{children}</IntlayerProvider>\n <Scripts />\n </body>\n </html>\n );\n}\n`;\n\nexport const ROOT_TEMPLATE_JS = `import {\n createRootRoute,\n HeadContent,\n Scripts,\n useParams,\n} from \"@tanstack/react-router\";\nimport { defaultLocale, getHTMLTextDir } from \"intlayer\";\nimport { IntlayerProvider } from \"react-intlayer\";\n\nexport const Route = createRootRoute({\n shellComponent: RootDocument,\n});\n\nfunction RootDocument({ children }) {\n const params = useParams({ strict: false });\n const locale = params.locale ?? defaultLocale;\n\n return (\n <html dir={getHTMLTextDir(locale)} lang={locale}>\n <head>\n <HeadContent />\n </head>\n <body>\n <IntlayerProvider locale={locale}>{children}</IntlayerProvider>\n <Scripts />\n </body>\n </html>\n );\n}\n`;\n"],"mappings":";;;;;;;;;;;;AAUA,MAAa,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;AA0BrC,MAAa,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgChC,MAAa,mBAAmB"}