@worldware/msg-cli 0.0.5 → 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 -196
  38. package/dist/lib/init-helpers.js +0 -219
  39. package/dist/lib/utilities.js +0 -286
@@ -0,0 +1,172 @@
1
+ // src/lib/utilities.ts
2
+ import {
3
+ MsgResource
4
+ } from "@worldware/msg";
5
+ import { readdir, readFile, writeFile } from "fs/promises";
6
+ import { basename, extname, join } from "path";
7
+ import { pathToFileURL } from "url";
8
+ import { XMLParser } from "fast-xml-parser";
9
+ var MSG_PATTERN = /\.msg\.(ts|js)$/i;
10
+ async function findMsgResourceFiles(directory) {
11
+ const result = [];
12
+ const entries = await readdir(directory, { withFileTypes: true });
13
+ for (const entry of entries) {
14
+ const fullPath = join(directory, entry.name);
15
+ if (entry.isFile() && MSG_PATTERN.test(entry.name)) {
16
+ result.push(fullPath);
17
+ } else if (entry.isDirectory()) {
18
+ result.push(...await findMsgResourceFiles(fullPath));
19
+ }
20
+ }
21
+ return result;
22
+ }
23
+ async function importMsgResources(filePaths) {
24
+ const byProjectName = /* @__PURE__ */ new Map();
25
+ for (const filePath of filePaths) {
26
+ if (!MSG_PATTERN.test(filePath)) {
27
+ throw new Error(`File does not have .msg. in filename: ${filePath}`);
28
+ }
29
+ const url = pathToFileURL(filePath).href;
30
+ const mod = await import(url);
31
+ const resource = mod.default ?? mod.resource ?? mod.MsgResource;
32
+ if (!resource || !(resource instanceof MsgResource)) {
33
+ throw new Error(
34
+ `Failed to import MsgResource from ${filePath}: no valid export found`
35
+ );
36
+ }
37
+ const project = resource.getProject();
38
+ const projectName = project.project.name;
39
+ let group = byProjectName.get(projectName);
40
+ if (!group) {
41
+ group = { project, resources: [] };
42
+ byProjectName.set(projectName, group);
43
+ }
44
+ group.resources.push(resource);
45
+ }
46
+ const result = /* @__PURE__ */ new Map();
47
+ for (const { project, resources } of byProjectName.values()) {
48
+ result.set(project, resources);
49
+ }
50
+ return result;
51
+ }
52
+ async function resourcesToXliffString(resources) {
53
+ const byProject = /* @__PURE__ */ new Map();
54
+ for (const resource of resources) {
55
+ const project = resource.getProject();
56
+ let arr = byProject.get(project);
57
+ if (!arr) {
58
+ arr = [];
59
+ byProject.set(project, arr);
60
+ }
61
+ arr.push(resource);
62
+ }
63
+ const result = /* @__PURE__ */ new Map();
64
+ for (const [project, arr] of byProject) {
65
+ const xliff = serializeResourcesToXliff(arr);
66
+ result.set(project, xliff);
67
+ }
68
+ return result;
69
+ }
70
+ function serializeResourcesToXliff(resources) {
71
+ const xmlns = "urn:oasis:names:tc:xliff:document:1.2";
72
+ const parts = [
73
+ '<?xml version="1.0" encoding="UTF-8"?>',
74
+ `<xliff version="1.2" xmlns="${xmlns}">`
75
+ ];
76
+ for (const resource of resources) {
77
+ const orig = `${resource.title}.json`;
78
+ const sourceLang = resource.attributes.lang || "en";
79
+ const data = resource.getData(false);
80
+ parts.push(
81
+ ` <file original="${escapeXml(orig)}" source-language="${escapeXml(sourceLang)}" datatype="plaintext">`
82
+ );
83
+ parts.push(" <body>");
84
+ for (const msg of data.messages || []) {
85
+ const key = msg.key;
86
+ const value = msg.value;
87
+ const attrs = [`id="${escapeXml(key)}"`, `resname="${escapeXml(key)}"`];
88
+ parts.push(` <trans-unit ${attrs.join(" ")}>`);
89
+ parts.push(` <source>${escapeXml(value)}</source>`);
90
+ parts.push(` </trans-unit>`);
91
+ }
92
+ parts.push(" </body>");
93
+ parts.push(" </file>");
94
+ }
95
+ parts.push("</xliff>");
96
+ return parts.join("\n");
97
+ }
98
+ function escapeXml(s) {
99
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
100
+ }
101
+ async function writeXliff(filePath, xliff) {
102
+ await writeFile(filePath, xliff, "utf-8");
103
+ }
104
+ async function readXliff(filePath) {
105
+ return readFile(filePath, "utf-8");
106
+ }
107
+ var xmlParser = new XMLParser({
108
+ ignoreAttributes: false,
109
+ attributeNamePrefix: "@_"
110
+ });
111
+ async function parseXliff(xliff) {
112
+ try {
113
+ const parsed = xmlParser.parse(xliff);
114
+ if (!parsed || typeof parsed !== "object") {
115
+ throw new Error("Invalid XLIFF: failed to parse");
116
+ }
117
+ return parsed;
118
+ } catch (err) {
119
+ const message = err instanceof Error ? err.message : "Failed to parse XLIFF";
120
+ throw new Error(`Invalid XLIFF 1.2: ${message}`);
121
+ }
122
+ }
123
+ async function xliffDataToResourceTranslationData(parsedXliff) {
124
+ const result = [];
125
+ const xliff = parsedXliff;
126
+ const fileEl = xliff?.xliff?.file;
127
+ if (!fileEl) return result;
128
+ const files = Array.isArray(fileEl) ? fileEl : [fileEl];
129
+ for (const file of files) {
130
+ const f = file;
131
+ const orig = f["@_original"] ?? "unknown";
132
+ const title = basename(orig, extname(orig)) || orig;
133
+ const targetLang = f["@_target-language"] ?? f["@_source-language"] ?? "";
134
+ const transUnits = f.body?.["trans-unit"];
135
+ const units = Array.isArray(transUnits) ? transUnits : transUnits ? [transUnits] : [];
136
+ const messages = [];
137
+ for (const tu of units) {
138
+ const t = tu;
139
+ const translate = (t["@_translate"] ?? "yes").toLowerCase();
140
+ if (translate === "no" || translate === "false") continue;
141
+ const key = t["@_resname"] ?? t["@_id"] ?? "";
142
+ const targetEl = t.target;
143
+ const value = (typeof targetEl === "object" && targetEl && "#text" in targetEl ? targetEl["#text"] : typeof targetEl === "string" ? targetEl : "") ?? "";
144
+ messages.push({ key, value });
145
+ }
146
+ result.push({
147
+ title,
148
+ attributes: { lang: targetLang, dir: "", dnt: false },
149
+ messages
150
+ });
151
+ }
152
+ return result;
153
+ }
154
+ async function xliffToTranslationData(xliff) {
155
+ const parsed = await parseXliff(xliff);
156
+ return xliffDataToResourceTranslationData(parsed);
157
+ }
158
+ async function writeTranslationData(filePath, data) {
159
+ const json = JSON.stringify(data, null, 2);
160
+ await writeFile(filePath, json, "utf-8");
161
+ }
162
+ export {
163
+ findMsgResourceFiles,
164
+ importMsgResources,
165
+ parseXliff,
166
+ readXliff,
167
+ resourcesToXliffString,
168
+ writeTranslationData,
169
+ writeXliff,
170
+ xliffDataToResourceTranslationData,
171
+ xliffToTranslationData
172
+ };
package/package.json CHANGED
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "name": "@worldware/msg-cli",
3
- "version": "0.0.5",
3
+ "version": "0.1.0",
4
4
  "description": "CLI for msg library",
