src/component/emit/emit-module.js
'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;