@worldware/msg-cli 0.0.4 → 0.1.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.
Files changed (39) hide show
  1. package/dist/chunk-4Q2252JQ.mjs +50 -0
  2. package/dist/chunk-DBC2Y6VQ.mjs +167 -0
  3. package/dist/chunk-KKYCVD5M.mjs +136 -0
  4. package/dist/commands/create/project.cjs +293 -0
  5. package/dist/commands/create/project.d.mts +22 -0
  6. package/dist/commands/create/project.d.ts +22 -0
  7. package/dist/commands/create/project.mjs +151 -0
  8. package/dist/commands/create/resource.cjs +355 -0
  9. package/dist/commands/create/resource.d.mts +22 -0
  10. package/dist/commands/create/resource.d.ts +22 -0
  11. package/dist/commands/create/resource.mjs +143 -0
  12. package/dist/commands/init.cjs +259 -0
  13. package/dist/commands/init.d.mts +20 -0
  14. package/dist/commands/init.d.ts +20 -0
  15. package/dist/commands/init.mjs +133 -0
  16. package/dist/lib/create-project-helpers.cjs +163 -0
  17. package/dist/lib/create-project-helpers.d.mts +50 -0
  18. package/dist/lib/create-project-helpers.d.ts +50 -0
  19. package/dist/lib/create-project-helpers.mjs +14 -0
  20. package/dist/lib/create-resource-helpers.cjs +225 -0
  21. package/dist/lib/create-resource-helpers.d.mts +55 -0
  22. package/dist/lib/create-resource-helpers.d.ts +55 -0
  23. package/dist/lib/create-resource-helpers.mjs +15 -0
  24. package/dist/lib/init-helpers.cjs +203 -0
  25. package/dist/lib/init-helpers.d.mts +100 -0
  26. package/dist/lib/init-helpers.d.ts +100 -0
  27. package/dist/lib/init-helpers.mjs +30 -0
  28. package/dist/lib/utilities.cjs +203 -0
  29. package/dist/lib/utilities.d.mts +59 -0
  30. package/dist/lib/utilities.d.ts +59 -0
  31. package/dist/lib/utilities.mjs +172 -0
  32. package/package.json +7 -4
  33. package/dist/commands/create/project.js +0 -160
  34. package/dist/commands/create/resource.js +0 -169
  35. package/dist/commands/init.js +0 -131
  36. package/dist/lib/create-project-helpers.js +0 -112
  37. package/dist/lib/create-resource-helpers.js +0 -178
  38. package/dist/lib/init-helpers.js +0 -219
  39. package/dist/lib/utilities.js +0 -286
