All files index.js

79.24% Statements 42/53
63.88% Branches 23/36
100% Functions 13/13
76.59% Lines 36/47

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        6x 3x   3x 3x   3x 3x 3x 3x     6x             3x         4x 4x   4x 4x       8x         3x   3x   3x   3x   3x 3x 3x     3x       3x           3x 3x       3x       3x         6x   3x     3x                 3x 1x   2x       3x 1x        
import path from 'node:path';
import { transform } from 'i18next-parser';
import vfs from 'vinyl-fs';
 
const isModule = (filePath) => !path.isAbsolute(filePath) && !filePath.startsWith('/') && !filePath.startsWith('./');
const removeDuplicatesFromArray = (arr) => Array.from(new Set(arr).values());
 
const searchForAllFilePaths = (currentEntry, depth = 0) => {
  let paths = [];
 
  if (Array.isArray(currentEntry) || Array.isArray(currentEntry.import)) {
    let entriesInCurrentEntry = currentEntry;
    Eif (currentEntry.import) {
      entriesInCurrentEntry = currentEntry.import;
    }
 
    paths = entriesInCurrentEntry.filter((e) => !isModule(e)).map((e) => path.dirname(e));
  } else E{
    if (!isModule(currentEntry)) {
      paths.push(path.dirname(currentEntry));
    }
  }
 
  return paths;
};
 
export default class I18nextWebpackPlugin {
  constructor(config) {
    this.extensions = ['.js', '.jsx', '.vue'];
    this.i18nConfig = config;
 
    Eif (this.i18nConfig.extensions) {
      this.extensions = this.i18nConfig.extensions;
    }
 
    // Remove leading dot
    this.extensions = this.extensions.map((ext) => ext.replace(/^\./, ''));
  }
 
  apply(compiler) {
    // check source directory
    Eif (!this.i18nConfig.src) {
      // entry
      const entry = compiler.options.entry;
 
      Iif (typeof entry === 'string') {
        this.i18nConfig.src = [path.dirname(entry)];
      } else Eif (typeof entry === 'object') {
        // filter relative paths
        let entries = [];
        Object.keys(entry).forEach((e) => {
          entries = entries.concat(searchForAllFilePaths(entry[e]));
        });
 
        this.i18nConfig.src = removeDuplicatesFromArray(entries);
      }
    }
    // check dest directory
    Iif (!this.i18nConfig.dest) {
      // Get the project root directory without using __dirname which can be problematic in ESM
      const currentWorkingDir = process.cwd();
      this.i18nConfig.dest = currentWorkingDir;
    }
 
    compiler.hooks.emit.tapAsync('i18nextWebpackPlugin', (compilation, callback) => {
      Iif (!this.i18nConfig) {
        console.error('i18next-scanner:', 'i18n object is missing');
        return callback();
      }
      Iif (!this.i18nConfig.src || this.i18nConfig.src.length === 0) {
        console.error('i18next-scanner:', 'src path is missing');
        return callback();
      }
      Iif (!this.i18nConfig.dest) {
        console.error('i18next-scanner:', 'dest path is missing');
        return callback();
      }
 
      const commaSeperatedExtensions = this.extensions.map((ext) => ext.replace(/^\./, '')).join(',');
 
      vfs
        .src(
          this.i18nConfig.src.map((e) =>
            path.join(
              e,
              `**/*.${this.extensions.length === 1 ? commaSeperatedExtensions : `{${commaSeperatedExtensions}}`}`
            )
          )
        )
        .pipe(new transform(this.i18nConfig.options))
        .pipe(vfs.dest(this.i18nConfig.dest))
        .on('end', () => {
          if (this.i18nConfig.async) {
            console.log('i18next-scanner: done.');
          } else {
            callback();
          }
        });
 
      if (this.i18nConfig.async) {
        callback();
      }
    });
  }
}