@intlayer/engine 9.5.9 → 9.5.10

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 (126) hide show
  1. package/dist/cjs/cli.cjs +7 -0
  2. package/dist/cjs/docReview/reviewReport.cjs.map +1 -1
  3. package/dist/cjs/init/cms.cjs +35 -0
  4. package/dist/cjs/init/cms.cjs.map +1 -1
  5. package/dist/cjs/init/documentationRouter.cjs +141 -0
  6. package/dist/cjs/init/documentationRouter.cjs.map +1 -0
  7. package/dist/cjs/init/frameworkSetup/backend/index.cjs +138 -0
  8. package/dist/cjs/init/frameworkSetup/backend/index.cjs.map +1 -0
  9. package/dist/cjs/init/frameworkSetup/backend/transforms.cjs +223 -0
  10. package/dist/cjs/init/frameworkSetup/backend/transforms.cjs.map +1 -0
  11. package/dist/cjs/init/frameworkSetup/index.cjs +9 -3
  12. package/dist/cjs/init/frameworkSetup/index.cjs.map +1 -1
  13. package/dist/cjs/init/frameworkSetup/localeRouting.cjs +13 -0
  14. package/dist/cjs/init/frameworkSetup/localeRouting.cjs.map +1 -0
  15. package/dist/cjs/init/frameworkSetup/nextAppRouter/index.cjs +34 -7
  16. package/dist/cjs/init/frameworkSetup/nextAppRouter/index.cjs.map +1 -1
  17. package/dist/cjs/init/frameworkSetup/nextAppRouter/templates.cjs +56 -0
  18. package/dist/cjs/init/frameworkSetup/nextAppRouter/templates.cjs.map +1 -1
  19. package/dist/cjs/init/frameworkSetup/nextAppRouter/transforms.cjs +2 -2
  20. package/dist/cjs/init/frameworkSetup/nextAppRouter/transforms.cjs.map +1 -1
  21. package/dist/cjs/init/frameworkSetup/tanstackStart/index.cjs +32 -3
  22. package/dist/cjs/init/frameworkSetup/tanstackStart/index.cjs.map +1 -1
  23. package/dist/cjs/init/frameworkSetup/tanstackStart/templates.cjs +58 -0
  24. package/dist/cjs/init/frameworkSetup/tanstackStart/templates.cjs.map +1 -1
  25. package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs +94 -14
  26. package/dist/cjs/init/frameworkSetup/tanstackStart/transforms.cjs.map +1 -1
  27. package/dist/cjs/init/index.cjs +46 -159
  28. package/dist/cjs/init/index.cjs.map +1 -1
  29. package/dist/cjs/init/utils/configManipulation.cjs +39 -0
  30. package/dist/cjs/init/utils/configManipulation.cjs.map +1 -1
  31. package/dist/cjs/init/utils/index.cjs +10 -0
  32. package/dist/cjs/init/utils/lintConfig.cjs +52 -0
  33. package/dist/cjs/init/utils/lintConfig.cjs.map +1 -0
  34. package/dist/cjs/init/utils/packageManager.cjs +62 -13
  35. package/dist/cjs/init/utils/packageManager.cjs.map +1 -1
  36. package/dist/cjs/init/utils/urlRoutingFramework.cjs +41 -0
  37. package/dist/cjs/init/utils/urlRoutingFramework.cjs.map +1 -0
  38. package/dist/cjs/initConfig/index.cjs +4 -1
  39. package/dist/cjs/initConfig/index.cjs.map +1 -1
  40. package/dist/cjs/loadDictionaries/logTypeScriptErrors.cjs +104 -43
  41. package/dist/cjs/loadDictionaries/logTypeScriptErrors.cjs.map +1 -1
  42. package/dist/esm/cli.mjs +5 -3
  43. package/dist/esm/docReview/reviewReport.mjs.map +1 -1
  44. package/dist/esm/init/cms.mjs +35 -2
  45. package/dist/esm/init/cms.mjs.map +1 -1
  46. package/dist/esm/init/documentationRouter.mjs +139 -0
  47. package/dist/esm/init/documentationRouter.mjs.map +1 -0
  48. package/dist/esm/init/frameworkSetup/backend/index.mjs +130 -0
  49. package/dist/esm/init/frameworkSetup/backend/index.mjs.map +1 -0
  50. package/dist/esm/init/frameworkSetup/backend/transforms.mjs +216 -0
  51. package/dist/esm/init/frameworkSetup/backend/transforms.mjs.map +1 -0
  52. package/dist/esm/init/frameworkSetup/index.mjs +9 -3
  53. package/dist/esm/init/frameworkSetup/index.mjs.map +1 -1
  54. package/dist/esm/init/frameworkSetup/localeRouting.mjs +12 -0
  55. package/dist/esm/init/frameworkSetup/localeRouting.mjs.map +1 -0
  56. package/dist/esm/init/frameworkSetup/nextAppRouter/index.mjs +36 -9
  57. package/dist/esm/init/frameworkSetup/nextAppRouter/index.mjs.map +1 -1
  58. package/dist/esm/init/frameworkSetup/nextAppRouter/templates.mjs +54 -1
  59. package/dist/esm/init/frameworkSetup/nextAppRouter/templates.mjs.map +1 -1
  60. package/dist/esm/init/frameworkSetup/nextAppRouter/transforms.mjs +2 -2
  61. package/dist/esm/init/frameworkSetup/nextAppRouter/transforms.mjs.map +1 -1
  62. package/dist/esm/init/frameworkSetup/tanstackStart/index.mjs +35 -6
  63. package/dist/esm/init/frameworkSetup/tanstackStart/index.mjs.map +1 -1
  64. package/dist/esm/init/frameworkSetup/tanstackStart/templates.mjs +56 -1
  65. package/dist/esm/init/frameworkSetup/tanstackStart/templates.mjs.map +1 -1
  66. package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs +94 -15
  67. package/dist/esm/init/frameworkSetup/tanstackStart/transforms.mjs.map +1 -1
  68. package/dist/esm/init/index.mjs +42 -158
  69. package/dist/esm/init/index.mjs.map +1 -1
  70. package/dist/esm/init/utils/configManipulation.mjs +38 -1
  71. package/dist/esm/init/utils/configManipulation.mjs.map +1 -1
  72. package/dist/esm/init/utils/index.mjs +5 -3
  73. package/dist/esm/init/utils/lintConfig.mjs +50 -0
  74. package/dist/esm/init/utils/lintConfig.mjs.map +1 -0
  75. package/dist/esm/init/utils/packageManager.mjs +60 -14
  76. package/dist/esm/init/utils/packageManager.mjs.map +1 -1
  77. package/dist/esm/init/utils/urlRoutingFramework.mjs +40 -0
  78. package/dist/esm/init/utils/urlRoutingFramework.mjs.map +1 -0
  79. package/dist/esm/initConfig/index.mjs +4 -1
  80. package/dist/esm/initConfig/index.mjs.map +1 -1
  81. package/dist/esm/loadDictionaries/logTypeScriptErrors.mjs +105 -44
  82. package/dist/esm/loadDictionaries/logTypeScriptErrors.mjs.map +1 -1
  83. package/dist/types/cli.d.ts +5 -3
  84. package/dist/types/docReview/reviewReport.d.ts.map +1 -1
  85. package/dist/types/formatDictionary.d.ts +2 -2
  86. package/dist/types/init/cms.d.ts +11 -0
  87. package/dist/types/init/cms.d.ts.map +1 -1
  88. package/dist/types/init/documentationRouter.d.ts +64 -0
  89. package/dist/types/init/documentationRouter.d.ts.map +1 -0
  90. package/dist/types/init/frameworkSetup/backend/index.d.ts +16 -0
  91. package/dist/types/init/frameworkSetup/backend/index.d.ts.map +1 -0
  92. package/dist/types/init/frameworkSetup/backend/transforms.d.ts +37 -0
  93. package/dist/types/init/frameworkSetup/backend/transforms.d.ts.map +1 -0
  94. package/dist/types/init/frameworkSetup/index.d.ts.map +1 -1
  95. package/dist/types/init/frameworkSetup/localeRouting.d.ts +11 -0
  96. package/dist/types/init/frameworkSetup/localeRouting.d.ts.map +1 -0
  97. package/dist/types/init/frameworkSetup/nextAppRouter/index.d.ts +5 -5
  98. package/dist/types/init/frameworkSetup/nextAppRouter/index.d.ts.map +1 -1
  99. package/dist/types/init/frameworkSetup/nextAppRouter/templates.d.ts +12 -0
  100. package/dist/types/init/frameworkSetup/nextAppRouter/templates.d.ts.map +1 -1
  101. package/dist/types/init/frameworkSetup/nextAppRouter/transforms.d.ts +10 -1
  102. package/dist/types/init/frameworkSetup/nextAppRouter/transforms.d.ts.map +1 -1
  103. package/dist/types/init/frameworkSetup/tanstackStart/index.d.ts +3 -2
  104. package/dist/types/init/frameworkSetup/tanstackStart/index.d.ts.map +1 -1
  105. package/dist/types/init/frameworkSetup/tanstackStart/templates.d.ts +10 -0
  106. package/dist/types/init/frameworkSetup/tanstackStart/templates.d.ts.map +1 -1
  107. package/dist/types/init/frameworkSetup/tanstackStart/transforms.d.ts +12 -0
  108. package/dist/types/init/frameworkSetup/tanstackStart/transforms.d.ts.map +1 -1
  109. package/dist/types/init/frameworkSetup/types.d.ts +6 -0
  110. package/dist/types/init/frameworkSetup/types.d.ts.map +1 -1
  111. package/dist/types/init/index.d.ts +15 -1
  112. package/dist/types/init/index.d.ts.map +1 -1
  113. package/dist/types/init/utils/configManipulation.d.ts +14 -0
  114. package/dist/types/init/utils/configManipulation.d.ts.map +1 -1
  115. package/dist/types/init/utils/index.d.ts +5 -3
  116. package/dist/types/init/utils/lintConfig.d.ts +28 -0
  117. package/dist/types/init/utils/lintConfig.d.ts.map +1 -0
  118. package/dist/types/init/utils/packageManager.d.ts +29 -6
  119. package/dist/types/init/utils/packageManager.d.ts.map +1 -1
  120. package/dist/types/init/utils/urlRoutingFramework.d.ts +9 -0
  121. package/dist/types/init/utils/urlRoutingFramework.d.ts.map +1 -0
  122. package/dist/types/initConfig/index.d.ts +3 -1
  123. package/dist/types/initConfig/index.d.ts.map +1 -1
  124. package/dist/types/loadDictionaries/logTypeScriptErrors.d.ts +4 -0
  125. package/dist/types/loadDictionaries/logTypeScriptErrors.d.ts.map +1 -1
  126. package/package.json +8 -8
