i18next-cli 1.41.0 → 1.41.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 CHANGED
@@ -28,7 +28,7 @@ const program = new commander.Command();
28
28
  program
29
29
  .name('i18next-cli')
30
30
  .description('A unified, high-performance i18next CLI.')
31
- .version('1.41.0'); // This string is replaced with the actual version at build time by rollup
31
+ .version('1.41.2'); // This string is replaced with the actual version at build time by rollup
32
32
  // new: global config override option
33
33
  program.option('-c, --config <path>', 'Path to i18next-cli config file (overrides detection)');
34
34
  program
@@ -8,6 +8,7 @@ var defaultValue = require('../../utils/default-value.js');
8
8
 
9
9
  // used for natural language check
10
10
  const chars = [' ', ',', '?', '!', ';'];
11
+ const pluralForms = ['zero', 'one', 'two', 'few', 'many', 'other'];
11
12
  /**
12
13
  * Converts a glob pattern to a regular expression for matching keys
13
14
  * @param glob - The glob pattern to convert
@@ -37,7 +38,6 @@ function isContextVariantOfAcceptingKey(existingKey, keysAcceptingContext, plura
37
38
  // Try to extract the base key from this existing key by removing context and/or plural suffixes
38
39
  let potentialBaseKey = existingKey;
39
40
  // First, try removing plural suffixes if present
40
- const pluralForms = ['zero', 'one', 'two', 'few', 'many', 'other'];
41
41
  for (const form of pluralForms) {
42
42
  if (potentialBaseKey.endsWith(`${pluralSeparator}${form}`)) {
43
43
  potentialBaseKey = potentialBaseKey.slice(0, -(pluralSeparator.length + form.length));
@@ -97,8 +97,7 @@ function sortObject(obj, config, customSort) {
97
97
  const sortedObj = {};
98
98
  const pluralSeparator = config?.extract?.pluralSeparator ?? '_';
99
99
  // Define the canonical order for plural forms
100
- const pluralOrder = ['zero', 'one', 'two', 'few', 'many', 'other'];
101
- const ordinalPluralOrder = pluralOrder.map(form => `ordinal${pluralSeparator}${form}`);
100
+ const ordinalPluralOrder = pluralForms.map(form => `ordinal${pluralSeparator}${form}`);
102
101
  const keys = Object.keys(obj).sort((a, b) => {
103
102
  // Helper function to extract base key and form info
104
103
  const getKeyInfo = (key) => {
@@ -110,7 +109,7 @@ function sortObject(obj, config, customSort) {
110
109
  }
111
110
  }
112
111
  // Handle cardinal plurals: key_form or key_context_form
113
- for (const form of pluralOrder) {
112
+ for (const form of pluralForms) {
114
113
  if (key.endsWith(`${pluralSeparator}${form}`)) {
115
114
  const base = key.slice(0, -(pluralSeparator.length + form.length));
116
115
  return { base, form, isOrdinal: false, isPlural: true, fullKey: key };
@@ -135,7 +134,7 @@ function sortObject(obj, config, customSort) {
135
134
  return aInfo.isOrdinal ? 1 : -1;
136
135
  }
137
136
  // Both same type (cardinal or ordinal), sort by canonical order
138
- const orderArray = aInfo.isOrdinal ? ordinalPluralOrder : pluralOrder;
137
+ const orderArray = aInfo.isOrdinal ? ordinalPluralOrder : pluralForms;
139
138
  const aIndex = orderArray.indexOf(aInfo.form);
140
139
  const bIndex = orderArray.indexOf(bInfo.form);
141
140
  if (aIndex !== -1 && bIndex !== -1) {
@@ -366,6 +365,49 @@ function buildNewTranslationsForNs(nsKeys, existingTranslations, config, locale,
366
365
  nestedObject.setNestedValue(newTranslations, existingKey, value, keySeparator ?? '.');
367
366
  }
368
367
  }
368
+ // PRESERVE LOCALE-SPECIFIC PLURAL FORMS: When dealing with plural keys in non-primary locales,
369
+ // preserve any existing plural forms that are NOT being explicitly generated.
370
+ // This ensures that locale-specific forms (like _few, _many) added by translators are preserved.
371
+ if (locale !== primaryLanguage && removeUnusedKeys) {
372
+ const existingKeys = nestedObject.getNestedKeys(existingTranslations, keySeparator ?? '.');
373
+ for (const existingKey of existingKeys) {
374
+ // Check if this is a plural form variant (ends with _form)
375
+ let isPluralForm = false;
376
+ let baseKey = existingKey;
377
+ let foundForm = '';
378
+ for (const form of pluralForms) {
379
+ if (existingKey.endsWith(`${pluralSeparator}${form}`)) {
380
+ baseKey = existingKey.slice(0, -(pluralSeparator.length + form.length));
381
+ foundForm = form;
382
+ isPluralForm = true;
383
+ break;
384
+ }
385
+ }
386
+ if (isPluralForm && foundForm) {
387
+ // Check if the base key is in our filtered keys (meaning it's a plural key we're handling)
388
+ const isBaseInExtracted = filteredKeys.some(({ key }) => {
389
+ let extractedBase = key;
390
+ for (const form of pluralForms) {
391
+ if (extractedBase.endsWith(`${pluralSeparator}${form}`)) {
392
+ extractedBase = extractedBase.slice(0, -(pluralSeparator.length + form.length));
393
+ break;
394
+ }
395
+ }
396
+ return extractedBase === baseKey;
397
+ });
398
+ if (isBaseInExtracted) {
399
+ // This is a plural form for a key we're handling.
400
+ // Check if it's already in newTranslations (will be set by the normal flow)
401
+ const isAlreadySet = nestedObject.getNestedValue(newTranslations, existingKey, keySeparator ?? '.') !== undefined;
402
+ if (!isAlreadySet) {
403
+ // This plural form is NOT being generated by our code, so preserve it
404
+ const value = nestedObject.getNestedValue(existingTranslations, existingKey, keySeparator ?? '.');
405
+ nestedObject.setNestedValue(newTranslations, existingKey, value, keySeparator ?? '.');
406
+ }
407
+ }
408
+ }
409
+ }
410
+ }
369
411
  // SPECIAL HANDLING: Preserve existing _zero forms even if not in extracted keys
370
412
  // This ensures that optional _zero forms are not removed when they exist
371
413
  if (removeUnusedKeys) {
@@ -202,20 +202,29 @@ class CallExpressionHandler {
202
202
  if (!ns)
203
203
  ns = this.config.extract.defaultNS;
204
204
  let finalKey = key;
205
+ let keyPrefix;
206
+ // Check for keyPrefix in call options before falling back to scope
207
+ if (options) {
208
+ const kpVal = astUtils.getObjectPropValue(options, 'keyPrefix');
209
+ if (typeof kpVal === 'string')
210
+ keyPrefix = kpVal;
211
+ }
212
+ // Fall back to scope keyPrefix if not overridden in options
213
+ keyPrefix ||= scopeInfo?.keyPrefix;
205
214
  // Apply keyPrefix AFTER namespace extraction
206
- if (scopeInfo?.keyPrefix) {
215
+ if (keyPrefix) {
207
216
  const keySeparator = this.config.extract.keySeparator ?? '.';
208
217
  // Apply keyPrefix - handle case where keyPrefix already ends with separator
209
218
  if (keySeparator !== false) {
210
- if (scopeInfo.keyPrefix.endsWith(keySeparator)) {
211
- finalKey = `${scopeInfo.keyPrefix}${key}`;
219
+ if (keyPrefix.endsWith(keySeparator)) {
220
+ finalKey = `${keyPrefix}${key}`;
212
221
  }
213
222
  else {
214
- finalKey = `${scopeInfo.keyPrefix}${keySeparator}${key}`;
223
+ finalKey = `${keyPrefix}${keySeparator}${key}`;
215
224
  }
216
225
  }
217
226
  else {
218
- finalKey = `${scopeInfo.keyPrefix}${key}`;
227
+ finalKey = `${keyPrefix}${key}`;
219
228
  }
220
229
  // Validate keyPrefix combinations that create problematic keys
221
230
  if (keySeparator !== false) {
@@ -223,7 +232,7 @@ class CallExpressionHandler {
223
232
  const segments = finalKey.split(keySeparator);
224
233
  const hasEmptySegment = segments.some(segment => segment.trim() === '');
225
234
  if (hasEmptySegment) {
226
- this.logger.warn(`Skipping key with empty segments: '${finalKey}' (keyPrefix: '${scopeInfo.keyPrefix}', key: '${key}')`);
235
+ this.logger.warn(`Skipping key with empty segments: '${finalKey}' (keyPrefix: '${keyPrefix}', key: '${key}')`);
227
236
  continue;
228
237
  }
229
238
  }
package/dist/esm/cli.js CHANGED
@@ -26,7 +26,7 @@ const program = new Command();
26
26
  program
27
27
  .name('i18next-cli')
28
28
  .description('A unified, high-performance i18next CLI.')
29
- .version('1.41.0'); // This string is replaced with the actual version at build time by rollup
29
+ .version('1.41.2'); // This string is replaced with the actual version at build time by rollup
30
30
  // new: global config override option
31
31
  program.option('-c, --config <path>', 'Path to i18next-cli config file (overrides detection)');
32
32
  program
@@ -6,6 +6,7 @@ import { resolveDefaultValue } from '../../utils/default-value.js';
6
6
 
7
7
  // used for natural language check
8
8
  const chars = [' ', ',', '?', '!', ';'];
9
+ const pluralForms = ['zero', 'one', 'two', 'few', 'many', 'other'];
9
10
  /**
10
11
  * Converts a glob pattern to a regular expression for matching keys
11
12
  * @param glob - The glob pattern to convert
@@ -35,7 +36,6 @@ function isContextVariantOfAcceptingKey(existingKey, keysAcceptingContext, plura
35
36
  // Try to extract the base key from this existing key by removing context and/or plural suffixes
36
37
  let potentialBaseKey = existingKey;
37
38
  // First, try removing plural suffixes if present
38
- const pluralForms = ['zero', 'one', 'two', 'few', 'many', 'other'];
39
39
  for (const form of pluralForms) {
40
40
  if (potentialBaseKey.endsWith(`${pluralSeparator}${form}`)) {
41
41
  potentialBaseKey = potentialBaseKey.slice(0, -(pluralSeparator.length + form.length));
@@ -95,8 +95,7 @@ function sortObject(obj, config, customSort) {
95
95
  const sortedObj = {};
96
96
  const pluralSeparator = config?.extract?.pluralSeparator ?? '_';
97
97
  // Define the canonical order for plural forms
98
- const pluralOrder = ['zero', 'one', 'two', 'few', 'many', 'other'];
99
- const ordinalPluralOrder = pluralOrder.map(form => `ordinal${pluralSeparator}${form}`);
98
+ const ordinalPluralOrder = pluralForms.map(form => `ordinal${pluralSeparator}${form}`);
100
99
  const keys = Object.keys(obj).sort((a, b) => {
101
100
  // Helper function to extract base key and form info
102
101
  const getKeyInfo = (key) => {
@@ -108,7 +107,7 @@ function sortObject(obj, config, customSort) {
108
107
  }
109
108
  }
110
109
  // Handle cardinal plurals: key_form or key_context_form
111
- for (const form of pluralOrder) {
110
+ for (const form of pluralForms) {
112
111
  if (key.endsWith(`${pluralSeparator}${form}`)) {
113
112
  const base = key.slice(0, -(pluralSeparator.length + form.length));
114
113
  return { base, form, isOrdinal: false, isPlural: true, fullKey: key };
@@ -133,7 +132,7 @@ function sortObject(obj, config, customSort) {
133
132
  return aInfo.isOrdinal ? 1 : -1;
134
133
  }
135
134
  // Both same type (cardinal or ordinal), sort by canonical order
136
- const orderArray = aInfo.isOrdinal ? ordinalPluralOrder : pluralOrder;
135
+ const orderArray = aInfo.isOrdinal ? ordinalPluralOrder : pluralForms;
137
136
  const aIndex = orderArray.indexOf(aInfo.form);
138
137
  const bIndex = orderArray.indexOf(bInfo.form);
139
138
  if (aIndex !== -1 && bIndex !== -1) {
@@ -364,6 +363,49 @@ function buildNewTranslationsForNs(nsKeys, existingTranslations, config, locale,
364
363
  setNestedValue(newTranslations, existingKey, value, keySeparator ?? '.');
365
364
  }
366
365
  }
366
+ // PRESERVE LOCALE-SPECIFIC PLURAL FORMS: When dealing with plural keys in non-primary locales,
367
+ // preserve any existing plural forms that are NOT being explicitly generated.
368
+ // This ensures that locale-specific forms (like _few, _many) added by translators are preserved.
369
+ if (locale !== primaryLanguage && removeUnusedKeys) {
370
+ const existingKeys = getNestedKeys(existingTranslations, keySeparator ?? '.');
371
+ for (const existingKey of existingKeys) {
372
+ // Check if this is a plural form variant (ends with _form)
373
+ let isPluralForm = false;
374
+ let baseKey = existingKey;
375
+ let foundForm = '';
376
+ for (const form of pluralForms) {
377
+ if (existingKey.endsWith(`${pluralSeparator}${form}`)) {
378
+ baseKey = existingKey.slice(0, -(pluralSeparator.length + form.length));
379
+ foundForm = form;
380
+ isPluralForm = true;
381
+ break;
382
+ }
383
+ }
384
+ if (isPluralForm && foundForm) {
385
+ // Check if the base key is in our filtered keys (meaning it's a plural key we're handling)
386
+ const isBaseInExtracted = filteredKeys.some(({ key }) => {
387
+ let extractedBase = key;
388
+ for (const form of pluralForms) {
389
+ if (extractedBase.endsWith(`${pluralSeparator}${form}`)) {
390
+ extractedBase = extractedBase.slice(0, -(pluralSeparator.length + form.length));
391
+ break;
392
+ }
393
+ }
394
+ return extractedBase === baseKey;
395
+ });
396
+ if (isBaseInExtracted) {
397
+ // This is a plural form for a key we're handling.
398
+ // Check if it's already in newTranslations (will be set by the normal flow)
399
+ const isAlreadySet = getNestedValue(newTranslations, existingKey, keySeparator ?? '.') !== undefined;
400
+ if (!isAlreadySet) {
401
+ // This plural form is NOT being generated by our code, so preserve it
402
+ const value = getNestedValue(existingTranslations, existingKey, keySeparator ?? '.');
403
+ setNestedValue(newTranslations, existingKey, value, keySeparator ?? '.');
404
+ }
405
+ }
406
+ }
407
+ }
408
+ }
367
409
  // SPECIAL HANDLING: Preserve existing _zero forms even if not in extracted keys
368
410
  // This ensures that optional _zero forms are not removed when they exist
369
411
  if (removeUnusedKeys) {
@@ -200,20 +200,29 @@ class CallExpressionHandler {
200
200
  if (!ns)
201
201
  ns = this.config.extract.defaultNS;
202
202
  let finalKey = key;
203
+ let keyPrefix;
204
+ // Check for keyPrefix in call options before falling back to scope
205
+ if (options) {
206
+ const kpVal = getObjectPropValue(options, 'keyPrefix');
207
+ if (typeof kpVal === 'string')
208
+ keyPrefix = kpVal;
209
+ }
210
+ // Fall back to scope keyPrefix if not overridden in options
211
+ keyPrefix ||= scopeInfo?.keyPrefix;
203
212
  // Apply keyPrefix AFTER namespace extraction
204
- if (scopeInfo?.keyPrefix) {
213
+ if (keyPrefix) {
205
214
  const keySeparator = this.config.extract.keySeparator ?? '.';
206
215
  // Apply keyPrefix - handle case where keyPrefix already ends with separator
207
216
  if (keySeparator !== false) {
208
- if (scopeInfo.keyPrefix.endsWith(keySeparator)) {
209
- finalKey = `${scopeInfo.keyPrefix}${key}`;
217
+ if (keyPrefix.endsWith(keySeparator)) {
218
+ finalKey = `${keyPrefix}${key}`;
210
219
  }
211
220
  else {
212
- finalKey = `${scopeInfo.keyPrefix}${keySeparator}${key}`;
221
+ finalKey = `${keyPrefix}${keySeparator}${key}`;
213
222
  }
214
223
  }
215
224
  else {
216
- finalKey = `${scopeInfo.keyPrefix}${key}`;
225
+ finalKey = `${keyPrefix}${key}`;
217
226
  }
218
227
  // Validate keyPrefix combinations that create problematic keys
219
228
  if (keySeparator !== false) {
@@ -221,7 +230,7 @@ class CallExpressionHandler {
221
230
  const segments = finalKey.split(keySeparator);
222
231
  const hasEmptySegment = segments.some(segment => segment.trim() === '');
223
232
  if (hasEmptySegment) {
224
- this.logger.warn(`Skipping key with empty segments: '${finalKey}' (keyPrefix: '${scopeInfo.keyPrefix}', key: '${key}')`);
233
+ this.logger.warn(`Skipping key with empty segments: '${finalKey}' (keyPrefix: '${keyPrefix}', key: '${key}')`);
225
234
  continue;
226
235
  }
227
236
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "i18next-cli",
3
- "version": "1.41.0",
3
+ "version": "1.41.2",
4
4
  "description": "A unified, high-performance i18next CLI.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -55,8 +55,8 @@
55
55
  "@rollup/plugin-replace": "6.0.3",
56
56
  "@rollup/plugin-terser": "0.4.4",
57
57
  "@types/inquirer": "9.0.9",
58
- "@types/node": "25.0.10",
59
- "@types/react": "19.2.9",
58
+ "@types/node": "25.2.0",
59
+ "@types/react": "19.2.10",
60
60
  "@vitest/coverage-v8": "4.0.18",
61
61
  "eslint": "9.39.2",
62
62
  "eslint-plugin-import": "2.32.0",
@@ -70,20 +70,20 @@
70
70
  },
71
71
  "dependencies": {
72
72
  "@croct/json5-parser": "0.2.2",
73
- "@swc/core": "1.15.10",
73
+ "@swc/core": "1.15.11",
74
74
  "chalk": "5.6.2",
75
75
  "chokidar": "5.0.0",
76
- "commander": "14.0.2",
76
+ "commander": "14.0.3",
77
77
  "execa": "9.6.1",
78
78
  "glob": "13.0.0",
79
79
  "i18next-resources-for-ts": "2.0.0",
80
- "inquirer": "13.2.1",
80
+ "inquirer": "13.2.2",
81
81
  "jiti": "2.6.1",
82
82
  "jsonc-parser": "3.3.1",
83
83
  "minimatch": "10.1.1",
84
84
  "ora": "9.1.0",
85
- "react": "^19.2.3",
86
- "react-i18next": "^16.5.3",
85
+ "react": "^19.2.4",
86
+ "react-i18next": "^16.5.4",
87
87
  "swc-walk": "1.0.1"
88
88
  }
89
89
  }
@@ -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,aAAa,CAAA;AA0rBnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;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,EAChB,GAAE;IACD,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,CAAA;CACb,GACL,OAAO,CAAC,iBAAiB,EAAE,CAAC,CA0I9B"}
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,aAAa,CAAA;AA2uBnF;;;;;;;;;;;;;;;;;;;;;;;;;;;;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,EAChB,GAAE;IACD,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,CAAA;CACb,GACL,OAAO,CAAC,iBAAiB,EAAE,CAAC,CA0I9B"}
@@ -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,aAAa,CAAA;AACvG,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAM1D,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,eAAe,CAAY;gBAGjC,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;IAU9B;;;OAGG;IACI,gBAAgB,IAAK,IAAI;IAIhC;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA4C3B;;;;;;;;;;;;;;OAcG;IACH,oBAAoB,CAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,GAAG,SAAS,GAAG,IAAI;IAuXxG;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA4BzB,OAAO,CAAC,oBAAoB;IA6E5B,OAAO,CAAC,wBAAwB;IAyEhC;;;;;;OAMG;IACH,OAAO,CAAC,4BAA4B;IA8BpC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,sBAAsB;IA2C9B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,gBAAgB;IA6LxB;;;;;;;;;OASG;IACH,OAAO,CAAC,eAAe;CA2BxB"}
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,aAAa,CAAA;AACvG,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAM1D,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,eAAe,CAAY;gBAGjC,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;IAU9B;;;OAGG;IACI,gBAAgB,IAAK,IAAI;IAIhC;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA4C3B;;;;;;;;;;;;;;OAcG;IACH,oBAAoB,CAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,GAAG,SAAS,GAAG,IAAI;IAgYxG;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA4BzB,OAAO,CAAC,oBAAoB;IA6E5B,OAAO,CAAC,wBAAwB;IAyEhC;;;;;;OAMG;IACH,OAAO,CAAC,4BAA4B;IA8BpC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,sBAAsB;IA2C9B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,gBAAgB;IA6LxB;;;;;;;;;OASG;IACH,OAAO,CAAC,eAAe;CA2BxB"}