@@ -0,0 +1,50 @@
1
+ import {
2
+ dynamicImportFromUrl
3
+ } from "./chunk-KKYCVD5M.mjs";
4
+ import {
5
+ loadPackageJsonForMsg
6
+ } from "./chunk-DBC2Y6VQ.mjs";
7
+
8
+ // src/lib/create-project-helpers.ts
9
+ import { existsSync, mkdirSync, writeFileSync } from "fs";
10
+ import { dirname, join, relative } from "path";
11
+ import { pathToFileURL } from "url";
12
+ function calculateRelativePath(projectsDir, translationsDir) {
13
+ const rel = relative(projectsDir, translationsDir);
14
+ return rel.startsWith(".") ? rel : `./${rel}`;
15
+ }
16
+ async function importMsgProjectFile(projectsDir, projectName) {
17
+ const basePath = join(projectsDir, projectName);
18
+ const exts = [".ts", ".js"];
19
+ for (const ext of exts) {
20
+ const p = `${basePath}${ext}`;
21
+ if (existsSync(p)) {
22
+ try {
23
+ const url = pathToFileURL(p).href;
24
+ const mod = await dynamicImportFromUrl(url);
25
+ return mod?.default ?? mod;
26
+ } catch {
27
+ return void 0;
28
+ }
29
+ }
30
+ }
31
+ return void 0;
32
+ }
33
+ function writeMsgProjectFile(filePath, content) {
34
+ const dir = dirname(filePath);
35
+ if (!existsSync(dir)) {
36
+ mkdirSync(dir, { recursive: true });
37
+ }
38
+ writeFileSync(filePath, content, "utf-8");
39
+ }
40
+ function loadPackageJsonForCreateProject(cwd) {
41
+ const ctx = loadPackageJsonForMsg(cwd, { requireL10n: true });
42
+ return ctx.pkg;
43
+ }
44
+
45
+ export {
46
+ calculateRelativePath,
47
+ importMsgProjectFile,
48
+ writeMsgProjectFile,
49
+ loadPackageJsonForCreateProject
50
+ };
@@ -0,0 +1,167 @@
1
+ // src/lib/init-helpers.ts
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
3
+ import { dirname, join } from "path";
4
+ var DEFAULT_I18N_DIR = "src/i18n";
5
+ var DEFAULT_L10N_DIR = "res/l10n";
6
+ function findPackageJsonPath(cwd) {
7
+ let dir = cwd;
8
+ for (; ; ) {
9
+ const p = join(dir, "package.json");
10
+ if (existsSync(p)) return p;
11
+ const parent = dirname(dir);
12
+ if (parent === dir) return null;
13
+ dir = parent;
14
+ }
15
+ }
16
+ function readPackageJson(pkgPath) {
17
+ const raw = readFileSync(pkgPath, "utf-8");
18
+ try {
19
+ const parsed = JSON.parse(raw);
20
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
21
+ throw new Error("package.json must be a JSON object");
22
+ }
23
+ return parsed;
24
+ } catch (err) {
25
+ if (err instanceof SyntaxError) {
26
+ throw new Error("Invalid package.json: " + err.message);
27
+ }
28
+ throw err;
29
+ }
30
+ }
31
+ function loadPackageJsonForMsg(cwd, options) {
32
+ const pkgPath = findPackageJsonPath(cwd);
33
+ if (!pkgPath) {
34
+ throw new Error("package.json not found. Run this command from the project root.");
35
+ }
36
+ let pkg;
37
+ try {
38
+ pkg = readPackageJson(pkgPath);
39
+ } catch (err) {
40
+ const msg = err instanceof Error ? err.message : "package.json could not be parsed.";
41
+ throw new Error(msg);
42
+ }
43
+ const dirs = pkg.directories;
44
+ if (!dirs || typeof dirs !== "object" || !dirs.i18n) {
45
+ throw new Error("package.json must contain directories.i18n. Run 'msg init' first.");
46
+ }
47
+ if (options?.requireL10n && !dirs.l10n) {
48
+ throw new Error(
49
+ "package.json must contain directories.i18n and directories.l10n. Run 'msg init' first."
50
+ );
51
+ }
52
+ const rootDir = dirname(pkgPath);
53
+ const useTypeScript = existsSync(join(rootDir, "tsconfig.json"));
54
+ const isEsm = pkg.type === "module";
55
+ return {
56
+ pkgPath,
57
+ rootDir,
58
+ pkg,
59
+ i18nDir: dirs.i18n,
60
+ l10nDir: dirs.l10n,
61
+ isEsm,
62
+ useTypeScript
63
+ };
64
+ }
65
+ function writePackageJson(pkgPath, pkg) {
66
+ const json = JSON.stringify(pkg, null, 2) + "\n";
67
+ writeFileSync(pkgPath, json, "utf-8");
68
+ }
69
+ function validatePaths(rootDir, i18nDir, l10nDir) {
70
+ const trimmedI18n = i18nDir.trim();
71
+ const trimmedL10n = l10nDir.trim();
72
+ if (!trimmedI18n) return { valid: false, error: "i18n directory path cannot be empty" };
73
+ if (!trimmedL10n) return { valid: false, error: "l10n directory path cannot be empty" };
74
+ if (trimmedI18n.startsWith("/") || /^[A-Za-z]:/.test(trimmedI18n)) {
75
+ return { valid: false, error: "i18n path must be relative" };
76
+ }
77
+ if (trimmedL10n.startsWith("/") || /^[A-Za-z]:/.test(trimmedL10n)) {
78
+ return { valid: false, error: "l10n path must be relative" };
79
+ }
80
+ return { valid: true };
81
+ }
82
+ var GITKEEP = ".gitkeep";
83
+ function ensureDirectoriesWithGitkeep(rootDir, i18nDir, l10nDir, force) {
84
+ const leaves = [
85
+ join(rootDir, i18nDir, "projects"),
86
+ join(rootDir, i18nDir, "resources"),
87
+ join(rootDir, l10nDir, "translations"),
88
+ join(rootDir, l10nDir, "xliff")
89
+ ];
90
+ for (const leaf of leaves) {
91
+ const parent = dirname(leaf);
92
+ if (!existsSync(parent)) {
93
+ mkdirSync(parent, { recursive: true });
94
+ }
95
+ if (!existsSync(leaf)) {
96
+ mkdirSync(leaf, { recursive: true });
97
+ }
98
+ const gitkeepPath = join(leaf, GITKEEP);
99
+ if (force || !existsSync(gitkeepPath)) {
100
+ writeFileSync(gitkeepPath, "", "utf-8");
101
+ }
102
+ }
103
+ }
104
+ function isAlreadyInitialized(pkg, rootDir, i18nDir, l10nDir) {
105
+ const dirs = pkg.directories;
106
+ if (!dirs || typeof dirs !== "object") return false;
107
+ if (dirs.i18n !== i18nDir || dirs.l10n !== l10nDir) return false;
108
+ const i18nFull = join(rootDir, i18nDir);
109
+ const l10nFull = join(rootDir, l10nDir);
110
+ return existsSync(i18nFull) && existsSync(l10nFull);
111
+ }
112
+ function addDirectoriesToPackageJson(pkg, i18nDir, l10nDir) {
113
+ const directories = { ...pkg.directories, i18n: i18nDir, l10n: l10nDir, root: "." };
114
+ return { ...pkg, directories };
115
+ }
116
+ function addImportAliasesToPackageJson(pkg, i18nDir, l10nDir) {
117
+ const imports = {
118
+ ...pkg.imports,
119
+ "#i18n/*": `${i18nDir}/*`,
120
+ "#l10n/*": `${l10nDir}/*`,
121
+ "#root/*": "./*"
122
+ };
123
+ return { ...pkg, imports };
124
+ }
125
+ function addScriptsToPackageJson(pkg) {
126
+ const scripts = {
127
+ ...pkg.scripts,
128
+ "i18n-export": "msg export:resources",
129
+ "l10n-import": "msg import:translations"
130
+ };
131
+ return { ...pkg, scripts };
132
+ }
133
+ function addTsconfigPaths(tsconfigPath, i18nDir, l10nDir) {
134
+ const raw = readFileSync(tsconfigPath, "utf-8");
135
+ let config;
136
+ try {
137
+ config = JSON.parse(raw);
138
+ } catch {
139
+ throw new Error("Invalid tsconfig.json");
140
+ }
141
+ if (!config.compilerOptions) config.compilerOptions = {};
142
+ const co = config.compilerOptions;
143
+ co.baseUrl = co.baseUrl ?? ".";
144
+ co.paths = {
145
+ ...co.paths,
146
+ "#i18n/*": [`${i18nDir}/*`],
147
+ "#l10n/*": [`${l10nDir}/*`],
148
+ "#root/*": ["./*"]
149
+ };
150
+ writeFileSync(tsconfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
151
+ }
152
+
153
+ export {
154
+ DEFAULT_I18N_DIR,
155
+ DEFAULT_L10N_DIR,
156
+ findPackageJsonPath,
157
+ readPackageJson,
158
+ loadPackageJsonForMsg,
159
+ writePackageJson,
160
+ validatePaths,
161
+ ensureDirectoriesWithGitkeep,
162
+ isAlreadyInitialized,
163
+ addDirectoriesToPackageJson,
164
+ addImportAliasesToPackageJson,
165
+ addScriptsToPackageJson,
166
+ addTsconfigPaths
167
+ };
@@ -0,0 +1,136 @@
1
+ import {
2
+ loadPackageJsonForMsg
3
+ } from "./chunk-DBC2Y6VQ.mjs";
4
+
5
+ // src/lib/create-resource-helpers.ts
6
+ import { existsSync, mkdirSync, writeFileSync } from "fs";
7
+ import { createRequire } from "module";
8
+ import { dirname, join } from "path";
9
+ import { fileURLToPath, pathToFileURL } from "url";
10
+ async function dynamicImportFromUrl(url) {
11
+ try {
12
+ return await import(
13
+ /* @vite-ignore */
14
+ url
15
+ );
16
+ } catch (err) {
17
+ const msg = err instanceof Error ? err.message : String(err);
18
+ const useRequire = msg.includes("dynamic import callback") || msg.includes("ERR_VM_DYNAMIC_IMPORT");
19
+ if (useRequire) {
20
+ try {
21
+ const path = url.startsWith("file:") ? fileURLToPath(url) : url;
22
+ const base = pathToFileURL(process.cwd()).href;
23
+ const req = createRequire(base);
24
+ const mod = req(path);
25
+ return Promise.resolve(mod ?? {});
26
+ } catch {
27
+ }
28
+ }
29
+ throw err;
30
+ }
31
+ }
32
+ function readPackageJsonForCreateResource(cwd) {
33
+ const ctx = loadPackageJsonForMsg(cwd);
34
+ return {
35
+ i18nDir: ctx.i18nDir,
36
+ isEsm: ctx.isEsm,
37
+ useTypeScript: ctx.useTypeScript
38
+ };
39
+ }
40
+ function dirFromSourceLocale(sourceLocale) {
41
+ const lang = sourceLocale.split("-")[0]?.toLowerCase() ?? "";
42
+ return lang === "ar" || lang === "he" ? "rtl" : "ltr";
43
+ }
44
+ async function importMsgProjectForResource(projectsDir, projectName) {
45
+ const basePath = join(projectsDir, projectName);
46
+ const exts = [".ts", ".js"];
47
+ for (const ext of exts) {
48
+ const p = `${basePath}${ext}`;
49
+ if (existsSync(p)) {
50
+ try {
51
+ const url = pathToFileURL(p).href;
52
+ const mod = await dynamicImportFromUrl(url);
53
+ const data = mod?.default ?? mod;
54
+ const sourceLocale = data?.locales?.sourceLocale;
55
+ if (!sourceLocale || typeof sourceLocale !== "string") {
56
+ throw new Error(
57
+ `Project file must export a default with locales.sourceLocale (got ${typeof data?.locales?.sourceLocale}).`
58
+ );
59
+ }
60
+ return {
61
+ sourceLocale,
62
+ dir: dirFromSourceLocale(sourceLocale)
63
+ };
64
+ } catch (err) {
65
+ const message = err instanceof Error ? err.message : String(err);
66
+ throw new Error(
67
+ `Project file '${projectName}${ext}' could not be loaded: ${message}`
68
+ );
69
+ }
70
+ }
71
+ }
72
+ return void 0;
73
+ }
74
+ function generateMsgResourceContent(params) {
75
+ const { title, projectName, sourceLocale, dir, isEsm } = params;
76
+ const projectImport = isEsm ? `../projects/${projectName}.js` : `../projects/${projectName}`;
77
+ const messagesBlock = ` messages: [
78
+ {
79
+ key: 'example.message',
80
+ value: 'Example message.',
81
+ notes: [
82
+ { type: 'description', content: 'This is an example message. You can delete it.' }
83
+ ]
84
+ }
85
+ ]`;
86
+ const titleStr = `'${title.replace(/'/g, "\\'")}'`;
87
+ const langStr = `'${sourceLocale.replace(/'/g, "\\'")}'`;
88
+ const dirStr = `'${dir}'`;
89
+ if (isEsm) {
90
+ return `import { MsgResource } from '@worldware/msg';
91
+ import project from '${projectImport}';
92
+
93
+ export default MsgResource.create({
94
+ title: ${titleStr},
95
+ attributes: {
96
+ lang: ${langStr},
97
+ dir: ${dirStr}
98
+ },
99
+ notes: [
100
+ { type: 'DESCRIPTION', content: 'This is a generated file. Replace this description with your own.' }
101
+ ],
102
+ ${messagesBlock}
103
+ }, project);
104
+ `;
105
+ }
106
+ return `const { MsgResource } = require('@worldware/msg');
107
+ const project = require('${projectImport}');
108
+
109
+ module.exports = MsgResource.create({
110
+ title: ${titleStr},
111
+ attributes: {
112
+ lang: ${langStr},
113
+ dir: ${dirStr}
114
+ },
115
+ notes: [
116
+ { type: 'DESCRIPTION', content: 'This is a generated file. Replace this description with your own.' }
117
+ ],
118
+ ${messagesBlock}
119
+ }, project);
120
+ `;
121
+ }
122
+ function writeMsgResourceFile(filePath, content) {
123
+ const dir = dirname(filePath);
124
+ if (!existsSync(dir)) {
125
+ mkdirSync(dir, { recursive: true });
126
+ }
127
+ writeFileSync(filePath, content, "utf-8");
128
+ }
129
+
130
+ export {
131
+ dynamicImportFromUrl,
132
+ readPackageJsonForCreateResource,
133
+ importMsgProjectForResource,
134
+ generateMsgResourceContent,
135
+ writeMsgResourceFile
136
+ };
@@ -0,0 +1,293 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/commands/create/project.ts
21
+ var project_exports = {};
22
+ __export(project_exports, {
23
+ default: () => CreateProject
24
+ });
25
+ module.exports = __toCommonJS(project_exports);
26
+ var import_core = require("@oclif/core");
27
+ var import_fs3 = require("fs");
28
+ var import_path3 = require("path");
29
+
30
+ // src/lib/create-project-helpers.ts
31
+ var import_fs2 = require("fs");
32
+ var import_path2 = require("path");
33
+ var import_url2 = require("url");
34
+
35
+ // src/lib/create-resource-helpers.ts
36
+ var import_module = require("module");
37
+ var import_url = require("url");
38
+
39
+ // src/lib/init-helpers.ts
40
+ var import_fs = require("fs");
41
+ var import_path = require("path");
42
+ function findPackageJsonPath(cwd) {
43
+ let dir = cwd;
44
+ for (; ; ) {
45
+ const p = (0, import_path.join)(dir, "package.json");
46
+ if ((0, import_fs.existsSync)(p)) return p;
47
+ const parent = (0, import_path.dirname)(dir);
48
+ if (parent === dir) return null;
49
+ dir = parent;
50
+ }
51
+ }
52
+ function readPackageJson(pkgPath) {
53
+ const raw = (0, import_fs.readFileSync)(pkgPath, "utf-8");
54
+ try {
55
+ const parsed = JSON.parse(raw);
56
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
57
+ throw new Error("package.json must be a JSON object");
58
+ }
59
+ return parsed;
60
+ } catch (err) {
61
+ if (err instanceof SyntaxError) {
62
+ throw new Error("Invalid package.json: " + err.message);
63
+ }
64
+ throw err;
65
+ }
66
+ }
67
+ function loadPackageJsonForMsg(cwd, options) {
68
+ const pkgPath = findPackageJsonPath(cwd);
69
+ if (!pkgPath) {
70
+ throw new Error("package.json not found. Run this command from the project root.");
71
+ }
72
+ let pkg;
73
+ try {
74
+ pkg = readPackageJson(pkgPath);
75
+ } catch (err) {
76
+ const msg = err instanceof Error ? err.message : "package.json could not be parsed.";
77
+ throw new Error(msg);
78
+ }
79
+ const dirs = pkg.directories;
80
+ if (!dirs || typeof dirs !== "object" || !dirs.i18n) {
81
+ throw new Error("package.json must contain directories.i18n. Run 'msg init' first.");
82
+ }
83
+ if (options?.requireL10n && !dirs.l10n) {
84
+ throw new Error(
85
+ "package.json must contain directories.i18n and directories.l10n. Run 'msg init' first."
86
+ );
87
+ }
88
+ const rootDir = (0, import_path.dirname)(pkgPath);
89
+ const useTypeScript = (0, import_fs.existsSync)((0, import_path.join)(rootDir, "tsconfig.json"));
90
+ const isEsm = pkg.type === "module";
91
+ return {
92
+ pkgPath,
93
+ rootDir,
94
+ pkg,
95
+ i18nDir: dirs.i18n,
96
+ l10nDir: dirs.l10n,
97
+ isEsm,
98
+ useTypeScript
99
+ };
100
+ }
101
+
102
+ // src/lib/create-resource-helpers.ts
103
+ async function dynamicImportFromUrl(url) {
104
+ try {
105
+ return await import(
106
+ /* @vite-ignore */
107
+ url
108
+ );
109
+ } catch (err) {
110
+ const msg = err instanceof Error ? err.message : String(err);
111
+ const useRequire = msg.includes("dynamic import callback") || msg.includes("ERR_VM_DYNAMIC_IMPORT");
112
+ if (useRequire) {
113
+ try {
114
+ const path = url.startsWith("file:") ? (0, import_url.fileURLToPath)(url) : url;
115
+ const base = (0, import_url.pathToFileURL)(process.cwd()).href;
116
+ const req = (0, import_module.createRequire)(base);
117
+ const mod = req(path);
118
+ return Promise.resolve(mod ?? {});
119
+ } catch {
120
+ }
121
+ }
122
+ throw err;
123
+ }
124
+ }
125
+
126
+ // src/lib/create-project-helpers.ts
127
+ function calculateRelativePath(projectsDir, translationsDir) {
128
+ const rel = (0, import_path2.relative)(projectsDir, translationsDir);
129
+ return rel.startsWith(".") ? rel : `./${rel}`;
130
+ }
131
+ async function importMsgProjectFile(projectsDir, projectName) {
132
+ const basePath = (0, import_path2.join)(projectsDir, projectName);
133
+ const exts = [".ts", ".js"];
134
+ for (const ext of exts) {
135
+ const p = `${basePath}${ext}`;
136
+ if ((0, import_fs2.existsSync)(p)) {
137
+ try {
138
+ const url = (0, import_url2.pathToFileURL)(p).href;
139
+ const mod = await dynamicImportFromUrl(url);
140
+ return mod?.default ?? mod;
141
+ } catch {
142
+ return void 0;
143
+ }
144
+ }
145
+ }
146
+ return void 0;
147
+ }
148
+ function writeMsgProjectFile(filePath, content) {
149
+ const dir = (0, import_path2.dirname)(filePath);
150
+ if (!(0, import_fs2.existsSync)(dir)) {
151
+ (0, import_fs2.mkdirSync)(dir, { recursive: true });
152
+ }
153
+ (0, import_fs2.writeFileSync)(filePath, content, "utf-8");
154
+ }
155
+ function loadPackageJsonForCreateProject(cwd) {
156
+ const ctx = loadPackageJsonForMsg(cwd, { requireL10n: true });
157
+ return ctx.pkg;
158
+ }
159
+
160
+ // src/commands/create/project.ts
161
+ var CreateProject = class _CreateProject extends import_core.Command {
162
+ static description = "Create a new MsgProject file in the projects directory (i18n/projects)";
163
+ static strict = false;
164
+ static args = {
165
+ projectName: import_core.Args.string({
166
+ required: false,
167
+ description: "Name of the project (used as file name)"
168
+ }),
169
+ source: import_core.Args.string({
170
+ required: false,
171
+ description: "Source locale for the project"
172
+ }),
173
+ targets: import_core.Args.string({
174
+ required: false,
175
+ description: "Target locale(s) (variadic)"
176
+ })
177
+ };
178
+ static flags = {
179
+ help: import_core.Flags.help({ char: "h" }),
180
+ extend: import_core.Flags.string({
181
+ char: "e",
182
+ description: "Extend an existing project"
183
+ })
184
+ };
185
+ async run() {
186
+ const { argv, flags } = await this.parse(_CreateProject);
187
+ const [projectName, source, ...targets] = argv;
188
+ if (!projectName?.trim()) {
189
+ this.error("projectName is required.", { exit: 1 });
190
+ }
191
+ if (!source?.trim()) {
192
+ this.error("source locale is required.", { exit: 1 });
193
+ }
194
+ if (!targets?.length || targets.every((t) => !t?.trim())) {
195
+ this.error("At least one target locale is required.", { exit: 1 });
196
+ }
197
+ const cwd = process.cwd();
198
+ const pkgPath = findPackageJsonPath(cwd);
199
+ if (!pkgPath) {
200
+ this.error("package.json not found. Run this command from the project root.", { exit: 1 });
201
+ }
202
+ let pkg;
203
+ try {
204
+ pkg = loadPackageJsonForCreateProject(cwd);
205
+ } catch (err) {
206
+ const msg = err instanceof Error ? err.message : String(err);
207
+ this.error(msg, { exit: 1 });
208
+ }
209
+ const rootDir = (0, import_path3.join)(pkgPath, "..");
210
+ const i18nDir = pkg.directories.i18n;
211
+ const l10nDir = pkg.directories.l10n;
212
+ const projectsDir = (0, import_path3.join)(rootDir, i18nDir, "projects");
213
+ const translationsDir = (0, import_path3.join)(rootDir, l10nDir, "translations");
214
+ const relPath = calculateRelativePath(projectsDir, translationsDir);
215
+ const useTypeScript = (0, import_fs3.existsSync)((0, import_path3.join)(rootDir, "tsconfig.json"));
216
+ const isEsm = pkg.type === "module";
217
+ const ext = useTypeScript ? ".ts" : ".js";
218
+ const outPath = (0, import_path3.join)(projectsDir, `${projectName}${ext}`);
219
+ if ((0, import_fs3.existsSync)(outPath)) {
220
+ this.error(`A project with the name '${projectName}' already exists.`, { exit: 1 });
221
+ }
222
+ let targetLocales = {};
223
+ let pseudoLocale = "en-XA";
224
+ if (flags.extend) {
225
+ const base = await importMsgProjectFile(projectsDir, flags.extend);
226
+ if (!base) {
227
+ this.error(`Project '${flags.extend}' could not be found to extend.`, { exit: 1 });
228
+ }
229
+ if (base.locales?.targetLocales && typeof base.locales.targetLocales === "object") {
230
+ targetLocales = { ...base.locales.targetLocales };
231
+ }
232
+ if (base.locales?.pseudoLocale) {
233
+ pseudoLocale = base.locales.pseudoLocale;
234
+ }
235
+ }
236
+ targetLocales[source] = [source];
237
+ for (const t of targets) {
238
+ if (t?.trim()) targetLocales[t.trim()] = [t.trim()];
239
+ }
240
+ const loaderPathLine = "const path = `${TRANSLATION_IMPORT_PATH}/${project}/${language}/${title}.json`;";
241
+ const loaderWarnLine = "console.warn(`Translations for locale ${language} could not be loaded.`, error);";
242
+ const loaderBody = `${loaderPathLine}
243
+ try {
244
+ const module = await import(path, { with: { type: 'json' } });
245
+ return module.default;
246
+ } catch (error) {
247
+ ${loaderWarnLine}
248
+ return {
249
+ title,
250
+ attributes: { lang: language, dir: '' },
251
+ notes: [],
252
+ messages: []
253
+ };
254
+ }`;
255
+ const importPath = relPath.replace(/\\/g, "/");
256
+ const content = isEsm ? `import { MsgProject } from '@worldware/msg';
257
+
258
+ const TRANSLATION_IMPORT_PATH = ${JSON.stringify(importPath)};
259
+ const loader = async (project, title, language) => {
260
+ ${loaderBody}
261
+ };
262
+
263
+ export default MsgProject.create({
264
+ project: { name: ${JSON.stringify(projectName)}, version: 1 },
265
+ locales: {
266
+ sourceLocale: ${JSON.stringify(source)},
267
+ pseudoLocale: ${JSON.stringify(pseudoLocale)},
268
+ targetLocales: ${JSON.stringify(targetLocales)}
269
+ },
270
+ loader
271
+ });
272
+ ` : `const { MsgProject } = require('@worldware/msg');
273
+
274
+ const TRANSLATION_IMPORT_PATH = ${JSON.stringify(importPath)};
275
+ const loader = async (project, title, language) => {
276
+ ${loaderBody}
277
+ };
278
+
279
+ module.exports = MsgProject.create({
280
+ project: { name: ${JSON.stringify(projectName)}, version: 1 },
281
+ locales: {
282
+ sourceLocale: ${JSON.stringify(source)},
283
+ pseudoLocale: ${JSON.stringify(pseudoLocale)},
284
+ targetLocales: ${JSON.stringify(targetLocales)}
285
+ },
286
+ loader
287
+ });
288
+ `;
289
+ this.log("Creating MsgProject file...");
290
+ writeMsgProjectFile(outPath, content);
291
+ this.log(`Created ${outPath}`);
292
+ }
293
+ };
@@ -0,0 +1,22 @@
1
+ import * as _oclif_core_lib_interfaces_parser_js from '@oclif/core/lib/interfaces/parser.js';
2
+ import { Command } from '@oclif/core';
3
+
4
+ /**
5
+ * Creates a new MsgProject file in the i18n projects directory.
6
+ */
7
+ declare class CreateProject extends Command {
8
+ static description: string;
9
+ static strict: boolean;
10
+ static args: {
11
+ projectName: _oclif_core_lib_interfaces_parser_js.Arg<string | undefined, Record<string, unknown>>;
12
+ source: _oclif_core_lib_interfaces_parser_js.Arg<string | undefined, Record<string, unknown>>;
13
+ targets: _oclif_core_lib_interfaces_parser_js.Arg<string | undefined, Record<string, unknown>>;
14
+ };
15
+ static flags: {
16
+ help: _oclif_core_lib_interfaces_parser_js.BooleanFlag<void>;
17
+ extend: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
18
+ };
19
+ run(): Promise<void>;
20
+ }
21
+
22
+ export { CreateProject as default };
@@ -0,0 +1,22 @@
1
+ import * as _oclif_core_lib_interfaces_parser_js from '@oclif/core/lib/interfaces/parser.js';
2
+ import { Command } from '@oclif/core';
3
+
4
+ /**
5
+ * Creates a new MsgProject file in the i18n projects directory.
6
+ */
7
+ declare class CreateProject extends Command {
8
+ static description: string;
9
+ static strict: boolean;
10
+ static args: {
11
+ projectName: _oclif_core_lib_interfaces_parser_js.Arg<string | undefined, Record<string, unknown>>;
12
+ source: _oclif_core_lib_interfaces_parser_js.Arg<string | undefined, Record<string, unknown>>;
13
+ targets: _oclif_core_lib_interfaces_parser_js.Arg<string | undefined, Record<string, unknown>>;
14
+ };
15
+ static flags: {
16
+ help: _oclif_core_lib_interfaces_parser_js.BooleanFlag<void>;
17
+ extend: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
18
+ };
19
+ run(): Promise<void>;
20
+ }
21
+
22
+ export { CreateProject as default };