@@ -0,0 +1,223 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_runtime = require('../../../_virtual/_rolldown/runtime.cjs');
3
+ const require_utils_babelParser = require('../../../utils/babelParser.cjs');
4
+ const require_init_utils_astImports = require('../../utils/astImports.cjs');
5
+ let recast = require("recast");
6
+ recast = require_runtime.__toESM(recast);
7
+
8
+ //#region src/init/frameworkSetup/backend/transforms.ts
9
+ const { namedTypes: n } = recast.types;
10
+ /** Local name the injected middleware / plugin factory is bound to. */
11
+ const MIDDLEWARE_IDENTIFIER = "intlayer";
12
+ /** babel-ts parser handles TypeScript *and* plain JavaScript. */
13
+ const parseCode = (code) => recast.parse(code, { parser: require_utils_babelParser.babelTsParser });
14
+ /** Parses a single statement. */
15
+ const parseStatement = (code) => parseCode(code).program.body[0];
16
+ /** Whether `node` is a `require("<source>")` call. */
17
+ const isRequireOf = (node, source) => node?.type === "CallExpression" && node.callee?.type === "Identifier" && node.callee.name === "require" && node.arguments[0]?.value === source;
18
+ /**
19
+ * Resolves the local names a factory is bound to at module scope, from ESM
20
+ * imports (`import express from "express"`, `import { Hono } from "hono"`) or
21
+ * CommonJS requires (`const express = require("express")`,
22
+ * `const { Hono } = require("hono")`).
23
+ */
24
+ const findFactoryLocalNames = (ast, factory) => {
25
+ const localNames = [];
26
+ const acceptsNamed = (name) => factory.named?.includes(name) ?? false;
27
+ for (const statement of ast.program.body) {
28
+ if (statement.type === "ImportDeclaration" && statement.source.value === factory.source) for (const specifier of statement.specifiers) {
29
+ const isAcceptedDefault = specifier.type === "ImportDefaultSpecifier" && factory.default;
30
+ const isAcceptedNamed = specifier.type === "ImportSpecifier" && acceptsNamed(specifier.imported.name);
31
+ if (isAcceptedDefault || isAcceptedNamed) localNames.push(specifier.local.name);
32
+ }
33
+ if (statement.type !== "VariableDeclaration") continue;
34
+ for (const declarator of statement.declarations) {
35
+ if (!isRequireOf(declarator.init, factory.source)) continue;
36
+ if (declarator.id.type === "Identifier" && factory.default) localNames.push(declarator.id.name);
37
+ if (declarator.id.type === "ObjectPattern") {
38
+ for (const property of declarator.id.properties) if (property.key?.type === "Identifier" && property.value?.type === "Identifier" && acceptsNamed(property.key.name)) localNames.push(property.value.name);
39
+ }
40
+ }
41
+ }
42
+ return localNames;
43
+ };
44
+ /** Whether the module uses CommonJS (`require`) rather than ESM imports. */
45
+ const isCommonJsModule = (ast) => !ast.program.body.some((statement) => statement.type === "ImportDeclaration" || statement.type === "ExportNamedDeclaration" || statement.type === "ExportDefaultDeclaration") && ast.program.body.some((statement) => statement.type === "VariableDeclaration" && statement.declarations.some((declarator) => declarator.init?.type === "CallExpression" && declarator.init.callee?.name === "require"));
46
+ /**
47
+ * Binds `intlayer` from `source`: an ESM named import, or — in a CommonJS
48
+ * module — `const { intlayer } = require("<source>");` placed after the last
49
+ * top-level `require`.
50
+ */
51
+ const ensureMiddlewareBinding = (ast, source) => {
52
+ if (!isCommonJsModule(ast)) {
53
+ require_init_utils_astImports.ensureNamedImport(ast, MIDDLEWARE_IDENTIFIER, source);
54
+ return;
55
+ }
56
+ const body = ast.program.body;
57
+ let insertIndex = 0;
58
+ body.forEach((statement, index) => {
59
+ if (statement.type === "VariableDeclaration" && statement.declarations.some((declarator) => declarator.init?.callee?.name === "require")) insertIndex = index + 1;
60
+ });
61
+ body.splice(insertIndex, 0, parseStatement(`const { ${MIDDLEWARE_IDENTIFIER} } = require("${source}");`));
62
+ };
63
+ /**
64
+ * Finds the first `const <app> = <init>` whose initializer matches, returning
65
+ * the app identifier and the statement path to insert after. `export const`
66
+ * declarations resolve to the export statement.
67
+ */
68
+ const findAppDeclaration = (ast, matchesInit) => {
69
+ let found = null;
70
+ recast.visit(ast, { visitVariableDeclarator(path) {
71
+ const { id, init } = path.node;
72
+ if (!found && id.type === "Identifier" && init && matchesInit(init)) {
73
+ let statementPath = path.parent;
74
+ if (statementPath.parent?.node.type === "ExportNamedDeclaration") statementPath = statementPath.parent;
75
+ found = {
76
+ appName: id.name,
77
+ statementPath
78
+ };
79
+ return false;
80
+ }
81
+ this.traverse(path);
82
+ } });
83
+ return found;
84
+ };
85
+ /** Whether `node` calls one of `calleeNames` directly (`express()`, `new Hono()`). */
86
+ const isFactoryCall = (node, calleeNames, type) => node?.type === type && node.callee?.type === "Identifier" && calleeNames.includes(node.callee.name);
87
+ /**
88
+ * Shared flow of the "declare the app, then register the middleware on the
89
+ * next line" frameworks (Express, Fastify, Hono, NestJS).
90
+ */
91
+ const registerAfterAppDeclaration = (code, { middlewareSource, findDeclaration, buildRegistration }) => {
92
+ if (code.includes(middlewareSource)) return {
93
+ code,
94
+ status: "already"
95
+ };
96
+ const ast = parseCode(code);
97
+ if (require_init_utils_astImports.isModuleScopeBinding(ast, MIDDLEWARE_IDENTIFIER)) return {
98
+ code,
99
+ status: "skipped"
100
+ };
101
+ const declaration = findDeclaration(ast);
102
+ if (!declaration) return {
103
+ code,
104
+ status: "skipped"
105
+ };
106
+ declaration.statementPath.insertAfter(parseStatement(buildRegistration(declaration.appName)));
107
+ ensureMiddlewareBinding(ast, middlewareSource);
108
+ return {
109
+ code: recast.print(ast).code,
110
+ status: "registered"
111
+ };
112
+ };
113
+ /**
114
+ * Registers `express-intlayer` right after `const app = express()`:
115
+ * `app.use(intlayer());`.
116
+ */
117
+ const registerExpressMiddleware = (code) => registerAfterAppDeclaration(code, {
118
+ middlewareSource: "express-intlayer",
119
+ findDeclaration: (ast) => {
120
+ const factoryNames = findFactoryLocalNames(ast, {
121
+ source: "express",
122
+ default: true
123
+ });
124
+ return findAppDeclaration(ast, (init) => isFactoryCall(init, factoryNames, "CallExpression"));
125
+ },
126
+ buildRegistration: (appName) => `${appName}.use(intlayer());`
127
+ });
128
+ /**
129
+ * Registers `fastify-intlayer` right after `const app = Fastify()`:
130
+ * `app.register(intlayer);`. Not awaited, so it also works in CommonJS and
131
+ * non-async scopes — Fastify queues plugins until `ready`/`listen`.
132
+ */
133
+ const registerFastifyPlugin = (code) => registerAfterAppDeclaration(code, {
134
+ middlewareSource: "fastify-intlayer",
135
+ findDeclaration: (ast) => {
136
+ const factoryNames = findFactoryLocalNames(ast, {
137
+ source: "fastify",
138
+ default: true,
139
+ named: ["fastify", "Fastify"]
140
+ });
141
+ return findAppDeclaration(ast, (init) => isFactoryCall(init, factoryNames, "CallExpression"));
142
+ },
143
+ buildRegistration: (appName) => `${appName}.register(intlayer);`
144
+ });
145
+ /**
146
+ * Registers `hono-intlayer` right after `const app = new Hono()`:
147
+ * `app.use("*", intlayer());`. A chained declaration
148
+ * (`new Hono().get(…)`) is skipped: its routes would be registered before the
149
+ * middleware, which Hono runs in registration order.
150
+ */
151
+ const registerHonoMiddleware = (code) => registerAfterAppDeclaration(code, {
152
+ middlewareSource: "hono-intlayer",
153
+ findDeclaration: (ast) => {
154
+ const factoryNames = findFactoryLocalNames(ast, {
155
+ source: "hono",
156
+ named: ["Hono"]
157
+ });
158
+ return findAppDeclaration(ast, (init) => isFactoryCall(init, factoryNames, "NewExpression"));
159
+ },
160
+ buildRegistration: (appName) => `${appName}.use("*", intlayer());`
161
+ });
162
+ /**
163
+ * Registers `express-intlayer` on a NestJS (Express platform) app right after
164
+ * `const app = await NestFactory.create(…)`: `app.use(intlayer());`.
165
+ */
166
+ const registerNestJsMiddleware = (code) => registerAfterAppDeclaration(code, {
167
+ middlewareSource: "express-intlayer",
168
+ findDeclaration: (ast) => findAppDeclaration(ast, (init) => {
169
+ const call = init.type === "AwaitExpression" ? init.argument : init;
170
+ return n.CallExpression.check(call) && n.MemberExpression.check(call.callee) && call.callee.object.name === "NestFactory" && call.callee.property.name === "create";
171
+ }),
172
+ buildRegistration: (appName) => `${appName}.use(intlayer());`
173
+ });
174
+ /**
175
+ * Registers `elysia-intlayer` directly on the app constructor:
176
+ * `new Elysia()` → `new Elysia().use(intlayer())`. Works for chained
177
+ * declarations too, and keeps the plugin ahead of every route.
178
+ */
179
+ const registerElysiaPlugin = (code) => {
180
+ const middlewareSource = "elysia-intlayer";
181
+ if (code.includes(middlewareSource)) return {
182
+ code,
183
+ status: "already"
184
+ };
185
+ const ast = parseCode(code);
186
+ if (require_init_utils_astImports.isModuleScopeBinding(ast, MIDDLEWARE_IDENTIFIER)) return {
187
+ code,
188
+ status: "skipped"
189
+ };
190
+ const factoryNames = findFactoryLocalNames(ast, {
191
+ source: "elysia",
192
+ named: ["Elysia"]
193
+ });
194
+ let registered = false;
195
+ recast.visit(ast, { visitNewExpression(path) {
196
+ if (registered) return false;
197
+ if (isFactoryCall(path.node, factoryNames, "NewExpression")) {
198
+ const withPlugin = parseStatement("__app__.use(intlayer());").expression;
199
+ withPlugin.callee.object = path.node;
200
+ path.replace(withPlugin);
201
+ registered = true;
202
+ return false;
203
+ }
204
+ this.traverse(path);
205
+ } });
206
+ if (!registered) return {
207
+ code,
208
+ status: "skipped"
209
+ };
210
+ ensureMiddlewareBinding(ast, middlewareSource);
211
+ return {
212
+ code: recast.print(ast).code,
213
+ status: "registered"
214
+ };
215
+ };
216
+
217
+ //#endregion
218
+ exports.registerElysiaPlugin = registerElysiaPlugin;
219
+ exports.registerExpressMiddleware = registerExpressMiddleware;
220
+ exports.registerFastifyPlugin = registerFastifyPlugin;
221
+ exports.registerHonoMiddleware = registerHonoMiddleware;
222
+ exports.registerNestJsMiddleware = registerNestJsMiddleware;
223
+ //# sourceMappingURL=transforms.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transforms.cjs","names":["babelTsParser","isModuleScopeBinding"],"sources":["../../../../../src/init/frameworkSetup/backend/transforms.ts"],"sourcesContent":["import * as recast from 'recast';\nimport { babelTsParser } from '../../../utils/babelParser';\nimport {\n ensureNamedImport,\n isModuleScopeBinding,\n} from '../../utils/astImports';\n\nconst { namedTypes: n } = recast.types;\n\n/** Local name the injected middleware / plugin factory is bound to. */\nconst MIDDLEWARE_IDENTIFIER = 'intlayer';\n\n/** babel-ts parser handles TypeScript *and* plain JavaScript. */\nconst parseCode = (code: string): any =>\n recast.parse(code, { parser: babelTsParser });\n\n/** Parses a single statement. */\nconst parseStatement = (code: string): any => parseCode(code).program.body[0];\n\n/** Result of a backend transform. `code` is unchanged for any non-`registered` status. */\nexport type BackendTransformResult = {\n code: string;\n status: 'registered' | 'already' | 'skipped';\n};\n\n/** How a server framework exposes its app factory. */\ntype FactoryImport = {\n /** Module the factory is imported from, e.g. `express`. */\n source: string;\n /** Accepted forms: the default export, and/or these named exports. */\n default?: boolean;\n named?: string[];\n};\n\n/** Whether `node` is a `require(\"<source>\")` call. */\nconst isRequireOf = (node: any, source: string): boolean =>\n node?.type === 'CallExpression' &&\n node.callee?.type === 'Identifier' &&\n node.callee.name === 'require' &&\n node.arguments[0]?.value === source;\n\n/**\n * Resolves the local names a factory is bound to at module scope, from ESM\n * imports (`import express from \"express\"`, `import { Hono } from \"hono\"`) or\n * CommonJS requires (`const express = require(\"express\")`,\n * `const { Hono } = require(\"hono\")`).\n */\nconst findFactoryLocalNames = (ast: any, factory: FactoryImport): string[] => {\n const localNames: string[] = [];\n const acceptsNamed = (name: string): boolean =>\n factory.named?.includes(name) ?? false;\n\n for (const statement of ast.program.body) {\n if (\n statement.type === 'ImportDeclaration' &&\n statement.source.value === factory.source\n ) {\n for (const specifier of statement.specifiers) {\n const isAcceptedDefault =\n specifier.type === 'ImportDefaultSpecifier' && factory.default;\n const isAcceptedNamed =\n specifier.type === 'ImportSpecifier' &&\n acceptsNamed(specifier.imported.name);\n if (isAcceptedDefault || isAcceptedNamed) {\n localNames.push(specifier.local.name);\n }\n }\n }\n\n if (statement.type !== 'VariableDeclaration') continue;\n\n for (const declarator of statement.declarations) {\n if (!isRequireOf(declarator.init, factory.source)) continue;\n\n if (declarator.id.type === 'Identifier' && factory.default) {\n localNames.push(declarator.id.name);\n }\n if (declarator.id.type === 'ObjectPattern') {\n for (const property of declarator.id.properties) {\n if (\n property.key?.type === 'Identifier' &&\n property.value?.type === 'Identifier' &&\n acceptsNamed(property.key.name)\n ) {\n localNames.push(property.value.name);\n }\n }\n }\n }\n }\n\n return localNames;\n};\n\n/** Whether the module uses CommonJS (`require`) rather than ESM imports. */\nconst isCommonJsModule = (ast: any): boolean =>\n !ast.program.body.some(\n (statement: any) =>\n statement.type === 'ImportDeclaration' ||\n statement.type === 'ExportNamedDeclaration' ||\n statement.type === 'ExportDefaultDeclaration'\n ) &&\n ast.program.body.some(\n (statement: any) =>\n statement.type === 'VariableDeclaration' &&\n statement.declarations.some(\n (declarator: any) =>\n declarator.init?.type === 'CallExpression' &&\n declarator.init.callee?.name === 'require'\n )\n );\n\n/**\n * Binds `intlayer` from `source`: an ESM named import, or — in a CommonJS\n * module — `const { intlayer } = require(\"<source>\");` placed after the last\n * top-level `require`.\n */\nconst ensureMiddlewareBinding = (ast: any, source: string): void => {\n if (!isCommonJsModule(ast)) {\n ensureNamedImport(ast, MIDDLEWARE_IDENTIFIER, source);\n return;\n }\n\n const body = ast.program.body;\n let insertIndex = 0;\n body.forEach((statement: any, index: number) => {\n const isRequireDeclaration =\n statement.type === 'VariableDeclaration' &&\n statement.declarations.some(\n (declarator: any) => declarator.init?.callee?.name === 'require'\n );\n if (isRequireDeclaration) insertIndex = index + 1;\n });\n\n body.splice(\n insertIndex,\n 0,\n parseStatement(`const { ${MIDDLEWARE_IDENTIFIER} } = require(\"${source}\");`)\n );\n};\n\n/**\n * Finds the first `const <app> = <init>` whose initializer matches, returning\n * the app identifier and the statement path to insert after. `export const`\n * declarations resolve to the export statement.\n */\nconst findAppDeclaration = (\n ast: any,\n matchesInit: (init: any) => boolean\n): { appName: string; statementPath: any } | null => {\n let found: { appName: string; statementPath: any } | null = null;\n\n recast.visit(ast, {\n visitVariableDeclarator(path) {\n const { id, init } = path.node as any;\n if (!found && id.type === 'Identifier' && init && matchesInit(init)) {\n let statementPath = path.parent;\n if (statementPath.parent?.node.type === 'ExportNamedDeclaration') {\n statementPath = statementPath.parent;\n }\n found = { appName: id.name, statementPath };\n return false;\n }\n this.traverse(path);\n },\n });\n\n return found;\n};\n\n/** Whether `node` calls one of `calleeNames` directly (`express()`, `new Hono()`). */\nconst isFactoryCall = (\n node: any,\n calleeNames: string[],\n type: 'CallExpression' | 'NewExpression'\n): boolean =>\n node?.type === type &&\n node.callee?.type === 'Identifier' &&\n calleeNames.includes(node.callee.name);\n\n/**\n * Shared flow of the \"declare the app, then register the middleware on the\n * next line\" frameworks (Express, Fastify, Hono, NestJS).\n */\nconst registerAfterAppDeclaration = (\n code: string,\n {\n middlewareSource,\n findDeclaration,\n buildRegistration,\n }: {\n middlewareSource: string;\n findDeclaration: (ast: any) => ReturnType<typeof findAppDeclaration>;\n buildRegistration: (appName: string) => string;\n }\n): BackendTransformResult => {\n if (code.includes(middlewareSource)) return { code, status: 'already' };\n\n const ast = parseCode(code);\n if (isModuleScopeBinding(ast, MIDDLEWARE_IDENTIFIER)) {\n return { code, status: 'skipped' };\n }\n\n const declaration = findDeclaration(ast);\n if (!declaration) return { code, status: 'skipped' };\n\n declaration.statementPath.insertAfter(\n parseStatement(buildRegistration(declaration.appName))\n );\n ensureMiddlewareBinding(ast, middlewareSource);\n\n return { code: recast.print(ast).code, status: 'registered' };\n};\n\n/**\n * Registers `express-intlayer` right after `const app = express()`:\n * `app.use(intlayer());`.\n */\nexport const registerExpressMiddleware = (\n code: string\n): BackendTransformResult =>\n registerAfterAppDeclaration(code, {\n middlewareSource: 'express-intlayer',\n findDeclaration: (ast) => {\n const factoryNames = findFactoryLocalNames(ast, {\n source: 'express',\n default: true,\n });\n return findAppDeclaration(ast, (init) =>\n isFactoryCall(init, factoryNames, 'CallExpression')\n );\n },\n buildRegistration: (appName) => `${appName}.use(intlayer());`,\n });\n\n/**\n * Registers `fastify-intlayer` right after `const app = Fastify()`:\n * `app.register(intlayer);`. Not awaited, so it also works in CommonJS and\n * non-async scopes — Fastify queues plugins until `ready`/`listen`.\n */\nexport const registerFastifyPlugin = (code: string): BackendTransformResult =>\n registerAfterAppDeclaration(code, {\n middlewareSource: 'fastify-intlayer',\n findDeclaration: (ast) => {\n const factoryNames = findFactoryLocalNames(ast, {\n source: 'fastify',\n default: true,\n named: ['fastify', 'Fastify'],\n });\n return findAppDeclaration(ast, (init) =>\n isFactoryCall(init, factoryNames, 'CallExpression')\n );\n },\n buildRegistration: (appName) => `${appName}.register(intlayer);`,\n });\n\n/**\n * Registers `hono-intlayer` right after `const app = new Hono()`:\n * `app.use(\"*\", intlayer());`. A chained declaration\n * (`new Hono().get(…)`) is skipped: its routes would be registered before the\n * middleware, which Hono runs in registration order.\n */\nexport const registerHonoMiddleware = (code: string): BackendTransformResult =>\n registerAfterAppDeclaration(code, {\n middlewareSource: 'hono-intlayer',\n findDeclaration: (ast) => {\n const factoryNames = findFactoryLocalNames(ast, {\n source: 'hono',\n named: ['Hono'],\n });\n return findAppDeclaration(ast, (init) =>\n isFactoryCall(init, factoryNames, 'NewExpression')\n );\n },\n buildRegistration: (appName) => `${appName}.use(\"*\", intlayer());`,\n });\n\n/**\n * Registers `express-intlayer` on a NestJS (Express platform) app right after\n * `const app = await NestFactory.create(…)`: `app.use(intlayer());`.\n */\nexport const registerNestJsMiddleware = (\n code: string\n): BackendTransformResult =>\n registerAfterAppDeclaration(code, {\n middlewareSource: 'express-intlayer',\n findDeclaration: (ast) =>\n findAppDeclaration(ast, (init) => {\n const call = init.type === 'AwaitExpression' ? init.argument : init;\n return (\n n.CallExpression.check(call) &&\n n.MemberExpression.check(call.callee) &&\n (call.callee.object as any).name === 'NestFactory' &&\n (call.callee.property as any).name === 'create'\n );\n }),\n buildRegistration: (appName) => `${appName}.use(intlayer());`,\n });\n\n/**\n * Registers `elysia-intlayer` directly on the app constructor:\n * `new Elysia()` → `new Elysia().use(intlayer())`. Works for chained\n * declarations too, and keeps the plugin ahead of every route.\n */\nexport const registerElysiaPlugin = (code: string): BackendTransformResult => {\n const middlewareSource = 'elysia-intlayer';\n if (code.includes(middlewareSource)) return { code, status: 'already' };\n\n const ast = parseCode(code);\n if (isModuleScopeBinding(ast, MIDDLEWARE_IDENTIFIER)) {\n return { code, status: 'skipped' };\n }\n\n const factoryNames = findFactoryLocalNames(ast, {\n source: 'elysia',\n named: ['Elysia'],\n });\n\n let registered = false;\n recast.visit(ast, {\n visitNewExpression(path) {\n if (registered) return false;\n if (isFactoryCall(path.node, factoryNames, 'NewExpression')) {\n const withPlugin = parseStatement(\n '__app__.use(intlayer());'\n ).expression;\n withPlugin.callee.object = path.node;\n path.replace(withPlugin);\n registered = true;\n return false;\n }\n this.traverse(path);\n },\n });\n\n if (!registered) return { code, status: 'skipped' };\n\n ensureMiddlewareBinding(ast, middlewareSource);\n\n return { code: recast.print(ast).code, status: 'registered' };\n};\n"],"mappings":";;;;;;;;AAOA,MAAM,EAAE,YAAY,MAAM,OAAO;;AAGjC,MAAM,wBAAwB;;AAG9B,MAAM,aAAa,SACjB,OAAO,MAAM,MAAM,EAAE,QAAQA,wCAAc,CAAC;;AAG9C,MAAM,kBAAkB,SAAsB,UAAU,IAAI,CAAC,CAAC,QAAQ,KAAK;;AAkB3E,MAAM,eAAe,MAAW,WAC9B,MAAM,SAAS,oBACf,KAAK,QAAQ,SAAS,gBACtB,KAAK,OAAO,SAAS,aACrB,KAAK,UAAU,EAAE,EAAE,UAAU;;;;;;;AAQ/B,MAAM,yBAAyB,KAAU,YAAqC;CAC5E,MAAM,aAAuB,CAAC;CAC9B,MAAM,gBAAgB,SACpB,QAAQ,OAAO,SAAS,IAAI,KAAK;CAEnC,KAAK,MAAM,aAAa,IAAI,QAAQ,MAAM;EACxC,IACE,UAAU,SAAS,uBACnB,UAAU,OAAO,UAAU,QAAQ,QAEnC,KAAK,MAAM,aAAa,UAAU,YAAY;GAC5C,MAAM,oBACJ,UAAU,SAAS,4BAA4B,QAAQ;GACzD,MAAM,kBACJ,UAAU,SAAS,qBACnB,aAAa,UAAU,SAAS,IAAI;GACtC,IAAI,qBAAqB,iBACvB,WAAW,KAAK,UAAU,MAAM,IAAI;EAExC;EAGF,IAAI,UAAU,SAAS,uBAAuB;EAE9C,KAAK,MAAM,cAAc,UAAU,cAAc;GAC/C,IAAI,CAAC,YAAY,WAAW,MAAM,QAAQ,MAAM,GAAG;GAEnD,IAAI,WAAW,GAAG,SAAS,gBAAgB,QAAQ,SACjD,WAAW,KAAK,WAAW,GAAG,IAAI;GAEpC,IAAI,WAAW,GAAG,SAAS,iBACzB;SAAK,MAAM,YAAY,WAAW,GAAG,YACnC,IACE,SAAS,KAAK,SAAS,gBACvB,SAAS,OAAO,SAAS,gBACzB,aAAa,SAAS,IAAI,IAAI,GAE9B,WAAW,KAAK,SAAS,MAAM,IAAI;GAEvC;EAEJ;CACF;CAEA,OAAO;AACT;;AAGA,MAAM,oBAAoB,QACxB,CAAC,IAAI,QAAQ,KAAK,MACf,cACC,UAAU,SAAS,uBACnB,UAAU,SAAS,4BACnB,UAAU,SAAS,0BACvB,KACA,IAAI,QAAQ,KAAK,MACd,cACC,UAAU,SAAS,yBACnB,UAAU,aAAa,MACpB,eACC,WAAW,MAAM,SAAS,oBAC1B,WAAW,KAAK,QAAQ,SAAS,SACrC,CACJ;;;;;;AAOF,MAAM,2BAA2B,KAAU,WAAyB;CAClE,IAAI,CAAC,iBAAiB,GAAG,GAAG;EAC1B,gDAAkB,KAAK,uBAAuB,MAAM;EACpD;CACF;CAEA,MAAM,OAAO,IAAI,QAAQ;CACzB,IAAI,cAAc;CAClB,KAAK,SAAS,WAAgB,UAAkB;EAM9C,IAJE,UAAU,SAAS,yBACnB,UAAU,aAAa,MACpB,eAAoB,WAAW,MAAM,QAAQ,SAAS,SACzD,GACwB,cAAc,QAAQ;CAClD,CAAC;CAED,KAAK,OACH,aACA,GACA,eAAe,WAAW,sBAAsB,gBAAgB,OAAO,IAAI,CAC7E;AACF;;;;;;AAOA,MAAM,sBACJ,KACA,gBACmD;CACnD,IAAI,QAAwD;CAE5D,OAAO,MAAM,KAAK,EAChB,wBAAwB,MAAM;EAC5B,MAAM,EAAE,IAAI,SAAS,KAAK;EAC1B,IAAI,CAAC,SAAS,GAAG,SAAS,gBAAgB,QAAQ,YAAY,IAAI,GAAG;GACnE,IAAI,gBAAgB,KAAK;GACzB,IAAI,cAAc,QAAQ,KAAK,SAAS,0BACtC,gBAAgB,cAAc;GAEhC,QAAQ;IAAE,SAAS,GAAG;IAAM;GAAc;GAC1C,OAAO;EACT;EACA,KAAK,SAAS,IAAI;CACpB,EACF,CAAC;CAED,OAAO;AACT;;AAGA,MAAM,iBACJ,MACA,aACA,SAEA,MAAM,SAAS,QACf,KAAK,QAAQ,SAAS,gBACtB,YAAY,SAAS,KAAK,OAAO,IAAI;;;;;AAMvC,MAAM,+BACJ,MACA,EACE,kBACA,iBACA,wBAMyB;CAC3B,IAAI,KAAK,SAAS,gBAAgB,GAAG,OAAO;EAAE;EAAM,QAAQ;CAAU;CAEtE,MAAM,MAAM,UAAU,IAAI;CAC1B,IAAIC,mDAAqB,KAAK,qBAAqB,GACjD,OAAO;EAAE;EAAM,QAAQ;CAAU;CAGnC,MAAM,cAAc,gBAAgB,GAAG;CACvC,IAAI,CAAC,aAAa,OAAO;EAAE;EAAM,QAAQ;CAAU;CAEnD,YAAY,cAAc,YACxB,eAAe,kBAAkB,YAAY,OAAO,CAAC,CACvD;CACA,wBAAwB,KAAK,gBAAgB;CAE7C,OAAO;EAAE,MAAM,OAAO,MAAM,GAAG,CAAC,CAAC;EAAM,QAAQ;CAAa;AAC9D;;;;;AAMA,MAAa,6BACX,SAEA,4BAA4B,MAAM;CAChC,kBAAkB;CAClB,kBAAkB,QAAQ;EACxB,MAAM,eAAe,sBAAsB,KAAK;GAC9C,QAAQ;GACR,SAAS;EACX,CAAC;EACD,OAAO,mBAAmB,MAAM,SAC9B,cAAc,MAAM,cAAc,gBAAgB,CACpD;CACF;CACA,oBAAoB,YAAY,GAAG,QAAQ;AAC7C,CAAC;;;;;;AAOH,MAAa,yBAAyB,SACpC,4BAA4B,MAAM;CAChC,kBAAkB;CAClB,kBAAkB,QAAQ;EACxB,MAAM,eAAe,sBAAsB,KAAK;GAC9C,QAAQ;GACR,SAAS;GACT,OAAO,CAAC,WAAW,SAAS;EAC9B,CAAC;EACD,OAAO,mBAAmB,MAAM,SAC9B,cAAc,MAAM,cAAc,gBAAgB,CACpD;CACF;CACA,oBAAoB,YAAY,GAAG,QAAQ;AAC7C,CAAC;;;;;;;AAQH,MAAa,0BAA0B,SACrC,4BAA4B,MAAM;CAChC,kBAAkB;CAClB,kBAAkB,QAAQ;EACxB,MAAM,eAAe,sBAAsB,KAAK;GAC9C,QAAQ;GACR,OAAO,CAAC,MAAM;EAChB,CAAC;EACD,OAAO,mBAAmB,MAAM,SAC9B,cAAc,MAAM,cAAc,eAAe,CACnD;CACF;CACA,oBAAoB,YAAY,GAAG,QAAQ;AAC7C,CAAC;;;;;AAMH,MAAa,4BACX,SAEA,4BAA4B,MAAM;CAChC,kBAAkB;CAClB,kBAAkB,QAChB,mBAAmB,MAAM,SAAS;EAChC,MAAM,OAAO,KAAK,SAAS,oBAAoB,KAAK,WAAW;EAC/D,OACE,EAAE,eAAe,MAAM,IAAI,KAC3B,EAAE,iBAAiB,MAAM,KAAK,MAAM,KACnC,KAAK,OAAO,OAAe,SAAS,iBACpC,KAAK,OAAO,SAAiB,SAAS;CAE3C,CAAC;CACH,oBAAoB,YAAY,GAAG,QAAQ;AAC7C,CAAC;;;;;;AAOH,MAAa,wBAAwB,SAAyC;CAC5E,MAAM,mBAAmB;CACzB,IAAI,KAAK,SAAS,gBAAgB,GAAG,OAAO;EAAE;EAAM,QAAQ;CAAU;CAEtE,MAAM,MAAM,UAAU,IAAI;CAC1B,IAAIA,mDAAqB,KAAK,qBAAqB,GACjD,OAAO;EAAE;EAAM,QAAQ;CAAU;CAGnC,MAAM,eAAe,sBAAsB,KAAK;EAC9C,QAAQ;EACR,OAAO,CAAC,QAAQ;CAClB,CAAC;CAED,IAAI,aAAa;CACjB,OAAO,MAAM,KAAK,EAChB,mBAAmB,MAAM;EACvB,IAAI,YAAY,OAAO;EACvB,IAAI,cAAc,KAAK,MAAM,cAAc,eAAe,GAAG;GAC3D,MAAM,aAAa,eACjB,0BACF,CAAC,CAAC;GACF,WAAW,OAAO,SAAS,KAAK;GAChC,KAAK,QAAQ,UAAU;GACvB,aAAa;GACb,OAAO;EACT;EACA,KAAK,SAAS,IAAI;CACpB,EACF,CAAC;CAED,IAAI,CAAC,YAAY,OAAO;EAAE;EAAM,QAAQ;CAAU;CAElD,wBAAwB,KAAK,gBAAgB;CAE7C,OAAO;EAAE,MAAM,OAAO,MAAM,GAAG,CAAC,CAAC;EAAM,QAAQ;CAAa;AAC9D"}
@@ -1,14 +1,20 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_init_frameworkSetup_backend_index = require('./backend/index.cjs');
2
3
  const require_init_frameworkSetup_nextAppRouter_index = require('./nextAppRouter/index.cjs');
