Source: helpers/BaseBuild.js

/**
 * @author Donii Sergii <doniysa@gmail.com>
 */

/**
 * @ignore _
 * @type {PathBuild}
 */

const pathBuild = require('./PathBuild'),
      _         = require('lodash');

/**
 * @class @abstract BaseBuild
 * Abstract class for building
 *
 * @property {Object|Array|String} paths Config path. See <a href="global.html#pathConfig">For detail</a>
 * @property {Array} ignores Ignores pattern which will be adding to all <code>gulp.src</code> functions for css build
 * @property {String} processor NPM package name which will be require for this config section
 * @property {String} sourceExt Source filename extension
 * @property {String} outputExt Output filename extension
 * @property {Object} liveReloadOptions <a target="_blank" href=https://github.com/vohof/gulp-livereload>Livereload</a> options for css building
 * @property {Function|undefined} additionalMinifyWatchCallback Additional minify watch callback. Called on <a href="Css.html">Css class</a>
 * @property {Function|undefined} additionalBuildCallback Additional build callback. Called on <a href="Css.html">Css class</a>
 * @property {Function|undefined} additionalWatchCallback Additional watch callback. Called on <a href="Css.html">Css class</a>
 * @property {Function|undefined} additionalMinifyWatchCallback Additional minify watch callback. Called on <a href="Css.html">Css class</a>
 * @property {Function|undefined} minifyOptions Options for <a target="_blank" href="https://www.npmjs.com/package/gulp-clean-css">gulp-clean-css</a> package
 * @property {String|undefined} minifySuffix Minify suffix for min file versions. By default is <code>.min</code>
 * @property {String|Array} watchTasks Task which will be run on build files watcher. Be default is <code>build-css</code>
 * @property {String|Array} watchMinifyTasks Task which will be run on minify files watcher. Be default is <code>minify-css</code>
 * @property {Array|Object} additionalMinifyPath Additional minify files pattern which will be adding to all <code>gulp.src</code> functions for minify css. See <a href="global.html#pathConfig">Path config options</a> for detail
 * @property {Boolean} enableMin Enable or disable run minify task & watcher. By default is true
 * @property {Object} processorOptions Options for gulp package which will be build css. Testing on <a target="_blank" href="https://github.com/stevelacy/gulp-stylus">gulp-stylus</a>, <a target="_blank" href="https://github.com/dlmanning/gulp-sass">gulp-sass</a> and <a target="_blank" href="https://github.com/stevelacy/gulp-less">gulp-less</a>
 * @property {Object} originalConfig Config which giving in constructor
 * @property {String} processorName Package name for build
 * @property {Object|Array} paths Paths
 * @property {Object|Array} processorOptions Processor options
 * @property {Array} tasks Additional task for build watcher
 * @property {Array|Object|undefined} additionalMinifyPath Additional minify paths
 * @property {Array|Object|undefined} additionalMinifyWatchCallback Additional minify watch paths
 * @property {Array|Object|undefined} additionalBuildCallback Additional build paths config
 * @property {Array|Object|undefined} additionalBuildCallback Additional build paths config
 * @property {Array|Object|undefined} minifyOptions Options for gulp-clean-css package
 * @property {Function|undefined} additionalMinifyWatchCallback Additional minify watch callback
 * @property {Function|undefined} additionalMinifyCallback Additional minify callback
 * @property {String} minifySuffix Suffix for minified files
 * @property {String} defaultProcessor Default processor
 * @property {String|Array} defTasks Default run tasks
 * @property {String|Array} watchTasks Watch tasks for build paths
 * @property {String|Array} watchMinifyTasks Watch tasks for minify paths
 * @property {{outDir: {String}, distDir: {String}}} configPaths Default path from config
 * @property {Object|Array} ignores Ignore files pattern
 *
 * @author Donii Sergii<doniysa@gmail.com>
 */
class BaseBuild {

    /**
     * BaseBuild constructor
     *
     * @param {Object} config CSS compiler config
     * @param {Object} liveReloadOptions Livereload options
     * @param {{outDir: {String}, distDir: {String}}} configPaths Default config paths
     *
     * @author Donii Sergii<doniysa@gmail.com>
     */
    constructor(config, liveReloadOptions, configPaths) {
        this.extension = 'css';
        if (new.target === BaseBuild) {
            throw new TypeError("Cannot construct BaseBuild instances directly");
        }
        this.originalConfig = config;
        this.configPaths    = configPaths;

        if (!config.sourceExt && !this.sourceExt) {
            throw 'Extension not set sourceExt in config';
        }
        this.sourceExt = this.sourceExt || config.sourceExt;
        this.outputExt = config.outputExt || this.sourceExt;

        this.processorName    = config.processor || this.defaultProcessor;
        this.paths            = config.paths;
        this.processorOptions = config.processorOptions;

        if (_.isString(this.processorName)) {
            this.processor = require(this.processorName);
        }

        this.ignores          = config.ignorePatterns;
        this.watchTasks       = config.watchTasks || this.defTasks;
        this.watchMinifyTasks = config.watchMinifyTasks || this.defMinifyTasks;
        if (_.isString(this.watchTasks)) {
            this.watchTasks = [this.watchTasks];
        }
        if (_.isString(this.watchMinifyTasks)) {
            this.watchMinifyTasks = [this.watchMinifyTasks];
        }
        this.liveReloadOptions             = (config.liveReloadOptions || (liveReloadOptions || {}));
        this.additionalMinifyPath          = config.externalMinifyPath;
        this.additionalBuildCallback       = config.buildCallback;
        this.additionalWatchCallback       = config.buildWatchCallback;
        this.additionalMinifyWatchCallback = config.buildMinifyWatchCallback;
        this.additionalMinifyCallback      = config.minifyCallback;

        this.minifyOptions = config.minifyOptions || {
                compatibility: 'ie9'
            };

        this.minifySuffix = config.suffix || '.min';
        this.enableMin    = config.enableMin || true;
    }

