broccoli-merge-files
Version:
Broccoli plugin to merge multiple files into one or multiple files
111 lines • 4.81 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const broccoli_plugin_1 = __importDefault(require("broccoli-plugin"));
const lodash_defaults_1 = __importDefault(require("lodash.defaults"));
const fast_glob_1 = __importDefault(require("fast-glob"));
const p_event_1 = __importDefault(require("p-event"));
const path_1 = require("path");
const util_1 = require("util");
const fs_1 = require("fs");
const readFile = util_1.promisify(fs_1.readFile);
const writeFile = util_1.promisify(fs_1.writeFile);
var DuplicateStrategy;
(function (DuplicateStrategy) {
DuplicateStrategy["Prohibit"] = "prohibit";
DuplicateStrategy["KeepFirst"] = "keep-first";
DuplicateStrategy["KeepLast"] = "keep-last";
DuplicateStrategy["KeepAll"] = "keep-all";
})(DuplicateStrategy = exports.DuplicateStrategy || (exports.DuplicateStrategy = {}));
const DEFAULT_OPTIONS = {
patterns: '**/*',
duplicates: DuplicateStrategy.Prohibit,
encoding: 'utf8',
sort: true
};
class BroccoliMergeFiles extends broccoli_plugin_1.default {
constructor(inputNodes, options) {
super(inputNodes, {
annotation: options.annotation,
persistentOutput: false,
needsCache: false
});
this.options = lodash_defaults_1.default({}, options, DEFAULT_OPTIONS);
}
async build() {
const entries = await this.readFiles();
const sorted = this.sort(entries);
const deduplicated = this.deduplicate(sorted);
const merged = await this.options.merge(deduplicated);
await this.writeOutput(merged);
}
async readFiles() {
const streams = this.inputPaths.map((path) => [
path,
fast_glob_1.default.stream(this.options.patterns, Object.assign({}, this.options.globOptions, { cwd: path, absolute: false, unique: true, onlyFiles: true, onlyDirectories: false, transform: null, stats: false }))
]);
const waiters = [];
const entries = [];
for (const [i, [cwd, stream]] of streams.entries()) {
stream.on('data', path => entries.push(this.processFile(i, cwd, path)));
waiters.push(p_event_1.default(stream, 'end'));
}
await Promise.all(waiters);
return Promise.all(entries);
}
async processFile(i, cwd, path) {
const absolutePath = path_1.resolve(cwd, path);
const content = await readFile(absolutePath, {
encoding: this.options.encoding
});
if (typeof this.options.transformFile === 'function') {
return [i, path, await this.options.transformFile(path, content)];
}
return [i, path, content];
}
sort(entries) {
if (typeof this.options.sort === 'function') {
return entries.sort(this.options.sort);
}
if (this.options.sort === true) {
return entries.sort((a, b) => a[0] - b[0] || a[1].localeCompare(b[1]));
}
return entries;
}
deduplicate(entries) {
if (this.options.duplicates === DuplicateStrategy.KeepAll)
return entries.map(([, fileName, contents]) => [fileName, contents]);
const map = new Map();
for (const [node, fileName, contents] of entries) {
if (map.has(fileName)) {
if (this.options.duplicates === DuplicateStrategy.Prohibit)
throw new Error(`File '${fileName}' appears in node ${node}, but was already seen in a previous node.`);
if (this.options.duplicates === DuplicateStrategy.KeepFirst)
continue;
}
map.set(fileName, contents);
}
return [...map.entries()];
}
async writeOutput(merged) {
if (typeof this.options.outputFileName === 'string') {
if (Array.isArray(merged))
throw new TypeError(`Expected 'merge' to return file contents for a single file, since 'outputFileName' has been specified.`);
await this.writeOutputFile(this.options.outputFileName, merged);
}
else {
if (!Array.isArray(merged))
throw new TypeError(`Expected 'merge' to return multiple file contents, since 'outputFileName' has not been specified.`);
await Promise.all(merged.map(([fileName, contents]) => this.writeOutputFile(fileName, contents)));
}
}
async writeOutputFile(fileName, contents) {
await writeFile(path_1.resolve(this.outputPath, fileName), contents, {
encoding: this.options.encoding
});
}
}
exports.BroccoliMergeFiles = BroccoliMergeFiles;
//# sourceMappingURL=index.js.map