@vocab/core 1.2.0 → 1.2.1

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.
@@ -27,7 +27,7 @@ var IntlMessageFormat__default = /*#__PURE__*/_interopDefault(IntlMessageFormat)
27
27
  var findUp__default = /*#__PURE__*/_interopDefault(findUp);
28
28
  var Validator__default = /*#__PURE__*/_interopDefault(Validator);
29
29
 
30
- const trace = debug__default['default'](`vocab:core`);
30
+ const trace = debug__default["default"](`vocab:core`);
31
31
 
32
32
  const defaultTranslationDirSuffix = '.vocab';
33
33
  const devTranslationFileName = 'translations.json';
@@ -74,37 +74,35 @@ function getAltLanguages({
74
74
  return languages.map(v => v.name).filter(lang => lang !== devLanguage);
75
75
  }
76
76
  function getDevLanguageFileFromTsFile(tsFilePath) {
77
- const directory = path__default['default'].dirname(tsFilePath);
78
- const result = path__default['default'].normalize(path__default['default'].join(directory, devTranslationFileName));
77
+ const directory = path__default["default"].dirname(tsFilePath);
78
+ const result = path__default["default"].normalize(path__default["default"].join(directory, devTranslationFileName));
79
79
  trace(`Returning dev language path ${result} for path ${tsFilePath}`);
80
80
  return result;
81
81
  }
82
82
  function getDevLanguageFileFromAltLanguageFile(altLanguageFilePath) {
83
- const directory = path__default['default'].dirname(altLanguageFilePath);
84
- const result = path__default['default'].normalize(path__default['default'].join(directory, devTranslationFileName));
83
+ const directory = path__default["default"].dirname(altLanguageFilePath);
84
+ const result = path__default["default"].normalize(path__default["default"].join(directory, devTranslationFileName));
85
85
  trace(`Returning dev language path ${result} for path ${altLanguageFilePath}`);
86
86
  return result;
87
87
  }
88
88
  function getTSFileFromDevLanguageFile(devLanguageFilePath) {
89
- const directory = path__default['default'].dirname(devLanguageFilePath);
90
- const result = path__default['default'].normalize(path__default['default'].join(directory, 'index.ts'));
89
+ const directory = path__default["default"].dirname(devLanguageFilePath);
90
+ const result = path__default["default"].normalize(path__default["default"].join(directory, 'index.ts'));
91
91
  trace(`Returning TS path ${result} for path ${devLanguageFilePath}`);
92
92
  return result;
93
93
  }
94
94
  function getAltLanguageFilePath(devLanguageFilePath, language) {
95
- const directory = path__default['default'].dirname(devLanguageFilePath);
96
- const result = path__default['default'].normalize(path__default['default'].join(directory, `${language}.translations.json`));
95
+ const directory = path__default["default"].dirname(devLanguageFilePath);
96
+ const result = path__default["default"].normalize(path__default["default"].join(directory, `${language}.translations.json`));
97
97
  trace(`Returning alt language path ${result} for path ${devLanguageFilePath}`);
98
- return path__default['default'].normalize(result);
98
+ return path__default["default"].normalize(result);
99
99
  }
100
100
  function mapValues(obj, func) {
101
101
  const newObj = {};
102
102
  const keys = Object.keys(obj);
103
-
104
103
  for (const key of keys) {
105
104
  newObj[key] = func(obj[key]);
106
105
  }
107
-
108
106
  return newObj;
109
107
  }
110
108
  function getTranslationMessages(translations) {
@@ -118,60 +116,49 @@ function generateLanguageFromTranslations({
118
116
  if (!generator.transformElement && !generator.transformMessage) {
119
117
  return baseTranslations;
120
118
  }
121
-
122
119
  const translationKeys = Object.keys(baseTranslations);
123
120
  const generatedTranslations = {};
124
-
125
121
  for (const translationKey of translationKeys) {
126
122
  const translation = baseTranslations[translationKey];
127
123
  let transformedMessage = translation.message;
128
-
129
124
  if (generator.transformElement) {
130
- const messageAst = new IntlMessageFormat__default['default'](translation.message).getAst();
125
+ const messageAst = new IntlMessageFormat__default["default"](translation.message).getAst();
131
126
  const transformedAst = messageAst.map(transformMessageFormatElement(generator.transformElement));
132
127
  transformedMessage = printer.printAST(transformedAst);
133
128
  }
134
-
135
129
  if (generator.transformMessage) {
136
130
  transformedMessage = generator.transformMessage(transformedMessage);
137
131
  }
138
-
139
132
  generatedTranslations[translationKey] = {
140
133
  message: transformedMessage
141
134
  };
142
135
  }
143
-
144
136
  return generatedTranslations;
145
137
  }
146
-
147
138
  function transformMessageFormatElement(transformElement) {
148
139
  return messageFormatElement => {
149
- const transformedMessageFormatElement = { ...messageFormatElement
140
+ const transformedMessageFormatElement = {
141
+ ...messageFormatElement
150
142
  };
151
-
152
143
  switch (transformedMessageFormatElement.type) {
153
144
  case icuMessageformatParser.TYPE.literal:
154
145
  const transformedValue = transformElement(transformedMessageFormatElement.value);
155
146
  transformedMessageFormatElement.value = transformedValue;
156
147
  break;
157
-
158
148
  case icuMessageformatParser.TYPE.select:
159
149
  case icuMessageformatParser.TYPE.plural:
160
- const transformedOptions = { ...transformedMessageFormatElement.options
150
+ const transformedOptions = {
151
+ ...transformedMessageFormatElement.options
161
152
  };
162
-
163
153
  for (const key of Object.keys(transformedOptions)) {
164
154
  transformedOptions[key].value = transformedOptions[key].value.map(transformMessageFormatElement(transformElement));
165
155
  }
166
-
167
156
  break;
168
-
169
157
  case icuMessageformatParser.TYPE.tag:
170
158
  const transformedChildren = transformedMessageFormatElement.children.map(transformMessageFormatElement(transformElement));
171
159
  transformedMessageFormatElement.children = transformedChildren;
172
160
  break;
173
161
  }
174
-
175
162
  return transformedMessageFormatElement;
176
163
  };
177
164
  }
@@ -186,7 +173,6 @@ function mergeWithDevLanguageTranslation({
186
173
  // Only use keys from the dev translation
187
174
  const keys = Object.keys(devTranslation);
188
175
  const newLanguage = {};
189
-
190
176
  for (const key of keys) {
191
177
  if (translation[key]) {
192
178
  newLanguage[key] = {
@@ -195,24 +181,19 @@ function mergeWithDevLanguageTranslation({
195
181
  };
196
182
  }
197
183
  }
198
-
199
184
  return newLanguage;
200
185
  }
201
-
202
186
  function getLanguageFallbacks({
203
187
  languages
204
188
  }) {
205
189
  const languageFallbackMap = new Map();
206
-
207
190
  for (const lang of languages) {
208
191
  if (lang.extends) {
209
192
  languageFallbackMap.set(lang.name, lang.extends);
210
193
  }
211
194
  }
212
-
213
195
  return languageFallbackMap;
214
196
  }
215
-
216
197
  function getLanguageHierarchy({
217
198
  languages
218
199
  }) {
@@ -220,19 +201,15 @@ function getLanguageHierarchy({
220
201
  const fallbacks = getLanguageFallbacks({
221
202
  languages
222
203
  });
223
-
224
204
  for (const lang of languages) {
225
205
  const langHierarchy = [];
226
206
  let currLang = lang.extends;
227
-
228
207
  while (currLang) {
229
208
  langHierarchy.push(currLang);
230
209
  currLang = fallbacks.get(currLang);
231
210
  }
232
-
233
211
  hierarchyMap.set(lang.name, langHierarchy);
234
212
  }
235
-
236
213
  return hierarchyMap;
237
214
  }
238
215
  function getFallbackLanguageOrder({
@@ -244,41 +221,31 @@ function getFallbackLanguageOrder({
244
221
  const languageHierarchy = getLanguageHierarchy({
245
222
  languages
246
223
  }).get(languageName);
247
-
248
224
  if (!languageHierarchy) {
249
225
  throw new Error(`Missing language hierarchy for ${languageName}`);
250
226
  }
251
-
252
227
  const fallbackLanguageOrder = [languageName];
253
-
254
228
  if (fallbacks !== 'none') {
255
229
  fallbackLanguageOrder.unshift(...languageHierarchy.reverse());
256
-
257
230
  if (fallbacks === 'all' && fallbackLanguageOrder[0] !== devLanguage) {
258
231
  fallbackLanguageOrder.unshift(devLanguage);
259
232
  }
260
233
  }
261
-
262
234
  return fallbackLanguageOrder;
263
235
  }
264
-
265
236
  function getNamespaceByFilePath(relativePath, {
266
237
  translationsDirectorySuffix = defaultTranslationDirSuffix
267
238
  }) {
268
- let namespace = path__default['default'].dirname(relativePath).replace(/^src\//, '').replace(/\//g, '_');
269
-
239
+ let namespace = path__default["default"].dirname(relativePath).replace(/^src\//, '').replace(/\//g, '_');
270
240
  if (namespace.endsWith(translationsDirectorySuffix)) {
271
241
  namespace = namespace.slice(0, -translationsDirectorySuffix.length);
272
242
  }
273
-
274
243
  return namespace;
275
244
  }
276
-
277
245
  function printValidationError(...params) {
278
246
  // eslint-disable-next-line no-console
279
- console.error(chalk__default['default'].red('Error loading translation:'), ...params);
247
+ console.error(chalk__default["default"].red('Error loading translation:'), ...params);
280
248
  }
281
-
282
249
  function getTranslationsFromFile(translationFileContents, {
283
250
  isAltLanguage,
284
251
  filePath,
@@ -287,29 +254,24 @@ function getTranslationsFromFile(translationFileContents, {
287
254
  if (!translationFileContents || typeof translationFileContents !== 'object') {
288
255
  throw new Error(`Unable to read translation file ${filePath}. Translations must be an object.`);
289
256
  }
290
-
291
257
  const {
292
258
  $namespace,
293
259
  _meta,
294
260
  ...keys
295
261
  } = translationFileContents;
296
-
297
262
  if (isAltLanguage && $namespace) {
298
263
  printValidationError(`Found $namespace in alt language file in ${filePath}. $namespace is only used in the dev language and will be ignored.`);
299
264
  }
300
-
301
265
  if (!isAltLanguage && $namespace && typeof $namespace !== 'string') {
302
266
  printValidationError(`Found non-string $namespace in language file in ${filePath}. $namespace must be a string.`);
303
267
  }
304
-
305
268
  if (isAltLanguage && _meta !== null && _meta !== void 0 && _meta.tags) {
306
269
  printValidationError(`Found _meta.tags in alt language file in ${filePath}. _meta.tags is only used in the dev language and will be ignored.`);
307
- } // Never return tags if we're fetching translations for an alt language
308
-
270
+ }
309
271
 
272
+ // Never return tags if we're fetching translations for an alt language
310
273
  const includeTags = !isAltLanguage && withTags;
311
274
  const validKeys = {};
312
-
313
275
  for (const [translationKey, {
314
276
  tags,
315
277
  ...translation
@@ -318,22 +280,19 @@ function getTranslationsFromFile(translationFileContents, {
318
280
  printValidationError(`Found string for a translation "${translationKey}" in ${filePath}. Translation must be an object of the format {message: string}.`);
319
281
  continue;
320
282
  }
321
-
322
283
  if (!translation) {
323
284
  printValidationError(`Found empty translation "${translationKey}" in ${filePath}. Translation must be an object of the format {message: string}.`);
324
285
  continue;
325
286
  }
326
-
327
287
  if (!translation.message || typeof translation.message !== 'string') {
328
288
  printValidationError(`No message found for translation "${translationKey}" in ${filePath}. Translation must be an object of the format {message: string}.`);
329
289
  continue;
330
290
  }
331
-
332
- validKeys[translationKey] = { ...translation,
291
+ validKeys[translationKey] = {
292
+ ...translation,
333
293
  tags: includeTags ? tags : undefined
334
294
  };
335
295
  }
336
-
337
296
  const metadata = {
338
297
  tags: includeTags ? _meta === null || _meta === void 0 ? void 0 : _meta.tags : undefined
339
298
  };
@@ -343,7 +302,6 @@ function getTranslationsFromFile(translationFileContents, {
343
302
  metadata
344
303
  };
345
304
  }
346
-
347
305
  function loadAltLanguageFile({
348
306
  filePath,
349
307
  languageName,
@@ -361,15 +319,12 @@ function loadAltLanguageFile({
361
319
  fallbacks
362
320
  });
363
321
  trace(`Loading alt language file with precedence: ${fallbackLanguageOrder.slice().reverse().join(' -> ')}`);
364
-
365
322
  for (const fallbackLanguage of fallbackLanguageOrder) {
366
323
  if (fallbackLanguage !== devLanguage) {
367
324
  try {
368
325
  const altFilePath = getAltLanguageFilePath(filePath, fallbackLanguage);
369
326
  delete require.cache[altFilePath];
370
-
371
327
  const translationFile = require(altFilePath);
372
-
373
328
  const {
374
329
  keys: fallbackLanguageTranslation
375
330
  } = getTranslationsFromFile(translationFile, {
@@ -388,17 +343,14 @@ function loadAltLanguageFile({
388
343
  Object.assign(altLanguageTranslation, devTranslation);
389
344
  }
390
345
  }
391
-
392
346
  return altLanguageTranslation;
393
347
  }
394
-
395
348
  function stripTagsFromTranslations(translations) {
396
349
  return Object.fromEntries(Object.entries(translations).map(([key, {
397
350
  tags,
398
351
  ...rest
399
352
  }]) => [key, rest]));
400
353
  }
401
-
402
354
  function loadTranslation({
403
355
  filePath,
404
356
  fallbacks,
@@ -407,10 +359,8 @@ function loadTranslation({
407
359
  trace(`Loading translation file in "${fallbacks}" fallback mode: "${filePath}"`);
408
360
  const languageSet = {};
409
361
  delete require.cache[filePath];
410
-
411
362
  const translationContent = require(filePath);
412
-
413
- const relativePath = path__default['default'].relative(userConfig.projectRoot || process.cwd(), filePath);
363
+ const relativePath = path__default["default"].relative(userConfig.projectRoot || process.cwd(), filePath);
414
364
  const {
415
365
  $namespace,
416
366
  keys: devTranslation,
@@ -425,7 +375,6 @@ function loadTranslation({
425
375
  languageSet[userConfig.devLanguage] = devTranslation;
426
376
  const devTranslationNoTags = withTags ? stripTagsFromTranslations(devTranslation) : devTranslation;
427
377
  const altLanguages = getAltLanguages(userConfig);
428
-
429
378
  for (const languageName of altLanguages) {
430
379
  languageSet[languageName] = loadAltLanguageFile({
431
380
  filePath,
@@ -434,7 +383,6 @@ function loadTranslation({
434
383
  fallbacks
435
384
  }, userConfig);
436
385
  }
437
-
438
386
  for (const generatedLanguage of userConfig.generatedLanguages || []) {
439
387
  const {
440
388
  name: generatedLanguageName,
@@ -447,7 +395,6 @@ function loadTranslation({
447
395
  generator
448
396
  });
449
397
  }
450
-
451
398
  return {
452
399
  filePath,
453
400
  keys: Object.keys(devTranslation),
@@ -466,7 +413,7 @@ async function loadAllTranslations({
466
413
  projectRoot,
467
414
  ignore = []
468
415
  } = config;
469
- const translationFiles = await glob__default['default'](getDevTranslationFileGlob(config), {
416
+ const translationFiles = await glob__default["default"](getDevTranslationFileGlob(config), {
470
417
  ignore: includeNodeModules ? ignore : [...ignore, '**/node_modules/**'],
471
418
  absolute: true,
472
419
  cwd: projectRoot
@@ -478,42 +425,33 @@ async function loadAllTranslations({
478
425
  withTags
479
426
  }, config)));
480
427
  const keys = new Set();
481
-
482
428
  for (const loadedTranslation of result) {
483
429
  for (const key of loadedTranslation.keys) {
484
430
  const uniqueKey = getUniqueKey(key, loadedTranslation.namespace);
485
-
486
431
  if (keys.has(uniqueKey)) {
487
432
  trace(`Duplicate keys found`);
488
433
  throw new Error(`Duplicate keys found. Key with namespace ${loadedTranslation.namespace} and key ${key} was found multiple times.`);
489
434
  }
490
-
491
435
  keys.add(uniqueKey);
492
436
  }
493
437
  }
494
-
495
438
  return result;
496
439
  }
497
440
 
498
441
  const encodeWithinSingleQuotes = v => v.replace(/'/g, "\\'");
499
-
500
442
  const encodeBackslash = v => v.replace(/\\/g, '\\\\');
501
-
502
443
  function extractHasTags(ast) {
503
444
  return ast.some(element => {
504
445
  if (icuMessageformatParser.isSelectElement(element)) {
505
446
  const children = Object.values(element.options).map(o => o.value);
506
447
  return children.some(child => extractHasTags(child));
507
448
  }
508
-
509
449
  return icuMessageformatParser.isTagElement(element);
510
450
  });
511
451
  }
512
-
513
452
  function extractParamTypes(ast) {
514
453
  let params = {};
515
454
  let imports = new Set();
516
-
517
455
  for (const element of ast) {
518
456
  if (icuMessageformatParser.isArgumentElement(element)) {
519
457
  params[element.value] = 'string';
@@ -521,6 +459,15 @@ function extractParamTypes(ast) {
521
459
  params[element.value] = 'number';
522
460
  } else if (icuMessageformatParser.isPluralElement(element)) {
523
461
  params[element.value] = 'number';
462
+ const children = Object.values(element.options).map(o => o.value);
463
+ for (const child of children) {
464
+ const [subParams, subImports] = extractParamTypes(child);
465
+ imports = new Set([...imports, ...subImports]);
466
+ params = {
467
+ ...params,
468
+ ...subParams
469
+ };
470
+ }
524
471
  } else if (icuMessageformatParser.isDateElement(element) || icuMessageformatParser.isTimeElement(element)) {
525
472
  params[element.value] = 'Date | number';
526
473
  } else if (icuMessageformatParser.isTagElement(element)) {
@@ -528,29 +475,27 @@ function extractParamTypes(ast) {
528
475
  imports.add(`import { FormatXMLElementFn } from '@vocab/types';`);
529
476
  const [subParams, subImports] = extractParamTypes(element.children);
530
477
  imports = new Set([...imports, ...subImports]);
531
- params = { ...params,
478
+ params = {
479
+ ...params,
532
480
  ...subParams
533
481
  };
534
482
  } else if (icuMessageformatParser.isSelectElement(element)) {
535
483
  params[element.value] = Object.keys(element.options).map(o => `'${o}'`).join(' | ');
536
484
  const children = Object.values(element.options).map(o => o.value);
537
-
538
485
  for (const child of children) {
539
486
  const [subParams, subImports] = extractParamTypes(child);
540
487
  imports = new Set([...imports, ...subImports]);
541
- params = { ...params,
488
+ params = {
489
+ ...params,
542
490
  ...subParams
543
491
  };
544
492
  }
545
493
  }
546
494
  }
547
-
548
495
  return [params, imports];
549
496
  }
550
-
551
497
  function serialiseObjectToType(v) {
552
498
  let result = '';
553
-
554
499
  for (const [key, value] of Object.entries(v)) {
555
500
  if (value && typeof value === 'object') {
556
501
  result += `'${encodeWithinSingleQuotes(key)}': ${serialiseObjectToType(value)},`;
@@ -558,32 +503,25 @@ function serialiseObjectToType(v) {
558
503
  result += `'${encodeWithinSingleQuotes(key)}': ${value},`;
559
504
  }
560
505
  }
561
-
562
506
  return `{ ${result} }`;
563
507
  }
564
-
565
508
  const banner = `// This file is automatically generated by Vocab.\n// To make changes update translation.json files directly.`;
566
-
567
509
  function serialiseTranslationRuntime(value, imports, loadedTranslation) {
568
510
  trace('Serialising translations:', loadedTranslation);
569
511
  const translationsType = {};
570
-
571
512
  for (const [key, {
572
513
  params,
573
514
  message,
574
515
  hasTags
575
516
  }] of value.entries()) {
576
517
  let translationFunctionString = `() => ${message}`;
577
-
578
518
  if (Object.keys(params).length > 0) {
579
519
  const formatGeneric = hasTags ? '<T = string>' : '';
580
520
  const formatReturn = hasTags ? 'string | T | Array<string | T>' : 'string';
581
521
  translationFunctionString = `${formatGeneric}(values: ${serialiseObjectToType(params)}) => ${formatReturn}`;
582
522
  }
583
-
584
523
  translationsType[encodeBackslash(key)] = translationFunctionString;
585
524
  }
586
-
587
525
  const content = Object.entries(loadedTranslation.languages).map(([languageName, translations]) => `'${encodeWithinSingleQuotes(languageName)}': createLanguage(${JSON.stringify(getTranslationMessages(translations))})`).join(',');
588
526
  const languagesUnionAsString = Object.keys(loadedTranslation.languages).map(l => `'${l}'`).join(' | ');
589
527
  return `${banner}
@@ -595,7 +533,6 @@ function serialiseTranslationRuntime(value, imports, loadedTranslation) {
595
533
 
596
534
  export default translations;`;
597
535
  }
598
-
599
536
  async function generateRuntime(loadedTranslation) {
600
537
  const {
601
538
  languages: loadedLanguages,
@@ -604,25 +541,23 @@ async function generateRuntime(loadedTranslation) {
604
541
  trace('Generating types for', filePath);
605
542
  const translationTypes = new Map();
606
543
  let imports = new Set();
607
-
608
544
  for (const key of loadedTranslation.keys) {
609
545
  let params = {};
610
546
  const messages = new Set();
611
547
  let hasTags = false;
612
-
613
548
  for (const translatedLanguage of Object.values(loadedLanguages)) {
614
549
  if (translatedLanguage[key]) {
615
550
  const ast = icuMessageformatParser.parse(translatedLanguage[key].message);
616
551
  hasTags = hasTags || extractHasTags(ast);
617
552
  const [parsedParams, parsedImports] = extractParamTypes(ast);
618
553
  imports = new Set([...imports, ...parsedImports]);
619
- params = { ...params,
554
+ params = {
555
+ ...params,
620
556
  ...parsedParams
621
557
  };
622
558
  messages.add(`'${encodeWithinSingleQuotes(translatedLanguage[key].message)}'`);
623
559
  }
624
560
  }
625
-
626
561
  const returnType = hasTags ? 'NonNullable<ReactNode>' : 'string';
627
562
  translationTypes.set(key, {
628
563
  params,
@@ -631,10 +566,10 @@ async function generateRuntime(loadedTranslation) {
631
566
  returnType
632
567
  });
633
568
  }
634
-
635
- const prettierConfig = await prettier__default['default'].resolveConfig(filePath);
569
+ const prettierConfig = await prettier__default["default"].resolveConfig(filePath);
636
570
  const serializedTranslationType = serialiseTranslationRuntime(translationTypes, imports, loadedTranslation);
637
- const declaration = prettier__default['default'].format(serializedTranslationType, { ...prettierConfig,
571
+ const declaration = prettier__default["default"].format(serializedTranslationType, {
572
+ ...prettierConfig,
638
573
  parser: 'typescript'
639
574
  });
640
575
  const outputFilePath = getTSFileFromDevLanguageFile(filePath);
@@ -643,22 +578,19 @@ async function generateRuntime(loadedTranslation) {
643
578
  }
644
579
  function watch(config) {
645
580
  const cwd = config.projectRoot || process.cwd();
646
- const watcher = chokidar__default['default'].watch([getDevTranslationFileGlob(config), getAltTranslationFileGlob(config), getTranslationFolderGlob(config)], {
581
+ const watcher = chokidar__default["default"].watch([getDevTranslationFileGlob(config), getAltTranslationFileGlob(config), getTranslationFolderGlob(config)], {
647
582
  cwd,
648
583
  ignored: config.ignore ? [...config.ignore, '**/node_modules/**'] : ['**/node_modules/**'],
649
584
  ignoreInitial: true
650
585
  });
651
-
652
586
  const onTranslationChange = async relativePath => {
653
587
  trace(`Detected change for file ${relativePath}`);
654
588
  let targetFile;
655
-
656
589
  if (isDevLanguageFile(relativePath)) {
657
- targetFile = path__default['default'].resolve(cwd, relativePath);
590
+ targetFile = path__default["default"].resolve(cwd, relativePath);
658
591
  } else if (isAltLanguageFile(relativePath)) {
659
- targetFile = getDevLanguageFileFromAltLanguageFile(path__default['default'].resolve(cwd, relativePath));
592
+ targetFile = getDevLanguageFileFromAltLanguageFile(path__default["default"].resolve(cwd, relativePath));
660
593
  }
661
-
662
594
  if (targetFile) {
663
595
  try {
664
596
  const loadedTranslation = loadTranslation({
@@ -668,23 +600,19 @@ function watch(config) {
668
600
  await generateRuntime(loadedTranslation);
669
601
  } catch (e) {
670
602
  // eslint-disable-next-line no-console
671
- console.log('Failed to generate types for', relativePath); // eslint-disable-next-line no-console
672
-
603
+ console.log('Failed to generate types for', relativePath);
604
+ // eslint-disable-next-line no-console
673
605
  console.error(e);
674
606
  }
675
607
  }
676
608
  };
677
-
678
609
  const onNewDirectory = async relativePath => {
679
610
  trace('Detected new directory', relativePath);
680
-
681
611
  if (!isTranslationDirectory(relativePath, config)) {
682
612
  trace('Ignoring non-translation directory:', relativePath);
683
613
  return;
684
614
  }
685
-
686
- const newFilePath = path__default['default'].join(relativePath, devTranslationFileName);
687
-
615
+ const newFilePath = path__default["default"].join(relativePath, devTranslationFileName);
688
616
  if (!fs.existsSync(newFilePath)) {
689
617
  await fs.promises.writeFile(newFilePath, JSON.stringify({}, null, 2));
690
618
  trace('Created new empty translation file:', newFilePath);
@@ -692,7 +620,6 @@ function watch(config) {
692
620
  trace(`New directory already contains translation file. Skipping creation. Existing file ${newFilePath}`);
693
621
  }
694
622
  };
695
-
696
623
  watcher.on('addDir', onNewDirectory);
697
624
  watcher.on('add', onTranslationChange).on('change', onTranslationChange);
698
625
  return () => watcher.close();
@@ -704,28 +631,24 @@ async function compile({
704
631
  fallbacks: 'all',
705
632
  includeNodeModules: false
706
633
  }, config);
707
-
708
634
  for (const loadedTranslation of translations) {
709
635
  await generateRuntime(loadedTranslation);
710
636
  }
711
-
712
637
  if (shouldWatch) {
713
638
  trace('Listening for changes to files...');
714
639
  return watch(config);
715
640
  }
716
641
  }
717
-
718
642
  async function writeIfChanged(filepath, contents) {
719
643
  let hasChanged = true;
720
-
721
644
  try {
722
645
  const existingContents = await fs.promises.readFile(filepath, {
723
646
  encoding: 'utf-8'
724
647
  });
725
648
  hasChanged = existingContents !== contents;
726
- } catch (e) {// ignore error, likely a file doesn't exist error so we want to write anyway
649
+ } catch (e) {
650
+ // ignore error, likely a file doesn't exist error so we want to write anyway
727
651
  }
728
-
729
652
  if (hasChanged) {
730
653
  await fs.promises.writeFile(filepath, contents, {
731
654
  encoding: 'utf-8'
@@ -736,36 +659,28 @@ async function writeIfChanged(filepath, contents) {
736
659
  /* eslint-disable no-console */
737
660
  function findMissingKeys(loadedTranslation, devLanguageName, altLanguages) {
738
661
  const devLanguage = loadedTranslation.languages[devLanguageName];
739
-
740
662
  if (!devLanguage) {
741
663
  throw new Error(`Failed to load dev language: ${loadedTranslation.filePath}`);
742
664
  }
743
-
744
665
  const result = {};
745
666
  let valid = true;
746
667
  const requiredKeys = Object.keys(devLanguage);
747
-
748
668
  if (requiredKeys.length > 0) {
749
669
  for (const altLanguageName of altLanguages) {
750
670
  var _loadedTranslation$la;
751
-
752
671
  const altLanguage = (_loadedTranslation$la = loadedTranslation.languages[altLanguageName]) !== null && _loadedTranslation$la !== void 0 ? _loadedTranslation$la : {};
753
-
754
672
  for (const key of requiredKeys) {
755
673
  var _altLanguage$key;
756
-
757
674
  if (typeof ((_altLanguage$key = altLanguage[key]) === null || _altLanguage$key === void 0 ? void 0 : _altLanguage$key.message) !== 'string') {
758
675
  if (!result[altLanguageName]) {
759
676
  result[altLanguageName] = [];
760
677
  }
761
-
762
678
  result[altLanguageName].push(key);
763
679
  valid = false;
764
680
  }
765
681
  }
766
682
  }
767
683
  }
768
-
769
684
  return [valid, result];
770
685
  }
771
686
  async function validate(config) {
@@ -774,21 +689,17 @@ async function validate(config) {
774
689
  includeNodeModules: true
775
690
  }, config);
776
691
  let valid = true;
777
-
778
692
  for (const loadedTranslation of allTranslations) {
779
693
  const [translationValid, result] = findMissingKeys(loadedTranslation, config.devLanguage, getAltLanguages(config));
780
-
781
694
  if (!translationValid) {
782
695
  valid = false;
783
- console.log(chalk__default['default'].red`Incomplete translations: "${chalk__default['default'].bold(loadedTranslation.relativePath)}"`);
784
-
696
+ console.log(chalk__default["default"].red`Incomplete translations: "${chalk__default["default"].bold(loadedTranslation.relativePath)}"`);
785
697
  for (const lang of Object.keys(result)) {
786
698
  const missingKeys = result[lang];
787
- console.log(chalk__default['default'].yellow(lang), '->', missingKeys.map(v => `"${v}"`).join(', '));
699
+ console.log(chalk__default["default"].yellow(lang), '->', missingKeys.map(v => `"${v}"`).join(', '));
788
700
  }
789
701
  }
790
702
  }
791
-
792
703
  return valid;
793
704
  }
794
705
 
@@ -798,10 +709,9 @@ class ValidationError extends Error {
798
709
  this.code = code;
799
710
  this.rawMessage = message;
800
711
  }
801
-
802
712
  }
803
713
 
804
- const validator = new Validator__default['default']();
714
+ const validator = new Validator__default["default"]();
805
715
  const schema = {
806
716
  $$strict: true,
807
717
  devLanguage: {
@@ -866,102 +776,85 @@ const schema = {
866
776
  }
867
777
  };
868
778
  const checkConfigFile = validator.compile(schema);
869
-
870
779
  const splitMap = (message, callback) => message.split(' ,').map(v => callback(v)).join(' ,');
871
-
872
780
  function validateConfig(c) {
873
- trace('Validating configuration file'); // Note: checkConfigFile mutates the config file by applying defaults
874
-
781
+ trace('Validating configuration file');
782
+ // Note: checkConfigFile mutates the config file by applying defaults
875
783
  const isValid = checkConfigFile(c);
876
-
877
784
  if (isValid !== true) {
878
785
  throw new ValidationError('InvalidStructure', (Array.isArray(isValid) ? isValid : []).map(v => {
879
786
  if (v.type === 'objectStrict') {
880
- return `Invalid key(s) ${splitMap(v.actual, m => `"${chalk__default['default'].cyan(m)}"`)}. Expected one of ${splitMap(v.expected, chalk__default['default'].green)}`;
787
+ return `Invalid key(s) ${splitMap(v.actual, m => `"${chalk__default["default"].cyan(m)}"`)}. Expected one of ${splitMap(v.expected, chalk__default["default"].green)}`;
881
788
  }
882
-
883
789
  if (v.field) {
884
790
  var _v$message;
885
-
886
- return (_v$message = v.message) === null || _v$message === void 0 ? void 0 : _v$message.replace(v.field, chalk__default['default'].cyan(v.field));
791
+ return (_v$message = v.message) === null || _v$message === void 0 ? void 0 : _v$message.replace(v.field, chalk__default["default"].cyan(v.field));
887
792
  }
888
-
889
793
  return v.message;
890
794
  }).join(' \n'));
891
795
  }
796
+ const languageStrings = c.languages.map(v => v.name);
892
797
 
893
- const languageStrings = c.languages.map(v => v.name); // Dev Language should exist in languages
894
-
798
+ // Dev Language should exist in languages
895
799
  if (!languageStrings.includes(c.devLanguage)) {
896
- throw new ValidationError('InvalidDevLanguage', `The dev language "${chalk__default['default'].bold.cyan(c.devLanguage)}" was not found in languages ${languageStrings.join(', ')}.`);
800
+ throw new ValidationError('InvalidDevLanguage', `The dev language "${chalk__default["default"].bold.cyan(c.devLanguage)}" was not found in languages ${languageStrings.join(', ')}.`);
897
801
  }
898
-
899
802
  const foundLanguages = [];
900
-
901
803
  for (const lang of c.languages) {
902
804
  // Languages must only exist once
903
805
  if (foundLanguages.includes(lang.name)) {
904
- throw new ValidationError('DuplicateLanguage', `The language "${chalk__default['default'].bold.cyan(lang.name)}" was defined multiple times.`);
806
+ throw new ValidationError('DuplicateLanguage', `The language "${chalk__default["default"].bold.cyan(lang.name)}" was defined multiple times.`);
905
807
  }
808
+ foundLanguages.push(lang.name);
906
809
 
907
- foundLanguages.push(lang.name); // Any extends must be in languages
908
-
810
+ // Any extends must be in languages
909
811
  if (lang.extends && !languageStrings.includes(lang.extends)) {
910
- throw new ValidationError('InvalidExtends', `The language "${chalk__default['default'].bold.cyan(lang.name)}"'s extends of ${chalk__default['default'].bold.cyan(lang.extends)} was not found in languages ${languageStrings.join(', ')}.`);
812
+ throw new ValidationError('InvalidExtends', `The language "${chalk__default["default"].bold.cyan(lang.name)}"'s extends of ${chalk__default["default"].bold.cyan(lang.extends)} was not found in languages ${languageStrings.join(', ')}.`);
911
813
  }
912
814
  }
913
-
914
815
  const foundGeneratedLanguages = [];
915
-
916
816
  for (const generatedLang of c.generatedLanguages || []) {
917
817
  // Generated languages must only exist once
918
818
  if (foundGeneratedLanguages.includes(generatedLang.name)) {
919
- throw new ValidationError('DuplicateGeneratedLanguage', `The generated language "${chalk__default['default'].bold.cyan(generatedLang.name)}" was defined multiple times.`);
819
+ throw new ValidationError('DuplicateGeneratedLanguage', `The generated language "${chalk__default["default"].bold.cyan(generatedLang.name)}" was defined multiple times.`);
920
820
  }
821
+ foundGeneratedLanguages.push(generatedLang.name);
921
822
 
922
- foundGeneratedLanguages.push(generatedLang.name); // Generated language names must not conflict with language names
923
-
823
+ // Generated language names must not conflict with language names
924
824
  if (languageStrings.includes(generatedLang.name)) {
925
- throw new ValidationError('InvalidGeneratedLanguage', `The generated language "${chalk__default['default'].bold.cyan(generatedLang.name)}" is already defined as a language.`);
926
- } // Any extends must be in languages
927
-
825
+ throw new ValidationError('InvalidGeneratedLanguage', `The generated language "${chalk__default["default"].bold.cyan(generatedLang.name)}" is already defined as a language.`);
826
+ }
928
827
 
828
+ // Any extends must be in languages
929
829
  if (generatedLang.extends && !languageStrings.includes(generatedLang.extends)) {
930
- throw new ValidationError('InvalidExtends', `The generated language "${chalk__default['default'].bold.cyan(generatedLang.name)}"'s extends of ${chalk__default['default'].bold.cyan(generatedLang.extends)} was not found in languages ${languageStrings.join(', ')}.`);
830
+ throw new ValidationError('InvalidExtends', `The generated language "${chalk__default["default"].bold.cyan(generatedLang.name)}"'s extends of ${chalk__default["default"].bold.cyan(generatedLang.extends)} was not found in languages ${languageStrings.join(', ')}.`);
931
831
  }
932
832
  }
933
-
934
833
  trace('Configuration file is valid');
935
834
  return true;
936
835
  }
937
-
938
836
  function createConfig(configFilePath) {
939
- const cwd = path__default['default'].dirname(configFilePath);
837
+ const cwd = path__default["default"].dirname(configFilePath);
940
838
  return {
941
839
  projectRoot: cwd,
942
840
  ...require(configFilePath)
943
841
  };
944
842
  }
945
-
946
843
  async function resolveConfig(customConfigFilePath) {
947
- const configFilePath = customConfigFilePath ? path__default['default'].resolve(customConfigFilePath) : await findUp__default['default']('vocab.config.js');
948
-
844
+ const configFilePath = customConfigFilePath ? path__default["default"].resolve(customConfigFilePath) : await findUp__default["default"]('vocab.config.js');
949
845
  if (configFilePath) {
950
846
  trace(`Resolved configuration file to ${configFilePath}`);
951
847
  return createConfig(configFilePath);
952
848
  }
953
-
954
849
  trace('No configuration file found');
955
850
  return null;
956
851
  }
957
852
  function resolveConfigSync(customConfigFilePath) {
958
- const configFilePath = customConfigFilePath ? path__default['default'].resolve(customConfigFilePath) : findUp__default['default'].sync('vocab.config.js');
959
-
853
+ const configFilePath = customConfigFilePath ? path__default["default"].resolve(customConfigFilePath) : findUp__default["default"].sync('vocab.config.js');
960
854
  if (configFilePath) {
961
855
  trace(`Resolved configuration file to ${configFilePath}`);
962
856
  return createConfig(configFilePath);
963
857
  }
964
-
965
858
  trace('No configuration file found');
966
859
  return null;
967
860
  }