@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,151 @@
1
+ import {
2
+ calculateRelativePath,
3
+ importMsgProjectFile,
4
+ loadPackageJsonForCreateProject,
5
+ writeMsgProjectFile
6
+ } from "../../chunk-4Q2252JQ.mjs";
7
+ import "../../chunk-KKYCVD5M.mjs";
8
+ import {
9
+ findPackageJsonPath
10
+ } from "../../chunk-DBC2Y6VQ.mjs";
11
+
12
+ // src/commands/create/project.ts
13
+ import { Args, Command, Flags } from "@oclif/core";
14
+ import { existsSync } from "fs";
15
+ import { join } from "path";
16
+ var CreateProject = class _CreateProject extends Command {
17
+ static description = "Create a new MsgProject file in the projects directory (i18n/projects)";
18
+ static strict = false;
19
+ static args = {
20
+ projectName: Args.string({
21
+ required: false,
22
+ description: "Name of the project (used as file name)"
23
+ }),
24
+ source: Args.string({
25
+ required: false,
26
+ description: "Source locale for the project"
27
+ }),
28
+ targets: Args.string({
29
+ required: false,
30
+ description: "Target locale(s) (variadic)"
31
+ })
32
+ };
33
+ static flags = {
34
+ help: Flags.help({ char: "h" }),
35
+ extend: Flags.string({
36
+ char: "e",
37
+ description: "Extend an existing project"
38
+ })
39
+ };
40
+ async run() {
41
+ const { argv, flags } = await this.parse(_CreateProject);
42
+ const [projectName, source, ...targets] = argv;
43
+ if (!projectName?.trim()) {
44
+ this.error("projectName is required.", { exit: 1 });
45
+ }
46
+ if (!source?.trim()) {
47
+ this.error("source locale is required.", { exit: 1 });
48
+ }
49
+ if (!targets?.length || targets.every((t) => !t?.trim())) {
50
+ this.error("At least one target locale is required.", { exit: 1 });
51
+ }
52
+ const cwd = process.cwd();
53
+ const pkgPath = findPackageJsonPath(cwd);
54
+ if (!pkgPath) {
55
+ this.error("package.json not found. Run this command from the project root.", { exit: 1 });
56
+ }
57
+ let pkg;
58
+ try {
59
+ pkg = loadPackageJsonForCreateProject(cwd);
60
+ } catch (err) {
61
+ const msg = err instanceof Error ? err.message : String(err);
62
+ this.error(msg, { exit: 1 });
63
+ }
64
+ const rootDir = join(pkgPath, "..");
65
+ const i18nDir = pkg.directories.i18n;
66
+ const l10nDir = pkg.directories.l10n;
67
+ const projectsDir = join(rootDir, i18nDir, "projects");
68
+ const translationsDir = join(rootDir, l10nDir, "translations");
69
+ const relPath = calculateRelativePath(projectsDir, translationsDir);
70
+ const useTypeScript = existsSync(join(rootDir, "tsconfig.json"));
71
+ const isEsm = pkg.type === "module";
72
+ const ext = useTypeScript ? ".ts" : ".js";
73
+ const outPath = join(projectsDir, `${projectName}${ext}`);
74
+ if (existsSync(outPath)) {
75
+ this.error(`A project with the name '${projectName}' already exists.`, { exit: 1 });
76
+ }
77
+ let targetLocales = {};
78
+ let pseudoLocale = "en-XA";
79
+ if (flags.extend) {
80
+ const base = await importMsgProjectFile(projectsDir, flags.extend);
81
+ if (!base) {
82
+ this.error(`Project '${flags.extend}' could not be found to extend.`, { exit: 1 });
83
+ }
84
+ if (base.locales?.targetLocales && typeof base.locales.targetLocales === "object") {
85
+ targetLocales = { ...base.locales.targetLocales };
86
+ }
87
+ if (base.locales?.pseudoLocale) {
88
+ pseudoLocale = base.locales.pseudoLocale;
89
+ }
90
+ }
91
+ targetLocales[source] = [source];
92
+ for (const t of targets) {
93
+ if (t?.trim()) targetLocales[t.trim()] = [t.trim()];
94
+ }
95
+ const loaderPathLine = "const path = `${TRANSLATION_IMPORT_PATH}/${project}/${language}/${title}.json`;";
96
+ const loaderWarnLine = "console.warn(`Translations for locale ${language} could not be loaded.`, error);";
97
+ const loaderBody = `${loaderPathLine}
98
+ try {
99
+ const module = await import(path, { with: { type: 'json' } });
100
+ return module.default;
101
+ } catch (error) {
102
+ ${loaderWarnLine}
103
+ return {
104
+ title,
105
+ attributes: { lang: language, dir: '' },
106
+ notes: [],
107
+ messages: []
108
+ };
109
+ }`;
110
+ const importPath = relPath.replace(/\\/g, "/");
111
+ const content = isEsm ? `import { MsgProject } from '@worldware/msg';
112
+
113
+ const TRANSLATION_IMPORT_PATH = ${JSON.stringify(importPath)};
114
+ const loader = async (project, title, language) => {
115
+ ${loaderBody}
116
+ };
117
+
118
+ export default MsgProject.create({
119
+ project: { name: ${JSON.stringify(projectName)}, version: 1 },
120
+ locales: {
121
+ sourceLocale: ${JSON.stringify(source)},
122
+ pseudoLocale: ${JSON.stringify(pseudoLocale)},
123
+ targetLocales: ${JSON.stringify(targetLocales)}
124
+ },
125
+ loader
126
+ });
127
+ ` : `const { MsgProject } = require('@worldware/msg');
128
+
129
+ const TRANSLATION_IMPORT_PATH = ${JSON.stringify(importPath)};
130
+ const loader = async (project, title, language) => {
131
+ ${loaderBody}
132
+ };
133
+
134
+ module.exports = MsgProject.create({
135
+ project: { name: ${JSON.stringify(projectName)}, version: 1 },
136
+ locales: {
137
+ sourceLocale: ${JSON.stringify(source)},
138
+ pseudoLocale: ${JSON.stringify(pseudoLocale)},
139
+ targetLocales: ${JSON.stringify(targetLocales)}
140
+ },
141
+ loader
142
+ });
143
+ `;
144
+ this.log("Creating MsgProject file...");
145
+ writeMsgProjectFile(outPath, content);
146
+ this.log(`Created ${outPath}`);
147
+ }
148
+ };
149
+ export {
150
+ CreateProject as default
151
+ };
@@ -0,0 +1,355 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/commands/create/resource.ts
31
+ var resource_exports = {};
32
+ __export(resource_exports, {
33
+ default: () => CreateResource
34
+ });
35
+ module.exports = __toCommonJS(resource_exports);
36
+ var import_core = require("@oclif/core");
37
+ var import_fs3 = require("fs");
38
+ var import_path3 = require("path");
39
+ var import_url2 = require("url");
40
+
41
+ // src/lib/create-resource-helpers.ts
42
+ var import_fs2 = require("fs");
43
+ var import_module = require("module");
44
+ var import_path2 = require("path");
45
+ var import_url = require("url");
46
+
47
+ // src/lib/init-helpers.ts
48
+ var import_fs = require("fs");
49
+ var import_path = require("path");
50
+ function findPackageJsonPath(cwd) {
51
+ let dir = cwd;
52
+ for (; ; ) {
53
+ const p = (0, import_path.join)(dir, "package.json");
54
+ if ((0, import_fs.existsSync)(p)) return p;
55
+ const parent = (0, import_path.dirname)(dir);
56
+ if (parent === dir) return null;
57
+ dir = parent;
58
+ }
59
+ }
60
+ function readPackageJson(pkgPath) {
61
+ const raw = (0, import_fs.readFileSync)(pkgPath, "utf-8");
62
+ try {
63
+ const parsed = JSON.parse(raw);
64
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
65
+ throw new Error("package.json must be a JSON object");
66
+ }
67
+ return parsed;
68
+ } catch (err) {
69
+ if (err instanceof SyntaxError) {
70
+ throw new Error("Invalid package.json: " + err.message);
71
+ }
72
+ throw err;
73
+ }
74
+ }
75
+ function loadPackageJsonForMsg(cwd, options) {
76
+ const pkgPath = findPackageJsonPath(cwd);
77
+ if (!pkgPath) {
78
+ throw new Error("package.json not found. Run this command from the project root.");
79
+ }
80
+ let pkg;
81
+ try {
82
+ pkg = readPackageJson(pkgPath);
83
+ } catch (err) {
84
+ const msg = err instanceof Error ? err.message : "package.json could not be parsed.";
85
+ throw new Error(msg);
86
+ }
87
+ const dirs = pkg.directories;
88
+ if (!dirs || typeof dirs !== "object" || !dirs.i18n) {
89
+ throw new Error("package.json must contain directories.i18n. Run 'msg init' first.");
90
+ }
91
+ if (options?.requireL10n && !dirs.l10n) {
92
+ throw new Error(
93
+ "package.json must contain directories.i18n and directories.l10n. Run 'msg init' first."
94
+ );
95
+ }
96
+ const rootDir = (0, import_path.dirname)(pkgPath);
97
+ const useTypeScript = (0, import_fs.existsSync)((0, import_path.join)(rootDir, "tsconfig.json"));
98
+ const isEsm = pkg.type === "module";
99
+ return {
100
+ pkgPath,
101
+ rootDir,
102
+ pkg,
103
+ i18nDir: dirs.i18n,
104
+ l10nDir: dirs.l10n,
105
+ isEsm,
106
+ useTypeScript
107
+ };
108
+ }
109
+
110
+ // src/lib/create-resource-helpers.ts
111
+ async function dynamicImportFromUrl(url) {
112
+ try {
113
+ return await import(
114
+ /* @vite-ignore */
115
+ url
116
+ );
117
+ } catch (err) {
118
+ const msg = err instanceof Error ? err.message : String(err);
119
+ const useRequire = msg.includes("dynamic import callback") || msg.includes("ERR_VM_DYNAMIC_IMPORT");
120
+ if (useRequire) {
121
+ try {
122
+ const path = url.startsWith("file:") ? (0, import_url.fileURLToPath)(url) : url;
123
+ const base = (0, import_url.pathToFileURL)(process.cwd()).href;
124
+ const req = (0, import_module.createRequire)(base);
125
+ const mod = req(path);
126
+ return Promise.resolve(mod ?? {});
127
+ } catch {
128
+ }
129
+ }
130
+ throw err;
131
+ }
132
+ }
133
+ function readPackageJsonForCreateResource(cwd) {
134
+ const ctx = loadPackageJsonForMsg(cwd);
135
+ return {
136
+ i18nDir: ctx.i18nDir,
137
+ isEsm: ctx.isEsm,
138
+ useTypeScript: ctx.useTypeScript
139
+ };
140
+ }
141
+ function dirFromSourceLocale(sourceLocale) {
142
+ const lang = sourceLocale.split("-")[0]?.toLowerCase() ?? "";
143
+ return lang === "ar" || lang === "he" ? "rtl" : "ltr";
144
+ }
145
+ async function importMsgProjectForResource(projectsDir, projectName) {
146
+ const basePath = (0, import_path2.join)(projectsDir, projectName);
147
+ const exts = [".ts", ".js"];
148
+ for (const ext of exts) {
149
+ const p = `${basePath}${ext}`;
150
+ if ((0, import_fs2.existsSync)(p)) {
151
+ try {
152
+ const url = (0, import_url.pathToFileURL)(p).href;
153
+ const mod = await dynamicImportFromUrl(url);
154
+ const data = mod?.default ?? mod;
155
+ const sourceLocale = data?.locales?.sourceLocale;
156
+ if (!sourceLocale || typeof sourceLocale !== "string") {
157
+ throw new Error(
158
+ `Project file must export a default with locales.sourceLocale (got ${typeof data?.locales?.sourceLocale}).`
159
+ );
160
+ }
161
+ return {
162
+ sourceLocale,
163
+ dir: dirFromSourceLocale(sourceLocale)
164
+ };
165
+ } catch (err) {
166
+ const message = err instanceof Error ? err.message : String(err);
167
+ throw new Error(
168
+ `Project file '${projectName}${ext}' could not be loaded: ${message}`
169
+ );
170
+ }
171
+ }
172
+ }
173
+ return void 0;
174
+ }
175
+ function generateMsgResourceContent(params) {
176
+ const { title, projectName, sourceLocale, dir, isEsm } = params;
177
+ const projectImport = isEsm ? `../projects/${projectName}.js` : `../projects/${projectName}`;
178
+ const messagesBlock = ` messages: [
179
+ {
180
+ key: 'example.message',
181
+ value: 'Example message.',
182
+ notes: [
183
+ { type: 'description', content: 'This is an example message. You can delete it.' }
184
+ ]
185
+ }
186
+ ]`;
187
+ const titleStr = `'${title.replace(/'/g, "\\'")}'`;
188
+ const langStr = `'${sourceLocale.replace(/'/g, "\\'")}'`;
189
+ const dirStr = `'${dir}'`;
190
+ if (isEsm) {
191
+ return `import { MsgResource } from '@worldware/msg';
192
+ import project from '${projectImport}';
193
+
194
+ export default MsgResource.create({
195
+ title: ${titleStr},
196
+ attributes: {
197
+ lang: ${langStr},
198
+ dir: ${dirStr}
199
+ },
200
+ notes: [
201
+ { type: 'DESCRIPTION', content: 'This is a generated file. Replace this description with your own.' }
202
+ ],
203
+ ${messagesBlock}
204
+ }, project);
205
+ `;
206
+ }
207
+ return `const { MsgResource } = require('@worldware/msg');
208
+ const project = require('${projectImport}');
209
+
210
+ module.exports = MsgResource.create({
211
+ title: ${titleStr},
212
+ attributes: {
213
+ lang: ${langStr},
214
+ dir: ${dirStr}
215
+ },
216
+ notes: [
217
+ { type: 'DESCRIPTION', content: 'This is a generated file. Replace this description with your own.' }
218
+ ],
219
+ ${messagesBlock}
220
+ }, project);
221
+ `;
222
+ }
223
+ function writeMsgResourceFile(filePath, content) {
224
+ const dir = (0, import_path2.dirname)(filePath);
225
+ if (!(0, import_fs2.existsSync)(dir)) {
226
+ (0, import_fs2.mkdirSync)(dir, { recursive: true });
227
+ }
228
+ (0, import_fs2.writeFileSync)(filePath, content, "utf-8");
229
+ }
230
+
231
+ // src/commands/create/resource.ts
232
+ var CreateResource = class _CreateResource extends import_core.Command {
233
+ static description = "Create a new MsgResource file in the resources directory (i18n/resources)";
234
+ static strict = false;
235
+ static args = {
236
+ projectName: import_core.Args.string({
237
+ required: false,
238
+ description: "Name of the project to import in the MsgResource file"
239
+ }),
240
+ title: import_core.Args.string({
241
+ required: false,
242
+ description: "Title of the resource and file name for the file"
243
+ })
244
+ };
245
+ static flags = {
246
+ help: import_core.Flags.help({ char: "h" }),
247
+ force: import_core.Flags.boolean({
248
+ char: "f",
249
+ description: "Overwrite an existing resource file"
250
+ }),
251
+ edit: import_core.Flags.boolean({
252
+ char: "e",
253
+ description: "Open the file for editing after creation"
254
+ })
255
+ };
256
+ async run() {
257
+ const { argv, flags } = await this.parse(_CreateResource);
258
+ const [projectName, title] = argv;
259
+ if (!projectName?.trim()) {
260
+ this.error("projectName is required. Run 'msg init' first if you have not.", {
261
+ exit: 1
262
+ });
263
+ }
264
+ if (!title?.trim()) {
265
+ this.error("title is required.", { exit: 1 });
266
+ }
267
+ const cwd = process.cwd();
268
+ const pkgPath = findPackageJsonPath(cwd);
269
+ if (!pkgPath) {
270
+ this.error("package.json not found. Run this command from the project root.", {
271
+ exit: 1
272
+ });
273
+ }
274
+ let pkgInfo;
275
+ try {
276
+ pkgInfo = readPackageJsonForCreateResource(cwd);
277
+ } catch (err) {
278
+ const msg = err instanceof Error ? err.message : String(err);
279
+ this.error(msg, { exit: 1 });
280
+ }
281
+ const rootDir = (0, import_path3.join)(pkgPath, "..");
282
+ const i18nDir = (0, import_path3.join)(rootDir, pkgInfo.i18nDir);
283
+ const projectsDir = (0, import_path3.join)(i18nDir, "projects");
284
+ const resourcesDir = (0, import_path3.join)(i18nDir, "resources");
285
+ if (!(0, import_fs3.existsSync)(i18nDir)) {
286
+ this.error(
287
+ `i18n directory '${pkgInfo.i18nDir}' does not exist. Run 'msg init' first.`,
288
+ { exit: 1 }
289
+ );
290
+ }
291
+ if (!(0, import_fs3.existsSync)(projectsDir)) {
292
+ this.error(
293
+ `i18n/projects directory does not exist. Run 'msg init' first.`,
294
+ { exit: 1 }
295
+ );
296
+ }
297
+ if (!(0, import_fs3.existsSync)(resourcesDir)) {
298
+ this.error(
299
+ `i18n/resources directory does not exist. Run 'msg init' first.`,
300
+ { exit: 1 }
301
+ );
302
+ }
303
+ const projectData = await importMsgProjectForResource(projectsDir, projectName.trim());
304
+ if (!projectData) {
305
+ this.error(
306
+ `Project '${projectName}' not found or could not be loaded. Check i18n/projects for a matching file.`,
307
+ { exit: 1 }
308
+ );
309
+ }
310
+ const ext = pkgInfo.useTypeScript ? ".ts" : ".js";
311
+ const outPath = (0, import_path3.join)(resourcesDir, `${title.trim()}.msg${ext}`);
312
+ if ((0, import_fs3.existsSync)(outPath) && !flags.force) {
313
+ this.error(
314
+ `Resource file '${title.trim()}.msg${ext}' already exists. Use -f or --force to overwrite.`,
315
+ { exit: 1 }
316
+ );
317
+ }
318
+ const content = generateMsgResourceContent({
319
+ title: title.trim(),
320
+ projectName: projectName.trim(),
321
+ sourceLocale: projectData.sourceLocale,
322
+ dir: projectData.dir,
323
+ isEsm: pkgInfo.isEsm
324
+ });
325
+ try {
326
+ writeMsgResourceFile(outPath, content);
327
+ } catch (err) {
328
+ const msg = err instanceof Error ? err.message : String(err);
329
+ this.error(`Could not generate resource file: ${msg}`, { exit: 1 });
330
+ }
331
+ if (process.env.VITEST !== "true") {
332
+ try {
333
+ const url = (0, import_url2.pathToFileURL)(outPath).href;
334
+ await dynamicImportFromUrl(url);
335
+ } catch (err) {
336
+ try {
337
+ (0, import_fs3.unlinkSync)(outPath);
338
+ } catch {
339
+ }
340
+ const msg = err instanceof Error ? err.message : String(err);
341
+ this.error(`Generated file is invalid or not importable: ${msg}`, { exit: 1 });
342
+ }
343
+ }
344
+ this.log(`Created ${outPath}`);
345
+ if (flags.edit) {
346
+ const editor = process.env.VISUAL || process.env.EDITOR;
347
+ if (editor) {
348
+ const { spawn } = await import("child_process");
349
+ spawn(editor, [outPath], { stdio: "inherit", detached: true });
350
+ } else {
351
+ this.warn("EDITOR or VISUAL not set. Open the file manually.");
352
+ }
353
+ }
354
+ }
355
+ };
@@ -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 MsgResource file in the i18n resources directory.
6
+ */
7
+ declare class CreateResource 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
+ title: _oclif_core_lib_interfaces_parser_js.Arg<string | undefined, Record<string, unknown>>;
13
+ };
14
+ static flags: {
15
+ help: _oclif_core_lib_interfaces_parser_js.BooleanFlag<void>;
16
+ force: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
17
+ edit: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
18
+ };
19
+ run(): Promise<void>;
20
+ }
21
+
22
+ export { CreateResource 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 MsgResource file in the i18n resources directory.
6
+ */
7
+ declare class CreateResource 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
+ title: _oclif_core_lib_interfaces_parser_js.Arg<string | undefined, Record<string, unknown>>;
13
+ };
14
+ static flags: {
15
+ help: _oclif_core_lib_interfaces_parser_js.BooleanFlag<void>;
16
+ force: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
17
+ edit: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
18
+ };
19
+ run(): Promise<void>;
20
+ }
21
+
22
+ export { CreateResource as default };
@@ -0,0 +1,143 @@
1
+ import {
2
+ dynamicImportFromUrl,
3
+ generateMsgResourceContent,
4
+ importMsgProjectForResource,
5
+ readPackageJsonForCreateResource,
6
+ writeMsgResourceFile
7
+ } from "../../chunk-KKYCVD5M.mjs";
8
+ import {
9
+ findPackageJsonPath
10
+ } from "../../chunk-DBC2Y6VQ.mjs";
11
+
12
+ // src/commands/create/resource.ts
13
+ import { Args, Command, Flags } from "@oclif/core";
14
+ import { existsSync, unlinkSync } from "fs";
15
+ import { join } from "path";
16
+ import { pathToFileURL } from "url";
17
+ var CreateResource = class _CreateResource extends Command {
18
+ static description = "Create a new MsgResource file in the resources directory (i18n/resources)";
19
+ static strict = false;
20
+ static args = {
21
+ projectName: Args.string({
22
+ required: false,
23
+ description: "Name of the project to import in the MsgResource file"
24
+ }),
25
+ title: Args.string({
26
+ required: false,
27
+ description: "Title of the resource and file name for the file"
28
+ })
29
+ };
30
+ static flags = {
31
+ help: Flags.help({ char: "h" }),
32
+ force: Flags.boolean({
33
+ char: "f",
34
+ description: "Overwrite an existing resource file"
35
+ }),
36
+ edit: Flags.boolean({
37
+ char: "e",
38
+ description: "Open the file for editing after creation"
39
+ })
40
+ };
41
+ async run() {
42
+ const { argv, flags } = await this.parse(_CreateResource);
43
+ const [projectName, title] = argv;
44
+ if (!projectName?.trim()) {
45
+ this.error("projectName is required. Run 'msg init' first if you have not.", {
46
+ exit: 1
47
+ });
48
+ }
49
+ if (!title?.trim()) {
50
+ this.error("title is required.", { exit: 1 });
51
+ }
52
+ const cwd = process.cwd();
53
+ const pkgPath = findPackageJsonPath(cwd);
54
+ if (!pkgPath) {
55
+ this.error("package.json not found. Run this command from the project root.", {
56
+ exit: 1
57
+ });
58
+ }
59
+ let pkgInfo;
60
+ try {
61
+ pkgInfo = readPackageJsonForCreateResource(cwd);
62
+ } catch (err) {
63
+ const msg = err instanceof Error ? err.message : String(err);
64
+ this.error(msg, { exit: 1 });
65
+ }
66
+ const rootDir = join(pkgPath, "..");
67
+ const i18nDir = join(rootDir, pkgInfo.i18nDir);
68
+ const projectsDir = join(i18nDir, "projects");
69
+ const resourcesDir = join(i18nDir, "resources");
70
+ if (!existsSync(i18nDir)) {
71
+ this.error(
72
+ `i18n directory '${pkgInfo.i18nDir}' does not exist. Run 'msg init' first.`,
73
+ { exit: 1 }
74
+ );
75
+ }
76
+ if (!existsSync(projectsDir)) {
77
+ this.error(
78
+ `i18n/projects directory does not exist. Run 'msg init' first.`,
79
+ { exit: 1 }
80
+ );
81
+ }
82
+ if (!existsSync(resourcesDir)) {
83
+ this.error(
84
+ `i18n/resources directory does not exist. Run 'msg init' first.`,
85
+ { exit: 1 }
86
+ );
87
+ }
88
+ const projectData = await importMsgProjectForResource(projectsDir, projectName.trim());
89
+ if (!projectData) {
90
+ this.error(
91
+ `Project '${projectName}' not found or could not be loaded. Check i18n/projects for a matching file.`,
92
+ { exit: 1 }
93
+ );
94
+ }
95
+ const ext = pkgInfo.useTypeScript ? ".ts" : ".js";
96
+ const outPath = join(resourcesDir, `${title.trim()}.msg${ext}`);
97
+ if (existsSync(outPath) && !flags.force) {
98
+ this.error(
99
+ `Resource file '${title.trim()}.msg${ext}' already exists. Use -f or --force to overwrite.`,
100
+ { exit: 1 }
101
+ );
102
+ }
103
+ const content = generateMsgResourceContent({
104
+ title: title.trim(),
105
+ projectName: projectName.trim(),
106
+ sourceLocale: projectData.sourceLocale,
107
+ dir: projectData.dir,
108
+ isEsm: pkgInfo.isEsm
109
+ });
110
+ try {
111
+ writeMsgResourceFile(outPath, content);
112
+ } catch (err) {
113
+ const msg = err instanceof Error ? err.message : String(err);
114
+ this.error(`Could not generate resource file: ${msg}`, { exit: 1 });
115
+ }
116
+ if (process.env.VITEST !== "true") {
117
+ try {
118
+ const url = pathToFileURL(outPath).href;
119
+ await dynamicImportFromUrl(url);
120
+ } catch (err) {
121
+ try {
122
+ unlinkSync(outPath);
123
+ } catch {
124
+ }
125
+ const msg = err instanceof Error ? err.message : String(err);
126
+ this.error(`Generated file is invalid or not importable: ${msg}`, { exit: 1 });
127
+ }
128
+ }
129
+ this.log(`Created ${outPath}`);
130
+ if (flags.edit) {
131
+ const editor = process.env.VISUAL || process.env.EDITOR;
132
+ if (editor) {
133
+ const { spawn } = await import("child_process");
134
+ spawn(editor, [outPath], { stdio: "inherit", detached: true });
135
+ } else {
136
+ this.warn("EDITOR or VISUAL not set. Open the file manually.");
137
+ }
138
+ }
139
+ }
140
+ };
141
+ export {
142
+ CreateResource as default
143
+ };