5
- "main": "dist/index.js",
5
+ "main": "dist/commands/init.cjs",
6
+ "module": "dist/commands/init.mjs",
7
+ "types": "dist/commands/init.d.ts",
6
8
  "scripts": {
7
9
  "test": "vitest run",
8
- "build": "tsc",
10
+ "build": "tsup",
9
11
  "coverage": "vitest run --coverage"
10
12
  },
11
13
  "repository": {
@@ -29,13 +31,14 @@
29
31
  },
30
32
  "dependencies": {
31
33
  "@oclif/core": "^4.8.0",
32
- "@worldware/msg": "^0.5.6",
34
+ "@worldware/msg": "^0.6.0",
33
35
  "fast-xml-parser": "^5.3.4"
34
36
  },
35
37
  "devDependencies": {
36
38
  "@types/node": "^22.0.0",
37
39
  "@vitest/coverage-v8": "^4.0.18",
38
40
  "ts-node": "^10.9.2",
41
+ "tsup": "^8.5.1",
39
42
  "typescript": "^5.9.3",
40
43
  "vitest": "^4.0.18"
41
44
  },
@@ -1,160 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- const core_1 = require("@oclif/core");
13
- const fs_1 = require("fs");
14
- const path_1 = require("path");
15
- const create_project_helpers_js_1 = require("../../lib/create-project-helpers.js");
16
- const init_helpers_js_1 = require("../../lib/init-helpers.js");
17
- /**
18
- * Creates a new MsgProject file in the i18n projects directory.
19
- */
20
- class CreateProject extends core_1.Command {
21
- run() {
22
- return __awaiter(this, void 0, void 0, function* () {
23
- var _a, _b;
24
- const { argv, flags } = yield this.parse(CreateProject);
25
- const [projectName, source, ...targets] = argv;
26
- if (!(projectName === null || projectName === void 0 ? void 0 : projectName.trim())) {
27
- this.error("projectName is required.", { exit: 1 });
28
- }
29
- if (!(source === null || source === void 0 ? void 0 : source.trim())) {
30
- this.error("source locale is required.", { exit: 1 });
31
- }
32
- if (!(targets === null || targets === void 0 ? void 0 : targets.length) || targets.every((t) => !(t === null || t === void 0 ? void 0 : t.trim()))) {
33
- this.error("At least one target locale is required.", { exit: 1 });
34
- }
35
- const cwd = process.cwd();
36
- const pkgPath = (0, init_helpers_js_1.findPackageJsonPath)(cwd);
37
- if (!pkgPath) {
38
- this.error("package.json not found. Run this command from the project root.", { exit: 1 });
39
- }
40
- let pkg;
41
- try {
42
- pkg = (0, create_project_helpers_js_1.loadPackageJsonForCreateProject)(cwd);
43
- }
44
- catch (err) {
45
- const msg = err instanceof Error ? err.message : String(err);
46
- this.error(msg, { exit: 1 });
47
- }
48
- const rootDir = (0, path_1.join)(pkgPath, "..");
49
- const i18nDir = pkg.directories.i18n;
50
- const l10nDir = pkg.directories.l10n;
51
- const projectsDir = (0, path_1.join)(rootDir, i18nDir, "projects");
52
- const translationsDir = (0, path_1.join)(rootDir, l10nDir, "translations");
53
- const relPath = (0, create_project_helpers_js_1.calculateRelativePath)(projectsDir, translationsDir);
54
- const useTypeScript = (0, fs_1.existsSync)((0, path_1.join)(rootDir, "tsconfig.json"));
55
- const isEsm = pkg.type === "module";
56
- const ext = useTypeScript ? ".ts" : ".js";
57
- const outPath = (0, path_1.join)(projectsDir, `${projectName}${ext}`);
58
- if ((0, fs_1.existsSync)(outPath)) {
59
- this.error(`A project with the name '${projectName}' already exists.`, { exit: 1 });
60
- }
61
- let targetLocales = {};
62
- let pseudoLocale = "en-XA";
63
- if (flags.extend) {
64
- const base = yield (0, create_project_helpers_js_1.importMsgProjectFile)(projectsDir, flags.extend);
65
- if (!base) {
66
- this.error(`Project '${flags.extend}' could not be found to extend.`, { exit: 1 });
67
- }
68
- if (((_a = base.locales) === null || _a === void 0 ? void 0 : _a.targetLocales) && typeof base.locales.targetLocales === "object") {
69
- targetLocales = Object.assign({}, base.locales.targetLocales);
70
- }
71
- if ((_b = base.locales) === null || _b === void 0 ? void 0 : _b.pseudoLocale) {
72
- pseudoLocale = base.locales.pseudoLocale;
73
- }
74
- }
75
- targetLocales[source] = [source];
76
- for (const t of targets) {
77
- if (t === null || t === void 0 ? void 0 : t.trim())
78
- targetLocales[t.trim()] = [t.trim()];
79
- }
80
- const loaderPathLine = "const path = `${TRANSLATION_IMPORT_PATH}/${project}/${language}/${title}.json`;";
81
- const loaderWarnLine = "console.warn(`Translations for locale ${language} could not be loaded.`, error);";
82
- const loaderBody = `${loaderPathLine}
83
- try {
84
- const module = await import(path, { with: { type: 'json' } });
85
- return module.default;
86
- } catch (error) {
87
- ${loaderWarnLine}
88
- return {
89
- title,
90
- attributes: { lang: language, dir: '' },
91
- notes: [],
92
- messages: []
93
- };
94
- }`;
95
- const importPath = relPath.replace(/\\/g, "/");
96
- const content = isEsm
97
- ? `import { MsgProject } from '@worldware/msg';
98
-
99
- const TRANSLATION_IMPORT_PATH = ${JSON.stringify(importPath)};
100
- const loader = async (project, title, language) => {
101
- ${loaderBody}
102
- };
103
-
104
- export default MsgProject.create({
105
- project: { name: ${JSON.stringify(projectName)}, version: 1 },
106
- locales: {
107
- sourceLocale: ${JSON.stringify(source)},
108
- pseudoLocale: ${JSON.stringify(pseudoLocale)},
109
- targetLocales: ${JSON.stringify(targetLocales)}
110
- },
111
- loader
112
- });
113
- `
114
- : `const { MsgProject } = require('@worldware/msg');
115
-
116
- const TRANSLATION_IMPORT_PATH = ${JSON.stringify(importPath)};
117
- const loader = async (project, title, language) => {
118
- ${loaderBody}
119
- };
120
-
121
- module.exports = MsgProject.create({
122
- project: { name: ${JSON.stringify(projectName)}, version: 1 },
123
- locales: {
124
- sourceLocale: ${JSON.stringify(source)},
125
- pseudoLocale: ${JSON.stringify(pseudoLocale)},
126
- targetLocales: ${JSON.stringify(targetLocales)}
127
- },
128
- loader
129
- });
130
- `;
131
- this.log("Creating MsgProject file...");
132
- (0, create_project_helpers_js_1.writeMsgProjectFile)(outPath, content);
133
- this.log(`Created ${outPath}`);
134
- });
135
- }
136
- }
137
- CreateProject.description = "Create a new MsgProject file in the projects directory (i18n/projects)";
138
- CreateProject.strict = false;
139
- CreateProject.args = {
140
- projectName: core_1.Args.string({
141
- required: false,
142
- description: "Name of the project (used as file name)",
143
- }),
144
- source: core_1.Args.string({
145
- required: false,
146
- description: "Source locale for the project",
147
- }),
148
- targets: core_1.Args.string({
149
- required: false,
150
- description: "Target locale(s) (variadic)",
151
- }),
152
- };
153
- CreateProject.flags = {
154
- help: core_1.Flags.help({ char: "h" }),
155
- extend: core_1.Flags.string({
156
- char: "e",
157
- description: "Extend an existing project",
158
- }),
159
- };
160
- exports.default = CreateProject;
@@ -1,169 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
- return new (P || (P = Promise))(function (resolve, reject) {
38
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
- step((generator = generator.apply(thisArg, _arguments || [])).next());
42
- });
43
- };
44
- Object.defineProperty(exports, "__esModule", { value: true });
45
- const core_1 = require("@oclif/core");
46
- const fs_1 = require("fs");
47
- const path_1 = require("path");
48
- const url_1 = require("url");
49
- const create_resource_helpers_js_1 = require("../../lib/create-resource-helpers.js");
50
- const init_helpers_js_1 = require("../../lib/init-helpers.js");
51
- /**
52
- * Creates a new MsgResource file in the i18n resources directory.
53
- */
54
- class CreateResource extends core_1.Command {
55
- run() {
56
- return __awaiter(this, void 0, void 0, function* () {
57
- const { argv, flags } = yield this.parse(CreateResource);
58
- const [projectName, title] = argv;
59
- if (!(projectName === null || projectName === void 0 ? void 0 : projectName.trim())) {
60
- this.error("projectName is required. Run 'msg init' first if you have not.", {
61
- exit: 1,
62
- });
63
- }
64
- if (!(title === null || title === void 0 ? void 0 : title.trim())) {
65
- this.error("title is required.", { exit: 1 });
66
- }
67
- const cwd = process.cwd();
68
- const pkgPath = (0, init_helpers_js_1.findPackageJsonPath)(cwd);
69
- if (!pkgPath) {
70
- this.error("package.json not found. Run this command from the project root.", {
71
- exit: 1,
72
- });
73
- }
74
- let pkgInfo;
75
- try {
76
- pkgInfo = (0, create_resource_helpers_js_1.readPackageJsonForCreateResource)(cwd);
77
- }
78
- catch (err) {
79
- const msg = err instanceof Error ? err.message : String(err);
80
- this.error(msg, { exit: 1 });
81
- }
82
- const rootDir = (0, path_1.join)(pkgPath, "..");
83
- const i18nDir = (0, path_1.join)(rootDir, pkgInfo.i18nDir);
84
- const projectsDir = (0, path_1.join)(i18nDir, "projects");
85
- const resourcesDir = (0, path_1.join)(i18nDir, "resources");
86
- if (!(0, fs_1.existsSync)(i18nDir)) {
87
- this.error(`i18n directory '${pkgInfo.i18nDir}' does not exist. Run 'msg init' first.`, { exit: 1 });
88
- }
89
- if (!(0, fs_1.existsSync)(projectsDir)) {
90
- this.error(`i18n/projects directory does not exist. Run 'msg init' first.`, { exit: 1 });
91
- }
92
- if (!(0, fs_1.existsSync)(resourcesDir)) {
93
- this.error(`i18n/resources directory does not exist. Run 'msg init' first.`, { exit: 1 });
94
- }
95
- const projectData = yield (0, create_resource_helpers_js_1.importMsgProjectForResource)(projectsDir, projectName.trim());
96
- if (!projectData) {
97
- this.error(`Project '${projectName}' not found or could not be loaded. Check i18n/projects for a matching file.`, { exit: 1 });
98
- }
99
- const ext = pkgInfo.useTypeScript ? ".ts" : ".js";
100
- const outPath = (0, path_1.join)(resourcesDir, `${title.trim()}.msg${ext}`);
101
- if ((0, fs_1.existsSync)(outPath) && !flags.force) {
102
- this.error(`Resource file '${title.trim()}.msg${ext}' already exists. Use -f or --force to overwrite.`, { exit: 1 });
103
- }
104
- const content = (0, create_resource_helpers_js_1.generateMsgResourceContent)({
105
- title: title.trim(),
106
- projectName: projectName.trim(),
107
- sourceLocale: projectData.sourceLocale,
108
- dir: projectData.dir,
109
- isEsm: pkgInfo.isEsm,
110
- });
111
- try {
112
- (0, create_resource_helpers_js_1.writeMsgResourceFile)(outPath, content);
113
- }
114
- catch (err) {
115
- const msg = err instanceof Error ? err.message : String(err);
116
- this.error(`Could not generate resource file: ${msg}`, { exit: 1 });
117
- }
118
- try {
119
- const url = (0, url_1.pathToFileURL)(outPath).href;
120
- yield (0, create_resource_helpers_js_1.dynamicImportFromUrl)(url);
121
- }
122
- catch (err) {
123
- try {
124
- (0, fs_1.unlinkSync)(outPath);
125
- }
126
- catch (_a) {
127
- // best-effort cleanup
128
- }
129
- const msg = err instanceof Error ? err.message : String(err);
130
- this.error(`Generated file is invalid or not importable: ${msg}`, { exit: 1 });
131
- }
132
- this.log(`Created ${outPath}`);
133
- if (flags.edit) {
134
- const editor = process.env.VISUAL || process.env.EDITOR;
135
- if (editor) {
136
- const { spawn } = yield Promise.resolve().then(() => __importStar(require("child_process")));
137
- spawn(editor, [outPath], { stdio: "inherit", detached: true });
138
- }
139
- else {
140
- this.warn("EDITOR or VISUAL not set. Open the file manually.");
141
- }
142
- }
143
- });
144
- }
145
- }
146
- CreateResource.description = "Create a new MsgResource file in the resources directory (i18n/resources)";
147
- CreateResource.strict = false;
148
- CreateResource.args = {
149
- projectName: core_1.Args.string({
150
- required: false,
151
- description: "Name of the project to import in the MsgResource file",
152
- }),
153
- title: core_1.Args.string({
154
- required: false,
155
- description: "Title of the resource and file name for the file",
156
- }),
157
- };
158
- CreateResource.flags = {
159
- help: core_1.Flags.help({ char: "h" }),
160
- force: core_1.Flags.boolean({
161
- char: "f",
162
- description: "Overwrite an existing resource file",
163
- }),
164
- edit: core_1.Flags.boolean({
165
- char: "e",
166
- description: "Open the file for editing after creation",
167
- }),
168
- };
169
- exports.default = CreateResource;
@@ -1,131 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- const core_1 = require("@oclif/core");
13
- const child_process_1 = require("child_process");
14
- const fs_1 = require("fs");
15
- const readline_1 = require("readline");
16
- const path_1 = require("path");
17
- const init_helpers_js_1 = require("../lib/init-helpers.js");
18
- /**
19
- * Scaffolds a msg project: directories, package.json entries, and dependencies.
20
- */
21
- class Init extends core_1.Command {
22
- run() {
23
- return __awaiter(this, void 0, void 0, function* () {
24
- var _a, _b, _c;
25
- const { flags } = yield this.parse(Init);
26
- const cwd = process.cwd();
27
- const pkgPath = (0, init_helpers_js_1.findPackageJsonPath)(cwd);
28
- if (!pkgPath) {
29
- this.error("package.json not found. Run this command from the project root.", {
30
- exit: 1,
31
- });
32
- }
33
- let i18nDir = (_a = flags.i18nDir) !== null && _a !== void 0 ? _a : init_helpers_js_1.DEFAULT_I18N_DIR;
34
- let l10nDir = (_b = flags.l10nDir) !== null && _b !== void 0 ? _b : init_helpers_js_1.DEFAULT_L10N_DIR;
35
- if (flags.interactive) {
36
- const rl = (0, readline_1.createInterface)({ input: process.stdin, output: process.stdout });
37
- const ask = (question, defaultVal) => new Promise((resolve) => {
38
- rl.question(`${question} [${defaultVal}]: `, (answer) => {
39
- resolve(((answer === null || answer === void 0 ? void 0 : answer.trim()) || defaultVal).trim() || defaultVal);
40
- });
41
- });
42
- if (!flags.i18nDir) {
43
- i18nDir = yield ask("i18n directory path (relative to project root):", init_helpers_js_1.DEFAULT_I18N_DIR);
44
- }
45
- if (!flags.l10nDir) {
46
- l10nDir = yield ask("l10n directory path (relative to project root):", init_helpers_js_1.DEFAULT_L10N_DIR);
47
- }
48
- rl.close();
49
- }
50
- const rootDir = (0, path_1.join)(cwd);
51
- const validation = (0, init_helpers_js_1.validatePaths)(rootDir, i18nDir, l10nDir);
52
- if (!validation.valid) {
53
- this.error((_c = validation.error) !== null && _c !== void 0 ? _c : "Invalid paths", { exit: 1 });
54
- }
55
- let pkg;
56
- try {
57
- pkg = (0, init_helpers_js_1.readPackageJson)(pkgPath);
58
- }
59
- catch (err) {
60
- const msg = err instanceof Error ? err.message : "Invalid or unreadable package.json";
61
- this.error(msg, { exit: 1 });
62
- }
63
- const alreadyInit = (0, init_helpers_js_1.isAlreadyInitialized)(pkg, rootDir, i18nDir, l10nDir);
64
- if (alreadyInit && !flags.force) {
65
- this.warn("Project appears already initialized for msg. Use -f or --force to re-run.");
66
- return;
67
- }
68
- this.log("Creating i18n and l10n directories...");
69
- try {
70
- (0, init_helpers_js_1.ensureDirectoriesWithGitkeep)(rootDir, i18nDir, l10nDir, flags.force);
71
- }
72
- catch (err) {
73
- const msg = err instanceof Error ? err.message : "Failed to create directories";
74
- this.error(msg, { exit: 1 });
75
- }
76
- this.log("Updating package.json...");
77
- pkg = (0, init_helpers_js_1.addDirectoriesToPackageJson)(pkg, i18nDir, l10nDir);
78
- pkg = (0, init_helpers_js_1.addImportAliasesToPackageJson)(pkg, i18nDir, l10nDir);
79
- pkg = (0, init_helpers_js_1.addScriptsToPackageJson)(pkg);
80
- try {
81
- (0, init_helpers_js_1.writePackageJson)(pkgPath, pkg);
82
- }
83
- catch (err) {
84
- const msg = err instanceof Error ? err.message : "Failed to write package.json";
85
- this.error(msg, { exit: 1 });
86
- }
87
- const tsconfigPath = (0, path_1.join)(rootDir, "tsconfig.json");
88
- if ((0, fs_1.existsSync)(tsconfigPath)) {
89
- this.log("Updating tsconfig.json for path aliases...");
90
- try {
91
- (0, init_helpers_js_1.addTsconfigPaths)(tsconfigPath, i18nDir, l10nDir);
92
- }
93
- catch (err) {
94
- this.warn(err instanceof Error ? err.message : "Could not update tsconfig.json; you may add paths manually.");
95
- }
96
- }
97
- this.log("Installing @worldware/msg...");
98
- const installResult = (0, child_process_1.spawnSync)("npm", ["install", "@worldware/msg@latest", "--save"], { cwd: rootDir, shell: true, stdio: "inherit" });
99
- if (installResult.status !== 0) {
100
- this.error("Failed to install @worldware/msg. Check your network and npm registry.", {
101
- exit: 1,
102
- });
103
- }
104
- this.log("Init complete.");
105
- });
106
- }
107
- }
108
- Init.description = "Scaffold a msg project (i18n/l10n directories, package.json, and dependencies)";
109
- Init.examples = [
110
- "<%= config.bin %> <%= command.id %>",
111
- "<%= config.bin %> <%= command.id %> --i18nDir lib/i18n --l10nDir data/l10n",
112
- "<%= config.bin %> <%= command.id %> -f",
113
- ];
114
- Init.flags = {
115
- help: core_1.Flags.help({ char: "h" }),
116
- interactive: core_1.Flags.boolean({
117
- char: "i",
118
- description: "Prompt for i18n and l10n directory paths",
119
- }),
120
- force: core_1.Flags.boolean({
121
- char: "f",
122
- description: "Force clean install; overwrite existing msg setup",
123
- }),
124
- i18nDir: core_1.Flags.string({
125
- description: "Relative path for the i18n directory",
126
- }),
127
- l10nDir: core_1.Flags.string({
128
- description: "Relative path for the l10n directory",
129
- }),
130
- };
131
- exports.default = Init;