i18next-cli 1.64.0 → 1.64.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/dist/cjs/cli.js +1 -1
- package/dist/cjs/extractor/core/translation-manager.js +5 -2
- package/dist/cjs/extractor/parsers/call-expression-handler.js +8 -3
- package/dist/cjs/extractor/parsers/comment-parser.js +7 -3
- package/dist/cjs/extractor/parsers/jsx-handler.js +5 -1
- package/dist/cjs/status.js +156 -30
- package/dist/esm/cli.js +1 -1
- package/dist/esm/extractor/core/translation-manager.js +5 -2
- package/dist/esm/extractor/parsers/call-expression-handler.js +8 -3
- package/dist/esm/extractor/parsers/comment-parser.js +7 -3
- package/dist/esm/extractor/parsers/jsx-handler.js +5 -1
- package/dist/esm/status.js +156 -30
- package/package.json +1 -1
- package/types/extractor/core/translation-manager.d.ts.map +1 -1
- package/types/extractor/parsers/call-expression-handler.d.ts.map +1 -1
- package/types/extractor/parsers/comment-parser.d.ts.map +1 -1
- package/types/extractor/parsers/jsx-handler.d.ts.map +1 -1
- package/types/status.d.ts.map +1 -1
package/dist/cjs/cli.js
CHANGED
|
@@ -37,7 +37,7 @@ const program = new commander.Command();
|
|
|
37
37
|
program
|
|
38
38
|
.name('i18next-cli')
|
|
39
39
|
.description('A unified, high-performance i18next CLI.')
|
|
40
|
-
.version('1.64.
|
|
40
|
+
.version('1.64.2'); // This string is replaced with the actual version at build time by rollup
|
|
41
41
|
// new: global config override option
|
|
42
42
|
program.option('-c, --config <path>', 'Path to i18next-cli config file (overrides detection)');
|
|
43
43
|
program
|
|
@@ -394,8 +394,11 @@ function buildNewTranslationsForNs(nsKeys, existingTranslations, config, locale,
|
|
|
394
394
|
if (shouldFilterKey(key)) {
|
|
395
395
|
return false;
|
|
396
396
|
}
|
|
397
|
-
if (!hasCount) {
|
|
398
|
-
// Non-plural keys are always included
|
|
397
|
+
if (!hasCount || config.extract.disablePlurals) {
|
|
398
|
+
// Non-plural keys are always included. Under `disablePlurals`, count keys
|
|
399
|
+
// are emitted as plain keys (no plural expansion) but still carry
|
|
400
|
+
// `hasCount` so `status` can recognise them — they must bypass the
|
|
401
|
+
// plural-form filtering below and always be included, exactly as before.
|
|
399
402
|
return true;
|
|
400
403
|
}
|
|
401
404
|
// For plural keys, check if this specific plural form is needed for the target language
|
|
@@ -337,12 +337,17 @@ class CallExpressionHandler {
|
|
|
337
337
|
// Check if plurals are disabled FIRST, before any plural optimization paths
|
|
338
338
|
if (this.config.extract.disablePlurals) {
|
|
339
339
|
// When plurals are disabled, treat count as a regular option (for interpolation only)
|
|
340
|
-
// Still handle context normally
|
|
340
|
+
// Still handle context normally. We keep `hasCount`/`isOrdinal` on the
|
|
341
|
+
// emitted key so `status` knows it is count-driven and can accept the
|
|
342
|
+
// file's plural variants (or the bare key) instead of demanding the
|
|
343
|
+
// literal base key. File generation ignores these flags under
|
|
344
|
+
// disablePlurals (see translation-manager), so output is unchanged.
|
|
345
|
+
const countMeta = hasCount ? { hasCount: true, isOrdinal: isOrdinalByKey } : {};
|
|
341
346
|
if (keysWithContext.length > 0) {
|
|
342
|
-
keysWithContext.forEach(this.pluginContext.addKey);
|
|
347
|
+
keysWithContext.forEach(k => this.pluginContext.addKey({ ...k, ...countMeta }));
|
|
343
348
|
}
|
|
344
349
|
else {
|
|
345
|
-
this.pluginContext.addKey({ key: finalKey, ns, defaultValue: dv, explicitDefault: explicitDefaultForBase });
|
|
350
|
+
this.pluginContext.addKey({ key: finalKey, ns, defaultValue: dv, explicitDefault: explicitDefaultForBase, ...countMeta });
|
|
346
351
|
}
|
|
347
352
|
continue; // This key is fully handled
|
|
348
353
|
}
|
|
@@ -124,14 +124,18 @@ function extractKeysFromComments(code, pluginContext, config, scopeResolver) {
|
|
|
124
124
|
ns = config.extract.defaultNS;
|
|
125
125
|
// 5. Handle context and count combinations based on disablePlurals setting
|
|
126
126
|
if (config.extract.disablePlurals) {
|
|
127
|
-
// When plurals are disabled, ignore count for key generation
|
|
127
|
+
// When plurals are disabled, ignore count for key generation. We still
|
|
128
|
+
// tag the key with `hasCount` (when a count was present) so `status` can
|
|
129
|
+
// recognise it as count-driven; file generation ignores the flag under
|
|
130
|
+
// disablePlurals (see translation-manager).
|
|
131
|
+
const countMeta = count ? { hasCount: true, isOrdinal } : {};
|
|
128
132
|
if (context) {
|
|
129
133
|
// Only generate context variants (no base key when context is static)
|
|
130
|
-
pluginContext.addKey({ key: `${key}_${context}`, ns, defaultValue: defaultValue ?? key });
|
|
134
|
+
pluginContext.addKey({ key: `${key}_${context}`, ns, defaultValue: defaultValue ?? key, ...countMeta });
|
|
131
135
|
}
|
|
132
136
|
else {
|
|
133
137
|
// Simple key (ignore count)
|
|
134
|
-
pluginContext.addKey({ key, ns, defaultValue: defaultValue ?? key });
|
|
138
|
+
pluginContext.addKey({ key, ns, defaultValue: defaultValue ?? key, ...countMeta });
|
|
135
139
|
}
|
|
136
140
|
}
|
|
137
141
|
else {
|
|
@@ -369,12 +369,16 @@ class JSXHandler {
|
|
|
369
369
|
else if (hasCount) {
|
|
370
370
|
// Check if plurals are disabled
|
|
371
371
|
if (this.config.extract.disablePlurals) {
|
|
372
|
-
// When plurals are disabled, just add the base keys (no plural forms)
|
|
372
|
+
// When plurals are disabled, just add the base keys (no plural forms).
|
|
373
|
+
// We keep `hasCount` so `status` recognises the key as count-driven and
|
|
374
|
+
// accepts the file's plural variants (or bare key); file generation
|
|
375
|
+
// ignores it under disablePlurals (see translation-manager).
|
|
373
376
|
extractedKeys.forEach(extractedKey => {
|
|
374
377
|
this.pluginContext.addKey({
|
|
375
378
|
key: extractedKey.key,
|
|
376
379
|
ns: extractedKey.ns,
|
|
377
380
|
defaultValue: extractedKey.defaultValue,
|
|
381
|
+
hasCount: true,
|
|
378
382
|
locations: extractedKey.locations
|
|
379
383
|
});
|
|
380
384
|
});
|
package/dist/cjs/status.js
CHANGED
|
@@ -26,6 +26,53 @@ function classifyValue(value) {
|
|
|
26
26
|
return 'empty';
|
|
27
27
|
return 'translated';
|
|
28
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Representative counts used to decide which CLDR plural categories a locale can
|
|
31
|
+
* actually reach in normal usage: small integers (the common case), a handful
|
|
32
|
+
* of larger integers, and common decimals (so categories that only fire for
|
|
33
|
+
* fractional display values — e.g. Polish/Russian `other` — stay required).
|
|
34
|
+
*
|
|
35
|
+
* Any category NOT produced by these counts is treated as "optional". The prime
|
|
36
|
+
* example is French `many`, which `Intl.PluralRules` only selects for values
|
|
37
|
+
* ≥ 1,000,000 — the i18next runtime can technically request it, but real apps
|
|
38
|
+
* almost never hit those values (and the runtime falls back to the base key
|
|
39
|
+
* when the variant is missing), so a missing `_many` should be a soft note
|
|
40
|
+
* rather than a hard "missing key" failure.
|
|
41
|
+
*/
|
|
42
|
+
const REPRESENTATIVE_COUNTS = (() => {
|
|
43
|
+
const counts = [];
|
|
44
|
+
for (let n = 0; n <= 20; n++)
|
|
45
|
+
counts.push(n);
|
|
46
|
+
counts.push(100, 101, 1000, 1001, 10000);
|
|
47
|
+
counts.push(0.5, 1.1, 1.5, 2.5, 3.5);
|
|
48
|
+
return counts;
|
|
49
|
+
})();
|
|
50
|
+
const optionalCategoriesCache = new Map();
|
|
51
|
+
/**
|
|
52
|
+
* Returns the CLDR plural categories for a locale that are NOT reachable by any
|
|
53
|
+
* representative count (see {@link REPRESENTATIVE_COUNTS}). These are reported
|
|
54
|
+
* by `status` as optional: a missing variant is a soft note instead of a hard
|
|
55
|
+
* absence, mirroring how the i18next runtime resolves such forms.
|
|
56
|
+
*/
|
|
57
|
+
function getOptionalPluralCategories(locale, isOrdinal) {
|
|
58
|
+
const type = isOrdinal ? 'ordinal' : 'cardinal';
|
|
59
|
+
const cacheKey = `${locale}|${type}`;
|
|
60
|
+
const cached = optionalCategoriesCache.get(cacheKey);
|
|
61
|
+
if (cached)
|
|
62
|
+
return cached;
|
|
63
|
+
let optional;
|
|
64
|
+
try {
|
|
65
|
+
const rules = pluralRules.safePluralRules(locale, { type });
|
|
66
|
+
const all = rules.resolvedOptions().pluralCategories;
|
|
67
|
+
const reachable = new Set(REPRESENTATIVE_COUNTS.map(n => rules.select(n)));
|
|
68
|
+
optional = new Set(all.filter(c => !reachable.has(c)));
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
optional = new Set();
|
|
72
|
+
}
|
|
73
|
+
optionalCategoriesCache.set(cacheKey, optional);
|
|
74
|
+
return optional;
|
|
75
|
+
}
|
|
29
76
|
/**
|
|
30
77
|
* Runs a health check on the project's i18next translations and displays a status report.
|
|
31
78
|
*
|
|
@@ -53,20 +100,44 @@ async function runStatus(config, options = {}) {
|
|
|
53
100
|
const report = await generateStatusReport(config);
|
|
54
101
|
spinner.succeed('Analysis complete.');
|
|
55
102
|
await displayStatusReport(report, config, options);
|
|
103
|
+
// When a specific locale is requested (`status <locale>`), the pass/fail
|
|
104
|
+
// result must reflect THAT locale only — otherwise the displayed summary
|
|
105
|
+
// (which is scoped to the requested locale) can contradict the exit code
|
|
106
|
+
// by failing on an unrelated secondary language. See issue #271.
|
|
107
|
+
const scopedLocale = options.detail && config.locales.includes(options.detail)
|
|
108
|
+
? options.detail
|
|
109
|
+
: undefined;
|
|
56
110
|
let hasMissing = false;
|
|
57
|
-
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
|
|
111
|
+
if (scopedLocale) {
|
|
112
|
+
if (scopedLocale === config.extract.primaryLanguage) {
|
|
113
|
+
// The primary language fails only on absent keys (used in code but
|
|
114
|
+
// missing from the file); empty placeholders are deliberate.
|
|
115
|
+
hasMissing = !!report.primary && report.primary.totalAbsent > 0;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
const localeData = report.locales.get(scopedLocale);
|
|
119
|
+
hasMissing = !!localeData && localeData.totalTranslated < localeData.totalKeys;
|
|
61
120
|
}
|
|
62
121
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
122
|
+
else {
|
|
123
|
+
for (const [, localeData] of report.locales.entries()) {
|
|
124
|
+
if (localeData.totalTranslated < localeData.totalKeys) {
|
|
125
|
+
hasMissing = true;
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// The primary language fails the check only on absent keys (used in code but
|
|
130
|
+
// missing from the translation file); empty placeholders are tolerated.
|
|
131
|
+
if (!hasMissing && report.primary && report.primary.totalAbsent > 0) {
|
|
132
|
+
hasMissing = true;
|
|
133
|
+
}
|
|
67
134
|
}
|
|
68
135
|
if (hasMissing) {
|
|
69
|
-
|
|
136
|
+
// Name the locale when the check is scoped so the failure reason is clear
|
|
137
|
+
// (the displayed summary already explains what is missing for it).
|
|
138
|
+
spinner.fail(scopedLocale
|
|
139
|
+
? `Error: Incomplete translations detected for "${scopedLocale}".`
|
|
140
|
+
: 'Error: Incomplete translations detected.');
|
|
70
141
|
process.exit(1);
|
|
71
142
|
}
|
|
72
143
|
}
|
|
@@ -222,6 +293,7 @@ async function generateStatusReport(config) {
|
|
|
222
293
|
let totalTranslatedForLocale = 0;
|
|
223
294
|
let totalEmptyForLocale = 0;
|
|
224
295
|
let totalAbsentForLocale = 0;
|
|
296
|
+
let totalOptionalForLocale = 0;
|
|
225
297
|
let totalKeysForLocale = 0;
|
|
226
298
|
const namespaces = new Map();
|
|
227
299
|
const mergedTranslations = mergeNamespaces
|
|
@@ -250,6 +322,7 @@ async function generateStatusReport(config) {
|
|
|
250
322
|
let translatedInNs = 0;
|
|
251
323
|
let emptyInNs = 0;
|
|
252
324
|
let absentInNs = 0;
|
|
325
|
+
let optionalInNs = 0;
|
|
253
326
|
let totalInNs = 0;
|
|
254
327
|
const keyDetails = [];
|
|
255
328
|
// Get the plural categories for THIS specific locale
|
|
@@ -314,37 +387,85 @@ async function generateStatusReport(config) {
|
|
|
314
387
|
// Only count this key if it's a plural form used by this locale
|
|
315
388
|
if (localePluralCategories.includes(category) && !processedKeys.has(baseKey)) {
|
|
316
389
|
processedKeys.add(baseKey);
|
|
317
|
-
totalInNs++;
|
|
318
390
|
const state = resolveAndClassify(baseKey);
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
391
|
+
const optionalCategories = getOptionalPluralCategories(locale, isOrdinalVariant);
|
|
392
|
+
// An optional category (e.g. French `_many`) is a soft note whenever
|
|
393
|
+
// it isn't translated — whether absent or an empty placeholder that
|
|
394
|
+
// `extract` wrote. It is never a hard failure. See #270 and
|
|
395
|
+
// getOptionalPluralCategories.
|
|
396
|
+
if (state !== 'translated' && optionalCategories.has(category)) {
|
|
397
|
+
optionalInNs++;
|
|
398
|
+
keyDetails.push({ key: baseKey, state: 'optional' });
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
totalInNs++;
|
|
402
|
+
if (state === 'translated')
|
|
403
|
+
translatedInNs++;
|
|
404
|
+
else if (state === 'empty')
|
|
405
|
+
emptyInNs++;
|
|
406
|
+
else
|
|
407
|
+
absentInNs++;
|
|
408
|
+
keyDetails.push({ key: baseKey, state });
|
|
409
|
+
}
|
|
326
410
|
}
|
|
327
411
|
}
|
|
328
412
|
else {
|
|
329
|
-
// This is a base plural key without expanded variants
|
|
330
|
-
//
|
|
413
|
+
// This is a base plural key without expanded variants. Mirror the
|
|
414
|
+
// i18next runtime, where t(key, { count }) resolves `key + suffix`
|
|
415
|
+
// and falls back to the bare `key`. A family is therefore satisfied
|
|
416
|
+
// either by its plural variants OR by a bare key (the convention
|
|
417
|
+
// used when `disablePlurals` is enabled and no variants are written).
|
|
331
418
|
const localePluralCategories = getLocalePluralCategories(locale, isOrdinal || false);
|
|
332
|
-
|
|
333
|
-
|
|
419
|
+
const optionalCategories = getOptionalPluralCategories(locale, isOrdinal || false);
|
|
420
|
+
const variants = localePluralCategories.map(category => ({
|
|
421
|
+
category,
|
|
422
|
+
pluralKey: isOrdinal
|
|
334
423
|
? `${baseKey}${pluralSeparator}ordinal${pluralSeparator}${category}`
|
|
335
|
-
: `${baseKey}${pluralSeparator}${category}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
424
|
+
: `${baseKey}${pluralSeparator}${category}`,
|
|
425
|
+
}));
|
|
426
|
+
const anyVariantPresent = variants.some(({ pluralKey }) => resolveAndClassify(pluralKey) !== 'absent');
|
|
427
|
+
const bareState = resolveAndClassify(baseKey);
|
|
428
|
+
if (!anyVariantPresent && bareState !== 'absent' && !processedKeys.has(baseKey)) {
|
|
429
|
+
// Convention (a): only the bare key exists (typical under
|
|
430
|
+
// disablePlurals, or single-"other" languages). The runtime
|
|
431
|
+
// resolves count via the bare key, so it satisfies the family on
|
|
432
|
+
// its own — don't demand plural variants that were never written.
|
|
433
|
+
processedKeys.add(baseKey);
|
|
339
434
|
totalInNs++;
|
|
340
|
-
|
|
341
|
-
if (state === 'translated')
|
|
435
|
+
if (bareState === 'translated')
|
|
342
436
|
translatedInNs++;
|
|
343
|
-
else if (
|
|
437
|
+
else if (bareState === 'empty')
|
|
344
438
|
emptyInNs++;
|
|
345
439
|
else
|
|
346
440
|
absentInNs++;
|
|
347
|
-
keyDetails.push({ key:
|
|
441
|
+
keyDetails.push({ key: baseKey, state: bareState });
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
// Convention (b): plural variants exist (or the family is missing
|
|
445
|
+
// entirely). Evaluate each CLDR category — a missing variant is a
|
|
446
|
+
// hard absence only when the category is required for this locale;
|
|
447
|
+
// optional categories (e.g. French `_many`) downgrade to a soft note.
|
|
448
|
+
for (const { category, pluralKey } of variants) {
|
|
449
|
+
if (processedKeys.has(pluralKey))
|
|
450
|
+
continue;
|
|
451
|
+
processedKeys.add(pluralKey);
|
|
452
|
+
const state = resolveAndClassify(pluralKey);
|
|
453
|
+
// An optional category (e.g. French `_many`) is a soft note
|
|
454
|
+
// whenever it isn't translated — never a hard failure. See #270.
|
|
455
|
+
if (state !== 'translated' && optionalCategories.has(category)) {
|
|
456
|
+
optionalInNs++;
|
|
457
|
+
keyDetails.push({ key: pluralKey, state: 'optional' });
|
|
458
|
+
continue;
|
|
459
|
+
}
|
|
460
|
+
totalInNs++;
|
|
461
|
+
if (state === 'translated')
|
|
462
|
+
translatedInNs++;
|
|
463
|
+
else if (state === 'empty')
|
|
464
|
+
emptyInNs++;
|
|
465
|
+
else
|
|
466
|
+
absentInNs++;
|
|
467
|
+
keyDetails.push({ key: pluralKey, state });
|
|
468
|
+
}
|
|
348
469
|
}
|
|
349
470
|
}
|
|
350
471
|
}
|
|
@@ -380,10 +501,11 @@ async function generateStatusReport(config) {
|
|
|
380
501
|
absentInNs++;
|
|
381
502
|
keyDetails.push({ key: variantKey, state });
|
|
382
503
|
}
|
|
383
|
-
namespaces.set(ns, { totalKeys: totalInNs, translatedKeys: translatedInNs, emptyKeys: emptyInNs, absentKeys: absentInNs, keyDetails });
|
|
504
|
+
namespaces.set(ns, { totalKeys: totalInNs, translatedKeys: translatedInNs, emptyKeys: emptyInNs, absentKeys: absentInNs, optionalKeys: optionalInNs, keyDetails });
|
|
384
505
|
totalTranslatedForLocale += translatedInNs;
|
|
385
506
|
totalEmptyForLocale += emptyInNs;
|
|
386
507
|
totalAbsentForLocale += absentInNs;
|
|
508
|
+
totalOptionalForLocale += optionalInNs;
|
|
387
509
|
totalKeysForLocale += totalInNs;
|
|
388
510
|
}
|
|
389
511
|
const localeStatus = {
|
|
@@ -391,6 +513,7 @@ async function generateStatusReport(config) {
|
|
|
391
513
|
totalTranslated: totalTranslatedForLocale,
|
|
392
514
|
totalEmpty: totalEmptyForLocale,
|
|
393
515
|
totalAbsent: totalAbsentForLocale,
|
|
516
|
+
totalOptional: totalOptionalForLocale,
|
|
394
517
|
namespaces,
|
|
395
518
|
};
|
|
396
519
|
if (isPrimary) {
|
|
@@ -482,6 +605,9 @@ async function displayDetailedLocaleReport(report, config, locale, namespaceFilt
|
|
|
482
605
|
else if (state === 'empty') {
|
|
483
606
|
console.log(` ${node_util.styleText('yellow', '~')} ${key} ${node_util.styleText('yellow', '(untranslated)')}`);
|
|
484
607
|
}
|
|
608
|
+
else if (state === 'optional') {
|
|
609
|
+
console.log(` ${node_util.styleText('gray', '○')} ${key} ${node_util.styleText('gray', '(optional plural form)')}`);
|
|
610
|
+
}
|
|
485
611
|
else {
|
|
486
612
|
console.log(` ${node_util.styleText('red', '✗')} ${key} ${node_util.styleText('red', '(absent)')}`);
|
|
487
613
|
}
|
package/dist/esm/cli.js
CHANGED
|
@@ -31,7 +31,7 @@ const program = new Command();
|
|
|
31
31
|
program
|
|
32
32
|
.name('i18next-cli')
|
|
33
33
|
.description('A unified, high-performance i18next CLI.')
|
|
34
|
-
.version('1.64.
|
|
34
|
+
.version('1.64.2'); // This string is replaced with the actual version at build time by rollup
|
|
35
35
|
// new: global config override option
|
|
36
36
|
program.option('-c, --config <path>', 'Path to i18next-cli config file (overrides detection)');
|
|
37
37
|
program
|
|
@@ -392,8 +392,11 @@ function buildNewTranslationsForNs(nsKeys, existingTranslations, config, locale,
|
|
|
392
392
|
if (shouldFilterKey(key)) {
|
|
393
393
|
return false;
|
|
394
394
|
}
|
|
395
|
-
if (!hasCount) {
|
|
396
|
-
// Non-plural keys are always included
|
|
395
|
+
if (!hasCount || config.extract.disablePlurals) {
|
|
396
|
+
// Non-plural keys are always included. Under `disablePlurals`, count keys
|
|
397
|
+
// are emitted as plain keys (no plural expansion) but still carry
|
|
398
|
+
// `hasCount` so `status` can recognise them — they must bypass the
|
|
399
|
+
// plural-form filtering below and always be included, exactly as before.
|
|
397
400
|
return true;
|
|
398
401
|
}
|
|
399
402
|
// For plural keys, check if this specific plural form is needed for the target language
|
|
@@ -335,12 +335,17 @@ class CallExpressionHandler {
|
|
|
335
335
|
// Check if plurals are disabled FIRST, before any plural optimization paths
|
|
336
336
|
if (this.config.extract.disablePlurals) {
|
|
337
337
|
// When plurals are disabled, treat count as a regular option (for interpolation only)
|
|
338
|
-
// Still handle context normally
|
|
338
|
+
// Still handle context normally. We keep `hasCount`/`isOrdinal` on the
|
|
339
|
+
// emitted key so `status` knows it is count-driven and can accept the
|
|
340
|
+
// file's plural variants (or the bare key) instead of demanding the
|
|
341
|
+
// literal base key. File generation ignores these flags under
|
|
342
|
+
// disablePlurals (see translation-manager), so output is unchanged.
|
|
343
|
+
const countMeta = hasCount ? { hasCount: true, isOrdinal: isOrdinalByKey } : {};
|
|
339
344
|
if (keysWithContext.length > 0) {
|
|
340
|
-
keysWithContext.forEach(this.pluginContext.addKey);
|
|
345
|
+
keysWithContext.forEach(k => this.pluginContext.addKey({ ...k, ...countMeta }));
|
|
341
346
|
}
|
|
342
347
|
else {
|
|
343
|
-
this.pluginContext.addKey({ key: finalKey, ns, defaultValue: dv, explicitDefault: explicitDefaultForBase });
|
|
348
|
+
this.pluginContext.addKey({ key: finalKey, ns, defaultValue: dv, explicitDefault: explicitDefaultForBase, ...countMeta });
|
|
344
349
|
}
|
|
345
350
|
continue; // This key is fully handled
|
|
346
351
|
}
|
|
@@ -122,14 +122,18 @@ function extractKeysFromComments(code, pluginContext, config, scopeResolver) {
|
|
|
122
122
|
ns = config.extract.defaultNS;
|
|
123
123
|
// 5. Handle context and count combinations based on disablePlurals setting
|
|
124
124
|
if (config.extract.disablePlurals) {
|
|
125
|
-
// When plurals are disabled, ignore count for key generation
|
|
125
|
+
// When plurals are disabled, ignore count for key generation. We still
|
|
126
|
+
// tag the key with `hasCount` (when a count was present) so `status` can
|
|
127
|
+
// recognise it as count-driven; file generation ignores the flag under
|
|
128
|
+
// disablePlurals (see translation-manager).
|
|
129
|
+
const countMeta = count ? { hasCount: true, isOrdinal } : {};
|
|
126
130
|
if (context) {
|
|
127
131
|
// Only generate context variants (no base key when context is static)
|
|
128
|
-
pluginContext.addKey({ key: `${key}_${context}`, ns, defaultValue: defaultValue ?? key });
|
|
132
|
+
pluginContext.addKey({ key: `${key}_${context}`, ns, defaultValue: defaultValue ?? key, ...countMeta });
|
|
129
133
|
}
|
|
130
134
|
else {
|
|
131
135
|
// Simple key (ignore count)
|
|
132
|
-
pluginContext.addKey({ key, ns, defaultValue: defaultValue ?? key });
|
|
136
|
+
pluginContext.addKey({ key, ns, defaultValue: defaultValue ?? key, ...countMeta });
|
|
133
137
|
}
|
|
134
138
|
}
|
|
135
139
|
else {
|
|
@@ -367,12 +367,16 @@ class JSXHandler {
|
|
|
367
367
|
else if (hasCount) {
|
|
368
368
|
// Check if plurals are disabled
|
|
369
369
|
if (this.config.extract.disablePlurals) {
|
|
370
|
-
// When plurals are disabled, just add the base keys (no plural forms)
|
|
370
|
+
// When plurals are disabled, just add the base keys (no plural forms).
|
|
371
|
+
// We keep `hasCount` so `status` recognises the key as count-driven and
|
|
372
|
+
// accepts the file's plural variants (or bare key); file generation
|
|
373
|
+
// ignores it under disablePlurals (see translation-manager).
|
|
371
374
|
extractedKeys.forEach(extractedKey => {
|
|
372
375
|
this.pluginContext.addKey({
|
|
373
376
|
key: extractedKey.key,
|
|
374
377
|
ns: extractedKey.ns,
|
|
375
378
|
defaultValue: extractedKey.defaultValue,
|
|
379
|
+
hasCount: true,
|
|
376
380
|
locations: extractedKey.locations
|
|
377
381
|
});
|
|
378
382
|
});
|
package/dist/esm/status.js
CHANGED
|
@@ -20,6 +20,53 @@ function classifyValue(value) {
|
|
|
20
20
|
return 'empty';
|
|
21
21
|
return 'translated';
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Representative counts used to decide which CLDR plural categories a locale can
|
|
25
|
+
* actually reach in normal usage: small integers (the common case), a handful
|
|
26
|
+
* of larger integers, and common decimals (so categories that only fire for
|
|
27
|
+
* fractional display values — e.g. Polish/Russian `other` — stay required).
|
|
28
|
+
*
|
|
29
|
+
* Any category NOT produced by these counts is treated as "optional". The prime
|
|
30
|
+
* example is French `many`, which `Intl.PluralRules` only selects for values
|
|
31
|
+
* ≥ 1,000,000 — the i18next runtime can technically request it, but real apps
|
|
32
|
+
* almost never hit those values (and the runtime falls back to the base key
|
|
33
|
+
* when the variant is missing), so a missing `_many` should be a soft note
|
|
34
|
+
* rather than a hard "missing key" failure.
|
|
35
|
+
*/
|
|
36
|
+
const REPRESENTATIVE_COUNTS = (() => {
|
|
37
|
+
const counts = [];
|
|
38
|
+
for (let n = 0; n <= 20; n++)
|
|
39
|
+
counts.push(n);
|
|
40
|
+
counts.push(100, 101, 1000, 1001, 10000);
|
|
41
|
+
counts.push(0.5, 1.1, 1.5, 2.5, 3.5);
|
|
42
|
+
return counts;
|
|
43
|
+
})();
|
|
44
|
+
const optionalCategoriesCache = new Map();
|
|
45
|
+
/**
|
|
46
|
+
* Returns the CLDR plural categories for a locale that are NOT reachable by any
|
|
47
|
+
* representative count (see {@link REPRESENTATIVE_COUNTS}). These are reported
|
|
48
|
+
* by `status` as optional: a missing variant is a soft note instead of a hard
|
|
49
|
+
* absence, mirroring how the i18next runtime resolves such forms.
|
|
50
|
+
*/
|
|
51
|
+
function getOptionalPluralCategories(locale, isOrdinal) {
|
|
52
|
+
const type = isOrdinal ? 'ordinal' : 'cardinal';
|
|
53
|
+
const cacheKey = `${locale}|${type}`;
|
|
54
|
+
const cached = optionalCategoriesCache.get(cacheKey);
|
|
55
|
+
if (cached)
|
|
56
|
+
return cached;
|
|
57
|
+
let optional;
|
|
58
|
+
try {
|
|
59
|
+
const rules = safePluralRules(locale, { type });
|
|
60
|
+
const all = rules.resolvedOptions().pluralCategories;
|
|
61
|
+
const reachable = new Set(REPRESENTATIVE_COUNTS.map(n => rules.select(n)));
|
|
62
|
+
optional = new Set(all.filter(c => !reachable.has(c)));
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
optional = new Set();
|
|
66
|
+
}
|
|
67
|
+
optionalCategoriesCache.set(cacheKey, optional);
|
|
68
|
+
return optional;
|
|
69
|
+
}
|
|
23
70
|
/**
|
|
24
71
|
* Runs a health check on the project's i18next translations and displays a status report.
|
|
25
72
|
*
|
|
@@ -47,20 +94,44 @@ async function runStatus(config, options = {}) {
|
|
|
47
94
|
const report = await generateStatusReport(config);
|
|
48
95
|
spinner.succeed('Analysis complete.');
|
|
49
96
|
await displayStatusReport(report, config, options);
|
|
97
|
+
// When a specific locale is requested (`status <locale>`), the pass/fail
|
|
98
|
+
// result must reflect THAT locale only — otherwise the displayed summary
|
|
99
|
+
// (which is scoped to the requested locale) can contradict the exit code
|
|
100
|
+
// by failing on an unrelated secondary language. See issue #271.
|
|
101
|
+
const scopedLocale = options.detail && config.locales.includes(options.detail)
|
|
102
|
+
? options.detail
|
|
103
|
+
: undefined;
|
|
50
104
|
let hasMissing = false;
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
|
|
105
|
+
if (scopedLocale) {
|
|
106
|
+
if (scopedLocale === config.extract.primaryLanguage) {
|
|
107
|
+
// The primary language fails only on absent keys (used in code but
|
|
108
|
+
// missing from the file); empty placeholders are deliberate.
|
|
109
|
+
hasMissing = !!report.primary && report.primary.totalAbsent > 0;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
const localeData = report.locales.get(scopedLocale);
|
|
113
|
+
hasMissing = !!localeData && localeData.totalTranslated < localeData.totalKeys;
|
|
55
114
|
}
|
|
56
115
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
116
|
+
else {
|
|
117
|
+
for (const [, localeData] of report.locales.entries()) {
|
|
118
|
+
if (localeData.totalTranslated < localeData.totalKeys) {
|
|
119
|
+
hasMissing = true;
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// The primary language fails the check only on absent keys (used in code but
|
|
124
|
+
// missing from the translation file); empty placeholders are tolerated.
|
|
125
|
+
if (!hasMissing && report.primary && report.primary.totalAbsent > 0) {
|
|
126
|
+
hasMissing = true;
|
|
127
|
+
}
|
|
61
128
|
}
|
|
62
129
|
if (hasMissing) {
|
|
63
|
-
|
|
130
|
+
// Name the locale when the check is scoped so the failure reason is clear
|
|
131
|
+
// (the displayed summary already explains what is missing for it).
|
|
132
|
+
spinner.fail(scopedLocale
|
|
133
|
+
? `Error: Incomplete translations detected for "${scopedLocale}".`
|
|
134
|
+
: 'Error: Incomplete translations detected.');
|
|
64
135
|
process.exit(1);
|
|
65
136
|
}
|
|
66
137
|
}
|
|
@@ -216,6 +287,7 @@ async function generateStatusReport(config) {
|
|
|
216
287
|
let totalTranslatedForLocale = 0;
|
|
217
288
|
let totalEmptyForLocale = 0;
|
|
218
289
|
let totalAbsentForLocale = 0;
|
|
290
|
+
let totalOptionalForLocale = 0;
|
|
219
291
|
let totalKeysForLocale = 0;
|
|
220
292
|
const namespaces = new Map();
|
|
221
293
|
const mergedTranslations = mergeNamespaces
|
|
@@ -244,6 +316,7 @@ async function generateStatusReport(config) {
|
|
|
244
316
|
let translatedInNs = 0;
|
|
245
317
|
let emptyInNs = 0;
|
|
246
318
|
let absentInNs = 0;
|
|
319
|
+
let optionalInNs = 0;
|
|
247
320
|
let totalInNs = 0;
|
|
248
321
|
const keyDetails = [];
|
|
249
322
|
// Get the plural categories for THIS specific locale
|
|
@@ -308,37 +381,85 @@ async function generateStatusReport(config) {
|
|
|
308
381
|
// Only count this key if it's a plural form used by this locale
|
|
309
382
|
if (localePluralCategories.includes(category) && !processedKeys.has(baseKey)) {
|
|
310
383
|
processedKeys.add(baseKey);
|
|
311
|
-
totalInNs++;
|
|
312
384
|
const state = resolveAndClassify(baseKey);
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
385
|
+
const optionalCategories = getOptionalPluralCategories(locale, isOrdinalVariant);
|
|
386
|
+
// An optional category (e.g. French `_many`) is a soft note whenever
|
|
387
|
+
// it isn't translated — whether absent or an empty placeholder that
|
|
388
|
+
// `extract` wrote. It is never a hard failure. See #270 and
|
|
389
|
+
// getOptionalPluralCategories.
|
|
390
|
+
if (state !== 'translated' && optionalCategories.has(category)) {
|
|
391
|
+
optionalInNs++;
|
|
392
|
+
keyDetails.push({ key: baseKey, state: 'optional' });
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
totalInNs++;
|
|
396
|
+
if (state === 'translated')
|
|
397
|
+
translatedInNs++;
|
|
398
|
+
else if (state === 'empty')
|
|
399
|
+
emptyInNs++;
|
|
400
|
+
else
|
|
401
|
+
absentInNs++;
|
|
402
|
+
keyDetails.push({ key: baseKey, state });
|
|
403
|
+
}
|
|
320
404
|
}
|
|
321
405
|
}
|
|
322
406
|
else {
|
|
323
|
-
// This is a base plural key without expanded variants
|
|
324
|
-
//
|
|
407
|
+
// This is a base plural key without expanded variants. Mirror the
|
|
408
|
+
// i18next runtime, where t(key, { count }) resolves `key + suffix`
|
|
409
|
+
// and falls back to the bare `key`. A family is therefore satisfied
|
|
410
|
+
// either by its plural variants OR by a bare key (the convention
|
|
411
|
+
// used when `disablePlurals` is enabled and no variants are written).
|
|
325
412
|
const localePluralCategories = getLocalePluralCategories(locale, isOrdinal || false);
|
|
326
|
-
|
|
327
|
-
|
|
413
|
+
const optionalCategories = getOptionalPluralCategories(locale, isOrdinal || false);
|
|
414
|
+
const variants = localePluralCategories.map(category => ({
|
|
415
|
+
category,
|
|
416
|
+
pluralKey: isOrdinal
|
|
328
417
|
? `${baseKey}${pluralSeparator}ordinal${pluralSeparator}${category}`
|
|
329
|
-
: `${baseKey}${pluralSeparator}${category}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
418
|
+
: `${baseKey}${pluralSeparator}${category}`,
|
|
419
|
+
}));
|
|
420
|
+
const anyVariantPresent = variants.some(({ pluralKey }) => resolveAndClassify(pluralKey) !== 'absent');
|
|
421
|
+
const bareState = resolveAndClassify(baseKey);
|
|
422
|
+
if (!anyVariantPresent && bareState !== 'absent' && !processedKeys.has(baseKey)) {
|
|
423
|
+
// Convention (a): only the bare key exists (typical under
|
|
424
|
+
// disablePlurals, or single-"other" languages). The runtime
|
|
425
|
+
// resolves count via the bare key, so it satisfies the family on
|
|
426
|
+
// its own — don't demand plural variants that were never written.
|
|
427
|
+
processedKeys.add(baseKey);
|
|
333
428
|
totalInNs++;
|
|
334
|
-
|
|
335
|
-
if (state === 'translated')
|
|
429
|
+
if (bareState === 'translated')
|
|
336
430
|
translatedInNs++;
|
|
337
|
-
else if (
|
|
431
|
+
else if (bareState === 'empty')
|
|
338
432
|
emptyInNs++;
|
|
339
433
|
else
|
|
340
434
|
absentInNs++;
|
|
341
|
-
keyDetails.push({ key:
|
|
435
|
+
keyDetails.push({ key: baseKey, state: bareState });
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
// Convention (b): plural variants exist (or the family is missing
|
|
439
|
+
// entirely). Evaluate each CLDR category — a missing variant is a
|
|
440
|
+
// hard absence only when the category is required for this locale;
|
|
441
|
+
// optional categories (e.g. French `_many`) downgrade to a soft note.
|
|
442
|
+
for (const { category, pluralKey } of variants) {
|
|
443
|
+
if (processedKeys.has(pluralKey))
|
|
444
|
+
continue;
|
|
445
|
+
processedKeys.add(pluralKey);
|
|
446
|
+
const state = resolveAndClassify(pluralKey);
|
|
447
|
+
// An optional category (e.g. French `_many`) is a soft note
|
|
448
|
+
// whenever it isn't translated — never a hard failure. See #270.
|
|
449
|
+
if (state !== 'translated' && optionalCategories.has(category)) {
|
|
450
|
+
optionalInNs++;
|
|
451
|
+
keyDetails.push({ key: pluralKey, state: 'optional' });
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
totalInNs++;
|
|
455
|
+
if (state === 'translated')
|
|
456
|
+
translatedInNs++;
|
|
457
|
+
else if (state === 'empty')
|
|
458
|
+
emptyInNs++;
|
|
459
|
+
else
|
|
460
|
+
absentInNs++;
|
|
461
|
+
keyDetails.push({ key: pluralKey, state });
|
|
462
|
+
}
|
|
342
463
|
}
|
|
343
464
|
}
|
|
344
465
|
}
|
|
@@ -374,10 +495,11 @@ async function generateStatusReport(config) {
|
|
|
374
495
|
absentInNs++;
|
|
375
496
|
keyDetails.push({ key: variantKey, state });
|
|
376
497
|
}
|
|
377
|
-
namespaces.set(ns, { totalKeys: totalInNs, translatedKeys: translatedInNs, emptyKeys: emptyInNs, absentKeys: absentInNs, keyDetails });
|
|
498
|
+
namespaces.set(ns, { totalKeys: totalInNs, translatedKeys: translatedInNs, emptyKeys: emptyInNs, absentKeys: absentInNs, optionalKeys: optionalInNs, keyDetails });
|
|
378
499
|
totalTranslatedForLocale += translatedInNs;
|
|
379
500
|
totalEmptyForLocale += emptyInNs;
|
|
380
501
|
totalAbsentForLocale += absentInNs;
|
|
502
|
+
totalOptionalForLocale += optionalInNs;
|
|
381
503
|
totalKeysForLocale += totalInNs;
|
|
382
504
|
}
|
|
383
505
|
const localeStatus = {
|
|
@@ -385,6 +507,7 @@ async function generateStatusReport(config) {
|
|
|
385
507
|
totalTranslated: totalTranslatedForLocale,
|
|
386
508
|
totalEmpty: totalEmptyForLocale,
|
|
387
509
|
totalAbsent: totalAbsentForLocale,
|
|
510
|
+
totalOptional: totalOptionalForLocale,
|
|
388
511
|
namespaces,
|
|
389
512
|
};
|
|
390
513
|
if (isPrimary) {
|
|
@@ -476,6 +599,9 @@ async function displayDetailedLocaleReport(report, config, locale, namespaceFilt
|
|
|
476
599
|
else if (state === 'empty') {
|
|
477
600
|
console.log(` ${styleText('yellow', '~')} ${key} ${styleText('yellow', '(untranslated)')}`);
|
|
478
601
|
}
|
|
602
|
+
else if (state === 'optional') {
|
|
603
|
+
console.log(` ${styleText('gray', '○')} ${key} ${styleText('gray', '(optional plural form)')}`);
|
|
604
|
+
}
|
|
479
605
|
else {
|
|
480
606
|
console.log(` ${styleText('red', '✗')} ${key} ${styleText('red', '(absent)')}`);
|
|
481
607
|
}
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translation-manager.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/translation-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"translation-manager.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/translation-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AA0jC9F;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EAC/B,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,EACvB,MAAM,EAAE,oBAAoB,EAC5B,EACE,uBAA+B,EAC/B,OAAe,EACf,oBAA4B,EAC5B,MAA4B,EAC7B,GAAE;IACD,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAA;CACX,GACL,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAiK9B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call-expression-handler.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/call-expression-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAA6C,MAAM,WAAW,CAAA;AAC1F,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,EAAgB,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1G,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAc7D,qBAAa,qBAAqB;IAChC,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,kBAAkB,CAAoB;IACvC,UAAU,cAAoB;IACrC,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,iBAAiB,CAAsC;gBAG7D,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,MAAM,EACd,kBAAkB,EAAE,kBAAkB,EACtC,cAAc,EAAE,MAAM,MAAM,EAC5B,cAAc,EAAE,MAAM,MAAM,EAC5B,iBAAiB,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAA2B;IAW3E;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;;;;;;;;;;;;;OAcG;IACH,oBAAoB,CAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,GAAG,SAAS,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"call-expression-handler.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/call-expression-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAA6C,MAAM,WAAW,CAAA;AAC1F,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,EAAgB,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1G,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAc7D,qBAAa,qBAAqB;IAChC,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,kBAAkB,CAAoB;IACvC,UAAU,cAAoB;IACrC,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,iBAAiB,CAAsC;gBAG7D,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,MAAM,EACd,kBAAkB,EAAE,kBAAkB,EACtC,cAAc,EAAE,MAAM,MAAM,EAC5B,cAAc,EAAE,MAAM,MAAM,EAC5B,iBAAiB,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAA2B;IAW3E;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;;;;;;;;;;;;;OAcG;IACH,oBAAoB,CAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,GAAG,SAAS,GAAG,IAAI;IA8ZxG;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAmBzB,OAAO,CAAC,wBAAwB;IAyEhC;;;;;;OAMG;IACH,OAAO,CAAC,4BAA4B;IAsDpC;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,OAAO,CAAC,sBAAsB;IA2B9B;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,uBAAuB;IAgB/B;;;;;;;;OAQG;IACH,OAAO,CAAC,iCAAiC;IAwFzC;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,gBAAgB;IAyMxB;;;;;;;;;OASG;IACH,OAAO,CAAC,eAAe;CA2BxB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comment-parser.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/comment-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAOzE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,oBAAoB,EAC5B,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GAC1F,IAAI,
|
|
1
|
+
{"version":3,"file":"comment-parser.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/comment-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAOzE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,oBAAoB,EAC5B,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GAC1F,IAAI,CAyJN"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsx-handler.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/jsx-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,UAAU,EAAqC,MAAM,WAAW,CAAA;AAC1F,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAgB,MAAM,gBAAgB,CAAA;AACvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAS7D,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,kBAAkB,CAAoB;IAC9C,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,cAAc,CAAc;gBAGlC,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,aAAa,EAAE,aAAa,EAC5B,kBAAkB,EAAE,kBAAkB,EACtC,cAAc,EAAE,MAAM,MAAM,EAC5B,cAAc,EAAE,MAAM,MAAM;IAS9B;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IAK3B;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,iCAAiC;IAgCzC;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;;;;;;;OAQG;IACH,gBAAgB,CAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"jsx-handler.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/jsx-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,UAAU,EAAqC,MAAM,WAAW,CAAA;AAC1F,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAgB,MAAM,gBAAgB,CAAA;AACvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAS7D,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,kBAAkB,CAAoB;IAC9C,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,cAAc,CAAc;gBAGlC,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,aAAa,EAAE,aAAa,EAC5B,kBAAkB,EAAE,kBAAkB,EACtC,cAAc,EAAE,MAAM,MAAM,EAC5B,cAAc,EAAE,MAAM,MAAM;IAS9B;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IAK3B;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,iCAAiC;IAgCzC;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;;;;;;;OAQG;IACH,gBAAgB,CAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,GAAG,IAAI;IA+UjI;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,0BAA0B;IAkIlC;;;;;;;;;OASG;IACH,OAAO,CAAC,cAAc;CAevB"}
|
package/types/status.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAgB,MAAM,YAAY,CAAA;AAOpE;;GAEG;AACH,UAAU,aAAa;IACrB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAgB,MAAM,YAAY,CAAA;AAOpE;;GAEG;AACH,UAAU,aAAa;IACrB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAyHD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,SAAS,CAAE,MAAM,EAAE,oBAAoB,EAAE,OAAO,GAAE,aAAkB,iBAoDzF"}
|