@verbatra/sdk 0.4.1 → 0.4.3
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 +2 -0
- package/dist/index.cjs +84 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -6
- package/dist/index.d.ts +14 -6
- package/dist/index.js +84 -31
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -37,7 +37,7 @@ type TranslationEntry$1 = Readonly<z.infer<typeof translationEntrySchema$1>>;
|
|
|
37
37
|
* (counts matter). Always returned (never thrown) for an ordinary mismatch.
|
|
38
38
|
*/
|
|
39
39
|
interface PlaceholderIntegrityResult {
|
|
40
|
-
/** True when nothing is missing or extra
|
|
40
|
+
/** True when nothing is missing or extra: the multisets match, regardless of order. */
|
|
41
41
|
readonly matches: boolean;
|
|
42
42
|
/** Occurrences present in source but absent from the translation, one per dropped occurrence. Sorted. */
|
|
43
43
|
readonly missing: readonly string[];
|
|
@@ -153,8 +153,11 @@ type AnthropicModel = Anthropic.Messages.Model;
|
|
|
153
153
|
*
|
|
154
154
|
* - `FORMALITY_DOWNGRADED`: a requested formality was not applied (the free tier does not support it).
|
|
155
155
|
* - `GLOSSARY_IGNORED`: a supplied generic glossary was not applied.
|
|
156
|
+
* - `PLACEHOLDER_UNSUPPORTED`: at least one placeholder- or ICU-bearing entry was left untranslated
|
|
157
|
+
* because DeepL cannot preserve those tokens; such entries are withheld (absent from the result maps)
|
|
158
|
+
* rather than sent to DeepL and mangled.
|
|
156
159
|
*/
|
|
157
|
-
type ProviderNoticeCode = "FORMALITY_DOWNGRADED" | "GLOSSARY_IGNORED";
|
|
160
|
+
type ProviderNoticeCode = "FORMALITY_DOWNGRADED" | "GLOSSARY_IGNORED" | "PLACEHOLDER_UNSUPPORTED";
|
|
158
161
|
/**
|
|
159
162
|
* An observable, structured signal that something was gracefully degraded (not an
|
|
160
163
|
* error). Carries only a stable code and a static message, never a key or content.
|
|
@@ -378,6 +381,8 @@ declare function loadConfig(options?: LoadConfigOptions): Promise<VerbatraConfig
|
|
|
378
381
|
* (thrown by `loadConfig`).
|
|
379
382
|
* - `CONFIG_INVALID`: a config was found but is unparseable or fails validation (thrown by `loadConfig`).
|
|
380
383
|
* - `UNKNOWN_FORMAT`: no adapter is registered for the configured format (thrown by `translate`).
|
|
384
|
+
* - `UNKNOWN_LOCALE`: a requested locale is not among the configured target locales (thrown by
|
|
385
|
+
* `check`, `diff`, and `exportWorkbook` via the shared locale selection).
|
|
381
386
|
* - `PROVIDER_CONSTRUCTION_FAILED`: the provider factory threw; wraps the provider's own error, including
|
|
382
387
|
* a missing `*_API_KEY` reported as `MISSING_API_KEY` (thrown by `translate`, non-dry-run only).
|
|
383
388
|
* - `SOURCE_UNREADABLE`: the source locale file is absent (thrown by `translate`, and by `watch` at startup).
|
|
@@ -388,7 +393,7 @@ declare function loadConfig(options?: LoadConfigOptions): Promise<VerbatraConfig
|
|
|
388
393
|
* per-locale failure carries no string code of its own. See the surfaced-not-thrown distinction on
|
|
389
394
|
* `translate`.
|
|
390
395
|
*/
|
|
391
|
-
type SdkErrorCode = "CONFIG_NOT_FOUND" | "CONFIG_INVALID" | "UNKNOWN_FORMAT" | "PROVIDER_CONSTRUCTION_FAILED" | "SOURCE_UNREADABLE" | "SOURCE_INVALID" | "LOCK_FILE_INVALID" | "LOCALE_FAILED";
|
|
396
|
+
type SdkErrorCode = "CONFIG_NOT_FOUND" | "CONFIG_INVALID" | "UNKNOWN_FORMAT" | "UNKNOWN_LOCALE" | "PROVIDER_CONSTRUCTION_FAILED" | "SOURCE_UNREADABLE" | "SOURCE_INVALID" | "LOCK_FILE_INVALID" | "LOCALE_FAILED";
|
|
392
397
|
/** The single structured error the SDK throws or records. Never carries a secret. */
|
|
393
398
|
declare class SdkError extends Error {
|
|
394
399
|
/** The stable {@link SdkErrorCode} for this failure; branch on this, not the message. */
|
|
@@ -648,7 +653,8 @@ interface CheckDeps {
|
|
|
648
653
|
* @param deps - Optional composition seams (registry, file system) for tests.
|
|
649
654
|
* @returns The aggregate and per-locale drift status.
|
|
650
655
|
* @throws {@link SdkError} `UNKNOWN_FORMAT`, `SOURCE_UNREADABLE`, `SOURCE_INVALID`, `LOCK_FILE_INVALID`
|
|
651
|
-
* with the same meanings as in `translate
|
|
656
|
+
* with the same meanings as in `translate`, or `UNKNOWN_LOCALE` when a requested locale is not
|
|
657
|
+
* among the configured target locales.
|
|
652
658
|
*/
|
|
653
659
|
declare function check(input: CheckInput, deps?: CheckDeps): Promise<CheckSummary>;
|
|
654
660
|
|
|
@@ -697,7 +703,8 @@ interface DiffDeps {
|
|
|
697
703
|
* @param deps - Optional composition seams (registry, file system) for tests.
|
|
698
704
|
* @returns The aggregate and per-locale pending change.
|
|
699
705
|
* @throws {@link SdkError} `UNKNOWN_FORMAT`, `SOURCE_UNREADABLE`, `SOURCE_INVALID`, `LOCK_FILE_INVALID`
|
|
700
|
-
* with the same meanings as in `translate
|
|
706
|
+
* with the same meanings as in `translate`, or `UNKNOWN_LOCALE` when a requested locale is not
|
|
707
|
+
* among the configured target locales.
|
|
701
708
|
*/
|
|
702
709
|
declare function diff(input: DiffInput, deps?: DiffDeps): Promise<DiffSummary>;
|
|
703
710
|
|
|
@@ -897,7 +904,8 @@ interface ExportWorkbookResult {
|
|
|
897
904
|
* @param deps - Optional composition seams (registry, file system) for tests.
|
|
898
905
|
* @returns Where the workbook was written and the per-locale row counts.
|
|
899
906
|
* @throws {@link SdkError} `UNKNOWN_FORMAT`, `SOURCE_UNREADABLE`, `SOURCE_INVALID`, `LOCK_FILE_INVALID`
|
|
900
|
-
* with the same meanings as in `translate
|
|
907
|
+
* with the same meanings as in `translate`, or `UNKNOWN_LOCALE` when a requested locale is not
|
|
908
|
+
* among the configured target locales.
|
|
901
909
|
*/
|
|
902
910
|
declare function exportWorkbook(input: ExportWorkbookInput, deps?: ExportWorkbookDeps): Promise<ExportWorkbookResult>;
|
|
903
911
|
|
package/dist/index.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ type TranslationEntry$1 = Readonly<z.infer<typeof translationEntrySchema$1>>;
|
|
|
37
37
|
* (counts matter). Always returned (never thrown) for an ordinary mismatch.
|
|
38
38
|
*/
|
|
39
39
|
interface PlaceholderIntegrityResult {
|
|
40
|
-
/** True when nothing is missing or extra
|
|
40
|
+
/** True when nothing is missing or extra: the multisets match, regardless of order. */
|
|
41
41
|
readonly matches: boolean;
|
|
42
42
|
/** Occurrences present in source but absent from the translation, one per dropped occurrence. Sorted. */
|
|
43
43
|
readonly missing: readonly string[];
|
|
@@ -153,8 +153,11 @@ type AnthropicModel = Anthropic.Messages.Model;
|
|
|
153
153
|
*
|
|
154
154
|
* - `FORMALITY_DOWNGRADED`: a requested formality was not applied (the free tier does not support it).
|
|
155
155
|
* - `GLOSSARY_IGNORED`: a supplied generic glossary was not applied.
|
|
156
|
+
* - `PLACEHOLDER_UNSUPPORTED`: at least one placeholder- or ICU-bearing entry was left untranslated
|
|
157
|
+
* because DeepL cannot preserve those tokens; such entries are withheld (absent from the result maps)
|
|
158
|
+
* rather than sent to DeepL and mangled.
|
|
156
159
|
*/
|
|
157
|
-
type ProviderNoticeCode = "FORMALITY_DOWNGRADED" | "GLOSSARY_IGNORED";
|
|
160
|
+
type ProviderNoticeCode = "FORMALITY_DOWNGRADED" | "GLOSSARY_IGNORED" | "PLACEHOLDER_UNSUPPORTED";
|
|
158
161
|
/**
|
|
159
162
|
* An observable, structured signal that something was gracefully degraded (not an
|
|
160
163
|
* error). Carries only a stable code and a static message, never a key or content.
|
|
@@ -378,6 +381,8 @@ declare function loadConfig(options?: LoadConfigOptions): Promise<VerbatraConfig
|
|
|
378
381
|
* (thrown by `loadConfig`).
|
|
379
382
|
* - `CONFIG_INVALID`: a config was found but is unparseable or fails validation (thrown by `loadConfig`).
|
|
380
383
|
* - `UNKNOWN_FORMAT`: no adapter is registered for the configured format (thrown by `translate`).
|
|
384
|
+
* - `UNKNOWN_LOCALE`: a requested locale is not among the configured target locales (thrown by
|
|
385
|
+
* `check`, `diff`, and `exportWorkbook` via the shared locale selection).
|
|
381
386
|
* - `PROVIDER_CONSTRUCTION_FAILED`: the provider factory threw; wraps the provider's own error, including
|
|
382
387
|
* a missing `*_API_KEY` reported as `MISSING_API_KEY` (thrown by `translate`, non-dry-run only).
|
|
383
388
|
* - `SOURCE_UNREADABLE`: the source locale file is absent (thrown by `translate`, and by `watch` at startup).
|
|
@@ -388,7 +393,7 @@ declare function loadConfig(options?: LoadConfigOptions): Promise<VerbatraConfig
|
|
|
388
393
|
* per-locale failure carries no string code of its own. See the surfaced-not-thrown distinction on
|
|
389
394
|
* `translate`.
|
|
390
395
|
*/
|
|
391
|
-
type SdkErrorCode = "CONFIG_NOT_FOUND" | "CONFIG_INVALID" | "UNKNOWN_FORMAT" | "PROVIDER_CONSTRUCTION_FAILED" | "SOURCE_UNREADABLE" | "SOURCE_INVALID" | "LOCK_FILE_INVALID" | "LOCALE_FAILED";
|
|
396
|
+
type SdkErrorCode = "CONFIG_NOT_FOUND" | "CONFIG_INVALID" | "UNKNOWN_FORMAT" | "UNKNOWN_LOCALE" | "PROVIDER_CONSTRUCTION_FAILED" | "SOURCE_UNREADABLE" | "SOURCE_INVALID" | "LOCK_FILE_INVALID" | "LOCALE_FAILED";
|
|
392
397
|
/** The single structured error the SDK throws or records. Never carries a secret. */
|
|
393
398
|
declare class SdkError extends Error {
|
|
394
399
|
/** The stable {@link SdkErrorCode} for this failure; branch on this, not the message. */
|
|
@@ -648,7 +653,8 @@ interface CheckDeps {
|
|
|
648
653
|
* @param deps - Optional composition seams (registry, file system) for tests.
|
|
649
654
|
* @returns The aggregate and per-locale drift status.
|
|
650
655
|
* @throws {@link SdkError} `UNKNOWN_FORMAT`, `SOURCE_UNREADABLE`, `SOURCE_INVALID`, `LOCK_FILE_INVALID`
|
|
651
|
-
* with the same meanings as in `translate
|
|
656
|
+
* with the same meanings as in `translate`, or `UNKNOWN_LOCALE` when a requested locale is not
|
|
657
|
+
* among the configured target locales.
|
|
652
658
|
*/
|
|
653
659
|
declare function check(input: CheckInput, deps?: CheckDeps): Promise<CheckSummary>;
|
|
654
660
|
|
|
@@ -697,7 +703,8 @@ interface DiffDeps {
|
|
|
697
703
|
* @param deps - Optional composition seams (registry, file system) for tests.
|
|
698
704
|
* @returns The aggregate and per-locale pending change.
|
|
699
705
|
* @throws {@link SdkError} `UNKNOWN_FORMAT`, `SOURCE_UNREADABLE`, `SOURCE_INVALID`, `LOCK_FILE_INVALID`
|
|
700
|
-
* with the same meanings as in `translate
|
|
706
|
+
* with the same meanings as in `translate`, or `UNKNOWN_LOCALE` when a requested locale is not
|
|
707
|
+
* among the configured target locales.
|
|
701
708
|
*/
|
|
702
709
|
declare function diff(input: DiffInput, deps?: DiffDeps): Promise<DiffSummary>;
|
|
703
710
|
|
|
@@ -897,7 +904,8 @@ interface ExportWorkbookResult {
|
|
|
897
904
|
* @param deps - Optional composition seams (registry, file system) for tests.
|
|
898
905
|
* @returns Where the workbook was written and the per-locale row counts.
|
|
899
906
|
* @throws {@link SdkError} `UNKNOWN_FORMAT`, `SOURCE_UNREADABLE`, `SOURCE_INVALID`, `LOCK_FILE_INVALID`
|
|
900
|
-
* with the same meanings as in `translate
|
|
907
|
+
* with the same meanings as in `translate`, or `UNKNOWN_LOCALE` when a requested locale is not
|
|
908
|
+
* among the configured target locales.
|
|
901
909
|
*/
|
|
902
910
|
declare function exportWorkbook(input: ExportWorkbookInput, deps?: ExportWorkbookDeps): Promise<ExportWorkbookResult>;
|
|
903
911
|
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,7 @@ import { parse as parse$1, TYPE } from '@formatjs/icu-messageformat-parser';
|
|
|
15
15
|
import { XMLSerializer, DOMParser } from '@xmldom/xmldom';
|
|
16
16
|
import { stringify, parse } from 'yaml';
|
|
17
17
|
import ExcelJS from 'exceljs';
|
|
18
|
+
import { Readable } from 'stream';
|
|
18
19
|
import JSZip from 'jszip';
|
|
19
20
|
import { watch as watch$1 } from 'chokidar';
|
|
20
21
|
|
|
@@ -151,7 +152,7 @@ function checkPlaceholders(source, translated) {
|
|
|
151
152
|
const extra = multisetExcess(translatedCounts, sourceCounts);
|
|
152
153
|
const reordered = missing.length === 0 && extra.length === 0 && !sameOrder(source, translated);
|
|
153
154
|
return {
|
|
154
|
-
matches: missing.length === 0 && extra.length === 0
|
|
155
|
+
matches: missing.length === 0 && extra.length === 0,
|
|
155
156
|
missing,
|
|
156
157
|
extra,
|
|
157
158
|
reordered
|
|
@@ -472,6 +473,19 @@ function createDefaultClient2() {
|
|
|
472
473
|
};
|
|
473
474
|
return { client, freeAccount };
|
|
474
475
|
}
|
|
476
|
+
var PLACEHOLDER_UNSUPPORTED_MESSAGE = "Some entries contain placeholders or ICU syntax that DeepL cannot preserve; they were left untranslated. Use an LLM provider to translate placeholder-bearing strings.";
|
|
477
|
+
function partitionByPlaceholders(entries) {
|
|
478
|
+
const protectable = [];
|
|
479
|
+
const unprotectable = [];
|
|
480
|
+
for (const entry of entries) {
|
|
481
|
+
if (entry.placeholders.length > 0) {
|
|
482
|
+
unprotectable.push(entry);
|
|
483
|
+
} else {
|
|
484
|
+
protectable.push(entry);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return { protectable, unprotectable };
|
|
488
|
+
}
|
|
475
489
|
var FORMALITY_DOWNGRADED_MESSAGE = "Formality was not applied: the configured DeepL key is a free-tier key, which does not support formality.";
|
|
476
490
|
var GLOSSARY_IGNORED_MESSAGE = "The supplied glossary term map was not applied: DeepL uses configured glossary IDs, not term maps.";
|
|
477
491
|
function buildTranslateOptions(input) {
|
|
@@ -535,6 +549,7 @@ function resolveClient(deps) {
|
|
|
535
549
|
}
|
|
536
550
|
async function translate(bundle, config, request) {
|
|
537
551
|
const data = validateRequest(request);
|
|
552
|
+
const { protectable, unprotectable } = partitionByPlaceholders(data.entries);
|
|
538
553
|
const genericGlossarySupplied = request.glossary !== void 0 && Object.keys(request.glossary).length > 0;
|
|
539
554
|
const { options, notices } = buildTranslateOptions({
|
|
540
555
|
freeAccount: bundle.freeAccount,
|
|
@@ -542,18 +557,28 @@ async function translate(bundle, config, request) {
|
|
|
542
557
|
...data.tone !== void 0 ? { tone: data.tone } : {},
|
|
543
558
|
...config.glossaryId !== void 0 ? { glossaryId: config.glossaryId } : {}
|
|
544
559
|
});
|
|
545
|
-
const
|
|
546
|
-
const results = await callClient2(
|
|
560
|
+
const { values, integrity } = await translateProtectable(
|
|
547
561
|
bundle.client,
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
562
|
+
data,
|
|
563
|
+
protectable,
|
|
564
|
+
options,
|
|
565
|
+
request.extractPlaceholders
|
|
552
566
|
);
|
|
553
|
-
|
|
554
|
-
|
|
567
|
+
if (unprotectable.length > 0) {
|
|
568
|
+
notices.push({ code: "PLACEHOLDER_UNSUPPORTED", message: PLACEHOLDER_UNSUPPORTED_MESSAGE });
|
|
569
|
+
}
|
|
555
570
|
return { values, integrity, notices };
|
|
556
571
|
}
|
|
572
|
+
async function translateProtectable(client, data, protectable, options, extract) {
|
|
573
|
+
if (protectable.length === 0) {
|
|
574
|
+
return { values: /* @__PURE__ */ new Map(), integrity: /* @__PURE__ */ new Map() };
|
|
575
|
+
}
|
|
576
|
+
const texts = protectable.map((entry) => entry.value);
|
|
577
|
+
const results = await callClient2(client, texts, data.sourceLocale, data.targetLocale, options);
|
|
578
|
+
const { values, integrityInputs } = zipResults(protectable, results);
|
|
579
|
+
const integrity = checkBatchIntegrity(integrityInputs, extract);
|
|
580
|
+
return { values, integrity };
|
|
581
|
+
}
|
|
557
582
|
function callClient2(client, texts, sourceLang, targetLang, options) {
|
|
558
583
|
return guardProviderCall(() => client.translateText(texts, sourceLang, targetLang, options));
|
|
559
584
|
}
|
|
@@ -2057,6 +2082,24 @@ function selectAdapter(format, registry = createDefaultRegistry()) {
|
|
|
2057
2082
|
);
|
|
2058
2083
|
}
|
|
2059
2084
|
|
|
2085
|
+
// src/flow/select-locales.ts
|
|
2086
|
+
function selectLocales(config, requested) {
|
|
2087
|
+
if (requested === void 0) {
|
|
2088
|
+
return config.targetLocales;
|
|
2089
|
+
}
|
|
2090
|
+
const configured = new Set(config.targetLocales);
|
|
2091
|
+
const unknown = requested.filter((locale) => !configured.has(locale));
|
|
2092
|
+
if (unknown.length > 0) {
|
|
2093
|
+
const label = unknown.length === 1 ? "locale" : "locales";
|
|
2094
|
+
throw new SdkError(
|
|
2095
|
+
"UNKNOWN_LOCALE",
|
|
2096
|
+
`Requested ${label} not in the configured target locales: ${unknown.join(", ")}. Configured targets: ${config.targetLocales.join(", ")}.`
|
|
2097
|
+
);
|
|
2098
|
+
}
|
|
2099
|
+
const wanted = new Set(requested);
|
|
2100
|
+
return config.targetLocales.filter((locale) => wanted.has(locale));
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2060
2103
|
// src/flow/source.ts
|
|
2061
2104
|
async function readSource(config, cwd, fs, adapter) {
|
|
2062
2105
|
const sourcePath = localeFilePath(cwd, config.files.pattern, config.sourceLocale);
|
|
@@ -2085,13 +2128,6 @@ async function readTarget(cwd, config, adapter, fs, locale) {
|
|
|
2085
2128
|
}
|
|
2086
2129
|
return (await adapter.read(path, locale)).resource;
|
|
2087
2130
|
}
|
|
2088
|
-
function selectedLocales(config, requested) {
|
|
2089
|
-
if (requested === void 0) {
|
|
2090
|
-
return config.targetLocales;
|
|
2091
|
-
}
|
|
2092
|
-
const wanted = new Set(requested);
|
|
2093
|
-
return config.targetLocales.filter((locale) => wanted.has(locale));
|
|
2094
|
-
}
|
|
2095
2131
|
async function diffLocales(input, deps = {}) {
|
|
2096
2132
|
const config = input.config;
|
|
2097
2133
|
const cwd = input.cwd ?? process.cwd();
|
|
@@ -2100,7 +2136,7 @@ async function diffLocales(input, deps = {}) {
|
|
|
2100
2136
|
const source = await readSource(config, cwd, fs, adapter);
|
|
2101
2137
|
const lock = await readLockFile(lockFilePath(cwd), fs);
|
|
2102
2138
|
return Promise.all(
|
|
2103
|
-
|
|
2139
|
+
selectLocales(config, input.locales).map(async (locale) => {
|
|
2104
2140
|
const target = await readTarget(cwd, config, adapter, fs, locale);
|
|
2105
2141
|
const diff2 = diffResources(source.resource, target, { baseline: baselineFor(lock, locale) });
|
|
2106
2142
|
return { locale, diff: diff2 };
|
|
@@ -2826,6 +2862,34 @@ function declaredSize(file) {
|
|
|
2826
2862
|
const size = data?.uncompressedSize;
|
|
2827
2863
|
return typeof size === "number" && Number.isFinite(size) ? size : void 0;
|
|
2828
2864
|
}
|
|
2865
|
+
async function streamEntryBounded(file, remaining) {
|
|
2866
|
+
const chunks = [];
|
|
2867
|
+
let raw = 0;
|
|
2868
|
+
let oversize = false;
|
|
2869
|
+
const source = new Readable({ objectMode: true }).wrap(
|
|
2870
|
+
file.nodeStream("nodebuffer")
|
|
2871
|
+
);
|
|
2872
|
+
try {
|
|
2873
|
+
for await (const chunk2 of source) {
|
|
2874
|
+
const buf = Buffer.isBuffer(chunk2) ? chunk2 : Buffer.from(chunk2);
|
|
2875
|
+
raw += buf.length;
|
|
2876
|
+
if (raw > remaining) {
|
|
2877
|
+
oversize = true;
|
|
2878
|
+
break;
|
|
2879
|
+
}
|
|
2880
|
+
chunks.push(buf);
|
|
2881
|
+
}
|
|
2882
|
+
} catch {
|
|
2883
|
+
throw new ExchangeError("WORKBOOK_INVALID", "A workbook entry could not be decompressed.");
|
|
2884
|
+
}
|
|
2885
|
+
if (oversize) {
|
|
2886
|
+
throw new ExchangeError(
|
|
2887
|
+
"WORKBOOK_INVALID",
|
|
2888
|
+
"The workbook decompresses to more than the permitted maximum bytes."
|
|
2889
|
+
);
|
|
2890
|
+
}
|
|
2891
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
2892
|
+
}
|
|
2829
2893
|
async function guardWorkbookBytes(bytes, limits) {
|
|
2830
2894
|
let zip;
|
|
2831
2895
|
try {
|
|
@@ -2855,12 +2919,8 @@ async function guardWorkbookBytes(bytes, limits) {
|
|
|
2855
2919
|
}
|
|
2856
2920
|
let actualTotal = 0;
|
|
2857
2921
|
for (const file of files) {
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
content = await file.async("string");
|
|
2861
|
-
} catch {
|
|
2862
|
-
throw new ExchangeError("WORKBOOK_INVALID", "A workbook entry could not be decompressed.");
|
|
2863
|
-
}
|
|
2922
|
+
const remaining = limits.maxDecompressedBytes - actualTotal;
|
|
2923
|
+
const content = await streamEntryBounded(file, remaining);
|
|
2864
2924
|
actualTotal += Buffer.byteLength(content, "utf8");
|
|
2865
2925
|
if (actualTotal > limits.maxDecompressedBytes) {
|
|
2866
2926
|
throw new ExchangeError(
|
|
@@ -3010,13 +3070,6 @@ function buildRows(source, target, baseline, includeUnchanged) {
|
|
|
3010
3070
|
}
|
|
3011
3071
|
return [...rows].sort((a, b) => a.key < b.key ? -1 : 1);
|
|
3012
3072
|
}
|
|
3013
|
-
function selectedLocales2(config, requested) {
|
|
3014
|
-
if (requested === void 0) {
|
|
3015
|
-
return config.targetLocales;
|
|
3016
|
-
}
|
|
3017
|
-
const wanted = new Set(requested);
|
|
3018
|
-
return config.targetLocales.filter((locale) => wanted.has(locale));
|
|
3019
|
-
}
|
|
3020
3073
|
async function exportWorkbook(input, deps = {}) {
|
|
3021
3074
|
const config = input.config;
|
|
3022
3075
|
const cwd = input.cwd ?? process.cwd();
|
|
@@ -3024,7 +3077,7 @@ async function exportWorkbook(input, deps = {}) {
|
|
|
3024
3077
|
const adapter = selectAdapter(config.format, deps.adapterRegistry);
|
|
3025
3078
|
const source = await readSource(config, cwd, fs, adapter);
|
|
3026
3079
|
const lock = await readLockFile(lockFilePath(cwd), fs);
|
|
3027
|
-
const locales =
|
|
3080
|
+
const locales = selectLocales(config, input.locales);
|
|
3028
3081
|
const sheets = await Promise.all(
|
|
3029
3082
|
locales.map(async (locale) => {
|
|
3030
3083
|
const target = await readTarget3(cwd, config, adapter, fs, locale);
|