UNPKG

@vendure/ngx-translate-extract

Version:
161 lines (160 loc) 5.87 kB
import { globSync } from 'glob'; import * as fs from 'node:fs'; import * as path from 'node:path'; import { TranslationCollection } from '../../utils/translation.collection.js'; import { cyan, green, bold, dim, red } from '../../utils/cli-color.js'; import { NullCache } from '../../cache/null-cache.js'; export class ExtractTask { inputs; outputs; options = { replace: false }; parsers = []; postProcessors = []; compiler; cache = new NullCache(); constructor(inputs, outputs, options) { this.inputs = inputs; this.outputs = outputs; this.inputs = inputs.map((input) => path.resolve(input)); this.outputs = outputs.map((output) => path.resolve(output)); this.options = { ...this.options, ...options }; } execute() { if (!this.compiler) { throw new Error('No compiler configured'); } this.printEnabledParsers(); this.printEnabledPostProcessors(); this.printEnabledCompiler(); this.out(bold('Extracting:')); const extracted = this.extract(); this.out(green('\nFound %d strings.\n'), extracted.count()); this.out(bold('Saving:')); this.outputs.forEach((output) => { let dir = output; let filename = `strings.${this.compiler.extension}`; if (!fs.existsSync(output) || !fs.statSync(output).isDirectory()) { dir = path.dirname(output); filename = path.basename(output); } const outputPath = path.join(dir, filename); let existing = new TranslationCollection(); if (!this.options.replace && fs.existsSync(outputPath)) { try { existing = this.compiler.parse(fs.readFileSync(outputPath, 'utf-8')); } catch (e) { this.out('%s %s', dim(`- ${outputPath}`), red('[ERROR]')); throw e; } } const draft = extracted.union(existing); const final = this.process(draft, extracted, existing); try { let event = 'CREATED'; if (fs.existsSync(outputPath)) { this.options.replace ? (event = 'REPLACED') : (event = 'MERGED'); } this.save(outputPath, final); this.out('%s %s', dim(`- ${outputPath}`), green(`[${event}]`)); } catch (e) { this.out('%s %s', dim(`- ${outputPath}`), red('[ERROR]')); throw e; } }); this.cache.persist(); } setParsers(parsers) { this.parsers = parsers; return this; } setCache(cache) { this.cache = cache; return this; } setPostProcessors(postProcessors) { this.postProcessors = postProcessors; return this; } setCompiler(compiler) { this.compiler = compiler; return this; } extract() { const collectionTypes = []; let skipped = 0; this.inputs.forEach((pattern) => { this.getFiles(pattern).forEach((filePath) => { const contents = fs.readFileSync(filePath, 'utf-8'); skipped += 1; const cachedCollectionValues = this.cache.get(`${pattern}:${filePath}:${contents}`, () => { skipped -= 1; this.out(dim('- %s'), filePath); return this.parsers .map((parser) => { const extracted = parser.extract(contents, filePath); return extracted instanceof TranslationCollection ? extracted.values : undefined; }) .filter((result) => result && !!Object.keys(result).length); }); collectionTypes.push(...cachedCollectionValues); }); }); if (skipped) { this.out(dim('- %s unchanged files skipped via cache'), skipped); } const values = {}; for (const collectionType of collectionTypes) { Object.assign(values, collectionType); } return new TranslationCollection(values); } process(draft, extracted, existing) { this.postProcessors.forEach((postProcessor) => { draft = postProcessor.process(draft, extracted, existing); }); return draft; } save(output, collection) { const dir = path.dirname(output); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } fs.writeFileSync(output, this.compiler.compile(collection)); } getFiles(pattern) { const sanitizedPattern = pattern.split(path.sep).join(path.posix.sep); return globSync(sanitizedPattern).filter((filePath) => fs.statSync(filePath).isFile()); } out(...args) { console.log.apply(this, args); } printEnabledParsers() { this.out(cyan('Enabled parsers:')); if (this.parsers.length) { this.out(cyan(dim(this.parsers.map((parser) => `- ${parser.constructor.name}`).join('\n')))); } else { this.out(cyan(dim('(none)'))); } this.out(); } printEnabledPostProcessors() { this.out(cyan('Enabled post processors:')); if (this.postProcessors.length) { this.out(cyan(dim(this.postProcessors.map((postProcessor) => `- ${postProcessor.constructor.name}`).join('\n')))); } else { this.out(cyan(dim('(none)'))); } this.out(); } printEnabledCompiler() { this.out(cyan('Compiler:')); this.out(cyan(dim(`- ${this.compiler.constructor.name}`))); this.out(); } }