@intlayer/engine 9.5.12 → 9.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/installSkills/skills/cli.md +28 -1
- package/dist/assets/installSkills/skills/compat.md +1 -1
- package/dist/assets/installSkills/skills/dev-tools.md +8 -6
- package/dist/cjs/cli.cjs +2 -0
- package/dist/cjs/init/index.cjs +12 -2
- package/dist/cjs/init/index.cjs.map +1 -1
- package/dist/cjs/init/utils/packageManager.cjs +1 -1
- package/dist/cjs/init/utils/packageManager.cjs.map +1 -1
- package/dist/cjs/installMCP/installMCP.cjs +35 -25
- package/dist/cjs/installMCP/installMCP.cjs.map +1 -1
- package/dist/cjs/installSkills/index.cjs +26 -1
- package/dist/cjs/installSkills/index.cjs.map +1 -1
- package/dist/cjs/listGitFiles.cjs +3 -5
- package/dist/cjs/listGitFiles.cjs.map +1 -1
- package/dist/cjs/listProjects.cjs +1 -2
- package/dist/cjs/listProjects.cjs.map +1 -1
- package/dist/esm/cli.mjs +3 -3
- package/dist/esm/init/index.mjs +12 -2
- package/dist/esm/init/index.mjs.map +1 -1
- package/dist/esm/init/utils/packageManager.mjs +1 -1
- package/dist/esm/init/utils/packageManager.mjs.map +1 -1
- package/dist/esm/installMCP/installMCP.mjs +35 -25
- package/dist/esm/installMCP/installMCP.mjs.map +1 -1
- package/dist/esm/installSkills/index.mjs +27 -3
- package/dist/esm/installSkills/index.mjs.map +1 -1
- package/dist/esm/listGitFiles.mjs +1 -1
- package/dist/esm/listGitFiles.mjs.map +1 -1
- package/dist/esm/listProjects.mjs +1 -1
- package/dist/esm/listProjects.mjs.map +1 -1
- package/dist/esm/utils/runParallel/pidTree.mjs +3 -3
- package/dist/esm/utils/runParallel/pidTree.mjs.map +1 -1
- package/dist/esm/utils/runParallel/ps.mjs +2 -2
- package/dist/esm/utils/runParallel/ps.mjs.map +1 -1
- package/dist/esm/utils/runParallel/wmic.mjs +2 -2
- package/dist/esm/utils/runParallel/wmic.mjs.map +1 -1
- package/dist/types/cli.d.ts +3 -3
- package/dist/types/init/index.d.ts.map +1 -1
- package/dist/types/init/utils/packageManager.d.ts +5 -0
- package/dist/types/init/utils/packageManager.d.ts.map +1 -1
- package/dist/types/installMCP/installMCP.d.ts +4 -0
- package/dist/types/installMCP/installMCP.d.ts.map +1 -1
- package/dist/types/installSkills/index.d.ts +6 -0
- package/dist/types/installSkills/index.d.ts.map +1 -1
- package/package.json +9 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listProjects.cjs","names":["simpleGit","configurationFilesCandidates","fg","dirname"],"sources":["../../src/listProjects.ts"],"sourcesContent":["import { dirname } from 'node:path';\nimport { configurationFilesCandidates } from '@intlayer/config/node';\nimport fg from 'fast-glob';\nimport simpleGit from 'simple-git';\n\nexport type ListProjectsOptions = {\n /**\n * Base directory to search from\n * @default process.cwd()\n */\n baseDir?: string;\n /**\n * If true, search from the git root directory instead of baseDir\n * @default false\n */\n gitRoot?: boolean;\n};\n\n/**\n * Returns the git repository root directory, or `null` when the given\n * directory is not inside a git repository.\n */\nexport const getGitRootDir = async (cwd?: string): Promise<string | null> => {\n try {\n const git = cwd ? simpleGit(cwd) : simpleGit();\n const rootDir = await git.revparse(['--show-toplevel']);\n return rootDir.trim();\n } catch (_error) {\n return null;\n }\n};\n\n/**\n * List all Intlayer projects by searching for configuration files\n *\n * @param options - Options for listing projects\n * @returns Array of absolute paths to project directories containing Intlayer config\n */\nexport const listProjects = async (\n options?: ListProjectsOptions\n): Promise<{ searchDir: string; projectsPath: string[] }> => {\n let searchDir = options?.baseDir ?? process.cwd();\n\n // If gitRoot option is enabled, try to get the git root directory\n if (options?.gitRoot) {\n const gitRootDir = await getGitRootDir(searchDir);\n if (gitRootDir) {\n searchDir = gitRootDir;\n }\n }\n\n // Build glob patterns for all config file candidates\n const configPatterns = configurationFilesCandidates.map(\n (fileName) => `**/${fileName}`\n );\n\n // Search for all config files\n const configFiles = await fg(configPatterns, {\n cwd: searchDir,\n absolute: true,\n ignore: ['**/node_modules/**', '**/.git/**'],\n dot: true, // Include dot files like .intlayerrc\n });\n\n // Extract unique directory paths from config files\n const projectDirs = [...new Set(configFiles.map((file) => dirname(file)))];\n\n // Sort alphabetically for consistent output\n return { searchDir, projectsPath: projectDirs.sort() };\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"listProjects.cjs","names":["simpleGit","configurationFilesCandidates","fg","dirname"],"sources":["../../src/listProjects.ts"],"sourcesContent":["import { dirname } from 'node:path';\nimport { configurationFilesCandidates } from '@intlayer/config/node';\nimport fg from 'fast-glob';\nimport { simpleGit } from 'simple-git';\n\nexport type ListProjectsOptions = {\n /**\n * Base directory to search from\n * @default process.cwd()\n */\n baseDir?: string;\n /**\n * If true, search from the git root directory instead of baseDir\n * @default false\n */\n gitRoot?: boolean;\n};\n\n/**\n * Returns the git repository root directory, or `null` when the given\n * directory is not inside a git repository.\n */\nexport const getGitRootDir = async (cwd?: string): Promise<string | null> => {\n try {\n const git = cwd ? simpleGit(cwd) : simpleGit();\n const rootDir = await git.revparse(['--show-toplevel']);\n return rootDir.trim();\n } catch (_error) {\n return null;\n }\n};\n\n/**\n * List all Intlayer projects by searching for configuration files\n *\n * @param options - Options for listing projects\n * @returns Array of absolute paths to project directories containing Intlayer config\n */\nexport const listProjects = async (\n options?: ListProjectsOptions\n): Promise<{ searchDir: string; projectsPath: string[] }> => {\n let searchDir = options?.baseDir ?? process.cwd();\n\n // If gitRoot option is enabled, try to get the git root directory\n if (options?.gitRoot) {\n const gitRootDir = await getGitRootDir(searchDir);\n if (gitRootDir) {\n searchDir = gitRootDir;\n }\n }\n\n // Build glob patterns for all config file candidates\n const configPatterns = configurationFilesCandidates.map(\n (fileName) => `**/${fileName}`\n );\n\n // Search for all config files\n const configFiles = await fg(configPatterns, {\n cwd: searchDir,\n absolute: true,\n ignore: ['**/node_modules/**', '**/.git/**'],\n dot: true, // Include dot files like .intlayerrc\n });\n\n // Extract unique directory paths from config files\n const projectDirs = [...new Set(configFiles.map((file) => dirname(file)))];\n\n // Sort alphabetically for consistent output\n return { searchDir, projectsPath: projectDirs.sort() };\n};\n"],"mappings":";;;;;;;;;;;;;AAsBA,MAAa,gBAAgB,OAAO,QAAyC;CAC3E,IAAI;EAGF,QAAO,OAFK,UAAMA,sBAAU,GAAG,QAAIA,sBAAU,EACpB,CAAC,SAAS,CAAC,iBAAiB,CAAC,EACxC,CAAC,KAAK;CACtB,SAAS,QAAQ;EACf,OAAO;CACT;AACF;;;;;;;AAQA,MAAa,eAAe,OAC1B,YAC2D;CAC3D,IAAI,YAAY,SAAS,WAAW,QAAQ,IAAI;CAGhD,IAAI,SAAS,SAAS;EACpB,MAAM,aAAa,MAAM,cAAc,SAAS;EAChD,IAAI,YACF,YAAY;CAEhB;CAGA,MAAM,iBAAiBC,mDAA6B,KACjD,aAAa,MAAM,UACtB;CAGA,MAAM,cAAc,UAAMC,mBAAG,gBAAgB;EAC3C,KAAK;EACL,UAAU;EACV,QAAQ,CAAC,sBAAsB,YAAY;EAC3C,KAAK;CACP,CAAC;CAGD,MAAM,cAAc,CAAC,GAAG,IAAI,IAAI,YAAY,KAAK,aAASC,mBAAQ,IAAI,CAAC,CAAC,CAAC;CAGzE,OAAO;EAAE;EAAW,cAAc,YAAY,KAAK;CAAE;AACvD"}
|
package/dist/esm/cli.mjs
CHANGED
|
@@ -16,8 +16,8 @@ import { hasUrlRoutingFramework } from "./init/utils/urlRoutingFramework.mjs";
|
|
|
16
16
|
import { upgradeIntlayerPackages } from "./init/upgradeIntlayerPackages.mjs";
|
|
17
17
|
import { getDefaultApplicationURL, initIntlayer, logInitSuccessMessage } from "./init/index.mjs";
|
|
18
18
|
import { installLSP } from "./installLSP.mjs";
|
|
19
|
-
import { PLATFORMS, PLATFORMS_METADATA, SKILLS, SKILLS_METADATA, getInitialSkills, installSkills } from "./installSkills/index.mjs";
|
|
20
|
-
import { installMCP } from "./installMCP/installMCP.mjs";
|
|
19
|
+
import { PLATFORMS, PLATFORMS_METADATA, SKILLS, SKILLS_METADATA, detectPlatform, getInitialSkills, installSkills } from "./installSkills/index.mjs";
|
|
20
|
+
import { MCP_TRANSPORTS, installMCP } from "./installMCP/installMCP.mjs";
|
|
21
21
|
import { listGitFiles, listGitLines } from "./listGitFiles.mjs";
|
|
22
22
|
|
|
23
|
-
export { COMPAT_I18N_LIBRARIES, DocumentationRouter, NEXT_INTLAYER_BABEL_CONFIG_CONTENT, PLATFORMS, PLATFORMS_METADATA, SKILLS, SKILLS_METADATA, detectCompatI18nLibraries, detectExportedComponentName, detectFormatCommand, detectPackageManager, enableEditorInConfig, findLockFileDir, getContentDeclarationFileTemplate, getDefaultApplicationURL, getDocumentationUrl, getGitRootDir, getInitialSkills, hasLintTooling, hasUrlRoutingFramework, initIntlayer, installLSP, installMCP, installPackages, installSkills, listDictionaries, listDictionariesWithStats, listGitFiles, listGitLines, listProjects, logConfigDetails, logInitSuccessMessage, prepareIntlayer, setupCmsCredentials, transformJSFile, upgradeIntlayerPackages, writeCmsCredentialsToEnv, writeContentDeclaration, writeJSFile };
|
|
23
|
+
export { COMPAT_I18N_LIBRARIES, DocumentationRouter, MCP_TRANSPORTS, NEXT_INTLAYER_BABEL_CONFIG_CONTENT, PLATFORMS, PLATFORMS_METADATA, SKILLS, SKILLS_METADATA, detectCompatI18nLibraries, detectExportedComponentName, detectFormatCommand, detectPackageManager, detectPlatform, enableEditorInConfig, findLockFileDir, getContentDeclarationFileTemplate, getDefaultApplicationURL, getDocumentationUrl, getGitRootDir, getInitialSkills, hasLintTooling, hasUrlRoutingFramework, initIntlayer, installLSP, installMCP, installPackages, installSkills, listDictionaries, listDictionariesWithStats, listGitFiles, listGitLines, listProjects, logConfigDetails, logInitSuccessMessage, prepareIntlayer, setupCmsCredentials, transformJSFile, upgradeIntlayerPackages, writeCmsCredentialsToEnv, writeContentDeclaration, writeJSFile };
|
package/dist/esm/init/index.mjs
CHANGED
|
@@ -60,7 +60,7 @@ const initIntlayer = async (rootDir, options) => {
|
|
|
60
60
|
...packageJson.dependencies ?? {},
|
|
61
61
|
...packageJson.devDependencies ?? {}
|
|
62
62
|
};
|
|
63
|
-
const movedPackages = moveCompatPackagesToDevDependencies(packageJson);
|
|
63
|
+
const movedPackages = options?.noInstallPackages ? [] : moveCompatPackagesToDevDependencies(packageJson);
|
|
64
64
|
if (movedPackages.length > 0) {
|
|
65
65
|
const indentation = packageJsonContent.match(/^[ \t]+(?=")/m)?.[0] ?? 2;
|
|
66
66
|
const trailingNewline = packageJsonContent.endsWith("\n") ? "\n" : "";
|
|
@@ -74,7 +74,8 @@ const initIntlayer = async (rootDir, options) => {
|
|
|
74
74
|
const { packagesToInstall, devPackagesToInstall, compatSyncConfig, compatVitePluginConfig, pendingCompatAdapters } = detectMissingIntlayerPackages(allDeps, {
|
|
75
75
|
linguiCatalogFormat,
|
|
76
76
|
dependencies: packageJson.dependencies,
|
|
77
|
-
devDependencies: packageJson.devDependencies
|
|
77
|
+
devDependencies: packageJson.devDependencies,
|
|
78
|
+
skipLintPlugin: options?.noEslint
|
|
78
79
|
});
|
|
79
80
|
/** Whether the compat adapter for a library is not released yet. */
|
|
80
81
|
const isCompatAdapterPending = (adapterPackage) => pendingCompatAdapters.includes(adapterPackage);
|
|
@@ -172,6 +173,15 @@ const initIntlayer = async (rootDir, options) => {
|
|
|
172
173
|
}
|
|
173
174
|
if (!options?.noEslint && hasLegacyEslint(allDeps)) logger(`${x} ${colorize(LINT_PLUGIN_PACKAGE_NAME, ANSIColors.MAGENTA)} needs ESLint ${9}+ (flat config) — skipped the Intlayer lint rules. Upgrade ESLint to enable them: ${colorizePath(DocumentationRouter.ESLint)}`, { level: "warn" });
|
|
174
175
|
if (!options?.noEslint && hasLintTooling(allDeps)) {
|
|
176
|
+
if (options?.noInstallPackages && !allDeps["eslint-plugin-intlayer"]) {
|
|
177
|
+
const lintPluginSpecifier = options.upgradeToVersion ? `${LINT_PLUGIN_PACKAGE_NAME}@${options.upgradeToVersion}` : LINT_PLUGIN_PACKAGE_NAME;
|
|
178
|
+
try {
|
|
179
|
+
installPackages(rootDir, [lintPluginSpecifier], packageManager, true);
|
|
180
|
+
logger(`${v} Installed: ${colorize(LINT_PLUGIN_PACKAGE_NAME, ANSIColors.MAGENTA)}`);
|
|
181
|
+
} catch {
|
|
182
|
+
logger(`${x} Failed to install ${LINT_PLUGIN_PACKAGE_NAME}. Please install it manually.`, { level: "warn" });
|
|
183
|
+
}
|
|
184
|
+
}
|
|
175
185
|
const oxlintConfigPath = ".oxlintrc.json";
|
|
176
186
|
const hasOxlintConfig = await exists(rootDir, oxlintConfigPath);
|
|
177
187
|
const shouldCreateOxlintConfig = !hasOxlintConfig && Boolean(allDeps.oxlint) && !allDeps.eslint;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/init/index.ts"],"sourcesContent":["import { join } from 'node:path';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { ROUTING_MODE } from '@intlayer/config/defaultValues';\nimport { colorize, colorizePath, logger, v, x } from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\nimport { getAlias } from '@intlayer/config/utils';\nimport { initConfig } from '../initConfig';\nimport {\n setCompilerOutputInConfig,\n setEnableProxyInConfig,\n setRoutingModeInConfig,\n setRoutingStorageOnlyInConfig,\n} from './cms';\nimport {\n DocumentationRouter,\n type DocumentationRouterType,\n getDocumentationUrl,\n} from './documentationRouter';\nimport { setupFramework } from './frameworkSetup';\nimport { upgradeIntlayerPackages } from './upgradeIntlayerPackages';\nimport type { CompatSyncConfig, RoutingMode } from './utils';\nimport {\n addIntlayerRulesToOxlintConfig,\n BACKEND_INTLAYER_PACKAGES,\n detectCompatI18nLibraries,\n detectJsonLocalePattern,\n detectLinguiCatalogPattern,\n detectMissingIntlayerPackages,\n detectNextIntlMessagesPattern,\n detectPackageManager,\n ensureDirectory,\n exists,\n findTsConfigFiles,\n getGithubWorkflows,\n getMetroConfigTemplate,\n hasIntlayerVitePlugin,\n hasLegacyEslint,\n hasLintTooling,\n hasUrlRoutingFramework,\n installPackages,\n isIntlayerPackageName,\n LINT_PLUGIN_PACKAGE_NAME,\n MINIMUM_ESLINT_MAJOR,\n moveCompatPackagesToDevDependencies,\n type OxlintConfig,\n parseJSONWithComments,\n readFileFromRoot,\n replaceViteConfigPluginImportSource,\n resolveGithubWorkflowsContext,\n setupNextCompilerBabelConfig,\n updateAstroConfig,\n updateIntlayerConfigWithSyncPlugin,\n updateMetroConfig,\n updateNextConfig,\n updateNextConfigForNextI18next,\n updateNextConfigForNextIntl,\n updateNextConfigForNextTranslate,\n updateNuxtConfig,\n updateNuxtConfigForNuxtjsI18n,\n updateViteConfig,\n updateViteConfigForCompatPlugin,\n writeFileToRoot,\n} from './utils';\n\nexport {\n DocumentationRouter,\n type DocumentationRouterType,\n getDocumentationUrl,\n};\n\n/**\n * Resolves the default dev-server URL of the detected framework, used as the\n * `editor.applicationURL` of the generated configuration file. Frameworks that\n * embed Vite (Astro, SvelteKit, …) are checked before the bare Vite fallback so\n * their own dev port wins.\n */\nexport const getDefaultApplicationURL = (\n dependencies: Record<string, string>\n): string => {\n if (dependencies.next) return 'http://localhost:3000';\n if (dependencies.astro) return 'http://localhost:4321';\n if (dependencies['@angular/core']) return 'http://localhost:4200';\n if (dependencies.nuxt) return 'http://localhost:3000';\n if (dependencies['@sveltejs/kit']) return 'http://localhost:5173';\n if (dependencies['react-scripts']) return 'http://localhost:3000';\n if (dependencies.vite) return 'http://localhost:5173';\n\n return 'http://localhost:3000';\n};\n\n/**\n * How the interactive init organizes autogenerated content (compiler output /\n * autofill):\n * - `per-component` — multilingual `.content` files co-located with components\n * (the configuration template default).\n * - `centralized` — per-locale JSON dictionaries under `/locales/{locale}/`.\n * - `json-namespaces` — plain per-locale JSON namespace files kept in sync\n * through `@intlayer/sync-json-plugin`.\n */\nexport type ContentStrategy =\n | 'per-component'\n | 'centralized'\n | 'json-namespaces';\n\n/**\n * OPTIONS\n */\nexport type InitOptions = {\n noGitignore?: boolean;\n /** Skip scaffolding the `fill` and `test` GitHub Actions workflows. */\n noGithubActions?: boolean;\n /**\n * Skip installing missing Intlayer dependencies and upgrading the Intlayer\n * packages of every `package.json` to their latest version.\n */\n noInstallPackages?: boolean;\n /** Skip adding the Intlayer extension to `.vscode/extensions.json`. */\n noVscodeExtension?: boolean;\n /** Skip writing the Intlayer LSP configuration to `.vscode/settings.json`. */\n noLsp?: boolean;\n /** Skip enabling the Intlayer lint rules (ESLint / oxlint). */\n noEslint?: boolean;\n /**\n * Skip the project setup: tsconfig types/aliases, the Intlayer config file,\n * bundler/framework configs and framework-specific\n * scaffolding (middleware/proxy, providers in layout/page). Defaults to\n * enabled.\n */\n noFrameworkSetup?: boolean;\n /** Skip logging the final success message and documentation link. */\n skipFinalMessage?: boolean;\n /**\n * Version to install the missing Intlayer packages at (typically the running\n * CLI version). Already declared Intlayer packages are upgraded to the latest\n * published version instead.\n */\n upgradeToVersion?: string;\n /**\n * Locale routing strategy to write to `routing.mode` in the generated/existing\n * Intlayer configuration file. When omitted, the configuration default\n * (`prefix-no-default`) is kept.\n */\n routingMode?: RoutingMode;\n /**\n * Whether the app routes by locale through the Intlayer proxy (middleware).\n * Written to `routing.enableProxy` in the configuration file and drives the\n * framework scaffolding: `false` skips the proxy file and any locale route\n * segment. When omitted, the configured value is kept (unset means enabled).\n */\n enableProxy?: boolean;\n /**\n * Content organization strategy chosen by the interactive init prompt. Drives\n * the `compiler.output` template (`centralized`) or the injection of the\n * syncJSON plugin (`json-namespaces`). When omitted (or `per-component`), the\n * configuration template default is kept.\n */\n contentStrategy?: ContentStrategy;\n};\n\n/**\n * MAIN LOGIC\n */\nexport const initIntlayer = async (rootDir: string, options?: InitOptions) => {\n logger(colorize('Checking Intlayer configuration...', ANSIColors.CYAN));\n\n // READ PACKAGE.JSON\n const packageJsonPath = 'package.json';\n if (!(await exists(rootDir, packageJsonPath))) {\n logger(\n `${x} No ${colorizePath('package.json')} found. Please run this script from the project root.`,\n { level: 'error' }\n );\n process.exit(1);\n }\n\n const packageJsonContent = await readFileFromRoot(rootDir, packageJsonPath);\n let packageJson: Record<string, any>;\n try {\n packageJson = JSON.parse(packageJsonContent);\n } catch {\n logger(`${x} Could not parse ${colorizePath('package.json')}.`, {\n level: 'error',\n });\n process.exit(1);\n }\n\n // Determine the correct documentation URL based on dependencies\n const guideUrl = getDocumentationUrl(packageJson);\n\n const allDeps: Record<string, string> = {\n ...(packageJson.dependencies ?? {}),\n ...(packageJson.devDependencies ?? {}),\n };\n\n // MOVE COMPAT PACKAGES (e.g. next-intl) REPLACED BY @INTLAYER/* TO DEVDEPENDENCIES\n const movedPackages = moveCompatPackagesToDevDependencies(packageJson);\n if (movedPackages.length > 0) {\n const indentation = packageJsonContent.match(/^[ \\t]+(?=\")/m)?.[0] ?? 2;\n const trailingNewline = packageJsonContent.endsWith('\\n') ? '\\n' : '';\n await writeFileToRoot(\n rootDir,\n packageJsonPath,\n `${JSON.stringify(packageJson, null, indentation)}${trailingNewline}`\n );\n for (const pkg of movedPackages) {\n logger(\n `${v} Moved ${colorize(pkg, ANSIColors.MAGENTA)} from dependencies to devDependencies`\n );\n }\n }\n\n // INSTALL MISSING INTLAYER DEPENDENCIES\n const packageManager = detectPackageManager(rootDir);\n\n // lingui keeps its catalogs as `.po` (default) or `.json`. Detect which so the\n // matching sync plugin (`syncPO` / `syncJSON`) + dev dependency are chosen.\n const linguiPresent = Boolean(\n allDeps['@lingui/core'] ||\n allDeps['@lingui/react'] ||\n allDeps['@intlayer/lingui']\n );\n\n const linguiCatalog = linguiPresent\n ? await detectLinguiCatalogPattern(rootDir)\n : null;\n\n // `linguiCatalogFormat` resolution:\n // 1. Filesystem scan result (authoritative when catalogs already exist)\n // 2. Fallback: 'po' (lingui's default) when lingui is installed but no\n // catalogs have been generated yet.\n const linguiCatalogFormat: 'po' | 'json' | null =\n linguiCatalog?.format ?? (linguiPresent ? 'po' : null);\n\n const {\n packagesToInstall,\n devPackagesToInstall,\n compatSyncConfig,\n compatVitePluginConfig,\n pendingCompatAdapters,\n } = detectMissingIntlayerPackages(allDeps, {\n linguiCatalogFormat,\n dependencies: packageJson.dependencies,\n devDependencies: packageJson.devDependencies,\n });\n\n /** Whether the compat adapter for a library is not released yet. */\n const isCompatAdapterPending = (adapterPackage: string): boolean =>\n pendingCompatAdapters.includes(adapterPackage);\n\n if (pendingCompatAdapters.length > 0) {\n logger(\n `${x} No released Intlayer adapter yet for ${pendingCompatAdapters\n .map((adapterPackage) => colorize(adapterPackage, ANSIColors.MAGENTA))\n .join(\n ', '\n )} — keeping your current i18n library and only syncing its catalogs with Intlayer.`,\n { level: 'warn' }\n );\n }\n\n // The `json-namespaces` content strategy uses the same syncJSON pipeline as\n // the compat libraries: plain per-locale JSON namespace files synced through\n // `@intlayer/sync-json-plugin`. A detected compat library keeps precedence —\n // its own catalog format/template is authoritative.\n const wantsJsonNamespaces =\n options?.contentStrategy === 'json-namespaces' && !compatSyncConfig;\n\n if (\n wantsJsonNamespaces &&\n !allDeps['@intlayer/sync-json-plugin'] &&\n !devPackagesToInstall.includes('@intlayer/sync-json-plugin')\n ) {\n devPackagesToInstall.push('@intlayer/sync-json-plugin');\n }\n\n if (!options?.noInstallPackages) {\n const withVersion = (packages: string[]): string[] =>\n options?.upgradeToVersion\n ? packages.map((pkg) =>\n isIntlayerPackageName(pkg)\n ? `${pkg}@${options.upgradeToVersion}`\n : pkg\n )\n : packages;\n\n if (packagesToInstall.length > 0) {\n logger(\n colorize('Installing missing Intlayer dependencies...', ANSIColors.CYAN)\n );\n try {\n installPackages(\n rootDir,\n withVersion(packagesToInstall),\n packageManager\n );\n logger(\n `${v} Installed: ${packagesToInstall.map((pkg) => colorize(pkg, ANSIColors.MAGENTA)).join(', ')}`\n );\n } catch {\n logger(\n `${x} Failed to install packages. Please install manually: ${packagesToInstall.join(' ')}`,\n { level: 'warn' }\n );\n }\n }\n\n if (devPackagesToInstall.length > 0) {\n logger(\n colorize(\n 'Installing missing Intlayer dev dependencies...',\n ANSIColors.CYAN\n )\n );\n try {\n installPackages(\n rootDir,\n withVersion(devPackagesToInstall),\n packageManager,\n true\n );\n logger(\n `${v} Installed: ${devPackagesToInstall.map((pkg) => colorize(pkg, ANSIColors.MAGENTA)).join(', ')}`\n );\n } catch {\n logger(\n `${x} Failed to install dev packages. Please install manually: ${devPackagesToInstall.join(' ')}`,\n { level: 'warn' }\n );\n }\n }\n\n // UPGRADE INTLAYER DEPENDENCIES TO LATEST\n await upgradeIntlayerPackages(rootDir);\n }\n\n // CHECK .GITIGNORE\n const gitignorePath = '.gitignore';\n if (\n !options?.noGitignore &&\n !options?.noFrameworkSetup &&\n (await exists(rootDir, gitignorePath))\n ) {\n const gitignoreContent = await readFileFromRoot(rootDir, gitignorePath);\n\n if (!gitignoreContent.includes('intlayer')) {\n const newContent = `${gitignoreContent}\\n# Intlayer\\n.intlayer\\n`;\n await writeFileToRoot(rootDir, gitignorePath, newContent);\n logger(\n `${v} Added ${colorizePath('.intlayer')} to ${colorizePath(gitignorePath)}`\n );\n } else {\n logger(`${v} ${colorizePath(gitignorePath)} already includes .intlayer`);\n }\n }\n\n // SCAFFOLD GITHUB ACTIONS WORKFLOWS (fill + test)\n // Generate two workflows whose commands match the detected package manager:\n // - intlayer-fill.yml: auto-fills missing translations on pull requests\n // - intlayer-test.yml: fails the PR when required locales are missing\n // Every command runs with `--ci`, which iterates over the Intlayer\n // project(s) of the repository. GitHub only triggers workflows stored at the\n // repository root, so in a monorepo the files are written to the git root\n // (see resolveGithubWorkflowsContext).\n if (!options?.noGithubActions) {\n const workflowsContext = await resolveGithubWorkflowsContext(\n rootDir,\n packageManager\n );\n const workflows = getGithubWorkflows(\n workflowsContext.packageManager,\n workflowsContext.options\n );\n\n for (const workflow of workflows) {\n if (await exists(workflowsContext.workflowsRootDir, workflow.filePath)) {\n logger(`${v} ${colorizePath(workflow.filePath)} already exists`);\n continue;\n }\n\n try {\n await ensureDirectory(\n workflowsContext.workflowsRootDir,\n join('.github', 'workflows')\n );\n await writeFileToRoot(\n workflowsContext.workflowsRootDir,\n workflow.filePath,\n workflow.content\n );\n logger(\n `${v} Added GitHub Actions workflow ${colorizePath(workflow.filePath)}`\n );\n } catch {\n logger(\n `${x} Could not create ${colorizePath(workflow.filePath)}. You may need to add it manually.`,\n { level: 'warn' }\n );\n }\n }\n }\n\n // CHECK VS CODE EXTENSION RECOMMENDATIONS\n const vscodeDir = '.vscode';\n const extensionsJsonPath = join(vscodeDir, 'extensions.json');\n const extensionId = 'intlayer.intlayer-vs-code-extension';\n\n if (!options?.noVscodeExtension) {\n try {\n let extensionsConfig: { recommendations: string[] } = {\n recommendations: [],\n };\n\n if (await exists(rootDir, extensionsJsonPath)) {\n const content = await readFileFromRoot(rootDir, extensionsJsonPath);\n extensionsConfig = parseJSONWithComments(content);\n } else {\n await ensureDirectory(rootDir, vscodeDir);\n }\n\n if (!extensionsConfig.recommendations) {\n extensionsConfig.recommendations = [];\n }\n\n if (!extensionsConfig.recommendations.includes(extensionId)) {\n extensionsConfig.recommendations.push(extensionId);\n await writeFileToRoot(\n rootDir,\n extensionsJsonPath,\n JSON.stringify(extensionsConfig, null, 2)\n );\n logger(\n `${v} Added ${colorize(extensionId, ANSIColors.MAGENTA)} to ${colorizePath(extensionsJsonPath)}`\n );\n } else {\n logger(\n `${v} ${colorizePath(extensionsJsonPath)} already includes ${colorize(extensionId, ANSIColors.MAGENTA)}`\n );\n }\n } catch {\n logger(\n `${x} Could not update ${colorizePath(extensionsJsonPath)}. You may need to add ${colorize(extensionId, ANSIColors.MAGENTA)} manually.`,\n { level: 'warn' }\n );\n }\n }\n\n // CHECK VS CODE LSP SETTINGS\n const settingsJsonPath = join(vscodeDir, 'settings.json');\n\n if (!options?.noLsp) {\n try {\n let settingsConfig: Record<string, unknown> = {};\n\n if (await exists(rootDir, settingsJsonPath)) {\n const content = await readFileFromRoot(rootDir, settingsJsonPath);\n settingsConfig = parseJSONWithComments(content);\n } else {\n await ensureDirectory(rootDir, vscodeDir);\n }\n\n let settingsUpdated = false;\n\n if (!settingsConfig['intlayer.languageServer.command']) {\n settingsConfig['intlayer.languageServer.command'] = 'npx';\n settingsUpdated = true;\n }\n\n if (!settingsConfig['intlayer.languageServer.args']) {\n settingsConfig['intlayer.languageServer.args'] = ['@intlayer/lsp'];\n settingsUpdated = true;\n }\n\n if (settingsUpdated) {\n await writeFileToRoot(\n rootDir,\n settingsJsonPath,\n JSON.stringify(settingsConfig, null, 2)\n );\n logger(\n `${v} Updated ${colorizePath(settingsJsonPath)} with LSP configuration`\n );\n } else {\n logger(\n `${v} ${colorizePath(settingsJsonPath)} already includes LSP configuration`\n );\n }\n } catch {\n logger(\n `${x} Could not update ${colorizePath(settingsJsonPath)}. You may need to add the LSP settings manually.`,\n { level: 'warn' }\n );\n }\n }\n\n // CHECK LINT RULES (eslint-plugin-intlayer)\n //\n // Gated on the project already having a linter installed: with no ESLint or\n // oxlint there is nothing to plug the rules into, and the guidance below\n // would just be noise. The same check gates the install in\n // `detectMissingIntlayerPackages`, so the two never disagree.\n //\n // Only the oxlint config is patched here: `.oxlintrc.json` is plain JSON and\n // safe to edit, whereas an ESLint flat config is arbitrary JavaScript that\n // cannot be rewritten reliably — that one is left to the user, with the\n // snippet printed below.\n if (!options?.noEslint && hasLegacyEslint(allDeps)) {\n logger(\n `${x} ${colorize(LINT_PLUGIN_PACKAGE_NAME, ANSIColors.MAGENTA)} needs ESLint ${MINIMUM_ESLINT_MAJOR}+ (flat config) — skipped the Intlayer lint rules. Upgrade ESLint to enable them: ${colorizePath(DocumentationRouter.ESLint)}`,\n { level: 'warn' }\n );\n }\n\n if (!options?.noEslint && hasLintTooling(allDeps)) {\n const oxlintConfigPath = '.oxlintrc.json';\n const hasOxlintConfig = await exists(rootDir, oxlintConfigPath);\n // An oxlint-only project without a config gets one; with ESLint around,\n // the rules go into the ESLint config instead.\n const shouldCreateOxlintConfig =\n !hasOxlintConfig && Boolean(allDeps.oxlint) && !allDeps.eslint;\n\n if (hasOxlintConfig || shouldCreateOxlintConfig) {\n try {\n const oxlintConfig: OxlintConfig = hasOxlintConfig\n ? parseJSONWithComments(\n await readFileFromRoot(rootDir, oxlintConfigPath)\n )\n : {};\n\n if (addIntlayerRulesToOxlintConfig(oxlintConfig)) {\n await writeFileToRoot(\n rootDir,\n oxlintConfigPath,\n JSON.stringify(oxlintConfig, null, 2)\n );\n logger(\n `${v} ${hasOxlintConfig ? 'Added the Intlayer lint rules to' : 'Created'} ${colorizePath(oxlintConfigPath)}`\n );\n } else {\n logger(\n `${v} ${colorizePath(oxlintConfigPath)} already includes the Intlayer lint rules`\n );\n }\n } catch {\n logger(\n `${x} Could not update ${colorizePath(oxlintConfigPath)}. You may need to add ${colorize(LINT_PLUGIN_PACKAGE_NAME, ANSIColors.MAGENTA)} manually.`,\n { level: 'warn' }\n );\n }\n } else {\n // ESLint flat config — print the snippet instead of rewriting the file.\n logger([\n colorize('Intlayer lint rules →', ANSIColors.MAGENTA),\n colorize(\n `Add the ${LINT_PLUGIN_PACKAGE_NAME} preset to the array your ESLint flat config exports, to catch hardcoded text and dynamic calls the compiler cannot optimize:`,\n ANSIColors.GREY_LIGHT\n ),\n colorize(\n ` import intlayer from '${LINT_PLUGIN_PACKAGE_NAME}';\\n\\n export default [\\n // ...your existing config\\n ...intlayer.configs.recommended,\\n ];`,\n ANSIColors.GREY_LIGHT\n ),\n colorizePath(DocumentationRouter.ESLint),\n ]);\n }\n }\n\n // PROJECT SETUP\n // Everything below edits the project itself: tsconfig types and aliases, the\n // Intlayer config file, bundler/framework configs and the\n // framework scaffolding. It only runs with the framework setup step, so\n // picking e.g. only the CI or editor steps never creates project files.\n if (!options?.noFrameworkSetup) {\n // CHECK TSCONFIGS\n const tsConfigFiles = await findTsConfigFiles(rootDir);\n let hasTsConfig = false;\n\n for (const fileName of tsConfigFiles) {\n if (await exists(rootDir, fileName)) {\n hasTsConfig = true;\n try {\n const fileContent = await readFileFromRoot(rootDir, fileName);\n const config = parseJSONWithComments(fileContent);\n const typeDefinition = './.intlayer/**/*.ts';\n\n let updated = false;\n\n if (!config.include) {\n // Skip if no include array (solution-style)\n } else if (\n Array.isArray(config.include) &&\n !(config.include as string[]).some((pattern: string) =>\n pattern.includes('.intlayer')\n )\n ) {\n config.include.push(typeDefinition);\n updated = true;\n } else if (config.include.includes(typeDefinition)) {\n logger(\n `${v} ${colorizePath(fileName)} already includes intlayer types`\n );\n }\n\n if (updated) {\n await writeFileToRoot(\n rootDir,\n fileName,\n JSON.stringify(config, null, 2)\n );\n logger(\n `${v} Updated ${colorizePath(fileName)} to include intlayer types`\n );\n }\n } catch {\n logger(\n `${x} Could not parse or update ${colorizePath(fileName)}. You may need to add ${colorizePath('.intlayer/types/**/*.ts')} manually.`,\n { level: 'warn' }\n );\n }\n }\n }\n\n // INITIALIZE CONFIG FILE\n const format = hasTsConfig ? 'intlayer.config.ts' : 'intlayer.config.mjs';\n\n // Detect the locale JSON file pattern already in the project so we can\n // insert the matching locales into the config and produce the most\n // accurate source template for compat libraries.\n const detectedPattern = await detectJsonLocalePattern(rootDir);\n\n const isConfigCreated = await initConfig(format, rootDir, {\n locales: detectedPattern?.locales,\n applicationURL: getDefaultApplicationURL(allDeps),\n });\n\n // APPLY CONTENT STRATEGY — CENTRALIZED\n // Point `compiler.output` at per-locale JSON dictionaries under `/locales/`\n // instead of the per-component template default.\n if (options?.contentStrategy === 'centralized') {\n await setCompilerOutputInConfig(\n rootDir,\n '/locales/{{locale}}/{{key}}.content.json'\n );\n }\n\n // INJECT SYNC-JSON PLUGIN FOR COMPAT LIBRARIES / JSON-NAMESPACES STRATEGY\n const syncConfigToInject: CompatSyncConfig | undefined =\n compatSyncConfig ??\n (wantsJsonNamespaces\n ? {\n format: 'i18next',\n sourceTemplate:\n detectedPattern?.template ?? './locales/${locale}/${key}.json',\n }\n : undefined);\n\n if (syncConfigToInject) {\n // For next-intl / use-intl, the messages path is authoritatively declared\n // in `i18n/request.ts` (e.g. `import(`../messages/${locale}.json`)`), so we\n // read it directly. It usually resolves to a single file per locale (no\n // `${key}` segment), whose first-level keys are namespaces — so the compat\n // config carries `splitKeys: true` to emit one dictionary per namespace.\n // Falls back to file-system globbing otherwise.\n const nextIntlMessagesPattern =\n allDeps['next-intl'] ||\n allDeps['@intlayer/next-intl'] ||\n allDeps['use-intl'] ||\n allDeps['@intlayer/use-intl']\n ? await detectNextIntlMessagesPattern(rootDir)\n : null;\n\n // lingui authoritatively resolves to `…/{locale}/messages.{po,json}`, where\n // the `messages` filename becomes the dictionary key. Prefer it so a `.po`\n // project gets `syncPO` (the generic JSON glob only sees `.json`).\n const sourceTemplate =\n linguiCatalog?.template ??\n nextIntlMessagesPattern?.template ??\n detectedPattern?.template;\n\n const resolvedSyncConfig = {\n ...syncConfigToInject,\n ...(sourceTemplate ? { sourceTemplate } : {}),\n };\n\n const syncPluginPackage =\n resolvedSyncConfig.plugin === 'po'\n ? '@intlayer/sync-po-plugin'\n : '@intlayer/sync-json-plugin';\n const syncPluginName =\n resolvedSyncConfig.plugin === 'po' ? 'syncPO' : 'syncJSON';\n\n // `splitKeys` only makes sense for a single file holding several namespaces.\n // If the resolved template addresses one namespace per file (`${key}`\n // segment), each file is already a single namespace — drop the flag so\n // syncJSON keeps one dictionary per file.\n if (\n resolvedSyncConfig.splitKeys &&\n resolvedSyncConfig.sourceTemplate.includes('${key}')\n ) {\n resolvedSyncConfig.splitKeys = false;\n }\n\n const intlayerConfigCandidates = [\n 'intlayer.config.ts',\n 'intlayer.config.mjs',\n 'intlayer.config.js',\n 'intlayer.config.cjs',\n ];\n\n for (const configFile of intlayerConfigCandidates) {\n if (await exists(rootDir, configFile)) {\n const configContent = await readFileFromRoot(rootDir, configFile);\n\n if (!configContent.includes(syncPluginPackage)) {\n const extension = configFile.split('.').pop()!;\n const updatedConfigContent = updateIntlayerConfigWithSyncPlugin(\n configContent,\n extension,\n resolvedSyncConfig\n );\n await writeFileToRoot(rootDir, configFile, updatedConfigContent);\n logger(\n `${v} Updated ${colorizePath(configFile)} with ${syncPluginName} compat plugin`\n );\n } else {\n logger(\n `${v} ${colorizePath(configFile)} already includes ${syncPluginName} plugin`\n );\n }\n break;\n }\n }\n }\n\n // APPLY ROUTING\n // An explicit choice (interactive prompt / `--routing`) is written to\n // `routing.mode` + `routing.enableProxy`. Without one, a freshly created\n // config is adapted to the project: frontends get prefix routing through\n // the proxy (the template ships it disabled), projects without URL routing\n // (backend, React Native…) keep only `routing.storage`. An existing config\n // is never rewritten without an explicit choice. A compat i18n library\n // owns the app routing, so its config keeps the template's disabled proxy:\n // compat bundler plugins wrap `intlayer()`, which would register it.\n const hasUrlRouting = hasUrlRoutingFramework(allDeps);\n const hasCompatI18nLibrary = detectCompatI18nLibraries(allDeps).length > 0;\n const shouldApplyDefaultRouting =\n isConfigCreated &&\n options?.routingMode === undefined &&\n !hasCompatI18nLibrary;\n\n if (shouldApplyDefaultRouting && !hasUrlRouting) {\n await setRoutingStorageOnlyInConfig(rootDir);\n }\n\n const routingMode =\n options?.routingMode ??\n (shouldApplyDefaultRouting && hasUrlRouting ? ROUTING_MODE : undefined);\n const enableProxy =\n options?.enableProxy ??\n (shouldApplyDefaultRouting && hasUrlRouting ? true : undefined);\n\n if (routingMode) {\n await setRoutingModeInConfig(rootDir, routingMode);\n }\n\n if (enableProxy !== undefined) {\n await setEnableProxyInConfig(rootDir, enableProxy);\n }\n\n let hasAliasConfiguration = false;\n\n // CHECK VITE CONFIG\n const viteConfigs = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs'];\n\n for (const file of viteConfigs) {\n if (await exists(rootDir, file)) {\n hasAliasConfiguration = true;\n const content = await readFileFromRoot(rootDir, file);\n const extension = file.split('.').pop()!;\n\n if (compatVitePluginConfig) {\n const { replacesVitePlugin } = compatVitePluginConfig;\n\n if (content.includes(compatVitePluginConfig.pluginPackageSource)) {\n logger(\n `${v} ${colorizePath(file)} already includes ${compatVitePluginConfig.pluginPackageSource}`\n );\n } else if (\n replacesVitePlugin &&\n content.includes(replacesVitePlugin.fromPackageSource)\n ) {\n // Drop-in replacement: rewrite the original i18n vite plugin's import\n // source, keeping its binding and call site (e.g. lingui).\n const updatedContent = replaceViteConfigPluginImportSource(\n content,\n replacesVitePlugin.importName,\n replacesVitePlugin.fromPackageSource,\n compatVitePluginConfig.pluginPackageSource\n );\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to import ${replacesVitePlugin.importName} from ${compatVitePluginConfig.pluginPackageSource}`\n );\n } else {\n const updatedContent = updateViteConfigForCompatPlugin(\n content,\n extension,\n compatVitePluginConfig\n );\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include ${compatVitePluginConfig.pluginFunctionName} compat plugin`\n );\n }\n } else if (hasIntlayerVitePlugin(content)) {\n // A compat adapter plugin (e.g. `reactI18nextVitePlugin`) already wraps\n // `intlayer()` internally, so skip adding a redundant standalone plugin.\n logger(\n `${v} ${colorizePath(file)} already includes an Intlayer plugin`\n );\n } else {\n const updatedContent = updateViteConfig(content, extension);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include Intlayer plugin`\n );\n }\n break;\n }\n }\n\n // CHECK NEXT CONFIG\n const nextConfigs = ['next.config.js', 'next.config.mjs', 'next.config.ts'];\n let isNextJsProject = false;\n\n for (const file of nextConfigs) {\n if (await exists(rootDir, file)) {\n isNextJsProject = true;\n hasAliasConfiguration = true;\n const content = await readFileFromRoot(rootDir, file);\n const extension = file.split('.').pop()!;\n\n if (allDeps['next-i18next'] || allDeps['@intlayer/next-i18next']) {\n if (!content.includes('@intlayer/next-i18next')) {\n const updatedContent = updateNextConfigForNextI18next(\n content,\n extension\n );\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include Intlayer next-i18next compat plugin`\n );\n } else {\n logger(\n `${v} ${colorizePath(file)} already includes @intlayer/next-i18next`\n );\n }\n } else if (allDeps['next-intl'] || allDeps['@intlayer/next-intl']) {\n if (!content.includes('@intlayer/next-intl/plugin')) {\n const updatedContent = updateNextConfigForNextIntl(\n content,\n extension\n );\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include Intlayer next-intl compat plugin`\n );\n } else {\n logger(\n `${v} ${colorizePath(file)} already includes @intlayer/next-intl/plugin`\n );\n }\n } else if (isCompatAdapterPending('@intlayer/next-translate')) {\n logger(\n `${v} Kept ${colorizePath(file)} untouched (next-translate stays in charge)`\n );\n } else if (\n allDeps['next-translate'] ||\n allDeps['@intlayer/next-translate']\n ) {\n if (!content.includes('@intlayer/next-translate')) {\n const updatedContent = updateNextConfigForNextTranslate(\n content,\n extension\n );\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include Intlayer next-translate compat plugin`\n );\n } else {\n logger(\n `${v} ${colorizePath(file)} already includes @intlayer/next-translate`\n );\n }\n } else if (!content.includes('next-intlayer')) {\n const updatedContent = updateNextConfig(content, extension);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include Intlayer plugin`\n );\n }\n break;\n }\n }\n\n // CHECK NEXT.JS COMPILER (BABEL)\n // When a Next.js project already uses Babel, install @intlayer/babel and print\n // the compiler + build-optimization plugins (extract, purge, minify, optimize)\n // to add. SWC projects need no setup: withIntlayer injects @intlayer/swc.\n if (isNextJsProject) {\n await setupNextCompilerBabelConfig({\n rootDir,\n packageManager,\n allDeps,\n skipInstall: Boolean(options?.noInstallPackages),\n });\n }\n\n // CHECK OTHER FRAMEWORKS CONFIG\n const astroConfigs = [\n 'astro.config.mjs',\n 'astro.config.js',\n 'astro.config.ts',\n 'astro.config.cjs',\n ];\n\n for (const file of astroConfigs) {\n if (await exists(rootDir, file)) {\n hasAliasConfiguration = true;\n\n if (file.startsWith('astro.config.')) {\n const content = await readFileFromRoot(rootDir, file);\n\n if (!content.includes('astro-intlayer')) {\n const extension = file.split('.').pop()!;\n const updatedContent = updateAstroConfig(content, extension);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include Intlayer integration`\n );\n }\n }\n break;\n }\n }\n\n const nuxtConfigs = ['nuxt.config.js', 'nuxt.config.ts'];\n for (const file of nuxtConfigs) {\n if (await exists(rootDir, file)) {\n hasAliasConfiguration = true;\n\n const content = await readFileFromRoot(rootDir, file);\n\n if (isCompatAdapterPending('@intlayer/nuxtjs-i18n')) {\n logger(\n `${v} Kept ${colorizePath(file)} untouched (@nuxtjs/i18n stays in charge)`\n );\n } else if (allDeps['@nuxtjs/i18n']) {\n if (!content.includes('@intlayer/nuxtjs-i18n')) {\n const updatedContent = updateNuxtConfigForNuxtjsI18n(content);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include @intlayer/nuxtjs-i18n module`\n );\n } else {\n logger(\n `${v} ${colorizePath(file)} already includes @intlayer/nuxtjs-i18n`\n );\n }\n } else if (!content.includes('nuxt-intlayer')) {\n const updatedContent = updateNuxtConfig(content);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include Intlayer module`\n );\n }\n break;\n }\n }\n\n // CHECK METRO CONFIG (React Native / Expo)\n // Metro is the React Native bundler. The Intlayer Metro plugin\n // (`react-native-intlayer/metro`) handles dictionary aliasing and building.\n // When no config exists we scaffold one; when one exists we safely wrap its\n // exported config with `configMetroIntlayerSync`, leaving custom async\n // (IIFE) configs untouched so existing setups are never broken.\n const isReactNativeProject = Boolean(\n allDeps['react-native'] || allDeps.expo\n );\n\n if (isReactNativeProject) {\n // Metro resolves Intlayer aliases itself, so skip the alias fallback below.\n hasAliasConfiguration = true;\n\n const metroConfigs = [\n 'metro.config.js',\n 'metro.config.cjs',\n 'metro.config.mjs',\n 'metro.config.ts',\n ];\n\n let metroConfigFile: string | undefined;\n\n for (const file of metroConfigs) {\n if (await exists(rootDir, file)) {\n metroConfigFile = file;\n break;\n }\n }\n\n if (metroConfigFile) {\n const content = await readFileFromRoot(rootDir, metroConfigFile);\n\n if (content.includes('react-native-intlayer')) {\n logger(\n `${v} ${colorizePath(metroConfigFile)} already includes the Intlayer Metro plugin`\n );\n } else {\n const extension = metroConfigFile.split('.').pop()!;\n const updatedContent = updateMetroConfig(content, extension);\n\n if (updatedContent !== content) {\n await writeFileToRoot(rootDir, metroConfigFile, updatedContent);\n logger(\n `${v} Updated ${colorizePath(metroConfigFile)} to include the Intlayer Metro plugin`\n );\n } else {\n logger(\n `${x} Could not automatically update ${colorizePath(metroConfigFile)}. Wrap your exported config with ${colorize('configMetroIntlayer', ANSIColors.MAGENTA)}: ${colorizePath(DocumentationRouter.ReactNativeAndExpo)}`,\n { level: 'warn' }\n );\n }\n }\n } else {\n const newMetroConfigFile = 'metro.config.js';\n await writeFileToRoot(\n rootDir,\n newMetroConfigFile,\n getMetroConfigTemplate(Boolean(allDeps.expo))\n );\n logger(\n `${v} Created ${colorizePath(newMetroConfigFile)} with the Intlayer Metro plugin`\n );\n }\n }\n\n // CHECK WEBPACK CONFIG\n const webpackConfigs = [\n 'webpack.config.js',\n 'webpack.config.ts',\n 'webpack.config.mjs',\n 'webpack.config.cjs',\n ];\n\n for (const file of webpackConfigs) {\n if (await exists(rootDir, file)) {\n hasAliasConfiguration = true;\n logger(\n `${v} Found ${colorizePath(\n file\n )}. Make sure to configure aliases manually or use the Intlayer Webpack plugin.`\n );\n break;\n }\n }\n\n // The server frameworks themselves, alongside their Intlayer packages: a\n // project may be mid-setup and carry only one of the two.\n const backendConfigPackages = [\n 'express',\n 'fastify',\n '@adonisjs/core',\n 'hono',\n 'elysia',\n ...BACKEND_INTLAYER_PACKAGES,\n ];\n\n if (backendConfigPackages.some((pkg) => allDeps[pkg])) {\n hasAliasConfiguration = true;\n }\n\n if (!hasAliasConfiguration) {\n const configuration = getConfiguration({ baseDir: rootDir });\n // `tsconfig`/`jsconfig` `paths` and `package.json` `imports` both expect\n // explicitly relative specifiers, so bare relative paths get a `./` prefix.\n const aliases = getAlias({\n configuration,\n formatter: (value) =>\n value.startsWith('./') || value.startsWith('../')\n ? value\n : `./${value}`,\n });\n\n if (hasTsConfig && tsConfigFiles.length > 0) {\n const tsConfigPath =\n tsConfigFiles.find((file) => file === 'tsconfig.json') ||\n tsConfigFiles[0];\n\n if (tsConfigPath) {\n const tsConfigContent = await readFileFromRoot(rootDir, tsConfigPath);\n const config = parseJSONWithComments(tsConfigContent);\n\n config.compilerOptions ??= {};\n config.compilerOptions.paths ??= {};\n\n let updated = false;\n\n Object.entries(aliases).forEach(([alias, path]) => {\n if (!config.compilerOptions.paths[alias]) {\n config.compilerOptions.paths[alias] = [path];\n updated = true;\n }\n });\n\n if (updated) {\n await writeFileToRoot(\n rootDir,\n tsConfigPath,\n JSON.stringify(config, null, 2)\n );\n\n logger(\n `${v} Updated ${colorizePath(\n tsConfigPath\n )} to include Intlayer aliases`\n );\n }\n }\n } else {\n const jsConfigPath = 'jsconfig.json';\n\n if (await exists(rootDir, jsConfigPath)) {\n const jsConfigContent = await readFileFromRoot(rootDir, jsConfigPath);\n const config = parseJSONWithComments(jsConfigContent);\n\n config.compilerOptions ??= {};\n config.compilerOptions.paths ??= {};\n\n let updated = false;\n\n Object.entries(aliases).forEach(([alias, path]) => {\n if (!config.compilerOptions.paths[alias]) {\n config.compilerOptions.paths[alias] = [path];\n updated = true;\n }\n });\n\n if (updated) {\n await writeFileToRoot(\n rootDir,\n jsConfigPath,\n JSON.stringify(config, null, 2)\n );\n logger(\n `${v} Updated ${colorizePath(\n jsConfigPath\n )} to include Intlayer aliases`\n );\n }\n } else {\n packageJson.imports ??= {};\n\n let updated = false;\n\n Object.entries(aliases).forEach(([alias, path]) => {\n const importAlias = alias.replace('@', '#');\n\n if (!packageJson.imports[importAlias]) {\n packageJson.imports[importAlias] = path;\n updated = true;\n }\n });\n\n if (updated) {\n await writeFileToRoot(\n rootDir,\n packageJsonPath,\n JSON.stringify(packageJson, null, 2)\n );\n logger(\n `${v} Updated ${colorizePath(\n packageJsonPath\n )} to include Intlayer imports`\n );\n }\n }\n }\n }\n\n // FRAMEWORK-SPECIFIC SCAFFOLDING\n // Sets up middleware/proxy and wraps the layout/page with the Intlayer\n // providers for the detected framework (Next.js App Router today). Idempotent\n // and non-destructive: it never overwrites user code it cannot safely\n // transform, skipping with guidance instead.\n //\n // Skipped entirely when a compat i18n library drives the app (i18next,\n // next-intl, vue-i18n, …): the app already owns its routing, providers and\n // layouts, and Intlayer only syncs its catalogs — restructuring routes or\n // injecting providers would break the existing setup.\n const hasCompatLibrary = Boolean(\n compatSyncConfig || compatVitePluginConfig\n );\n\n if (hasCompatLibrary) {\n logger(\n `${v} Compat i18n library detected — keeping the app structure untouched (no route restructure, no provider injection)`\n );\n }\n\n if (!hasCompatLibrary) {\n try {\n // Prefer the user's choices, else the configured routing (mode defaults\n // to `prefix-no-default`, an unset `enableProxy` means enabled). Drives\n // the proxy file and the locale route segment the adapters scaffold.\n const { routing } = getConfiguration({ baseDir: rootDir });\n\n await setupFramework({\n rootDir,\n allDeps,\n packageManager,\n useTypeScript: hasTsConfig,\n routingMode: routingMode ?? routing.mode,\n enableProxy: enableProxy ?? routing.enableProxy !== false,\n });\n } catch {\n logger(\n `${x} Framework-specific scaffolding failed. Your existing files were left untouched; follow the documentation to finish the setup.`,\n { level: 'warn' }\n );\n }\n }\n }\n\n // FINAL SUCCESS MESSAGE\n if (!options?.skipFinalMessage) {\n logInitSuccessMessage(guideUrl);\n }\n\n return { guideUrl };\n};\n\nexport const logInitSuccessMessage = (guideUrl: string): void => {\n logger(`${v} ${colorize('Intlayer init setup complete.', ANSIColors.GREEN)}`);\n logger([\n colorize('Next →', ANSIColors.MAGENTA),\n colorize(\n 'Follow the instructions in the documentation to complete the setup:',\n ANSIColors.GREY_LIGHT\n ),\n colorizePath(guideUrl),\n ]);\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/init/index.ts"],"sourcesContent":["import { join } from 'node:path';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { ROUTING_MODE } from '@intlayer/config/defaultValues';\nimport { colorize, colorizePath, logger, v, x } from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\nimport { getAlias } from '@intlayer/config/utils';\nimport { initConfig } from '../initConfig';\nimport {\n setCompilerOutputInConfig,\n setEnableProxyInConfig,\n setRoutingModeInConfig,\n setRoutingStorageOnlyInConfig,\n} from './cms';\nimport {\n DocumentationRouter,\n type DocumentationRouterType,\n getDocumentationUrl,\n} from './documentationRouter';\nimport { setupFramework } from './frameworkSetup';\nimport { upgradeIntlayerPackages } from './upgradeIntlayerPackages';\nimport type { CompatSyncConfig, RoutingMode } from './utils';\nimport {\n addIntlayerRulesToOxlintConfig,\n BACKEND_INTLAYER_PACKAGES,\n detectCompatI18nLibraries,\n detectJsonLocalePattern,\n detectLinguiCatalogPattern,\n detectMissingIntlayerPackages,\n detectNextIntlMessagesPattern,\n detectPackageManager,\n ensureDirectory,\n exists,\n findTsConfigFiles,\n getGithubWorkflows,\n getMetroConfigTemplate,\n hasIntlayerVitePlugin,\n hasLegacyEslint,\n hasLintTooling,\n hasUrlRoutingFramework,\n installPackages,\n isIntlayerPackageName,\n LINT_PLUGIN_PACKAGE_NAME,\n MINIMUM_ESLINT_MAJOR,\n moveCompatPackagesToDevDependencies,\n type OxlintConfig,\n parseJSONWithComments,\n readFileFromRoot,\n replaceViteConfigPluginImportSource,\n resolveGithubWorkflowsContext,\n setupNextCompilerBabelConfig,\n updateAstroConfig,\n updateIntlayerConfigWithSyncPlugin,\n updateMetroConfig,\n updateNextConfig,\n updateNextConfigForNextI18next,\n updateNextConfigForNextIntl,\n updateNextConfigForNextTranslate,\n updateNuxtConfig,\n updateNuxtConfigForNuxtjsI18n,\n updateViteConfig,\n updateViteConfigForCompatPlugin,\n writeFileToRoot,\n} from './utils';\n\nexport {\n DocumentationRouter,\n type DocumentationRouterType,\n getDocumentationUrl,\n};\n\n/**\n * Resolves the default dev-server URL of the detected framework, used as the\n * `editor.applicationURL` of the generated configuration file. Frameworks that\n * embed Vite (Astro, SvelteKit, …) are checked before the bare Vite fallback so\n * their own dev port wins.\n */\nexport const getDefaultApplicationURL = (\n dependencies: Record<string, string>\n): string => {\n if (dependencies.next) return 'http://localhost:3000';\n if (dependencies.astro) return 'http://localhost:4321';\n if (dependencies['@angular/core']) return 'http://localhost:4200';\n if (dependencies.nuxt) return 'http://localhost:3000';\n if (dependencies['@sveltejs/kit']) return 'http://localhost:5173';\n if (dependencies['react-scripts']) return 'http://localhost:3000';\n if (dependencies.vite) return 'http://localhost:5173';\n\n return 'http://localhost:3000';\n};\n\n/**\n * How the interactive init organizes autogenerated content (compiler output /\n * autofill):\n * - `per-component` — multilingual `.content` files co-located with components\n * (the configuration template default).\n * - `centralized` — per-locale JSON dictionaries under `/locales/{locale}/`.\n * - `json-namespaces` — plain per-locale JSON namespace files kept in sync\n * through `@intlayer/sync-json-plugin`.\n */\nexport type ContentStrategy =\n | 'per-component'\n | 'centralized'\n | 'json-namespaces';\n\n/**\n * OPTIONS\n */\nexport type InitOptions = {\n noGitignore?: boolean;\n /** Skip scaffolding the `fill` and `test` GitHub Actions workflows. */\n noGithubActions?: boolean;\n /**\n * Skip installing missing Intlayer dependencies and upgrading the Intlayer\n * packages of every `package.json` to their latest version.\n */\n noInstallPackages?: boolean;\n /** Skip adding the Intlayer extension to `.vscode/extensions.json`. */\n noVscodeExtension?: boolean;\n /** Skip writing the Intlayer LSP configuration to `.vscode/settings.json`. */\n noLsp?: boolean;\n /** Skip enabling the Intlayer lint rules (ESLint / oxlint). */\n noEslint?: boolean;\n /**\n * Skip the project setup: tsconfig types/aliases, the Intlayer config file,\n * bundler/framework configs and framework-specific\n * scaffolding (middleware/proxy, providers in layout/page). Defaults to\n * enabled.\n */\n noFrameworkSetup?: boolean;\n /** Skip logging the final success message and documentation link. */\n skipFinalMessage?: boolean;\n /**\n * Version to install the missing Intlayer packages at (typically the running\n * CLI version). Already declared Intlayer packages are upgraded to the latest\n * published version instead.\n */\n upgradeToVersion?: string;\n /**\n * Locale routing strategy to write to `routing.mode` in the generated/existing\n * Intlayer configuration file. When omitted, the configuration default\n * (`prefix-no-default`) is kept.\n */\n routingMode?: RoutingMode;\n /**\n * Whether the app routes by locale through the Intlayer proxy (middleware).\n * Written to `routing.enableProxy` in the configuration file and drives the\n * framework scaffolding: `false` skips the proxy file and any locale route\n * segment. When omitted, the configured value is kept (unset means enabled).\n */\n enableProxy?: boolean;\n /**\n * Content organization strategy chosen by the interactive init prompt. Drives\n * the `compiler.output` template (`centralized`) or the injection of the\n * syncJSON plugin (`json-namespaces`). When omitted (or `per-component`), the\n * configuration template default is kept.\n */\n contentStrategy?: ContentStrategy;\n};\n\n/**\n * MAIN LOGIC\n */\nexport const initIntlayer = async (rootDir: string, options?: InitOptions) => {\n logger(colorize('Checking Intlayer configuration...', ANSIColors.CYAN));\n\n // READ PACKAGE.JSON\n const packageJsonPath = 'package.json';\n if (!(await exists(rootDir, packageJsonPath))) {\n logger(\n `${x} No ${colorizePath('package.json')} found. Please run this script from the project root.`,\n { level: 'error' }\n );\n process.exit(1);\n }\n\n const packageJsonContent = await readFileFromRoot(rootDir, packageJsonPath);\n let packageJson: Record<string, any>;\n try {\n packageJson = JSON.parse(packageJsonContent);\n } catch {\n logger(`${x} Could not parse ${colorizePath('package.json')}.`, {\n level: 'error',\n });\n process.exit(1);\n }\n\n // Determine the correct documentation URL based on dependencies\n const guideUrl = getDocumentationUrl(packageJson);\n\n const allDeps: Record<string, string> = {\n ...(packageJson.dependencies ?? {}),\n ...(packageJson.devDependencies ?? {}),\n };\n\n // MOVE COMPAT PACKAGES (e.g. next-intl) REPLACED BY @INTLAYER/* TO DEVDEPENDENCIES\n // Part of the package step: the move pairs with installing the adapters.\n const movedPackages = options?.noInstallPackages\n ? []\n : moveCompatPackagesToDevDependencies(packageJson);\n if (movedPackages.length > 0) {\n const indentation = packageJsonContent.match(/^[ \\t]+(?=\")/m)?.[0] ?? 2;\n const trailingNewline = packageJsonContent.endsWith('\\n') ? '\\n' : '';\n await writeFileToRoot(\n rootDir,\n packageJsonPath,\n `${JSON.stringify(packageJson, null, indentation)}${trailingNewline}`\n );\n for (const pkg of movedPackages) {\n logger(\n `${v} Moved ${colorize(pkg, ANSIColors.MAGENTA)} from dependencies to devDependencies`\n );\n }\n }\n\n // INSTALL MISSING INTLAYER DEPENDENCIES\n const packageManager = detectPackageManager(rootDir);\n\n // lingui keeps its catalogs as `.po` (default) or `.json`. Detect which so the\n // matching sync plugin (`syncPO` / `syncJSON`) + dev dependency are chosen.\n const linguiPresent = Boolean(\n allDeps['@lingui/core'] ||\n allDeps['@lingui/react'] ||\n allDeps['@intlayer/lingui']\n );\n\n const linguiCatalog = linguiPresent\n ? await detectLinguiCatalogPattern(rootDir)\n : null;\n\n // `linguiCatalogFormat` resolution:\n // 1. Filesystem scan result (authoritative when catalogs already exist)\n // 2. Fallback: 'po' (lingui's default) when lingui is installed but no\n // catalogs have been generated yet.\n const linguiCatalogFormat: 'po' | 'json' | null =\n linguiCatalog?.format ?? (linguiPresent ? 'po' : null);\n\n const {\n packagesToInstall,\n devPackagesToInstall,\n compatSyncConfig,\n compatVitePluginConfig,\n pendingCompatAdapters,\n } = detectMissingIntlayerPackages(allDeps, {\n linguiCatalogFormat,\n dependencies: packageJson.dependencies,\n devDependencies: packageJson.devDependencies,\n skipLintPlugin: options?.noEslint,\n });\n\n /** Whether the compat adapter for a library is not released yet. */\n const isCompatAdapterPending = (adapterPackage: string): boolean =>\n pendingCompatAdapters.includes(adapterPackage);\n\n if (pendingCompatAdapters.length > 0) {\n logger(\n `${x} No released Intlayer adapter yet for ${pendingCompatAdapters\n .map((adapterPackage) => colorize(adapterPackage, ANSIColors.MAGENTA))\n .join(\n ', '\n )} — keeping your current i18n library and only syncing its catalogs with Intlayer.`,\n { level: 'warn' }\n );\n }\n\n // The `json-namespaces` content strategy uses the same syncJSON pipeline as\n // the compat libraries: plain per-locale JSON namespace files synced through\n // `@intlayer/sync-json-plugin`. A detected compat library keeps precedence —\n // its own catalog format/template is authoritative.\n const wantsJsonNamespaces =\n options?.contentStrategy === 'json-namespaces' && !compatSyncConfig;\n\n if (\n wantsJsonNamespaces &&\n !allDeps['@intlayer/sync-json-plugin'] &&\n !devPackagesToInstall.includes('@intlayer/sync-json-plugin')\n ) {\n devPackagesToInstall.push('@intlayer/sync-json-plugin');\n }\n\n if (!options?.noInstallPackages) {\n const withVersion = (packages: string[]): string[] =>\n options?.upgradeToVersion\n ? packages.map((pkg) =>\n isIntlayerPackageName(pkg)\n ? `${pkg}@${options.upgradeToVersion}`\n : pkg\n )\n : packages;\n\n if (packagesToInstall.length > 0) {\n logger(\n colorize('Installing missing Intlayer dependencies...', ANSIColors.CYAN)\n );\n try {\n installPackages(\n rootDir,\n withVersion(packagesToInstall),\n packageManager\n );\n logger(\n `${v} Installed: ${packagesToInstall.map((pkg) => colorize(pkg, ANSIColors.MAGENTA)).join(', ')}`\n );\n } catch {\n logger(\n `${x} Failed to install packages. Please install manually: ${packagesToInstall.join(' ')}`,\n { level: 'warn' }\n );\n }\n }\n\n if (devPackagesToInstall.length > 0) {\n logger(\n colorize(\n 'Installing missing Intlayer dev dependencies...',\n ANSIColors.CYAN\n )\n );\n try {\n installPackages(\n rootDir,\n withVersion(devPackagesToInstall),\n packageManager,\n true\n );\n logger(\n `${v} Installed: ${devPackagesToInstall.map((pkg) => colorize(pkg, ANSIColors.MAGENTA)).join(', ')}`\n );\n } catch {\n logger(\n `${x} Failed to install dev packages. Please install manually: ${devPackagesToInstall.join(' ')}`,\n { level: 'warn' }\n );\n }\n }\n\n // UPGRADE INTLAYER DEPENDENCIES TO LATEST\n await upgradeIntlayerPackages(rootDir);\n }\n\n // CHECK .GITIGNORE\n const gitignorePath = '.gitignore';\n if (\n !options?.noGitignore &&\n !options?.noFrameworkSetup &&\n (await exists(rootDir, gitignorePath))\n ) {\n const gitignoreContent = await readFileFromRoot(rootDir, gitignorePath);\n\n if (!gitignoreContent.includes('intlayer')) {\n const newContent = `${gitignoreContent}\\n# Intlayer\\n.intlayer\\n`;\n await writeFileToRoot(rootDir, gitignorePath, newContent);\n logger(\n `${v} Added ${colorizePath('.intlayer')} to ${colorizePath(gitignorePath)}`\n );\n } else {\n logger(`${v} ${colorizePath(gitignorePath)} already includes .intlayer`);\n }\n }\n\n // SCAFFOLD GITHUB ACTIONS WORKFLOWS (fill + test)\n // Generate two workflows whose commands match the detected package manager:\n // - intlayer-fill.yml: auto-fills missing translations on pull requests\n // - intlayer-test.yml: fails the PR when required locales are missing\n // Every command runs with `--ci`, which iterates over the Intlayer\n // project(s) of the repository. GitHub only triggers workflows stored at the\n // repository root, so in a monorepo the files are written to the git root\n // (see resolveGithubWorkflowsContext).\n if (!options?.noGithubActions) {\n const workflowsContext = await resolveGithubWorkflowsContext(\n rootDir,\n packageManager\n );\n const workflows = getGithubWorkflows(\n workflowsContext.packageManager,\n workflowsContext.options\n );\n\n for (const workflow of workflows) {\n if (await exists(workflowsContext.workflowsRootDir, workflow.filePath)) {\n logger(`${v} ${colorizePath(workflow.filePath)} already exists`);\n continue;\n }\n\n try {\n await ensureDirectory(\n workflowsContext.workflowsRootDir,\n join('.github', 'workflows')\n );\n await writeFileToRoot(\n workflowsContext.workflowsRootDir,\n workflow.filePath,\n workflow.content\n );\n logger(\n `${v} Added GitHub Actions workflow ${colorizePath(workflow.filePath)}`\n );\n } catch {\n logger(\n `${x} Could not create ${colorizePath(workflow.filePath)}. You may need to add it manually.`,\n { level: 'warn' }\n );\n }\n }\n }\n\n // CHECK VS CODE EXTENSION RECOMMENDATIONS\n const vscodeDir = '.vscode';\n const extensionsJsonPath = join(vscodeDir, 'extensions.json');\n const extensionId = 'intlayer.intlayer-vs-code-extension';\n\n if (!options?.noVscodeExtension) {\n try {\n let extensionsConfig: { recommendations: string[] } = {\n recommendations: [],\n };\n\n if (await exists(rootDir, extensionsJsonPath)) {\n const content = await readFileFromRoot(rootDir, extensionsJsonPath);\n extensionsConfig = parseJSONWithComments(content);\n } else {\n await ensureDirectory(rootDir, vscodeDir);\n }\n\n if (!extensionsConfig.recommendations) {\n extensionsConfig.recommendations = [];\n }\n\n if (!extensionsConfig.recommendations.includes(extensionId)) {\n extensionsConfig.recommendations.push(extensionId);\n await writeFileToRoot(\n rootDir,\n extensionsJsonPath,\n JSON.stringify(extensionsConfig, null, 2)\n );\n logger(\n `${v} Added ${colorize(extensionId, ANSIColors.MAGENTA)} to ${colorizePath(extensionsJsonPath)}`\n );\n } else {\n logger(\n `${v} ${colorizePath(extensionsJsonPath)} already includes ${colorize(extensionId, ANSIColors.MAGENTA)}`\n );\n }\n } catch {\n logger(\n `${x} Could not update ${colorizePath(extensionsJsonPath)}. You may need to add ${colorize(extensionId, ANSIColors.MAGENTA)} manually.`,\n { level: 'warn' }\n );\n }\n }\n\n // CHECK VS CODE LSP SETTINGS\n const settingsJsonPath = join(vscodeDir, 'settings.json');\n\n if (!options?.noLsp) {\n try {\n let settingsConfig: Record<string, unknown> = {};\n\n if (await exists(rootDir, settingsJsonPath)) {\n const content = await readFileFromRoot(rootDir, settingsJsonPath);\n settingsConfig = parseJSONWithComments(content);\n } else {\n await ensureDirectory(rootDir, vscodeDir);\n }\n\n let settingsUpdated = false;\n\n if (!settingsConfig['intlayer.languageServer.command']) {\n settingsConfig['intlayer.languageServer.command'] = 'npx';\n settingsUpdated = true;\n }\n\n if (!settingsConfig['intlayer.languageServer.args']) {\n settingsConfig['intlayer.languageServer.args'] = ['@intlayer/lsp'];\n settingsUpdated = true;\n }\n\n if (settingsUpdated) {\n await writeFileToRoot(\n rootDir,\n settingsJsonPath,\n JSON.stringify(settingsConfig, null, 2)\n );\n logger(\n `${v} Updated ${colorizePath(settingsJsonPath)} with LSP configuration`\n );\n } else {\n logger(\n `${v} ${colorizePath(settingsJsonPath)} already includes LSP configuration`\n );\n }\n } catch {\n logger(\n `${x} Could not update ${colorizePath(settingsJsonPath)}. You may need to add the LSP settings manually.`,\n { level: 'warn' }\n );\n }\n }\n\n // CHECK LINT RULES (eslint-plugin-intlayer)\n //\n // Gated on the project already having a linter installed: with no ESLint or\n // oxlint there is nothing to plug the rules into, and the guidance below\n // would just be noise. The same check gates the install in\n // `detectMissingIntlayerPackages`, so the two never disagree.\n //\n // Only the oxlint config is patched here: `.oxlintrc.json` is plain JSON and\n // safe to edit, whereas an ESLint flat config is arbitrary JavaScript that\n // cannot be rewritten reliably — that one is left to the user, with the\n // snippet printed below.\n if (!options?.noEslint && hasLegacyEslint(allDeps)) {\n logger(\n `${x} ${colorize(LINT_PLUGIN_PACKAGE_NAME, ANSIColors.MAGENTA)} needs ESLint ${MINIMUM_ESLINT_MAJOR}+ (flat config) — skipped the Intlayer lint rules. Upgrade ESLint to enable them: ${colorizePath(DocumentationRouter.ESLint)}`,\n { level: 'warn' }\n );\n }\n\n if (!options?.noEslint && hasLintTooling(allDeps)) {\n // Without the package step (`intlayer init eslint`), the lint step\n // installs its own plugin so the rules it enables can resolve.\n if (options?.noInstallPackages && !allDeps[LINT_PLUGIN_PACKAGE_NAME]) {\n const lintPluginSpecifier = options.upgradeToVersion\n ? `${LINT_PLUGIN_PACKAGE_NAME}@${options.upgradeToVersion}`\n : LINT_PLUGIN_PACKAGE_NAME;\n\n try {\n installPackages(rootDir, [lintPluginSpecifier], packageManager, true);\n logger(\n `${v} Installed: ${colorize(LINT_PLUGIN_PACKAGE_NAME, ANSIColors.MAGENTA)}`\n );\n } catch {\n logger(\n `${x} Failed to install ${LINT_PLUGIN_PACKAGE_NAME}. Please install it manually.`,\n { level: 'warn' }\n );\n }\n }\n\n const oxlintConfigPath = '.oxlintrc.json';\n const hasOxlintConfig = await exists(rootDir, oxlintConfigPath);\n // An oxlint-only project without a config gets one; with ESLint around,\n // the rules go into the ESLint config instead.\n const shouldCreateOxlintConfig =\n !hasOxlintConfig && Boolean(allDeps.oxlint) && !allDeps.eslint;\n\n if (hasOxlintConfig || shouldCreateOxlintConfig) {\n try {\n const oxlintConfig: OxlintConfig = hasOxlintConfig\n ? parseJSONWithComments(\n await readFileFromRoot(rootDir, oxlintConfigPath)\n )\n : {};\n\n if (addIntlayerRulesToOxlintConfig(oxlintConfig)) {\n await writeFileToRoot(\n rootDir,\n oxlintConfigPath,\n JSON.stringify(oxlintConfig, null, 2)\n );\n logger(\n `${v} ${hasOxlintConfig ? 'Added the Intlayer lint rules to' : 'Created'} ${colorizePath(oxlintConfigPath)}`\n );\n } else {\n logger(\n `${v} ${colorizePath(oxlintConfigPath)} already includes the Intlayer lint rules`\n );\n }\n } catch {\n logger(\n `${x} Could not update ${colorizePath(oxlintConfigPath)}. You may need to add ${colorize(LINT_PLUGIN_PACKAGE_NAME, ANSIColors.MAGENTA)} manually.`,\n { level: 'warn' }\n );\n }\n } else {\n // ESLint flat config — print the snippet instead of rewriting the file.\n logger([\n colorize('Intlayer lint rules →', ANSIColors.MAGENTA),\n colorize(\n `Add the ${LINT_PLUGIN_PACKAGE_NAME} preset to the array your ESLint flat config exports, to catch hardcoded text and dynamic calls the compiler cannot optimize:`,\n ANSIColors.GREY_LIGHT\n ),\n colorize(\n ` import intlayer from '${LINT_PLUGIN_PACKAGE_NAME}';\\n\\n export default [\\n // ...your existing config\\n ...intlayer.configs.recommended,\\n ];`,\n ANSIColors.GREY_LIGHT\n ),\n colorizePath(DocumentationRouter.ESLint),\n ]);\n }\n }\n\n // PROJECT SETUP\n // Everything below edits the project itself: tsconfig types and aliases, the\n // Intlayer config file, bundler/framework configs and the\n // framework scaffolding. It only runs with the framework setup step, so\n // picking e.g. only the CI or editor steps never creates project files.\n if (!options?.noFrameworkSetup) {\n // CHECK TSCONFIGS\n const tsConfigFiles = await findTsConfigFiles(rootDir);\n let hasTsConfig = false;\n\n for (const fileName of tsConfigFiles) {\n if (await exists(rootDir, fileName)) {\n hasTsConfig = true;\n try {\n const fileContent = await readFileFromRoot(rootDir, fileName);\n const config = parseJSONWithComments(fileContent);\n const typeDefinition = './.intlayer/**/*.ts';\n\n let updated = false;\n\n if (!config.include) {\n // Skip if no include array (solution-style)\n } else if (\n Array.isArray(config.include) &&\n !(config.include as string[]).some((pattern: string) =>\n pattern.includes('.intlayer')\n )\n ) {\n config.include.push(typeDefinition);\n updated = true;\n } else if (config.include.includes(typeDefinition)) {\n logger(\n `${v} ${colorizePath(fileName)} already includes intlayer types`\n );\n }\n\n if (updated) {\n await writeFileToRoot(\n rootDir,\n fileName,\n JSON.stringify(config, null, 2)\n );\n logger(\n `${v} Updated ${colorizePath(fileName)} to include intlayer types`\n );\n }\n } catch {\n logger(\n `${x} Could not parse or update ${colorizePath(fileName)}. You may need to add ${colorizePath('.intlayer/types/**/*.ts')} manually.`,\n { level: 'warn' }\n );\n }\n }\n }\n\n // INITIALIZE CONFIG FILE\n const format = hasTsConfig ? 'intlayer.config.ts' : 'intlayer.config.mjs';\n\n // Detect the locale JSON file pattern already in the project so we can\n // insert the matching locales into the config and produce the most\n // accurate source template for compat libraries.\n const detectedPattern = await detectJsonLocalePattern(rootDir);\n\n const isConfigCreated = await initConfig(format, rootDir, {\n locales: detectedPattern?.locales,\n applicationURL: getDefaultApplicationURL(allDeps),\n });\n\n // APPLY CONTENT STRATEGY — CENTRALIZED\n // Point `compiler.output` at per-locale JSON dictionaries under `/locales/`\n // instead of the per-component template default.\n if (options?.contentStrategy === 'centralized') {\n await setCompilerOutputInConfig(\n rootDir,\n '/locales/{{locale}}/{{key}}.content.json'\n );\n }\n\n // INJECT SYNC-JSON PLUGIN FOR COMPAT LIBRARIES / JSON-NAMESPACES STRATEGY\n const syncConfigToInject: CompatSyncConfig | undefined =\n compatSyncConfig ??\n (wantsJsonNamespaces\n ? {\n format: 'i18next',\n sourceTemplate:\n detectedPattern?.template ?? './locales/${locale}/${key}.json',\n }\n : undefined);\n\n if (syncConfigToInject) {\n // For next-intl / use-intl, the messages path is authoritatively declared\n // in `i18n/request.ts` (e.g. `import(`../messages/${locale}.json`)`), so we\n // read it directly. It usually resolves to a single file per locale (no\n // `${key}` segment), whose first-level keys are namespaces — so the compat\n // config carries `splitKeys: true` to emit one dictionary per namespace.\n // Falls back to file-system globbing otherwise.\n const nextIntlMessagesPattern =\n allDeps['next-intl'] ||\n allDeps['@intlayer/next-intl'] ||\n allDeps['use-intl'] ||\n allDeps['@intlayer/use-intl']\n ? await detectNextIntlMessagesPattern(rootDir)\n : null;\n\n // lingui authoritatively resolves to `…/{locale}/messages.{po,json}`, where\n // the `messages` filename becomes the dictionary key. Prefer it so a `.po`\n // project gets `syncPO` (the generic JSON glob only sees `.json`).\n const sourceTemplate =\n linguiCatalog?.template ??\n nextIntlMessagesPattern?.template ??\n detectedPattern?.template;\n\n const resolvedSyncConfig = {\n ...syncConfigToInject,\n ...(sourceTemplate ? { sourceTemplate } : {}),\n };\n\n const syncPluginPackage =\n resolvedSyncConfig.plugin === 'po'\n ? '@intlayer/sync-po-plugin'\n : '@intlayer/sync-json-plugin';\n const syncPluginName =\n resolvedSyncConfig.plugin === 'po' ? 'syncPO' : 'syncJSON';\n\n // `splitKeys` only makes sense for a single file holding several namespaces.\n // If the resolved template addresses one namespace per file (`${key}`\n // segment), each file is already a single namespace — drop the flag so\n // syncJSON keeps one dictionary per file.\n if (\n resolvedSyncConfig.splitKeys &&\n resolvedSyncConfig.sourceTemplate.includes('${key}')\n ) {\n resolvedSyncConfig.splitKeys = false;\n }\n\n const intlayerConfigCandidates = [\n 'intlayer.config.ts',\n 'intlayer.config.mjs',\n 'intlayer.config.js',\n 'intlayer.config.cjs',\n ];\n\n for (const configFile of intlayerConfigCandidates) {\n if (await exists(rootDir, configFile)) {\n const configContent = await readFileFromRoot(rootDir, configFile);\n\n if (!configContent.includes(syncPluginPackage)) {\n const extension = configFile.split('.').pop()!;\n const updatedConfigContent = updateIntlayerConfigWithSyncPlugin(\n configContent,\n extension,\n resolvedSyncConfig\n );\n await writeFileToRoot(rootDir, configFile, updatedConfigContent);\n logger(\n `${v} Updated ${colorizePath(configFile)} with ${syncPluginName} compat plugin`\n );\n } else {\n logger(\n `${v} ${colorizePath(configFile)} already includes ${syncPluginName} plugin`\n );\n }\n break;\n }\n }\n }\n\n // APPLY ROUTING\n // An explicit choice (interactive prompt / `--routing`) is written to\n // `routing.mode` + `routing.enableProxy`. Without one, a freshly created\n // config is adapted to the project: frontends get prefix routing through\n // the proxy (the template ships it disabled), projects without URL routing\n // (backend, React Native…) keep only `routing.storage`. An existing config\n // is never rewritten without an explicit choice. A compat i18n library\n // owns the app routing, so its config keeps the template's disabled proxy:\n // compat bundler plugins wrap `intlayer()`, which would register it.\n const hasUrlRouting = hasUrlRoutingFramework(allDeps);\n const hasCompatI18nLibrary = detectCompatI18nLibraries(allDeps).length > 0;\n const shouldApplyDefaultRouting =\n isConfigCreated &&\n options?.routingMode === undefined &&\n !hasCompatI18nLibrary;\n\n if (shouldApplyDefaultRouting && !hasUrlRouting) {\n await setRoutingStorageOnlyInConfig(rootDir);\n }\n\n const routingMode =\n options?.routingMode ??\n (shouldApplyDefaultRouting && hasUrlRouting ? ROUTING_MODE : undefined);\n const enableProxy =\n options?.enableProxy ??\n (shouldApplyDefaultRouting && hasUrlRouting ? true : undefined);\n\n if (routingMode) {\n await setRoutingModeInConfig(rootDir, routingMode);\n }\n\n if (enableProxy !== undefined) {\n await setEnableProxyInConfig(rootDir, enableProxy);\n }\n\n let hasAliasConfiguration = false;\n\n // CHECK VITE CONFIG\n const viteConfigs = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs'];\n\n for (const file of viteConfigs) {\n if (await exists(rootDir, file)) {\n hasAliasConfiguration = true;\n const content = await readFileFromRoot(rootDir, file);\n const extension = file.split('.').pop()!;\n\n if (compatVitePluginConfig) {\n const { replacesVitePlugin } = compatVitePluginConfig;\n\n if (content.includes(compatVitePluginConfig.pluginPackageSource)) {\n logger(\n `${v} ${colorizePath(file)} already includes ${compatVitePluginConfig.pluginPackageSource}`\n );\n } else if (\n replacesVitePlugin &&\n content.includes(replacesVitePlugin.fromPackageSource)\n ) {\n // Drop-in replacement: rewrite the original i18n vite plugin's import\n // source, keeping its binding and call site (e.g. lingui).\n const updatedContent = replaceViteConfigPluginImportSource(\n content,\n replacesVitePlugin.importName,\n replacesVitePlugin.fromPackageSource,\n compatVitePluginConfig.pluginPackageSource\n );\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to import ${replacesVitePlugin.importName} from ${compatVitePluginConfig.pluginPackageSource}`\n );\n } else {\n const updatedContent = updateViteConfigForCompatPlugin(\n content,\n extension,\n compatVitePluginConfig\n );\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include ${compatVitePluginConfig.pluginFunctionName} compat plugin`\n );\n }\n } else if (hasIntlayerVitePlugin(content)) {\n // A compat adapter plugin (e.g. `reactI18nextVitePlugin`) already wraps\n // `intlayer()` internally, so skip adding a redundant standalone plugin.\n logger(\n `${v} ${colorizePath(file)} already includes an Intlayer plugin`\n );\n } else {\n const updatedContent = updateViteConfig(content, extension);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include Intlayer plugin`\n );\n }\n break;\n }\n }\n\n // CHECK NEXT CONFIG\n const nextConfigs = ['next.config.js', 'next.config.mjs', 'next.config.ts'];\n let isNextJsProject = false;\n\n for (const file of nextConfigs) {\n if (await exists(rootDir, file)) {\n isNextJsProject = true;\n hasAliasConfiguration = true;\n const content = await readFileFromRoot(rootDir, file);\n const extension = file.split('.').pop()!;\n\n if (allDeps['next-i18next'] || allDeps['@intlayer/next-i18next']) {\n if (!content.includes('@intlayer/next-i18next')) {\n const updatedContent = updateNextConfigForNextI18next(\n content,\n extension\n );\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include Intlayer next-i18next compat plugin`\n );\n } else {\n logger(\n `${v} ${colorizePath(file)} already includes @intlayer/next-i18next`\n );\n }\n } else if (allDeps['next-intl'] || allDeps['@intlayer/next-intl']) {\n if (!content.includes('@intlayer/next-intl/plugin')) {\n const updatedContent = updateNextConfigForNextIntl(\n content,\n extension\n );\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include Intlayer next-intl compat plugin`\n );\n } else {\n logger(\n `${v} ${colorizePath(file)} already includes @intlayer/next-intl/plugin`\n );\n }\n } else if (isCompatAdapterPending('@intlayer/next-translate')) {\n logger(\n `${v} Kept ${colorizePath(file)} untouched (next-translate stays in charge)`\n );\n } else if (\n allDeps['next-translate'] ||\n allDeps['@intlayer/next-translate']\n ) {\n if (!content.includes('@intlayer/next-translate')) {\n const updatedContent = updateNextConfigForNextTranslate(\n content,\n extension\n );\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include Intlayer next-translate compat plugin`\n );\n } else {\n logger(\n `${v} ${colorizePath(file)} already includes @intlayer/next-translate`\n );\n }\n } else if (!content.includes('next-intlayer')) {\n const updatedContent = updateNextConfig(content, extension);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include Intlayer plugin`\n );\n }\n break;\n }\n }\n\n // CHECK NEXT.JS COMPILER (BABEL)\n // When a Next.js project already uses Babel, install @intlayer/babel and print\n // the compiler + build-optimization plugins (extract, purge, minify, optimize)\n // to add. SWC projects need no setup: withIntlayer injects @intlayer/swc.\n if (isNextJsProject) {\n await setupNextCompilerBabelConfig({\n rootDir,\n packageManager,\n allDeps,\n skipInstall: Boolean(options?.noInstallPackages),\n });\n }\n\n // CHECK OTHER FRAMEWORKS CONFIG\n const astroConfigs = [\n 'astro.config.mjs',\n 'astro.config.js',\n 'astro.config.ts',\n 'astro.config.cjs',\n ];\n\n for (const file of astroConfigs) {\n if (await exists(rootDir, file)) {\n hasAliasConfiguration = true;\n\n if (file.startsWith('astro.config.')) {\n const content = await readFileFromRoot(rootDir, file);\n\n if (!content.includes('astro-intlayer')) {\n const extension = file.split('.').pop()!;\n const updatedContent = updateAstroConfig(content, extension);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include Intlayer integration`\n );\n }\n }\n break;\n }\n }\n\n const nuxtConfigs = ['nuxt.config.js', 'nuxt.config.ts'];\n for (const file of nuxtConfigs) {\n if (await exists(rootDir, file)) {\n hasAliasConfiguration = true;\n\n const content = await readFileFromRoot(rootDir, file);\n\n if (isCompatAdapterPending('@intlayer/nuxtjs-i18n')) {\n logger(\n `${v} Kept ${colorizePath(file)} untouched (@nuxtjs/i18n stays in charge)`\n );\n } else if (allDeps['@nuxtjs/i18n']) {\n if (!content.includes('@intlayer/nuxtjs-i18n')) {\n const updatedContent = updateNuxtConfigForNuxtjsI18n(content);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include @intlayer/nuxtjs-i18n module`\n );\n } else {\n logger(\n `${v} ${colorizePath(file)} already includes @intlayer/nuxtjs-i18n`\n );\n }\n } else if (!content.includes('nuxt-intlayer')) {\n const updatedContent = updateNuxtConfig(content);\n await writeFileToRoot(rootDir, file, updatedContent);\n logger(\n `${v} Updated ${colorizePath(file)} to include Intlayer module`\n );\n }\n break;\n }\n }\n\n // CHECK METRO CONFIG (React Native / Expo)\n // Metro is the React Native bundler. The Intlayer Metro plugin\n // (`react-native-intlayer/metro`) handles dictionary aliasing and building.\n // When no config exists we scaffold one; when one exists we safely wrap its\n // exported config with `configMetroIntlayerSync`, leaving custom async\n // (IIFE) configs untouched so existing setups are never broken.\n const isReactNativeProject = Boolean(\n allDeps['react-native'] || allDeps.expo\n );\n\n if (isReactNativeProject) {\n // Metro resolves Intlayer aliases itself, so skip the alias fallback below.\n hasAliasConfiguration = true;\n\n const metroConfigs = [\n 'metro.config.js',\n 'metro.config.cjs',\n 'metro.config.mjs',\n 'metro.config.ts',\n ];\n\n let metroConfigFile: string | undefined;\n\n for (const file of metroConfigs) {\n if (await exists(rootDir, file)) {\n metroConfigFile = file;\n break;\n }\n }\n\n if (metroConfigFile) {\n const content = await readFileFromRoot(rootDir, metroConfigFile);\n\n if (content.includes('react-native-intlayer')) {\n logger(\n `${v} ${colorizePath(metroConfigFile)} already includes the Intlayer Metro plugin`\n );\n } else {\n const extension = metroConfigFile.split('.').pop()!;\n const updatedContent = updateMetroConfig(content, extension);\n\n if (updatedContent !== content) {\n await writeFileToRoot(rootDir, metroConfigFile, updatedContent);\n logger(\n `${v} Updated ${colorizePath(metroConfigFile)} to include the Intlayer Metro plugin`\n );\n } else {\n logger(\n `${x} Could not automatically update ${colorizePath(metroConfigFile)}. Wrap your exported config with ${colorize('configMetroIntlayer', ANSIColors.MAGENTA)}: ${colorizePath(DocumentationRouter.ReactNativeAndExpo)}`,\n { level: 'warn' }\n );\n }\n }\n } else {\n const newMetroConfigFile = 'metro.config.js';\n await writeFileToRoot(\n rootDir,\n newMetroConfigFile,\n getMetroConfigTemplate(Boolean(allDeps.expo))\n );\n logger(\n `${v} Created ${colorizePath(newMetroConfigFile)} with the Intlayer Metro plugin`\n );\n }\n }\n\n // CHECK WEBPACK CONFIG\n const webpackConfigs = [\n 'webpack.config.js',\n 'webpack.config.ts',\n 'webpack.config.mjs',\n 'webpack.config.cjs',\n ];\n\n for (const file of webpackConfigs) {\n if (await exists(rootDir, file)) {\n hasAliasConfiguration = true;\n logger(\n `${v} Found ${colorizePath(\n file\n )}. Make sure to configure aliases manually or use the Intlayer Webpack plugin.`\n );\n break;\n }\n }\n\n // The server frameworks themselves, alongside their Intlayer packages: a\n // project may be mid-setup and carry only one of the two.\n const backendConfigPackages = [\n 'express',\n 'fastify',\n '@adonisjs/core',\n 'hono',\n 'elysia',\n ...BACKEND_INTLAYER_PACKAGES,\n ];\n\n if (backendConfigPackages.some((pkg) => allDeps[pkg])) {\n hasAliasConfiguration = true;\n }\n\n if (!hasAliasConfiguration) {\n const configuration = getConfiguration({ baseDir: rootDir });\n // `tsconfig`/`jsconfig` `paths` and `package.json` `imports` both expect\n // explicitly relative specifiers, so bare relative paths get a `./` prefix.\n const aliases = getAlias({\n configuration,\n formatter: (value) =>\n value.startsWith('./') || value.startsWith('../')\n ? value\n : `./${value}`,\n });\n\n if (hasTsConfig && tsConfigFiles.length > 0) {\n const tsConfigPath =\n tsConfigFiles.find((file) => file === 'tsconfig.json') ||\n tsConfigFiles[0];\n\n if (tsConfigPath) {\n const tsConfigContent = await readFileFromRoot(rootDir, tsConfigPath);\n const config = parseJSONWithComments(tsConfigContent);\n\n config.compilerOptions ??= {};\n config.compilerOptions.paths ??= {};\n\n let updated = false;\n\n Object.entries(aliases).forEach(([alias, path]) => {\n if (!config.compilerOptions.paths[alias]) {\n config.compilerOptions.paths[alias] = [path];\n updated = true;\n }\n });\n\n if (updated) {\n await writeFileToRoot(\n rootDir,\n tsConfigPath,\n JSON.stringify(config, null, 2)\n );\n\n logger(\n `${v} Updated ${colorizePath(\n tsConfigPath\n )} to include Intlayer aliases`\n );\n }\n }\n } else {\n const jsConfigPath = 'jsconfig.json';\n\n if (await exists(rootDir, jsConfigPath)) {\n const jsConfigContent = await readFileFromRoot(rootDir, jsConfigPath);\n const config = parseJSONWithComments(jsConfigContent);\n\n config.compilerOptions ??= {};\n config.compilerOptions.paths ??= {};\n\n let updated = false;\n\n Object.entries(aliases).forEach(([alias, path]) => {\n if (!config.compilerOptions.paths[alias]) {\n config.compilerOptions.paths[alias] = [path];\n updated = true;\n }\n });\n\n if (updated) {\n await writeFileToRoot(\n rootDir,\n jsConfigPath,\n JSON.stringify(config, null, 2)\n );\n logger(\n `${v} Updated ${colorizePath(\n jsConfigPath\n )} to include Intlayer aliases`\n );\n }\n } else {\n packageJson.imports ??= {};\n\n let updated = false;\n\n Object.entries(aliases).forEach(([alias, path]) => {\n const importAlias = alias.replace('@', '#');\n\n if (!packageJson.imports[importAlias]) {\n packageJson.imports[importAlias] = path;\n updated = true;\n }\n });\n\n if (updated) {\n await writeFileToRoot(\n rootDir,\n packageJsonPath,\n JSON.stringify(packageJson, null, 2)\n );\n logger(\n `${v} Updated ${colorizePath(\n packageJsonPath\n )} to include Intlayer imports`\n );\n }\n }\n }\n }\n\n // FRAMEWORK-SPECIFIC SCAFFOLDING\n // Sets up middleware/proxy and wraps the layout/page with the Intlayer\n // providers for the detected framework (Next.js App Router today). Idempotent\n // and non-destructive: it never overwrites user code it cannot safely\n // transform, skipping with guidance instead.\n //\n // Skipped entirely when a compat i18n library drives the app (i18next,\n // next-intl, vue-i18n, …): the app already owns its routing, providers and\n // layouts, and Intlayer only syncs its catalogs — restructuring routes or\n // injecting providers would break the existing setup.\n const hasCompatLibrary = Boolean(\n compatSyncConfig || compatVitePluginConfig\n );\n\n if (hasCompatLibrary) {\n logger(\n `${v} Compat i18n library detected — keeping the app structure untouched (no route restructure, no provider injection)`\n );\n }\n\n if (!hasCompatLibrary) {\n try {\n // Prefer the user's choices, else the configured routing (mode defaults\n // to `prefix-no-default`, an unset `enableProxy` means enabled). Drives\n // the proxy file and the locale route segment the adapters scaffold.\n const { routing } = getConfiguration({ baseDir: rootDir });\n\n await setupFramework({\n rootDir,\n allDeps,\n packageManager,\n useTypeScript: hasTsConfig,\n routingMode: routingMode ?? routing.mode,\n enableProxy: enableProxy ?? routing.enableProxy !== false,\n });\n } catch {\n logger(\n `${x} Framework-specific scaffolding failed. Your existing files were left untouched; follow the documentation to finish the setup.`,\n { level: 'warn' }\n );\n }\n }\n }\n\n // FINAL SUCCESS MESSAGE\n if (!options?.skipFinalMessage) {\n logInitSuccessMessage(guideUrl);\n }\n\n return { guideUrl };\n};\n\nexport const logInitSuccessMessage = (guideUrl: string): void => {\n logger(`${v} ${colorize('Intlayer init setup complete.', ANSIColors.GREEN)}`);\n logger([\n colorize('Next →', ANSIColors.MAGENTA),\n colorize(\n 'Follow the instructions in the documentation to complete the setup:',\n ANSIColors.GREY_LIGHT\n ),\n colorizePath(guideUrl),\n ]);\n};\n"],"mappings":"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"}
|
|
@@ -285,7 +285,7 @@ const detectMissingIntlayerPackages = (allDependencies, options = {}) => {
|
|
|
285
285
|
if (isInstalled("hono")) addIfMissing("hono-intlayer");
|
|
286
286
|
if (isInstalled("elysia")) addIfMissing("elysia-intlayer");
|
|
287
287
|
if (isInstalled("@adonisjs/core")) addIfMissing("adonis-intlayer");
|
|
288
|
-
if (hasLintTooling(allDependencies)) addDevIfMissing("eslint-plugin-intlayer");
|
|
288
|
+
if (!options.skipLintPlugin && hasLintTooling(allDependencies)) addDevIfMissing("eslint-plugin-intlayer");
|
|
289
289
|
if (isInstalled("next-intl") || isInstalled("@intlayer/next-intl")) {
|
|
290
290
|
markCompatReplacement("next-intl", "@intlayer/next-intl");
|
|
291
291
|
compatSyncConfig ??= {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageManager.mjs","names":[],"sources":["../../../../src/init/utils/packageManager.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { isVersionAtLeast } from './version';\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 /**\n * Which sync plugin ingests the catalogs:\n * - `'json'` → `syncJSON` from `@intlayer/sync-json-plugin` (default).\n * - `'po'` → `syncPO` from `@intlayer/sync-po-plugin` (lingui's default\n * format).\n */\n plugin?: 'json' | 'po';\n /**\n * JSON format matching the compat library's conventions. Ignored when\n * `plugin` is `'po'` (PO catalogs are always serialized as gettext).\n */\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 * Set when the compat plugin is a drop-in replacement for an i18n library's\n * own Vite plugin (e.g. lingui ships `@lingui/vite-plugin`). When the original\n * import is present, init rewrites only that import's module source to\n * `pluginPackageSource` — keeping the binding and its call site — instead of\n * injecting a second import and appending another plugin to the array.\n */\n replacesVitePlugin?: {\n /** Imported binding to keep, e.g. `'lingui'`. */\n importName: string;\n /** Original package source to rewrite, e.g. `'@lingui/vite-plugin'`. */\n fromPackageSource: string;\n };\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 /** Compat packages in dependencies that got replaced and should be moved to devDependencies. */\n packagesToMoveToDev: 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 * Compat adapters the project would need but that are not published yet\n * (see {@link PENDING_COMPAT_ADAPTERS}). The original library is kept as is;\n * only its catalogs are synced.\n */\n pendingCompatAdapters: string[];\n};\n\n/**\n * Compat adapters that live in `compat-comming/` and are not published to npm\n * yet. Installing one fails the whole install command, so init keeps the\n * original library, skips the adapter and its bundler / framework wiring, and\n * only syncs the catalogs. Remove an entry once its package is released.\n */\nexport const PENDING_COMPAT_ADAPTERS: ReadonlySet<string> = new Set([\n '@intlayer/nuxtjs-i18n',\n '@intlayer/svelte-i18n',\n '@intlayer/ngx-translate',\n]);\n\n/** Lock files revealing the package manager, in detection priority order. */\nconst LOCK_FILE_PACKAGE_MANAGERS: ReadonlyArray<\n readonly [lockFile: string, packageManager: PackageManager]\n> = [\n ['bun.lock', 'bun'],\n ['bun.lockb', 'bun'],\n ['pnpm-lock.yaml', 'pnpm'],\n ['yarn.lock', 'yarn'],\n ['package-lock.json', 'npm'],\n];\n\n/** Package managers accepted in the `packageManager` field of `package.json`. */\nconst PACKAGE_MANAGERS: readonly PackageManager[] = [\n 'bun',\n 'pnpm',\n 'yarn',\n 'npm',\n];\n\n/**\n * Reads the package manager pinned by the `packageManager` field of the\n * `package.json` in `directory` (e.g. `\"pnpm@9.0.0\"`), if any.\n */\nconst readPackageManagerField = (directory: string): PackageManager | null => {\n try {\n const { packageManager } = JSON.parse(\n readFileSync(join(directory, 'package.json'), 'utf8')\n ) as { packageManager?: unknown };\n\n if (typeof packageManager !== 'string') return null;\n\n const name = packageManager.split('@')[0] as PackageManager;\n return PACKAGE_MANAGERS.includes(name) ? name : null;\n } catch {\n return null;\n }\n};\n\n/**\n * Detects the package manager in use by checking for lock files in the\n * project root, then the `packageManager` field of its `package.json`. Falls\n * back to npm when neither is found.\n */\nexport const detectPackageManager = (rootDir: string): PackageManager =>\n LOCK_FILE_PACKAGE_MANAGERS.find(([lockFile]) =>\n existsSync(join(rootDir, lockFile))\n )?.[1] ??\n readPackageManagerField(rootDir) ??\n 'npm';\n\n/**\n * Walks up from `startDir` to the nearest directory holding a lock file — the\n * workspace root an install must run from. Stops at the repository root\n * (`.git`) and returns `null` when no lock file is found.\n */\nexport const findLockFileDir = (startDir: string): string | null => {\n let currentDir = resolve(startDir);\n\n while (true) {\n const hasLockFile = LOCK_FILE_PACKAGE_MANAGERS.some(([lockFile]) =>\n existsSync(join(currentDir, lockFile))\n );\n if (hasLockFile) return currentDir;\n if (existsSync(join(currentDir, '.git'))) return null;\n\n const parentDir = dirname(currentDir);\n if (parentDir === currentDir) return null;\n currentDir = parentDir;\n }\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 */\n/** Extra signals (from a filesystem scan) that refine compat detection. */\nexport type DetectMissingPackagesOptions = {\n /**\n * Catalog format detected for a lingui project (`'po'` or `'json'`), or\n * `null`/undefined when none was found. Decides which sync plugin + dev\n * dependency the lingui compat setup uses.\n */\n linguiCatalogFormat?: 'po' | 'json' | null;\n /**\n * The project's runtime dependencies (from `package.json` `dependencies`).\n * When provided, compat packages found here that are replaced by `@intlayer/*`\n * are reported in `packagesToMoveToDev`.\n */\n dependencies?: Record<string, string>;\n /**\n * The project's development dependencies (from `package.json` `devDependencies`).\n */\n devDependencies?: Record<string, string>;\n};\n\n/** An existing i18n library Intlayer ships a compat adapter for. */\nexport type CompatI18nLibrary = {\n /** Human-readable name, used to report the detection back to the user. */\n label: string;\n /**\n * Dependency names that reveal the library — both the upstream packages and\n * the Intlayer adapters, so a project that already ran `init` is still\n * recognized.\n */\n packages: readonly string[];\n /**\n * Upstream third-party packages replaced by Intlayer compat adapters at runtime,\n * mapped to their adapter package name.\n */\n replacements: Record<string, string>;\n};\n\n/**\n * Existing i18n libraries Intlayer can adapt, keyed by the dependencies that\n * reveal them. Mirrors the compat branches of\n * {@link detectMissingIntlayerPackages}: a library listed here is one that\n * detection will wire up on its own once its package is in `package.json`.\n */\nexport const COMPAT_I18N_LIBRARIES: readonly CompatI18nLibrary[] = [\n {\n label: 'i18next / react-i18next',\n packages: [\n 'i18next',\n 'react-i18next',\n '@intlayer/i18next',\n '@intlayer/react-i18next',\n ],\n replacements: {\n i18next: '@intlayer/i18next',\n 'react-i18next': '@intlayer/react-i18next',\n },\n },\n {\n label: 'next-intl / use-intl',\n packages: [\n 'next-intl',\n 'use-intl',\n '@intlayer/next-intl',\n '@intlayer/use-intl',\n ],\n replacements: {\n 'next-intl': '@intlayer/next-intl',\n 'use-intl': '@intlayer/use-intl',\n },\n },\n {\n label: 'vue-i18n',\n packages: ['vue-i18n', '@intlayer/vue-i18n'],\n replacements: {\n 'vue-i18n': '@intlayer/vue-i18n',\n },\n },\n {\n label: '@nuxtjs/i18n',\n packages: ['@nuxtjs/i18n', '@intlayer/nuxtjs-i18n'],\n replacements: {\n '@nuxtjs/i18n': '@intlayer/nuxtjs-i18n',\n },\n },\n {\n label: 'next-i18next',\n packages: ['next-i18next', '@intlayer/next-i18next'],\n replacements: {\n 'next-i18next': '@intlayer/next-i18next',\n },\n },\n {\n label: 'next-translate',\n packages: ['next-translate', '@intlayer/next-translate'],\n replacements: {\n 'next-translate': '@intlayer/next-translate',\n },\n },\n {\n label: 'react-intl',\n packages: ['react-intl', '@intlayer/react-intl'],\n replacements: {\n 'react-intl': '@intlayer/react-intl',\n },\n },\n {\n label: 'Lingui',\n packages: ['@lingui/core', '@lingui/react', '@intlayer/lingui'],\n replacements: {\n '@lingui/core': '@intlayer/lingui',\n '@lingui/react': '@intlayer/lingui',\n },\n },\n {\n label: 'svelte-i18n',\n packages: ['svelte-i18n', '@intlayer/svelte-i18n'],\n replacements: {\n 'svelte-i18n': '@intlayer/svelte-i18n',\n },\n },\n {\n label: '@ngneat/transloco',\n packages: ['@ngneat/transloco', '@intlayer/transloco'],\n replacements: {\n '@ngneat/transloco': '@intlayer/transloco',\n },\n },\n {\n label: '@ngx-translate/core',\n packages: ['@ngx-translate/core', '@intlayer/ngx-translate'],\n replacements: {\n '@ngx-translate/core': '@intlayer/ngx-translate',\n },\n },\n {\n label: 'node-polyglot',\n packages: ['node-polyglot', '@intlayer/polyglot'],\n replacements: {\n 'node-polyglot': '@intlayer/polyglot',\n },\n },\n {\n label: 'i18n-js',\n packages: ['i18n-js', '@intlayer/i18n-js'],\n replacements: {\n 'i18n-js': '@intlayer/i18n-js',\n },\n },\n];\n\n/**\n * Maps third-party i18n libraries to the Intlayer compat adapter that replaces\n * them at runtime, derived from {@link COMPAT_I18N_LIBRARIES}.\n */\nexport const COMPAT_PACKAGE_REPLACEMENTS: Record<string, string> =\n Object.fromEntries(\n COMPAT_I18N_LIBRARIES.flatMap((library) =>\n Object.entries(library.replacements)\n )\n );\n\n/**\n * When a project uses a compat i18n package (such as `next-intl`) that gets\n * replaced by an `@intlayer/*` adapter (e.g. `@intlayer/next-intl`), moves the\n * original package from `dependencies` to `devDependencies` in `package.json`.\n *\n * Returns the list of package names that were moved.\n */\nexport const moveCompatPackagesToDevDependencies = (\n packageJson: Record<string, any>\n): string[] => {\n const movedPackages: string[] = [];\n if (!packageJson.dependencies) return movedPackages;\n\n for (const compatPackage of Object.keys(COMPAT_PACKAGE_REPLACEMENTS)) {\n if (packageJson.dependencies[compatPackage]) {\n const version = packageJson.dependencies[compatPackage];\n delete packageJson.dependencies[compatPackage];\n\n packageJson.devDependencies = packageJson.devDependencies ?? {};\n if (!packageJson.devDependencies[compatPackage]) {\n packageJson.devDependencies[compatPackage] = version;\n }\n movedPackages.push(compatPackage);\n }\n }\n\n return movedPackages;\n};\n\n/**\n * Returns the labels of the compat i18n libraries present in `dependencies`.\n *\n * Lets the init flow report (and branch on) the libraries it found without\n * asking the user, since {@link detectMissingIntlayerPackages} already derives\n * the adapters, sync plugin and config from the very same dependency map.\n *\n * @param dependencies - Merged dependencies of the target project.\n */\nexport const detectCompatI18nLibraries = (\n dependencies: Record<string, string>\n): string[] =>\n COMPAT_I18N_LIBRARIES.filter((library) =>\n library.packages.some((packageName) => Boolean(dependencies[packageName]))\n ).map((library) => library.label);\n\n/** Lowest ESLint major `eslint-plugin-intlayer` supports (flat config). */\nexport const MINIMUM_ESLINT_MAJOR = 9;\n\n/**\n * True when the project pins ESLint below {@link MINIMUM_ESLINT_MAJOR}.\n * Installing the plugin there fails on its `eslint` peer range (and takes the\n * whole install command down with it). Ranges without a version number\n * (`latest`, `*`, `catalog:`) are assumed current.\n *\n * @param dependencies - Merged dependencies of the target project.\n */\nexport const hasLegacyEslint = (\n dependencies: Record<string, string>\n): boolean => {\n const eslintVersion = dependencies.eslint;\n if (!eslintVersion || !/\\d/.test(eslintVersion)) return false;\n return !isVersionAtLeast(eslintVersion, MINIMUM_ESLINT_MAJOR);\n};\n\n/**\n * True when the project already lints with a linter the Intlayer rules can\n * plug into: oxlint, or ESLint 9+.\n *\n * Shared with the init flow so that installing the plugin and wiring up its\n * configuration are gated on exactly the same condition — a project that does\n * not lint, or lints with ESLint 8, is left alone.\n *\n * @param dependencies - Merged dependencies of the target project.\n */\nexport const hasLintTooling = (dependencies: Record<string, string>): boolean =>\n !hasLegacyEslint(dependencies) &&\n (Boolean(dependencies.eslint) || Boolean(dependencies.oxlint));\n\nexport const detectMissingIntlayerPackages = (\n allDependencies: Record<string, string>,\n options: DetectMissingPackagesOptions = {}\n): IntlayerPackageAnalysis => {\n const packagesToInstall: string[] = [];\n const devPackagesToInstall: string[] = [];\n const packagesToMoveToDev: string[] = [];\n const pendingCompatAdapters: string[] = [];\n\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 /**\n * Whether an adapter can be used: published, or already installed by the\n * user (e.g. a local build).\n */\n const isAdapterAvailable = (adapterPackage: string): boolean =>\n !PENDING_COMPAT_ADAPTERS.has(adapterPackage) || isInstalled(adapterPackage);\n\n const markCompatReplacement = (\n originalPackage: string,\n adapterPackage: string\n ): void => {\n if (!isAdapterAvailable(adapterPackage)) {\n if (!pendingCompatAdapters.includes(adapterPackage)) {\n pendingCompatAdapters.push(adapterPackage);\n }\n return;\n }\n\n addIfMissing(adapterPackage);\n addDevIfMissing(originalPackage);\n\n const isExplicitDev = Boolean(options.devDependencies?.[originalPackage]);\n const isExplicitProd = Boolean(options.dependencies?.[originalPackage]);\n const isImplicitProd =\n !options.dependencies &&\n !options.devDependencies &&\n Boolean(allDependencies[originalPackage]);\n\n if ((isExplicitProd || isImplicitProd) && !isExplicitDev) {\n if (!packagesToMoveToDev.includes(originalPackage)) {\n packagesToMoveToDev.push(originalPackage);\n }\n }\n };\n\n // Core package — always required\n addIfMissing('intlayer');\n\n const isReactNativeProject =\n isInstalled('react-native') || isInstalled('expo');\n\n // Framework-specific runtime integrations\n if (isInstalled('next')) {\n addIfMissing('next-intlayer');\n } else if (isReactNativeProject) {\n addIfMissing('react-native-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 // Meta-frameworks whose config init wires the Intlayer module /\n // integration into. A `@nuxtjs/i18n` app keeps its own module instead.\n if (isInstalled('nuxt') && !isInstalled('@nuxtjs/i18n')) {\n addIfMissing('nuxt-intlayer');\n }\n\n if (isInstalled('astro')) {\n addIfMissing('astro-intlayer');\n }\n\n // Server frameworks. NestJS runs on Express unless the Fastify platform is\n // installed, so it gets the matching adapter.\n const isNestJsProject = isInstalled('@nestjs/core');\n const isNestJsOnFastify = isInstalled('@nestjs/platform-fastify');\n\n if (isInstalled('express') || (isNestJsProject && !isNestJsOnFastify)) {\n addIfMissing('express-intlayer');\n }\n\n if (isInstalled('fastify') || isNestJsOnFastify) {\n addIfMissing('fastify-intlayer');\n }\n\n if (isInstalled('hono')) {\n addIfMissing('hono-intlayer');\n }\n\n if (isInstalled('elysia')) {\n addIfMissing('elysia-intlayer');\n }\n\n if (isInstalled('@adonisjs/core')) {\n addIfMissing('adonis-intlayer');\n }\n\n // Lint rules — only when the project already lints.\n if (hasLintTooling(allDependencies)) {\n addDevIfMissing('eslint-plugin-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 markCompatReplacement('next-intl', '@intlayer/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 markCompatReplacement('next-i18next', '@intlayer/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 markCompatReplacement('next-translate', '@intlayer/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 — vite alias injection (`i18next` → `@intlayer/i18next`) so existing\n // `import … from 'i18next'` is served by Intlayer without touching call sites.\n if (isInstalled('i18next') || isInstalled('@intlayer/i18next')) {\n markCompatReplacement('i18next', '@intlayer/i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n // When react-i18next is also present, its wrapper plugin aliases both\n // `react-i18next` and `i18next`, so it must win — only inject the bare\n // i18next plugin when no React wrapper is installed.\n if (\n !isInstalled('react-i18next') &&\n !isInstalled('@intlayer/react-i18next')\n ) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'i18nextVitePlugin',\n pluginPackageSource: '@intlayer/i18next/plugin',\n };\n }\n }\n\n // react-i18next — vite alias injection (`react-i18next` → `@intlayer/react-i18next`\n // and `i18next` → `@intlayer/i18next`) so components keep importing from\n // `react-i18next` unchanged.\n if (isInstalled('react-i18next') || isInstalled('@intlayer/react-i18next')) {\n markCompatReplacement('react-i18next', '@intlayer/react-i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'reactI18nextVitePlugin',\n pluginPackageSource: '@intlayer/react-i18next/plugin',\n };\n }\n\n // vue-i18n — vite alias injection required\n if (isInstalled('vue-i18n') || isInstalled('@intlayer/vue-i18n')) {\n markCompatReplacement('vue-i18n', '@intlayer/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 markCompatReplacement('use-intl', '@intlayer/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 markCompatReplacement('react-intl', '@intlayer/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 markCompatReplacement('@ngneat/transloco', '@intlayer/transloco');\n if (isAdapterAvailable('@intlayer/transloco')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'translocoVitePlugin',\n pluginPackageSource: '@intlayer/transloco/plugin',\n };\n }\n }\n\n // svelte-i18n — vite alias injection required, flat JSON (i18next-compatible)\n if (isInstalled('svelte-i18n') || isInstalled('@intlayer/svelte-i18n')) {\n markCompatReplacement('svelte-i18n', '@intlayer/svelte-i18n');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}.json',\n };\n if (isAdapterAvailable('@intlayer/svelte-i18n')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'svelteI18nVitePlugin',\n pluginPackageSource: '@intlayer/svelte-i18n/plugin',\n };\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 markCompatReplacement('node-polyglot', '@intlayer/polyglot');\n if (isAdapterAvailable('@intlayer/polyglot')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'polyglotVitePlugin',\n pluginPackageSource: '@intlayer/polyglot/plugin',\n };\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 markCompatReplacement('@nuxtjs/i18n', '@intlayer/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 markCompatReplacement('@ngx-translate/core', '@intlayer/ngx-translate');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './assets/i18n/${locale}.json',\n };\n if (isAdapterAvailable('@intlayer/ngx-translate')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'ngxTranslateVitePlugin',\n pluginPackageSource: '@intlayer/ngx-translate/plugin',\n };\n }\n }\n\n // @lingui/core — vite alias injection required.\n // lingui keeps one catalog file per locale (default name `messages`), as\n // `.po` (its default) or `.json`. The catalog filename is captured by the\n // `${key}` segment so the produced dictionary key is `messages`, matching the\n // fixed `messages` namespace the lingui compat runtime reads from.\n if (\n isInstalled('@lingui/core') ||\n isInstalled('@lingui/react') ||\n isInstalled('@intlayer/lingui')\n ) {\n markCompatReplacement('@lingui/core', '@intlayer/lingui');\n\n if (isInstalled('@lingui/react')) {\n markCompatReplacement('@lingui/react', '@intlayer/lingui');\n }\n\n const linguiUsesPo = options.linguiCatalogFormat === 'po';\n compatSyncConfig ??= linguiUsesPo\n ? {\n plugin: 'po',\n format: 'icu',\n sourceTemplate: './src/locales/${locale}/${key}.po',\n }\n : {\n plugin: 'json',\n format: 'icu',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n\n compatVitePluginConfig ??= {\n // `@intlayer/lingui/plugin` exports `lingui` as a drop-in replacement for\n // `@lingui/vite-plugin`, so a fresh project gets `lingui()` injected and a\n // project already using `@lingui/vite-plugin` only has its import source\n // rewritten (see `replacesVitePlugin`).\n pluginFunctionName: 'lingui',\n pluginPackageSource: '@intlayer/lingui/plugin',\n replacesVitePlugin: {\n importName: 'lingui',\n fromPackageSource: '@lingui/vite-plugin',\n },\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 markCompatReplacement('i18n-js', '@intlayer/i18n-js');\n if (isAdapterAvailable('@intlayer/i18n-js')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'i18nJsVitePlugin',\n pluginPackageSource: '@intlayer/i18n-js/plugin',\n };\n }\n }\n\n if (compatSyncConfig) {\n addDevIfMissing(\n compatSyncConfig.plugin === 'po'\n ? '@intlayer/sync-po-plugin'\n : '@intlayer/sync-json-plugin'\n );\n }\n\n return {\n packagesToInstall,\n devPackagesToInstall,\n packagesToMoveToDev,\n compatSyncConfig,\n compatVitePluginConfig,\n pendingCompatAdapters,\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`), as well as the\n * `intlayer-*` packages (e.g. `intlayer-editor`).\n */\nexport const isIntlayerPackageName = (packageName: string): boolean =>\n packageName === 'intlayer' ||\n packageName.startsWith('@intlayer/') ||\n packageName.startsWith('intlayer-') ||\n packageName.endsWith('-intlayer');\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\n const match = version.match(/(\\d+)\\.(\\d+)\\.(\\d+)/);\n\n return match ? `${match[1]}.${match[2]}.${match[3]}` : null;\n};\n\n/**\n * Runs the package manager install command synchronously, so edited\n * `package.json` ranges are resolved and the lock file updated. Throws if the\n * install process exits with a non-zero code.\n */\nexport const runPackageInstall = (\n rootDir: string,\n packageManager: PackageManager\n): void => {\n execSync(`${packageManager} install`, { cwd: rootDir, stdio: 'inherit' });\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"packageManager.mjs","names":[],"sources":["../../../../src/init/utils/packageManager.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { isVersionAtLeast } from './version';\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 /**\n * Which sync plugin ingests the catalogs:\n * - `'json'` → `syncJSON` from `@intlayer/sync-json-plugin` (default).\n * - `'po'` → `syncPO` from `@intlayer/sync-po-plugin` (lingui's default\n * format).\n */\n plugin?: 'json' | 'po';\n /**\n * JSON format matching the compat library's conventions. Ignored when\n * `plugin` is `'po'` (PO catalogs are always serialized as gettext).\n */\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 * Set when the compat plugin is a drop-in replacement for an i18n library's\n * own Vite plugin (e.g. lingui ships `@lingui/vite-plugin`). When the original\n * import is present, init rewrites only that import's module source to\n * `pluginPackageSource` — keeping the binding and its call site — instead of\n * injecting a second import and appending another plugin to the array.\n */\n replacesVitePlugin?: {\n /** Imported binding to keep, e.g. `'lingui'`. */\n importName: string;\n /** Original package source to rewrite, e.g. `'@lingui/vite-plugin'`. */\n fromPackageSource: string;\n };\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 /** Compat packages in dependencies that got replaced and should be moved to devDependencies. */\n packagesToMoveToDev: 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 * Compat adapters the project would need but that are not published yet\n * (see {@link PENDING_COMPAT_ADAPTERS}). The original library is kept as is;\n * only its catalogs are synced.\n */\n pendingCompatAdapters: string[];\n};\n\n/**\n * Compat adapters that live in `compat-comming/` and are not published to npm\n * yet. Installing one fails the whole install command, so init keeps the\n * original library, skips the adapter and its bundler / framework wiring, and\n * only syncs the catalogs. Remove an entry once its package is released.\n */\nexport const PENDING_COMPAT_ADAPTERS: ReadonlySet<string> = new Set([\n '@intlayer/nuxtjs-i18n',\n '@intlayer/svelte-i18n',\n '@intlayer/ngx-translate',\n]);\n\n/** Lock files revealing the package manager, in detection priority order. */\nconst LOCK_FILE_PACKAGE_MANAGERS: ReadonlyArray<\n readonly [lockFile: string, packageManager: PackageManager]\n> = [\n ['bun.lock', 'bun'],\n ['bun.lockb', 'bun'],\n ['pnpm-lock.yaml', 'pnpm'],\n ['yarn.lock', 'yarn'],\n ['package-lock.json', 'npm'],\n];\n\n/** Package managers accepted in the `packageManager` field of `package.json`. */\nconst PACKAGE_MANAGERS: readonly PackageManager[] = [\n 'bun',\n 'pnpm',\n 'yarn',\n 'npm',\n];\n\n/**\n * Reads the package manager pinned by the `packageManager` field of the\n * `package.json` in `directory` (e.g. `\"pnpm@9.0.0\"`), if any.\n */\nconst readPackageManagerField = (directory: string): PackageManager | null => {\n try {\n const { packageManager } = JSON.parse(\n readFileSync(join(directory, 'package.json'), 'utf8')\n ) as { packageManager?: unknown };\n\n if (typeof packageManager !== 'string') return null;\n\n const name = packageManager.split('@')[0] as PackageManager;\n return PACKAGE_MANAGERS.includes(name) ? name : null;\n } catch {\n return null;\n }\n};\n\n/**\n * Detects the package manager in use by checking for lock files in the\n * project root, then the `packageManager` field of its `package.json`. Falls\n * back to npm when neither is found.\n */\nexport const detectPackageManager = (rootDir: string): PackageManager =>\n LOCK_FILE_PACKAGE_MANAGERS.find(([lockFile]) =>\n existsSync(join(rootDir, lockFile))\n )?.[1] ??\n readPackageManagerField(rootDir) ??\n 'npm';\n\n/**\n * Walks up from `startDir` to the nearest directory holding a lock file — the\n * workspace root an install must run from. Stops at the repository root\n * (`.git`) and returns `null` when no lock file is found.\n */\nexport const findLockFileDir = (startDir: string): string | null => {\n let currentDir = resolve(startDir);\n\n while (true) {\n const hasLockFile = LOCK_FILE_PACKAGE_MANAGERS.some(([lockFile]) =>\n existsSync(join(currentDir, lockFile))\n );\n if (hasLockFile) return currentDir;\n if (existsSync(join(currentDir, '.git'))) return null;\n\n const parentDir = dirname(currentDir);\n if (parentDir === currentDir) return null;\n currentDir = parentDir;\n }\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 */\n/** Extra signals (from a filesystem scan) that refine compat detection. */\nexport type DetectMissingPackagesOptions = {\n /**\n * Catalog format detected for a lingui project (`'po'` or `'json'`), or\n * `null`/undefined when none was found. Decides which sync plugin + dev\n * dependency the lingui compat setup uses.\n */\n linguiCatalogFormat?: 'po' | 'json' | null;\n /**\n * The project's runtime dependencies (from `package.json` `dependencies`).\n * When provided, compat packages found here that are replaced by `@intlayer/*`\n * are reported in `packagesToMoveToDev`.\n */\n dependencies?: Record<string, string>;\n /**\n * The project's development dependencies (from `package.json` `devDependencies`).\n */\n devDependencies?: Record<string, string>;\n /**\n * Skip `eslint-plugin-intlayer`, even when the project lints. Set when the\n * lint step is not part of the setup.\n */\n skipLintPlugin?: boolean;\n};\n\n/** An existing i18n library Intlayer ships a compat adapter for. */\nexport type CompatI18nLibrary = {\n /** Human-readable name, used to report the detection back to the user. */\n label: string;\n /**\n * Dependency names that reveal the library — both the upstream packages and\n * the Intlayer adapters, so a project that already ran `init` is still\n * recognized.\n */\n packages: readonly string[];\n /**\n * Upstream third-party packages replaced by Intlayer compat adapters at runtime,\n * mapped to their adapter package name.\n */\n replacements: Record<string, string>;\n};\n\n/**\n * Existing i18n libraries Intlayer can adapt, keyed by the dependencies that\n * reveal them. Mirrors the compat branches of\n * {@link detectMissingIntlayerPackages}: a library listed here is one that\n * detection will wire up on its own once its package is in `package.json`.\n */\nexport const COMPAT_I18N_LIBRARIES: readonly CompatI18nLibrary[] = [\n {\n label: 'i18next / react-i18next',\n packages: [\n 'i18next',\n 'react-i18next',\n '@intlayer/i18next',\n '@intlayer/react-i18next',\n ],\n replacements: {\n i18next: '@intlayer/i18next',\n 'react-i18next': '@intlayer/react-i18next',\n },\n },\n {\n label: 'next-intl / use-intl',\n packages: [\n 'next-intl',\n 'use-intl',\n '@intlayer/next-intl',\n '@intlayer/use-intl',\n ],\n replacements: {\n 'next-intl': '@intlayer/next-intl',\n 'use-intl': '@intlayer/use-intl',\n },\n },\n {\n label: 'vue-i18n',\n packages: ['vue-i18n', '@intlayer/vue-i18n'],\n replacements: {\n 'vue-i18n': '@intlayer/vue-i18n',\n },\n },\n {\n label: '@nuxtjs/i18n',\n packages: ['@nuxtjs/i18n', '@intlayer/nuxtjs-i18n'],\n replacements: {\n '@nuxtjs/i18n': '@intlayer/nuxtjs-i18n',\n },\n },\n {\n label: 'next-i18next',\n packages: ['next-i18next', '@intlayer/next-i18next'],\n replacements: {\n 'next-i18next': '@intlayer/next-i18next',\n },\n },\n {\n label: 'next-translate',\n packages: ['next-translate', '@intlayer/next-translate'],\n replacements: {\n 'next-translate': '@intlayer/next-translate',\n },\n },\n {\n label: 'react-intl',\n packages: ['react-intl', '@intlayer/react-intl'],\n replacements: {\n 'react-intl': '@intlayer/react-intl',\n },\n },\n {\n label: 'Lingui',\n packages: ['@lingui/core', '@lingui/react', '@intlayer/lingui'],\n replacements: {\n '@lingui/core': '@intlayer/lingui',\n '@lingui/react': '@intlayer/lingui',\n },\n },\n {\n label: 'svelte-i18n',\n packages: ['svelte-i18n', '@intlayer/svelte-i18n'],\n replacements: {\n 'svelte-i18n': '@intlayer/svelte-i18n',\n },\n },\n {\n label: '@ngneat/transloco',\n packages: ['@ngneat/transloco', '@intlayer/transloco'],\n replacements: {\n '@ngneat/transloco': '@intlayer/transloco',\n },\n },\n {\n label: '@ngx-translate/core',\n packages: ['@ngx-translate/core', '@intlayer/ngx-translate'],\n replacements: {\n '@ngx-translate/core': '@intlayer/ngx-translate',\n },\n },\n {\n label: 'node-polyglot',\n packages: ['node-polyglot', '@intlayer/polyglot'],\n replacements: {\n 'node-polyglot': '@intlayer/polyglot',\n },\n },\n {\n label: 'i18n-js',\n packages: ['i18n-js', '@intlayer/i18n-js'],\n replacements: {\n 'i18n-js': '@intlayer/i18n-js',\n },\n },\n];\n\n/**\n * Maps third-party i18n libraries to the Intlayer compat adapter that replaces\n * them at runtime, derived from {@link COMPAT_I18N_LIBRARIES}.\n */\nexport const COMPAT_PACKAGE_REPLACEMENTS: Record<string, string> =\n Object.fromEntries(\n COMPAT_I18N_LIBRARIES.flatMap((library) =>\n Object.entries(library.replacements)\n )\n );\n\n/**\n * When a project uses a compat i18n package (such as `next-intl`) that gets\n * replaced by an `@intlayer/*` adapter (e.g. `@intlayer/next-intl`), moves the\n * original package from `dependencies` to `devDependencies` in `package.json`.\n *\n * Returns the list of package names that were moved.\n */\nexport const moveCompatPackagesToDevDependencies = (\n packageJson: Record<string, any>\n): string[] => {\n const movedPackages: string[] = [];\n if (!packageJson.dependencies) return movedPackages;\n\n for (const compatPackage of Object.keys(COMPAT_PACKAGE_REPLACEMENTS)) {\n if (packageJson.dependencies[compatPackage]) {\n const version = packageJson.dependencies[compatPackage];\n delete packageJson.dependencies[compatPackage];\n\n packageJson.devDependencies = packageJson.devDependencies ?? {};\n if (!packageJson.devDependencies[compatPackage]) {\n packageJson.devDependencies[compatPackage] = version;\n }\n movedPackages.push(compatPackage);\n }\n }\n\n return movedPackages;\n};\n\n/**\n * Returns the labels of the compat i18n libraries present in `dependencies`.\n *\n * Lets the init flow report (and branch on) the libraries it found without\n * asking the user, since {@link detectMissingIntlayerPackages} already derives\n * the adapters, sync plugin and config from the very same dependency map.\n *\n * @param dependencies - Merged dependencies of the target project.\n */\nexport const detectCompatI18nLibraries = (\n dependencies: Record<string, string>\n): string[] =>\n COMPAT_I18N_LIBRARIES.filter((library) =>\n library.packages.some((packageName) => Boolean(dependencies[packageName]))\n ).map((library) => library.label);\n\n/** Lowest ESLint major `eslint-plugin-intlayer` supports (flat config). */\nexport const MINIMUM_ESLINT_MAJOR = 9;\n\n/**\n * True when the project pins ESLint below {@link MINIMUM_ESLINT_MAJOR}.\n * Installing the plugin there fails on its `eslint` peer range (and takes the\n * whole install command down with it). Ranges without a version number\n * (`latest`, `*`, `catalog:`) are assumed current.\n *\n * @param dependencies - Merged dependencies of the target project.\n */\nexport const hasLegacyEslint = (\n dependencies: Record<string, string>\n): boolean => {\n const eslintVersion = dependencies.eslint;\n if (!eslintVersion || !/\\d/.test(eslintVersion)) return false;\n return !isVersionAtLeast(eslintVersion, MINIMUM_ESLINT_MAJOR);\n};\n\n/**\n * True when the project already lints with a linter the Intlayer rules can\n * plug into: oxlint, or ESLint 9+.\n *\n * Shared with the init flow so that installing the plugin and wiring up its\n * configuration are gated on exactly the same condition — a project that does\n * not lint, or lints with ESLint 8, is left alone.\n *\n * @param dependencies - Merged dependencies of the target project.\n */\nexport const hasLintTooling = (dependencies: Record<string, string>): boolean =>\n !hasLegacyEslint(dependencies) &&\n (Boolean(dependencies.eslint) || Boolean(dependencies.oxlint));\n\nexport const detectMissingIntlayerPackages = (\n allDependencies: Record<string, string>,\n options: DetectMissingPackagesOptions = {}\n): IntlayerPackageAnalysis => {\n const packagesToInstall: string[] = [];\n const devPackagesToInstall: string[] = [];\n const packagesToMoveToDev: string[] = [];\n const pendingCompatAdapters: string[] = [];\n\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 /**\n * Whether an adapter can be used: published, or already installed by the\n * user (e.g. a local build).\n */\n const isAdapterAvailable = (adapterPackage: string): boolean =>\n !PENDING_COMPAT_ADAPTERS.has(adapterPackage) || isInstalled(adapterPackage);\n\n const markCompatReplacement = (\n originalPackage: string,\n adapterPackage: string\n ): void => {\n if (!isAdapterAvailable(adapterPackage)) {\n if (!pendingCompatAdapters.includes(adapterPackage)) {\n pendingCompatAdapters.push(adapterPackage);\n }\n return;\n }\n\n addIfMissing(adapterPackage);\n addDevIfMissing(originalPackage);\n\n const isExplicitDev = Boolean(options.devDependencies?.[originalPackage]);\n const isExplicitProd = Boolean(options.dependencies?.[originalPackage]);\n const isImplicitProd =\n !options.dependencies &&\n !options.devDependencies &&\n Boolean(allDependencies[originalPackage]);\n\n if ((isExplicitProd || isImplicitProd) && !isExplicitDev) {\n if (!packagesToMoveToDev.includes(originalPackage)) {\n packagesToMoveToDev.push(originalPackage);\n }\n }\n };\n\n // Core package — always required\n addIfMissing('intlayer');\n\n const isReactNativeProject =\n isInstalled('react-native') || isInstalled('expo');\n\n // Framework-specific runtime integrations\n if (isInstalled('next')) {\n addIfMissing('next-intlayer');\n } else if (isReactNativeProject) {\n addIfMissing('react-native-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 // Meta-frameworks whose config init wires the Intlayer module /\n // integration into. A `@nuxtjs/i18n` app keeps its own module instead.\n if (isInstalled('nuxt') && !isInstalled('@nuxtjs/i18n')) {\n addIfMissing('nuxt-intlayer');\n }\n\n if (isInstalled('astro')) {\n addIfMissing('astro-intlayer');\n }\n\n // Server frameworks. NestJS runs on Express unless the Fastify platform is\n // installed, so it gets the matching adapter.\n const isNestJsProject = isInstalled('@nestjs/core');\n const isNestJsOnFastify = isInstalled('@nestjs/platform-fastify');\n\n if (isInstalled('express') || (isNestJsProject && !isNestJsOnFastify)) {\n addIfMissing('express-intlayer');\n }\n\n if (isInstalled('fastify') || isNestJsOnFastify) {\n addIfMissing('fastify-intlayer');\n }\n\n if (isInstalled('hono')) {\n addIfMissing('hono-intlayer');\n }\n\n if (isInstalled('elysia')) {\n addIfMissing('elysia-intlayer');\n }\n\n if (isInstalled('@adonisjs/core')) {\n addIfMissing('adonis-intlayer');\n }\n\n // Lint rules — only when the project already lints.\n if (!options.skipLintPlugin && hasLintTooling(allDependencies)) {\n addDevIfMissing('eslint-plugin-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 markCompatReplacement('next-intl', '@intlayer/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 markCompatReplacement('next-i18next', '@intlayer/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 markCompatReplacement('next-translate', '@intlayer/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 — vite alias injection (`i18next` → `@intlayer/i18next`) so existing\n // `import … from 'i18next'` is served by Intlayer without touching call sites.\n if (isInstalled('i18next') || isInstalled('@intlayer/i18next')) {\n markCompatReplacement('i18next', '@intlayer/i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n // When react-i18next is also present, its wrapper plugin aliases both\n // `react-i18next` and `i18next`, so it must win — only inject the bare\n // i18next plugin when no React wrapper is installed.\n if (\n !isInstalled('react-i18next') &&\n !isInstalled('@intlayer/react-i18next')\n ) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'i18nextVitePlugin',\n pluginPackageSource: '@intlayer/i18next/plugin',\n };\n }\n }\n\n // react-i18next — vite alias injection (`react-i18next` → `@intlayer/react-i18next`\n // and `i18next` → `@intlayer/i18next`) so components keep importing from\n // `react-i18next` unchanged.\n if (isInstalled('react-i18next') || isInstalled('@intlayer/react-i18next')) {\n markCompatReplacement('react-i18next', '@intlayer/react-i18next');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n compatVitePluginConfig ??= {\n pluginFunctionName: 'reactI18nextVitePlugin',\n pluginPackageSource: '@intlayer/react-i18next/plugin',\n };\n }\n\n // vue-i18n — vite alias injection required\n if (isInstalled('vue-i18n') || isInstalled('@intlayer/vue-i18n')) {\n markCompatReplacement('vue-i18n', '@intlayer/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 markCompatReplacement('use-intl', '@intlayer/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 markCompatReplacement('react-intl', '@intlayer/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 markCompatReplacement('@ngneat/transloco', '@intlayer/transloco');\n if (isAdapterAvailable('@intlayer/transloco')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'translocoVitePlugin',\n pluginPackageSource: '@intlayer/transloco/plugin',\n };\n }\n }\n\n // svelte-i18n — vite alias injection required, flat JSON (i18next-compatible)\n if (isInstalled('svelte-i18n') || isInstalled('@intlayer/svelte-i18n')) {\n markCompatReplacement('svelte-i18n', '@intlayer/svelte-i18n');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './src/locales/${locale}.json',\n };\n if (isAdapterAvailable('@intlayer/svelte-i18n')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'svelteI18nVitePlugin',\n pluginPackageSource: '@intlayer/svelte-i18n/plugin',\n };\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 markCompatReplacement('node-polyglot', '@intlayer/polyglot');\n if (isAdapterAvailable('@intlayer/polyglot')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'polyglotVitePlugin',\n pluginPackageSource: '@intlayer/polyglot/plugin',\n };\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 markCompatReplacement('@nuxtjs/i18n', '@intlayer/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 markCompatReplacement('@ngx-translate/core', '@intlayer/ngx-translate');\n compatSyncConfig ??= {\n format: 'i18next',\n sourceTemplate: './assets/i18n/${locale}.json',\n };\n if (isAdapterAvailable('@intlayer/ngx-translate')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'ngxTranslateVitePlugin',\n pluginPackageSource: '@intlayer/ngx-translate/plugin',\n };\n }\n }\n\n // @lingui/core — vite alias injection required.\n // lingui keeps one catalog file per locale (default name `messages`), as\n // `.po` (its default) or `.json`. The catalog filename is captured by the\n // `${key}` segment so the produced dictionary key is `messages`, matching the\n // fixed `messages` namespace the lingui compat runtime reads from.\n if (\n isInstalled('@lingui/core') ||\n isInstalled('@lingui/react') ||\n isInstalled('@intlayer/lingui')\n ) {\n markCompatReplacement('@lingui/core', '@intlayer/lingui');\n\n if (isInstalled('@lingui/react')) {\n markCompatReplacement('@lingui/react', '@intlayer/lingui');\n }\n\n const linguiUsesPo = options.linguiCatalogFormat === 'po';\n compatSyncConfig ??= linguiUsesPo\n ? {\n plugin: 'po',\n format: 'icu',\n sourceTemplate: './src/locales/${locale}/${key}.po',\n }\n : {\n plugin: 'json',\n format: 'icu',\n sourceTemplate: './src/locales/${locale}/${key}.json',\n };\n\n compatVitePluginConfig ??= {\n // `@intlayer/lingui/plugin` exports `lingui` as a drop-in replacement for\n // `@lingui/vite-plugin`, so a fresh project gets `lingui()` injected and a\n // project already using `@lingui/vite-plugin` only has its import source\n // rewritten (see `replacesVitePlugin`).\n pluginFunctionName: 'lingui',\n pluginPackageSource: '@intlayer/lingui/plugin',\n replacesVitePlugin: {\n importName: 'lingui',\n fromPackageSource: '@lingui/vite-plugin',\n },\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 markCompatReplacement('i18n-js', '@intlayer/i18n-js');\n if (isAdapterAvailable('@intlayer/i18n-js')) {\n compatVitePluginConfig ??= {\n pluginFunctionName: 'i18nJsVitePlugin',\n pluginPackageSource: '@intlayer/i18n-js/plugin',\n };\n }\n }\n\n if (compatSyncConfig) {\n addDevIfMissing(\n compatSyncConfig.plugin === 'po'\n ? '@intlayer/sync-po-plugin'\n : '@intlayer/sync-json-plugin'\n );\n }\n\n return {\n packagesToInstall,\n devPackagesToInstall,\n packagesToMoveToDev,\n compatSyncConfig,\n compatVitePluginConfig,\n pendingCompatAdapters,\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`), as well as the\n * `intlayer-*` packages (e.g. `intlayer-editor`).\n */\nexport const isIntlayerPackageName = (packageName: string): boolean =>\n packageName === 'intlayer' ||\n packageName.startsWith('@intlayer/') ||\n packageName.startsWith('intlayer-') ||\n packageName.endsWith('-intlayer');\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\n const match = version.match(/(\\d+)\\.(\\d+)\\.(\\d+)/);\n\n return match ? `${match[1]}.${match[2]}.${match[3]}` : null;\n};\n\n/**\n * Runs the package manager install command synchronously, so edited\n * `package.json` ranges are resolved and the lock file updated. Throws if the\n * install process exits with a non-zero code.\n */\nexport const runPackageInstall = (\n rootDir: string,\n packageManager: PackageManager\n): void => {\n execSync(`${packageManager} install`, { cwd: rootDir, stdio: 'inherit' });\n};\n"],"mappings":"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"}
|