3
4
  const require_init_frameworkSetup_tanstackStart_index = require('./tanstackStart/index.cjs');
4
5
 
5
6
  //#region src/init/frameworkSetup/index.ts
6
7
  /**
7
8
  * Registered framework adapters, tried in order. The first one whose `detect`
8
- * returns true handles the project. Add new adapters (Nuxt, Vite + React, …)
9
- * here as they are implemented.
9
+ * returns true handles the project. Frontend adapters come first, so an app
10
+ * with its own server keeps its frontend scaffolding. Add new adapters (Nuxt,
11
+ * Vite + React, …) here as they are implemented.
10
12
  */
11
- const adapters = [require_init_frameworkSetup_nextAppRouter_index.nextAppRouterAdapter, require_init_frameworkSetup_tanstackStart_index.tanStackStartAdapter];
13
+ const adapters = [
14
+ require_init_frameworkSetup_nextAppRouter_index.nextAppRouterAdapter,
15
+ require_init_frameworkSetup_tanstackStart_index.tanStackStartAdapter,
16
+ ...require_init_frameworkSetup_backend_index.backendAdapters
17
+ ];
12
18
  /**
13
19
  * Runs framework-specific scaffolding (middleware/proxy, providers in
14
20
  * layout/page, example content) for the first adapter that matches the project.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["nextAppRouterAdapter","tanStackStartAdapter"],"sources":["../../../../src/init/frameworkSetup/index.ts"],"sourcesContent":["import { nextAppRouterAdapter } from './nextAppRouter';\nimport { tanStackStartAdapter } from './tanstackStart';\nimport type { FrameworkAdapter, FrameworkSetupContext } from './types';\n\nexport type { FrameworkAdapter, FrameworkSetupContext } from './types';\n\n/**\n * Registered framework adapters, tried in order. The first one whose `detect`\n * returns true handles the project. Add new adapters (Nuxt, Vite + React, …)\n * here as they are implemented.\n */\nconst adapters: FrameworkAdapter[] = [\n nextAppRouterAdapter,\n tanStackStartAdapter,\n];\n\n/**\n * Runs framework-specific scaffolding (middleware/proxy, providers in\n * layout/page, example content) for the first adapter that matches the project.\n * No-ops when no adapter recognizes the project. Each adapter is idempotent and\n * non-destructive, so this is safe to run on existing applications.\n */\nexport const setupFramework = async (\n context: FrameworkSetupContext\n): Promise<void> => {\n for (const adapter of adapters) {\n if (await adapter.detect(context)) {\n await adapter.setup(context);\n return;\n }\n }\n};\n"],"mappings":";;;;;;;;;;AAWA,MAAM,WAA+B,CACnCA,sEACAC,oEACF;;;;;;;AAQA,MAAa,iBAAiB,OAC5B,YACkB;CAClB,KAAK,MAAM,WAAW,UACpB,IAAI,MAAM,QAAQ,OAAO,OAAO,GAAG;EACjC,MAAM,QAAQ,MAAM,OAAO;EAC3B;CACF;AAEJ"}
