@twin.org/merge-locales 0.9.3-next.7 → 0.9.3-next.9

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/es/cli.js CHANGED
@@ -20,7 +20,7 @@ export class CLI extends CLIBase {
20
20
  return this.execute({
21
21
  title: "TWIN Merge Locales",
22
22
  appName: "merge-locales",
23
- version: "0.9.3-next.7", // x-release-please-version
23
+ version: "0.9.3-next.9", // x-release-please-version
24
24
  icon: "⚙️ ",
25
25
  supportsEnvFiles: false,
26
26
  overrideOutputWidth: options?.overrideOutputWidth
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE;;GAEG;AACH,MAAM,OAAO,GAAI,SAAQ,OAAO;IAC/B;;;;;;;OAOG;IACI,KAAK,CAAC,GAAG,CACf,IAAc,EACd,gBAAyB,EACzB,OAA0C;QAE1C,OAAO,IAAI,CAAC,OAAO,CAClB;YACC,KAAK,EAAE,oBAAoB;YAC3B,OAAO,EAAE,eAAe;YACxB,OAAO,EAAE,cAAc,EAAE,2BAA2B;YACpD,IAAI,EAAE,KAAK;YACX,gBAAgB,EAAE,KAAK;YACvB,mBAAmB,EAAE,OAAO,EAAE,mBAAmB;SACjD,EACD,gBAAgB,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,EACzF,IAAI,CACJ,CAAC;IACH,CAAC;IAED;;;OAGG;IACO,aAAa,CAAC,OAAgB;QACvC,wBAAwB,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;CACD","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { CLIBase } from \"@twin.org/cli-core\";\nimport type { Command } from \"commander\";\nimport { buildCommandMergeLocales } from \"./commands/mergeLocales.js\";\n\n/**\n * The main entry point for the CLI.\n */\nexport class CLI extends CLIBase {\n\t/**\n\t * Run the app.\n\t * @param argv The process arguments.\n\t * @param localesDirectory The directory for the locales, default to relative to the script.\n\t * @param options Additional options.\n\t * @param options.overrideOutputWidth Override the output width.\n\t * @returns The exit code.\n\t */\n\tpublic async run(\n\t\targv: string[],\n\t\tlocalesDirectory?: string,\n\t\toptions?: { overrideOutputWidth?: number }\n\t): Promise<number> {\n\t\treturn this.execute(\n\t\t\t{\n\t\t\t\ttitle: \"TWIN Merge Locales\",\n\t\t\t\tappName: \"merge-locales\",\n\t\t\t\tversion: \"0.9.3-next.7\", // x-release-please-version\n\t\t\t\ticon: \"⚙️ \",\n\t\t\t\tsupportsEnvFiles: false,\n\t\t\t\toverrideOutputWidth: options?.overrideOutputWidth\n\t\t\t},\n\t\t\tlocalesDirectory ?? path.join(path.dirname(fileURLToPath(import.meta.url)), \"../locales\"),\n\t\t\targv\n\t\t);\n\t}\n\n\t/**\n\t * Configure any options or actions at the root program level.\n\t * @param program The root program command.\n\t */\n\tprotected configureRoot(program: Command): void {\n\t\tbuildCommandMergeLocales(program);\n\t}\n}\n"]}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtE;;GAEG;AACH,MAAM,OAAO,GAAI,SAAQ,OAAO;IAC/B;;;;;;;OAOG;IACI,KAAK,CAAC,GAAG,CACf,IAAc,EACd,gBAAyB,EACzB,OAA0C;QAE1C,OAAO,IAAI,CAAC,OAAO,CAClB;YACC,KAAK,EAAE,oBAAoB;YAC3B,OAAO,EAAE,eAAe;YACxB,OAAO,EAAE,cAAc,EAAE,2BAA2B;YACpD,IAAI,EAAE,KAAK;YACX,gBAAgB,EAAE,KAAK;YACvB,mBAAmB,EAAE,OAAO,EAAE,mBAAmB;SACjD,EACD,gBAAgB,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,EACzF,IAAI,CACJ,CAAC;IACH,CAAC;IAED;;;OAGG;IACO,aAAa,CAAC,OAAgB;QACvC,wBAAwB,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;CACD","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { CLIBase } from \"@twin.org/cli-core\";\nimport type { Command } from \"commander\";\nimport { buildCommandMergeLocales } from \"./commands/mergeLocales.js\";\n\n/**\n * The main entry point for the CLI.\n */\nexport class CLI extends CLIBase {\n\t/**\n\t * Run the app.\n\t * @param argv The process arguments.\n\t * @param localesDirectory The directory for the locales, default to relative to the script.\n\t * @param options Additional options.\n\t * @param options.overrideOutputWidth Override the output width.\n\t * @returns The exit code.\n\t */\n\tpublic async run(\n\t\targv: string[],\n\t\tlocalesDirectory?: string,\n\t\toptions?: { overrideOutputWidth?: number }\n\t): Promise<number> {\n\t\treturn this.execute(\n\t\t\t{\n\t\t\t\ttitle: \"TWIN Merge Locales\",\n\t\t\t\tappName: \"merge-locales\",\n\t\t\t\tversion: \"0.9.3-next.9\", // x-release-please-version\n\t\t\t\ticon: \"⚙️ \",\n\t\t\t\tsupportsEnvFiles: false,\n\t\t\t\toverrideOutputWidth: options?.overrideOutputWidth\n\t\t\t},\n\t\t\tlocalesDirectory ?? path.join(path.dirname(fileURLToPath(import.meta.url)), \"../locales\"),\n\t\t\targv\n\t\t);\n\t}\n\n\t/**\n\t * Configure any options or actions at the root program level.\n\t * @param program The root program command.\n\t */\n\tprotected configureRoot(program: Command): void {\n\t\tbuildCommandMergeLocales(program);\n\t}\n}\n"]}
@@ -57,8 +57,6 @@ export async function mergeLocales(workingDirectory, config) {
57
57
  locales.push({ label: "English", code: "en" });
58
58
  }
