@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
@@ -1 +1 @@
1
- {"version":3,"file":"configManipulation.cjs","names":[],"sources":["../../../../src/init/utils/configManipulation.ts"],"sourcesContent":["import * as recast from 'recast';\nimport type {\n CompatSyncConfig,\n CompatVitePluginConfig,\n} from './packageManager';\n\nconst { builders: b, namedTypes: n } = recast.types;\n\nconst injectImport = (\n ast: any,\n isCJS: boolean,\n importName: string,\n source: string\n) => {\n const body = ast.program.body;\n const hasImport = body.some((stmt: any) => {\n if (isCJS) {\n return (\n n.VariableDeclaration.check(stmt) &&\n stmt.declarations.some(\n (decl: any) =>\n n.VariableDeclarator.check(decl) &&\n n.CallExpression.check(decl.init) &&\n n.Identifier.check(decl.init.callee) &&\n decl.init.callee.name === 'require' &&\n n.StringLiteral.check(decl.init.arguments[0]) &&\n decl.init.arguments[0].value === source\n )\n );\n }\n return (\n n.ImportDeclaration.check(stmt) &&\n (stmt.source.value === source ||\n stmt.specifiers.some(\n (spec: any) =>\n (n.ImportSpecifier.check(spec) &&\n spec.imported.name === importName) ||\n (n.ImportDefaultSpecifier.check(spec) &&\n spec.local?.name === importName)\n ))\n );\n });\n\n if (hasImport) return;\n\n const declaration = isCJS\n ? b.variableDeclaration('const', [\n b.variableDeclarator(\n b.identifier(`{ ${importName} }`),\n b.callExpression(b.identifier('require'), [b.stringLiteral(source)])\n ),\n ])\n : b.importDeclaration(\n [b.importSpecifier(b.identifier(importName))],\n b.stringLiteral(source)\n );\n\n ast.program.body.unshift(declaration);\n};\n\nconst updatePluginArray = (\n objExpr: any,\n propertyName: string,\n pluginName: string\n) => {\n if (\n !objExpr ||\n (objExpr.type !== 'ObjectExpression' && !n.ObjectExpression.check(objExpr))\n )\n return;\n\n let prop = objExpr.properties.find((p: any) => {\n if (!p?.key) return false;\n const keyName = p.key.name || p.key.value;\n return keyName === propertyName;\n }) as any;\n\n if (!prop) {\n prop = b.property(\n 'init',\n b.identifier(propertyName),\n b.arrayExpression([])\n );\n objExpr.properties.push(prop);\n }\n\n const arrayValue = prop.value;\n\n if (\n arrayValue &&\n (arrayValue.type === 'ArrayExpression' ||\n n.ArrayExpression.check(arrayValue))\n ) {\n const hasPlugin = arrayValue.elements.some((el: any) => {\n const callee = el?.callee;\n if (!callee) return false;\n const name = callee.name || callee.id?.name;\n return name === pluginName || name === 'il';\n });\n\n if (!hasPlugin) {\n arrayValue.elements.push(b.callExpression(b.identifier(pluginName), []));\n }\n }\n};\n\nconst genericRecastVisit = (\n ast: any,\n updateConfigObject: (obj: any) => void,\n callNames: string[] = ['defineConfig']\n) => {\n recast.visit(ast, {\n visitExportDefaultDeclaration(path) {\n const decl = path.node.declaration;\n\n if (n.ObjectExpression.check(decl)) {\n updateConfigObject(decl);\n } else if (\n n.CallExpression.check(decl) &&\n n.Identifier.check(decl.callee) &&\n callNames.includes(decl.callee.name)\n ) {\n if (n.ObjectExpression.check(decl.arguments[0])) {\n updateConfigObject(decl.arguments[0]);\n }\n } else if (n.Identifier.check(decl)) {\n const name = decl.name;\n ast.program.body.forEach((stmt: any) => {\n if (n.VariableDeclaration.check(stmt)) {\n stmt.declarations.forEach((vdecl: any) => {\n if (\n n.VariableDeclarator.check(vdecl) &&\n n.Identifier.check(vdecl.id) &&\n vdecl.id.name === name &&\n n.ObjectExpression.check(vdecl.init)\n ) {\n updateConfigObject(vdecl.init);\n }\n });\n }\n });\n }\n return false;\n },\n visitAssignmentExpression(path) {\n const { left, right } = path.node;\n\n if (\n n.MemberExpression.check(left) &&\n recast.print(left).code === 'module.exports'\n ) {\n if (n.ObjectExpression.check(right)) {\n updateConfigObject(right);\n } else if (\n n.CallExpression.check(right) &&\n n.Identifier.check(right.callee) &&\n callNames.includes(right.callee.name)\n ) {\n if (n.ObjectExpression.check(right.arguments[0])) {\n updateConfigObject(right.arguments[0]);\n }\n }\n }\n return false;\n },\n });\n};\n\nexport const updateViteConfig = (\n content: string,\n extension: string\n): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const isCJSFile =\n extension === 'cjs' ||\n (content.includes('module.exports') && !content.includes('import '));\n\n injectImport(ast, isCJSFile, 'intlayer', 'vite-intlayer');\n\n genericRecastVisit(ast, (obj) =>\n updatePluginArray(obj, 'plugins', 'intlayer')\n );\n\n return recast.print(ast).code;\n};\n\nexport const updateAstroConfig = (\n content: string,\n extension: string\n): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const isCJSFile =\n extension === 'cjs' ||\n (content.includes('module.exports') && !content.includes('import '));\n\n injectImport(ast, isCJSFile, 'intlayer', 'astro-intlayer');\n\n genericRecastVisit(ast, (obj) =>\n updatePluginArray(obj, 'integrations', 'intlayer')\n );\n\n return recast.print(ast).code;\n};\n\nexport const updateNextConfig = (\n content: string,\n extension: string\n): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const isCJSFile = extension === 'cjs' || content.includes('module.exports');\n\n injectImport(ast, isCJSFile, 'withIntlayer', 'next-intlayer/server');\n\n recast.visit(ast, {\n visitExportDefaultDeclaration(path) {\n const declaration = path.node.declaration;\n if (\n n.Expression.check(declaration) &&\n !(\n n.CallExpression.check(declaration) &&\n n.Identifier.check(declaration.callee) &&\n declaration.callee.name === 'withIntlayer'\n )\n ) {\n path\n .get('declaration')\n .replace(\n b.callExpression(b.identifier('withIntlayer'), [declaration as any])\n );\n }\n return false;\n },\n visitAssignmentExpression(path) {\n const { left, right } = path.node;\n\n if (\n n.MemberExpression.check(left) &&\n recast.print(left).code === 'module.exports' &&\n !(\n n.CallExpression.check(right) &&\n n.Identifier.check(right.callee) &&\n right.callee.name === 'withIntlayer'\n )\n ) {\n path\n .get('right')\n .replace(b.callExpression(b.identifier('withIntlayer'), [right]));\n }\n return false;\n },\n });\n\n return recast.print(ast).code;\n};\n\nexport const updateNuxtConfig = (content: string): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const updateConfigObject = (objExpr: any) => {\n if (\n !objExpr ||\n (objExpr.type !== 'ObjectExpression' &&\n !n.ObjectExpression.check(objExpr))\n )\n return;\n\n let modulesProp = objExpr.properties.find((p: any) => {\n if (!p?.key) return false;\n const keyName = p.key.name || p.key.value;\n return keyName === 'modules';\n }) as any;\n\n if (!modulesProp) {\n modulesProp = b.property(\n 'init',\n b.identifier('modules'),\n b.arrayExpression([])\n );\n objExpr.properties.push(modulesProp);\n }\n\n const modulesValue = modulesProp.value;\n\n if (\n modulesValue &&\n (modulesValue.type === 'ArrayExpression' ||\n n.ArrayExpression.check(modulesValue))\n ) {\n const hasModule = modulesValue.elements.some((el: any) => {\n if (\n n.StringLiteral.check(el) ||\n el.type === 'StringLiteral' ||\n el.type === 'Literal'\n ) {\n return (el.value || el.extra?.rawValue) === 'nuxt-intlayer';\n }\n return false;\n });\n\n if (!hasModule) {\n modulesValue.elements.push(b.stringLiteral('nuxt-intlayer'));\n }\n }\n };\n\n genericRecastVisit(ast, updateConfigObject, ['defineNuxtConfig']);\n\n return recast.print(ast).code;\n};\n\n/**\n * Updates a Vite config for vue-i18n compat: injects `vueI18nVitePlugin` from\n * `@intlayer/vue-i18n/plugin` into the plugins array.\n */\nexport const updateViteConfigForVueI18n = (\n content: string,\n extension: string\n): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const isCJSFile =\n extension === 'cjs' ||\n (content.includes('module.exports') && !content.includes('import '));\n\n injectImport(\n ast,\n isCJSFile,\n 'vueI18nVitePlugin',\n '@intlayer/vue-i18n/plugin'\n );\n\n genericRecastVisit(ast, (obj) =>\n updatePluginArray(obj, 'plugins', 'vueI18nVitePlugin')\n );\n\n return recast.print(ast).code;\n};\n\n/**\n * Generic vite config updater for any compat plugin that uses alias injection.\n * Injects the named import from `pluginPackageSource` and appends the plugin\n * call to the `plugins` array.\n */\nexport const updateViteConfigForCompatPlugin = (\n content: string,\n extension: string,\n pluginConfig: CompatVitePluginConfig\n): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const isCJSFile =\n extension === 'cjs' ||\n (content.includes('module.exports') && !content.includes('import '));\n\n injectImport(\n ast,\n isCJSFile,\n pluginConfig.pluginFunctionName,\n pluginConfig.pluginPackageSource\n );\n\n genericRecastVisit(ast, (obj) =>\n updatePluginArray(obj, 'plugins', pluginConfig.pluginFunctionName)\n );\n\n return recast.print(ast).code;\n};\n\n/**\n * Generic Next.js config wrapper for compat plugins. Injects the import and\n * wraps the default export / `module.exports` with a HOC call.\n */\nconst wrapNextConfigWithHoc = (\n content: string,\n extension: string,\n hocFunctionName: string,\n pluginPackageSource: string\n): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const isCJSFile = extension === 'cjs' || content.includes('module.exports');\n\n injectImport(ast, isCJSFile, hocFunctionName, pluginPackageSource);\n\n recast.visit(ast, {\n visitExportDefaultDeclaration(path) {\n const declaration = path.node.declaration;\n if (\n n.Expression.check(declaration) &&\n !(\n n.CallExpression.check(declaration) &&\n n.Identifier.check(declaration.callee) &&\n declaration.callee.name === hocFunctionName\n )\n ) {\n path\n .get('declaration')\n .replace(\n b.callExpression(b.identifier(hocFunctionName), [\n declaration as any,\n ])\n );\n }\n return false;\n },\n visitAssignmentExpression(path) {\n const { left, right } = path.node;\n\n if (\n n.MemberExpression.check(left) &&\n recast.print(left).code === 'module.exports' &&\n !(\n n.CallExpression.check(right) &&\n n.Identifier.check(right.callee) &&\n right.callee.name === hocFunctionName\n )\n ) {\n path\n .get('right')\n .replace(b.callExpression(b.identifier(hocFunctionName), [right]));\n }\n return false;\n },\n });\n\n return recast.print(ast).code;\n};\n\n/**\n * Updates a Next.js config for next-translate compat: wraps the default export\n * with `withNextTranslate` from `@intlayer/next-translate/plugin`.\n */\nexport const updateNextConfigForNextTranslate = (\n content: string,\n extension: string\n): string =>\n wrapNextConfigWithHoc(\n content,\n extension,\n 'withNextTranslate',\n '@intlayer/next-translate/plugin'\n );\n\n/**\n * Updates a Nuxt config for nuxtjs-i18n compat: adds `@intlayer/nuxtjs-i18n`\n * to the `modules` array.\n */\nexport const updateNuxtConfigForNuxtjsI18n = (content: string): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const updateConfigObject = (objExpr: any) => {\n if (\n !objExpr ||\n (objExpr.type !== 'ObjectExpression' &&\n !n.ObjectExpression.check(objExpr))\n )\n return;\n\n let modulesProp = (objExpr.properties as any[]).find((p: any) => {\n if (!p?.key) return false;\n const keyName = p.key.name || p.key.value;\n return keyName === 'modules';\n }) as any;\n\n if (!modulesProp) {\n modulesProp = b.property(\n 'init',\n b.identifier('modules'),\n b.arrayExpression([])\n );\n (objExpr.properties as any[]).push(modulesProp);\n }\n\n const modulesValue = modulesProp.value;\n\n if (\n modulesValue &&\n (modulesValue.type === 'ArrayExpression' ||\n n.ArrayExpression.check(modulesValue))\n ) {\n const hasModule = (modulesValue.elements as any[]).some((el: any) => {\n if (\n n.StringLiteral.check(el) ||\n el.type === 'StringLiteral' ||\n el.type === 'Literal'\n ) {\n return (el.value ?? el.extra?.rawValue) === '@intlayer/nuxtjs-i18n';\n }\n return false;\n });\n\n if (!hasModule) {\n (modulesValue.elements as any[]).push(\n b.stringLiteral('@intlayer/nuxtjs-i18n')\n );\n }\n }\n };\n\n genericRecastVisit(ast, updateConfigObject, ['defineNuxtConfig']);\n\n return recast.print(ast).code;\n};\n\n/**\n * Updates a Next.js config for next-i18next compat: wraps the default export\n * with `withI18next` from `@intlayer/next-i18next/plugin`.\n */\nexport const updateNextConfigForNextI18next = (\n content: string,\n extension: string\n): string =>\n wrapNextConfigWithHoc(\n content,\n extension,\n 'withI18next',\n '@intlayer/next-i18next/plugin'\n );\n\n/**\n * Updates a Next.js config for next-intl compat: replaces any existing\n * `next-intl/plugin` import source with `@intlayer/next-intl/plugin`, or\n * injects `createNextIntlPlugin` with a factory-call wrapper when no such\n * import is present.\n */\nexport const updateNextConfigForNextIntl = (\n content: string,\n extension: string\n): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const isCJSFile = extension === 'cjs' || content.includes('module.exports');\n let replacedExistingSource = false;\n\n // Replace 'next-intl/plugin' import source with the compat package.\n recast.visit(ast, {\n visitImportDeclaration(path) {\n if (path.node.source.value === 'next-intl/plugin') {\n path.node.source = b.stringLiteral('@intlayer/next-intl/plugin');\n replacedExistingSource = true;\n }\n return false;\n },\n });\n\n if (replacedExistingSource) {\n return recast.print(ast).code;\n }\n\n // No existing next-intl/plugin import: check whether createNextIntlPlugin is\n // already present from any source before injecting the full factory pattern.\n const hasCreatePlugin = (ast.program.body as any[]).some((stmt: any) => {\n if (!n.ImportDeclaration.check(stmt)) return false;\n return (stmt.specifiers ?? []).some(\n (spec: any) =>\n (n.ImportSpecifier.check(spec) &&\n spec.imported.name === 'createNextIntlPlugin') ||\n (n.ImportDefaultSpecifier.check(spec) &&\n spec.local?.name === 'createNextIntlPlugin')\n );\n });\n\n if (hasCreatePlugin) {\n return recast.print(ast).code;\n }\n\n // Inject the import.\n injectImport(\n ast,\n isCJSFile,\n 'createNextIntlPlugin',\n '@intlayer/next-intl/plugin'\n );\n\n // Insert a factory-call variable declaration after the last import.\n const lastImportIndex = (ast.program.body as any[]).reduce(\n (lastIndex: number, stmt: any, index: number) => {\n if (n.ImportDeclaration.check(stmt)) return index;\n return lastIndex;\n },\n -1\n );\n\n const factoryCallDeclaration = b.variableDeclaration('const', [\n b.variableDeclarator(\n b.identifier('_withNextIntlayer'),\n b.callExpression(b.identifier('createNextIntlPlugin'), [])\n ),\n ]);\n\n (ast.program.body as any[]).splice(\n lastImportIndex + 1,\n 0,\n factoryCallDeclaration\n );\n\n // Wrap the default export with _withNextIntlayer(...).\n recast.visit(ast, {\n visitExportDefaultDeclaration(path) {\n const declaration = path.node.declaration;\n if (\n n.Expression.check(declaration) &&\n !(\n n.CallExpression.check(declaration) &&\n n.Identifier.check(declaration.callee) &&\n declaration.callee.name === '_withNextIntlayer'\n )\n ) {\n path\n .get('declaration')\n .replace(\n b.callExpression(b.identifier('_withNextIntlayer'), [\n declaration as any,\n ])\n );\n }\n return false;\n },\n visitAssignmentExpression(path) {\n const { left, right } = path.node;\n\n if (\n n.MemberExpression.check(left) &&\n recast.print(left).code === 'module.exports' &&\n !(\n n.CallExpression.check(right) &&\n n.Identifier.check(right.callee) &&\n right.callee.name === '_withNextIntlayer'\n )\n ) {\n path\n .get('right')\n .replace(\n b.callExpression(b.identifier('_withNextIntlayer'), [right])\n );\n }\n return false;\n },\n });\n\n return recast.print(ast).code;\n};\n\n/**\n * Parses a syncJSON({ ... }) call expression from a source snippet so it can\n * be injected into a config AST without manually constructing template-literal\n * nodes via builders.\n *\n * The destructuring parameters adapt to whether the source template uses the\n * `key` placeholder (nested pattern) or only `locale` (flat pattern).\n */\nconst buildSyncJSONCallNode = (syncConfig: CompatSyncConfig): any => {\n const usesKey = syncConfig.sourceTemplate.includes('${key}');\n const paramDestructuring =\n syncConfig.format === 'icu'\n ? usesKey\n ? '{ key, locale }'\n : '{ locale }'\n : usesKey\n ? '{ locale, key }'\n : '{ locale }';\n\n // The sourceTemplate contains ${locale} / ${key} as literal characters;\n // they become proper template expressions once the snippet is parsed by recast.\n const snippet = `syncJSON({ format: '${syncConfig.format}', source: (${paramDestructuring}) => \\`${syncConfig.sourceTemplate}\\` })`;\n const snippetAst = recast.parse(snippet, {\n parser: require('recast/parsers/typescript'),\n });\n return (snippetAst.program.body[0] as any).expression;\n};\n\n/**\n * Injects or ensures `dictionary: { format: '<value>' }` exists in an object\n * expression. Leaves any pre-existing `dictionary` properties untouched —\n * only the `format` sub-property is added when absent.\n */\nconst injectDictionaryFormat = (objExpr: any, format: string): void => {\n if (\n !objExpr ||\n (objExpr.type !== 'ObjectExpression' && !n.ObjectExpression.check(objExpr))\n )\n return;\n\n let dictionaryProp = (objExpr.properties as any[]).find((prop: any) => {\n if (!prop?.key) return false;\n return (prop.key.name ?? prop.key.value) === 'dictionary';\n });\n\n if (!dictionaryProp) {\n dictionaryProp = b.property(\n 'init',\n b.identifier('dictionary'),\n b.objectExpression([])\n );\n (objExpr.properties as any[]).push(dictionaryProp);\n }\n\n const dictionaryObj = dictionaryProp.value;\n if (\n !dictionaryObj ||\n (dictionaryObj.type !== 'ObjectExpression' &&\n !n.ObjectExpression.check(dictionaryObj))\n )\n return;\n\n const hasFormat = (dictionaryObj.properties as any[]).some((prop: any) => {\n if (!prop?.key) return false;\n return (prop.key.name ?? prop.key.value) === 'format';\n });\n\n if (!hasFormat) {\n (dictionaryObj.properties as any[]).push(\n b.property('init', b.identifier('format'), b.stringLiteral(format))\n );\n }\n};\n\n/**\n * Injects the syncJSON import and a configured syncJSON(...) call into the\n * plugins array of an intlayer config file. Idempotent: skips when\n * @intlayer/sync-json-plugin is already imported.\n */\nexport const updateIntlayerConfigWithSyncPlugin = (\n content: string,\n extension: string,\n syncConfig: CompatSyncConfig\n): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const isCJSFile = extension === 'cjs' || content.includes('module.exports');\n\n injectImport(ast, isCJSFile, 'syncJSON', '@intlayer/sync-json-plugin');\n\n const callNode = buildSyncJSONCallNode(syncConfig);\n\n genericRecastVisit(ast, (objExpr) => {\n if (\n !objExpr ||\n (objExpr.type !== 'ObjectExpression' &&\n !n.ObjectExpression.check(objExpr))\n )\n return;\n\n // Inject dictionary.format alongside the plugin so intlayer knows how to\n // interpret dictionary content at runtime.\n injectDictionaryFormat(objExpr, syncConfig.format);\n\n let pluginsProp = (objExpr.properties as any[]).find((prop: any) => {\n if (!prop?.key) return false;\n const keyName = prop.key.name ?? prop.key.value;\n return keyName === 'plugins';\n });\n\n if (!pluginsProp) {\n pluginsProp = b.property(\n 'init',\n b.identifier('plugins'),\n b.arrayExpression([])\n );\n (objExpr.properties as any[]).push(pluginsProp);\n }\n\n const arrayValue = pluginsProp.value;\n\n if (\n arrayValue &&\n (arrayValue.type === 'ArrayExpression' ||\n n.ArrayExpression.check(arrayValue))\n ) {\n const hasSyncJSON = (arrayValue.elements as any[]).some(\n (element: any) => {\n const callee = element?.callee;\n if (!callee) return false;\n const name: string = callee.name ?? callee.id?.name;\n return name === 'syncJSON';\n }\n );\n\n if (!hasSyncJSON) {\n (arrayValue.elements as any[]).push(callNode);\n }\n }\n });\n\n return recast.print(ast).code;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"configManipulation.cjs","names":[],"sources":["../../../../src/init/utils/configManipulation.ts"],"sourcesContent":["import * as recast from 'recast';\nimport type {\n CompatSyncConfig,\n CompatVitePluginConfig,\n} from './packageManager';\n\nconst { builders: b, namedTypes: n } = recast.types;\n\nconst injectImport = (\n ast: any,\n isCJS: boolean,\n importName: string,\n source: string\n) => {\n const body = ast.program.body;\n const hasImport = body.some((stmt: any) => {\n if (isCJS) {\n return (\n n.VariableDeclaration.check(stmt) &&\n stmt.declarations.some(\n (decl: any) =>\n n.VariableDeclarator.check(decl) &&\n n.CallExpression.check(decl.init) &&\n n.Identifier.check(decl.init.callee) &&\n decl.init.callee.name === 'require' &&\n n.StringLiteral.check(decl.init.arguments[0]) &&\n decl.init.arguments[0].value === source\n )\n );\n }\n return (\n n.ImportDeclaration.check(stmt) &&\n (stmt.source.value === source ||\n stmt.specifiers.some(\n (spec: any) =>\n (n.ImportSpecifier.check(spec) &&\n spec.imported.name === importName) ||\n (n.ImportDefaultSpecifier.check(spec) &&\n spec.local?.name === importName)\n ))\n );\n });\n\n if (hasImport) return;\n\n const declaration = isCJS\n ? b.variableDeclaration('const', [\n b.variableDeclarator(\n b.identifier(`{ ${importName} }`),\n b.callExpression(b.identifier('require'), [b.stringLiteral(source)])\n ),\n ])\n : b.importDeclaration(\n [b.importSpecifier(b.identifier(importName))],\n b.stringLiteral(source)\n );\n\n ast.program.body.unshift(declaration);\n};\n\nconst updatePluginArray = (\n objExpr: any,\n propertyName: string,\n pluginName: string\n) => {\n if (\n !objExpr ||\n (objExpr.type !== 'ObjectExpression' && !n.ObjectExpression.check(objExpr))\n )\n return;\n\n let prop = objExpr.properties.find((p: any) => {\n if (!p?.key) return false;\n const keyName = p.key.name || p.key.value;\n return keyName === propertyName;\n }) as any;\n\n if (!prop) {\n prop = b.property(\n 'init',\n b.identifier(propertyName),\n b.arrayExpression([])\n );\n objExpr.properties.push(prop);\n }\n\n const arrayValue = prop.value;\n\n if (\n arrayValue &&\n (arrayValue.type === 'ArrayExpression' ||\n n.ArrayExpression.check(arrayValue))\n ) {\n const hasPlugin = arrayValue.elements.some((el: any) => {\n const callee = el?.callee;\n if (!callee) return false;\n const name = callee.name || callee.id?.name;\n return name === pluginName || name === 'il';\n });\n\n if (!hasPlugin) {\n arrayValue.elements.push(b.callExpression(b.identifier(pluginName), []));\n }\n }\n};\n\nconst genericRecastVisit = (\n ast: any,\n updateConfigObject: (obj: any) => void,\n callNames: string[] = ['defineConfig']\n) => {\n recast.visit(ast, {\n visitExportDefaultDeclaration(path) {\n const decl = path.node.declaration;\n\n if (n.ObjectExpression.check(decl)) {\n updateConfigObject(decl);\n } else if (\n n.CallExpression.check(decl) &&\n n.Identifier.check(decl.callee) &&\n callNames.includes(decl.callee.name)\n ) {\n if (n.ObjectExpression.check(decl.arguments[0])) {\n updateConfigObject(decl.arguments[0]);\n }\n } else if (n.Identifier.check(decl)) {\n const name = decl.name;\n ast.program.body.forEach((stmt: any) => {\n if (n.VariableDeclaration.check(stmt)) {\n stmt.declarations.forEach((vdecl: any) => {\n if (\n n.VariableDeclarator.check(vdecl) &&\n n.Identifier.check(vdecl.id) &&\n vdecl.id.name === name &&\n n.ObjectExpression.check(vdecl.init)\n ) {\n updateConfigObject(vdecl.init);\n }\n });\n }\n });\n }\n return false;\n },\n visitAssignmentExpression(path) {\n const { left, right } = path.node;\n\n if (\n n.MemberExpression.check(left) &&\n recast.print(left).code === 'module.exports'\n ) {\n if (n.ObjectExpression.check(right)) {\n updateConfigObject(right);\n } else if (\n n.CallExpression.check(right) &&\n n.Identifier.check(right.callee) &&\n callNames.includes(right.callee.name)\n ) {\n if (n.ObjectExpression.check(right.arguments[0])) {\n updateConfigObject(right.arguments[0]);\n }\n }\n }\n return false;\n },\n });\n};\n\nexport const updateViteConfig = (\n content: string,\n extension: string\n): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const isCJSFile =\n extension === 'cjs' ||\n (content.includes('module.exports') && !content.includes('import '));\n\n injectImport(ast, isCJSFile, 'intlayer', 'vite-intlayer');\n\n genericRecastVisit(ast, (obj) =>\n updatePluginArray(obj, 'plugins', 'intlayer')\n );\n\n return recast.print(ast).code;\n};\n\nexport const updateAstroConfig = (\n content: string,\n extension: string\n): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const isCJSFile =\n extension === 'cjs' ||\n (content.includes('module.exports') && !content.includes('import '));\n\n injectImport(ast, isCJSFile, 'intlayer', 'astro-intlayer');\n\n genericRecastVisit(ast, (obj) =>\n updatePluginArray(obj, 'integrations', 'intlayer')\n );\n\n return recast.print(ast).code;\n};\n\nexport const updateNextConfig = (\n content: string,\n extension: string\n): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const isCJSFile = extension === 'cjs' || content.includes('module.exports');\n\n injectImport(ast, isCJSFile, 'withIntlayer', 'next-intlayer/server');\n\n recast.visit(ast, {\n visitExportDefaultDeclaration(path) {\n const declaration = path.node.declaration;\n if (\n n.Expression.check(declaration) &&\n !(\n n.CallExpression.check(declaration) &&\n n.Identifier.check(declaration.callee) &&\n declaration.callee.name === 'withIntlayer'\n )\n ) {\n path\n .get('declaration')\n .replace(\n b.callExpression(b.identifier('withIntlayer'), [declaration as any])\n );\n }\n return false;\n },\n visitAssignmentExpression(path) {\n const { left, right } = path.node;\n\n if (\n n.MemberExpression.check(left) &&\n recast.print(left).code === 'module.exports' &&\n !(\n n.CallExpression.check(right) &&\n n.Identifier.check(right.callee) &&\n right.callee.name === 'withIntlayer'\n )\n ) {\n path\n .get('right')\n .replace(b.callExpression(b.identifier('withIntlayer'), [right]));\n }\n return false;\n },\n });\n\n return recast.print(ast).code;\n};\n\nexport const updateNuxtConfig = (content: string): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const updateConfigObject = (objExpr: any) => {\n if (\n !objExpr ||\n (objExpr.type !== 'ObjectExpression' &&\n !n.ObjectExpression.check(objExpr))\n )\n return;\n\n let modulesProp = objExpr.properties.find((p: any) => {\n if (!p?.key) return false;\n const keyName = p.key.name || p.key.value;\n return keyName === 'modules';\n }) as any;\n\n if (!modulesProp) {\n modulesProp = b.property(\n 'init',\n b.identifier('modules'),\n b.arrayExpression([])\n );\n objExpr.properties.push(modulesProp);\n }\n\n const modulesValue = modulesProp.value;\n\n if (\n modulesValue &&\n (modulesValue.type === 'ArrayExpression' ||\n n.ArrayExpression.check(modulesValue))\n ) {\n const hasModule = modulesValue.elements.some((el: any) => {\n if (\n n.StringLiteral.check(el) ||\n el.type === 'StringLiteral' ||\n el.type === 'Literal'\n ) {\n return (el.value || el.extra?.rawValue) === 'nuxt-intlayer';\n }\n return false;\n });\n\n if (!hasModule) {\n modulesValue.elements.push(b.stringLiteral('nuxt-intlayer'));\n }\n }\n };\n\n genericRecastVisit(ast, updateConfigObject, ['defineNuxtConfig']);\n\n return recast.print(ast).code;\n};\n\n/**\n * Updates a Vite config for vue-i18n compat: injects `vueI18nVitePlugin` from\n * `@intlayer/vue-i18n/plugin` into the plugins array.\n */\nexport const updateViteConfigForVueI18n = (\n content: string,\n extension: string\n): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const isCJSFile =\n extension === 'cjs' ||\n (content.includes('module.exports') && !content.includes('import '));\n\n injectImport(\n ast,\n isCJSFile,\n 'vueI18nVitePlugin',\n '@intlayer/vue-i18n/plugin'\n );\n\n genericRecastVisit(ast, (obj) =>\n updatePluginArray(obj, 'plugins', 'vueI18nVitePlugin')\n );\n\n return recast.print(ast).code;\n};\n\n/**\n * Generic vite config updater for any compat plugin that uses alias injection.\n * Injects the named import from `pluginPackageSource` and appends the plugin\n * call to the `plugins` array.\n */\nexport const updateViteConfigForCompatPlugin = (\n content: string,\n extension: string,\n pluginConfig: CompatVitePluginConfig\n): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const isCJSFile =\n extension === 'cjs' ||\n (content.includes('module.exports') && !content.includes('import '));\n\n injectImport(\n ast,\n isCJSFile,\n pluginConfig.pluginFunctionName,\n pluginConfig.pluginPackageSource\n );\n\n genericRecastVisit(ast, (obj) =>\n updatePluginArray(obj, 'plugins', pluginConfig.pluginFunctionName)\n );\n\n return recast.print(ast).code;\n};\n\n/**\n * Generic Next.js config wrapper for compat plugins. Injects the import and\n * wraps the default export / `module.exports` with a HOC call.\n */\nconst wrapNextConfigWithHoc = (\n content: string,\n extension: string,\n hocFunctionName: string,\n pluginPackageSource: string\n): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const isCJSFile = extension === 'cjs' || content.includes('module.exports');\n\n injectImport(ast, isCJSFile, hocFunctionName, pluginPackageSource);\n\n recast.visit(ast, {\n visitExportDefaultDeclaration(path) {\n const declaration = path.node.declaration;\n if (\n n.Expression.check(declaration) &&\n !(\n n.CallExpression.check(declaration) &&\n n.Identifier.check(declaration.callee) &&\n declaration.callee.name === hocFunctionName\n )\n ) {\n path\n .get('declaration')\n .replace(\n b.callExpression(b.identifier(hocFunctionName), [\n declaration as any,\n ])\n );\n }\n return false;\n },\n visitAssignmentExpression(path) {\n const { left, right } = path.node;\n\n if (\n n.MemberExpression.check(left) &&\n recast.print(left).code === 'module.exports' &&\n !(\n n.CallExpression.check(right) &&\n n.Identifier.check(right.callee) &&\n right.callee.name === hocFunctionName\n )\n ) {\n path\n .get('right')\n .replace(b.callExpression(b.identifier(hocFunctionName), [right]));\n }\n return false;\n },\n });\n\n return recast.print(ast).code;\n};\n\n/**\n * Updates a Next.js config for next-translate compat: wraps the default export\n * with `withNextTranslate` from `@intlayer/next-translate/plugin`.\n */\nexport const updateNextConfigForNextTranslate = (\n content: string,\n extension: string\n): string =>\n wrapNextConfigWithHoc(\n content,\n extension,\n 'withNextTranslate',\n '@intlayer/next-translate/plugin'\n );\n\n/**\n * Updates a Nuxt config for nuxtjs-i18n compat: adds `@intlayer/nuxtjs-i18n`\n * to the `modules` array.\n */\nexport const updateNuxtConfigForNuxtjsI18n = (content: string): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const updateConfigObject = (objExpr: any) => {\n if (\n !objExpr ||\n (objExpr.type !== 'ObjectExpression' &&\n !n.ObjectExpression.check(objExpr))\n )\n return;\n\n let modulesProp = (objExpr.properties as any[]).find((p: any) => {\n if (!p?.key) return false;\n const keyName = p.key.name || p.key.value;\n return keyName === 'modules';\n }) as any;\n\n if (!modulesProp) {\n modulesProp = b.property(\n 'init',\n b.identifier('modules'),\n b.arrayExpression([])\n );\n (objExpr.properties as any[]).push(modulesProp);\n }\n\n const modulesValue = modulesProp.value;\n\n if (\n modulesValue &&\n (modulesValue.type === 'ArrayExpression' ||\n n.ArrayExpression.check(modulesValue))\n ) {\n const hasModule = (modulesValue.elements as any[]).some((el: any) => {\n if (\n n.StringLiteral.check(el) ||\n el.type === 'StringLiteral' ||\n el.type === 'Literal'\n ) {\n return (el.value ?? el.extra?.rawValue) === '@intlayer/nuxtjs-i18n';\n }\n return false;\n });\n\n if (!hasModule) {\n (modulesValue.elements as any[]).push(\n b.stringLiteral('@intlayer/nuxtjs-i18n')\n );\n }\n }\n };\n\n genericRecastVisit(ast, updateConfigObject, ['defineNuxtConfig']);\n\n return recast.print(ast).code;\n};\n\n/**\n * Updates a Next.js config for next-i18next compat: wraps the default export\n * with `withI18next` from `@intlayer/next-i18next/plugin`.\n */\nexport const updateNextConfigForNextI18next = (\n content: string,\n extension: string\n): string =>\n wrapNextConfigWithHoc(\n content,\n extension,\n 'withI18next',\n '@intlayer/next-i18next/plugin'\n );\n\n/**\n * Updates a Next.js config for next-intl compat: replaces any existing\n * `next-intl/plugin` import source with `@intlayer/next-intl/plugin`, or\n * injects `createNextIntlPlugin` with a factory-call wrapper when no such\n * import is present.\n */\nexport const updateNextConfigForNextIntl = (\n content: string,\n extension: string\n): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const isCJSFile = extension === 'cjs' || content.includes('module.exports');\n let replacedExistingSource = false;\n\n // Replace 'next-intl/plugin' import source with the compat package.\n recast.visit(ast, {\n visitImportDeclaration(path) {\n if (path.node.source.value === 'next-intl/plugin') {\n path.node.source = b.stringLiteral('@intlayer/next-intl/plugin');\n replacedExistingSource = true;\n }\n return false;\n },\n });\n\n if (replacedExistingSource) {\n return recast.print(ast).code;\n }\n\n // No existing next-intl/plugin import: check whether createNextIntlPlugin is\n // already present from any source before injecting the full factory pattern.\n const hasCreatePlugin = (ast.program.body as any[]).some((stmt: any) => {\n if (!n.ImportDeclaration.check(stmt)) return false;\n return (stmt.specifiers ?? []).some(\n (spec: any) =>\n (n.ImportSpecifier.check(spec) &&\n spec.imported.name === 'createNextIntlPlugin') ||\n (n.ImportDefaultSpecifier.check(spec) &&\n spec.local?.name === 'createNextIntlPlugin')\n );\n });\n\n if (hasCreatePlugin) {\n return recast.print(ast).code;\n }\n\n // Inject the import.\n injectImport(\n ast,\n isCJSFile,\n 'createNextIntlPlugin',\n '@intlayer/next-intl/plugin'\n );\n\n // Insert a factory-call variable declaration after the last import.\n const lastImportIndex = (ast.program.body as any[]).reduce(\n (lastIndex: number, stmt: any, index: number) => {\n if (n.ImportDeclaration.check(stmt)) return index;\n return lastIndex;\n },\n -1\n );\n\n const factoryCallDeclaration = b.variableDeclaration('const', [\n b.variableDeclarator(\n b.identifier('_withNextIntlayer'),\n b.callExpression(b.identifier('createNextIntlPlugin'), [])\n ),\n ]);\n\n (ast.program.body as any[]).splice(\n lastImportIndex + 1,\n 0,\n factoryCallDeclaration\n );\n\n // Wrap the default export with _withNextIntlayer(...).\n recast.visit(ast, {\n visitExportDefaultDeclaration(path) {\n const declaration = path.node.declaration;\n if (\n n.Expression.check(declaration) &&\n !(\n n.CallExpression.check(declaration) &&\n n.Identifier.check(declaration.callee) &&\n declaration.callee.name === '_withNextIntlayer'\n )\n ) {\n path\n .get('declaration')\n .replace(\n b.callExpression(b.identifier('_withNextIntlayer'), [\n declaration as any,\n ])\n );\n }\n return false;\n },\n visitAssignmentExpression(path) {\n const { left, right } = path.node;\n\n if (\n n.MemberExpression.check(left) &&\n recast.print(left).code === 'module.exports' &&\n !(\n n.CallExpression.check(right) &&\n n.Identifier.check(right.callee) &&\n right.callee.name === '_withNextIntlayer'\n )\n ) {\n path\n .get('right')\n .replace(\n b.callExpression(b.identifier('_withNextIntlayer'), [right])\n );\n }\n return false;\n },\n });\n\n return recast.print(ast).code;\n};\n\n/**\n * Parses a syncJSON({ ... }) call expression from a source snippet so it can\n * be injected into a config AST without manually constructing template-literal\n * nodes via builders.\n *\n * The destructuring parameters adapt to whether the source template uses the\n * `key` placeholder (nested pattern) or only `locale` (flat pattern).\n */\nconst buildSyncJSONCallNode = (syncConfig: CompatSyncConfig): any => {\n const usesKey = syncConfig.sourceTemplate.includes('${key}');\n const paramDestructuring =\n syncConfig.format === 'icu'\n ? usesKey\n ? '{ key, locale }'\n : '{ locale }'\n : usesKey\n ? '{ locale, key }'\n : '{ locale }';\n\n // `splitKeys` is written explicitly only when forced on (next-intl / use-intl\n // single-file namespace model). When omitted, syncJSON auto-detects it from\n // the presence of a `${key}` segment in the source.\n const splitKeysProperty = syncConfig.splitKeys ? ', splitKeys: true' : '';\n\n // The sourceTemplate contains ${locale} / ${key} as literal characters;\n // they become proper template expressions once the snippet is parsed by recast.\n const snippet = `syncJSON({ format: '${syncConfig.format}', source: (${paramDestructuring}) => \\`${syncConfig.sourceTemplate}\\`${splitKeysProperty} })`;\n const snippetAst = recast.parse(snippet, {\n parser: require('recast/parsers/typescript'),\n });\n return (snippetAst.program.body[0] as any).expression;\n};\n\n/**\n * Injects or ensures `dictionary: { format: '<value>' }` exists in an object\n * expression. Leaves any pre-existing `dictionary` properties untouched —\n * only the `format` sub-property is added when absent.\n */\nconst injectDictionaryFormat = (objExpr: any, format: string): void => {\n if (\n !objExpr ||\n (objExpr.type !== 'ObjectExpression' && !n.ObjectExpression.check(objExpr))\n )\n return;\n\n let dictionaryProp = (objExpr.properties as any[]).find((prop: any) => {\n if (!prop?.key) return false;\n return (prop.key.name ?? prop.key.value) === 'dictionary';\n });\n\n if (!dictionaryProp) {\n dictionaryProp = b.property(\n 'init',\n b.identifier('dictionary'),\n b.objectExpression([])\n );\n (objExpr.properties as any[]).push(dictionaryProp);\n }\n\n const dictionaryObj = dictionaryProp.value;\n if (\n !dictionaryObj ||\n (dictionaryObj.type !== 'ObjectExpression' &&\n !n.ObjectExpression.check(dictionaryObj))\n )\n return;\n\n const hasFormat = (dictionaryObj.properties as any[]).some((prop: any) => {\n if (!prop?.key) return false;\n return (prop.key.name ?? prop.key.value) === 'format';\n });\n\n if (!hasFormat) {\n (dictionaryObj.properties as any[]).push(\n b.property('init', b.identifier('format'), b.stringLiteral(format))\n );\n }\n};\n\n/**\n * Injects the syncJSON import and a configured syncJSON(...) call into the\n * plugins array of an intlayer config file. Idempotent: skips when\n * @intlayer/sync-json-plugin is already imported.\n */\nexport const updateIntlayerConfigWithSyncPlugin = (\n content: string,\n extension: string,\n syncConfig: CompatSyncConfig\n): string => {\n const ast = recast.parse(content, {\n parser: require('recast/parsers/typescript'),\n });\n\n const isCJSFile = extension === 'cjs' || content.includes('module.exports');\n\n injectImport(ast, isCJSFile, 'syncJSON', '@intlayer/sync-json-plugin');\n\n const callNode = buildSyncJSONCallNode(syncConfig);\n\n genericRecastVisit(ast, (objExpr) => {\n if (\n !objExpr ||\n (objExpr.type !== 'ObjectExpression' &&\n !n.ObjectExpression.check(objExpr))\n )\n return;\n\n // Inject dictionary.format alongside the plugin so intlayer knows how to\n // interpret dictionary content at runtime.\n injectDictionaryFormat(objExpr, syncConfig.format);\n\n let pluginsProp = (objExpr.properties as any[]).find((prop: any) => {\n if (!prop?.key) return false;\n const keyName = prop.key.name ?? prop.key.value;\n return keyName === 'plugins';\n });\n\n if (!pluginsProp) {\n pluginsProp = b.property(\n 'init',\n b.identifier('plugins'),\n b.arrayExpression([])\n );\n (objExpr.properties as any[]).push(pluginsProp);\n }\n\n const arrayValue = pluginsProp.value;\n\n if (\n arrayValue &&\n (arrayValue.type === 'ArrayExpression' ||\n n.ArrayExpression.check(arrayValue))\n ) {\n const hasSyncJSON = (arrayValue.elements as any[]).some(\n (element: any) => {\n const callee = element?.callee;\n if (!callee) return false;\n const name: string = callee.name ?? callee.id?.name;\n return name === 'syncJSON';\n }\n );\n\n if (!hasSyncJSON) {\n (arrayValue.elements as any[]).push(callNode);\n }\n }\n });\n\n return recast.print(ast).code;\n};\n"],"mappings":"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"}
@@ -126,9 +126,54 @@ const detectJsonLocalePattern = async (rootDir) => {
126
126
  locales: Array.from(flatLocales)
127
127
  };
