@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.
- package/dist/chunk-4Q2252JQ.mjs +50 -0
- package/dist/chunk-DBC2Y6VQ.mjs +167 -0
- package/dist/chunk-KKYCVD5M.mjs +136 -0
- package/dist/commands/create/project.cjs +293 -0
- package/dist/commands/create/project.d.mts +22 -0
- package/dist/commands/create/project.d.ts +22 -0
- package/dist/commands/create/project.mjs +151 -0
- package/dist/commands/create/resource.cjs +355 -0
- package/dist/commands/create/resource.d.mts +22 -0
- package/dist/commands/create/resource.d.ts +22 -0
- package/dist/commands/create/resource.mjs +143 -0
- package/dist/commands/init.cjs +259 -0
- package/dist/commands/init.d.mts +20 -0
- package/dist/commands/init.d.ts +20 -0
- package/dist/commands/init.mjs +133 -0
- package/dist/lib/create-project-helpers.cjs +163 -0
- package/dist/lib/create-project-helpers.d.mts +50 -0
- package/dist/lib/create-project-helpers.d.ts +50 -0
- package/dist/lib/create-project-helpers.mjs +14 -0
- package/dist/lib/create-resource-helpers.cjs +225 -0
- package/dist/lib/create-resource-helpers.d.mts +55 -0
- package/dist/lib/create-resource-helpers.d.ts +55 -0
- package/dist/lib/create-resource-helpers.mjs +15 -0
- package/dist/lib/init-helpers.cjs +203 -0
- package/dist/lib/init-helpers.d.mts +100 -0
- package/dist/lib/init-helpers.d.ts +100 -0
- package/dist/lib/init-helpers.mjs +30 -0
- package/dist/lib/utilities.cjs +203 -0
- package/dist/lib/utilities.d.mts +59 -0
- package/dist/lib/utilities.d.ts +59 -0
- package/dist/lib/utilities.mjs +172 -0
- package/package.json +7 -4
- package/dist/commands/create/project.js +0 -160
- package/dist/commands/create/resource.js +0 -169
- package/dist/commands/init.js +0 -131
- package/dist/lib/create-project-helpers.js +0 -112
- package/dist/lib/create-resource-helpers.js +0 -196
- package/dist/lib/init-helpers.js +0 -219
- package/dist/lib/utilities.js +0 -286
|
@@ -0,0 +1,259 @@
|
|
|
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/init.ts
|
|
21
|
+
var init_exports = {};
|
|
22
|
+
__export(init_exports, {
|
|
23
|
+
default: () => Init
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(init_exports);
|
|
26
|
+
var import_core = require("@oclif/core");
|
|
27
|
+
var import_child_process = require("child_process");
|
|
28
|
+
var import_fs2 = require("fs");
|
|
29
|
+
var import_readline = require("readline");
|
|
30
|
+
var import_path2 = require("path");
|
|
31
|
+
|
|
32
|
+
// src/lib/init-helpers.ts
|
|
33
|
+
var import_fs = require("fs");
|
|
34
|
+
var import_path = require("path");
|
|
35
|
+
var DEFAULT_I18N_DIR = "src/i18n";
|
|
36
|
+
var DEFAULT_L10N_DIR = "res/l10n";
|
|
37
|
+
function findPackageJsonPath(cwd) {
|
|
38
|
+
let dir = cwd;
|
|
39
|
+
for (; ; ) {
|
|
40
|
+
const p = (0, import_path.join)(dir, "package.json");
|
|
41
|
+
if ((0, import_fs.existsSync)(p)) return p;
|
|
42
|
+
const parent = (0, import_path.dirname)(dir);
|
|
43
|
+
if (parent === dir) return null;
|
|
44
|
+
dir = parent;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function readPackageJson(pkgPath) {
|
|
48
|
+
const raw = (0, import_fs.readFileSync)(pkgPath, "utf-8");
|
|
49
|
+
try {
|
|
50
|
+
const parsed = JSON.parse(raw);
|
|
51
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
52
|
+
throw new Error("package.json must be a JSON object");
|
|
53
|
+
}
|
|
54
|
+
return parsed;
|
|
55
|
+
} catch (err) {
|
|
56
|
+
if (err instanceof SyntaxError) {
|
|
57
|
+
throw new Error("Invalid package.json: " + err.message);
|
|
58
|
+
}
|
|
59
|
+
throw err;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function writePackageJson(pkgPath, pkg) {
|
|
63
|
+
const json = JSON.stringify(pkg, null, 2) + "\n";
|
|
64
|
+
(0, import_fs.writeFileSync)(pkgPath, json, "utf-8");
|
|
65
|
+
}
|
|
66
|
+
function validatePaths(rootDir, i18nDir, l10nDir) {
|
|
67
|
+
const trimmedI18n = i18nDir.trim();
|
|
68
|
+
const trimmedL10n = l10nDir.trim();
|
|
69
|
+
if (!trimmedI18n) return { valid: false, error: "i18n directory path cannot be empty" };
|
|
70
|
+
if (!trimmedL10n) return { valid: false, error: "l10n directory path cannot be empty" };
|
|
71
|
+
if (trimmedI18n.startsWith("/") || /^[A-Za-z]:/.test(trimmedI18n)) {
|
|
72
|
+
return { valid: false, error: "i18n path must be relative" };
|
|
73
|
+
}
|
|
74
|
+
if (trimmedL10n.startsWith("/") || /^[A-Za-z]:/.test(trimmedL10n)) {
|
|
75
|
+
return { valid: false, error: "l10n path must be relative" };
|
|
76
|
+
}
|
|
77
|
+
return { valid: true };
|
|
78
|
+
}
|
|
79
|
+
var GITKEEP = ".gitkeep";
|
|
80
|
+
function ensureDirectoriesWithGitkeep(rootDir, i18nDir, l10nDir, force) {
|
|
81
|
+
const leaves = [
|
|
82
|
+
(0, import_path.join)(rootDir, i18nDir, "projects"),
|
|
83
|
+
(0, import_path.join)(rootDir, i18nDir, "resources"),
|
|
84
|
+
(0, import_path.join)(rootDir, l10nDir, "translations"),
|
|
85
|
+
(0, import_path.join)(rootDir, l10nDir, "xliff")
|
|
86
|
+
];
|
|
87
|
+
for (const leaf of leaves) {
|
|
88
|
+
const parent = (0, import_path.dirname)(leaf);
|
|
89
|
+
if (!(0, import_fs.existsSync)(parent)) {
|
|
90
|
+
(0, import_fs.mkdirSync)(parent, { recursive: true });
|
|
91
|
+
}
|
|
92
|
+
if (!(0, import_fs.existsSync)(leaf)) {
|
|
93
|
+
(0, import_fs.mkdirSync)(leaf, { recursive: true });
|
|
94
|
+
}
|
|
95
|
+
const gitkeepPath = (0, import_path.join)(leaf, GITKEEP);
|
|
96
|
+
if (force || !(0, import_fs.existsSync)(gitkeepPath)) {
|
|
97
|
+
(0, import_fs.writeFileSync)(gitkeepPath, "", "utf-8");
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function isAlreadyInitialized(pkg, rootDir, i18nDir, l10nDir) {
|
|
102
|
+
const dirs = pkg.directories;
|
|
103
|
+
if (!dirs || typeof dirs !== "object") return false;
|
|
104
|
+
if (dirs.i18n !== i18nDir || dirs.l10n !== l10nDir) return false;
|
|
105
|
+
const i18nFull = (0, import_path.join)(rootDir, i18nDir);
|
|
106
|
+
const l10nFull = (0, import_path.join)(rootDir, l10nDir);
|
|
107
|
+
return (0, import_fs.existsSync)(i18nFull) && (0, import_fs.existsSync)(l10nFull);
|
|
108
|
+
}
|
|
109
|
+
function addDirectoriesToPackageJson(pkg, i18nDir, l10nDir) {
|
|
110
|
+
const directories = { ...pkg.directories, i18n: i18nDir, l10n: l10nDir, root: "." };
|
|
111
|
+
return { ...pkg, directories };
|
|
112
|
+
}
|
|
113
|
+
function addImportAliasesToPackageJson(pkg, i18nDir, l10nDir) {
|
|
114
|
+
const imports = {
|
|
115
|
+
...pkg.imports,
|
|
116
|
+
"#i18n/*": `${i18nDir}/*`,
|
|
117
|
+
"#l10n/*": `${l10nDir}/*`,
|
|
118
|
+
"#root/*": "./*"
|
|
119
|
+
};
|
|
120
|
+
return { ...pkg, imports };
|
|
121
|
+
}
|
|
122
|
+
function addScriptsToPackageJson(pkg) {
|
|
123
|
+
const scripts = {
|
|
124
|
+
...pkg.scripts,
|
|
125
|
+
"i18n-export": "msg export:resources",
|
|
126
|
+
"l10n-import": "msg import:translations"
|
|
127
|
+
};
|
|
128
|
+
return { ...pkg, scripts };
|
|
129
|
+
}
|
|
130
|
+
function addTsconfigPaths(tsconfigPath, i18nDir, l10nDir) {
|
|
131
|
+
const raw = (0, import_fs.readFileSync)(tsconfigPath, "utf-8");
|
|
132
|
+
let config;
|
|
133
|
+
try {
|
|
134
|
+
config = JSON.parse(raw);
|
|
135
|
+
} catch {
|
|
136
|
+
throw new Error("Invalid tsconfig.json");
|
|
137
|
+
}
|
|
138
|
+
if (!config.compilerOptions) config.compilerOptions = {};
|
|
139
|
+
const co = config.compilerOptions;
|
|
140
|
+
co.baseUrl = co.baseUrl ?? ".";
|
|
141
|
+
co.paths = {
|
|
142
|
+
...co.paths,
|
|
143
|
+
"#i18n/*": [`${i18nDir}/*`],
|
|
144
|
+
"#l10n/*": [`${l10nDir}/*`],
|
|
145
|
+
"#root/*": ["./*"]
|
|
146
|
+
};
|
|
147
|
+
(0, import_fs.writeFileSync)(tsconfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/commands/init.ts
|
|
151
|
+
var Init = class _Init extends import_core.Command {
|
|
152
|
+
static description = "Scaffold a msg project (i18n/l10n directories, package.json, and dependencies)";
|
|
153
|
+
static examples = [
|
|
154
|
+
"<%= config.bin %> <%= command.id %>",
|
|
155
|
+
"<%= config.bin %> <%= command.id %> --i18nDir lib/i18n --l10nDir data/l10n",
|
|
156
|
+
"<%= config.bin %> <%= command.id %> -f"
|
|
157
|
+
];
|
|
158
|
+
static flags = {
|
|
159
|
+
help: import_core.Flags.help({ char: "h" }),
|
|
160
|
+
interactive: import_core.Flags.boolean({
|
|
161
|
+
char: "i",
|
|
162
|
+
description: "Prompt for i18n and l10n directory paths"
|
|
163
|
+
}),
|
|
164
|
+
force: import_core.Flags.boolean({
|
|
165
|
+
char: "f",
|
|
166
|
+
description: "Force clean install; overwrite existing msg setup"
|
|
167
|
+
}),
|
|
168
|
+
i18nDir: import_core.Flags.string({
|
|
169
|
+
description: "Relative path for the i18n directory"
|
|
170
|
+
}),
|
|
171
|
+
l10nDir: import_core.Flags.string({
|
|
172
|
+
description: "Relative path for the l10n directory"
|
|
173
|
+
})
|
|
174
|
+
};
|
|
175
|
+
async run() {
|
|
176
|
+
const { flags } = await this.parse(_Init);
|
|
177
|
+
const cwd = process.cwd();
|
|
178
|
+
const pkgPath = findPackageJsonPath(cwd);
|
|
179
|
+
if (!pkgPath) {
|
|
180
|
+
this.error("package.json not found. Run this command from the project root.", {
|
|
181
|
+
exit: 1
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
let i18nDir = flags.i18nDir ?? DEFAULT_I18N_DIR;
|
|
185
|
+
let l10nDir = flags.l10nDir ?? DEFAULT_L10N_DIR;
|
|
186
|
+
if (flags.interactive) {
|
|
187
|
+
const rl = (0, import_readline.createInterface)({ input: process.stdin, output: process.stdout });
|
|
188
|
+
const ask = (question, defaultVal) => new Promise((resolve) => {
|
|
189
|
+
rl.question(`${question} [${defaultVal}]: `, (answer) => {
|
|
190
|
+
resolve((answer?.trim() || defaultVal).trim() || defaultVal);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
if (!flags.i18nDir) {
|
|
194
|
+
i18nDir = await ask("i18n directory path (relative to project root):", DEFAULT_I18N_DIR);
|
|
195
|
+
}
|
|
196
|
+
if (!flags.l10nDir) {
|
|
197
|
+
l10nDir = await ask("l10n directory path (relative to project root):", DEFAULT_L10N_DIR);
|
|
198
|
+
}
|
|
199
|
+
rl.close();
|
|
200
|
+
}
|
|
201
|
+
const rootDir = (0, import_path2.join)(cwd);
|
|
202
|
+
const validation = validatePaths(rootDir, i18nDir, l10nDir);
|
|
203
|
+
if (!validation.valid) {
|
|
204
|
+
this.error(validation.error ?? "Invalid paths", { exit: 1 });
|
|
205
|
+
}
|
|
206
|
+
let pkg;
|
|
207
|
+
try {
|
|
208
|
+
pkg = readPackageJson(pkgPath);
|
|
209
|
+
} catch (err) {
|
|
210
|
+
const msg = err instanceof Error ? err.message : "Invalid or unreadable package.json";
|
|
211
|
+
this.error(msg, { exit: 1 });
|
|
212
|
+
}
|
|
213
|
+
const alreadyInit = isAlreadyInitialized(pkg, rootDir, i18nDir, l10nDir);
|
|
214
|
+
if (alreadyInit && !flags.force) {
|
|
215
|
+
this.warn("Project appears already initialized for msg. Use -f or --force to re-run.");
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
this.log("Creating i18n and l10n directories...");
|
|
219
|
+
try {
|
|
220
|
+
ensureDirectoriesWithGitkeep(rootDir, i18nDir, l10nDir, flags.force);
|
|
221
|
+
} catch (err) {
|
|
222
|
+
const msg = err instanceof Error ? err.message : "Failed to create directories";
|
|
223
|
+
this.error(msg, { exit: 1 });
|
|
224
|
+
}
|
|
225
|
+
this.log("Updating package.json...");
|
|
226
|
+
pkg = addDirectoriesToPackageJson(pkg, i18nDir, l10nDir);
|
|
227
|
+
pkg = addImportAliasesToPackageJson(pkg, i18nDir, l10nDir);
|
|
228
|
+
pkg = addScriptsToPackageJson(pkg);
|
|
229
|
+
try {
|
|
230
|
+
writePackageJson(pkgPath, pkg);
|
|
231
|
+
} catch (err) {
|
|
232
|
+
const msg = err instanceof Error ? err.message : "Failed to write package.json";
|
|
233
|
+
this.error(msg, { exit: 1 });
|
|
234
|
+
}
|
|
235
|
+
const tsconfigPath = (0, import_path2.join)(rootDir, "tsconfig.json");
|
|
236
|
+
if ((0, import_fs2.existsSync)(tsconfigPath)) {
|
|
237
|
+
this.log("Updating tsconfig.json for path aliases...");
|
|
238
|
+
try {
|
|
239
|
+
addTsconfigPaths(tsconfigPath, i18nDir, l10nDir);
|
|
240
|
+
} catch (err) {
|
|
241
|
+
this.warn(
|
|
242
|
+
err instanceof Error ? err.message : "Could not update tsconfig.json; you may add paths manually."
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
this.log("Installing @worldware/msg...");
|
|
247
|
+
const installResult = (0, import_child_process.spawnSync)(
|
|
248
|
+
"npm",
|
|
249
|
+
["install", "@worldware/msg@latest", "--save"],
|
|
250
|
+
{ cwd: rootDir, shell: true, stdio: "inherit" }
|
|
251
|
+
);
|
|
252
|
+
if (installResult.status !== 0) {
|
|
253
|
+
this.error("Failed to install @worldware/msg. Check your network and npm registry.", {
|
|
254
|
+
exit: 1
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
this.log("Init complete.");
|
|
258
|
+
}
|
|
259
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
* Scaffolds a msg project: directories, package.json entries, and dependencies.
|
|
6
|
+
*/
|
|
7
|
+
declare class Init extends Command {
|
|
8
|
+
static description: string;
|
|
9
|
+
static examples: string[];
|
|
10
|
+
static flags: {
|
|
11
|
+
help: _oclif_core_lib_interfaces_parser_js.BooleanFlag<void>;
|
|
12
|
+
interactive: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
|
|
13
|
+
force: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
|
|
14
|
+
i18nDir: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
|
15
|
+
l10nDir: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
|
16
|
+
};
|
|
17
|
+
run(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { Init as default };
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
* Scaffolds a msg project: directories, package.json entries, and dependencies.
|
|
6
|
+
*/
|
|
7
|
+
declare class Init extends Command {
|
|
8
|
+
static description: string;
|
|
9
|
+
static examples: string[];
|
|
10
|
+
static flags: {
|
|
11
|
+
help: _oclif_core_lib_interfaces_parser_js.BooleanFlag<void>;
|
|
12
|
+
interactive: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
|
|
13
|
+
force: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
|
|
14
|
+
i18nDir: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
|
15
|
+
l10nDir: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
|
16
|
+
};
|
|
17
|
+
run(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { Init as default };
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_I18N_DIR,
|
|
3
|
+
DEFAULT_L10N_DIR,
|
|
4
|
+
addDirectoriesToPackageJson,
|
|
5
|
+
addImportAliasesToPackageJson,
|
|
6
|
+
addScriptsToPackageJson,
|
|
7
|
+
addTsconfigPaths,
|
|
8
|
+
ensureDirectoriesWithGitkeep,
|
|
9
|
+
findPackageJsonPath,
|
|
10
|
+
isAlreadyInitialized,
|
|
11
|
+
readPackageJson,
|
|
12
|
+
validatePaths,
|
|
13
|
+
writePackageJson
|
|
14
|
+
} from "../chunk-DBC2Y6VQ.mjs";
|
|
15
|
+
|
|
16
|
+
// src/commands/init.ts
|
|
17
|
+
import { Command, Flags } from "@oclif/core";
|
|
18
|
+
import { spawnSync } from "child_process";
|
|
19
|
+
import { existsSync } from "fs";
|
|
20
|
+
import { createInterface } from "readline";
|
|
21
|
+
import { join } from "path";
|
|
22
|
+
var Init = class _Init extends Command {
|
|
23
|
+
static description = "Scaffold a msg project (i18n/l10n directories, package.json, and dependencies)";
|
|
24
|
+
static examples = [
|
|
25
|
+
"<%= config.bin %> <%= command.id %>",
|
|
26
|
+
"<%= config.bin %> <%= command.id %> --i18nDir lib/i18n --l10nDir data/l10n",
|
|
27
|
+
"<%= config.bin %> <%= command.id %> -f"
|
|
28
|
+
];
|
|
29
|
+
static flags = {
|
|
30
|
+
help: Flags.help({ char: "h" }),
|
|
31
|
+
interactive: Flags.boolean({
|
|
32
|
+
char: "i",
|
|
33
|
+
description: "Prompt for i18n and l10n directory paths"
|
|
34
|
+
}),
|
|
35
|
+
force: Flags.boolean({
|
|
36
|
+
char: "f",
|
|
37
|
+
description: "Force clean install; overwrite existing msg setup"
|
|
38
|
+
}),
|
|
39
|
+
i18nDir: Flags.string({
|
|
40
|
+
description: "Relative path for the i18n directory"
|
|
41
|
+
}),
|
|
42
|
+
l10nDir: Flags.string({
|
|
43
|
+
description: "Relative path for the l10n directory"
|
|
44
|
+
})
|
|
45
|
+
};
|
|
46
|
+
async run() {
|
|
47
|
+
const { flags } = await this.parse(_Init);
|
|
48
|
+
const cwd = process.cwd();
|
|
49
|
+
const pkgPath = findPackageJsonPath(cwd);
|
|
50
|
+
if (!pkgPath) {
|
|
51
|
+
this.error("package.json not found. Run this command from the project root.", {
|
|
52
|
+
exit: 1
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
let i18nDir = flags.i18nDir ?? DEFAULT_I18N_DIR;
|
|
56
|
+
let l10nDir = flags.l10nDir ?? DEFAULT_L10N_DIR;
|
|
57
|
+
if (flags.interactive) {
|
|
58
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
59
|
+
const ask = (question, defaultVal) => new Promise((resolve) => {
|
|
60
|
+
rl.question(`${question} [${defaultVal}]: `, (answer) => {
|
|
61
|
+
resolve((answer?.trim() || defaultVal).trim() || defaultVal);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
if (!flags.i18nDir) {
|
|
65
|
+
i18nDir = await ask("i18n directory path (relative to project root):", DEFAULT_I18N_DIR);
|
|
66
|
+
}
|
|
67
|
+
if (!flags.l10nDir) {
|
|
68
|
+
l10nDir = await ask("l10n directory path (relative to project root):", DEFAULT_L10N_DIR);
|
|
69
|
+
}
|
|
70
|
+
rl.close();
|
|
71
|
+
}
|
|
72
|
+
const rootDir = join(cwd);
|
|
73
|
+
const validation = validatePaths(rootDir, i18nDir, l10nDir);
|
|
74
|
+
if (!validation.valid) {
|
|
75
|
+
this.error(validation.error ?? "Invalid paths", { exit: 1 });
|
|
76
|
+
}
|
|
77
|
+
let pkg;
|
|
78
|
+
try {
|
|
79
|
+
pkg = readPackageJson(pkgPath);
|
|
80
|
+
} catch (err) {
|
|
81
|
+
const msg = err instanceof Error ? err.message : "Invalid or unreadable package.json";
|
|
82
|
+
this.error(msg, { exit: 1 });
|
|
83
|
+
}
|
|
84
|
+
const alreadyInit = isAlreadyInitialized(pkg, rootDir, i18nDir, l10nDir);
|
|
85
|
+
if (alreadyInit && !flags.force) {
|
|
86
|
+
this.warn("Project appears already initialized for msg. Use -f or --force to re-run.");
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
this.log("Creating i18n and l10n directories...");
|
|
90
|
+
try {
|
|
91
|
+
ensureDirectoriesWithGitkeep(rootDir, i18nDir, l10nDir, flags.force);
|
|
92
|
+
} catch (err) {
|
|
93
|
+
const msg = err instanceof Error ? err.message : "Failed to create directories";
|
|
94
|
+
this.error(msg, { exit: 1 });
|
|
95
|
+
}
|
|
96
|
+
this.log("Updating package.json...");
|
|
97
|
+
pkg = addDirectoriesToPackageJson(pkg, i18nDir, l10nDir);
|
|
98
|
+
pkg = addImportAliasesToPackageJson(pkg, i18nDir, l10nDir);
|
|
99
|
+
pkg = addScriptsToPackageJson(pkg);
|
|
100
|
+
try {
|
|
101
|
+
writePackageJson(pkgPath, pkg);
|
|
102
|
+
} catch (err) {
|
|
103
|
+
const msg = err instanceof Error ? err.message : "Failed to write package.json";
|
|
104
|
+
this.error(msg, { exit: 1 });
|
|
105
|
+
}
|
|
106
|
+
const tsconfigPath = join(rootDir, "tsconfig.json");
|
|
107
|
+
if (existsSync(tsconfigPath)) {
|
|
108
|
+
this.log("Updating tsconfig.json for path aliases...");
|
|
109
|
+
try {
|
|
110
|
+
addTsconfigPaths(tsconfigPath, i18nDir, l10nDir);
|
|
111
|
+
} catch (err) {
|
|
112
|
+
this.warn(
|
|
113
|
+
err instanceof Error ? err.message : "Could not update tsconfig.json; you may add paths manually."
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
this.log("Installing @worldware/msg...");
|
|
118
|
+
const installResult = spawnSync(
|
|
119
|
+
"npm",
|
|
120
|
+
["install", "@worldware/msg@latest", "--save"],
|
|
121
|
+
{ cwd: rootDir, shell: true, stdio: "inherit" }
|
|
122
|
+
);
|
|
123
|
+
if (installResult.status !== 0) {
|
|
124
|
+
this.error("Failed to install @worldware/msg. Check your network and npm registry.", {
|
|
125
|
+
exit: 1
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
this.log("Init complete.");
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
export {
|
|
132
|
+
Init as default
|
|
133
|
+
};
|
|
@@ -0,0 +1,163 @@
|
|
|
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/lib/create-project-helpers.ts
|
|
21
|
+
var create_project_helpers_exports = {};
|
|
22
|
+
__export(create_project_helpers_exports, {
|
|
23
|
+
calculateRelativePath: () => calculateRelativePath,
|
|
24
|
+
importMsgProjectFile: () => importMsgProjectFile,
|
|
25
|
+
loadPackageJsonForCreateProject: () => loadPackageJsonForCreateProject,
|
|
26
|
+
writeMsgProjectFile: () => writeMsgProjectFile
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(create_project_helpers_exports);
|
|
29
|
+
var import_fs2 = require("fs");
|
|
30
|
+
var import_path2 = require("path");
|
|
31
|
+
var import_url2 = require("url");
|
|
32
|
+
|
|
33
|
+
// src/lib/create-resource-helpers.ts
|
|
34
|
+
var import_module = require("module");
|
|
35
|
+
var import_url = require("url");
|
|
36
|
+
|
|
37
|
+
// src/lib/init-helpers.ts
|
|
38
|
+
var import_fs = require("fs");
|
|
39
|
+
var import_path = require("path");
|
|
40
|
+
function findPackageJsonPath(cwd) {
|
|
41
|
+
let dir = cwd;
|
|
42
|
+
for (; ; ) {
|
|
43
|
+
const p = (0, import_path.join)(dir, "package.json");
|
|
44
|
+
if ((0, import_fs.existsSync)(p)) return p;
|
|
45
|
+
const parent = (0, import_path.dirname)(dir);
|
|
46
|
+
if (parent === dir) return null;
|
|
47
|
+
dir = parent;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function readPackageJson(pkgPath) {
|
|
51
|
+
const raw = (0, import_fs.readFileSync)(pkgPath, "utf-8");
|
|
52
|
+
try {
|
|
53
|
+
const parsed = JSON.parse(raw);
|
|
54
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
55
|
+
throw new Error("package.json must be a JSON object");
|
|
56
|
+
}
|
|
57
|
+
return parsed;
|
|
58
|
+
} catch (err) {
|
|
59
|
+
if (err instanceof SyntaxError) {
|
|
60
|
+
throw new Error("Invalid package.json: " + err.message);
|
|
61
|
+
}
|
|
62
|
+
throw err;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function loadPackageJsonForMsg(cwd, options) {
|
|
66
|
+
const pkgPath = findPackageJsonPath(cwd);
|
|
67
|
+
if (!pkgPath) {
|
|
68
|
+
throw new Error("package.json not found. Run this command from the project root.");
|
|
69
|
+
}
|
|
70
|
+
let pkg;
|
|
71
|
+
try {
|
|
72
|
+
pkg = readPackageJson(pkgPath);
|
|
73
|
+
} catch (err) {
|
|
74
|
+
const msg = err instanceof Error ? err.message : "package.json could not be parsed.";
|
|
75
|
+
throw new Error(msg);
|
|
76
|
+
}
|
|
77
|
+
const dirs = pkg.directories;
|
|
78
|
+
if (!dirs || typeof dirs !== "object" || !dirs.i18n) {
|
|
79
|
+
throw new Error("package.json must contain directories.i18n. Run 'msg init' first.");
|
|
80
|
+
}
|
|
81
|
+
if (options?.requireL10n && !dirs.l10n) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
"package.json must contain directories.i18n and directories.l10n. Run 'msg init' first."
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
const rootDir = (0, import_path.dirname)(pkgPath);
|
|
87
|
+
const useTypeScript = (0, import_fs.existsSync)((0, import_path.join)(rootDir, "tsconfig.json"));
|
|
88
|
+
const isEsm = pkg.type === "module";
|
|
89
|
+
return {
|
|
90
|
+
pkgPath,
|
|
91
|
+
rootDir,
|
|
92
|
+
pkg,
|
|
93
|
+
i18nDir: dirs.i18n,
|
|
94
|
+
l10nDir: dirs.l10n,
|
|
95
|
+
isEsm,
|
|
96
|
+
useTypeScript
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// src/lib/create-resource-helpers.ts
|
|
101
|
+
async function dynamicImportFromUrl(url) {
|
|
102
|
+
try {
|
|
103
|
+
return await import(
|
|
104
|
+
/* @vite-ignore */
|
|
105
|
+
url
|
|
106
|
+
);
|
|
107
|
+
} catch (err) {
|
|
108
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
109
|
+
const useRequire = msg.includes("dynamic import callback") || msg.includes("ERR_VM_DYNAMIC_IMPORT");
|
|
110
|
+
if (useRequire) {
|
|
111
|
+
try {
|
|
112
|
+
const path = url.startsWith("file:") ? (0, import_url.fileURLToPath)(url) : url;
|
|
113
|
+
const base = (0, import_url.pathToFileURL)(process.cwd()).href;
|
|
114
|
+
const req = (0, import_module.createRequire)(base);
|
|
115
|
+
const mod = req(path);
|
|
116
|
+
return Promise.resolve(mod ?? {});
|
|
117
|
+
} catch {
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
throw err;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// src/lib/create-project-helpers.ts
|
|
125
|
+
function calculateRelativePath(projectsDir, translationsDir) {
|
|
126
|
+
const rel = (0, import_path2.relative)(projectsDir, translationsDir);
|
|
127
|
+
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
128
|
+
}
|
|
129
|
+
async function importMsgProjectFile(projectsDir, projectName) {
|
|
130
|
+
const basePath = (0, import_path2.join)(projectsDir, projectName);
|
|
131
|
+
const exts = [".ts", ".js"];
|
|
132
|
+
for (const ext of exts) {
|
|
133
|
+
const p = `${basePath}${ext}`;
|
|
134
|
+
if ((0, import_fs2.existsSync)(p)) {
|
|
135
|
+
try {
|
|
136
|
+
const url = (0, import_url2.pathToFileURL)(p).href;
|
|
137
|
+
const mod = await dynamicImportFromUrl(url);
|
|
138
|
+
return mod?.default ?? mod;
|
|
139
|
+
} catch {
|
|
140
|
+
return void 0;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return void 0;
|
|
145
|
+
}
|
|
146
|
+
function writeMsgProjectFile(filePath, content) {
|
|
147
|
+
const dir = (0, import_path2.dirname)(filePath);
|
|
148
|
+
if (!(0, import_fs2.existsSync)(dir)) {
|
|
149
|
+
(0, import_fs2.mkdirSync)(dir, { recursive: true });
|
|
150
|
+
}
|
|
151
|
+
(0, import_fs2.writeFileSync)(filePath, content, "utf-8");
|
|
152
|
+
}
|
|
153
|
+
function loadPackageJsonForCreateProject(cwd) {
|
|
154
|
+
const ctx = loadPackageJsonForMsg(cwd, { requireL10n: true });
|
|
155
|
+
return ctx.pkg;
|
|
156
|
+
}
|
|
157
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
158
|
+
0 && (module.exports = {
|
|
159
|
+
calculateRelativePath,
|
|
160
|
+
importMsgProjectFile,
|
|
161
|
+
loadPackageJsonForCreateProject,
|
|
162
|
+
writeMsgProjectFile
|
|
163
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { PackageJson } from './init-helpers.mjs';
|
|
2
|
+
|
|
3
|
+
/** Minimal type for MsgProject-like data we read from an existing project file. */
|
|
4
|
+
interface MsgProjectFileData {
|
|
5
|
+
project?: {
|
|
6
|
+
name?: string;
|
|
7
|
+
version?: number;
|
|
8
|
+
};
|
|
9
|
+
locales?: {
|
|
10
|
+
sourceLocale?: string;
|
|
11
|
+
pseudoLocale?: string;
|
|
12
|
+
targetLocales?: Record<string, string[]>;
|
|
13
|
+
};
|
|
14
|
+
loader?: unknown;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Calculates the relative path from the i18n projects directory to the l10n translations directory.
|
|
18
|
+
* @param projectsDir - Absolute path to i18n/projects (e.g. root/i18n/projects)
|
|
19
|
+
* @param translationsDir - Absolute path to l10n/translations (e.g. root/l10n/translations)
|
|
20
|
+
* @returns Relative path string from projects to translations, suitable for import()
|
|
21
|
+
*/
|
|
22
|
+
declare function calculateRelativePath(projectsDir: string, translationsDir: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Imports an existing MsgProject module from the projects directory.
|
|
25
|
+
* @param projectsDir - Absolute path to i18n/projects
|
|
26
|
+
* @param projectName - Name of the project (file name without extension)
|
|
27
|
+
* @returns The default export (MsgProject instance or data) or undefined if not found
|
|
28
|
+
*/
|
|
29
|
+
declare function importMsgProjectFile(projectsDir: string, projectName: string): Promise<MsgProjectFileData | undefined>;
|
|
30
|
+
/**
|
|
31
|
+
* Writes an MsgProject file to the projects directory.
|
|
32
|
+
* @param filePath - Absolute path of the file to write (including extension)
|
|
33
|
+
* @param content - Full file content string
|
|
34
|
+
*/
|
|
35
|
+
declare function writeMsgProjectFile(filePath: string, content: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* Loads package.json from the given directory (walking up to find it).
|
|
38
|
+
* Requires directories.i18n and directories.l10n.
|
|
39
|
+
* @param cwd - Directory to start from (e.g. process.cwd())
|
|
40
|
+
* @returns Parsed package.json with directories.i18n and directories.l10n
|
|
41
|
+
* @throws Error if package.json not found or missing directories.i18n / directories.l10n
|
|
42
|
+
*/
|
|
43
|
+
declare function loadPackageJsonForCreateProject(cwd: string): PackageJson & {
|
|
44
|
+
directories: {
|
|
45
|
+
i18n: string;
|
|
46
|
+
l10n: string;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export { type MsgProjectFileData, calculateRelativePath, importMsgProjectFile, loadPackageJsonForCreateProject, writeMsgProjectFile };
|