All files / lib/utils parse.ts

92.98% Statements 53/57
70% Branches 14/20
100% Functions 15/15
92.86% Lines 52/56

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 1206x 6x   6x   6x   6x 6x 6x 6x           50x             50x 150x     6x 80x   6x 20x 20x 80x         6x 30x   30x   70x 70x     70x           28x     6x 20x   20x 40x       6x     10x   10x   10x       10x           10x   10x   10x 20x     30x 30x     10x 28x   28x   28x 10x     28x   28x   28x   28x 124x 134x 134x           10x    
import * as fs from 'fs';
import * as path from 'path';
import { I18nTranslation } from '../i18n.constants';
import * as flat from 'flat';
import { I18nOptions } from '..';
import { promisify } from 'util';
 
const readdir = promisify(fs.readdir);
const lstat = promisify(fs.lstat);
const exists = promisify(fs.exists);
const readFile = promisify(fs.readFile);
 
function mapAsync<T, U>(
  array: T[],
  callbackfn: (value: T, index: number, array: T[]) => Promise<U>,
): Promise<U[]> {
  return Promise.all(array.map(callbackfn));
}
 
async function filterAsync<T>(
  array: T[],
  callbackfn: (value: T, index: number, array: T[]) => Promise<boolean>,
): Promise<T[]> {
  const filterMap = await mapAsync(array, callbackfn);
  return array.filter((value, index) => filterMap[index]);
}
 
const isDirectory = async (source: string) =>
  (await lstat(source)).isDirectory();
 
export const getDirectories = async (source: string) => {
  const dirs = await readdir(source);
  return filterAsync(
    dirs.map(name => path.join(source, name)),
    isDirectory,
  );
};
 
const getFiles = async (dirPath: string, pattern: RegExp) => {
  const dirs = await readdir(dirPath, { withFileTypes: true });
 
  return (
    await filterAsync(dirs, async (f: fs.Dirent | string) => {
      try {
        Iif (typeof f === 'string') {
          return (await exists(path.join(dirPath, f))) && pattern.test(f);
        } else {
          return f.isFile() && pattern.test(f.name);
        }
      } catch {
        return false;
      }
    })
  ).map(f => path.join(dirPath, typeof f === 'string' ? f : f.name));
};
 
export async function getLanguages(options: I18nOptions) {
  const i18nPath = path.normalize(options.path + path.sep);
 
  return (await getDirectories(i18nPath)).map(dir =>
    path.relative(i18nPath, dir),
  );
}
 
export async function parseTranslations(
  options: I18nOptions,
): Promise<I18nTranslation> {
  const i18nPath = path.normalize(options.path + path.sep);
 
  const translations: I18nTranslation = {};
 
  Iif (!(await exists(i18nPath))) {
    throw new Error(`i18n path (${i18nPath}) cannot be found`);
  }
 
  Iif (!options.filePattern.match(/\*\.[A-z]+/)) {
    throw new Error(
      `filePattern should be formatted like: *.json, *.txt, *.custom etc`,
    );
  }
 
  const languages = await getLanguages(options);
 
  const pattern = new RegExp('.' + options.filePattern.replace('.', '.'));
 
  const files = await [
    ...languages.map(l => path.join(i18nPath, l)),
    i18nPath,
  ].reduce(async (files, path) => {
    (await files).push(...(await getFiles(path, pattern)));
    return files;
  }, Promise.resolve([]));
 
  for (const file of files) {
    let global = false;
 
    const key = path.dirname(path.relative(i18nPath, file)).split(path.sep)[0];
 
    if (key === '.') {
      global = true;
    }
 
    const data = JSON.parse(await readFile(file, 'utf8'));
 
    const prefix = path.basename(file).split('.')[0];
 
    const flatData = flat.flatten(data);
 
    for (const property of Object.keys(flatData)) {
      [...(global ? languages : [key])].forEach(lang => {
        translations[lang] = !!translations[lang] ? translations[lang] : {};
        translations[lang][`${global ? '' : `${prefix}.`}${property}`] =
          flatData[property];
      });
    }
  }
 
  return translations;
}