intor-cli 0.0.15 → 0.0.17
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/README.md +24 -27
- package/package.json +2 -4
- package/src/cli/commands/check.ts +23 -17
- package/src/cli/commands/discover.ts +32 -0
- package/src/cli/commands/generate.ts +35 -40
- package/src/cli/commands/index.ts +4 -0
- package/src/cli/commands/options/index.ts +1 -0
- package/src/cli/commands/options/options.ts +55 -0
- package/src/cli/commands/utils/normalize-message-files.ts +49 -0
- package/src/cli/commands/utils/normalize-reader-options.ts +15 -28
- package/src/cli/commands/validate.ts +26 -30
- package/src/cli/index.ts +10 -6
- package/src/cli/menu/index.ts +1 -0
- package/src/cli/menu/prompts/prompt-check.ts +74 -0
- package/src/cli/menu/prompts/prompt-discover.ts +25 -0
- package/src/cli/menu/prompts/prompt-generate.ts +106 -0
- package/src/cli/menu/prompts/prompt-validate.ts +49 -0
- package/src/cli/menu/prompts/shared/prompt-reader-options.ts +63 -0
- package/src/cli/menu/prompts/shared/shared.ts +76 -0
- package/src/cli/menu/run.ts +72 -0
- package/src/cli/version.ts +3 -0
- package/src/constants.ts +6 -0
- package/src/core/artifacts/index.ts +5 -0
- package/src/core/artifacts/schema/build-schema.ts +13 -0
- package/src/core/artifacts/schema/index.ts +3 -0
- package/src/core/{generated → artifacts/schema}/read-schema.ts +4 -4
- package/src/core/artifacts/schema/write-schema.ts +14 -0
- package/src/{build/build-types → core/artifacts/types/build}/build-types.ts +9 -10
- package/src/{build/build-types → core/artifacts/types/build}/utils/normalize-rich-infer-node.ts +1 -1
- package/src/{build/build-types → core/artifacts/types/build}/utils/render-infer-node.ts +1 -1
- package/src/core/artifacts/types/index.ts +2 -0
- package/src/core/artifacts/types/write-types.ts +8 -0
- package/src/core/artifacts/types.ts +20 -0
- package/src/core/collect-messages/collect-other-locale-messages.ts +5 -7
- package/src/core/collect-messages/collect-runtime-messages.ts +10 -6
- package/src/core/collect-messages/index.ts +1 -0
- package/src/core/collect-messages/readers.ts +1 -0
- package/src/core/collect-messages/types.ts +7 -1
- package/src/core/constants/index.ts +2 -0
- package/src/core/discover-configs/discover-configs.ts +47 -26
- package/src/core/extract-usages/extract-usages.ts +33 -24
- package/src/core/index.ts +12 -7
- package/src/core/infer-shape/index.ts +4 -0
- package/src/core/{infer-schema/messages/infer-messages-schema.ts → infer-shape/infer-messages-shape.ts} +5 -10
- package/src/core/{infer-schema/replacements/infer-replacements-schema.ts → infer-shape/infer-replacements-shape.ts} +6 -11
- package/src/core/{infer-schema/rich/infer-rich-schema.ts → infer-shape/infer-rich-shape.ts} +5 -10
- package/src/core/infer-shape/infer-shapes.ts +21 -0
- package/src/core/{infer-schema → infer-shape}/types.ts +4 -4
- package/src/core/scan/index.ts +2 -0
- package/src/core/{extract-usages/load-source-files-from-tscofnig.ts → scan/load-source-files.ts} +34 -15
- package/src/core/scan/scan-files.ts +25 -0
- package/src/features/check/build-scoped-usages.ts +35 -0
- package/src/features/check/check.ts +51 -53
- package/src/features/check/diagnostics/collect.ts +6 -2
- package/src/features/check/diagnostics/group.ts +0 -1
- package/src/features/check/index.ts +1 -0
- package/src/features/check/render-config-summary.ts +47 -0
- package/src/features/check/types.ts +12 -0
- package/src/features/discover/discover.ts +22 -0
- package/src/features/discover/index.ts +1 -0
- package/src/features/generate/generate.ts +56 -49
- package/src/features/generate/index.ts +1 -0
- package/src/features/generate/render-overrides.ts +73 -0
- package/src/features/generate/render-summary.ts +28 -0
- package/src/features/generate/types.ts +12 -0
- package/src/features/generate/utils/resolve-message-source.ts +20 -0
- package/src/features/generate/utils/validate-message-source.ts +53 -0
- package/src/features/index.ts +4 -3
- package/src/features/shared/to-relative-path.ts +10 -0
- package/src/features/shared/write-json-report.ts +19 -0
- package/src/features/validate/index.ts +1 -0
- package/src/features/validate/{messages/validate-messages-schema.ts → missing/collect-missing-messages.ts} +5 -5
- package/src/features/validate/{replacements/validate-replacements-schema.ts → missing/collect-missing-replacements.ts} +4 -4
- package/src/features/validate/missing/collect-missing-requirements.ts +44 -0
- package/src/features/validate/{rich/validate-rich-schema.ts → missing/collect-missing-rich.ts} +5 -5
- package/src/features/validate/render-config-summary.ts +47 -0
- package/src/features/validate/render-locale-blocks.ts +56 -0
- package/src/features/validate/types.ts +14 -0
- package/src/features/validate/validate.ts +38 -43
- package/src/logger.ts +95 -0
- package/src/render.ts +57 -0
- package/src/build/build-schemas/build-schemas.ts +0 -13
- package/src/build/build-schemas/index.ts +0 -1
- package/src/build/index.ts +0 -3
- package/src/build/types.ts +0 -20
- package/src/cli/interactive/prompt-generate.ts +0 -121
- package/src/cli/interactive/prompt-validate.ts +0 -101
- package/src/cli/interactive/run.ts +0 -64
- package/src/core/generated/index.ts +0 -6
- package/src/core/generated/write-messages-snapshot.ts +0 -27
- package/src/core/generated/write-schema.ts +0 -9
- package/src/core/generated/write-types.ts +0 -8
- package/src/core/infer-schema/index.ts +0 -4
- package/src/core/infer-schema/infer-schemas.ts +0 -20
- package/src/core/infer-schema/messages/index.ts +0 -1
- package/src/core/infer-schema/replacements/index.ts +0 -1
- package/src/core/infer-schema/rich/index.ts +0 -1
- package/src/core/scan-logger.ts +0 -10
- package/src/features/check/print-summary.ts +0 -28
- package/src/features/generate/print-configs.ts +0 -8
- package/src/features/generate/print-overrides.ts +0 -62
- package/src/features/generate/print-summary.ts +0 -26
- package/src/features/print.ts +0 -43
- package/src/features/validate/messages/index.ts +0 -1
- package/src/features/validate/print-summary.ts +0 -65
- package/src/features/validate/replacements/index.ts +0 -1
- package/src/features/validate/rich/index.ts +0 -1
- package/src/features/validate/validate-locale-messages.ts +0 -38
- /package/src/core/{generated → artifacts}/ensure-and-write.ts +0 -0
- /package/src/{build/build-types → core/artifacts/types/build}/index.ts +0 -0
- /package/src/{build/build-types → core/artifacts/types/build}/output/append-config-block.ts +0 -0
- /package/src/{build/build-types → core/artifacts/types/build}/output/append-footer.ts +0 -0
- /package/src/{build/build-types → core/artifacts/types/build}/output/append-header.ts +0 -0
- /package/src/{build/build-types → core/artifacts/types/build}/output/index.ts +0 -0
- /package/src/{build/build-types → core/artifacts/types/build}/utils/indent.ts +0 -0
- /package/src/core/{infer-schema/replacements → infer-shape/utils}/extract-interpolation-names.ts +0 -0
- /package/src/core/{infer-schema → infer-shape}/utils/infer-object.ts +0 -0
- /package/src/core/{infer-schema → infer-shape}/utils/is-message-object.ts +0 -0
- /package/src/core/{infer-schema → infer-shape}/utils/should-skip-key.ts +0 -0
- /package/src/core/{infer-schema → infer-shape}/utils/strip-internal-keys.ts +0 -0
- /package/src/features/{spinner.ts → shared/spinner.ts} +0 -0
package/README.md
CHANGED
|
@@ -6,59 +6,56 @@
|
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
|
|
9
|
-
<table>
|
|
10
|
-
<tr>
|
|
11
|
-
<td align="center">
|
|
12
|
-
<img src="generate-demo.gif" />
|
|
13
|
-
</td>
|
|
14
|
-
<td align="center">
|
|
15
|
-
<img src="check-demo.gif" />
|
|
16
|
-
</td>
|
|
17
|
-
</tr>
|
|
18
|
-
</table>
|
|
19
9
|
</div>
|
|
20
10
|
|
|
21
11
|
## Overview
|
|
22
12
|
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
13
|
+
- **discover** — config discovery
|
|
14
|
+
- **generate** — schema and type generation
|
|
15
|
+
- **check** — static usage analysis
|
|
25
16
|
- **validate** — locale completeness
|
|
26
17
|
|
|
18
|
+
<img src='demo.gif' />
|
|
19
|
+
|
|
27
20
|
## Commands
|
|
28
21
|
|
|
29
|
-
|
|
22
|
+
Running `intor-cli` without a command launches the interactive menu.
|
|
23
|
+
|
|
24
|
+
### Discover
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx intor-cli discover
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Discovers Intor configs in the current workspace.
|
|
31
|
+
|
|
32
|
+
### Generate
|
|
30
33
|
|
|
31
34
|
```bash
|
|
32
35
|
npx intor-cli generate
|
|
33
36
|
```
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
- Uses the default locale as the single source of truth
|
|
37
|
-
- Reports message override behavior during generation
|
|
38
|
+
Generates schemas and TypeScript types from the default locale.
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
### Check
|
|
40
41
|
|
|
41
42
|
```bash
|
|
42
43
|
npx intor-cli check
|
|
43
44
|
```
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
- Detects incorrect keys, replacements, and rich tag usage
|
|
47
|
-
- Reports diagnostics with precise source locations
|
|
46
|
+
Analyzes translator usage and reports diagnostics.
|
|
48
47
|
|
|
49
|
-
|
|
48
|
+
### Validate
|
|
50
49
|
|
|
51
50
|
```bash
|
|
52
51
|
npx intor-cli validate
|
|
53
52
|
```
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
Validates locale messages against generated schemas.
|
|
55
|
+
|
|
56
|
+
---
|
|
58
57
|
|
|
59
58
|
## Design Guarantees
|
|
60
59
|
|
|
61
|
-
-
|
|
60
|
+
- Schemas and types are inferred **only from the default locale**.
|
|
62
61
|
- All locales are expected to share the same message shape.
|
|
63
|
-
- Locale is treated strictly as a runtime dimension, not a structural one.
|
|
64
|
-
- Generated types are intentionally conservative and do not enforce locale completeness.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "intor-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"description": "The Intor CLI",
|
|
5
5
|
"author": "Yiming Liao",
|
|
6
6
|
"homepage": "https://github.com/yiming-liao/intor-cli#readme",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@intor/reader-yaml": "^0.1.1",
|
|
47
47
|
"cac": "6.7.14",
|
|
48
48
|
"fast-glob": "3.3.3",
|
|
49
|
-
"intor": "2.3.
|
|
49
|
+
"intor": "^2.3.35",
|
|
50
50
|
"logry": "2.1.6",
|
|
51
51
|
"ora": "9.0.0",
|
|
52
52
|
"picocolors": "1.1.1",
|
|
@@ -65,8 +65,6 @@
|
|
|
65
65
|
"eslint-plugin-unused-imports": "4.3.0",
|
|
66
66
|
"knip": "5.79.0",
|
|
67
67
|
"prettier": "3.7.4",
|
|
68
|
-
"remark": "15.0.1",
|
|
69
|
-
"remark-gfm": "4.0.1",
|
|
70
68
|
"typescript": "5.9.3",
|
|
71
69
|
"typescript-eslint": "8.51.0",
|
|
72
70
|
"vitest": "4.0.16"
|
|
@@ -1,33 +1,39 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CliOption } from "./options";
|
|
2
2
|
import type { CAC } from "cac";
|
|
3
|
+
import { features } from "../../constants";
|
|
3
4
|
import { check } from "../../features";
|
|
5
|
+
import { options } from "./options";
|
|
4
6
|
|
|
5
7
|
export function registerCheckCommand(cli: CAC) {
|
|
6
8
|
cli
|
|
7
9
|
// -----------------------------------------------------------------------
|
|
8
10
|
// Command
|
|
9
11
|
// -----------------------------------------------------------------------
|
|
10
|
-
.command(
|
|
12
|
+
.command(features.check.name, features.check.title)
|
|
11
13
|
|
|
12
14
|
// -----------------------------------------------------------------------
|
|
13
|
-
//
|
|
15
|
+
// Options
|
|
14
16
|
// -----------------------------------------------------------------------
|
|
15
|
-
.option(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
)
|
|
19
|
-
.option("--debug", "Enable debug logging")
|
|
17
|
+
.option(...options.debug)
|
|
18
|
+
.option(...options.tsconfig)
|
|
19
|
+
.option(...options.format)
|
|
20
|
+
.option(...options.output)
|
|
20
21
|
|
|
21
22
|
// -----------------------------------------------------------------------
|
|
22
23
|
// Action
|
|
23
24
|
// -----------------------------------------------------------------------
|
|
24
|
-
.action(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
.action(
|
|
26
|
+
async (
|
|
27
|
+
options: Pick<CliOption, "debug" | "tsconfig" | "format" | "output">,
|
|
28
|
+
) => {
|
|
29
|
+
const { debug, tsconfig, format, output } = options;
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
await check({ debug, tsconfigPath: tsconfig, format, output });
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error(error instanceof Error ? error.message : error);
|
|
35
|
+
process.exitCode = 1;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
);
|
|
33
39
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { CliOption } from "./options";
|
|
2
|
+
import type { CAC } from "cac";
|
|
3
|
+
import { features } from "../../constants";
|
|
4
|
+
import { discover } from "../../features";
|
|
5
|
+
import { options } from "./options";
|
|
6
|
+
|
|
7
|
+
export function registerDiscoverCommand(cli: CAC) {
|
|
8
|
+
cli
|
|
9
|
+
// -----------------------------------------------------------------------
|
|
10
|
+
// Command
|
|
11
|
+
// -----------------------------------------------------------------------
|
|
12
|
+
.command(features.discover.name, features.discover.title)
|
|
13
|
+
|
|
14
|
+
// -----------------------------------------------------------------------
|
|
15
|
+
// Options
|
|
16
|
+
// -----------------------------------------------------------------------
|
|
17
|
+
.option(...options.debug)
|
|
18
|
+
|
|
19
|
+
// -----------------------------------------------------------------------
|
|
20
|
+
// Action
|
|
21
|
+
// -----------------------------------------------------------------------
|
|
22
|
+
.action(async (options: Pick<CliOption, "debug">) => {
|
|
23
|
+
const { debug } = options;
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
await discover({ debug });
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error(error instanceof Error ? error.message : error);
|
|
29
|
+
process.exitCode = 1;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CliOption } from "./options";
|
|
2
2
|
import type { CAC } from "cac";
|
|
3
|
+
import { features } from "../../constants";
|
|
3
4
|
import { generate } from "../../features";
|
|
5
|
+
import { version } from "../version";
|
|
6
|
+
import { options } from "./options";
|
|
7
|
+
import { normalizeMessageFiles } from "./utils/normalize-message-files";
|
|
4
8
|
import { normalizeReaderOptions } from "./utils/normalize-reader-options";
|
|
5
9
|
|
|
6
10
|
export function registerGenerateCommand(cli: CAC) {
|
|
@@ -8,53 +12,44 @@ export function registerGenerateCommand(cli: CAC) {
|
|
|
8
12
|
// -----------------------------------------------------------------------
|
|
9
13
|
// Command
|
|
10
14
|
// -----------------------------------------------------------------------
|
|
11
|
-
.command(
|
|
15
|
+
.command(features.generate.name, features.generate.title)
|
|
12
16
|
|
|
13
17
|
// -----------------------------------------------------------------------
|
|
14
18
|
// Option
|
|
15
19
|
// -----------------------------------------------------------------------
|
|
16
|
-
.option(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
)
|
|
20
|
-
.option(
|
|
21
|
-
"--ext <ext>",
|
|
22
|
-
"Enable extra messages file extension (repeatable)",
|
|
23
|
-
{ default: [] },
|
|
24
|
-
)
|
|
25
|
-
.option(
|
|
26
|
-
"--reader <mapping>",
|
|
27
|
-
"Custom reader mapping in the form <ext=path> (repeatable)",
|
|
28
|
-
{ default: [] },
|
|
29
|
-
)
|
|
30
|
-
.option(
|
|
31
|
-
"--debug",
|
|
32
|
-
"Print debug information during config discovery and generation",
|
|
33
|
-
)
|
|
20
|
+
.option(...options.debug)
|
|
21
|
+
.option(...options.messageFile)
|
|
22
|
+
.option(...options.messageFiles)
|
|
23
|
+
.option(...options.ext)
|
|
24
|
+
.option(...options.reader)
|
|
34
25
|
|
|
35
26
|
// -----------------------------------------------------------------------
|
|
36
27
|
// Action
|
|
37
28
|
// -----------------------------------------------------------------------
|
|
38
|
-
.action(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
29
|
+
.action(
|
|
30
|
+
async (
|
|
31
|
+
options: Pick<
|
|
32
|
+
CliOption,
|
|
33
|
+
"debug" | "messageFile" | "messageFiles" | "ext" | "reader"
|
|
34
|
+
>,
|
|
35
|
+
) => {
|
|
36
|
+
const { debug, messageFile, messageFiles, ...readerOptions } = options;
|
|
45
37
|
|
|
46
|
-
|
|
38
|
+
const result = normalizeMessageFiles(messageFile, messageFiles);
|
|
39
|
+
const { exts, customReaders } = normalizeReaderOptions(readerOptions);
|
|
47
40
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
41
|
+
try {
|
|
42
|
+
await generate({
|
|
43
|
+
debug,
|
|
44
|
+
messageSource: result,
|
|
45
|
+
exts,
|
|
46
|
+
customReaders,
|
|
47
|
+
toolVersion: version,
|
|
48
|
+
});
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error(error instanceof Error ? error.message : error);
|
|
51
|
+
process.exitCode = 1;
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
);
|
|
60
55
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { options, type CliOptions as CliOption } from "./options";
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { CAC } from "cac";
|
|
2
|
+
|
|
3
|
+
export const options = {
|
|
4
|
+
debug: ["--debug", "Enable debug logging", { default: false }],
|
|
5
|
+
|
|
6
|
+
tsconfig: [
|
|
7
|
+
"--tsconfig <path>",
|
|
8
|
+
"Path to tsconfig.json (default: tsconfig.json)",
|
|
9
|
+
],
|
|
10
|
+
|
|
11
|
+
messageFile: [
|
|
12
|
+
"--message-file <file>",
|
|
13
|
+
"Explicit message file for single-config projects",
|
|
14
|
+
],
|
|
15
|
+
|
|
16
|
+
messageFiles: [
|
|
17
|
+
"--message-files <mapping...>",
|
|
18
|
+
"Explicit message file mapping in the form <configId=path> (repeatable)",
|
|
19
|
+
{ default: [] },
|
|
20
|
+
],
|
|
21
|
+
|
|
22
|
+
ext: [
|
|
23
|
+
"--ext <ext>",
|
|
24
|
+
"Enable extra messages file extension (repeatable)",
|
|
25
|
+
{ default: [] },
|
|
26
|
+
],
|
|
27
|
+
|
|
28
|
+
reader: [
|
|
29
|
+
"--reader <mapping>",
|
|
30
|
+
"Custom reader mapping in the form <ext=path> (repeatable)",
|
|
31
|
+
{ default: [] },
|
|
32
|
+
],
|
|
33
|
+
|
|
34
|
+
format: [
|
|
35
|
+
"--format <format>",
|
|
36
|
+
"Output format: human | json",
|
|
37
|
+
{ default: "human" },
|
|
38
|
+
],
|
|
39
|
+
|
|
40
|
+
output: [
|
|
41
|
+
"--output <file>",
|
|
42
|
+
"Write output to file (only applies to json format)",
|
|
43
|
+
],
|
|
44
|
+
} as const satisfies Record<string, Parameters<CAC["option"]>>;
|
|
45
|
+
|
|
46
|
+
export interface CliOptions {
|
|
47
|
+
debug?: boolean;
|
|
48
|
+
tsconfig?: string;
|
|
49
|
+
messageFile?: string;
|
|
50
|
+
messageFiles?: string[];
|
|
51
|
+
ext?: string[];
|
|
52
|
+
reader?: string[];
|
|
53
|
+
format?: "human" | "json";
|
|
54
|
+
output?: string;
|
|
55
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { MessageSource } from "../../../features";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Normalize message file CLI options into a MessageSource.
|
|
5
|
+
*/
|
|
6
|
+
export function normalizeMessageFiles(
|
|
7
|
+
messageFile?: string,
|
|
8
|
+
messageFiles: string[] = [],
|
|
9
|
+
): MessageSource {
|
|
10
|
+
if (messageFile && messageFiles.length > 0) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
"Cannot use --message-file and --message-files at the same time.",
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// --------------------------------------------------
|
|
17
|
+
// single mode
|
|
18
|
+
// --------------------------------------------------
|
|
19
|
+
if (messageFile) {
|
|
20
|
+
return {
|
|
21
|
+
mode: "single",
|
|
22
|
+
file: messageFile,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// --------------------------------------------------
|
|
27
|
+
// mapping mode
|
|
28
|
+
// --------------------------------------------------
|
|
29
|
+
if (messageFiles.length > 0) {
|
|
30
|
+
const files: Record<string, string> = {};
|
|
31
|
+
|
|
32
|
+
for (const messageFile of messageFiles) {
|
|
33
|
+
const [id, path] = messageFile.split("=", 2);
|
|
34
|
+
if (!id || !path) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`Invalid --message-files entry: "${messageFile}". Each entry must be in the form: <configId=path>`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
files[id] = path;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
mode: "mapping",
|
|
44
|
+
files,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return { mode: "none" };
|
|
49
|
+
}
|
|
@@ -1,46 +1,33 @@
|
|
|
1
|
-
import type { ExtraExt } from "../../../core";
|
|
2
|
-
|
|
3
|
-
export interface NormalizedReaderOptions {
|
|
4
|
-
exts: ExtraExt[];
|
|
5
|
-
customReaders?: Record<string, string>;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface RawReaderOptions {
|
|
9
|
-
ext?: string | string[];
|
|
10
|
-
reader?: string[];
|
|
11
|
-
}
|
|
1
|
+
import type { ReaderOptions, ExtraExt } from "../../../core";
|
|
2
|
+
import type { CliOptions } from "../options/options";
|
|
12
3
|
|
|
13
4
|
/**
|
|
14
|
-
* Normalize CLI reader-related options
|
|
15
|
-
* - ext: string | string[] → string[]
|
|
16
|
-
* - reader: ["md=./reader.ts"] → { md: "./reader.ts" }
|
|
5
|
+
* Normalize CLI reader-related options
|
|
17
6
|
*/
|
|
18
|
-
export function normalizeReaderOptions(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const exts = options.ext
|
|
23
|
-
? Array.isArray(options.ext)
|
|
24
|
-
? options.ext
|
|
25
|
-
: [options.ext]
|
|
26
|
-
: [];
|
|
27
|
-
|
|
7
|
+
export function normalizeReaderOptions({
|
|
8
|
+
ext = [],
|
|
9
|
+
reader = [],
|
|
10
|
+
}: Pick<CliOptions, "ext" | "reader">): ReaderOptions {
|
|
28
11
|
// Normalize custom readers
|
|
29
12
|
let customReaders: Record<string, string> | undefined;
|
|
30
13
|
|
|
31
|
-
if (
|
|
14
|
+
if (reader && reader.length > 0) {
|
|
32
15
|
customReaders = {};
|
|
33
16
|
|
|
34
|
-
for (const item of
|
|
17
|
+
for (const item of reader) {
|
|
35
18
|
const [key, value] = item.split("=", 2);
|
|
36
|
-
if (!key || !value)
|
|
19
|
+
if (!key || !value) {
|
|
20
|
+
throw new Error(
|
|
21
|
+
`Invalid --reader entry: "${item}". Each entry must be in the form: <ext=path>`,
|
|
22
|
+
);
|
|
23
|
+
}
|
|
37
24
|
|
|
38
25
|
customReaders[key] = value;
|
|
39
26
|
}
|
|
40
27
|
}
|
|
41
28
|
|
|
42
29
|
return {
|
|
43
|
-
exts:
|
|
30
|
+
exts: ext as ExtraExt[],
|
|
44
31
|
customReaders,
|
|
45
32
|
};
|
|
46
33
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CliOptions } from "./options/options";
|
|
2
2
|
import type { CAC } from "cac";
|
|
3
|
+
import { features } from "../../constants";
|
|
3
4
|
import { validate } from "../../features";
|
|
5
|
+
import { options } from "./options";
|
|
4
6
|
import { normalizeReaderOptions } from "./utils/normalize-reader-options";
|
|
5
7
|
|
|
6
8
|
export function registerValidateCommand(cli: CAC) {
|
|
@@ -8,43 +10,37 @@ export function registerValidateCommand(cli: CAC) {
|
|
|
8
10
|
// -----------------------------------------------------------------------
|
|
9
11
|
// Command
|
|
10
12
|
// -----------------------------------------------------------------------
|
|
11
|
-
.command(
|
|
13
|
+
.command(features.validate.name, features.validate.title)
|
|
12
14
|
|
|
13
15
|
// -----------------------------------------------------------------------
|
|
14
16
|
// Option
|
|
15
17
|
// -----------------------------------------------------------------------
|
|
16
|
-
.option(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
)
|
|
21
|
-
.option(
|
|
22
|
-
"--reader <mapping>",
|
|
23
|
-
"Custom reader mapping in the form <ext=path> (repeatable)",
|
|
24
|
-
{ default: [] },
|
|
25
|
-
)
|
|
26
|
-
.option(
|
|
27
|
-
"--debug",
|
|
28
|
-
"Print debug information during config discovery and generation",
|
|
29
|
-
)
|
|
18
|
+
.option(...options.debug)
|
|
19
|
+
.option(...options.ext)
|
|
20
|
+
.option(...options.reader)
|
|
21
|
+
.option(...options.format)
|
|
22
|
+
.option(...options.output)
|
|
30
23
|
|
|
31
24
|
// -----------------------------------------------------------------------
|
|
32
25
|
// Action
|
|
33
26
|
// -----------------------------------------------------------------------
|
|
34
|
-
.action(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
27
|
+
.action(
|
|
28
|
+
async (
|
|
29
|
+
options: Pick<
|
|
30
|
+
CliOptions,
|
|
31
|
+
"debug" | "ext" | "reader" | "format" | "output"
|
|
32
|
+
>,
|
|
33
|
+
) => {
|
|
34
|
+
const { debug, format, output, ...readerOptions } = options;
|
|
40
35
|
|
|
41
|
-
|
|
36
|
+
const { exts, customReaders } = normalizeReaderOptions(readerOptions);
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
38
|
+
try {
|
|
39
|
+
await validate({ debug, format, output, exts, customReaders });
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error(error instanceof Error ? error.message : error);
|
|
42
|
+
process.exitCode = 1;
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
);
|
|
50
46
|
}
|
package/src/cli/index.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
2
|
|
|
3
3
|
import { cac } from "cac";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
import {
|
|
5
|
+
registerDiscoverCommand,
|
|
6
|
+
registerGenerateCommand,
|
|
7
|
+
registerCheckCommand,
|
|
8
|
+
registerValidateCommand,
|
|
9
|
+
} from "./commands";
|
|
10
|
+
import { run } from "./menu";
|
|
8
11
|
|
|
9
12
|
const VERSION = "0.1.10";
|
|
10
13
|
|
|
@@ -13,10 +16,10 @@ async function main() {
|
|
|
13
16
|
const args = process.argv.slice(2);
|
|
14
17
|
|
|
15
18
|
// -------------------------------------------------------------------
|
|
16
|
-
// Interactive
|
|
19
|
+
// Interactive menu bypasses CAC entirely
|
|
17
20
|
// -------------------------------------------------------------------
|
|
18
21
|
if (args.length === 0) {
|
|
19
|
-
await
|
|
22
|
+
await run();
|
|
20
23
|
return;
|
|
21
24
|
}
|
|
22
25
|
|
|
@@ -25,6 +28,7 @@ async function main() {
|
|
|
25
28
|
// -------------------------------------------------------------------
|
|
26
29
|
const cli = cac("intor");
|
|
27
30
|
|
|
31
|
+
registerDiscoverCommand(cli);
|
|
28
32
|
registerGenerateCommand(cli);
|
|
29
33
|
registerCheckCommand(cli);
|
|
30
34
|
registerValidateCommand(cli);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { run } from "./run";
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { CheckOptions } from "../../../features";
|
|
2
|
+
import { text, isCancel, confirm } from "@clack/prompts";
|
|
3
|
+
import {
|
|
4
|
+
promptMode,
|
|
5
|
+
promptDebug,
|
|
6
|
+
printOptionsSummary,
|
|
7
|
+
promptFormat,
|
|
8
|
+
promptOutput,
|
|
9
|
+
} from "./shared/shared";
|
|
10
|
+
|
|
11
|
+
export async function promptCheck(): Promise<CheckOptions | null> {
|
|
12
|
+
// ------------------------------------------------------------------
|
|
13
|
+
// Mode
|
|
14
|
+
// ------------------------------------------------------------------
|
|
15
|
+
const mode = await promptMode();
|
|
16
|
+
if (!mode) return null;
|
|
17
|
+
if (mode === "default") return {};
|
|
18
|
+
|
|
19
|
+
const options: CheckOptions = {};
|
|
20
|
+
|
|
21
|
+
// ------------------------------------------------------------------
|
|
22
|
+
// tsconfig path
|
|
23
|
+
// ------------------------------------------------------------------
|
|
24
|
+
const useCustomTsconfig = await confirm({
|
|
25
|
+
message: "Do you want to use a custom tsconfig file?",
|
|
26
|
+
initialValue: false,
|
|
27
|
+
});
|
|
28
|
+
if (isCancel(useCustomTsconfig)) return null;
|
|
29
|
+
|
|
30
|
+
if (useCustomTsconfig) {
|
|
31
|
+
const path = await text({
|
|
32
|
+
message: "Path to tsconfig file",
|
|
33
|
+
placeholder: "tsconfig.json",
|
|
34
|
+
defaultValue: "tsconfig.json",
|
|
35
|
+
});
|
|
36
|
+
if (isCancel(path)) return null;
|
|
37
|
+
options.tsconfigPath = path || undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ------------------------------------------------------------------
|
|
41
|
+
// Output format
|
|
42
|
+
// ------------------------------------------------------------------
|
|
43
|
+
const format = await promptFormat();
|
|
44
|
+
if (!format) return null;
|
|
45
|
+
options.format = format;
|
|
46
|
+
|
|
47
|
+
// ------------------------------------------------------------------
|
|
48
|
+
// Output file (only for json)
|
|
49
|
+
// ------------------------------------------------------------------
|
|
50
|
+
if (format === "json") {
|
|
51
|
+
const output = await promptOutput();
|
|
52
|
+
if (output === null) return null;
|
|
53
|
+
options.output = output;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ------------------------------------------------------------------
|
|
57
|
+
// Debug
|
|
58
|
+
// ------------------------------------------------------------------
|
|
59
|
+
const debug = await promptDebug();
|
|
60
|
+
if (debug === null) return null;
|
|
61
|
+
if (debug) options.debug = true;
|
|
62
|
+
|
|
63
|
+
// ------------------------------------------------------------------
|
|
64
|
+
// Summary
|
|
65
|
+
// ------------------------------------------------------------------
|
|
66
|
+
printOptionsSummary("Check options", [
|
|
67
|
+
["tsconfig", options.tsconfigPath ?? "tsconfig.json"],
|
|
68
|
+
["format", options.format ?? "human"],
|
|
69
|
+
["output", options.output ?? "stdout"],
|
|
70
|
+
["debug", options.debug ? "on" : "off"],
|
|
71
|
+
]);
|
|
72
|
+
|
|
73
|
+
return options;
|
|
74
|
+
}
|