128
128
  };
129
+ /** Common locations of the `next-intl` request config, relative to the root. */
130
+ const NEXT_INTL_REQUEST_FILES = [
131
+ "i18n/request.ts",
132
+ "i18n/request.tsx",
133
+ "i18n/request.js",
134
+ "i18n/request.mjs",
135
+ "src/i18n/request.ts",
136
+ "src/i18n/request.tsx",
137
+ "src/i18n/request.js",
138
+ "src/i18n/request.mjs",
139
+ "app/i18n/request.ts",
140
+ "src/app/i18n/request.ts"
141
+ ];
142
+ /**
143
+ * Derives the messages source template from a `next-intl` `i18n/request.ts`
144
+ * file, which is the authoritative location of the messages path in a next-intl
145
+ * project (e.g. `messages: (await import(\`../messages/${locale}.json\`)).default`).
146
+ *
147
+ * Reading it removes the ambiguity of globbing the file system and yields the
148
+ * exact `source` template for `syncJSON`. When the resulting template has no
149
+ * `${key}` segment (the common single-file-per-locale layout, where top-level
150
+ * keys are namespaces), `syncJSON` `splitKeys` auto-detection turns each
151
+ * top-level key into its own dictionary.
152
+ *
153
+ * Returns `null` when no request file is found, the messages import cannot be
154
+ * parsed, or the path is not project-root-relative (e.g. uses a TS path alias).
155
+ *
156
+ * @param rootDir - Project root directory.
157
+ */
158
+ const detectNextIntlMessagesPattern = async (rootDir) => {
159
+ for (const requestFile of NEXT_INTL_REQUEST_FILES) {
160
+ if (!await exists(rootDir, requestFile)) continue;
161
+ const importPath = (await readFileFromRoot(rootDir, requestFile)).match(/import\(\s*`([^`]*\$\{\s*locale\s*\}[^`]*\.json)`/)?.[1];
162
+ if (!importPath) continue;
163
+ if (!importPath.startsWith(".")) continue;
164
+ const relativeTemplate = (0, node_path.relative)(rootDir, (0, node_path.resolve)((0, node_path.dirname)((0, node_path.resolve)(rootDir, requestFile)), importPath)).split(node_path.sep).join("/");
165
+ const template = relativeTemplate.startsWith(".") ? relativeTemplate : `./${relativeTemplate}`;
166
+ return {
167
+ type: template.includes("${key}") || template.includes("${namespace}") ? "nested" : "flat",
168
+ template
169
+ };
170
+ }
171
+ return null;
172
+ };
129
173
 
130
174
  //#endregion
131
175
  exports.detectJsonLocalePattern = detectJsonLocalePattern;
176
+ exports.detectNextIntlMessagesPattern = detectNextIntlMessagesPattern;
132
177
  exports.ensureDirectory = ensureDirectory;
133
178
  exports.exists = exists;
134
179
  exports.readFileFromRoot = readFileFromRoot;
@@ -1 +1 @@
1
- {"version":3,"file":"fileSystem.cjs","names":["ALL_LOCALES","EXCLUDED_PATHS"],"sources":["../../../../src/init/utils/fileSystem.ts"],"sourcesContent":["import { access, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { EXCLUDED_PATHS } from '@intlayer/config/defaultValues';\nimport { ALL_LOCALES } from '@intlayer/types/allLocales';\nimport fg from 'fast-glob';\n\n/**\n * Helper to check if a file exists\n */\nexport const exists = async (rootDir: string, filePath: string) => {\n try {\n await access(join(rootDir, filePath));\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Helper to read a file\n */\nexport const readFileFromRoot = async (rootDir: string, filePath: string) =>\n await readFile(join(rootDir, filePath), 'utf8');\n\n/**\n * Helper to write a file\n */\nexport const writeFileToRoot = async (\n rootDir: string,\n filePath: string,\n content: string\n) => await writeFile(join(rootDir, filePath), content, 'utf8');\n\n/**\n * Helper to ensure a directory exists\n */\nexport const ensureDirectory = async (rootDir: string, dirPath: string) => {\n try {\n await mkdir(join(rootDir, dirPath), { recursive: true });\n } catch {\n // Directory already exists or could not be created\n }\n};\n\n/**\n * Pattern type for locale JSON file organisation.\n * - 'nested': files are at `{base}/{locale}/{key}.json`\n * - 'flat': files are at `{base}/{locale}.json`\n */\nexport type JsonLocalePatternType = 'nested' | 'flat';\n\n/**\n * Detected locale JSON file pattern and the corresponding source template.\n * `template` uses `${locale}` and `${key}` as literal placeholders (not JS\n * expressions) so it can be embedded directly in a template-literal string.\n */\nexport type JsonLocalePattern = {\n type: JsonLocalePatternType;\n /**\n * Source path template for syncJSON `source` option.\n * Example nested: `./locales/${locale}/${key}.json`\n * Example flat: `./locales/${locale}.json`\n */\n template: string;\n /**\n * Detected locales in the directory.\n */\n locales: string[];\n};\n\n/**\n * Set of all known locale string values from the intlayer Locales registry\n * (e.g. `'en'`, `'fr'`, `'zh-TW'`). Keyed by the exact locale string so\n * `.has()` lookups are O(1) and common short directory names (`src`, `lib`,\n * `app`, …) are not mistaken for locales.\n */\nconst ALL_LOCALE_VALUES = new Set<string>(Object.values(ALL_LOCALES));\n\n/**\n * Returns true when `segment` matches a known BCP-47 locale identifier, e.g.\n * `en`, `fr`, `zh-TW`, `pt-BR`, `en-US`.\n */\nconst isLocaleSegment = (segment: string): boolean =>\n ALL_LOCALE_VALUES.has(segment);\n\n/** JSON filenames that are never locale translation files. */\nconst KNOWN_CONFIG_FILENAMES = new Set([\n 'package.json',\n 'tsconfig.json',\n 'jsconfig.json',\n 'biome.json',\n 'turbo.json',\n 'lerna.json',\n 'vercel.json',\n 'netlify.json',\n 'babel.config.json',\n 'jest.config.json',\n 'vitest.config.json',\n '.eslintrc.json',\n '.prettierrc.json',\n]);\n\n/**\n * Scans the project for JSON files and determines whether locale files are\n * organised as `{base}/{locale}/{key}.json` (nested) or `{base}/{locale}.json`\n * (flat). Returns the most likely source template, or `null` when no locale\n * JSON files are found.\n *\n * The returned `template` contains `${locale}` and `${key}` as **literal**\n * placeholder strings so it can be embedded inside a JS template literal.\n */\nexport const detectJsonLocalePattern = async (\n rootDir: string\n): Promise<JsonLocalePattern | null> => {\n const files = await fg('**/*.json', {\n cwd: rootDir,\n ignore: EXCLUDED_PATHS,\n absolute: false,\n onlyFiles: true,\n });\n\n const nestedBasePaths: string[] = [];\n const flatBasePaths: string[] = [];\n const nestedLocales = new Set<string>();\n const flatLocales = new Set<string>();\n\n for (const file of files) {\n const parts = file.split('/');\n const filename = parts[parts.length - 1] ?? '';\n\n if (KNOWN_CONFIG_FILENAMES.has(filename)) continue;\n\n // Nested: …/{locale}/{key}.json — parent directory is a locale code\n if (parts.length >= 3) {\n const localeDir = parts[parts.length - 2] ?? '';\n if (isLocaleSegment(localeDir)) {\n nestedBasePaths.push(parts.slice(0, -2).join('/') || '.');\n nestedLocales.add(localeDir);\n }\n }\n\n // Flat: …/{locale}.json — filename (without extension) is a locale code\n if (parts.length >= 2) {\n const baseName = filename.slice(0, -5); // strip \".json\"\n if (isLocaleSegment(baseName)) {\n flatBasePaths.push(parts.slice(0, -1).join('/') || '.');\n flatLocales.add(baseName);\n }\n }\n }\n\n if (nestedBasePaths.length === 0 && flatBasePaths.length === 0) {\n return null;\n }\n\n /**\n * Returns the path prefix that appears most frequently among the matches,\n * formatted as a relative path suitable for a source template.\n */\n const mostFrequentPrefix = (paths: string[]): string => {\n const counts = paths.reduce<Record<string, number>>((accumulator, path) => {\n accumulator[path] = (accumulator[path] ?? 0) + 1;\n return accumulator;\n }, {});\n const topEntry = Object.entries(counts).sort(([, a], [, b]) => b - a)[0];\n const basePath = topEntry?.[0] ?? '.';\n return basePath === '.' ? '.' : `./${basePath}`;\n };\n\n if (nestedBasePaths.length >= flatBasePaths.length) {\n const prefix = mostFrequentPrefix(nestedBasePaths);\n return {\n type: 'nested',\n // Literal ${locale} and ${key} — not evaluated here, used in template literals\n template: `${prefix}/\\${locale}/\\${key}.json`,\n locales: Array.from(nestedLocales),\n };\n }\n\n const prefix = mostFrequentPrefix(flatBasePaths);\n return {\n type: 'flat',\n template: `${prefix}/\\${locale}.json`,\n locales: Array.from(flatLocales),\n };\n};\n"],"mappings":";;;;;;;;;;;;;AASA,MAAa,SAAS,OAAO,SAAiB,aAAqB;AACjE,KAAI;AACF,yDAAkB,SAAS,SAAS,CAAC;AACrC,SAAO;SACD;AACN,SAAO;;;;;;AAOX,MAAa,mBAAmB,OAAO,SAAiB,aACtD,yDAAoB,SAAS,SAAS,EAAE,OAAO;;;;AAKjD,MAAa,kBAAkB,OAC7B,SACA,UACA,YACG,0DAAqB,SAAS,SAAS,EAAE,SAAS,OAAO;;;;AAK9D,MAAa,kBAAkB,OAAO,SAAiB,YAAoB;AACzE,KAAI;AACF,wDAAiB,SAAS,QAAQ,EAAE,EAAE,WAAW,MAAM,CAAC;SAClD;;;;;;;;AAqCV,MAAM,oBAAoB,IAAI,IAAY,OAAO,OAAOA,uCAAY,CAAC;;;;;AAMrE,MAAM,mBAAmB,YACvB,kBAAkB,IAAI,QAAQ;;AAGhC,MAAM,yBAAyB,IAAI,IAAI;CACrC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;;;;;;;AAWF,MAAa,0BAA0B,OACrC,YACsC;CACtC,MAAM,QAAQ,6BAAS,aAAa;EAClC,KAAK;EACL,QAAQC;EACR,UAAU;EACV,WAAW;EACZ,CAAC;CAEF,MAAM,kBAA4B,EAAE;CACpC,MAAM,gBAA0B,EAAE;CAClC,MAAM,gCAAgB,IAAI,KAAa;CACvC,MAAM,8BAAc,IAAI,KAAa;AAErC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,QAAQ,KAAK,MAAM,IAAI;EAC7B,MAAM,WAAW,MAAM,MAAM,SAAS,MAAM;AAE5C,MAAI,uBAAuB,IAAI,SAAS,CAAE;AAG1C,MAAI,MAAM,UAAU,GAAG;GACrB,MAAM,YAAY,MAAM,MAAM,SAAS,MAAM;AAC7C,OAAI,gBAAgB,UAAU,EAAE;AAC9B,oBAAgB,KAAK,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,IAAI,IAAI,IAAI;AACzD,kBAAc,IAAI,UAAU;;;AAKhC,MAAI,MAAM,UAAU,GAAG;GACrB,MAAM,WAAW,SAAS,MAAM,GAAG,GAAG;AACtC,OAAI,gBAAgB,SAAS,EAAE;AAC7B,kBAAc,KAAK,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,IAAI,IAAI,IAAI;AACvD,gBAAY,IAAI,SAAS;;;;AAK/B,KAAI,gBAAgB,WAAW,KAAK,cAAc,WAAW,EAC3D,QAAO;;;;;CAOT,MAAM,sBAAsB,UAA4B;EACtD,MAAM,SAAS,MAAM,QAAgC,aAAa,SAAS;AACzE,eAAY,SAAS,YAAY,SAAS,KAAK;AAC/C,UAAO;KACN,EAAE,CAAC;EAEN,MAAM,WADW,OAAO,QAAQ,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,OAAO,IAAI,EAAE,CAAC,KAC1C,MAAM;AAClC,SAAO,aAAa,MAAM,MAAM,KAAK;;AAGvC,KAAI,gBAAgB,UAAU,cAAc,OAE1C,QAAO;EACL,MAAM;EAEN,UAAU,GAJG,mBAAmB,gBAIb,CAAC;EACpB,SAAS,MAAM,KAAK,cAAc;EACnC;AAIH,QAAO;EACL,MAAM;EACN,UAAU,GAHG,mBAAmB,cAGb,CAAC;EACpB,SAAS,MAAM,KAAK,YAAY;EACjC"}
1
+ {"version":3,"file":"fileSystem.cjs","names":["ALL_LOCALES","EXCLUDED_PATHS","sep"],"sources":["../../../../src/init/utils/fileSystem.ts"],"sourcesContent":["import { access, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join, relative, resolve, sep } from 'node:path';\nimport { EXCLUDED_PATHS } from '@intlayer/config/defaultValues';\nimport { ALL_LOCALES } from '@intlayer/types/allLocales';\nimport fg from 'fast-glob';\n\n/**\n * Helper to check if a file exists\n */\nexport const exists = async (rootDir: string, filePath: string) => {\n try {\n await access(join(rootDir, filePath));\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Helper to read a file\n */\nexport const readFileFromRoot = async (rootDir: string, filePath: string) =>\n await readFile(join(rootDir, filePath), 'utf8');\n\n/**\n * Helper to write a file\n */\nexport const writeFileToRoot = async (\n rootDir: string,\n filePath: string,\n content: string\n) => await writeFile(join(rootDir, filePath), content, 'utf8');\n\n/**\n * Helper to ensure a directory exists\n */\nexport const ensureDirectory = async (rootDir: string, dirPath: string) => {\n try {\n await mkdir(join(rootDir, dirPath), { recursive: true });\n } catch {\n // Directory already exists or could not be created\n }\n};\n\n/**\n * Pattern type for locale JSON file organisation.\n * - 'nested': files are at `{base}/{locale}/{key}.json`\n * - 'flat': files are at `{base}/{locale}.json`\n */\nexport type JsonLocalePatternType = 'nested' | 'flat';\n\n/**\n * Detected locale JSON file pattern and the corresponding source template.\n * `template` uses `${locale}` and `${key}` as literal placeholders (not JS\n * expressions) so it can be embedded directly in a template-literal string.\n */\nexport type JsonLocalePattern = {\n type: JsonLocalePatternType;\n /**\n * Source path template for syncJSON `source` option.\n * Example nested: `./locales/${locale}/${key}.json`\n * Example flat: `./locales/${locale}.json`\n */\n template: string;\n /**\n * Detected locales in the directory.\n */\n locales: string[];\n};\n\n/**\n * Set of all known locale string values from the intlayer Locales registry\n * (e.g. `'en'`, `'fr'`, `'zh-TW'`). Keyed by the exact locale string so\n * `.has()` lookups are O(1) and common short directory names (`src`, `lib`,\n * `app`, …) are not mistaken for locales.\n */\nconst ALL_LOCALE_VALUES = new Set<string>(Object.values(ALL_LOCALES));\n\n/**\n * Returns true when `segment` matches a known BCP-47 locale identifier, e.g.\n * `en`, `fr`, `zh-TW`, `pt-BR`, `en-US`.\n */\nconst isLocaleSegment = (segment: string): boolean =>\n ALL_LOCALE_VALUES.has(segment);\n\n/** JSON filenames that are never locale translation files. */\nconst KNOWN_CONFIG_FILENAMES = new Set([\n 'package.json',\n 'tsconfig.json',\n 'jsconfig.json',\n 'biome.json',\n 'turbo.json',\n 'lerna.json',\n 'vercel.json',\n 'netlify.json',\n 'babel.config.json',\n 'jest.config.json',\n 'vitest.config.json',\n '.eslintrc.json',\n '.prettierrc.json',\n]);\n\n/**\n * Scans the project for JSON files and determines whether locale files are\n * organised as `{base}/{locale}/{key}.json` (nested) or `{base}/{locale}.json`\n * (flat). Returns the most likely source template, or `null` when no locale\n * JSON files are found.\n *\n * The returned `template` contains `${locale}` and `${key}` as **literal**\n * placeholder strings so it can be embedded inside a JS template literal.\n */\nexport const detectJsonLocalePattern = async (\n rootDir: string\n): Promise<JsonLocalePattern | null> => {\n const files = await fg('**/*.json', {\n cwd: rootDir,\n ignore: EXCLUDED_PATHS,\n absolute: false,\n onlyFiles: true,\n });\n\n const nestedBasePaths: string[] = [];\n const flatBasePaths: string[] = [];\n const nestedLocales = new Set<string>();\n const flatLocales = new Set<string>();\n\n for (const file of files) {\n const parts = file.split('/');\n const filename = parts[parts.length - 1] ?? '';\n\n if (KNOWN_CONFIG_FILENAMES.has(filename)) continue;\n\n // Nested: …/{locale}/{key}.json — parent directory is a locale code\n if (parts.length >= 3) {\n const localeDir = parts[parts.length - 2] ?? '';\n if (isLocaleSegment(localeDir)) {\n nestedBasePaths.push(parts.slice(0, -2).join('/') || '.');\n nestedLocales.add(localeDir);\n }\n }\n\n // Flat: …/{locale}.json — filename (without extension) is a locale code\n if (parts.length >= 2) {\n const baseName = filename.slice(0, -5); // strip \".json\"\n if (isLocaleSegment(baseName)) {\n flatBasePaths.push(parts.slice(0, -1).join('/') || '.');\n flatLocales.add(baseName);\n }\n }\n }\n\n if (nestedBasePaths.length === 0 && flatBasePaths.length === 0) {\n return null;\n }\n\n /**\n * Returns the path prefix that appears most frequently among the matches,\n * formatted as a relative path suitable for a source template.\n */\n const mostFrequentPrefix = (paths: string[]): string => {\n const counts = paths.reduce<Record<string, number>>((accumulator, path) => {\n accumulator[path] = (accumulator[path] ?? 0) + 1;\n return accumulator;\n }, {});\n const topEntry = Object.entries(counts).sort(([, a], [, b]) => b - a)[0];\n const basePath = topEntry?.[0] ?? '.';\n return basePath === '.' ? '.' : `./${basePath}`;\n };\n\n if (nestedBasePaths.length >= flatBasePaths.length) {\n const prefix = mostFrequentPrefix(nestedBasePaths);\n return {\n type: 'nested',\n // Literal ${locale} and ${key} — not evaluated here, used in template literals\n template: `${prefix}/\\${locale}/\\${key}.json`,\n locales: Array.from(nestedLocales),\n };\n }\n\n const prefix = mostFrequentPrefix(flatBasePaths);\n return {\n type: 'flat',\n template: `${prefix}/\\${locale}.json`,\n locales: Array.from(flatLocales),\n };\n};\n\n/**\n * The messages source template derived from a `next-intl` `i18n/request.ts`\n * file, ready to be used as a `syncJSON` `source` builder.\n */\nexport type NextIntlMessagesPattern = {\n /** `'flat'` (one file per locale) or `'nested'` (per-namespace files). */\n type: JsonLocalePatternType;\n /**\n * Source path template relative to the project root, with `${locale}` (and\n * `${key}` when nested) as literal placeholders, e.g. `./messages/${locale}.json`.\n */\n template: string;\n};\n\n/** Common locations of the `next-intl` request config, relative to the root. */\nconst NEXT_INTL_REQUEST_FILES = [\n 'i18n/request.ts',\n 'i18n/request.tsx',\n 'i18n/request.js',\n 'i18n/request.mjs',\n 'src/i18n/request.ts',\n 'src/i18n/request.tsx',\n 'src/i18n/request.js',\n 'src/i18n/request.mjs',\n 'app/i18n/request.ts',\n 'src/app/i18n/request.ts',\n];\n\n/**\n * Derives the messages source template from a `next-intl` `i18n/request.ts`\n * file, which is the authoritative location of the messages path in a next-intl\n * project (e.g. `messages: (await import(\\`../messages/${locale}.json\\`)).default`).\n *\n * Reading it removes the ambiguity of globbing the file system and yields the\n * exact `source` template for `syncJSON`. When the resulting template has no\n * `${key}` segment (the common single-file-per-locale layout, where top-level\n * keys are namespaces), `syncJSON` `splitKeys` auto-detection turns each\n * top-level key into its own dictionary.\n *\n * Returns `null` when no request file is found, the messages import cannot be\n * parsed, or the path is not project-root-relative (e.g. uses a TS path alias).\n *\n * @param rootDir - Project root directory.\n */\nexport const detectNextIntlMessagesPattern = async (\n rootDir: string\n): Promise<NextIntlMessagesPattern | null> => {\n for (const requestFile of NEXT_INTL_REQUEST_FILES) {\n if (!(await exists(rootDir, requestFile))) continue;\n\n const content = await readFileFromRoot(rootDir, requestFile);\n\n // Capture the template-literal path of the messages dynamic import, e.g.\n // import(`../messages/${locale}.json`) → `../messages/${locale}.json`.\n const importMatch = content.match(\n /import\\(\\s*`([^`]*\\$\\{\\s*locale\\s*\\}[^`]*\\.json)`/\n );\n\n const importPath = importMatch?.[1];\n if (!importPath) continue;\n\n // Only relative imports can be resolved against the file system; path\n // aliases (e.g. `@/messages/...`) are skipped in favour of glob detection.\n if (!importPath.startsWith('.')) continue;\n\n // Resolve the import (relative to the request file) back to a\n // project-root-relative template. The `${locale}` / `${key}` placeholders\n // are kept literal — path utilities treat them as ordinary segments.\n const requestDir = dirname(resolve(rootDir, requestFile));\n const absoluteTemplate = resolve(requestDir, importPath);\n const relativeTemplate = relative(rootDir, absoluteTemplate)\n .split(sep)\n .join('/');\n\n const template = relativeTemplate.startsWith('.')\n ? relativeTemplate\n : `./${relativeTemplate}`;\n\n const type: JsonLocalePatternType =\n template.includes('${key}') || template.includes('${namespace}')\n ? 'nested'\n : 'flat';\n\n return { type, template };\n }\n\n return null;\n};\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_init_utils_configManipulation = require('./configManipulation.cjs');
3
2
  const require_init_utils_fileSystem = require('./fileSystem.cjs');
3
+ const require_init_utils_configManipulation = require('./configManipulation.cjs');
4
4
  const require_init_utils_githubActions = require('./githubActions.cjs');
5
5
  const require_init_utils_jsonParser = require('./jsonParser.cjs');
6
6
  const require_init_utils_packageManager = require('./packageManager.cjs');
@@ -10,12 +10,17 @@ exports.GITHUB_FILL_WORKFLOW_PATH = require_init_utils_githubActions.GITHUB_FILL
10
10
  exports.GITHUB_TEST_WORKFLOW_PATH = require_init_utils_githubActions.GITHUB_TEST_WORKFLOW_PATH;
11
11
  exports.detectJsonLocalePattern = require_init_utils_fileSystem.detectJsonLocalePattern;
12
12
  exports.detectMissingIntlayerPackages = require_init_utils_packageManager.detectMissingIntlayerPackages;
13
+ exports.detectNextIntlMessagesPattern = require_init_utils_fileSystem.detectNextIntlMessagesPattern;
14
+ exports.detectOutdatedIntlayerPackages = require_init_utils_packageManager.detectOutdatedIntlayerPackages;
13
15
  exports.detectPackageManager = require_init_utils_packageManager.detectPackageManager;
14
16
  exports.ensureDirectory = require_init_utils_fileSystem.ensureDirectory;
15
17
  exports.exists = require_init_utils_fileSystem.exists;
16
18
  exports.findTsConfigFiles = require_init_utils_tsConfig.findTsConfigFiles;
17
19
  exports.getGithubWorkflows = require_init_utils_githubActions.getGithubWorkflows;
20
+ exports.getInstalledPackageVersion = require_init_utils_packageManager.getInstalledPackageVersion;
18
21
  exports.installPackages = require_init_utils_packageManager.installPackages;
22
+ exports.isIntlayerPackageName = require_init_utils_packageManager.isIntlayerPackageName;
23
+ exports.normalizeVersion = require_init_utils_packageManager.normalizeVersion;
19
24
  exports.parseJSONWithComments = require_init_utils_jsonParser.parseJSONWithComments;
20
25
  exports.readFileFromRoot = require_init_utils_fileSystem.readFileFromRoot;
21
26
  exports.updateAstroConfig = require_init_utils_configManipulation.updateAstroConfig;
@@ -29,4 +34,5 @@ exports.updateNuxtConfigForNuxtjsI18n = require_init_utils_configManipulation.up
29
34
  exports.updateViteConfig = require_init_utils_configManipulation.updateViteConfig;
30
35
  exports.updateViteConfigForCompatPlugin = require_init_utils_configManipulation.updateViteConfigForCompatPlugin;
31
36
  exports.updateViteConfigForVueI18n = require_init_utils_configManipulation.updateViteConfigForVueI18n;
37
+ exports.upgradePackages = require_init_utils_packageManager.upgradePackages;
32
38
  exports.writeFileToRoot = require_init_utils_fileSystem.writeFileToRoot;
@@ -2,6 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_runtime = require('../../_virtual/_rolldown/runtime.cjs');
3
3
  let node_path = require("node:path");
4
4
  let node_fs = require("node:fs");
5
+ let _intlayer_config_utils = require("@intlayer/config/utils");
5
6
  let node_child_process = require("node:child_process");
6
7
 
7
8
  //#region src/init/utils/packageManager.ts
@@ -57,7 +58,8 @@ const detectMissingIntlayerPackages = (allDependencies) => {
57
58
  addIfMissing("next-intl");
58
59
  compatSyncConfig ??= {
59
60
  format: "icu",
60
- sourceTemplate: "./locales/${locale}/${key}.json"
61
+ sourceTemplate: "./messages/${locale}.json",
62
+ splitKeys: true
61
63
  };
62
64
  }
63
65
  if (isInstalled("next-i18next") || isInstalled("@intlayer/next-i18next")) {
@@ -104,6 +106,19 @@ const detectMissingIntlayerPackages = (allDependencies) => {
104
106
  pluginPackageSource: "@intlayer/vue-i18n/plugin"
105
107
  };
106
108
  }
109
+ if (isInstalled("use-intl") || isInstalled("@intlayer/use-intl")) {
110
+ addIfMissing("@intlayer/use-intl");
111
+ addIfMissing("use-intl");
112
+ compatSyncConfig ??= {
113
+ format: "icu",
114
+ sourceTemplate: "./messages/${locale}.json",
115
+ splitKeys: true
116
+ };
117
+ compatVitePluginConfig ??= {
118
+ pluginFunctionName: "useIntlVitePlugin",
119
+ pluginPackageSource: "@intlayer/use-intl/plugin"
120
+ };
121
+ }
107
122
  if (isInstalled("react-intl") || isInstalled("@intlayer/react-intl")) {
108
123
  addIfMissing("@intlayer/react-intl");
109
124
  addIfMissing("react-intl");
@@ -198,9 +213,77 @@ const installPackages = (rootDir, packages, packageManager, isDev = false) => {
198
213
  stdio: "inherit"
199
214
  });
200
215
  };
216
+ /**
217
+ * Determines whether a dependency name belongs to the Intlayer ecosystem.
218
+ *
219
+ * Matches the core `intlayer` package, every scoped `@intlayer/*` package
220
+ * (including compat adapters such as `@intlayer/next-intl`) and the framework
221
+ * runtime integrations that follow the `<framework>-intlayer` convention
222
+ * (e.g. `next-intlayer`, `react-intlayer`, `express-intlayer`).
223
+ */
224
+ const isIntlayerPackageName = (packageName) => packageName === "intlayer" || packageName.startsWith("@intlayer/") || /-intlayer$/.test(packageName);
225
+ /**
226
+ * Reduces a semver range or full version to its `major.minor.patch` core,
227
+ * stripping range prefixes (`^`, `~`), pre-release identifiers and build
228
+ * metadata. Returns `null` when no `major.minor.patch` can be extracted.
229
+ *
230
+ * @example normalizeVersion('^9.0.0-canary.3') // '9.0.0'
231
+ */
232
+ const normalizeVersion = (version) => {
233
+ if (!version || typeof version !== "string") return null;
234
+ const match = version.match(/(\d+)\.(\d+)\.(\d+)/);
235
+ return match ? `${match[1]}.${match[2]}.${match[3]}` : null;
236
+ };
237
+ /**
238
+ * Reads the installed version of a package from its `package.json` inside the
239
+ * project's `node_modules`. Returns `null` when the package is not installed or
240
+ * its manifest cannot be read.
241
+ */
242
+ const getInstalledPackageVersion = (rootDir, packageName) => {
243
+ try {
244
+ const manifestPath = (0, node_path.join)(rootDir, "node_modules", packageName, "package.json");
245
+ if (!(0, node_fs.existsSync)(manifestPath)) return null;
246
+ const { version } = JSON.parse((0, node_fs.readFileSync)(manifestPath, "utf-8"));
247
+ return typeof version === "string" ? version : null;
248
+ } catch {
249
+ return null;
250
+ }
251
+ };
252
+ /**
253
+ * Returns the Intlayer packages from `dependencies` whose installed version is
254
+ * behind `targetVersion` (compared on `major.minor.patch`). Packages that are
255
+ * not installed yet are ignored — those are handled by
256
+ * {@link detectMissingIntlayerPackages}.
257
+ */
258
+ const detectOutdatedIntlayerPackages = (rootDir, dependencies, targetVersion) => {
259
+ const normalizedTarget = normalizeVersion(targetVersion);
260
+ if (!normalizedTarget) return [];
261
+ return Object.keys(dependencies).filter(isIntlayerPackageName).filter((packageName) => {
262
+ const normalizedInstalled = normalizeVersion(getInstalledPackageVersion(rootDir, packageName) ?? void 0);
263
+ if (!normalizedInstalled) return false;
264
+ return (0, _intlayer_config_utils.compareVersions)(normalizedInstalled, "<", normalizedTarget);
265
+ });
266
+ };
267
+ /**
268
+ * Upgrades the given packages to `targetVersion` synchronously, preserving the
269
+ * dependency type via the `isDev` flag. Throws if the install process exits
270
+ * with a non-zero code.
271
+ */
272
+ const upgradePackages = (rootDir, packages, packageManager, targetVersion, isDev = false) => {
273
+ if (packages.length === 0) return;
274
+ (0, node_child_process.execSync)(buildInstallCommand(packageManager, packages.map((packageName) => `${packageName}@${targetVersion}`), isDev), {
275
+ cwd: rootDir,
276
+ stdio: "inherit"
277
+ });
278
+ };
201
279
 
202
280
  //#endregion
203
281
  exports.detectMissingIntlayerPackages = detectMissingIntlayerPackages;
282
+ exports.detectOutdatedIntlayerPackages = detectOutdatedIntlayerPackages;
204
283
  exports.detectPackageManager = detectPackageManager;
284
+ exports.getInstalledPackageVersion = getInstalledPackageVersion;
205
285
  exports.installPackages = installPackages;
286
+ exports.isIntlayerPackageName = isIntlayerPackageName;
287
+ exports.normalizeVersion = normalizeVersion;
288
+ exports.upgradePackages = upgradePackages;
206
289
  //# sourceMappingURL=packageManager.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageManager.cjs","names":[],"sources":["../../../../src/init/utils/packageManager.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\n/** Package managers supported for dependency installation. */\nexport type PackageManager = 'bun' | 'pnpm' | 'yarn' | 'npm';\n\n/**\n * Configuration for the syncJSON plugin injected into intlayer.config\n * when a compat i18n library is detected.\n */\nexport type CompatSyncConfig = {\n /** JSON format matching the compat library's conventions. */\n format: 'icu' | 'i18next' | 'vue-i18n';\n /**\n * Source path template using ${locale} and ${key} placeholders.\n * Rendered as a template literal in the generated config.\n */\n sourceTemplate: string;\n};\n\n/**\n * Configuration for injecting a compat vite plugin into vite.config.\n * The plugin replaces the generic `intlayer` plugin for libraries that\n * require alias injection (e.g. `vue-i18n` → `@intlayer/vue-i18n`).\n */\nexport type CompatVitePluginConfig = {\n /** Exported function name from the plugin package, e.g. `'vueI18nVitePlugin'`. */\n pluginFunctionName: string;\n /** Import path for the plugin package, e.g. `'@intlayer/vue-i18n/plugin'`. */\n pluginPackageSource: string;\n};\n\n/** Result of analyzing project dependencies for intlayer package gaps. */\nexport type IntlayerPackageAnalysis = {\n /** Intlayer packages that are referenced but not yet installed. */\n packagesToInstall: string[];\n /** Intlayer dev packages that are referenced but not yet installed. */\n devPackagesToInstall: string[];\n /**\n * syncJSON plugin configuration to inject when a compat i18n library is\n * detected. Undefined when no compat library is present or format is not\n * yet implemented.\n */\n compatSyncConfig: CompatSyncConfig | undefined;\n /**\n * Vite config plugin to inject when a vite-based compat library is\n * detected. Undefined for Next.js/Nuxt-only compat libs or when no compat\n * library requires alias injection.\n */\n compatVitePluginConfig: CompatVitePluginConfig | undefined;\n};\n\n/**\n * Detects the package manager in use by checking for lock files in the\n * project root. Falls back to npm when no lock file is found.\n */\nexport const detectPackageManager = (rootDir: string): PackageManager => {\n if (\n existsSync(join(rootDir, 'bun.lock')) ||\n existsSync(join(rootDir, 'bun.lockb'))\n ) {\n return 'bun';\n }\n if (existsSync(join(rootDir, 'pnpm-lock.yaml'))) {\n return 'pnpm';\n }\n if (existsSync(join(rootDir, 'yarn.lock'))) {\n return 'yarn';\n }\n return 'npm';\n};\n\n/**\n * Returns the install command for the given package manager and package list.\n */\nconst buildInstallCommand = (\n packageManager: PackageManager,\n packages: string[],\n isDev: boolean = false\n): string => {\n const packageList = packages.join(' ');\n switch (packageManager) {\n case 'bun':\n return `bun add ${isDev ? '-d ' : ''}${packageList}`;\n case 'pnpm':\n return `pnpm add ${isDev ? '-D ' : ''}${packageList}`;\n case 'yarn':\n return `yarn add ${isDev ? '-D ' : ''}${packageList}`;\n case 'npm':\n return `npm install ${isDev ? '-D ' : ''}${packageList}`;\n }\n};\n\n/**\n * Analyzes existing project dependencies to determine which intlayer packages\n * are missing and what syncJSON configuration to inject when compat i18n\n * libraries are present.\n */\nexport const detectMissingIntlayerPackages = (\n allDependencies: Record<string, string>\n): IntlayerPackageAnalysis => {\n const packagesToInstall: string[] = [];\n const devPackagesToInstall: string[] = [];\n let compatSyncConfig: CompatSyncConfig | undefined;\n let compatVitePluginConfig: CompatVitePluginConfig | undefined;\n\n const isInstalled = (packageName: string): boolean =>\n Boolean(allDependencies[packageName]);\n\n const addIfMissing = (packageName: string): void => {\n if (!isInstalled(packageName)) {\n packagesToInstall.push(packageName);\n }\n };\n\n const addDevIfMissing = (packageName: string): void => {\n if (!isInstalled(packageName)) {\n devPackagesToInstall.push(packageName);\n }\n };\n\n // Core package — always required\n addIfMissing('intlayer');\n\n // Framework-specific runtime integrations\n if (isInstalled('next')) {\n addIfMissing('next-intlayer');\n } else if (isInstalled('react')) {\n addIfMissing('react-intlayer');\n }\n\n if (isInstalled('svelte')) {\n addIfMissing('svelte-intlayer');\n }\n\n if (isInstalled('solid-js')) {\n addIfMissing('solid-intlayer');\n }\n\n if (isInstalled('@angular/core')) {\n addIfMissing('angular-intlayer');\n }\n\n if (isInstalled('vue')) {\n addIfMissing('vue-intlayer');\n }\n\n if (isInstalled('vite')) {\n addIfMissing('vite-intlayer');\n }\n\n // -------------------------------------------------------------------------\n // Compat adapters for existing i18n libraries.\n //\n // Detection order matters: more specific libraries are checked first so that\n // `compatSyncConfig ??=` and `compatVitePluginConfig ??=` capture the most\n // relevant match. Libraries that only affect the Next.js or Nuxt config do\n // not set `compatVitePluginConfig` (handled separately in init/index.ts).\n // Libraries whose JSON format is not yet supported leave `compatSyncConfig`\n // undefined so no syncJSON plugin is injected.\n // -------------------------------------------------------------------------\n\n // next-intl — next.js only, ICU format\n if (isInstalled('next-intl') || isInstalled('@intlayer/next-intl')) {\n addIfMissing('@intlayer/next-intl');\n addIfMissing('next-intl');\n compatSyncConfig ??= {\n format: 'icu',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n // next config handled via updateNextConfigForNextIntl in init/index.ts\n }\n\n // next-i18next — next.js only, i18next JSON format\n if (isInstalled('next-i18next') || isInstalled('@intlayer/next-i18next')) {\n addIfMissing('@intlayer/next-i18next');\n addIfMissing('next-i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n // next config handled via updateNextConfigForNextI18next in init/index.ts\n }\n\n // next-translate — next.js only, i18next-style flat-namespace JSON\n if (\n isInstalled('next-translate') ||\n isInstalled('@intlayer/next-translate')\n ) {\n addIfMissing('@intlayer/next-translate');\n addIfMissing('next-translate');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n // next config handled via updateNextConfigForNextTranslate in init/index.ts\n }\n\n // i18next — explicit import from @intlayer/i18next (no alias injection needed)\n if (isInstalled('i18next') || isInstalled('@intlayer/i18next')) {\n addIfMissing('@intlayer/i18next');\n // Ensure the required peer dependency is installed\n addIfMissing('i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n }\n\n // react-i18next — explicit import from @intlayer/react-i18next (no alias)\n if (isInstalled('react-i18next') || isInstalled('@intlayer/react-i18next')) {\n addIfMissing('@intlayer/react-i18next');\n // Ensure the required peer dependency is installed\n addIfMissing('react-i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n }\n\n // vue-i18n — vite alias injection required\n if (isInstalled('vue-i18n') || isInstalled('@intlayer/vue-i18n')) {\n addIfMissing('@intlayer/vue-i18n');\n addIfMissing('vue-i18n');\n compatSyncConfig ??= {\n format: 'vue-i18n',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'vueI18nVitePlugin',\n pluginPackageSource: '@intlayer/vue-i18n/plugin',\n };\n }\n\n // react-intl — vite alias injection required, ICU format\n if (isInstalled('react-intl') || isInstalled('@intlayer/react-intl')) {\n addIfMissing('@intlayer/react-intl');\n addIfMissing('react-intl');\n compatSyncConfig ??= {\n format: 'icu',\n sourceTemplate: './src/i18n/${locale}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'reactIntlVitePlugin',\n pluginPackageSource: '@intlayer/react-intl/plugin',\n };\n }\n\n // @ngneat/transloco — vite alias injection required\n // @todo syncJSON format not yet implemented for transloco\n if (isInstalled('@ngneat/transloco') || isInstalled('@intlayer/transloco')) {\n addIfMissing('@intlayer/transloco');\n addIfMissing('@ngneat/transloco');\n compatVitePluginConfig ??= {\n pluginFunctionName: 'translocoVitePlugin',\n pluginPackageSource: '@intlayer/transloco/plugin',\n };\n }\n\n // svelte-i18n — vite alias injection required, flat JSON (i18next-compatible)\n if (isInstalled('svelte-i18n') || isInstalled('@intlayer/svelte-i18n')) {\n addIfMissing('@intlayer/svelte-i18n');\n addIfMissing('svelte-i18n');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'svelteI18nVitePlugin',\n pluginPackageSource: '@intlayer/svelte-i18n/plugin',\n };\n }\n\n // node-polyglot — vite alias injection required\n // @todo syncJSON format not yet implemented for polyglot\n if (isInstalled('node-polyglot') || isInstalled('@intlayer/polyglot')) {\n addIfMissing('@intlayer/polyglot');\n addIfMissing('node-polyglot');\n compatVitePluginConfig ??= {\n pluginFunctionName: 'polyglotVitePlugin',\n pluginPackageSource: '@intlayer/polyglot/plugin',\n };\n }\n\n // @nuxtjs/i18n — nuxt module (no vite plugin), vue-i18n JSON format\n if (isInstalled('@nuxtjs/i18n') || isInstalled('@intlayer/nuxtjs-i18n')) {\n addIfMissing('@intlayer/nuxtjs-i18n');\n addIfMissing('@nuxtjs/i18n');\n compatSyncConfig ??= {\n format: 'vue-i18n',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n // nuxt config handled via updateNuxtConfigForNuxtjsI18n in init/index.ts\n }\n\n // @ngx-translate/core — vite alias injection required, flat JSON (i18next)\n if (\n isInstalled('@ngx-translate/core') ||\n isInstalled('@intlayer/ngx-translate')\n ) {\n addIfMissing('@intlayer/ngx-translate');\n addIfMissing('@ngx-translate/core');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './assets/i18n/${locale}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'ngxTranslateVitePlugin',\n pluginPackageSource: '@intlayer/ngx-translate/plugin',\n };\n }\n\n // @lingui/core — vite alias injection required\n // @todo syncJSON format not yet implemented for lingui (uses PO files)\n if (\n isInstalled('@lingui/core') ||\n isInstalled('@lingui/react') ||\n isInstalled('@intlayer/lingui')\n ) {\n addIfMissing('@intlayer/lingui');\n addIfMissing('@lingui/core');\n compatVitePluginConfig ??= {\n pluginFunctionName: 'linguiVitePlugin',\n pluginPackageSource: '@intlayer/lingui/plugin',\n };\n }\n\n // i18n-js — vite alias injection required\n // @todo syncJSON format not yet implemented for i18n-js\n if (isInstalled('i18n-js') || isInstalled('@intlayer/i18n-js')) {\n addIfMissing('@intlayer/i18n-js');\n addIfMissing('i18n-js');\n compatVitePluginConfig ??= {\n pluginFunctionName: 'i18nJsVitePlugin',\n pluginPackageSource: '@intlayer/i18n-js/plugin',\n };\n }\n\n if (compatSyncConfig) {\n addDevIfMissing('@intlayer/sync-json-plugin');\n }\n\n return {\n packagesToInstall,\n devPackagesToInstall,\n compatSyncConfig,\n compatVitePluginConfig,\n };\n};\n\n/**\n * Runs the package install command synchronously.\n * Throws if the install process exits with a non-zero code.\n */\nexport const installPackages = (\n rootDir: string,\n packages: string[],\n packageManager: PackageManager,\n isDev: boolean = false\n): void => {\n const command = buildInstallCommand(packageManager, packages, isDev);\n execSync(command, { cwd: rootDir, stdio: 'inherit' });\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"packageManager.cjs","names":[],"sources":["../../../../src/init/utils/packageManager.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { compareVersions } from '@intlayer/config/utils';\n\n/** Package managers supported for dependency installation. */\nexport type PackageManager = 'bun' | 'pnpm' | 'yarn' | 'npm';\n\n/**\n * Configuration for the syncJSON plugin injected into intlayer.config\n * when a compat i18n library is detected.\n */\nexport type CompatSyncConfig = {\n /** JSON format matching the compat library's conventions. */\n format: 'icu' | 'i18next' | 'vue-i18n';\n /**\n * Source path template using ${locale} and ${key} placeholders.\n * Rendered as a template literal in the generated config.\n */\n sourceTemplate: string;\n /**\n * Force `splitKeys: true` in the generated `syncJSON(...)` call so each\n * top-level key of a single per-locale file becomes its own dictionary.\n *\n * Set for libraries whose single `messages/${locale}.json` file groups\n * namespaces by its first-level keys (`next-intl` / `use-intl`, where\n * `useTranslations('Hero')` resolves to the `Hero` dictionary). Left\n * undefined for libraries whose top-level keys are plain message keys\n * (e.g. `i18next`, `react-intl`); for those, syncJSON's auto-detection\n * (split only when the source has no `${key}` segment) stays in control.\n *\n * Only meaningful for flat templates (no `${key}` segment); it is dropped\n * automatically when the resolved template addresses one namespace per file.\n */\n splitKeys?: boolean;\n};\n\n/**\n * Configuration for injecting a compat vite plugin into vite.config.\n * The plugin replaces the generic `intlayer` plugin for libraries that\n * require alias injection (e.g. `vue-i18n` → `@intlayer/vue-i18n`).\n */\nexport type CompatVitePluginConfig = {\n /** Exported function name from the plugin package, e.g. `'vueI18nVitePlugin'`. */\n pluginFunctionName: string;\n /** Import path for the plugin package, e.g. `'@intlayer/vue-i18n/plugin'`. */\n pluginPackageSource: string;\n};\n\n/** Result of analyzing project dependencies for intlayer package gaps. */\nexport type IntlayerPackageAnalysis = {\n /** Intlayer packages that are referenced but not yet installed. */\n packagesToInstall: string[];\n /** Intlayer dev packages that are referenced but not yet installed. */\n devPackagesToInstall: string[];\n /**\n * syncJSON plugin configuration to inject when a compat i18n library is\n * detected. Undefined when no compat library is present or format is not\n * yet implemented.\n */\n compatSyncConfig: CompatSyncConfig | undefined;\n /**\n * Vite config plugin to inject when a vite-based compat library is\n * detected. Undefined for Next.js/Nuxt-only compat libs or when no compat\n * library requires alias injection.\n */\n compatVitePluginConfig: CompatVitePluginConfig | undefined;\n};\n\n/**\n * Detects the package manager in use by checking for lock files in the\n * project root. Falls back to npm when no lock file is found.\n */\nexport const detectPackageManager = (rootDir: string): PackageManager => {\n if (\n existsSync(join(rootDir, 'bun.lock')) ||\n existsSync(join(rootDir, 'bun.lockb'))\n ) {\n return 'bun';\n }\n if (existsSync(join(rootDir, 'pnpm-lock.yaml'))) {\n return 'pnpm';\n }\n if (existsSync(join(rootDir, 'yarn.lock'))) {\n return 'yarn';\n }\n return 'npm';\n};\n\n/**\n * Returns the install command for the given package manager and package list.\n */\nconst buildInstallCommand = (\n packageManager: PackageManager,\n packages: string[],\n isDev: boolean = false\n): string => {\n const packageList = packages.join(' ');\n switch (packageManager) {\n case 'bun':\n return `bun add ${isDev ? '-d ' : ''}${packageList}`;\n case 'pnpm':\n return `pnpm add ${isDev ? '-D ' : ''}${packageList}`;\n case 'yarn':\n return `yarn add ${isDev ? '-D ' : ''}${packageList}`;\n case 'npm':\n return `npm install ${isDev ? '-D ' : ''}${packageList}`;\n }\n};\n\n/**\n * Analyzes existing project dependencies to determine which intlayer packages\n * are missing and what syncJSON configuration to inject when compat i18n\n * libraries are present.\n */\nexport const detectMissingIntlayerPackages = (\n allDependencies: Record<string, string>\n): IntlayerPackageAnalysis => {\n const packagesToInstall: string[] = [];\n const devPackagesToInstall: string[] = [];\n let compatSyncConfig: CompatSyncConfig | undefined;\n let compatVitePluginConfig: CompatVitePluginConfig | undefined;\n\n const isInstalled = (packageName: string): boolean =>\n Boolean(allDependencies[packageName]);\n\n const addIfMissing = (packageName: string): void => {\n if (!isInstalled(packageName)) {\n packagesToInstall.push(packageName);\n }\n };\n\n const addDevIfMissing = (packageName: string): void => {\n if (!isInstalled(packageName)) {\n devPackagesToInstall.push(packageName);\n }\n };\n\n // Core package — always required\n addIfMissing('intlayer');\n\n // Framework-specific runtime integrations\n if (isInstalled('next')) {\n addIfMissing('next-intlayer');\n } else if (isInstalled('react')) {\n addIfMissing('react-intlayer');\n }\n\n if (isInstalled('svelte')) {\n addIfMissing('svelte-intlayer');\n }\n\n if (isInstalled('solid-js')) {\n addIfMissing('solid-intlayer');\n }\n\n if (isInstalled('@angular/core')) {\n addIfMissing('angular-intlayer');\n }\n\n if (isInstalled('vue')) {\n addIfMissing('vue-intlayer');\n }\n\n if (isInstalled('vite')) {\n addIfMissing('vite-intlayer');\n }\n\n // -------------------------------------------------------------------------\n // Compat adapters for existing i18n libraries.\n //\n // Detection order matters: more specific libraries are checked first so that\n // `compatSyncConfig ??=` and `compatVitePluginConfig ??=` capture the most\n // relevant match. Libraries that only affect the Next.js or Nuxt config do\n // not set `compatVitePluginConfig` (handled separately in init/index.ts).\n // Libraries whose JSON format is not yet supported leave `compatSyncConfig`\n // undefined so no syncJSON plugin is injected.\n // -------------------------------------------------------------------------\n\n // next-intl — next.js only, ICU format. Default layout is a single file per\n // locale (`messages/${locale}.json`) whose top-level keys are namespaces;\n // syncJSON `splitKeys` auto-detection (no `${key}` segment) turns each\n // top-level key into its own dictionary. The exact path is refined from\n // `i18n/request.ts` in init/index.ts when present.\n if (isInstalled('next-intl') || isInstalled('@intlayer/next-intl')) {\n addIfMissing('@intlayer/next-intl');\n addIfMissing('next-intl');\n compatSyncConfig ??= {\n format: 'icu',\n sourceTemplate: './messages/${locale}.json',\n // next-intl groups namespaces by the first-level keys of one file.\n splitKeys: true,\n };\n // next config handled via updateNextConfigForNextIntl in init/index.ts\n }\n\n // next-i18next — next.js only, i18next JSON format\n if (isInstalled('next-i18next') || isInstalled('@intlayer/next-i18next')) {\n addIfMissing('@intlayer/next-i18next');\n addIfMissing('next-i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n // next config handled via updateNextConfigForNextI18next in init/index.ts\n }\n\n // next-translate — next.js only, i18next-style flat-namespace JSON\n if (\n isInstalled('next-translate') ||\n isInstalled('@intlayer/next-translate')\n ) {\n addIfMissing('@intlayer/next-translate');\n addIfMissing('next-translate');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n // next config handled via updateNextConfigForNextTranslate in init/index.ts\n }\n\n // i18next — explicit import from @intlayer/i18next (no alias injection needed)\n if (isInstalled('i18next') || isInstalled('@intlayer/i18next')) {\n addIfMissing('@intlayer/i18next');\n // Ensure the required peer dependency is installed\n addIfMissing('i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n }\n\n // react-i18next — explicit import from @intlayer/react-i18next (no alias)\n if (isInstalled('react-i18next') || isInstalled('@intlayer/react-i18next')) {\n addIfMissing('@intlayer/react-i18next');\n // Ensure the required peer dependency is installed\n addIfMissing('react-i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n }\n\n // vue-i18n — vite alias injection required\n if (isInstalled('vue-i18n') || isInstalled('@intlayer/vue-i18n')) {\n addIfMissing('@intlayer/vue-i18n');\n addIfMissing('vue-i18n');\n compatSyncConfig ??= {\n format: 'vue-i18n',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'vueI18nVitePlugin',\n pluginPackageSource: '@intlayer/vue-i18n/plugin',\n };\n }\n\n // use-intl — framework-agnostic React core of next-intl; vite alias\n // injection required, ICU format. Commonly a single `messages/${locale}.json`\n // file whose top-level keys are namespaces, handled by syncJSON `splitKeys`\n // auto-detection (no `${key}` segment in the source template).\n if (isInstalled('use-intl') || isInstalled('@intlayer/use-intl')) {\n addIfMissing('@intlayer/use-intl');\n addIfMissing('use-intl');\n compatSyncConfig ??= {\n format: 'icu',\n sourceTemplate: './messages/${locale}.json',\n // use-intl (the core of next-intl) uses the same single-file namespace model.\n splitKeys: true,\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'useIntlVitePlugin',\n pluginPackageSource: '@intlayer/use-intl/plugin',\n };\n }\n\n // react-intl — vite alias injection required, ICU format\n if (isInstalled('react-intl') || isInstalled('@intlayer/react-intl')) {\n addIfMissing('@intlayer/react-intl');\n addIfMissing('react-intl');\n compatSyncConfig ??= {\n format: 'icu',\n sourceTemplate: './src/i18n/${locale}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'reactIntlVitePlugin',\n pluginPackageSource: '@intlayer/react-intl/plugin',\n };\n }\n\n // @ngneat/transloco — vite alias injection required\n // @todo syncJSON format not yet implemented for transloco\n if (isInstalled('@ngneat/transloco') || isInstalled('@intlayer/transloco')) {\n addIfMissing('@intlayer/transloco');\n addIfMissing('@ngneat/transloco');\n compatVitePluginConfig ??= {\n pluginFunctionName: 'translocoVitePlugin',\n pluginPackageSource: '@intlayer/transloco/plugin',\n };\n }\n\n // svelte-i18n — vite alias injection required, flat JSON (i18next-compatible)\n if (isInstalled('svelte-i18n') || isInstalled('@intlayer/svelte-i18n')) {\n addIfMissing('@intlayer/svelte-i18n');\n addIfMissing('svelte-i18n');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'svelteI18nVitePlugin',\n pluginPackageSource: '@intlayer/svelte-i18n/plugin',\n };\n }\n\n // node-polyglot — vite alias injection required\n // @todo syncJSON format not yet implemented for polyglot\n if (isInstalled('node-polyglot') || isInstalled('@intlayer/polyglot')) {\n addIfMissing('@intlayer/polyglot');\n addIfMissing('node-polyglot');\n compatVitePluginConfig ??= {\n pluginFunctionName: 'polyglotVitePlugin',\n pluginPackageSource: '@intlayer/polyglot/plugin',\n };\n }\n\n // @nuxtjs/i18n — nuxt module (no vite plugin), vue-i18n JSON format\n if (isInstalled('@nuxtjs/i18n') || isInstalled('@intlayer/nuxtjs-i18n')) {\n addIfMissing('@intlayer/nuxtjs-i18n');\n addIfMissing('@nuxtjs/i18n');\n compatSyncConfig ??= {\n format: 'vue-i18n',\n sourceTemplate: './locales/${locale}/${key}.json',\n };\n // nuxt config handled via updateNuxtConfigForNuxtjsI18n in init/index.ts\n }\n\n // @ngx-translate/core — vite alias injection required, flat JSON (i18next)\n if (\n isInstalled('@ngx-translate/core') ||\n isInstalled('@intlayer/ngx-translate')\n ) {\n addIfMissing('@intlayer/ngx-translate');\n addIfMissing('@ngx-translate/core');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './assets/i18n/${locale}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'ngxTranslateVitePlugin',\n pluginPackageSource: '@intlayer/ngx-translate/plugin',\n };\n }\n\n // @lingui/core — vite alias injection required\n // @todo syncJSON format not yet implemented for lingui (uses PO files)\n if (\n isInstalled('@lingui/core') ||\n isInstalled('@lingui/react') ||\n isInstalled('@intlayer/lingui')\n ) {\n addIfMissing('@intlayer/lingui');\n addIfMissing('@lingui/core');\n compatVitePluginConfig ??= {\n pluginFunctionName: 'linguiVitePlugin',\n pluginPackageSource: '@intlayer/lingui/plugin',\n };\n }\n\n // i18n-js — vite alias injection required\n // @todo syncJSON format not yet implemented for i18n-js\n if (isInstalled('i18n-js') || isInstalled('@intlayer/i18n-js')) {\n addIfMissing('@intlayer/i18n-js');\n addIfMissing('i18n-js');\n compatVitePluginConfig ??= {\n pluginFunctionName: 'i18nJsVitePlugin',\n pluginPackageSource: '@intlayer/i18n-js/plugin',\n };\n }\n\n if (compatSyncConfig) {\n addDevIfMissing('@intlayer/sync-json-plugin');\n }\n\n return {\n packagesToInstall,\n devPackagesToInstall,\n compatSyncConfig,\n compatVitePluginConfig,\n };\n};\n\n/**\n * Runs the package install command synchronously.\n * Throws if the install process exits with a non-zero code.\n */\nexport const installPackages = (\n rootDir: string,\n packages: string[],\n packageManager: PackageManager,\n isDev: boolean = false\n): void => {\n const command = buildInstallCommand(packageManager, packages, isDev);\n execSync(command, { cwd: rootDir, stdio: 'inherit' });\n};\n\n/**\n * Determines whether a dependency name belongs to the Intlayer ecosystem.\n *\n * Matches the core `intlayer` package, every scoped `@intlayer/*` package\n * (including compat adapters such as `@intlayer/next-intl`) and the framework\n * runtime integrations that follow the `<framework>-intlayer` convention\n * (e.g. `next-intlayer`, `react-intlayer`, `express-intlayer`).\n */\nexport const isIntlayerPackageName = (packageName: string): boolean =>\n packageName === 'intlayer' ||\n packageName.startsWith('@intlayer/') ||\n /-intlayer$/.test(packageName);\n\n/**\n * Reduces a semver range or full version to its `major.minor.patch` core,\n * stripping range prefixes (`^`, `~`), pre-release identifiers and build\n * metadata. Returns `null` when no `major.minor.patch` can be extracted.\n *\n * @example normalizeVersion('^9.0.0-canary.3') // '9.0.0'\n */\nexport const normalizeVersion = (version?: string): string | null => {\n if (!version || typeof version !== 'string') return null;\n const match = version.match(/(\\d+)\\.(\\d+)\\.(\\d+)/);\n return match ? `${match[1]}.${match[2]}.${match[3]}` : null;\n};\n\n/**\n * Reads the installed version of a package from its `package.json` inside the\n * project's `node_modules`. Returns `null` when the package is not installed or\n * its manifest cannot be read.\n */\nexport const getInstalledPackageVersion = (\n rootDir: string,\n packageName: string\n): string | null => {\n try {\n const manifestPath = join(\n rootDir,\n 'node_modules',\n packageName,\n 'package.json'\n );\n if (!existsSync(manifestPath)) return null;\n const { version } = JSON.parse(readFileSync(manifestPath, 'utf-8'));\n return typeof version === 'string' ? version : null;\n } catch {\n return null;\n }\n};\n\n/**\n * Returns the Intlayer packages from `dependencies` whose installed version is\n * behind `targetVersion` (compared on `major.minor.patch`). Packages that are\n * not installed yet are ignored — those are handled by\n * {@link detectMissingIntlayerPackages}.\n */\nexport const detectOutdatedIntlayerPackages = (\n rootDir: string,\n dependencies: Record<string, string>,\n targetVersion: string\n): string[] => {\n const normalizedTarget = normalizeVersion(targetVersion);\n if (!normalizedTarget) return [];\n\n return Object.keys(dependencies)\n .filter(isIntlayerPackageName)\n .filter((packageName) => {\n const installedVersion = getInstalledPackageVersion(rootDir, packageName);\n const normalizedInstalled = normalizeVersion(\n installedVersion ?? undefined\n );\n if (!normalizedInstalled) return false;\n return compareVersions(normalizedInstalled, '<', normalizedTarget);\n });\n};\n\n/**\n * Upgrades the given packages to `targetVersion` synchronously, preserving the\n * dependency type via the `isDev` flag. Throws if the install process exits\n * with a non-zero code.\n */\nexport const upgradePackages = (\n rootDir: string,\n packages: string[],\n packageManager: PackageManager,\n targetVersion: string,\n isDev: boolean = false\n): void => {\n if (packages.length === 0) return;\n const versionedPackages = packages.map(\n (packageName) => `${packageName}@${targetVersion}`\n );\n const command = buildInstallCommand(packageManager, versionedPackages, isDev);\n execSync(command, { cwd: rootDir, stdio: 'inherit' });\n};\n"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { nextAppRouterAdapter } from "./nextAppRouter/index.mjs";
2
+ import { tanStackStartAdapter } from "./tanstackStart/index.mjs";
3
+
4
+ //#region src/init/frameworkSetup/index.ts
5
+ /**
6
+ * Registered framework adapters, tried in order. The first one whose `detect`
7
+ * returns true handles the project. Add new adapters (Nuxt, Vite + React, …)
8
+ * here as they are implemented.
9
+ */
10
+ const adapters = [nextAppRouterAdapter, tanStackStartAdapter];
11
+ /**
12
+ * Runs framework-specific scaffolding (middleware/proxy, providers in
13
+ * layout/page, example content) for the first adapter that matches the project.
14
+ * No-ops when no adapter recognizes the project. Each adapter is idempotent and
15
+ * non-destructive, so this is safe to run on existing applications.
16
+ */
17
+ const setupFramework = async (context) => {
18
+ for (const adapter of adapters) if (await adapter.detect(context)) {
19
+ await adapter.setup(context);
20
+ return;
21
+ }
22
+ };
23
+
24
+ //#endregion
25
+ export { setupFramework };
26
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"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,CACnC,sBACA,qBACD;;;;;;;AAQD,MAAa,iBAAiB,OAC5B,YACkB;AAClB,MAAK,MAAM,WAAW,SACpB,KAAI,MAAM,QAAQ,OAAO,QAAQ,EAAE;AACjC,QAAM,QAAQ,MAAM,QAAQ;AAC5B"}
@@ -0,0 +1,52 @@
1
+ import { exists } from "../../utils/fileSystem.mjs";
2
+ import { join } from "node:path";
3
+
4
+ //#region src/init/frameworkSetup/nextAppRouter/detect.ts
5
+ /** Script extensions probed when locating an App Router convention file. */
6
+ const SCRIPT_EXTENSIONS = [
7
+ "tsx",
8
+ "jsx",
9
+ "ts",
10
+ "js"
11
+ ];
12
+ /**
13
+ * Detects the Next.js App Router directory, preferring `src/app` over `app`.
14
+ * Returns `null` when neither exists (e.g. a Pages Router project).
15
+ */
16
+ const detectNextAppDir = async (rootDir) => {
17
+ if (await exists(rootDir, join("src", "app"))) return {
18
+ appDir: join("src", "app"),
19
+ srcDir: "src"
20
+ };
21
+ if (await exists(rootDir, "app")) return {
22
+ appDir: "app",
23
+ srcDir: ""
24
+ };
25
+ return null;
26
+ };
27
+ /**
28
+ * Finds an existing App Router convention file (e.g. `layout`, `page`) within
29
+ * `dir`, trying each known script extension. Returns the matching relative path
30
+ * or `null`.
31
+ */
32
+ const findAppFile = async (rootDir, dir, baseName) => {
33
+ for (const extension of SCRIPT_EXTENSIONS) {
34
+ const candidate = join(dir, `${baseName}.${extension}`);
35
+ if (await exists(rootDir, candidate)) return candidate;
36
+ }
37
+ return null;
38
+ };
39
+ /**
40
+ * Returns true when the dependency `version` range targets a major >= `major`.
41
+ * Tolerant of leading range characters, e.g. `^16.0.0`, `~16`, `16.1.0`.
42
+ */
43
+ const isVersionAtLeast = (version, major) => {
44
+ if (!version || typeof version !== "string") return false;
45
+ const match = version.match(/(\d+)/);
46
+ if (!match?.[1]) return false;
47
+ return parseInt(match[1], 10) >= major;
48
+ };
49
+
50
+ //#endregion
51
+ export { detectNextAppDir, findAppFile, isVersionAtLeast };
52
+ //# sourceMappingURL=detect.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.mjs","names":[],"sources":["../../../../../src/init/frameworkSetup/nextAppRouter/detect.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { exists } from '../../utils/fileSystem';\n\n/** Script extensions probed when locating an App Router convention file. */\nconst SCRIPT_EXTENSIONS = ['tsx', 'jsx', 'ts', 'js'] as const;\n\n/** Location of the Next.js App Router directory within the project. */\nexport type NextAppDirInfo = {\n /** App Router directory relative to the root, e.g. `src/app` or `app`. */\n appDir: string;\n /** `src` when the project uses a `src/` directory, otherwise `''`. */\n srcDir: string;\n};\n\n/**\n * Detects the Next.js App Router directory, preferring `src/app` over `app`.\n * Returns `null` when neither exists (e.g. a Pages Router project).\n */\nexport const detectNextAppDir = async (\n rootDir: string\n): Promise<NextAppDirInfo | null> => {\n if (await exists(rootDir, join('src', 'app'))) {\n return { appDir: join('src', 'app'), srcDir: 'src' };\n }\n if (await exists(rootDir, 'app')) {\n return { appDir: 'app', srcDir: '' };\n }\n return null;\n};\n\n/**\n * Finds an existing App Router convention file (e.g. `layout`, `page`) within\n * `dir`, trying each known script extension. Returns the matching relative path\n * or `null`.\n */\nexport const findAppFile = async (\n rootDir: string,\n dir: string,\n baseName: string\n): Promise<string | null> => {\n for (const extension of SCRIPT_EXTENSIONS) {\n const candidate = join(dir, `${baseName}.${extension}`);\n if (await exists(rootDir, candidate)) {\n return candidate;\n }\n }\n return null;\n};\n\n/**\n * Returns true when the dependency `version` range targets a major >= `major`.\n * Tolerant of leading range characters, e.g. `^16.0.0`, `~16`, `16.1.0`.\n */\nexport const isVersionAtLeast = (\n version: string | undefined,\n major: number\n): boolean => {\n if (!version || typeof version !== 'string') return false;\n const match = version.match(/(\\d+)/);\n if (!match?.[1]) return false;\n return parseInt(match[1], 10) >= major;\n};\n"],"mappings":";;;;;AAIA,MAAM,oBAAoB;CAAC;CAAO;CAAO;CAAM;CAAK;;;;;AAcpD,MAAa,mBAAmB,OAC9B,YACmC;AACnC,KAAI,MAAM,OAAO,SAAS,KAAK,OAAO,MAAM,CAAC,CAC3C,QAAO;EAAE,QAAQ,KAAK,OAAO,MAAM;EAAE,QAAQ;EAAO;AAEtD,KAAI,MAAM,OAAO,SAAS,MAAM,CAC9B,QAAO;EAAE,QAAQ;EAAO,QAAQ;EAAI;AAEtC,QAAO;;;;;;;AAQT,MAAa,cAAc,OACzB,SACA,KACA,aAC2B;AAC3B,MAAK,MAAM,aAAa,mBAAmB;EACzC,MAAM,YAAY,KAAK,KAAK,GAAG,SAAS,GAAG,YAAY;AACvD,MAAI,MAAM,OAAO,SAAS,UAAU,CAClC,QAAO;;AAGX,QAAO;;;;;;AAOT,MAAa,oBACX,SACA,UACY;AACZ,KAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;CACpD,MAAM,QAAQ,QAAQ,MAAM,QAAQ;AACpC,KAAI,CAAC,QAAQ,GAAI,QAAO;AACxB,QAAO,SAAS,MAAM,IAAI,GAAG,IAAI"}