    /**
     * Get build paths
     *
     * @returns {Object}
     *
     * @author Donii Sergii<doniysa@gmail.com>
     */
    getBuildPaths() {
        let currentPaths = (new pathBuild(this.paths, this.defaultOutPath || this.configPaths.outDir, this.configPaths)).processFullPath(true);

        if (!currentPaths.length) {
            return [];
        }

        return currentPaths;
    }

    /**
     * Check processor set
     *
     * @returns {boolean}
     *
     * @author Donii Sergii<doniysa@gmail.com>
     */
    checkProcessor() {
        return true;
    }

    /**
     * Build task
     *
     * @author Donii Sergii<doniysa@gmail.com>
     */
    build() {
        let _self = this,
            paths = this.getBuildPaths();

        if (!_.size(paths)) {
            return;
        }

        if (!this.checkProcessor()) {
            return;
        }

        _.each(paths, (path) => {
            _self.runBuildTask.apply(_self, [path]);
        });

        if (_.isFunction(this.additionalBuildCallback)) {
            this.additionalBuildCallback.apply(this);
        }
    }

    /**
     * Generate paths
     *
     * @param {Object|Array} _paths Arrays
     *
     * @author Donii Sergii<doniysa@gmail.com>
     */
    runForPaths(_paths) {
        let _self = this;
        if (_.size(_paths)) {
            _.each(_paths, (path) => {
                _self.runMinify.apply(_self, [path]);
            });
        }
    }

    /**
     * Run watcher for build
     *
     * @author Donii Sergii<doniysa@gmail.com>
     */
    buildWatch(gulp) {
        let paths;

        if (!_.size(paths = this.getBuildPaths())) {
            return;
        }

        gulp.watch(pathBuild.buildWatchPaths(paths), this.watchTasks);

        if (_.isFunction(this.additionalWatchCallback)) {
            this.additionalWatchCallback.apply(this);
        }

        this.minifyWatch(gulp);
    }

    preparePath(paths, min) {
        let _self = this;

        paths.forEach((path, index) => {
            if (!min) {
                return path;
            }

            if (!_self.outputExt || !_self.outputExt) {
                return;
            }

            paths[index] = (paths[index] + "/**/**/**/**/*." + _self.outputExt).replace(/\/\//g, '/');
        });

        return paths;
    };

    /**
     * Run watcher for minify task
     *
     * @author Donii Sergii<doniysa@gmail.com>
     */
    minifyWatch(gulp) {

        if (!this.enableMin) {
            return;
        }

        if (_.isFunction(this.additionalMinifyWatchCallback)) {
            this.additionalMinifyWatchCallback.apply(this);
        }
        let paths = (new pathBuild(this.paths, this.defaultOutPath || this.configPaths.outDir, this.configPaths)).processFullPath(true);
        console.log(paths, this.preparePath(pathBuild.buildWatchPaths(paths, 'dest', true), true), this.watchTasks);

        if (!_.size(paths)) {
            return;
        }

        // console.log(this.preparePath(pathBuild.buildWatchPaths(paths, 'dest', true), true));
        gulp.watch(this.preparePath(pathBuild.buildWatchPaths(paths, 'dest', true), true), this.watchMinifyTasks);

        if (_.isFunction(this.additionalWatchMinifyCallback)) {
            this.additionalWatchMinifyCallback.apply(this);
        }

    }

    /**
     * Run minify-css task
     *
     * @author Donii Sergii<doniysa@gmail.com>
     */
    minify() {
        if (!this.enableMin) {
            return;
        }

        let additionalPaths = (new pathBuild(this.additionalMinifyPath, this.configPaths)).processFullPath(),
            currentPaths    = (new pathBuild(this.paths, this.defaultOutPath, this.configPaths)).processFullPath(true),
            _self           = this;

        if (!_.size(currentPaths) && !_.size(additionalPaths)) {
            return;
        }

        if (_.isFunction(this.additionalMinifyCallback)) {
            this.additionalMinifyCallback(this);
        }

        _self.runForPaths(currentPaths);
        _self.runForPaths(additionalPaths);
    }
}

module.exports = BaseBuild;