Home Manual Reference Source

src/services/building/builder.js

const { provider } = require('jimple');
/**
 * This is the main _"bridge service"_ for building: It connects the rest of the building services
 * and perform most of the _"building-related tasks"_.
 */
class Builder {
  /**
   * Class constructor.
   * @param {BuildCleaner}    buildCleaner    Used to clean a target builded files before building
   *                                          again.
   * @param {BuildCopier}     buildCopier     Used to copy a target files if it doesn't require
   *                                          bundling.
   * @param {BuildEngines}    buildEngines    To access the engines in charge of building targets.
   * @param {buildTranspiler} buildTranspiler To transpile files of atarget that doesn't require
   *                                          bundling.
   * @param {Targets}         targets         To access targets information.
   */
  constructor(
    buildCleaner,
    buildCopier,
    buildEngines,
    buildTranspiler,
    targets
  ) {
    /**
     * A local reference for the `buildCleaner` service.
     * @type {BuildCleaner}
     */
    this.buildCleaner = buildCleaner;
    /**
     * A local reference for the `buildCopier` service.
     * @type {BuildCopier}
     */
    this.buildCopier = buildCopier;
    /**
     * A local reference for the `buildEngines` service.
     * @type {BuildEngines}
     */
    this.buildEngines = buildEngines;
    /**
     * A local reference for the `buildTranspiler` service.
     * @type {BuildTranspiler}
     */
    this.buildTranspiler = buildTranspiler;
    /**
     * A local reference for the `targets` service.
     * @type {Targets}
     */
    this.targets = targets;
  }
  /**
   * Get a build command for a target. If the target doesn't require bundling, it will return an
   * empty string, otherwise, it will ask the build engine the target uses for the required shell
   * command.
   * @param {Target}  target               The target information.
   * @param {string}  buildType            The type of build intended: `production` or
   *                                       `development`.
   * @param {boolean} [forceRun=false]     Whether or not the build command should also run the
   *                                       target. It's _"forced"_ because it overwrites the
   *                                       `runOnDevelopment` setting.
   * @param {boolean} [forceWatch=false]   Whether or not the target files should be watched and
   *                                       the build recreated when they changed.
   * @param {boolean} [forceInspect=false] Whether or not the Node inspector should be enabled.
   *                                       Only valid for Node targets.
   * @param {boolean} [forceAnalyze=false] Whether or not the target bundle should be analyzed.
   * @return {string}
   * @todo These parameters should be an object.
   */
  getTargetBuildCommand(
    target,
    buildType,
    forceRun = false,
    forceWatch = false,
    forceInspect = false,
    forceAnalyze = false
  ) {
    let command = '';
    if (target.bundle !== false) {
      const engine = this.buildEngines.getEngine(target.engine);
      command = engine.getBuildCommand(
        target,
        buildType,
        forceRun,
        forceWatch,
        forceInspect,
        forceAnalyze
      );
    }

    return command;
  }
  /**
   * Copy a target files to the distribution directory. The only reason to copy a target files are:
   * If the target needs to be transpiles or if the build type is `production`, on all the other
   * cases the method won't do anything.
   * @param {string} targetName The name of the target.
   * @param {string} buildType  The type of build it's being made: `production` or `development`.
   * @return {Promise<undefined,Error>}
   */
  copyTarget(targetName, buildType) {
    const target = this.targets.getTarget(targetName);
    let result;
    if (
      target.is.node &&
      target.bundle === false &&
      (buildType === 'production' || target.transpile)
    ) {
      result = this.buildCopier.copyTargetFiles(target);
    } else {
      result = Promise.resolve();
    }

    return result;
  }
  /**
   * Transpile a target files **that have been previously copied** to the distribution directory.
   * If the target is not a Node target or it doesn't require transpiling, this method won't do
   * anything.
   * @param {string} targetName The name of the target.
   * @param {string} buildType  The type of build it's being made: `production` or `development`.
   * @return {Promise<undefined,Error>}
   */
  transpileTarget(targetName, buildType) {
    const target = this.targets.getTarget(targetName);
    let result;
    if (
      target.is.node &&
      target.bundle === false &&
      target.transpile
    ) {
      result = this.buildTranspiler.transpileTargetFiles(target, buildType);
    } else {
      result = Promise.resolve();
    }

    return result;
  }
  /**
   * Removes all previous builds/copies of a target from the distribution directory.
   * @param {string|target} targetName The name of the target, or the target itself.
   * @return {Promise<undefined,Error>}
   */
  cleanTarget(targetName) {
    const target = typeof targetName === 'string' ?
      this.targets.getTarget(targetName) :
      targetName;

    return this.buildCleaner.cleanTarget(target);
  }
}
/**
 * The service provider that once registered on the app container will set an instance of
 * `Builder` as the `builder` service.
 * @example
 * // Register it on the container
 * container.register(builder);
 * // Getting access to the service instance
 * const builder = container.get('builder');
 * @type {Provider}
 */
const builder = provider((app) => {
  app.set('builder', () => new Builder(
    app.get('buildCleaner'),
    app.get('buildCopier'),
    app.get('buildEngines'),
    app.get('buildTranspiler'),
    app.get('targets')
  ));
});

module.exports = {
  Builder,
  builder,
};