Home Reference Source Repository

src/component/npm-component.js

'use strict';

const DependencyBasedComponent = require('./dependency-based-component');
const emitEvents = require('./emit/events');
const events = require('./npm/events');
const os = require('os');
const fse = require('fs-extra');
const NpmModule = require('./npm/npm-module');
const Cache = require('./npm/cache');
const path = require('path');

/**
 * NPM component
 */
class NpmComponent extends DependencyBasedComponent {
  /**
   * @param {*} args
   */
  constructor(...args) {
    super(...args);
    
    this._cacheDir = null;
    this._cache = {};
  }
  
  /**
   * @returns {string}
   */
  get name() {
    return 'npm';
  }
  
  /**
   * @returns {string[]}
   */
  get dependencies() {
    return [ 'emit' ];
  }
  
  /**
   * @param {Emitter} emitter
   * 
   * @returns {Promise}
   */
  cacheDir(emitter) {
    if (this._cacheDir) {
      return Promise.resolve(this._cacheDir);
    }
    
    this._cacheDir = path.join(os.tmpdir(), '_recink_npm_cache_');
    
    return fse.ensureDir(this._cacheDir)
      .then(() => {
        this.logger.debug('Npm cache', this._cacheDir);
        
        return emitter.emitBlocking(events.npm.cache.init, this._cacheDir)
          .then(() => Promise.resolve(this._cacheDir));
      });
  }
  
  /**
   * @param {Emitter} emitter
   * @param {string} name
   * 
   * @returns {Promise}
   */
  cache(emitter, name) {
    if (this._cache.hasOwnProperty(name)) {
      return Promise.resolve(this._cache[name]);
    }
    
    return this.cacheDir(emitter)
      .then(cacheDir => {
        this._cache[name] = new Cache(cacheDir, name);
        
        return Promise.resolve(this._cache[name]);
      });
  }
  
  /**
   * @param {Emitter} emitter
   * 
   * @returns {Promise}
   */
  run(emitter) {
    return new Promise(resolve => {
      emitter.onBlocking(emitEvents.module.process.start, emitModule => {
        return this.cache(emitter, emitModule.name)
          .then(cache => {
            const npmModule = new NpmModule(
              emitModule.container.get('root'),
              cache,
              this.logger
            );
            
            this.logger.info(
              this.logger.emoji.hat, 
              `Ensure dependencies in place for ${ emitModule.name }`
            );
            
            emitter.emit(events.npm.dependencies.install, npmModule, emitModule);
            
            return npmModule.install(
              Object.assign(
                {}, 
                this.container.get('dependencies', {}), 
                emitModule.container.get('dependencies', {})
              ),
              [].concat(
                this.container.get('scripts', []),
                emitModule.container.get('scripts', [])
              )
            ).then(() => {              
              emitter.emit(events.npm.dependencies.postinstall, npmModule, emitModule);
            });
          });
      });
      
      emitter.on(emitEvents.modules.process.end, () => {
        process.nextTick(() => resolve());
      });
    });
  }
}

module.exports = NpmComponent;