1
+ {"version":3,"file":"index.cjs","names":["nextAppRouterAdapter","tanStackStartAdapter","backendAdapters"],"sources":["../../../../src/init/frameworkSetup/index.ts"],"sourcesContent":["import { backendAdapters } from './backend';\nimport { nextAppRouterAdapter } from './nextAppRouter';\nimport { tanStackStartAdapter } from './tanstackStart';\nimport type { FrameworkAdapter, FrameworkSetupContext } from './types';\n\nexport type { FrameworkAdapter, FrameworkSetupContext } from './types';\n\n/**\n * Registered framework adapters, tried in order. The first one whose `detect`\n * returns true handles the project. Frontend adapters come first, so an app\n * with its own server keeps its frontend scaffolding. Add new adapters (Nuxt,\n * Vite + React, …) here as they are implemented.\n */\nconst adapters: FrameworkAdapter[] = [\n nextAppRouterAdapter,\n tanStackStartAdapter,\n ...backendAdapters,\n];\n\n/**\n * Runs framework-specific scaffolding (middleware/proxy, providers in\n * layout/page, example content) for the first adapter that matches the project.\n * No-ops when no adapter recognizes the project. Each adapter is idempotent and\n * non-destructive, so this is safe to run on existing applications.\n */\nexport const setupFramework = async (\n context: FrameworkSetupContext\n): Promise<void> => {\n for (const adapter of adapters) {\n if (await adapter.detect(context)) {\n await adapter.setup(context);\n return;\n }\n }\n};\n"],"mappings":";;;;;;;;;;;;AAaA,MAAM,WAA+B;CACnCA;CACAC;CACA,GAAGC;AACL;;;;;;;AAQA,MAAa,iBAAiB,OAC5B,YACkB;CAClB,KAAK,MAAM,WAAW,UACpB,IAAI,MAAM,QAAQ,OAAO,OAAO,GAAG;EACjC,MAAM,QAAQ,MAAM,OAAO;EAC3B;CACF;AAEJ"}
@@ -0,0 +1,13 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ //#region src/init/frameworkSetup/localeRouting.ts
3
+ /**
4
+ * Whether the locale is carried by a URL path segment (`/fr/about`), which the
5
+ * framework router must declare (`[locale]`, `{-$locale}`, `$locale`…). Only the
6
+ * prefix routing modes do, and only while the proxy is enabled: `no-prefix` and
7
+ * `search-params` resolve the locale from storage/headers/query instead.
8
+ */
9
+ const usesLocalePathSegment = ({ routingMode, enableProxy }) => enableProxy && (routingMode === "prefix-all" || routingMode === "prefix-no-default");
10
+
11
+ //#endregion
12
+ exports.usesLocalePathSegment = usesLocalePathSegment;
13
+ //# sourceMappingURL=localeRouting.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localeRouting.cjs","names":[],"sources":["../../../../src/init/frameworkSetup/localeRouting.ts"],"sourcesContent":["import type { FrameworkSetupContext } from './types';\n\n/**\n * Whether the locale is carried by a URL path segment (`/fr/about`), which the\n * framework router must declare (`[locale]`, `{-$locale}`, `$locale`…). Only the\n * prefix routing modes do, and only while the proxy is enabled: `no-prefix` and\n * `search-params` resolve the locale from storage/headers/query instead.\n */\nexport const usesLocalePathSegment = ({\n routingMode,\n enableProxy,\n}: Pick<FrameworkSetupContext, 'routingMode' | 'enableProxy'>): boolean =>\n enableProxy &&\n (routingMode === 'prefix-all' || routingMode === 'prefix-no-default');\n"],"mappings":";;;;;;;;AAQA,MAAa,yBAAyB,EACpC,aACA,kBAEA,gBACC,gBAAgB,gBAAgB,gBAAgB"}
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_runtime = require('../../../_virtual/_rolldown/runtime.cjs');
3
3
  const require_init_utils_fileSystem = require('../../utils/fileSystem.cjs');
