@formatjs/cli-lib 8.5.0 → 8.5.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/gts_extractor-Dc-C_f4R.js +14 -0
- package/gts_extractor-Dc-C_f4R.js.map +1 -0
- package/{src/hbs_extractor.js → hbs_extractor-Eiqkz4d7.js} +9 -8
- package/hbs_extractor-Eiqkz4d7.js.map +1 -0
- package/index.d.ts +144 -7
- package/index.js +633 -2
- package/index.js.map +1 -0
- package/package.json +5 -5
- package/parse_script-EspfGgzZ.js +93 -0
- package/parse_script-EspfGgzZ.js.map +1 -0
- package/{src/svelte_extractor.js → svelte_extractor-Fr1Z3JHX.js} +16 -37
- package/svelte_extractor-Fr1Z3JHX.js.map +1 -0
- package/vue_extractor-Btw05cfG.js +41 -0
- package/vue_extractor-Btw05cfG.js.map +1 -0
- package/main.d.ts +0 -1
- package/main.js +0 -3
- package/src/cli.d.ts +0 -2
- package/src/cli.js +0 -145
- package/src/compile.d.ts +0 -63
- package/src/compile.js +0 -95
- package/src/compile_folder.d.ts +0 -2
- package/src/compile_folder.js +0 -8
- package/src/console_utils.d.ts +0 -7
- package/src/console_utils.js +0 -62
- package/src/extract.d.ts +0 -87
- package/src/extract.js +0 -212
- package/src/formatters/crowdin.d.ts +0 -7
- package/src/formatters/crowdin.js +0 -21
- package/src/formatters/default.d.ts +0 -6
- package/src/formatters/default.js +0 -9
- package/src/formatters/index.d.ts +0 -9
- package/src/formatters/index.js +0 -31
- package/src/formatters/lokalise.d.ts +0 -9
- package/src/formatters/lokalise.js +0 -18
- package/src/formatters/simple.d.ts +0 -4
- package/src/formatters/simple.js +0 -8
- package/src/formatters/smartling.d.ts +0 -21
- package/src/formatters/smartling.js +0 -39
- package/src/formatters/transifex.d.ts +0 -9
- package/src/formatters/transifex.js +0 -18
- package/src/gts_extractor.d.ts +0 -1
- package/src/gts_extractor.js +0 -14
- package/src/hbs_extractor.d.ts +0 -1
- package/src/parse_script.d.ts +0 -7
- package/src/parse_script.js +0 -43
- package/src/pseudo_locale.d.ts +0 -22
- package/src/pseudo_locale.js +0 -231
- package/src/svelte_extractor.d.ts +0 -2
- package/src/verify/checkExtraKeys.d.ts +0 -1
- package/src/verify/checkExtraKeys.js +0 -32
- package/src/verify/checkMissingKeys.d.ts +0 -1
- package/src/verify/checkMissingKeys.js +0 -33
- package/src/verify/checkStructuralEquality.d.ts +0 -1
- package/src/verify/checkStructuralEquality.js +0 -71
- package/src/verify/index.d.ts +0 -13
- package/src/verify/index.js +0 -26
- package/src/vue_extractor.d.ts +0 -2
- package/src/vue_extractor.js +0 -58
package/src/compile.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { parse } from "@formatjs/icu-messageformat-parser";
|
|
2
|
-
import { outputFile } from "fs-extra/esm";
|
|
3
|
-
import { readFile } from "fs/promises";
|
|
4
|
-
import * as stringifyNs from "json-stable-stringify";
|
|
5
|
-
import { debug, warn, writeStdout } from "./console_utils.js";
|
|
6
|
-
import { resolveBuiltinFormatter } from "./formatters/index.js";
|
|
7
|
-
import { generateENXA, generateENXB, generateXXAC, generateXXHA, generateXXLS } from "./pseudo_locale.js";
|
|
8
|
-
const stringify = stringifyNs.default || stringifyNs;
|
|
9
|
-
/**
|
|
10
|
-
* Aggregate `inputFiles` into a single JSON blob and compile.
|
|
11
|
-
* Also checks for conflicting IDs.
|
|
12
|
-
* Then returns the serialized result as a `string` since key order
|
|
13
|
-
* makes a difference in some vendor.
|
|
14
|
-
* @param inputFiles Input files
|
|
15
|
-
* @param opts Options
|
|
16
|
-
* @returns serialized result in string format
|
|
17
|
-
*/
|
|
18
|
-
export async function compile(inputFiles, opts = {}) {
|
|
19
|
-
debug("Compiling files:", inputFiles);
|
|
20
|
-
const { ast, format, pseudoLocale, skipErrors, ignoreTag, signal } = opts;
|
|
21
|
-
signal?.throwIfAborted();
|
|
22
|
-
const formatter = await resolveBuiltinFormatter(format);
|
|
23
|
-
const messages = {};
|
|
24
|
-
const messageAsts = {};
|
|
25
|
-
const idsWithFileName = {};
|
|
26
|
-
const compiledFiles = await Promise.all(inputFiles.map((f) => readFile(f, {
|
|
27
|
-
encoding: "utf8",
|
|
28
|
-
signal
|
|
29
|
-
}).then((content) => JSON.parse(content)).then(formatter.compile)));
|
|
30
|
-
debug("Compiled files:", compiledFiles);
|
|
31
|
-
for (let i = 0; i < inputFiles.length; i++) {
|
|
32
|
-
const inputFile = inputFiles[i];
|
|
33
|
-
debug("Processing file:", inputFile);
|
|
34
|
-
const compiled = compiledFiles[i];
|
|
35
|
-
for (const id in compiled) {
|
|
36
|
-
if (messages[id] && messages[id] !== compiled[id]) {
|
|
37
|
-
throw new Error(`Conflicting ID "${id}" with different translation found in these 2 files:
|
|
38
|
-
ID: ${id}
|
|
39
|
-
Message from ${idsWithFileName[id]}: ${messages[id]}
|
|
40
|
-
Message from ${inputFile}: ${compiled[id]}
|
|
41
|
-
`);
|
|
42
|
-
}
|
|
43
|
-
try {
|
|
44
|
-
const msgAst = parse(compiled[id], { ignoreTag });
|
|
45
|
-
messages[id] = compiled[id];
|
|
46
|
-
switch (pseudoLocale) {
|
|
47
|
-
case "xx-LS":
|
|
48
|
-
messageAsts[id] = generateXXLS(msgAst);
|
|
49
|
-
break;
|
|
50
|
-
case "xx-AC":
|
|
51
|
-
messageAsts[id] = generateXXAC(msgAst);
|
|
52
|
-
break;
|
|
53
|
-
case "xx-HA":
|
|
54
|
-
messageAsts[id] = generateXXHA(msgAst);
|
|
55
|
-
break;
|
|
56
|
-
case "en-XA":
|
|
57
|
-
messageAsts[id] = generateENXA(msgAst);
|
|
58
|
-
break;
|
|
59
|
-
case "en-XB":
|
|
60
|
-
messageAsts[id] = generateENXB(msgAst);
|
|
61
|
-
break;
|
|
62
|
-
default:
|
|
63
|
-
messageAsts[id] = msgAst;
|
|
64
|
-
break;
|
|
65
|
-
}
|
|
66
|
-
idsWithFileName[id] = inputFile;
|
|
67
|
-
} catch (e) {
|
|
68
|
-
warn("Error validating message \"%s\" with ID \"%s\" in file \"%s\"", compiled[id], id, inputFile);
|
|
69
|
-
if (!skipErrors) {
|
|
70
|
-
throw e;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return stringify(ast ? messageAsts : messages, {
|
|
76
|
-
space: 2,
|
|
77
|
-
cmp: formatter.compareMessages || undefined
|
|
78
|
-
}) ?? "";
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Aggregate `inputFiles` into a single JSON blob and compile.
|
|
82
|
-
* Also checks for conflicting IDs and write output to `outFile`.
|
|
83
|
-
* @param inputFiles Input files
|
|
84
|
-
* @param compileOpts options
|
|
85
|
-
* @returns A `Promise` that resolves if file was written successfully
|
|
86
|
-
*/
|
|
87
|
-
export default async function compileAndWrite(inputFiles, compileOpts = {}) {
|
|
88
|
-
const { outFile, ...opts } = compileOpts;
|
|
89
|
-
const serializedResult = await compile(inputFiles, opts) + "\n";
|
|
90
|
-
if (outFile) {
|
|
91
|
-
debug("Writing output file:", outFile);
|
|
92
|
-
return outputFile(outFile, serializedResult);
|
|
93
|
-
}
|
|
94
|
-
await writeStdout(serializedResult);
|
|
95
|
-
}
|
package/src/compile_folder.d.ts
DELETED
package/src/compile_folder.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { outputFile } from "fs-extra/esm";
|
|
2
|
-
import { basename, join } from "path";
|
|
3
|
-
import { compile } from "./compile.js";
|
|
4
|
-
export default async function compileFolder(files, outFolder, opts = {}) {
|
|
5
|
-
const results = await Promise.all(files.map((f) => compile([f], opts)));
|
|
6
|
-
const outFiles = files.map((f) => join(outFolder, basename(f)));
|
|
7
|
-
return Promise.all(outFiles.map((outFile, i) => outputFile(outFile, results[i])));
|
|
8
|
-
}
|
package/src/console_utils.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export declare const writeStderr: (arg1: string | Uint8Array) => Promise<void>;
|
|
2
|
-
export declare const writeStdout: (arg1: string | Uint8Array) => Promise<void>;
|
|
3
|
-
export declare function clearLine(terminal: (typeof process)["stderr"]): Promise<void>;
|
|
4
|
-
export declare function debug(message: string, ...args: any[]): Promise<void>;
|
|
5
|
-
export declare function warn(message: string, ...args: any[]): Promise<void>;
|
|
6
|
-
export declare function error(message: string, ...args: any[]): Promise<void>;
|
|
7
|
-
export declare function getStdinAsString(): Promise<string>;
|
package/src/console_utils.js
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { clearLine as nativeClearLine, cursorTo as nativeCursorTo } from "readline";
|
|
2
|
-
import { format, promisify, styleText } from "node:util";
|
|
3
|
-
const CLEAR_WHOLE_LINE = 0;
|
|
4
|
-
export const writeStderr = promisify(process.stderr.write).bind(process.stderr);
|
|
5
|
-
export const writeStdout = promisify(process.stdout.write).bind(process.stdout);
|
|
6
|
-
// From:
|
|
7
|
-
// https://github.com/yarnpkg/yarn/blob/53d8004229f543f342833310d5af63a4b6e59c8a/src/reporters/console/util.js
|
|
8
|
-
export async function clearLine(terminal) {
|
|
9
|
-
if (!terminal.hasColors?.()) {
|
|
10
|
-
if (terminal.isTTY) {
|
|
11
|
-
// terminal
|
|
12
|
-
if (terminal.columns > 0) {
|
|
13
|
-
await writeStderr(`\r${" ".repeat(terminal.columns - 1)}`);
|
|
14
|
-
}
|
|
15
|
-
await writeStderr(`\r`);
|
|
16
|
-
}
|
|
17
|
-
} else {
|
|
18
|
-
nativeClearLine(terminal, CLEAR_WHOLE_LINE);
|
|
19
|
-
nativeCursorTo(terminal, 0, undefined);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
const LEVEL_COLORS = {
|
|
23
|
-
debug: "green",
|
|
24
|
-
warn: "yellow",
|
|
25
|
-
error: "red"
|
|
26
|
-
};
|
|
27
|
-
function label(level, message) {
|
|
28
|
-
return `[@formatjs/cli] [${styleText(LEVEL_COLORS[level], level.toUpperCase())}] ${message}`;
|
|
29
|
-
}
|
|
30
|
-
export async function debug(message, ...args) {
|
|
31
|
-
if (process.env.LOG_LEVEL !== "debug") {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
await clearLine(process.stderr);
|
|
35
|
-
await writeStderr(format(label("debug", message), ...args));
|
|
36
|
-
await writeStderr("\n");
|
|
37
|
-
}
|
|
38
|
-
export async function warn(message, ...args) {
|
|
39
|
-
await clearLine(process.stderr);
|
|
40
|
-
await writeStderr(format(label("warn", message), ...args));
|
|
41
|
-
await writeStderr("\n");
|
|
42
|
-
}
|
|
43
|
-
export async function error(message, ...args) {
|
|
44
|
-
await clearLine(process.stderr);
|
|
45
|
-
await writeStderr(format(label("error", message), ...args));
|
|
46
|
-
await writeStderr("\n");
|
|
47
|
-
}
|
|
48
|
-
export function getStdinAsString() {
|
|
49
|
-
let result = "";
|
|
50
|
-
return new Promise((resolve) => {
|
|
51
|
-
process.stdin.setEncoding("utf-8");
|
|
52
|
-
process.stdin.on("readable", () => {
|
|
53
|
-
let chunk;
|
|
54
|
-
while (chunk = process.stdin.read()) {
|
|
55
|
-
result += chunk;
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
process.stdin.on("end", () => {
|
|
59
|
-
resolve(result);
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
}
|
package/src/extract.d.ts
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { type MessageDescriptor, type Opts } from "@formatjs/ts-transformer";
|
|
2
|
-
import { type Formatter } from "./formatters/index.js";
|
|
3
|
-
export interface ExtractionResult<M = Record<string, string>> {
|
|
4
|
-
/**
|
|
5
|
-
* List of extracted messages
|
|
6
|
-
*/
|
|
7
|
-
messages: MessageDescriptor[];
|
|
8
|
-
/**
|
|
9
|
-
* Metadata extracted w/ `pragma`
|
|
10
|
-
*/
|
|
11
|
-
meta?: M;
|
|
12
|
-
}
|
|
13
|
-
export interface ExtractedMessageDescriptor extends MessageDescriptor {
|
|
14
|
-
/**
|
|
15
|
-
* Line number
|
|
16
|
-
*/
|
|
17
|
-
line?: number;
|
|
18
|
-
/**
|
|
19
|
-
* Column number
|
|
20
|
-
*/
|
|
21
|
-
col?: number;
|
|
22
|
-
/**
|
|
23
|
-
* Metadata extracted from pragma
|
|
24
|
-
*/
|
|
25
|
-
meta?: Record<string, string>;
|
|
26
|
-
}
|
|
27
|
-
export type ExtractCLIOptions = Omit<ExtractOpts, "overrideIdFn" | "onMsgExtracted" | "onMetaExtracted"> & {
|
|
28
|
-
/**
|
|
29
|
-
* Output File
|
|
30
|
-
*/
|
|
31
|
-
outFile?: string;
|
|
32
|
-
/**
|
|
33
|
-
* Input File
|
|
34
|
-
*/
|
|
35
|
-
inFile?: string;
|
|
36
|
-
/**
|
|
37
|
-
* Ignore file glob pattern
|
|
38
|
-
*/
|
|
39
|
-
ignore?: string[];
|
|
40
|
-
/**
|
|
41
|
-
* Whether to follow symbolic links when traversing directories.
|
|
42
|
-
* Defaults to true for compatibility with pnpm symlinked node_modules.
|
|
43
|
-
*/
|
|
44
|
-
followLinks?: boolean;
|
|
45
|
-
};
|
|
46
|
-
export type ExtractOpts = Opts & {
|
|
47
|
-
/**
|
|
48
|
-
* Whether to throw an error if we had any issues with
|
|
49
|
-
* 1 of the source files
|
|
50
|
-
*/
|
|
51
|
-
throws?: boolean;
|
|
52
|
-
/**
|
|
53
|
-
* Message ID interpolation pattern
|
|
54
|
-
*/
|
|
55
|
-
idInterpolationPattern?: string;
|
|
56
|
-
/**
|
|
57
|
-
* Whether we read from stdin instead of a file
|
|
58
|
-
*/
|
|
59
|
-
readFromStdin?: boolean;
|
|
60
|
-
/**
|
|
61
|
-
* Either path to a formatter file that controls the shape of JSON file from `outFile` or {@link Formatter} object.
|
|
62
|
-
*/
|
|
63
|
-
format?: string | Formatter<any>;
|
|
64
|
-
/**
|
|
65
|
-
* Whether to hoist selectors & flatten sentences
|
|
66
|
-
*/
|
|
67
|
-
flatten?: boolean;
|
|
68
|
-
/**
|
|
69
|
-
* An AbortSignal to cancel the extraction
|
|
70
|
-
*/
|
|
71
|
-
signal?: AbortSignal;
|
|
72
|
-
} & Pick<Opts, "onMsgExtracted" | "onMetaExtracted">;
|
|
73
|
-
/**
|
|
74
|
-
* Extract strings from source files
|
|
75
|
-
* @param files list of files
|
|
76
|
-
* @param extractOpts extract options
|
|
77
|
-
* @returns messages serialized as JSON string since key order
|
|
78
|
-
* matters for some `format`
|
|
79
|
-
*/
|
|
80
|
-
export declare function extract(files: readonly string[], extractOpts: ExtractOpts): Promise<string>;
|
|
81
|
-
/**
|
|
82
|
-
* Extract strings from source files, also writes to a file.
|
|
83
|
-
* @param files list of files
|
|
84
|
-
* @param extractOpts extract options
|
|
85
|
-
* @returns A Promise that resolves if output file was written successfully
|
|
86
|
-
*/
|
|
87
|
-
export default function extractAndWrite(files: readonly string[], extractOpts: ExtractCLIOptions): Promise<void>;
|
package/src/extract.js
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
import { interpolateName } from "@formatjs/ts-transformer";
|
|
2
|
-
import { outputFile } from "fs-extra/esm";
|
|
3
|
-
import { debug, getStdinAsString, warn, writeStdout } from "./console_utils.js";
|
|
4
|
-
import * as stringifyNs from "json-stable-stringify";
|
|
5
|
-
import { resolveBuiltinFormatter } from "./formatters/index.js";
|
|
6
|
-
import { parseScript } from "./parse_script.js";
|
|
7
|
-
import { readFile } from "fs/promises";
|
|
8
|
-
const stringify = stringifyNs.default || stringifyNs;
|
|
9
|
-
function calculateLineColFromOffset(text, start) {
|
|
10
|
-
if (!start) {
|
|
11
|
-
return {
|
|
12
|
-
line: 1,
|
|
13
|
-
col: 1
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
const chunk = text.slice(0, start);
|
|
17
|
-
const lines = chunk.split("\n");
|
|
18
|
-
const lastLine = lines[lines.length - 1];
|
|
19
|
-
return {
|
|
20
|
-
line: lines.length,
|
|
21
|
-
col: lastLine.length
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
async function processFile(source, fn, { idInterpolationPattern, ...opts }) {
|
|
25
|
-
let messages = [];
|
|
26
|
-
let meta;
|
|
27
|
-
const onMsgExtracted = opts.onMsgExtracted;
|
|
28
|
-
const onMetaExtracted = opts.onMetaExtracted;
|
|
29
|
-
opts = {
|
|
30
|
-
...opts,
|
|
31
|
-
additionalComponentNames: ["$formatMessage", ...opts.additionalComponentNames || []],
|
|
32
|
-
onMsgExtracted(filePath, msgs) {
|
|
33
|
-
if (opts.extractSourceLocation) {
|
|
34
|
-
msgs = msgs.map((msg) => ({
|
|
35
|
-
...msg,
|
|
36
|
-
...calculateLineColFromOffset(source, msg.start)
|
|
37
|
-
}));
|
|
38
|
-
}
|
|
39
|
-
messages = messages.concat(msgs);
|
|
40
|
-
if (onMsgExtracted) {
|
|
41
|
-
onMsgExtracted(filePath, msgs);
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
onMetaExtracted(filePath, m) {
|
|
45
|
-
meta = m;
|
|
46
|
-
if (onMetaExtracted) {
|
|
47
|
-
onMetaExtracted(filePath, m);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
if (!opts.overrideIdFn && idInterpolationPattern) {
|
|
52
|
-
opts = {
|
|
53
|
-
...opts,
|
|
54
|
-
overrideIdFn: (id, defaultMessage, description, fileName) => id || interpolateName({ resourcePath: fileName }, idInterpolationPattern, { content: description ? `${defaultMessage}#${typeof description === "string" ? description : stringify(description)}` : defaultMessage })
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
debug("Processing opts for %s: %s", fn, opts);
|
|
58
|
-
const scriptParseFn = parseScript(opts, fn);
|
|
59
|
-
if (fn.endsWith(".vue")) {
|
|
60
|
-
debug("Processing %s using vue extractor", fn);
|
|
61
|
-
const { parseFile } = await import("./vue_extractor.js");
|
|
62
|
-
parseFile(source, fn, scriptParseFn);
|
|
63
|
-
} else if (fn.endsWith(".svelte")) {
|
|
64
|
-
debug("Processing %s using svelte extractor", fn);
|
|
65
|
-
const { parseFile } = await import("./svelte_extractor.js");
|
|
66
|
-
parseFile(source, fn, scriptParseFn);
|
|
67
|
-
} else if (fn.endsWith(".hbs")) {
|
|
68
|
-
debug("Processing %s using hbs extractor", fn);
|
|
69
|
-
const { parseFile } = await import("./hbs_extractor.js");
|
|
70
|
-
parseFile(source, fn, opts);
|
|
71
|
-
} else if (fn.endsWith(".gts") || fn.endsWith(".gjs")) {
|
|
72
|
-
debug("Processing %s as gts/gjs file", fn);
|
|
73
|
-
const { parseFile } = await import("./gts_extractor.js");
|
|
74
|
-
parseFile(source, fn, opts);
|
|
75
|
-
} else {
|
|
76
|
-
debug("Processing %s using typescript extractor", fn);
|
|
77
|
-
scriptParseFn(source);
|
|
78
|
-
}
|
|
79
|
-
debug("Done extracting %s messages: %s", fn, messages);
|
|
80
|
-
if (meta) {
|
|
81
|
-
debug("Extracted meta:", meta);
|
|
82
|
-
messages.forEach((m) => m.meta = meta);
|
|
83
|
-
}
|
|
84
|
-
return {
|
|
85
|
-
messages,
|
|
86
|
-
meta
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Extract strings from source files
|
|
91
|
-
* @param files list of files
|
|
92
|
-
* @param extractOpts extract options
|
|
93
|
-
* @returns messages serialized as JSON string since key order
|
|
94
|
-
* matters for some `format`
|
|
95
|
-
*/
|
|
96
|
-
export async function extract(files, extractOpts) {
|
|
97
|
-
const { throws, readFromStdin, signal, ...opts } = extractOpts;
|
|
98
|
-
// When throws is not explicitly true, we want to collect partial results
|
|
99
|
-
const shouldThrow = throws === true;
|
|
100
|
-
// Pass throws option to transformer for per-message error handling
|
|
101
|
-
const optsWithThrows = {
|
|
102
|
-
...opts,
|
|
103
|
-
throws: shouldThrow,
|
|
104
|
-
onMsgError: !shouldThrow ? (_, e) => warn(e.message) : undefined
|
|
105
|
-
};
|
|
106
|
-
let rawResults = [];
|
|
107
|
-
try {
|
|
108
|
-
if (readFromStdin) {
|
|
109
|
-
debug(`Reading input from stdin`);
|
|
110
|
-
// Read from stdin
|
|
111
|
-
if (process.stdin.isTTY) {
|
|
112
|
-
warn("Reading source file from TTY.");
|
|
113
|
-
}
|
|
114
|
-
const stdinSource = await getStdinAsString();
|
|
115
|
-
rawResults = [await processFile(stdinSource, "dummy", optsWithThrows)];
|
|
116
|
-
} else {
|
|
117
|
-
// Use Promise.allSettled when throws is not explicitly true to collect partial results
|
|
118
|
-
if (!shouldThrow) {
|
|
119
|
-
const settledResults = await Promise.allSettled(files.map(async (fn) => {
|
|
120
|
-
debug("Extracting file:", fn);
|
|
121
|
-
const source = await readFile(fn, {
|
|
122
|
-
encoding: "utf8",
|
|
123
|
-
signal
|
|
124
|
-
});
|
|
125
|
-
return processFile(source, fn, optsWithThrows);
|
|
126
|
-
}));
|
|
127
|
-
rawResults = settledResults.map((result) => {
|
|
128
|
-
if (result.status === "fulfilled") {
|
|
129
|
-
return result.value;
|
|
130
|
-
} else {
|
|
131
|
-
warn(String(result.reason));
|
|
132
|
-
return undefined;
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
} else {
|
|
136
|
-
rawResults = await Promise.all(files.map(async (fn) => {
|
|
137
|
-
debug("Extracting file:", fn);
|
|
138
|
-
const source = await readFile(fn, {
|
|
139
|
-
encoding: "utf8",
|
|
140
|
-
signal
|
|
141
|
-
});
|
|
142
|
-
return processFile(source, fn, optsWithThrows);
|
|
143
|
-
}));
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
} catch (e) {
|
|
147
|
-
if (shouldThrow) {
|
|
148
|
-
throw e;
|
|
149
|
-
} else {
|
|
150
|
-
warn(String(e));
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
const formatter = await resolveBuiltinFormatter(opts.format);
|
|
154
|
-
const extractionResults = rawResults.filter((r) => !!r);
|
|
155
|
-
const extractedMessages = new Map();
|
|
156
|
-
for (const { messages } of extractionResults) {
|
|
157
|
-
for (const message of messages) {
|
|
158
|
-
const { id, description, defaultMessage } = message;
|
|
159
|
-
if (!id) {
|
|
160
|
-
const error = new Error(`[FormatJS CLI] Missing message id for message:
|
|
161
|
-
${JSON.stringify(message, undefined, 2)}`);
|
|
162
|
-
if (throws) {
|
|
163
|
-
throw error;
|
|
164
|
-
} else {
|
|
165
|
-
warn(error.message);
|
|
166
|
-
}
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
if (extractedMessages.has(id)) {
|
|
170
|
-
const existing = extractedMessages.get(id);
|
|
171
|
-
if (stringify(description) !== stringify(existing.description) || defaultMessage !== existing.defaultMessage) {
|
|
172
|
-
const error = new Error(`[FormatJS CLI] Duplicate message id: "${id}", ` + "but the `description` and/or `defaultMessage` are different.");
|
|
173
|
-
if (throws) {
|
|
174
|
-
throw error;
|
|
175
|
-
} else {
|
|
176
|
-
warn(error.message);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
extractedMessages.set(id, message);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
const results = {};
|
|
184
|
-
const messages = Array.from(extractedMessages.values());
|
|
185
|
-
for (const { id, ...msg } of messages) {
|
|
186
|
-
// GH #3537: flatten is now applied during extraction in the babel plugin,
|
|
187
|
-
// so we don't need to apply it again here. The messages are already flattened.
|
|
188
|
-
results[id] = msg;
|
|
189
|
-
}
|
|
190
|
-
if (typeof formatter.serialize === "function") {
|
|
191
|
-
return formatter.serialize(formatter.format(results));
|
|
192
|
-
}
|
|
193
|
-
return stringify(formatter.format(results), {
|
|
194
|
-
space: 2,
|
|
195
|
-
cmp: formatter.compareMessages || undefined
|
|
196
|
-
}) ?? "";
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Extract strings from source files, also writes to a file.
|
|
200
|
-
* @param files list of files
|
|
201
|
-
* @param extractOpts extract options
|
|
202
|
-
* @returns A Promise that resolves if output file was written successfully
|
|
203
|
-
*/
|
|
204
|
-
export default async function extractAndWrite(files, extractOpts) {
|
|
205
|
-
const { outFile, ...opts } = extractOpts;
|
|
206
|
-
const serializedResult = await extract(files, opts) + "\n";
|
|
207
|
-
if (outFile) {
|
|
208
|
-
debug("Writing output file:", outFile);
|
|
209
|
-
return outputFile(outFile, serializedResult);
|
|
210
|
-
}
|
|
211
|
-
await writeStdout(serializedResult);
|
|
212
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import "./default.js";
|
|
2
|
-
export const format = (msgs) => {
|
|
3
|
-
const results = {};
|
|
4
|
-
for (const [id, msg] of Object.entries(msgs)) {
|
|
5
|
-
results[id] = {
|
|
6
|
-
message: msg.defaultMessage,
|
|
7
|
-
description: typeof msg.description === "string" ? msg.description : JSON.stringify(msg.description)
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
return results;
|
|
11
|
-
};
|
|
12
|
-
export const compile = (msgs) => {
|
|
13
|
-
const results = {};
|
|
14
|
-
for (const [id, msg] of Object.entries(msgs)) {
|
|
15
|
-
if (id === "smartling") {
|
|
16
|
-
continue;
|
|
17
|
-
}
|
|
18
|
-
results[id] = msg.message;
|
|
19
|
-
}
|
|
20
|
-
return results;
|
|
21
|
-
};
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { type MessageDescriptor } from "@formatjs/ts-transformer";
|
|
2
|
-
export type FormatFn<T = Record<string, MessageDescriptor>> = (msgs: Record<string, MessageDescriptor>) => T;
|
|
3
|
-
export type CompileFn<T = Record<string, MessageDescriptor>> = (msgs: T) => Record<string, string>;
|
|
4
|
-
export type SerializeFn<T = Record<string, MessageDescriptor>> = (msgs: T) => string;
|
|
5
|
-
export declare const format: FormatFn;
|
|
6
|
-
export declare const compile: CompileFn;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { Comparator } from "json-stable-stringify";
|
|
2
|
-
import { type CompileFn, type FormatFn, type SerializeFn } from "./default.js";
|
|
3
|
-
export interface Formatter<T> {
|
|
4
|
-
serialize?: SerializeFn<T>;
|
|
5
|
-
format: FormatFn<T>;
|
|
6
|
-
compile: CompileFn<T>;
|
|
7
|
-
compareMessages?: Comparator;
|
|
8
|
-
}
|
|
9
|
-
export declare function resolveBuiltinFormatter(format?: string | Formatter<unknown>): Promise<any>;
|
package/src/formatters/index.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { resolve } from "path";
|
|
2
|
-
import { pathToFileURL } from "url";
|
|
3
|
-
import * as crowdin from "./crowdin.js";
|
|
4
|
-
import * as defaultFormatter from "./default.js";
|
|
5
|
-
import "./default.js";
|
|
6
|
-
import * as lokalise from "./lokalise.js";
|
|
7
|
-
import * as simple from "./simple.js";
|
|
8
|
-
import * as smartling from "./smartling.js";
|
|
9
|
-
import * as transifex from "./transifex.js";
|
|
10
|
-
export async function resolveBuiltinFormatter(format) {
|
|
11
|
-
if (!format) {
|
|
12
|
-
return defaultFormatter;
|
|
13
|
-
}
|
|
14
|
-
if (typeof format !== "string") {
|
|
15
|
-
return format;
|
|
16
|
-
}
|
|
17
|
-
switch (format) {
|
|
18
|
-
case "transifex": return transifex;
|
|
19
|
-
case "smartling": return smartling;
|
|
20
|
-
case "simple": return simple;
|
|
21
|
-
case "lokalise": return lokalise;
|
|
22
|
-
case "crowdin": return crowdin;
|
|
23
|
-
}
|
|
24
|
-
try {
|
|
25
|
-
// eslint-disable-next-line import/dynamic-import-chunkname
|
|
26
|
-
return import(pathToFileURL(resolve(process.cwd(), format)).href);
|
|
27
|
-
} catch (e) {
|
|
28
|
-
console.error(`Cannot resolve formatter ${format}`);
|
|
29
|
-
throw e;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type CompileFn, type FormatFn } from "./default.js";
|
|
2
|
-
export type StructuredJson = Record<string, {
|
|
3
|
-
translation: string;
|
|
4
|
-
notes?: string;
|
|
5
|
-
context?: string;
|
|
6
|
-
limit?: string;
|
|
7
|
-
}>;
|
|
8
|
-
export declare const format: FormatFn<StructuredJson>;
|
|
9
|
-
export declare const compile: CompileFn<StructuredJson>;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import "./default.js";
|
|
2
|
-
export const format = (msgs) => {
|
|
3
|
-
const results = {};
|
|
4
|
-
for (const [id, msg] of Object.entries(msgs)) {
|
|
5
|
-
results[id] = {
|
|
6
|
-
translation: msg.defaultMessage,
|
|
7
|
-
notes: typeof msg.description === "string" ? msg.description : JSON.stringify(msg.description)
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
return results;
|
|
11
|
-
};
|
|
12
|
-
export const compile = (msgs) => {
|
|
13
|
-
const results = {};
|
|
14
|
-
for (const [id, msg] of Object.entries(msgs)) {
|
|
15
|
-
results[id] = msg.translation;
|
|
16
|
-
}
|
|
17
|
-
return results;
|
|
18
|
-
};
|
package/src/formatters/simple.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { Comparator } from "json-stable-stringify";
|
|
2
|
-
import { type CompileFn, type FormatFn } from "./default.js";
|
|
3
|
-
export interface SmartlingDirectives {
|
|
4
|
-
translate_paths: [{
|
|
5
|
-
path: string;
|
|
6
|
-
key: string;
|
|
7
|
-
instruction: string;
|
|
8
|
-
}];
|
|
9
|
-
variants_enabled: boolean;
|
|
10
|
-
string_format: string;
|
|
11
|
-
[k: string]: any;
|
|
12
|
-
}
|
|
13
|
-
export type SmartlingJson = {
|
|
14
|
-
smartling: SmartlingDirectives;
|
|
15
|
-
} & Record<string, {
|
|
16
|
-
message: string;
|
|
17
|
-
description?: string;
|
|
18
|
-
}>;
|
|
19
|
-
export declare const format: FormatFn<SmartlingJson>;
|
|
20
|
-
export declare const compareMessages: Comparator;
|
|
21
|
-
export declare const compile: CompileFn<SmartlingJson>;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import "./default.js";
|
|
2
|
-
export const format = (msgs) => {
|
|
3
|
-
const results = { smartling: {
|
|
4
|
-
translate_paths: [{
|
|
5
|
-
path: "*/message",
|
|
6
|
-
key: "{*}/message",
|
|
7
|
-
instruction: "*/description"
|
|
8
|
-
}],
|
|
9
|
-
variants_enabled: true,
|
|
10
|
-
string_format: "icu"
|
|
11
|
-
} };
|
|
12
|
-
for (const [id, msg] of Object.entries(msgs)) {
|
|
13
|
-
results[id] = {
|
|
14
|
-
message: msg.defaultMessage,
|
|
15
|
-
description: typeof msg.description === "string" ? msg.description : JSON.stringify(msg.description)
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
return results;
|
|
19
|
-
};
|
|
20
|
-
export const compareMessages = (el1, el2) => {
|
|
21
|
-
// `smartling` has to be the 1st key
|
|
22
|
-
if (el1.key === "smartling") {
|
|
23
|
-
return -1;
|
|
24
|
-
}
|
|
25
|
-
if (el2.key === "smartling") {
|
|
26
|
-
return 1;
|
|
27
|
-
}
|
|
28
|
-
return el1.key < el2.key ? -1 : el1.key === el2.key ? 0 : 1;
|
|
29
|
-
};
|
|
30
|
-
export const compile = (msgs) => {
|
|
31
|
-
const results = {};
|
|
32
|
-
for (const [id, msg] of Object.entries(msgs)) {
|
|
33
|
-
if (id === "smartling") {
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
results[id] = msg.message;
|
|
37
|
-
}
|
|
38
|
-
return results;
|
|
39
|
-
};
|