59
59
  CLIDisplay.value(I18n.formatMessage("commands.merge-locales.labels.outputDirectory"), outputDirectory);
60
- const npmRoot = await CLIUtils.findNpmRoot(workingDirectory);
61
- CLIDisplay.value(I18n.formatMessage("commands.merge-locales.labels.npmRoot"), npmRoot);
62
60
  CLIDisplay.break();
63
61
  CLIDisplay.task(I18n.formatMessage("commands.merge-locales.progress.creatingOutputDirectory"), outputDirectory);
64
62
  try {
@@ -66,22 +64,34 @@ export async function mergeLocales(workingDirectory, config) {
66
64
  }
67
65
  catch { }
68
66
  await mkdir(outputDirectory, { recursive: true });
69
- let packageNames = [];
70
- const packageJson = await findDependencies(npmRoot, path.join(workingDirectory, "package.json"), packageNames);
67
+ const packageLocations = {};
68
+ const packageJson = await findDependencies(workingDirectory, path.join(workingDirectory, "package.json"), packageLocations);
71
69
  excludePackages.push("@twin.org/merge-locales");
72
70
  excludePackages.push("@twin.org/nameof");
73
71
  excludePackages.push("@twin.org/nameof-transformer");
74
- packageNames = packageNames.filter(pkg => !excludePackages.includes(pkg));
75
- packageNames.push(...includePackages);
72
+ const packageNames = Object.keys(packageLocations).filter(pkg => !excludePackages.includes(pkg));
73
+ for (const includePackage of includePackages) {
74
+ if (!packageNames.includes(includePackage)) {
75
+ const packageRoot = packageLocations[includePackage] ??
76
+ (await CLIUtils.findPackageRoot(includePackage, workingDirectory));
77
+ if (Is.stringValue(packageRoot)) {
78
+ packageLocations[includePackage] = packageRoot;
79
+ packageNames.push(includePackage);
80
+ }
81
+ else {
82
+ CLIDisplay.warning(`${I18n.formatMessage("commands.merge-locales.labels.packageNotFound")}: ${includePackage}`);
83
+ }
84
+ }
85
+ }
76
86
  CLIDisplay.break();
77
87
  CLIDisplay.section(I18n.formatMessage("commands.merge-locales.labels.sourcePackages"));
78
88
  for (const packageName of packageNames) {
79
- CLIDisplay.value("", packageName, 1);
89
+ CLIDisplay.value(packageName, packageLocations[packageName], 1);
80
90
  }
81
91
  CLIDisplay.break();
82
92
  const localeDictionaries = {};
83
93
  for (const packageName of packageNames) {
84
- const packageLocalDirectory = path.join(npmRoot, packageName, "locales");
94
+ const packageLocalDirectory = path.join(packageLocations[packageName], "locales");
85
95
  await mergePackageLocales(packageLocalDirectory, packageName, locales, localeDictionaries);
86
96
  }
87
97
  // Merge the main package last so that it can override any other packages.
@@ -121,32 +131,46 @@ async function mergePackageLocales(packageLocalDirectory, packageName, locales,
121
131
  }
122
132
  /**
123
133
  * Find dependencies for the package.
124
- * @param npmRoot The root of the NPM packages.
134
+ * @param searchFolder The folder to resolve the dependencies from.
125
135
  * @param packageJsonPath The path to the package.json.
126
- * @param packageNames The package names to add to.
136
+ * @param packageLocations The package locations to add to, keyed by package name.
127
137
  * @returns The package details.
128
138
  * @internal
129
139
  */
130
- async function findDependencies(npmRoot, packageJsonPath, packageNames) {
140
+ async function findDependencies(searchFolder, packageJsonPath, packageLocations) {
131
141
  const packageJson = await CLIUtils.readJsonFile(packageJsonPath);
132
142
  if (Is.objectValue(packageJson?.dependencies)) {
133
143
  for (const pkg in packageJson.dependencies) {
134
- if (pkg.startsWith("@twin.org") && !packageNames.includes(pkg)) {
135
- packageNames.push(pkg);
136
- const packagePath = path.join(npmRoot, pkg, "package.json");
137
- await findDependencies(npmRoot, packagePath, packageNames);
138
- }
144
+ await findPackageDependencies(searchFolder, pkg, packageLocations);
139
145
  }
140
146
  }
141
147
  if (Is.objectValue(packageJson?.peerDependencies)) {
142
148
  for (const pkg in packageJson.peerDependencies) {
143
- if (pkg.startsWith("@twin.org") && !packageNames.includes(pkg)) {
144
- packageNames.push(pkg);
145
- const packagePath = path.join(npmRoot, pkg, "package.json");
146
- await findDependencies(npmRoot, packagePath, packageNames);
147
- }
149
+ await findPackageDependencies(searchFolder, pkg, packageLocations);
148
150
  }
149
151
  }
150
152
  return packageJson ?? {};
151
153
  }
154
+ /**
155
+ * Locate a package and find its dependencies.
156
+ * @param searchFolder The folder to resolve the package from.
157
+ * @param packageName The name of the package to locate.
158
+ * @param packageLocations The package locations to add to, keyed by package name.
159
+ * @internal
160
+ */
161
+ async function findPackageDependencies(searchFolder, packageName, packageLocations) {
162
+ if (!packageName.startsWith("@twin.org") || Is.stringValue(packageLocations[packageName])) {
163
+ return;
164
+ }
165
+ // The location of a package can not be assumed to be in a single root node_modules folder,
166
+ // as package managers such nest the dependencies of each package, so walk the tree
167
+ // from the folder of the package which depends on it.
168
+ const packageRoot = await CLIUtils.findPackageRoot(packageName, searchFolder);
169
+ if (!Is.stringValue(packageRoot)) {
170
+ CLIDisplay.warning(`${I18n.formatMessage("commands.merge-locales.labels.packageNotFound")}: ${packageName}`);
171
+ return;
172
+ }
173
+ packageLocations[packageName] = packageRoot;
174
+ await findDependencies(packageRoot, path.join(packageRoot, "package.json"), packageLocations);
175
+ }
152
176
  //# sourceMappingURL=mergeLocales.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mergeLocales.js","sourceRoot":"","sources":["../../../src/commands/mergeLocales.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { mkdir, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { CLIDisplay, CLIUtils } from \"@twin.org/cli-core\";\nimport {\n\tGeneralError,\n\tI18n,\n\tIs,\n\tObjectHelper,\n\ttype ILocale,\n\ttype ILocaleDictionary\n} from \"@twin.org/core\";\nimport type { Command } from \"commander\";\nimport type { IMergeLocalesConfig } from \"../models/IMergeLocalesConfig.js\";\nimport type { IPackageJson } from \"../models/IPackageJson.js\";\n\n/**\n * Build the root command to be consumed by the CLI.\n * @param program The command to build on.\n */\nexport function buildCommandMergeLocales(program: Command): void {\n\tprogram\n\t\t.option(\n\t\t\tI18n.formatMessage(\"commands.merge-locales.options.config.param\"),\n\t\t\tI18n.formatMessage(\"commands.merge-locales.options.config.description\")\n\t\t)\n\t\t.action(async opts => {\n\t\t\tawait actionCommandMergeLocales(opts);\n\t\t});\n}\n\n/**\n * Action the root command.\n * @param opts The options for the command.\n * @param opts.config The optional configuration file.\n */\nexport async function actionCommandMergeLocales(opts: { config?: string }): Promise<void> {\n\tlet config: IMergeLocalesConfig | undefined;\n\tif (Is.stringValue(opts.config)) {\n\t\ttry {\n\t\t\tconst configJson = path.resolve(opts.config);\n\t\t\tCLIDisplay.value(I18n.formatMessage(\"commands.merge-locales.labels.configJson\"), configJson);\n\t\t\tCLIDisplay.break();\n\n\t\t\tCLIDisplay.task(I18n.formatMessage(\"commands.merge-locales.progress.loadingConfigJson\"));\n\t\t\tCLIDisplay.break();\n\n\t\t\tconfig = await CLIUtils.readJsonFile<IMergeLocalesConfig>(configJson);\n\t\t\tCLIDisplay.break();\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\"commands\", \"commands.merge-locales.configFailed\", undefined, err);\n\t\t}\n\n\t\tif (Is.empty(config)) {\n\t\t\tthrow new GeneralError(\"commands\", \"commands.merge-locales.configFailed\");\n\t\t}\n\t}\n\n\tawait mergeLocales(process.cwd(), config ?? {});\n\n\tCLIDisplay.done();\n}\n\n/**\n * Merge the locales.\n * @param workingDirectory The folder the app was run from.\n * @param config The configuration for the app.\n */\nexport async function mergeLocales(\n\tworkingDirectory: string,\n\tconfig: IMergeLocalesConfig\n): Promise<void> {\n\tCLIDisplay.value(\n\t\tI18n.formatMessage(\"commands.merge-locales.labels.workingDirectory\"),\n\t\tworkingDirectory\n\t);\n\n\tconst outputDirectory = path.resolve(config.outputDirectory ?? \"./dist/locales\");\n\tconst locales = config.locales ?? [];\n\tconst includePackages = config.includePackages ?? [];\n\tconst excludePackages = config.excludePackages ?? [];\n\n\tif (locales.length === 0) {\n\t\tlocales.push({ label: \"English\", code: \"en\" });\n\t}\n\tCLIDisplay.value(\n\t\tI18n.formatMessage(\"commands.merge-locales.labels.outputDirectory\"),\n\t\toutputDirectory\n\t);\n\n\tconst npmRoot = await CLIUtils.findNpmRoot(workingDirectory);\n\tCLIDisplay.value(I18n.formatMessage(\"commands.merge-locales.labels.npmRoot\"), npmRoot);\n\tCLIDisplay.break();\n\n\tCLIDisplay.task(\n\t\tI18n.formatMessage(\"commands.merge-locales.progress.creatingOutputDirectory\"),\n\t\toutputDirectory\n\t);\n\n\ttry {\n\t\tawait rm(outputDirectory, { recursive: true });\n\t} catch {}\n\tawait mkdir(outputDirectory, { recursive: true });\n\n\tlet packageNames: string[] = [];\n\n\tconst packageJson = await findDependencies(\n\t\tnpmRoot,\n\t\tpath.join(workingDirectory, \"package.json\"),\n\t\tpackageNames\n\t);\n\n\texcludePackages.push(\"@twin.org/merge-locales\");\n\texcludePackages.push(\"@twin.org/nameof\");\n\texcludePackages.push(\"@twin.org/nameof-transformer\");\n\n\tpackageNames = packageNames.filter(pkg => !excludePackages.includes(pkg));\n\tpackageNames.push(...includePackages);\n\n\tCLIDisplay.break();\n\tCLIDisplay.section(I18n.formatMessage(\"commands.merge-locales.labels.sourcePackages\"));\n\tfor (const packageName of packageNames) {\n\t\tCLIDisplay.value(\"\", packageName, 1);\n\t}\n\tCLIDisplay.break();\n\n\tconst localeDictionaries: { [locale: string]: ILocaleDictionary } = {};\n\n\tfor (const packageName of packageNames) {\n\t\tconst packageLocalDirectory = path.join(npmRoot, packageName, \"locales\");\n\t\tawait mergePackageLocales(packageLocalDirectory, packageName, locales, localeDictionaries);\n\t}\n\n\t// Merge the main package last so that it can override any other packages.\n\tif (Is.stringValue(packageJson.name)) {\n\t\tawait mergePackageLocales(\n\t\t\tpath.join(workingDirectory, \"locales\"),\n\t\t\tpackageJson.name,\n\t\t\tlocales,\n\t\t\tlocaleDictionaries\n\t\t);\n\t}\n\n\tCLIDisplay.break();\n\tCLIDisplay.task(I18n.formatMessage(\"commands.merge-locales.progress.writingMergedLocales\"));\n\n\tfor (const localeDictionary in localeDictionaries) {\n\t\tconst localeFile = path.join(outputDirectory, `${localeDictionary}.json`);\n\t\tCLIDisplay.value(\n\t\t\tI18n.formatMessage(\"commands.merge-locales.labels.writingLocale\"),\n\t\t\tlocaleFile,\n\t\t\t1\n\t\t);\n\t\tawait writeFile(\n\t\t\tlocaleFile,\n\t\t\t`${JSON.stringify(localeDictionaries[localeDictionary], undefined, \"\\t\")}\\n`,\n\t\t\t\"utf8\"\n\t\t);\n\t}\n\tCLIDisplay.break();\n}\n\n/**\n * Merge the locales for a package.\n * @param packageLocalDirectory The root of the NPM packages.\n * @param packageName The name of the package.\n * @param locales The locales to merge.\n * @internal\n */\nasync function mergePackageLocales(\n\tpackageLocalDirectory: string,\n\tpackageName: string,\n\tlocales: ILocale[],\n\tlocaleDictionaries: { [locale: string]: ILocaleDictionary }\n): Promise<void> {\n\tCLIDisplay.task(\n\t\tI18n.formatMessage(\"commands.merge-locales.progress.mergingLocalesForPackage\"),\n\t\tpackageName\n\t);\n\n\tif (await CLIUtils.dirExists(packageLocalDirectory)) {\n\t\tfor (const locale of locales) {\n\t\t\tconst localeFile = path.join(packageLocalDirectory, `${locale.code}.json`);\n\t\t\tif (await CLIUtils.dirExists(localeFile)) {\n\t\t\t\tCLIDisplay.value(\n\t\t\t\t\tI18n.formatMessage(\"commands.merge-locales.labels.mergingLocale\"),\n\t\t\t\t\tlocale.code,\n\t\t\t\t\t1\n\t\t\t\t);\n\n\t\t\t\tconst localeDictionary = await CLIUtils.readJsonFile<ILocaleDictionary>(localeFile);\n\t\t\t\tlocaleDictionaries[locale.code] ??= {};\n\t\t\t\tlocaleDictionaries[locale.code] = ObjectHelper.merge(\n\t\t\t\t\tlocaleDictionaries[locale.code],\n\t\t\t\t\tlocaleDictionary\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\tCLIDisplay.break();\n}\n\n/**\n * Find dependencies for the package.\n * @param npmRoot The root of the NPM packages.\n * @param packageJsonPath The path to the package.json.\n * @param packageNames The package names to add to.\n * @returns The package details.\n * @internal\n */\nasync function findDependencies(\n\tnpmRoot: string,\n\tpackageJsonPath: string,\n\tpackageNames: string[]\n): Promise<IPackageJson> {\n\tconst packageJson = await CLIUtils.readJsonFile<IPackageJson>(packageJsonPath);\n\n\tif (Is.objectValue(packageJson?.dependencies)) {\n\t\tfor (const pkg in packageJson.dependencies) {\n\t\t\tif (pkg.startsWith(\"@twin.org\") && !packageNames.includes(pkg)) {\n\t\t\t\tpackageNames.push(pkg);\n\t\t\t\tconst packagePath = path.join(npmRoot, pkg, \"package.json\");\n\t\t\t\tawait findDependencies(npmRoot, packagePath, packageNames);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (Is.objectValue(packageJson?.peerDependencies)) {\n\t\tfor (const pkg in packageJson.peerDependencies) {\n\t\t\tif (pkg.startsWith(\"@twin.org\") && !packageNames.includes(pkg)) {\n\t\t\t\tpackageNames.push(pkg);\n\t\t\t\tconst packagePath = path.join(npmRoot, pkg, \"package.json\");\n\t\t\t\tawait findDependencies(npmRoot, packagePath, packageNames);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn packageJson ?? {};\n}\n"]}
1
+ {"version":3,"file":"mergeLocales.js","sourceRoot":"","sources":["../../../src/commands/mergeLocales.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { mkdir, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { CLIDisplay, CLIUtils } from \"@twin.org/cli-core\";\nimport {\n\tGeneralError,\n\tI18n,\n\tIs,\n\tObjectHelper,\n\ttype ILocale,\n\ttype ILocaleDictionary\n} from \"@twin.org/core\";\nimport type { Command } from \"commander\";\nimport type { IMergeLocalesConfig } from \"../models/IMergeLocalesConfig.js\";\nimport type { IPackageJson } from \"../models/IPackageJson.js\";\n\n/**\n * Build the root command to be consumed by the CLI.\n * @param program The command to build on.\n */\nexport function buildCommandMergeLocales(program: Command): void {\n\tprogram\n\t\t.option(\n\t\t\tI18n.formatMessage(\"commands.merge-locales.options.config.param\"),\n\t\t\tI18n.formatMessage(\"commands.merge-locales.options.config.description\")\n\t\t)\n\t\t.action(async opts => {\n\t\t\tawait actionCommandMergeLocales(opts);\n\t\t});\n}\n\n/**\n * Action the root command.\n * @param opts The options for the command.\n * @param opts.config The optional configuration file.\n */\nexport async function actionCommandMergeLocales(opts: { config?: string }): Promise<void> {\n\tlet config: IMergeLocalesConfig | undefined;\n\tif (Is.stringValue(opts.config)) {\n\t\ttry {\n\t\t\tconst configJson = path.resolve(opts.config);\n\t\t\tCLIDisplay.value(I18n.formatMessage(\"commands.merge-locales.labels.configJson\"), configJson);\n\t\t\tCLIDisplay.break();\n\n\t\t\tCLIDisplay.task(I18n.formatMessage(\"commands.merge-locales.progress.loadingConfigJson\"));\n\t\t\tCLIDisplay.break();\n\n\t\t\tconfig = await CLIUtils.readJsonFile<IMergeLocalesConfig>(configJson);\n\t\t\tCLIDisplay.break();\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(\"commands\", \"commands.merge-locales.configFailed\", undefined, err);\n\t\t}\n\n\t\tif (Is.empty(config)) {\n\t\t\tthrow new GeneralError(\"commands\", \"commands.merge-locales.configFailed\");\n\t\t}\n\t}\n\n\tawait mergeLocales(process.cwd(), config ?? {});\n\n\tCLIDisplay.done();\n}\n\n/**\n * Merge the locales.\n * @param workingDirectory The folder the app was run from.\n * @param config The configuration for the app.\n */\nexport async function mergeLocales(\n\tworkingDirectory: string,\n\tconfig: IMergeLocalesConfig\n): Promise<void> {\n\tCLIDisplay.value(\n\t\tI18n.formatMessage(\"commands.merge-locales.labels.workingDirectory\"),\n\t\tworkingDirectory\n\t);\n\n\tconst outputDirectory = path.resolve(config.outputDirectory ?? \"./dist/locales\");\n\tconst locales = config.locales ?? [];\n\tconst includePackages = config.includePackages ?? [];\n\tconst excludePackages = config.excludePackages ?? [];\n\n\tif (locales.length === 0) {\n\t\tlocales.push({ label: \"English\", code: \"en\" });\n\t}\n\tCLIDisplay.value(\n\t\tI18n.formatMessage(\"commands.merge-locales.labels.outputDirectory\"),\n\t\toutputDirectory\n\t);\n\n\tCLIDisplay.break();\n\n\tCLIDisplay.task(\n\t\tI18n.formatMessage(\"commands.merge-locales.progress.creatingOutputDirectory\"),\n\t\toutputDirectory\n\t);\n\n\ttry {\n\t\tawait rm(outputDirectory, { recursive: true });\n\t} catch {}\n\tawait mkdir(outputDirectory, { recursive: true });\n\n\tconst packageLocations: { [packageName: string]: string } = {};\n\n\tconst packageJson = await findDependencies(\n\t\tworkingDirectory,\n\t\tpath.join(workingDirectory, \"package.json\"),\n\t\tpackageLocations\n\t);\n\n\texcludePackages.push(\"@twin.org/merge-locales\");\n\texcludePackages.push(\"@twin.org/nameof\");\n\texcludePackages.push(\"@twin.org/nameof-transformer\");\n\n\tconst packageNames = Object.keys(packageLocations).filter(pkg => !excludePackages.includes(pkg));\n\n\tfor (const includePackage of includePackages) {\n\t\tif (!packageNames.includes(includePackage)) {\n\t\t\tconst packageRoot =\n\t\t\t\tpackageLocations[includePackage] ??\n\t\t\t\t(await CLIUtils.findPackageRoot(includePackage, workingDirectory));\n\n\t\t\tif (Is.stringValue(packageRoot)) {\n\t\t\t\tpackageLocations[includePackage] = packageRoot;\n\t\t\t\tpackageNames.push(includePackage);\n\t\t\t} else {\n\t\t\t\tCLIDisplay.warning(\n\t\t\t\t\t`${I18n.formatMessage(\"commands.merge-locales.labels.packageNotFound\")}: ${includePackage}`\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tCLIDisplay.break();\n\tCLIDisplay.section(I18n.formatMessage(\"commands.merge-locales.labels.sourcePackages\"));\n\tfor (const packageName of packageNames) {\n\t\tCLIDisplay.value(packageName, packageLocations[packageName], 1);\n\t}\n\tCLIDisplay.break();\n\n\tconst localeDictionaries: { [locale: string]: ILocaleDictionary } = {};\n\n\tfor (const packageName of packageNames) {\n\t\tconst packageLocalDirectory = path.join(packageLocations[packageName], \"locales\");\n\t\tawait mergePackageLocales(packageLocalDirectory, packageName, locales, localeDictionaries);\n\t}\n\n\t// Merge the main package last so that it can override any other packages.\n\tif (Is.stringValue(packageJson.name)) {\n\t\tawait mergePackageLocales(\n\t\t\tpath.join(workingDirectory, \"locales\"),\n\t\t\tpackageJson.name,\n\t\t\tlocales,\n\t\t\tlocaleDictionaries\n\t\t);\n\t}\n\n\tCLIDisplay.break();\n\tCLIDisplay.task(I18n.formatMessage(\"commands.merge-locales.progress.writingMergedLocales\"));\n\n\tfor (const localeDictionary in localeDictionaries) {\n\t\tconst localeFile = path.join(outputDirectory, `${localeDictionary}.json`);\n\t\tCLIDisplay.value(\n\t\t\tI18n.formatMessage(\"commands.merge-locales.labels.writingLocale\"),\n\t\t\tlocaleFile,\n\t\t\t1\n\t\t);\n\t\tawait writeFile(\n\t\t\tlocaleFile,\n\t\t\t`${JSON.stringify(localeDictionaries[localeDictionary], undefined, \"\\t\")}\\n`,\n\t\t\t\"utf8\"\n\t\t);\n\t}\n\tCLIDisplay.break();\n}\n\n/**\n * Merge the locales for a package.\n * @param packageLocalDirectory The root of the NPM packages.\n * @param packageName The name of the package.\n * @param locales The locales to merge.\n * @internal\n */\nasync function mergePackageLocales(\n\tpackageLocalDirectory: string,\n\tpackageName: string,\n\tlocales: ILocale[],\n\tlocaleDictionaries: { [locale: string]: ILocaleDictionary }\n): Promise<void> {\n\tCLIDisplay.task(\n\t\tI18n.formatMessage(\"commands.merge-locales.progress.mergingLocalesForPackage\"),\n\t\tpackageName\n\t);\n\n\tif (await CLIUtils.dirExists(packageLocalDirectory)) {\n\t\tfor (const locale of locales) {\n\t\t\tconst localeFile = path.join(packageLocalDirectory, `${locale.code}.json`);\n\t\t\tif (await CLIUtils.dirExists(localeFile)) {\n\t\t\t\tCLIDisplay.value(\n\t\t\t\t\tI18n.formatMessage(\"commands.merge-locales.labels.mergingLocale\"),\n\t\t\t\t\tlocale.code,\n\t\t\t\t\t1\n\t\t\t\t);\n\n\t\t\t\tconst localeDictionary = await CLIUtils.readJsonFile<ILocaleDictionary>(localeFile);\n\t\t\t\tlocaleDictionaries[locale.code] ??= {};\n\t\t\t\tlocaleDictionaries[locale.code] = ObjectHelper.merge(\n\t\t\t\t\tlocaleDictionaries[locale.code],\n\t\t\t\t\tlocaleDictionary\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\tCLIDisplay.break();\n}\n\n/**\n * Find dependencies for the package.\n * @param searchFolder The folder to resolve the dependencies from.\n * @param packageJsonPath The path to the package.json.\n * @param packageLocations The package locations to add to, keyed by package name.\n * @returns The package details.\n * @internal\n */\nasync function findDependencies(\n\tsearchFolder: string,\n\tpackageJsonPath: string,\n\tpackageLocations: { [packageName: string]: string }\n): Promise<IPackageJson> {\n\tconst packageJson = await CLIUtils.readJsonFile<IPackageJson>(packageJsonPath);\n\n\tif (Is.objectValue(packageJson?.dependencies)) {\n\t\tfor (const pkg in packageJson.dependencies) {\n\t\t\tawait findPackageDependencies(searchFolder, pkg, packageLocations);\n\t\t}\n\t}\n\n\tif (Is.objectValue(packageJson?.peerDependencies)) {\n\t\tfor (const pkg in packageJson.peerDependencies) {\n\t\t\tawait findPackageDependencies(searchFolder, pkg, packageLocations);\n\t\t}\n\t}\n\n\treturn packageJson ?? {};\n}\n\n/**\n * Locate a package and find its dependencies.\n * @param searchFolder The folder to resolve the package from.\n * @param packageName The name of the package to locate.\n * @param packageLocations The package locations to add to, keyed by package name.\n * @internal\n */\nasync function findPackageDependencies(\n\tsearchFolder: string,\n\tpackageName: string,\n\tpackageLocations: { [packageName: string]: string }\n): Promise<void> {\n\tif (!packageName.startsWith(\"@twin.org\") || Is.stringValue(packageLocations[packageName])) {\n\t\treturn;\n\t}\n\n\t// The location of a package can not be assumed to be in a single root node_modules folder,\n\t// as package managers such nest the dependencies of each package, so walk the tree\n\t// from the folder of the package which depends on it.\n\tconst packageRoot = await CLIUtils.findPackageRoot(packageName, searchFolder);\n\n\tif (!Is.stringValue(packageRoot)) {\n\t\tCLIDisplay.warning(\n\t\t\t`${I18n.formatMessage(\"commands.merge-locales.labels.packageNotFound\")}: ${packageName}`\n\t\t);\n\t\treturn;\n\t}\n\n\tpackageLocations[packageName] = packageRoot;\n\n\tawait findDependencies(packageRoot, path.join(packageRoot, \"package.json\"), packageLocations);\n}\n"]}
@@ -218,7 +218,7 @@
218
218
  "configJson": "Config JSON",
219
219
  "workingDirectory": "Working Directory",
220
220
  "outputDirectory": "Output Directory",
221
- "npmRoot": "NPM Root",
221
+ "packageNotFound": "Package Not Found",
222
222
  "sourcePackages": "Source Packages",
223
223
  "writingLocale": "Writing Locale",
224
224
  "mergingLocale": "Merging Locale"
package/docs/changelog.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.3-next.9](https://github.com/iotaledger/twin-framework/compare/merge-locales-v0.9.3-next.8...merge-locales-v0.9.3-next.9) (2026-09-10)
4
+
5
+
6
+ ### Miscellaneous Chores
7
+
8
+ * **merge-locales:** Synchronize repo versions
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @twin.org/cli-core bumped from 0.9.3-next.8 to 0.9.3-next.9
16
+ * @twin.org/core bumped from 0.9.3-next.8 to 0.9.3-next.9
17
+ * @twin.org/nameof bumped from 0.9.3-next.8 to 0.9.3-next.9
18
+ * devDependencies
19
+ * @twin.org/nameof-transformer bumped from 0.9.3-next.8 to 0.9.3-next.9
20
+ * @twin.org/nameof-vitest-plugin bumped from 0.9.3-next.8 to 0.9.3-next.9
21
+
22
+ ## [0.9.3-next.8](https://github.com/iotaledger/twin-framework/compare/merge-locales-v0.9.3-next.7...merge-locales-v0.9.3-next.8) (2026-09-07)
23
+
24
+
25
+ ### Features
26
+
27
+ * improve node_modules location detection ([#486](https://github.com/iotaledger/twin-framework/issues/486)) ([c786853](https://github.com/iotaledger/twin-framework/commit/c7868538e9074f789577c0ab55552f3bcec0ef0e))
28
+
29
+
30
+ ### Dependencies
31
+
32
+ * The following workspace dependencies were updated
33
+ * dependencies
34
+ * @twin.org/cli-core bumped from 0.9.3-next.7 to 0.9.3-next.8
35
+ * @twin.org/core bumped from 0.9.3-next.7 to 0.9.3-next.8
36
+ * @twin.org/nameof bumped from 0.9.3-next.7 to 0.9.3-next.8
37
+ * devDependencies
38
+ * @twin.org/nameof-transformer bumped from 0.9.3-next.7 to 0.9.3-next.8
39
+ * @twin.org/nameof-vitest-plugin bumped from 0.9.3-next.7 to 0.9.3-next.8
40
+
3
41
  ## [0.9.3-next.7](https://github.com/iotaledger/twin-framework/compare/merge-locales-v0.9.3-next.6...merge-locales-v0.9.3-next.7) (2026-09-07)
4
42
 
5
43
 
package/locales/en.json CHANGED
@@ -24,7 +24,7 @@
24
24
  "configJson": "Config JSON",
25
25
  "workingDirectory": "Working Directory",
26
26
  "outputDirectory": "Output Directory",
27
- "npmRoot": "NPM Root",
27
+ "packageNotFound": "Package Not Found",
28
28
  "sourcePackages": "Source Packages",
29
29
  "writingLocale": "Writing Locale",
30
30
  "mergingLocale": "Merging Locale"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/merge-locales",
3
- "version": "0.9.3-next.7",
3
+ "version": "0.9.3-next.9",
4
4
  "description": "Merge locale files from all dependencies",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,9 +14,9 @@
14
14
  "node": ">=24.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@twin.org/cli-core": "0.9.3-next.7",
18
- "@twin.org/core": "0.9.3-next.7",
19
- "@twin.org/nameof": "0.9.3-next.7",
17
+ "@twin.org/cli-core": "0.9.3-next.9",
18
+ "@twin.org/core": "0.9.3-next.9",
19
+ "@twin.org/nameof": "0.9.3-next.9",
20
20
  "commander": "15.0.0",
21
21
  "glob": "13.0.6"
22
22
  },