4
+ const require_init_frameworkSetup_localeRouting = require('../localeRouting.cjs');
4
5
  const require_init_utils_version = require('../../utils/version.cjs');
5
6
  const require_init_frameworkSetup_nextAppRouter_detect = require('./detect.cjs');
6
7
  const require_init_frameworkSetup_nextAppRouter_restructure = require('./restructure.cjs');
@@ -10,6 +11,7 @@ let node_path = require("node:path");
10
11
  let _intlayer_config_colors = require("@intlayer/config/colors");
11
12
  _intlayer_config_colors = require_runtime.__toESM(_intlayer_config_colors);
12
13
  let _intlayer_config_logger = require("@intlayer/config/logger");
14
+ let node_fs_promises = require("node:fs/promises");
13
15
 
14
16
  //#region src/init/frameworkSetup/nextAppRouter/index.ts
15
17
  /**
@@ -64,11 +66,29 @@ const createIfMissing = async (rootDir, filePath, content, description) => {
64
66
  return true;
65
67
  };
66
68
  /**
67
- * Next.js App Router adapter. Scaffolds the locale proxy/middleware, restructures
68
- * the app into a `[locale]` segment, and wraps the layout with the unified
69
- * Intlayer provider — all idempotently and without overwriting recognizable
70
- * user code. Pages are never wrapped: `IntlayerProvider` in the locale layout
71
- * covers them.
69
+ * Wires an app whose URLs carry no locale segment (`no-prefix`,
70
+ * `search-params`, or no proxy): routes stay at the app root and the root
71
+ * layout provides the locale resolved by `getLocale()`. An app already nested
72
+ * under a locale segment is left untouched, with guidance.
73
+ */
74
+ const setupUnprefixedApp = async (rootDir, appDir, useTypeScript) => {
75
+ const scriptExtension = useTypeScript ? "tsx" : "jsx";
76
+ const existingLocaleSegment = (await (0, node_fs_promises.readdir)((0, node_path.join)(rootDir, appDir))).find(require_init_frameworkSetup_nextAppRouter_restructure.isLocaleSegment);
77
+ if (existingLocaleSegment) {
78
+ (0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.x} Routes live under ${(0, _intlayer_config_logger.colorizePath)((0, node_path.join)(appDir, existingLocaleSegment))} but the chosen routing has no locale in the URL — move them back to ${(0, _intlayer_config_logger.colorizePath)(appDir)} manually.`, { level: "warn" });
79
+ return;
80
+ }
81
+ const existingLayout = await require_init_frameworkSetup_nextAppRouter_detect.findAppFile(rootDir, appDir, "layout");
82
+ if (existingLayout) await transformExistingFile(rootDir, existingLayout, (code) => require_init_frameworkSetup_nextAppRouter_transforms.wrapLayoutWithProvider(code, { exportStaticParams: false }));
83
+ else await createIfMissing(rootDir, (0, node_path.join)(appDir, `layout.${scriptExtension}`), useTypeScript ? require_init_frameworkSetup_nextAppRouter_templates.UNPREFIXED_ROOT_LAYOUT_TEMPLATE_TS : require_init_frameworkSetup_nextAppRouter_templates.UNPREFIXED_ROOT_LAYOUT_TEMPLATE_JS, "root layout");
84
+ if (!await require_init_frameworkSetup_nextAppRouter_detect.findAppFile(rootDir, appDir, "page")) await createIfMissing(rootDir, (0, node_path.join)(appDir, `page.${scriptExtension}`), require_init_frameworkSetup_nextAppRouter_templates.UNPREFIXED_PAGE_TEMPLATE, "page");
85
+ };
86
+ /**
87
+ * Next.js App Router adapter. Scaffolds the locale proxy/middleware (when the
88
+ * proxy is enabled), restructures the app into a `[locale]` segment (prefix
89
+ * routing modes only), and wraps the layout with the unified Intlayer provider
90
+ * — all idempotently and without overwriting recognizable user code. Pages are
91
+ * never wrapped: `IntlayerProvider` in the layout covers them.
72
92
  */
73
93
  const nextAppRouterAdapter = {
74
94
  name: "Next.js App Router",
@@ -76,14 +96,21 @@ const nextAppRouterAdapter = {
76
96
  if (!allDeps.next) return false;
77
97
  return await require_init_frameworkSetup_nextAppRouter_detect.detectNextAppDir(rootDir) !== null;
78
98
  },
79
- setup: async ({ rootDir, allDeps, useTypeScript }) => {
99
+ setup: async ({ rootDir, allDeps, useTypeScript, routingMode, enableProxy }) => {
80
100
  const appDirInfo = await require_init_frameworkSetup_nextAppRouter_detect.detectNextAppDir(rootDir);
81
101
  if (!appDirInfo) return;
82
102
  const { appDir, srcDir } = appDirInfo;
83
103
  const isNext16 = require_init_utils_version.isVersionAtLeast(allDeps.next, 16);
84
104
  const scriptExtension = useTypeScript ? "tsx" : "jsx";
85
105
  (0, _intlayer_config_logger.logger)((0, _intlayer_config_logger.colorize)("Setting up Next.js App Router integration...", _intlayer_config_colors.CYAN));
86
- await ensureProxyOrMiddleware(rootDir, srcDir, isNext16);
106
+ if (enableProxy) await ensureProxyOrMiddleware(rootDir, srcDir, isNext16);
107
+ if (!require_init_frameworkSetup_localeRouting.usesLocalePathSegment({
108
+ routingMode,
109
+ enableProxy
110
+ })) {
111
+ await setupUnprefixedApp(rootDir, appDir, useTypeScript);
112
+ return;
113
+ }
87
114
  const restructureResult = await require_init_frameworkSetup_nextAppRouter_restructure.restructureAppIntoLocale(rootDir, appDir);
88
115
  if (restructureResult.status === "moved") (0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} Restructured app routes under ${(0, _intlayer_config_logger.colorizePath)((0, node_path.join)(appDir, "[locale]"))}: ${restructureResult.movedEntries.map((entry) => (0, _intlayer_config_logger.colorize)(entry, _intlayer_config_colors.MAGENTA)).join(", ")}`);
89
116
  else if (restructureResult.status === "already-structured") (0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} ${(0, _intlayer_config_logger.colorizePath)((0, node_path.join)(appDir, restructureResult.localeSegment))} already exists, skipping restructure`);
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["exists","join","v","colorizePath","PROXY_TEMPLATE","MIDDLEWARE_TEMPLATE","ensureDirectory","writeFileToRoot","x","readFileFromRoot","detectNextAppDir","isVersionAtLeast","colorize","ANSIColors","restructureAppIntoLocale","ROOT_LAYOUT_TEMPLATE_TS","ROOT_LAYOUT_TEMPLATE_JS","findAppFile","wrapLayoutWithProvider","LOCALE_LAYOUT_TEMPLATE_TS","LOCALE_LAYOUT_TEMPLATE_JS","LOCALE_PAGE_TEMPLATE_TS","LOCALE_PAGE_TEMPLATE_JS"],"sources":["../../../../../src/init/frameworkSetup/nextAppRouter/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 type { FrameworkAdapter, FrameworkSetupContext } from '../types';\nimport { detectNextAppDir, findAppFile, isVersionAtLeast } from './detect';\nimport { restructureAppIntoLocale } from './restructure';\nimport {\n LOCALE_LAYOUT_TEMPLATE_JS,\n LOCALE_LAYOUT_TEMPLATE_TS,\n LOCALE_PAGE_TEMPLATE_JS,\n LOCALE_PAGE_TEMPLATE_TS,\n MIDDLEWARE_TEMPLATE,\n PROXY_TEMPLATE,\n ROOT_LAYOUT_TEMPLATE_JS,\n ROOT_LAYOUT_TEMPLATE_TS,\n} from './templates';\nimport { type TransformResult, wrapLayoutWithProvider } from './transforms';\n\n/**\n * Creates the locale-detection proxy (Next >= 16) or middleware (Next < 16),\n * but only when neither already exists, so a user's custom file is never\n * touched. Placed next to the app directory's parent (`src/` when present).\n */\nconst ensureProxyOrMiddleware = async (\n rootDir: string,\n srcDir: string,\n isNext16: boolean\n): Promise<void> => {\n const baseDir = srcDir || '.';\n const proxyCandidates = [\n 'proxy.ts',\n 'proxy.js',\n 'middleware.ts',\n 'middleware.js',\n ];\n\n for (const candidate of proxyCandidates) {\n if (await exists(rootDir, join(baseDir, candidate))) {\n logger(\n `${v} ${colorizePath(join(baseDir, candidate))} already exists, leaving it untouched`\n );\n return;\n }\n }\n\n const fileName = isNext16 ? 'proxy.ts' : 'middleware.ts';\n const content = isNext16 ? PROXY_TEMPLATE : MIDDLEWARE_TEMPLATE;\n const targetPath = join(baseDir, fileName);\n\n if (srcDir) await ensureDirectory(rootDir, srcDir);\n await writeFileToRoot(rootDir, targetPath, content);\n logger(`${v} Created ${colorizePath(targetPath)} for locale detection`);\n};\n\n/** Logs the outcome of a layout 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-client':\n logger(\n `${x} ${colorizePath(filePath)} is a client component — add the Intlayer provider manually.`,\n { level: 'warn' }\n );\n break;\n case 'skipped':\n logger(\n `${x} Could not safely add the Intlayer provider to ${colorizePath(filePath)} — please wire it 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 * Next.js App Router adapter. Scaffolds the locale proxy/middleware, restructures\n * the app into a `[locale]` segment, and wraps the layout with the unified\n * Intlayer provider — all idempotently and without overwriting recognizable\n * user code. Pages are never wrapped: `IntlayerProvider` in the locale layout\n * covers them.\n */\nexport const nextAppRouterAdapter: FrameworkAdapter = {\n name: 'Next.js App Router',\n\n detect: async ({ rootDir, allDeps }) => {\n if (!allDeps.next) return false;\n return (await detectNextAppDir(rootDir)) !== null;\n },\n\n setup: async ({ rootDir, allDeps, useTypeScript }: FrameworkSetupContext) => {\n const appDirInfo = await detectNextAppDir(rootDir);\n if (!appDirInfo) return;\n\n const { appDir, srcDir } = appDirInfo;\n const isNext16 = isVersionAtLeast(allDeps.next, 16);\n const scriptExtension = useTypeScript ? 'tsx' : 'jsx';\n\n logger(\n colorize('Setting up Next.js App Router integration...', ANSIColors.CYAN)\n );\n\n // 1. Locale detection proxy / middleware (create only when absent).\n await ensureProxyOrMiddleware(rootDir, srcDir, isNext16);\n\n // 2. Move routable files under a `[locale]` segment (idempotent).\n const restructureResult = await restructureAppIntoLocale(rootDir, appDir);\n if (restructureResult.status === 'moved') {\n logger(\n `${v} Restructured app routes under ${colorizePath(join(appDir, '[locale]'))}: ${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(appDir, restructureResult.localeSegment))} already exists, skipping restructure`\n );\n }\n\n // When the app already uses a different locale-prefix scheme (e.g. an\n // `[...locale]` / `[[...locale]]` catch-all), respect the user's routing:\n // don't scaffold a second, conflicting `[locale]` segment.\n if (\n restructureResult.status === 'already-structured' &&\n restructureResult.localeSegment !== '[locale]'\n ) {\n logger(\n `${v} Detected existing locale routing (${colorize(restructureResult.localeSegment, ANSIColors.MAGENTA)}), skipping locale layout/page scaffold`\n );\n return;\n }\n\n const localeDir = join(appDir, '[locale]');\n await ensureDirectory(rootDir, localeDir);\n\n // 3. Minimal pass-through root layout (the `[locale]` layout owns `<html>`).\n await createIfMissing(\n rootDir,\n join(appDir, `layout.${scriptExtension}`),\n useTypeScript ? ROOT_LAYOUT_TEMPLATE_TS : ROOT_LAYOUT_TEMPLATE_JS,\n 'root layout'\n );\n\n // 4. Locale layout — transform an existing one, else scaffold from template.\n const existingLayout = await findAppFile(rootDir, localeDir, 'layout');\n if (existingLayout) {\n await transformExistingFile(\n rootDir,\n existingLayout,\n wrapLayoutWithProvider\n );\n } else {\n await createIfMissing(\n rootDir,\n join(localeDir, `layout.${scriptExtension}`),\n useTypeScript ? LOCALE_LAYOUT_TEMPLATE_TS : LOCALE_LAYOUT_TEMPLATE_JS,\n 'locale layout'\n );\n }\n\n // 5. Locale page — only scaffolded when absent. An existing page needs no\n // transform: the locale layout's `IntlayerProvider` already covers it.\n const existingPage = await findAppFile(rootDir, localeDir, 'page');\n if (!existingPage) {\n await createIfMissing(\n rootDir,\n join(localeDir, `page.${scriptExtension}`),\n useTypeScript ? LOCALE_PAGE_TEMPLATE_TS : LOCALE_PAGE_TEMPLATE_JS,\n 'locale page'\n );\n }\n },\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["exists","join","v","colorizePath","PROXY_TEMPLATE","MIDDLEWARE_TEMPLATE","ensureDirectory","writeFileToRoot","x","readFileFromRoot","readdir","isLocaleSegment","findAppFile","wrapLayoutWithProvider","UNPREFIXED_ROOT_LAYOUT_TEMPLATE_TS","UNPREFIXED_ROOT_LAYOUT_TEMPLATE_JS","UNPREFIXED_PAGE_TEMPLATE","detectNextAppDir","isVersionAtLeast","colorize","ANSIColors","usesLocalePathSegment","restructureAppIntoLocale","ROOT_LAYOUT_TEMPLATE_TS","ROOT_LAYOUT_TEMPLATE_JS","LOCALE_LAYOUT_TEMPLATE_TS","LOCALE_LAYOUT_TEMPLATE_JS","LOCALE_PAGE_TEMPLATE_TS","LOCALE_PAGE_TEMPLATE_JS"],"sources":["../../../../../src/init/frameworkSetup/nextAppRouter/index.ts"],"sourcesContent":["import { readdir } from 'node:fs/promises';\nimport { 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 { usesLocalePathSegment } from '../localeRouting';\nimport type { FrameworkAdapter, FrameworkSetupContext } from '../types';\nimport { detectNextAppDir, findAppFile, isVersionAtLeast } from './detect';\nimport { isLocaleSegment, restructureAppIntoLocale } from './restructure';\nimport {\n LOCALE_LAYOUT_TEMPLATE_JS,\n LOCALE_LAYOUT_TEMPLATE_TS,\n LOCALE_PAGE_TEMPLATE_JS,\n LOCALE_PAGE_TEMPLATE_TS,\n MIDDLEWARE_TEMPLATE,\n PROXY_TEMPLATE,\n ROOT_LAYOUT_TEMPLATE_JS,\n ROOT_LAYOUT_TEMPLATE_TS,\n UNPREFIXED_PAGE_TEMPLATE,\n UNPREFIXED_ROOT_LAYOUT_TEMPLATE_JS,\n UNPREFIXED_ROOT_LAYOUT_TEMPLATE_TS,\n} from './templates';\nimport { type TransformResult, wrapLayoutWithProvider } from './transforms';\n\n/**\n * Creates the locale-detection proxy (Next >= 16) or middleware (Next < 16),\n * but only when neither already exists, so a user's custom file is never\n * touched. Placed next to the app directory's parent (`src/` when present).\n */\nconst ensureProxyOrMiddleware = async (\n rootDir: string,\n srcDir: string,\n isNext16: boolean\n): Promise<void> => {\n const baseDir = srcDir || '.';\n const proxyCandidates = [\n 'proxy.ts',\n 'proxy.js',\n 'middleware.ts',\n 'middleware.js',\n ];\n\n for (const candidate of proxyCandidates) {\n if (await exists(rootDir, join(baseDir, candidate))) {\n logger(\n `${v} ${colorizePath(join(baseDir, candidate))} already exists, leaving it untouched`\n );\n return;\n }\n }\n\n const fileName = isNext16 ? 'proxy.ts' : 'middleware.ts';\n const content = isNext16 ? PROXY_TEMPLATE : MIDDLEWARE_TEMPLATE;\n const targetPath = join(baseDir, fileName);\n\n if (srcDir) await ensureDirectory(rootDir, srcDir);\n await writeFileToRoot(rootDir, targetPath, content);\n logger(`${v} Created ${colorizePath(targetPath)} for locale detection`);\n};\n\n/** Logs the outcome of a layout 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-client':\n logger(\n `${x} ${colorizePath(filePath)} is a client component — add the Intlayer provider manually.`,\n { level: 'warn' }\n );\n break;\n case 'skipped':\n logger(\n `${x} Could not safely add the Intlayer provider to ${colorizePath(filePath)} — please wire it 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 * Wires an app whose URLs carry no locale segment (`no-prefix`,\n * `search-params`, or no proxy): routes stay at the app root and the root\n * layout provides the locale resolved by `getLocale()`. An app already nested\n * under a locale segment is left untouched, with guidance.\n */\nconst setupUnprefixedApp = async (\n rootDir: string,\n appDir: string,\n useTypeScript: boolean\n): Promise<void> => {\n const scriptExtension = useTypeScript ? 'tsx' : 'jsx';\n\n const entries = await readdir(join(rootDir, appDir));\n const existingLocaleSegment = entries.find(isLocaleSegment);\n if (existingLocaleSegment) {\n logger(\n `${x} Routes live under ${colorizePath(join(appDir, existingLocaleSegment))} but the chosen routing has no locale in the URL — move them back to ${colorizePath(appDir)} manually.`,\n { level: 'warn' }\n );\n return;\n }\n\n const existingLayout = await findAppFile(rootDir, appDir, 'layout');\n if (existingLayout) {\n await transformExistingFile(rootDir, existingLayout, (code) =>\n wrapLayoutWithProvider(code, { exportStaticParams: false })\n );\n } else {\n await createIfMissing(\n rootDir,\n join(appDir, `layout.${scriptExtension}`),\n useTypeScript\n ? UNPREFIXED_ROOT_LAYOUT_TEMPLATE_TS\n : UNPREFIXED_ROOT_LAYOUT_TEMPLATE_JS,\n 'root layout'\n );\n }\n\n if (!(await findAppFile(rootDir, appDir, 'page'))) {\n await createIfMissing(\n rootDir,\n join(appDir, `page.${scriptExtension}`),\n UNPREFIXED_PAGE_TEMPLATE,\n 'page'\n );\n }\n};\n\n/**\n * Next.js App Router adapter. Scaffolds the locale proxy/middleware (when the\n * proxy is enabled), restructures the app into a `[locale]` segment (prefix\n * routing modes only), and wraps the layout with the unified Intlayer provider\n * — all idempotently and without overwriting recognizable user code. Pages are\n * never wrapped: `IntlayerProvider` in the layout covers them.\n */\nexport const nextAppRouterAdapter: FrameworkAdapter = {\n name: 'Next.js App Router',\n\n detect: async ({ rootDir, allDeps }) => {\n if (!allDeps.next) return false;\n return (await detectNextAppDir(rootDir)) !== null;\n },\n\n setup: async ({\n rootDir,\n allDeps,\n useTypeScript,\n routingMode,\n enableProxy,\n }: FrameworkSetupContext) => {\n const appDirInfo = await detectNextAppDir(rootDir);\n if (!appDirInfo) return;\n\n const { appDir, srcDir } = appDirInfo;\n const isNext16 = isVersionAtLeast(allDeps.next, 16);\n const scriptExtension = useTypeScript ? 'tsx' : 'jsx';\n\n logger(\n colorize('Setting up Next.js App Router integration...', ANSIColors.CYAN)\n );\n\n // 1. Locale detection proxy / middleware (create only when absent).\n if (enableProxy) {\n await ensureProxyOrMiddleware(rootDir, srcDir, isNext16);\n }\n\n // Without a locale path segment, routes stay where they are.\n if (!usesLocalePathSegment({ routingMode, enableProxy })) {\n await setupUnprefixedApp(rootDir, appDir, useTypeScript);\n return;\n }\n\n // 2. Move routable files under a `[locale]` segment (idempotent).\n const restructureResult = await restructureAppIntoLocale(rootDir, appDir);\n if (restructureResult.status === 'moved') {\n logger(\n `${v} Restructured app routes under ${colorizePath(join(appDir, '[locale]'))}: ${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(appDir, restructureResult.localeSegment))} already exists, skipping restructure`\n );\n }\n\n // When the app already uses a different locale-prefix scheme (e.g. an\n // `[...locale]` / `[[...locale]]` catch-all), respect the user's routing:\n // don't scaffold a second, conflicting `[locale]` segment.\n if (\n restructureResult.status === 'already-structured' &&\n restructureResult.localeSegment !== '[locale]'\n ) {\n logger(\n `${v} Detected existing locale routing (${colorize(restructureResult.localeSegment, ANSIColors.MAGENTA)}), skipping locale layout/page scaffold`\n );\n return;\n }\n\n const localeDir = join(appDir, '[locale]');\n await ensureDirectory(rootDir, localeDir);\n\n // 3. Minimal pass-through root layout (the `[locale]` layout owns `<html>`).\n await createIfMissing(\n rootDir,\n join(appDir, `layout.${scriptExtension}`),\n useTypeScript ? ROOT_LAYOUT_TEMPLATE_TS : ROOT_LAYOUT_TEMPLATE_JS,\n 'root layout'\n );\n\n // 4. Locale layout — transform an existing one, else scaffold from template.\n const existingLayout = await findAppFile(rootDir, localeDir, 'layout');\n if (existingLayout) {\n await transformExistingFile(\n rootDir,\n existingLayout,\n wrapLayoutWithProvider\n );\n } else {\n await createIfMissing(\n rootDir,\n join(localeDir, `layout.${scriptExtension}`),\n useTypeScript ? LOCALE_LAYOUT_TEMPLATE_TS : LOCALE_LAYOUT_TEMPLATE_JS,\n 'locale layout'\n );\n }\n\n // 5. Locale page — only scaffolded when absent. An existing page needs no\n // transform: the locale layout's `IntlayerProvider` already covers it.\n const existingPage = await findAppFile(rootDir, localeDir, 'page');\n if (!existingPage) {\n await createIfMissing(\n rootDir,\n join(localeDir, `page.${scriptExtension}`),\n useTypeScript ? LOCALE_PAGE_TEMPLATE_TS : LOCALE_PAGE_TEMPLATE_JS,\n 'locale page'\n );\n }\n },\n};\n"],"mappings":"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"}
@@ -108,6 +108,59 @@ const LOCALE_PAGE_TEMPLATE_JS = `const Page = async ({ params }) => {
108
108
  );
109
109
  };
110
110
 
111
+ export default Page;
112
+ `;
113
+ /**
114
+ * Root layout (`app/layout.tsx`) for routing modes without a locale path
115
+ * segment (`no-prefix`, `search-params`, or no proxy at all). Owns `<html>` and
116
+ * resolves the locale from the request (cookie / header) via `getLocale()`.
117
+ */
118
+ const UNPREFIXED_ROOT_LAYOUT_TEMPLATE_TS = `import type { PropsWithChildren } from "react";
119
+ import { getHTMLTextDir } from "intlayer";
120
+ import { getLocale, IntlayerProvider } from "next-intlayer/server";
121
+
122
+ const RootLayout = async ({ children }: PropsWithChildren) => {
123
+ const locale = await getLocale();
124
+
125
+ return (
126
+ <html lang={locale} dir={getHTMLTextDir(locale)}>
127
+ <body>
128
+ <IntlayerProvider locale={locale}>{children}</IntlayerProvider>
129
+ </body>
130
+ </html>
131
+ );
132
+ };
133
+
134
+ export default RootLayout;
135
+ `;
136
+ const UNPREFIXED_ROOT_LAYOUT_TEMPLATE_JS = `import { getHTMLTextDir } from "intlayer";
137
+ import { getLocale, IntlayerProvider } from "next-intlayer/server";
138
+
139
+ const RootLayout = async ({ children }) => {
140
+ const locale = await getLocale();
141
+
142
+ return (
143
+ <html lang={locale} dir={getHTMLTextDir(locale)}>
144
+ <body>
145
+ <IntlayerProvider locale={locale}>{children}</IntlayerProvider>
146
+ </body>
147
+ </html>
148
+ );
149
+ };
150
+
151
+ export default RootLayout;
152
+ `;
153
+ /**
154
+ * Home page (`app/page.tsx`) for routing modes without a locale path segment.
155
+ * Identical for TypeScript and JavaScript projects.
156
+ */
157
+ const UNPREFIXED_PAGE_TEMPLATE = `const Page = () => (
158
+ <main>
159
+ <h1>Hello</h1>
160
+ <p>Get started by editing this page.</p>
161
+ </main>
162
+ );
163
+
111
164
  export default Page;
112
165
  `;
113
166
 
@@ -120,4 +173,7 @@ exports.MIDDLEWARE_TEMPLATE = MIDDLEWARE_TEMPLATE;
120
173
  exports.PROXY_TEMPLATE = PROXY_TEMPLATE;
121
174
  exports.ROOT_LAYOUT_TEMPLATE_JS = ROOT_LAYOUT_TEMPLATE_JS;
122
175
  exports.ROOT_LAYOUT_TEMPLATE_TS = ROOT_LAYOUT_TEMPLATE_TS;
176
+ exports.UNPREFIXED_PAGE_TEMPLATE = UNPREFIXED_PAGE_TEMPLATE;
177
+ exports.UNPREFIXED_ROOT_LAYOUT_TEMPLATE_JS = UNPREFIXED_ROOT_LAYOUT_TEMPLATE_JS;
178
+ exports.UNPREFIXED_ROOT_LAYOUT_TEMPLATE_TS = UNPREFIXED_ROOT_LAYOUT_TEMPLATE_TS;
123
179
  //# sourceMappingURL=templates.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"templates.cjs","names":[],"sources":["../../../../../src/init/frameworkSetup/nextAppRouter/templates.ts"],"sourcesContent":["/**\n * File templates for a fresh Next.js App Router integration. These are only\n * written when the target file does not exist (or, for the locale layout/page,\n * when the app is effectively empty) — they never overwrite user code.\n */\n\n/** Next.js >= 16 locale-detection proxy (`src/proxy.ts`). */\nexport const PROXY_TEMPLATE = `export { intlayerProxy as proxy } from \"next-intlayer/proxy\";\n\nexport const config = {\n matcher:\n \"/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\\\\\\\..*|_next).*)\",\n};\n`;\n\n/** Next.js < 16 locale-detection middleware (`src/middleware.ts`). */\nexport const MIDDLEWARE_TEMPLATE = `export { intlayerMiddleware as middleware } from \"next-intlayer/middleware\";\n\nexport const config = {\n matcher:\n \"/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\\\\\\\..*|_next).*)\",\n};\n`;\n\n/** Minimal pass-through root layout (`app/layout.tsx`), lets `[locale]/layout` own `<html>`. */\nexport const ROOT_LAYOUT_TEMPLATE_TS = `import type { PropsWithChildren, FC } from \"react\";\n\nconst RootLayout: FC<PropsWithChildren> = ({ children }) => <>{children}</>;\n\nexport default RootLayout;\n`;\n\nexport const ROOT_LAYOUT_TEMPLATE_JS = `const RootLayout = ({ children }) => <>{children}</>;\n\nexport default RootLayout;\n`;\n\n/**\n * Locale layout (`app/[locale]/layout.tsx`) providing `<html>` + the unified\n * provider. `IntlayerProvider` seeds both the server context (read by server\n * hooks and by any page below, without per-page wrapping) and the client\n * provider in one mount.\n */\nexport const LOCALE_LAYOUT_TEMPLATE_TS = `import { type NextLayoutIntlayer } from \"next-intlayer\";\nimport { IntlayerProvider } from \"next-intlayer/server\";\nimport { getHTMLTextDir } from \"intlayer\";\n\nexport { generateStaticParams } from \"next-intlayer\";\n\nconst LocaleLayout: NextLayoutIntlayer = async ({ children, params }) => {\n const { locale } = await params;\n\n return (\n <html lang={locale} dir={getHTMLTextDir(locale)}>\n <body>\n <IntlayerProvider locale={locale}>{children}</IntlayerProvider>\n </body>\n </html>\n );\n};\n\nexport default LocaleLayout;\n`;\n\nexport const LOCALE_LAYOUT_TEMPLATE_JS = `import { IntlayerProvider } from \"next-intlayer/server\";\nimport { getHTMLTextDir } from \"intlayer\";\n\nexport { generateStaticParams } from \"next-intlayer\";\n\nconst LocaleLayout = async ({ children, params }) => {\n const { locale } = await params;\n\n return (\n <html lang={locale} dir={getHTMLTextDir(locale)}>\n <body>\n <IntlayerProvider locale={locale}>{children}</IntlayerProvider>\n </body>\n </html>\n );\n};\n\nexport default LocaleLayout;\n`;\n\n/**\n * Locale home page (`app/[locale]/page.tsx`). Self-contained starter that does\n * not depend on an example content declaration — add Intlayer content (a\n * `*.content.ts` file consumed via `useIntlayer`) as the next step.\n */\nexport const LOCALE_PAGE_TEMPLATE_TS = `import { type NextPageIntlayer } from \"next-intlayer\";\n\nconst Page: NextPageIntlayer = async ({ params }) => {\n const { locale } = await params;\n\n return (\n <main>\n <h1>{locale}</h1>\n <p>Get started by editing this page.</p>\n </main>\n );\n};\n\nexport default Page;\n`;\n\nexport const LOCALE_PAGE_TEMPLATE_JS = `const Page = async ({ params }) => {\n const { locale } = await params;\n\n return (\n <main>\n <h1>{locale}</h1>\n <p>Get started by editing this page.</p>\n </main>\n );\n};\n\nexport default Page;\n`;\n"],"mappings":";;;;;;;;AAOA,MAAa,iBAAiB;;;;;;;;AAS9B,MAAa,sBAAsB;;;;;;;;AASnC,MAAa,0BAA0B;;;;;;AAOvC,MAAa,0BAA0B;;;;;;;;;;AAWvC,MAAa,4BAA4B;;;;;;;;;;;;;;;;;;;;AAqBzC,MAAa,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;AAyBzC,MAAa,0BAA0B;;;;;;;;;;;;;;;AAgBvC,MAAa,0BAA0B"}
1
+ {"version":3,"file":"templates.cjs","names":[],"sources":["../../../../../src/init/frameworkSetup/nextAppRouter/templates.ts"],"sourcesContent":["/**\n * File templates for a fresh Next.js App Router integration. These are only\n * written when the target file does not exist (or, for the locale layout/page,\n * when the app is effectively empty) — they never overwrite user code.\n */\n\n/** Next.js >= 16 locale-detection proxy (`src/proxy.ts`). */\nexport const PROXY_TEMPLATE = `export { intlayerProxy as proxy } from \"next-intlayer/proxy\";\n\nexport const config = {\n matcher:\n \"/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\\\\\\\..*|_next).*)\",\n};\n`;\n\n/** Next.js < 16 locale-detection middleware (`src/middleware.ts`). */\nexport const MIDDLEWARE_TEMPLATE = `export { intlayerMiddleware as middleware } from \"next-intlayer/middleware\";\n\nexport const config = {\n matcher:\n \"/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\\\\\\\..*|_next).*)\",\n};\n`;\n\n/** Minimal pass-through root layout (`app/layout.tsx`), lets `[locale]/layout` own `<html>`. */\nexport const ROOT_LAYOUT_TEMPLATE_TS = `import type { PropsWithChildren, FC } from \"react\";\n\nconst RootLayout: FC<PropsWithChildren> = ({ children }) => <>{children}</>;\n\nexport default RootLayout;\n`;\n\nexport const ROOT_LAYOUT_TEMPLATE_JS = `const RootLayout = ({ children }) => <>{children}</>;\n\nexport default RootLayout;\n`;\n\n/**\n * Locale layout (`app/[locale]/layout.tsx`) providing `<html>` + the unified\n * provider. `IntlayerProvider` seeds both the server context (read by server\n * hooks and by any page below, without per-page wrapping) and the client\n * provider in one mount.\n */\nexport const LOCALE_LAYOUT_TEMPLATE_TS = `import { type NextLayoutIntlayer } from \"next-intlayer\";\nimport { IntlayerProvider } from \"next-intlayer/server\";\nimport { getHTMLTextDir } from \"intlayer\";\n\nexport { generateStaticParams } from \"next-intlayer\";\n\nconst LocaleLayout: NextLayoutIntlayer = async ({ children, params }) => {\n const { locale } = await params;\n\n return (\n <html lang={locale} dir={getHTMLTextDir(locale)}>\n <body>\n <IntlayerProvider locale={locale}>{children}</IntlayerProvider>\n </body>\n </html>\n );\n};\n\nexport default LocaleLayout;\n`;\n\nexport const LOCALE_LAYOUT_TEMPLATE_JS = `import { IntlayerProvider } from \"next-intlayer/server\";\nimport { getHTMLTextDir } from \"intlayer\";\n\nexport { generateStaticParams } from \"next-intlayer\";\n\nconst LocaleLayout = async ({ children, params }) => {\n const { locale } = await params;\n\n return (\n <html lang={locale} dir={getHTMLTextDir(locale)}>\n <body>\n <IntlayerProvider locale={locale}>{children}</IntlayerProvider>\n </body>\n </html>\n );\n};\n\nexport default LocaleLayout;\n`;\n\n/**\n * Locale home page (`app/[locale]/page.tsx`). Self-contained starter that does\n * not depend on an example content declaration — add Intlayer content (a\n * `*.content.ts` file consumed via `useIntlayer`) as the next step.\n */\nexport const LOCALE_PAGE_TEMPLATE_TS = `import { type NextPageIntlayer } from \"next-intlayer\";\n\nconst Page: NextPageIntlayer = async ({ params }) => {\n const { locale } = await params;\n\n return (\n <main>\n <h1>{locale}</h1>\n <p>Get started by editing this page.</p>\n </main>\n );\n};\n\nexport default Page;\n`;\n\nexport const LOCALE_PAGE_TEMPLATE_JS = `const Page = async ({ params }) => {\n const { locale } = await params;\n\n return (\n <main>\n <h1>{locale}</h1>\n <p>Get started by editing this page.</p>\n </main>\n );\n};\n\nexport default Page;\n`;\n\n/**\n * Root layout (`app/layout.tsx`) for routing modes without a locale path\n * segment (`no-prefix`, `search-params`, or no proxy at all). Owns `<html>` and\n * resolves the locale from the request (cookie / header) via `getLocale()`.\n */\nexport const UNPREFIXED_ROOT_LAYOUT_TEMPLATE_TS = `import type { PropsWithChildren } from \"react\";\nimport { getHTMLTextDir } from \"intlayer\";\nimport { getLocale, IntlayerProvider } from \"next-intlayer/server\";\n\nconst RootLayout = async ({ children }: PropsWithChildren) => {\n const locale = await getLocale();\n\n return (\n <html lang={locale} dir={getHTMLTextDir(locale)}>\n <body>\n <IntlayerProvider locale={locale}>{children}</IntlayerProvider>\n </body>\n </html>\n );\n};\n\nexport default RootLayout;\n`;\n\nexport const UNPREFIXED_ROOT_LAYOUT_TEMPLATE_JS = `import { getHTMLTextDir } from \"intlayer\";\nimport { getLocale, IntlayerProvider } from \"next-intlayer/server\";\n\nconst RootLayout = async ({ children }) => {\n const locale = await getLocale();\n\n return (\n <html lang={locale} dir={getHTMLTextDir(locale)}>\n <body>\n <IntlayerProvider locale={locale}>{children}</IntlayerProvider>\n </body>\n </html>\n );\n};\n\nexport default RootLayout;\n`;\n\n/**\n * Home page (`app/page.tsx`) for routing modes without a locale path segment.\n * Identical for TypeScript and JavaScript projects.\n */\nexport const UNPREFIXED_PAGE_TEMPLATE = `const Page = () => (\n <main>\n <h1>Hello</h1>\n <p>Get started by editing this page.</p>\n </main>\n);\n\nexport default Page;\n`;\n"],"mappings":";;;;;;;;AAOA,MAAa,iBAAiB;;;;;;;;AAS9B,MAAa,sBAAsB;;;;;;;;AASnC,MAAa,0BAA0B;;;;;;AAOvC,MAAa,0BAA0B;;;;;;;;;;AAWvC,MAAa,4BAA4B;;;;;;;;;;;;;;;;;;;;AAqBzC,MAAa,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;AAyBzC,MAAa,0BAA0B;;;;;;;;;;;;;;;AAgBvC,MAAa,0BAA0B;;;;;;;;;;;;;;;;;;AAmBvC,MAAa,qCAAqC;;;;;;;;;;;;;;;;;;AAmBlD,MAAa,qCAAqC;;;;;;;;;;;;;;;;;;;;;AAsBlD,MAAa,2BAA2B"}
@@ -91,7 +91,7 @@ const setHtmlLang = (ast) => {
91
91
  * pages below the locale layout read locale/variant from it without wrapping
92
92
  * themselves individually (see the removed `wrapPageWithProvider`).
93
93
  */
94
- const wrapLayoutWithProvider = (code) => {
94
+ const wrapLayoutWithProvider = (code, { exportStaticParams = true } = {}) => {
95
95
  const ast = parseTsx(code);
96
96
  if (isClientComponent(ast)) return {
97
97
  code,
@@ -123,7 +123,7 @@ const wrapLayoutWithProvider = (code) => {
123
123
  };
124
124
  require_init_utils_astImports.ensureNamedImport(ast, "IntlayerProvider", "next-intlayer/server");
125
125
  require_init_utils_astImports.ensureNamedImport(ast, "getLocale", "next-intlayer/server");
126
- ensureExportFrom(ast, "generateStaticParams", "next-intlayer");
126
+ if (exportStaticParams) ensureExportFrom(ast, "generateStaticParams", "next-intlayer");
127
127
  ensureAwaitedLocale(funcNode);
128
128
  setHtmlLang(ast);
129
129
  return {