simbo/gulpplug

View on GitHub
lib/plug.js

Summary

Maintainability
A
1 hr
Test Coverage
'use strict';

var path = require('path');

var arrayify = require('arrayify'),
    autoPlug = require('auto-plug'),
    glob = require('glob'),
    Options = require('defined-options');

var Task = require('./task.js');

var is = Options.is;

function Plug(gulp, options) {
  this.gulp = gulp;
  this.tasks = {};
  this.plugins = {};
  this.setOptions(options);
  [
    ['util', 'gulp-util'],
    ['runSequence', 'run-sequence']
  ]
    .forEach(function(mod) {
      Object.defineProperty(this, mod[0], {
        get: function() {
          return require(mod[1]);
        }
      });
    }.bind(this));
}

Plug.prototype.setOptions = function(options) {
  if (!this.hasOwnProperty('options')) {
    this.options = new Options({
      module: {
        default: module.parent.parent,
        validate: 'object'
      },
      require: {
        default: function() {
          return this.options.module.require;
        },
        validate: 'function'
      },
      cwd: {
        default: function() {
          return path.dirname(this.options.module.filename);
        },
        validate: 'string!empty'
      },
      tasksDir: {
        default: '.gulpplug',
        validate: 'string!empty'
      },
      tasksGlob: {
        default: '**/*.js',
        validate: 'string!empty'
      },
      getTaskName: {
        default: function() {
          return getTasknameFromFilepath;
        },
        validate: 'function'
      }
    });
  }
  options = typeof options === 'object' ? options : {};
  this.options.merge(options);
  if (this.options.validate('module', options.module)) {
    ['require', 'cwd'].forEach(function(rel) {
      if (!this.options.validate(rel, options[rel])) {
        this.options.default(rel);
      }
    }.bind(this));
  }
  return this;
};

Plug.prototype.getTasksFromGlob = function() {
  return glob.sync(this.options.tasksGlob, {
    cwd: path.join(this.options.cwd, this.options.tasksDir)
  }).reduce(function(tasks, filepath) {
    tasks.push([this.getTasknameFromFilepath(filepath), filepath]);
    return tasks;
  }.bind(this), []);
};

Plug.prototype.addTasks = function(tasks) {
  tasks = tasks || this.getTasksFromGlob();
  arrayify(tasks).forEach(function(task) {
    this.addTask.apply(this, arrayify(task));
  }.bind(this));
  return this;
};

Plug.prototype.addTask = function(task, taskFile) {
  var taskModule = task.length && taskFile ?
    this.options.require(path.join(this.options.cwd, this.options.tasksDir, taskFile)) : false;
  task = new Task(task, taskModule);
  if (task.isValid()) {
    this.gulp.task(task.name, task.dependencies, task.fn.bind(this));
    this.tasks[task.name] = task;
  }
  return this;
};

Plug.prototype.addSequence = function(taskName, sequence, taskDescription) {
  if (!is('string!empty', taskName)) return this;
  sequence = arrayify(sequence).filter(function(seq) {
    return is(['string!empty[]', 'string!empty'], seq);
  });
  taskDescription = is('string!empty', taskDescription) ?
    taskDescription : sequence.reduce(function(descr, seq) {
      return descr.concat([Array.isArray(seq) ?
          this.util.colors.gray('[') +
          seq.map(function(seq_) {
            return this.util.colors.cyan(seq_);
          }.bind(this)).join(this.util.colors.gray(' + ')) +
          this.util.colors.gray(']') :
        this.util.colors.cyan(seq)]);
    }.bind(this), []).join(this.util.colors.gray(', '));
  this.addTask({
    name: taskName,
    description: taskDescription,
    fn: function(done) {
      this.runSequence.apply(this.gulp, sequence.concat([done]));
    }
  });
  return this;
};

Plug.prototype.getTasks = function() {
  return Object.keys(this.tasks).reduce(function(tasks, taskName) {
    tasks.push(this.tasks[taskName]);
    return tasks;
  }.bind(this), []);
};

Plug.prototype.addHelpTask = function() {
  this.addTask({
    name: 'help',
    fn: helpTask,
    description: 'display help message'
  });
  if (!this.gulp.hasTask('default')) {
    this.gulp.task('default', ['help']);
  }
  return this;
};

function helpTask(done) {
  var line = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━';
  this.util.log(this.util.colors.gray(line));
  this.util.log(this.util.colors.yellow('Available Tasks:'));
  this.getTasks().filter(function(task) {
    return task.description !== false;
  }).sort(function(taskA, taskB) {
    if (taskA.name < taskB.name) return -1;
    if (taskA.name > taskB.name) return 1;
    return 0;
  }).forEach(function(task) {
    this.util.log(
      this.util.colors.cyan(task.name) +
      this.util.colors.gray(' ➜ ') +
      (typeof task.description === 'string' && task.description.length > 0 ?
        this.util.colors.white(task.description) : this.util.colors.gray('(no description)')
      )
    );
  }.bind(this));
  this.util.log(this.util.colors.gray(line));
  done();
}

Plug.prototype.getTasknameFromFilepath = function(filepath) {
  return this.options.getTaskName(filepath);
};

function getTasknameFromFilepath(filepath) {
  return filepath
    .replace(/([^a-z0-9_\.\/-]+)|(\.[^\.]+$)/gi, '')
    .replace(new RegExp(path.sep, 'g'), ':');
}

Plug.prototype.loadPlugins = function(autoPlugOptions) {
  autoPlugOptions = autoPlugOptions || {};
  if (!autoPlugOptions.hasOwnProperty('module')) {
    autoPlugOptions.module = this.options.module;
  }
  autoPlugOptions.prefix = 'gulp';
  this.plugins = autoPlug(autoPlugOptions);
  return this;
};

module.exports = Plug;