UNPKG

@gasket/plugin-intl

Version:
213 lines (212 loc) 9.16 kB
Object.defineProperty(exports, "__esModule", { value: true }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { BuildModules: function() { return BuildModules; }, /** * Discovers locale files under node modules with and copies them to output dir. * @param {import("@gasket/core").Gasket} gasket - Gasket API */ default: function() { return buildModules; } }); const _fsextra = /*#__PURE__*/ _interop_require_default(require("fs-extra")); const _path = /*#__PURE__*/ _interop_require_default(require("path")); const _fsutils = require("./utils/fs-utils.cjs"); const _configureutils = require("./utils/configure-utils.cjs"); const _debug = /*#__PURE__*/ _interop_require_default(require("debug")); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const debugLog = (0, _debug.default)('gasket:plugin:intl:buildModules'); const rePkgParts = RegExp("^(?<name>(?:@[\\w-]+\\/)?[\\w-]+)(?<dir>\\/[\\w-]+)?$"); class BuildModules { /** * Given a source folder, this function minifies all the files in that folder * and sets a unique hash for each file and saves in the target location * @param {string} srcDir - Source directory path * @param {string} tgtDir - Target directory path * @returns {Promise} promise */ async copyFolder(srcDir, tgtDir) { debugLog(`Copying folder from ${srcDir} to ${tgtDir}`); const fileNames = await _fsextra.default.readdir(srcDir); const promises = fileNames.map(async (fileName)=>{ const srcFile = _path.default.join(srcDir, fileName); const tgtFile = _path.default.join(tgtDir, fileName); if (_path.default.extname(srcFile) === '.json') { return await this.copyFile(srcFile, tgtFile); } }); return await Promise.all(promises); } /** * Copies the source file to proper target location * @param {string} src - full path to source file * @param {string} tgt - target folder location * @returns {Promise} - resolves once the file is saved */ async copyFile(src, tgt) { debugLog(`Copying file from ${src} to ${tgt}`); await _fsextra.default.mkdirp(_path.default.dirname(tgt)); const buffer = await _fsextra.default.readFile(src); const output = JSON.parse(buffer); return (0, _fsutils.saveJsonFile)(tgt, output); } /** * Processes locale files from source to target build directory * @param {string} srcDir - Source locale directory * @param {string} tgtDir - Target locale directory * @param {string[]} fileNames - Names of the locale files * @returns {Promise} promise */ processFiles(srcDir, tgtDir, fileNames) { debugLog(`Processing files in ${srcDir} to target ${tgtDir}`); const promises = fileNames.map(async (fileName)=>{ const srcFile = _path.default.join(srcDir, fileName); const tgtFile = _path.default.join(tgtDir, fileName); if (_path.default.extname(srcFile) === '.json') { return await this.copyFile(srcFile, tgtFile); } else if ((await _fsextra.default.lstat(srcFile)).isDirectory()) { return await this.copyFolder(srcFile, tgtFile); } }); return Promise.all(promises); } /** * Reads the source directory and returns the package name e.g. @gasket/next * @param {string} srcDir - Source directory path * @returns {string} package name */ getPackageNameFromDir(srcDir) { const leafFolder = _path.default.dirname(srcDir); const leafFolderName = _path.default.basename(leafFolder); const parentFolder = _path.default.dirname(leafFolder); const parentFolderName = _path.default.basename(parentFolder); let pkgName = leafFolderName; if (parentFolderName.startsWith('@')) { pkgName = `${parentFolderName}/${leafFolderName}`; } return pkgName; } /** * Reads the package.json and returns the package name e.g. @gasket/next * @param {string} srcDir - Source directory path (a locales directory) * @returns {Promise<string>} package name */ async getPackageName(srcDir) { const pkgDir = _path.default.dirname(srcDir); try { const pkg = await _fsextra.default.readJson(_path.default.join(pkgDir, 'package.json')); return pkg.name || this.getPackageNameFromDir(srcDir); } catch { return this.getPackageNameFromDir(srcDir); } } /** * Processes directories * @param {import('./internal.d.ts').SrcPkgDir[]} srcPkgDirs - list of dirs to process */ async processDirs(srcPkgDirs) { for (const [pkgName, srcDir] of srcPkgDirs){ const tgtDir = _path.default.join(this._outputDir, pkgName); this._logger.info(`build:locales: Updating locale files for: ${pkgName}`); await _fsextra.default.remove(tgtDir); await _fsextra.default.mkdirp(tgtDir); const fileNames = await _fsextra.default.readdir(srcDir); await this.processFiles(srcDir, tgtDir, fileNames); } this._logger.info(`build:locales: Completed locale files update.`); } /** * Find modules that have /locales folder to process * @returns {Promise<import('./internal.d.ts').SrcPkgDir[]>} source package directories */ async discoverDirs() { /** @type {import('./internal.d.ts').SrcPkgDir[]} */ const results = []; for await (const [pkgName, dir] of (0, _fsutils.getPackageDirs)(this._nodeModulesDir)){ if (!this._excludes.includes(_path.default.basename(dir))) { const buildDir = _path.default.resolve(_path.default.join(dir, ...this._lookupDir.split('/'))); try { const stat = await _fsextra.default.lstat(buildDir); if (stat.isDirectory()) { results.push([ pkgName, buildDir ]); } } catch { // ignore } } } return results; } /** * Find modules with locale directories to process * @returns {Promise<import('./internal.d.ts').SrcPkgDir[]>} source package directories */ async gatherModuleDirs() { if (this._lookupModuleDirs) { const promises = this._lookupModuleDirs.map(async (lookupDir)=>{ const match = lookupDir.match(rePkgParts); const pkgName = match?.groups?.name; if (!pkgName) { this._logger.warn(`build:locales: malformed module name: ${lookupDir}`); return; } const subDir = (match.groups.dir ?? '/locales').substring(1); const buildDir = _path.default.join(this._nodeModulesDir, ...pkgName.split('/'), ...subDir.split('/')); try { const stat = await _fsextra.default.lstat(buildDir); if (stat.isDirectory()) { return [ pkgName, buildDir ]; } } catch { // skip } this._logger.warn(`build:locales: locales directory not found for: ${lookupDir}`); }); const results = (await Promise.all(promises)).filter(Boolean); return /** @type {import('./internal.d.ts').SrcPkgDir[]} */ results; } return this.discoverDirs(); } /** * Starts the build process */ async run() { await _fsextra.default.remove(this._outputDir); await _fsextra.default.mkdirp(this._outputDir); const srcPkgDirs = await this.gatherModuleDirs(); await this.processDirs(srcPkgDirs); } /** * Instantiate a builder to gather locale files * @param {import("@gasket/core").Gasket} gasket - Gasket API */ constructor(gasket){ const { logger, config: { root } } = gasket; const intlConfig = (0, _configureutils.getIntlConfig)(gasket); const { modules } = intlConfig; if (Array.isArray(modules)) { this._lookupModuleDirs = modules; } /** @type {Record<string, any>} */ let excludes, localesDir; if (typeof modules === 'object' && !Array.isArray(modules)) { ({ excludes, localesDir } = modules); } this._logger = logger; this._outputDir = _path.default.resolve(_path.default.join(intlConfig.localesDir, 'modules')); this._nodeModulesDir = _path.default.resolve(_path.default.join(root, 'node_modules')); this._lookupDir = localesDir; this._excludes = excludes; } } async function buildModules(gasket) { const builder = new BuildModules(gasket); await builder.run(); }