UNPKG

recink

Version:

Rethink CI for JavaScript applications

233 lines (199 loc) 4.9 kB
'use strict'; const print = require('print'); const path = require('path'); const fse = require('fs-extra'); const readdir = require('readdir-enhanced'); const events = require('./events'); /** * Class representing emited test module */ class EmitModule { /** * @param {string} name * @param {Container} container * @param {Emitter} emitter * @param {*} logger */ constructor(name, container, emitter, logger) { this._emitter = emitter; this._logger = logger; this._name = name; this._container = container; this._stats = { total: 0, emitted: 0, ignored: 0, dirs: 0, }; } /** * @returns {Promise} */ check() { const moduleRoot = this.container.get('root', null); if (!moduleRoot) { return Promise.reject(new Error(`Missing root for module ${ this.name }`)); } return fse.pathExists(moduleRoot) .then(hasModuleRoot => { if (!hasModuleRoot) { return Promise.reject(new Error( `Module ${ this.name } root ${ moduleRoot } does not exists or wrong permissions set` )); } return Promise.resolve(); }) } /** * @param {*} container * * @returns {Promise} */ process(container) { return new Promise((resolve, reject) => { const moduleRoot = this.container.get('root'); const options = { deep: this._deepFilter(container).bind(this), filter: this._filter(container).bind(this), }; let ended = false; let processing = 0; readdir.stream(moduleRoot, options) .on('data', filePath => { filePath = filePath.toString(); processing++; const payload = { file: filePath, fileAbs: path.join(moduleRoot, filePath), module: this, }; this.logger.debug('Emit asset', JSON.stringify( Object.assign({}, payload, { module: this.name }) )); this.emitter .maxParallel(events.module.emit.asset, EmitModule.MAX_PARALLEL_ASSETS_EMIT) .emitBlocking(events.module.emit.asset, payload) .then(() => { processing--; if (processing <= 0 && ended) { resolve(); } }) .catch(error => { this.logger.warn(this.logger.emoji.poop, `failed dispatching asset ${ filePath }`); reject(error); }); }) .on('end', () => { ended = true; if (processing <= 0) { resolve(); } }) .on('error', error => reject(error)); }); } /** * @param {Container} container * * @returns {function} * * @private */ _filter(container) { const pattern = container.get('pattern', []); const ignore = container.get('ignore', []); return stats => { const result = stats.isFile() && pattern.filter(p => this._test(p, stats.path)).length > 0 && ignore.filter(i => this._test(i, stats.path)).length <= 0; if (stats.isFile()) { if (result) { this.stats.emitted++; } else { this.stats.ignored++; } this.stats.total++; } else if(stats.isDirectory()) { this.stats.dirs++; } return result; }; } /** * @param {Container} container * * @returns {function} * * @private */ _deepFilter(container) { const ignore = container.get('ignore', []); return stats => { return ignore.filter(i => this._test(i, stats.path)).length <= 0; }; } /** * @param {string|RegExp} pattern * @param {string} value * * @returns {boolean} * * @private */ _test(pattern, value) { if (!(pattern instanceof RegExp)) { return value.indexOf(pattern.toString()) !== -1; } return pattern.test(value); } /** * @returns {*} */ get logger() { return this._logger; } /** * @returns {Emitter} */ get emitter() { return this._emitter; } /** * @returns {string} */ get name() { return this._name; } /** * @returns {Container} */ get container() { return this._container; } /** * @returns {*} */ get stats() { return this._stats; } /** * @returns {string} */ dumpStats() { return print(this.stats, { showArrayIndices: true, showArrayLength: true, sortProps: false, }).replace(/\t/g, ' ') } /** * @returns {number} * * @todo make it configurable for specific use cases */ static get MAX_PARALLEL_ASSETS_EMIT() { return 1; } } module.exports = EmitModule;