@worldware/msg-cli 0.0.2
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/LICENSE +21 -0
- package/README.md +181 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +7 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +7 -0
- package/dist/commands/create/project.js +160 -0
- package/dist/commands/create/resource.js +169 -0
- package/dist/commands/init.js +131 -0
- package/dist/lib/create-project-helpers.js +112 -0
- package/dist/lib/create-resource-helpers.js +176 -0
- package/dist/lib/init-helpers.js +219 -0
- package/dist/lib/utilities.js +286 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Joel Sahleen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# msg-cli
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
msg-cli is a command-line tool for the [msg](https://github.com/worldware-studios/msg) library. It helps you scaffold internationalization (i18n) and localization (l10n) layout and wire up your project for use with msg.
|
|
6
|
+
|
|
7
|
+
**Current status:** Implemented commands: `init` (scaffold i18n/l10n and config), `create project` (template a new MsgProject file in i18n/projects), and `create resource` (template a new MsgResource file in i18n/resources).
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
Install globally:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @worldware/msg-cli
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or use via `npx`:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx @worldware/msg-cli <command>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
For project-local setup, run `msg init` in your project root to add msg and msg-cli as dependencies and scaffold directories and config.
|
|
24
|
+
|
|
25
|
+
## Core Concepts
|
|
26
|
+
|
|
27
|
+
- **i18n (internationalization):** Source message projects and resources. MsgProject and MsgResource files live under the i18n directory (default `src/i18n`).
|
|
28
|
+
- **l10n (localization):** Exported XLIFF files and imported translation JSON. Exports and translation data live under the l10n directory (default `res/l10n`).
|
|
29
|
+
- **Import aliases:** The init command adds `#i18n/*` and `#l10n/*` (and `#root/*`) to `package.json` so you can import with short paths like `import project from '#i18n/projects/main'`.
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
**Commands:** `init`, `create project`, `create resource`.
|
|
34
|
+
|
|
35
|
+
### init
|
|
36
|
+
|
|
37
|
+
Scaffold a msg project: create i18n and l10n directories, update `package.json` (directories, import aliases, scripts), optionally update `tsconfig.json` for path aliases, and install `@worldware/msg`.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
msg init
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
| Flag | Description |
|
|
44
|
+
|------|-------------|
|
|
45
|
+
| `-h`, `--help` | Show help for the init command. |
|
|
46
|
+
| `-i` | Interactive: prompt for i18n and l10n directory paths. |
|
|
47
|
+
| `-f`, `--force` | Force a clean run; overwrite or re-apply existing msg setup. |
|
|
48
|
+
| `--i18nDir <path>` | Relative path for the i18n directory (default: `src/i18n`). |
|
|
49
|
+
| `--l10nDir <path>` | Relative path for the l10n directory (default: `res/l10n`). |
|
|
50
|
+
|
|
51
|
+
**Examples:**
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Default layout (src/i18n, res/l10n)
|
|
55
|
+
msg init
|
|
56
|
+
|
|
57
|
+
# Custom paths
|
|
58
|
+
msg init --i18nDir lib/i18n --l10nDir data/l10n
|
|
59
|
+
|
|
60
|
+
# Re-run and overwrite existing setup
|
|
61
|
+
msg init -f
|
|
62
|
+
|
|
63
|
+
# Prompt for paths
|
|
64
|
+
msg init -i
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**What init does:**
|
|
68
|
+
|
|
69
|
+
1. Creates `i18n` with subdirectories `projects` and `resources`, and `l10n` with `translations` and `xliff` (or your custom paths).
|
|
70
|
+
2. Adds `.gitkeep` in each leaf directory.
|
|
71
|
+
3. Adds `directories.i18n`, `directories.l10n`, and `directories.root` to `package.json`.
|
|
72
|
+
4. Adds import aliases `#i18n/*`, `#l10n/*`, and `#root/*` to `package.json`.
|
|
73
|
+
5. Adds scripts `i18n-export` and `l10n-import` (pointing to `msg export:resources` and `msg import:translations`) for when those commands are available.
|
|
74
|
+
6. If `tsconfig.json` exists, adds `compilerOptions.baseUrl` and `compilerOptions.paths` for the aliases.
|
|
75
|
+
7. Installs the latest `@worldware/msg` as a dependency.
|
|
76
|
+
|
|
77
|
+
### create project
|
|
78
|
+
|
|
79
|
+
Create a new MsgProject file in the i18n projects directory. Requires `package.json` with `directories.i18n` and `directories.l10n` (run `msg init` first).
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
msg create project <projectName> <source> <targets...> [--extend <name>]
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
| Argument | Required | Description |
|
|
86
|
+
|-------------|----------|------------------------------------------|
|
|
87
|
+
| `projectName` | Yes | Name of the project (used as file name). |
|
|
88
|
+
| `source` | Yes | Source locale (e.g. `en`). |
|
|
89
|
+
| `targets` | Yes (≥1) | Target locale(s), e.g. `fr`, `de`, `es`. |
|
|
90
|
+
|
|
91
|
+
| Flag | Short | Description |
|
|
92
|
+
|------------|-------|--------------------------------|
|
|
93
|
+
| `--extend` | `-e` | Extend an existing project. |
|
|
94
|
+
| `--help` | `-h` | Show help for create project. |
|
|
95
|
+
|
|
96
|
+
**Examples:**
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Create project myApp with source en and targets fr, de
|
|
100
|
+
msg create project myApp en fr de
|
|
101
|
+
|
|
102
|
+
# Extend an existing project
|
|
103
|
+
msg create project extendedApp en de --extend base
|
|
104
|
+
|
|
105
|
+
# Help
|
|
106
|
+
msg create project -h
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Behavior:**
|
|
110
|
+
|
|
111
|
+
- Writes the file to `i18n/projects/<projectName>.js` or `.ts` (TypeScript if `tsconfig.json` exists).
|
|
112
|
+
- Uses ES module or CommonJS export based on `package.json` `"type"`.
|
|
113
|
+
- Generates a translation loader that imports from `l10n/translations` using the relative path from `i18n/projects` (from `directories` in package.json).
|
|
114
|
+
- With `--extend <name>`, merges target locales and pseudoLocale from the existing project.
|
|
115
|
+
- Errors if the project name already exists, package.json is missing or invalid, or required directories are not configured.
|
|
116
|
+
|
|
117
|
+
### create resource
|
|
118
|
+
|
|
119
|
+
Create a new MsgResource file in the i18n resources directory. Requires `msg init` and a project file in `i18n/projects` (run `msg create project` first).
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
msg create resource <projectName> <title> [-f] [-e]
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
| Argument | Required | Description |
|
|
126
|
+
|-------------|----------|----------------------------------------------------|
|
|
127
|
+
| `projectName` | Yes | Name of the project to import in the MsgResource. |
|
|
128
|
+
| `title` | Yes | Title of the resource and file name (e.g. `messages` → `messages.msg.js`). |
|
|
129
|
+
|
|
130
|
+
| Flag | Short | Description |
|
|
131
|
+
|------------|-------|------------------------------------------|
|
|
132
|
+
| `--force` | `-f` | Overwrite an existing resource file. |
|
|
133
|
+
| `--edit` | `-e` | Open the file for editing after creation.|
|
|
134
|
+
| `--help` | `-h` | Show help for create resource. |
|
|
135
|
+
|
|
136
|
+
**Examples:**
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# Create resource messages for project myProject
|
|
140
|
+
msg create resource myProject messages
|
|
141
|
+
|
|
142
|
+
# Overwrite existing resource
|
|
143
|
+
msg create resource myProject messages --force
|
|
144
|
+
|
|
145
|
+
# Create and open in editor
|
|
146
|
+
msg create resource myProject messages --edit
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Behavior:**
|
|
150
|
+
|
|
151
|
+
- Writes the file to `i18n/resources/<title>.msg.js` or `.msg.ts` (TypeScript if `tsconfig.json` exists).
|
|
152
|
+
- Uses ES module or CommonJS export based on `package.json` `"type"`.
|
|
153
|
+
- Sets `lang` from the project's `sourceLocale` and `dir` to `rtl` for Arabic/Hebrew, `ltr` otherwise.
|
|
154
|
+
- Includes a minimal example message. Validates that the generated file is importable.
|
|
155
|
+
- Errors if i18n/projects or i18n/resources does not exist, the project is not found, or the resource file already exists (unless `--force`).
|
|
156
|
+
|
|
157
|
+
## API Reference
|
|
158
|
+
|
|
159
|
+
The CLI does not expose a programmatic API. For library usage, see [@worldware/msg](https://github.com/worldware-studios/msg).
|
|
160
|
+
|
|
161
|
+
## Development
|
|
162
|
+
|
|
163
|
+
- **Setup:** `npm install`
|
|
164
|
+
- **Build:** `npm run build`
|
|
165
|
+
- **Tests:** `npm run test`
|
|
166
|
+
- **Coverage:** `npm run coverage`
|
|
167
|
+
|
|
168
|
+
Source layout:
|
|
169
|
+
|
|
170
|
+
- `src/commands/` — CLI commands (init, create/project, create/resource).
|
|
171
|
+
- `src/lib/` — Shared utilities, init helpers, create-project helpers, and create-resource helpers.
|
|
172
|
+
- `src/specs/` — Feature and command specs.
|
|
173
|
+
- `src/tests/` — Vitest tests and fixtures.
|
|
174
|
+
|
|
175
|
+
## License
|
|
176
|
+
|
|
177
|
+
MIT. See [LICENSE](LICENSE).
|
|
178
|
+
|
|
179
|
+
## Keywords
|
|
180
|
+
|
|
181
|
+
i18n, l10n, internationalization, localization, xliff, msg, cli
|
package/bin/dev.cmd
ADDED
package/bin/dev.js
ADDED
package/bin/run.cmd
ADDED
package/bin/run.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
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;
|
|
@@ -0,0 +1,169 @@
|
|
|
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 Promise.resolve(`${url}`).then(s => __importStar(require(s)));
|
|
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;
|