'use strict';

var ___dist_vendor_js = require('../dist/vendor.js');
var events = require('events');
var path = require('path');
var fs = require('fs');

var log = ___dist_vendor_js.debug('fileUtils');

var SLASH = '/'.charCodeAt(0);

function isDirectory (p) {
  return (fs.existsSync(p) && fs.lstatSync(p).isDirectory())
}

function isAbsolute$1(p) {
  // this is broken since node 8
  // return path.resolve(p) === path.normalize(p)
  return path.isAbsolute(p)
}

function copySync(src, dest) {
  var dir = _dir(dest);
  log(("ensureDirSync(" + dir + ")"));
  ___dist_vendor_js.fse.ensureDirSync(dir);
  ___dist_vendor_js.fse.copySync(src, dest);
}

function writeSync(dest, buf) {
  var dir = _dir(dest);
  ___dist_vendor_js.fse.ensureDirSync(dir);
  fs.writeFileSync(dest, buf);
}

function _dir(p) {
  if (p.charCodeAt(p.length-1) === SLASH) { return p }
  else { return path.dirname(p) }
}

var log$1 = ___dist_vendor_js.debug('bundler');

var opts = {
  encoding: 'utf-8',
  persistent: true,
  // TODO: do we really want this
  // Under windows I found especially Sublime
  // causing a lot of double events
  awaitWriteFinish: {
    stabilityThreshold: 100,
    pollInterval: 50
  }
};

var FileWatcher = (function (EventEmitter$$1) {
  function FileWatcher (file) {
    EventEmitter$$1.call(this);
    this._file = file;
    var watcher = ___dist_vendor_js.chokidar.watch(file, opts);
    this._watcher = watcher;
    watcher.setMaxListeners(0);
    watcher.on('error', function(err) {
      if ( err.code === 'ENOENT' ) {
        // can't watch files that don't exist (e.g. injected by plugins somehow)
      } else {
        throw err
      }
    });
    watcher.on('unlink', this.onDelete.bind(this));
    watcher.on('change', this.onChange.bind(this));
  }

  if ( EventEmitter$$1 ) FileWatcher.__proto__ = EventEmitter$$1;
  FileWatcher.prototype = Object.create( EventEmitter$$1 && EventEmitter$$1.prototype );
  FileWatcher.prototype.constructor = FileWatcher;

  FileWatcher.prototype.close = function close () {
    this._watcher.close();
  };

  FileWatcher.prototype.onDelete = function onDelete (file) {
    log$1('File deleted: %s', file);
    this.emit('unlink', this._file);
    // TODO: we need to think about a way to explicitly
    // free watchers
    // ATM, watchers are only freed when stopping the bundler
    // this.close()
  };

  FileWatcher.prototype.onChange = function onChange (file) {
    log$1('File changed: %s', file);
    this.emit('change', file);
  };

  return FileWatcher;
}(events.EventEmitter));

var opts$1 = {
  encoding: 'utf-8',
  persistent: true,
  ignoreInitial: true
};

var GlobWatcher = function GlobWatcher (pattern) {
  var watcher = ___dist_vendor_js.chokidar.watch(pattern, opts$1);
  this._watcher = watcher;
  watcher.setMaxListeners(0);
  watcher.on('error', function(err) {
    throw err
  });
};

GlobWatcher.prototype.close = function close () {
  this._watcher.close();
};

GlobWatcher.prototype.on = function on (evt, handler) {
  this._watcher.on(evt, handler);
};

var Watcher = function Watcher() {
  this.watching = false;
  this.watchEntries = {};
  this.watchers = {};

  // make sure that watchers are disposed on exit
  this.stop = this.stop.bind(this);
  process.on('SIGINT', this.stop);
  process.on('exit', this.stop);
};

Watcher.prototype.start = function start () {
  if (this.watching) { return }
  var watchEntries = this.watchEntries;
  var watchers = this.watchers;
  Object.keys(watchEntries).forEach(function(id) {
    var watcher = watchers[id];
    if (watcher) { watcher.close(); }
    var watchEntry = watchEntries[id];
    watchers[id] = this._createWatcher(watchEntry);
  }.bind(this));
  this.watching = true;
};

Watcher.prototype.stop = function stop () {
  var watchEntries = this.watchEntries;
  var watchers = this.watchers;
  Object.keys(watchEntries).forEach(function(id) {
    var watcher = watchers[id];
    if (watcher) {
      watcher.close();
      delete watchers[id];
    }
  });
  this.watching = false;
};

Watcher.prototype.watch = function watch (patternOrPath, hooks) {
  if (!patternOrPath || !___dist_vendor_js.isString(patternOrPath)) {
    throw new Error('Watcher.watch(): invalid path ' + patternOrPath)
  }
  var watchEntries = this.watchEntries;
  var watchers = this.watchers;
  var watchEntry;
  var type = ___dist_vendor_js.glob.hasMagic(patternOrPath) ? 'glob' : 'file';
  if (type === 'file' && !isAbsolute$1(patternOrPath)) {
    throw new Error('Only absolute file paths are allowed. Was '+patternOrPath)
  }
  if (!watchEntries[patternOrPath]) {
    watchEntry = {
      type: type,
      path: patternOrPath,
      handlers: [hooks]
    };
    watchEntries[patternOrPath] = watchEntry;
  } else {
    watchEntries[patternOrPath].handlers.push(hooks);
    return
  }
  if (this.watching) {
    watchers[patternOrPath] = this._createWatcher(watchEntry);
  }
};

Watcher.prototype._createWatcher = function _createWatcher (watchEntry) {
  var w = watchEntry.type === 'file' ?
    new FileWatcher(watchEntry.path) :
    new GlobWatcher(watchEntry.path);
  // console.log('### watching %s', watchEntry.path)
  watchEntry.handlers.forEach(function(hooks) {
    Object.keys(hooks).forEach(function(evt) {
      w.on(evt, hooks[evt]);
    });
  });
  return w
};

var Task = function Task(name, fn, deps) {
  this.name = name;
  this.fn = fn;
  this.deps = deps;
  this.description = '';
};
Task.prototype.describe = function describe (description) {
  this.description = description;
  return this
};

var Action = function Action(inputs, outputs) {
  this.inputs = inputs || [];
  this.outputs = outputs || [];
};

var prototypeAccessors$1 = { id: {},descr: {} };

Action.prototype.invalidate = function invalidate () {
  // nothing by default
  // Note: some actions use Action.removeOutputs()
};

Action.prototype.update = function update (next) {}; // eslint-disable-line no-unused-vars

prototypeAccessors$1.id.get = function () {
  return String(this.inputs) + '->' + String(this.outputs)
};

prototypeAccessors$1.descr.get = function () {
  return this.id
};

Object.defineProperties( Action.prototype, prototypeAccessors$1 );

Action.removeOutputs = function(action) {
  action.outputs.forEach(function(file) {
    log$1('Invalidating %s', file);
    ___dist_vendor_js.fse.removeSync(file);
  });
};

var log$3 = ___dist_vendor_js.debug('copy');

/*
  Copy a single file into dist folder:
  ```
    copy('./foo.js', 'dist/')
  ```

  Copy a single file with renaming
  ```
    copy('./foo.js', 'dist/bar.js')
  ```

  Copy a whole directory into dist folder
  ```
    copy('./assets', 'dist/')
  ```

  Copy a whole directory into dist folder with renaming
  ```
    copy('./node_modules/substance/dist', 'dist/substance')
  ```

  Copy with glob pattern
  ```
    copy('./node_modules/substance/packages/** /*.css', 'dist/styles/', { root: './node_modules/substance/'})
  ```
*/

var CopyCommand = function CopyCommand(src, dest, opts) {
  this.src = src;
  this.dest = dest;
  this.opts = opts || {};
};

var prototypeAccessors = { id: {},name: {} };

prototypeAccessors.id.get = function () {
  return ['CopyCommand', this.src, '->', this.dest].join(' ')
};

prototypeAccessors.name.get = function () {
  return 'copy'
};

CopyCommand.prototype.execute = function execute (bundler) {
  bundler._info('Copy:', this.src, '->', this.dest);
  var rootDir = bundler.rootDir;
  var dest = this.dest;
  if (!isAbsolute$1(dest)) { dest = path.join(rootDir, dest); }
  var lastIsSlash = (dest[dest.length-1] === path.sep);
  if (___dist_vendor_js.glob.hasMagic(this.src)) {
    // use the parent of the first * as relative root
    // for paths found via glob
    if (!this.opts.root) {
      var idx = this.src.lastIndexOf('*');
      var root = path.dirname(this.src.slice(0, idx));
      this.opts.root = root;
    }
    return this._executeWithGlob(bundler)
  }
  else if (isDirectory(this.src)) {
    log$3('Copying a directory...');
    if (this.opts.root) {
      // just use the option
    } else if (lastIsSlash) {
      if (isAbsolute$1(this.src)) {
        this.opts.root = path.dirname(this.src);
      } else {
        this.opts.root = path.join(rootDir, path.dirname(this.src));
      }
      log$3('using implicit root dir: ' + this.opts.root);
    } else {
      this.opts.root = this.src;
      log$3('using implicit root dir: ' + this.opts.root);
    }
    this.src = this.src+"/**/*";
    return this._executeWithGlob(bundler)
  }
  else {
    return this._executeWithoutGlob(bundler)
  }
};

CopyCommand.prototype._executeWithoutGlob = function _executeWithoutGlob (bundler) {
  var rootDir = bundler.rootDir;
  var dest = this.dest;
  var src = this.src;
  if (!isAbsolute$1(src)) { src = path.join(rootDir, src); }
  if (!isAbsolute$1(dest)) { dest = path.join(rootDir, dest); }
  var lastIsSlash = (dest[dest.length-1] === path.sep);
  if (lastIsSlash || isDirectory(dest)) { dest = path.join(dest, path.basename(src)); }
  // console.log('####', dest, isAbsolute(dest), dest[dest.length-1], path.sep, lastIsSlash, path.basename(src))
  var action = new CopyAction(src, dest);
  bundler._registerAction(action);
  action._execute();
};

CopyCommand.prototype._executeWithGlob = function _executeWithGlob (bundler) {
  var rootDir = bundler.rootDir;
  var watcher = bundler.watcher;
  var pattern = this.src;
  var dest = this.dest;
  if (!isAbsolute$1(dest)) { dest = path.join(rootDir, dest); }
  var globRoot = rootDir;
  if (this.opts.root) {
    if (isAbsolute$1(this.opts.root)) {
      globRoot = this.opts.root;
    } else {
      globRoot = path.join(rootDir, this.opts.root);
    }
  }
  var files = ___dist_vendor_js.glob.sync(pattern, {});
  if (files) {
    files.forEach(function(file) {
      var srcPath = path.join(rootDir, file);
      if (isDirectory(srcPath)) { return }
      var destPath = path.join(dest, path.relative(globRoot, file));
      var action = new CopyAction(srcPath, destPath);
      bundler._registerAction(action);
      action._execute();
    });
  } else {
    console.error('No files found for pattern %s', pattern);
  }

  // add a watcher that is used to register actions
  // for added files
  watcher.watch(pattern, {
    'add': this._onAdd.bind(this, bundler)
  });
};

/*
  When used with a glob pattern this gets called
  when a new file has been added
*/
CopyCommand.prototype._onAdd = function _onAdd (bundler, file) {
  if (isDirectory(file)) { return }
  var rootDir = bundler.rootDir;
  var srcPath = file;
  if (!isAbsolute$1(srcPath)) { srcPath = path.join(rootDir, srcPath); }
  if (!fs.existsSync(srcPath)) { return }
  var globRoot = this.opts.root ? path.join(rootDir, this.opts.root) : rootDir;
  var destPath = path.join(this.dest, path.relative(globRoot, file));
  if (!isAbsolute$1(destPath)) { destPath = path.join(rootDir, destPath); }
  var action = new CopyAction(srcPath, destPath);
  bundler._registerAction(action);
  bundler._schedule(action);
};

Object.defineProperties( CopyCommand.prototype, prototypeAccessors );

var CopyAction = (function (Action$$1) {
  function CopyAction(src, dest) {
    Action$$1.call(this, [src], [dest]);

    if (!isAbsolute$1(src)) {
      throw new Error('Only absolute paths are allowed. Was ' + src)
    }
    if (!isAbsolute$1(dest)) {
      throw new Error('Only absolute paths are allowed. Was ' + dest)
    }
    // use real paths so that we do not register copy actions
    // for the same file twice (~ in presence of sym links)
    src = fs.realpathSync(src);

    this.src = src;
    this.dest = dest;
  }

  if ( Action$$1 ) CopyAction.__proto__ = Action$$1;
  CopyAction.prototype = Object.create( Action$$1 && Action$$1.prototype );
  CopyAction.prototype.constructor = CopyAction;

  var prototypeAccessors$1 = { id: {} };

  prototypeAccessors$1.id.get = function () {
    return ['Copy:',this.src,'->',this.dest].join(' ')
  };

  CopyAction.prototype.execute = function execute (bundler) {
    bundler._info(this.id);
    this._execute();
  };

  CopyAction.prototype.invalidate = function invalidate () {
    ___dist_vendor_js.fse.removeSync(this.dest);
  };

  CopyAction.prototype._execute = function _execute () {
    var src = this.src;
    var dest = this.dest;
    if (fs.existsSync(src)) {
      log$3(("copying " + src + " -> " + dest));
      copySync(src, dest);
    }
  };

  Object.defineProperties( CopyAction.prototype, prototypeAccessors$1 );

  return CopyAction;
}(Action));

function randomId() {
  var length = 8;
  var ts = Date.now().toString();
  var parts = ts.split('').reverse();
  var id = new Array(length);
  for (var i = length - 1; i >= 0; i--) {
    id[i] = _getRandomInt(0,parts.length-1);
  }
  return id.join('')
}

function _getRandomInt( min, max ) {
  return Math.floor(Math.random()*(max-min+1))+min
}

var CustomCommand = function CustomCommand(description, params) {
  this._id = randomId();
  this.description = description;
  this.src = params.src;
  this.dest = params.dest;
  this._execute = params.execute;
  if (!___dist_vendor_js.isFunction(this._execute)) {
    throw new Error("'execute' must be a function")
  }
};

var prototypeAccessors$2 = { id: {},descr: {},name: {} };

prototypeAccessors$2.id.get = function () {
  return this._id
};

prototypeAccessors$2.descr.get = function () {
  return this.description
};

prototypeAccessors$2.name.get = function () {
  return 'custom'
};


CustomCommand.prototype.execute = function execute (bundler) {
  if (this.src && ___dist_vendor_js.isArray(this.src)) {
    return this._executeWithCollection(bundler)
  } else if (this.src && ___dist_vendor_js.glob.hasMagic(this.src)) {
    return this._executeWithGlob(bundler)
  } else {
    return this._executeWithoutGlob(bundler)
  }
};

CustomCommand.prototype._executeWithoutGlob = function _executeWithoutGlob (bundler) {
  var src = this.src;
  var dest = this.dest;
  if (src && !isAbsolute$1(src)) { src = path.join(bundler.rootDir, src); }
  if (dest && !isAbsolute$1(dest)) { dest = path.join(bundler.rootDir, dest); }
  var action = new CustomAction(this._id, this.description, [src], [dest], this._execute);
  bundler._registerAction(action);
  return action.execute(bundler)
};

CustomCommand.prototype._executeWithGlob = function _executeWithGlob (bundler) {
  var rootDir = bundler.rootDir;
  var watcher = bundler.watcher;
  var pattern = this.src;
  var dest = this.dest;
  if (!isAbsolute$1(dest)) { dest = path.join(rootDir, dest); }
  var files = ___dist_vendor_js.glob.sync(pattern, {});
  if (files) {
    files = files.map(function(file) {
      return path.join(rootDir, file)
    });
    var action = new CustomAction(this._id, this.description, files, [dest], this._execute);
    bundler._registerAction(action);
    var result = action.execute(bundler);
    // TODO: need to rework the whole dynamic registry stuff
    watcher.watch(pattern, {
      add: function(file) {
        action.inputs.push(file);
        action.inputs = ___dist_vendor_js.uniq(action.inputs);
        var _actionsByInput = bundler._actionsByInput;
        if (!_actionsByInput[file]) { _actionsByInput[file] = []; }
        _actionsByInput[file] = ___dist_vendor_js.uniq(_actionsByInput[file].concat(action));
      }
    });
    return result
  } else {
    console.error('No files found for pattern %s', pattern);
  }
};

CustomCommand.prototype._executeWithCollection = function _executeWithCollection (bundler) {
  var rootDir = bundler.rootDir;
  var watcher = bundler.watcher;
  var dest = this.dest;
  if (dest && !isAbsolute$1(dest)) { dest = path.join(rootDir, dest); }
  var files = [];
  var patterns = [];
  this.src.forEach(function(fileOrPattern) {
    if (___dist_vendor_js.glob.hasMagic(fileOrPattern)) {
      patterns.push(fileOrPattern);
      files = files.concat(___dist_vendor_js.glob.sync(fileOrPattern, {}));
    } else {
      files.push(fileOrPattern);
    }
  });
  if (files.length) {
    files = files.map(function(file) {
      return path.join(rootDir, file)
    });
    var action = new CustomAction(this._id, this.description, files, [dest], this._execute);
    bundler._registerAction(action);
    var result = action.execute(bundler);
    patterns.forEach(function(pattern) {
      // TODO: need to rework the whole dynamic registry stuff
      watcher.watch(pattern, {
        add: function(file) {
          action.inputs.push(file);
          action.inputs = ___dist_vendor_js.uniq(action.inputs);
          var _actionsByInput = bundler._actionsByInput;
          if (!_actionsByInput[file]) { _actionsByInput[file] = []; }
          _actionsByInput[file] = ___dist_vendor_js.uniq(_actionsByInput[file].concat(action));
        }
      });
    });
    return result
  } else {
    console.error('No files found for pattern %s', patterns);
  }
};

Object.defineProperties( CustomCommand.prototype, prototypeAccessors$2 );

var CustomAction = (function (Action$$1) {
  function CustomAction(id, description, inputs, outputs, _execute) {
    Action$$1.call(this, inputs.filter(Boolean), outputs.filter(Boolean));
    this._id = id;
    this._description = description;
    this._execute = _execute;
  }

  if ( Action$$1 ) CustomAction.__proto__ = Action$$1;
  CustomAction.prototype = Object.create( Action$$1 && Action$$1.prototype );
  CustomAction.prototype.constructor = CustomAction;

  var prototypeAccessors$1 = { id: {},description: {} };

  prototypeAccessors$1.id.get = function () {
    return this._id
  };

  prototypeAccessors$1.description.get = function () {
    return this._description
  };

  CustomAction.prototype.execute = function execute (bundler) {
    bundler._info(this._description);
    var t0 = Date.now();
    this.outputs.forEach(function(f) {
      ___dist_vendor_js.fse.ensureDirSync(path.dirname(f));
    });
    var inputs = this.inputs.filter(function(file) {
      return fs.existsSync(file)
    });
    return Promise.resolve(this._execute(inputs))
    .then(function() {
      bundler._info(___dist_vendor_js.colors.green('..finished in %s ms.'), Date.now()-t0);
    })
  };

  Object.defineProperties( CustomAction.prototype, prototypeAccessors$1 );

  return CustomAction;
}(Action));

var ExecCommand = function ExecCommand(cmd, options) {
  if ( options === void 0 ) options = {};

  this.cmd = cmd;
  this.options = options;
};

var prototypeAccessors$3 = { id: {},name: {} };

prototypeAccessors$3.id.get = function () {
  return ['Exec:', this.cmd].join(' ')
};

prototypeAccessors$3.name.get = function () {
  return 'exec'
};

ExecCommand.prototype.execute = function execute (bundler) {
  var action = new ExecAction(this);
  bundler._registerAction(action);
  return action.execute(bundler)
};

Object.defineProperties( ExecCommand.prototype, prototypeAccessors$3 );

var ExecAction = (function (Action$$1) {
  function ExecAction(command) {
    Action$$1.call(this);

    this.command = command;
    this.cmd = command.cmd;
    this.options = command.options;
  }

  if ( Action$$1 ) ExecAction.__proto__ = Action$$1;
  ExecAction.prototype = Object.create( Action$$1 && Action$$1.prototype );
  ExecAction.prototype.constructor = ExecAction;

  var prototypeAccessors$1 = { id: {} };

  prototypeAccessors$1.id.get = function () {
    return ['Exec: ', this.cmd].join('')
  };

  ExecAction.prototype.execute = function execute (bundler) {
    var this$1 = this;

    var exec = require('child_process').exec;
    var cmd = this.cmd;
    var options = this.options;
    if (options.cwd && !fs.existsSync(options.cwd)) {
      throw new Error('Directory does not exist! ' + options.cwd)
    }
    return new Promise(function (resolve, reject) {
      bundler._info(this$1.descr);
      exec(cmd, options, function (err) {
        if (err) {
          reject(new Error(err));
        } else {
          resolve();
        }
      });
    })
  };

  Object.defineProperties( ExecAction.prototype, prototypeAccessors$1 );

  return ExecAction;
}(Action));

var ForEachCommand = function ForEachCommand(pattern, handler) {
  this._id = randomId();
  this.description = "forEach(" + pattern + ")...";
  this.pattern = pattern;
  this.handler = handler;
  if (!___dist_vendor_js.isFunction(handler)) {
    throw new Error("'handler' must be a function")
  }
};

var prototypeAccessors$4 = { id: {},descr: {},name: {} };

prototypeAccessors$4.id.get = function () {
  return this._id
};

prototypeAccessors$4.descr.get = function () {
  return this.description
};

prototypeAccessors$4.name.get = function () {
  return 'forEach'
};

ForEachCommand.prototype.execute = function execute (bundler) {
    var this$1 = this;

  var rootDir = bundler.rootDir;
  var watcher = bundler.watcher;
  var pattern = this.pattern;
  var files = ___dist_vendor_js.glob.sync(pattern, {});
  if (files) {
    var t0 = Date.now();
    bundler._info(this.description);
    var actions = files.map(function (file) {
      var absFile = !isAbsolute$1(file) ? path.join(rootDir, file) : file;
      return this$1._createAction(bundler, file, absFile, 'first-pass')
    });
    watcher.watch(pattern, {
      add: function(file) {
        var absFile = !isAbsolute$1(file) ? path.join(rootDir, file) : file;
        this._createAction(bundler, file, absFile);
      }
    });
    return Promise.all(actions).then(function () {
      bundler._info(___dist_vendor_js.colors.green('..finished in %s ms.'), Date.now()-t0);
    })
  } else {
    console.error('No files found for pattern %s', pattern);
  }
};

ForEachCommand.prototype._createAction = function _createAction (bundler, file, absFile, firstPass) {
  var action = new FileAction(this.description, file, absFile, this.handler);
  bundler._registerAction(action);
  return action.execute(bundler, firstPass)
};

Object.defineProperties( ForEachCommand.prototype, prototypeAccessors$4 );

var FileAction = (function (Action$$1) {
  function FileAction(title, file, absFile, handler) {
    Action$$1.call(this, [absFile], []);
    this.handler = handler;
    this.file = file;
    this.absFile = absFile;

    this._id = randomId();
    this.title = title;
  }

  if ( Action$$1 ) FileAction.__proto__ = Action$$1;
  FileAction.prototype = Object.create( Action$$1 && Action$$1.prototype );
  FileAction.prototype.constructor = FileAction;

  var prototypeAccessors$1 = { id: {},description: {} };

  prototypeAccessors$1.id.get = function () {
    return this._id
  };

  prototypeAccessors$1.description.get = function () {
    return this.title + ': ' + this.file
  };

  FileAction.prototype.execute = function execute (bundler, firstPass) {
    if (!firstPass) {
      bundler._info(this.title);
    }
    var t0 = Date.now();
    var file = this.file;
    var absFile = this.absFile;
    if (!fs.existsSync(absFile)) {
      throw new Error('File does not exist:', absFile)
    }
    return Promise.resolve(
      this.handler(file, {
        action: createActionProxy(bundler, this),
        fs: createFsProxy(bundler, this)
      })
    ).then(function () {
      if (!firstPass) {
        bundler._info(___dist_vendor_js.colors.green('..finished in %s ms.'), Date.now()-t0);
      }
    })
  };

  Object.defineProperties( FileAction.prototype, prototypeAccessors$1 );

  return FileAction;
}(Action));

function createActionProxy(bundler, action) {
  return {
    setDependencies: function setDependencies(deps) {
      // TODO: instead of adding files to the watcher
      // it would be more accurate to replace
      // the inputs.
      // For now it is good enough
      deps.forEach(function (f) {
        if (!isAbsolute$1(f)) {
          f = path.join(bundler.rootDir, f);
        }
        addInput(bundler, action, f);
      });
    }
  }
}

function createFsProxy(bundler, action) {
  return {
    readFileSync: function readFileSync$$1(f) {
      var args = [], len = arguments.length - 1;
      while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];

      if (!isAbsolute$1(f)) {
        f = path.join(bundler.rootDir, f);
      }
      addInput(bundler, action, f);
      return fs.readFileSync.apply(fs, [ f ].concat( args ))
    },
    writeFileSync: function writeFileSync$$1(f) {
      var args = [], len = arguments.length - 1;
      while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];

      if (!isAbsolute$1(f)) {
        f = path.join(bundler.rootDir, f);
      }
      addOutput(bundler, action, f);
      ___dist_vendor_js.fse.ensureDirSync(path.dirname(f));
      return fs.writeFileSync.apply(fs, [ f ].concat( args ))
    }
  }
}

function addInput(bundler, action, file) {
  if (!file) { return }
  if (action.inputs.indexOf(file) < 0) {
    action.inputs.push(file);
    bundler._registerActionInput(action, file);
  }
}

function addOutput(bundler, action, file) {
  if (!file) { return }
  if (action.outputs.indexOf(file) < 0) {
    action.outputs.push(file);
    bundler._registerActionOutput(action, file);
  }
}

var MakeCommand = function MakeCommand(module, tasks) {
  this.module = module;
  this.tasks = tasks || [];
};

var prototypeAccessors$5 = { id: {},name: {} };

prototypeAccessors$5.id.get = function () {
  return ['Make', this.module].concat(this.tasks).join(' ')
};

prototypeAccessors$5.name.get = function () {
  return 'make'
};

MakeCommand.prototype.execute = function execute (bundler) {
  bundler._info(this.id);

  var tasks = this.tasks;
  var module = this.module;
  var makefile;
  if (isAbsolute$1(module)) {
    makefile = module;
  } else {
    makefile = require.resolve(module+'/make.js');
  }
  if (!fs.existsSync(makefile)) {
    throw new Error('Could not find "make.js" in module "%s"', module)
  }
  makefile = fs.realpathSync(makefile);

  return new Promise(_runMake)

  function _runMake(resolve, reject) {
    // get the real location of the module in case
    // it is npm-linked
    var cp = require('child_process');
    var args = tasks.concat(['--remote']);
    if (bundler.opts.watch) { args.push('--watch'); }
    var child = cp.fork(makefile, args, {
      cwd: path.dirname(makefile)
    });
    child.on('message', function(msg) {
      if (msg === 'done') {
        resolve();
      }
    });
    child.on('error', function(error) {
      reject(new Error(error));
    });
  }
};

Object.defineProperties( MakeCommand.prototype, prototypeAccessors$5 );

var MinifyCommand = function MinifyCommand(src, opts) {
  if ( opts === void 0 ) opts = {};

  if (!/.js$/.exec(src)) { throw new Error("'src' must be a path to a '.js' file") }
  this.src = src;
  this.opts = opts;
  this._isWatching = false;
};

var prototypeAccessors$6 = { id: {},name: {} };

prototypeAccessors$6.id.get = function () {
  return ['MinifyCommand', this.src].join(' ')
};

prototypeAccessors$6.name.get = function () {
  return 'minify'
};

MinifyCommand.prototype.execute = function execute (bundler) {
  var src = this.src;
  if (!isAbsolute$1(src)) { src = path.join(bundler.rootDir, src); }
  var dest = path.join(path.dirname(src), path.basename(src, '.js')+'.min.js');
  var action = new MinifyAction(src, dest, this.opts);
  bundler._registerAction(action);
  action.execute(bundler);
};

Object.defineProperties( MinifyCommand.prototype, prototypeAccessors$6 );

var MinifyAction = (function (Action$$1) {
  function MinifyAction(src, dest, opts) {
    if ( opts === void 0 ) opts = {};

    Action$$1.call(this, [src], [dest]);

    this.src = src;
    this.dest = dest;
    this.debug = (opts.debug !== false);

    if (this.debug !== false) {
      this.destSourceMap = dest+'.map';
      this.outputs.push(this.destSourceMap);
    }
  }

  if ( Action$$1 ) MinifyAction.__proto__ = Action$$1;
  MinifyAction.prototype = Object.create( Action$$1 && Action$$1.prototype );
  MinifyAction.prototype.constructor = MinifyAction;

  var prototypeAccessors$1 = { id: {} };

  prototypeAccessors$1.id.get = function () {
    return ['Minify:', this.src].join(' ')
  };

  MinifyAction.prototype.execute = function execute (bundler) {
    bundler._info(this.id);
    // uglify can not be bundled as it does dynamic file loading
    // and we also don't ship it, thus it is required as late as possible
    var uglify = require('uglify-js-harmony');
    var src = this.src;
    var dest = this.dest;
    var inSourceMap = src + '.map';
    var code = fs.readFileSync(src, 'utf8');
    var destSourceMap = this.destSourceMap;
    var opts = {
      fromString: true,
    };
    if (this.debug) {
      opts.outSourceMap = destSourceMap;
      opts.sourceMapUrl = './'+path.basename(destSourceMap);
    }
    if (fs.existsSync(inSourceMap)) {
      opts.inSourceMap = inSourceMap;
    }
    var t0 = Date.now();
    var result = uglify.minify(code, opts);
    writeSync(dest, result.code);
    if (this.debug) {
      writeSync(destSourceMap, result.map);
    }
    bundler._info(___dist_vendor_js.colors.green('..finished in %s ms.'), Date.now()-t0);
  };

  MinifyAction.prototype.invalidate = function invalidate () {
    Action$$1.removeOutputs(this);
  };

  Object.defineProperties( MinifyAction.prototype, prototypeAccessors$1 );

  return MinifyAction;
}(Action));

var RemoveCommand = function RemoveCommand(rmPath) {
  this.rmPath = rmPath;
};

var prototypeAccessors$7 = { id: {},name: {} };

prototypeAccessors$7.id.get = function () {
  return ['Remove:', this.rmPath].join(' ')
};

prototypeAccessors$7.name.get = function () {
  return 'rm'
};

RemoveCommand.prototype.execute = function execute (bundler) {
  var rmPath = this.rmPath;
  if (rmPath[0] === '.') {
    rmPath = path.join(bundler.rootDir, rmPath);
  }
  if (fs.existsSync(rmPath)) {
    bundler._info(this.id);
    ___dist_vendor_js.fse.removeSync(this.rmPath);
  }
};

Object.defineProperties( RemoveCommand.prototype, prototypeAccessors$7 );

var EMPTY_ID = "\0ignore:empty.js";
var EMPTY_CODE = "export default {}";

function ignore(opts) {
  var keys = opts || [];
  function _shouldIgnore(importee) {
    for (var i = 0; i < keys.length; i++) {
      var key = keys[i];
      if (importee && importee.startsWith(key)) { return true }
    }
    return false
  }
  return {
    name: "resolve",
    resolveId: function resolveId(importee) {
      if (_shouldIgnore(importee)) {
        return EMPTY_ID
      }
      return null
    },
    load: function(id) {
      if (id === EMPTY_ID) {
        return EMPTY_CODE
      }
    }
  }
}

function buble$1 ( options ) {
  if ( !options ) { options = {}; }
  var filter = ___dist_vendor_js.pluginutils.createFilter( options.include, options.exclude );

  if ( !options.transforms ) { options.transforms = {}; }
  options.transforms.modules = false;

  return {
    name: 'buble',

    transform: function ( code, id ) {
      if (!/\.js$/.exec(id)) { return null }
      if ( !filter( id ) ) { return null }
      return ___dist_vendor_js.buble.transform( code, options )
    }
  }
}

/* eslint-disable semi */
var createFilter = ___dist_vendor_js.pluginutils.createFilter;

var istanbulPlugin = function (options) {
  if ( options === void 0 ) options = {};

  var filter = createFilter(options.include, options.exclude);

  return {
    transform: function transform (code, id) {
      // const istanbul = require('istanbul');
      if (!filter(id)) { return; }

      var instrumenter;
      var sourceMap = Boolean(options.sourceMap);
      var opts = Object.assign({}, options.instrumenterConfig);

      if (sourceMap) {
        opts.codeGenerationOptions = Object.assign({},
          opts.codeGenerationOptions || {format: {compact: !opts.noCompact}},
          {sourceMap: id, sourceMapWithCode: true}
        );
      }

      opts.esModules = true;
      instrumenter = new ___dist_vendor_js.Instrumenter(opts);

      // console.log('## Running istanbul on', id)
      code = instrumenter.instrumentSync(code, id);

      var map = sourceMap ?
                instrumenter.lastSourceMap().toJSON() :
                {mappings: ''};

      return { code: code, map: map };
    }
  };
};

function cleanup(options) {
  if ( options === void 0 ) options = {};

  var sourceMap = options.sourceMap !== false;
  return {
    name: "cleanup",
    transform: function(code) {
      var magicString = new ___dist_vendor_js.MagicString( code );
      ___dist_vendor_js.acorn.parse(code, {
        ecmaVersion: 8,
        sourceType: 'module',
        onComment: function(block, text, start, end) {
          magicString.remove(start, end);
        }
      });
      code = magicString.toString();
      var map = sourceMap ? magicString.generateMap({
        includeContent: true,
        hires: true
      }) : null;
      return { code: code, map: map }
    }
  }
}

var ENTRY = '\0rollup-glob:ENTRY';

function rollupGlob(options) {
  if ( options === void 0 ) options = {};

  var pattern = options.pattern;
  if (!pattern) { throw new Error("'pattern' is mandatory.") }
  return {
    name: "glob",
    resolveId: function resolveId (id) {
      if (id === ENTRY) { return ENTRY }
    },
    load: function load (id) {
      if (id === ENTRY) {
        var files = [];
        if (___dist_vendor_js.isArray(pattern)) {
          pattern.forEach(function (p) {
            files = files.concat(___dist_vendor_js.glob.sync(p));
          });
        } else {
          files = ___dist_vendor_js.glob.sync(pattern);
        }
        var index = files.map(function (f) {
          return ("import './" + f + "'")
        }).join('\n');
        return index
      }
    }
  }
}

rollupGlob.ENTRY = ENTRY;

var createFilter$1 = ___dist_vendor_js.pluginutils.createFilter;
var makeLegalIdentifier = ___dist_vendor_js.pluginutils.makeLegalIdentifier;

function json ( options ) {
  if ( options === void 0 ) options = {};

  var filter = createFilter$1( options.include, options.exclude );

  return {
    name: 'json',

    transform: function transform ( json, id ) {
      if ( id.slice( -5 ) !== '.json' ) { return null; }
      if ( !filter( id ) ) { return null; }

      var code = '';

      // Manipulating properties so keeping as `let`
      // eslint-disable-next-line prefer-const
      var ast = {
        type: 'Program',
        sourceType: 'module',
        start: 0,
        end: null,
        body: []
      };

      if ( json[0] !== '{' ) {
        code = "export default " + json + ";";

        ast.body.push({
          type: 'ExportDefaultDeclaration',
          start: 0,
          end: code.length,
          declaration: {
            type: 'Literal',
            start: 15,
            end: code.length - 1,
            value: null,
            raw: 'null'
          }
        });
      } else {
        var data = JSON.parse( json );

        var validKeys = [];
        var invalidKeys = [];

        Object.keys( data ).forEach( function (key) {
          if ( key === makeLegalIdentifier( key ) ) {
            validKeys.push( key );
          } else {
            invalidKeys.push( key );
          }
        });

        var char = 0;

        validKeys.forEach( function (key) {
          var declarationType = options.preferConst ? 'const' : 'var';
          var declaration = "export " + declarationType + " " + key + " = " + (JSON.stringify( data[ key ] )) + ";";

          var start = char;
          var end = start + declaration.length;

          // generate fake AST node while we're here
          ast.body.push({
            type: 'ExportNamedDeclaration',
            start: char,
            end: char + declaration.length,
            declaration: {
              type: 'VariableDeclaration',
              start: start + 7, // 'export '.length
              end: end,
              declarations: [
                {
                  type: 'VariableDeclarator',
                  start: start + 7 + declarationType.length + 1, // `export ${declarationType} `.length
                  end: end - 1,
                  id: {
                    type: 'Identifier',
                    start: start + 7 + declarationType.length + 1, // `export ${declarationType} `.length
                    end: start + 7 + declarationType.length + 1 + key.length, // `export ${declarationType} ${key}`.length
                    name: key
                  },
                  init: {
                    type: 'Literal',
                    start: start + 7 + declarationType.length + 1 + key.length + 3, // `export ${declarationType} ${key} = `.length
                    end: end - 1,
                    value: null,
                    raw: 'null'
                  }
                }
              ],
              kind: declarationType
            },
            specifiers: [],
            source: null
          });

          char = end + 1;
          code += declaration + "\n";
        });

        var defaultExportNode = {
          type: 'ExportDefaultDeclaration',
          start: char,
          end: null,
          declaration: {
            type: 'ObjectExpression',
            start: char + 15,
            end: null,
            properties: []
          }
        };

        char += 18; // 'export default {\n\t'.length'

        var defaultExportRows = validKeys.map( function (key) {
          var row = key + ": " + key;

          var start = char;
          var end = start + row.length;

          defaultExportNode.declaration.properties.push({
            type: 'Property',
            start: start,
            end: end,
            method: false,
            shorthand: false,
            computed: false,
            key: {
              type: 'Identifier',
              start: start,
              end: start + key.length,
              name: key
            },
            value: {
              type: 'Identifier',
              start: start + key.length + 2,
              end: end,
              name: key
            },
            kind: 'init'
          });

          char += row.length + 3; // ',\n\t'.length

          return row;
        }).concat( invalidKeys.map( function (key) { return ("\"" + key + "\": " + (JSON.stringify( data[ key ] ))); } ) );

        code += "export default {\n\t" + (defaultExportRows.join( ',\n\t' )) + "\n};";
        ast.body.push( defaultExportNode );

        var end = code.length;

        defaultExportNode.declaration.end = end - 1;
        defaultExportNode.end = end;
      }

      ast.end = code.length;

      return { ast: ast, code: code, map: { mappings: '' } };
    }
  };
}

var ZERO = "\0".charCodeAt(0);

var nodeResolve = require('rollup-plugin-node-resolve');

var RollupCommand = function RollupCommand(src, opts) {
  if (!src) { throw new Error("'src' is mandatory.") }
  // rollup does not have a good behavior with src being a glob pattern.
  // for that purpose we detect if src contains glob pattern
  // and then use a generated index file as entry
  var srcPattern = null;
  if(___dist_vendor_js.isArray(src) || ___dist_vendor_js.glob.hasMagic(src)) {
    srcPattern = src;
    src = rollupGlob.ENTRY;
  }
  this.src = src;

  var sourceMap = (opts.sourceMap !== false);

  // in rollup external and globals are often
  // redundant, thus we added an option to specify
  // externals as object, like you would define globals
  // This of course only makes sense for single-target builds
  // In multi-target builds you should define globals
  // in the target specification.
  var globals = Object.assign({}, opts.globals);
  if (opts.external && ___dist_vendor_js.isPlainObject(opts.external)) {
    Object.assign(globals, opts.external);
    opts.external = Object.keys(opts.external);
  }

  // NOTE: we must remove all externals which are ignored
  // as we want to give 'ignore' a higher precedence
  // rollup will not ask our resolver if it finds a matching
  // external
  if (opts.ignore && opts.ignore.length > 0 && opts.external) {
    opts.external = opts.external.filter(function (ext) {
      return opts.ignore.indexOf(ext)<0
    });
  }

  // parse targets
  if (opts.targets) {
    this.targets = opts.targets;
    delete opts.targets;
  } else if (opts.target) {
    this.targets = [opts.target];
    delete opts.target;
  } else {
    // all these are actually target specific options
    // but allowed on top-level for convenience
    // however, here we normalize, wrapping this into
    // 'targets'
    var TARGET_OPTS = [
      'dest', 'format', 'moduleName', 'paths',
      'sourceMap', 'sourceMapRoot', 'sourceMapPrefix'
    ];
    var target = {};
    TARGET_OPTS.forEach(function (name) {
      if (opts.hasOwnProperty(name)) {
        target[name] = opts[name];
        delete opts[name];
      }
    });
    // HACK: special treatment for globals
    target.globals = globals;
    this.targets = [target];
  }

  var resolveOpts;
  // always add node-resolve, only don't if set to false
  if (opts.resolve !== false) {
    resolveOpts = opts.resolve || { main: true, jsnext: true };
  }
  delete opts.resolve;

  var aliasOpts;
  if (opts.alias) {
    aliasOpts = opts.alias || {};
  }
  delete opts.alias;

  var ignoreOpts;
  if (opts.ignore) {
    ignoreOpts = opts.ignore;
  }
  delete opts.ignore;

  // commonjs modules
  var cjsOpts;
  if (opts.commonjs) {
    if (opts.commonjs === true) {
      // default setting
      cjsOpts = {
        include: ['node_modules/**']
      };
    } else if (___dist_vendor_js.isArray(opts.commonjs)) {
      var include = opts.commonjs.map(function (name) { return '**/'+name+'/**'; });
      cjsOpts = { include: include };
    } else if (___dist_vendor_js.isPlainObject(opts.commonjs)) {
      cjsOpts = opts.commonjs;
    }
  }
  delete opts.commonjs;

  var bubleOpts = null;
  if (opts.buble) {
    bubleOpts = Object.assign({}, opts.buble);
  }
  delete opts.buble;

  var jsonOpts = null;
  if (opts.json) {
    jsonOpts = opts.json;
  }
  delete opts.json;

  var istanbulOpts = null;
  if (opts.istanbul) {
    istanbulOpts = opts.istanbul;
  }
  delete opts.istanbul;

  var cleanupOpts = null;
  if (opts.cleanup) {
    cleanupOpts = opts.cleanup;
  }
  delete opts.cleanup;

  // Plugins

  var plugins = [];

  // if the src contains a glob pattern we use rollupGlob to generate the entry
  if (srcPattern) { plugins.push(rollupGlob({pattern:srcPattern})); }

  if (ignoreOpts) { plugins.push(ignore(ignoreOpts)); }

  if (aliasOpts) { plugins.push(___dist_vendor_js.alias(aliasOpts)); }

  // resolve plugin takes care of finding imports in 'node_modules'
  // NOTE: better this be the first and does everything related to resolving
  // i.e., aliases, ignores etc.
  if (resolveOpts) { plugins.push(nodeResolve(resolveOpts)); }

  // this is necesssary so that already existing sourcemaps
  // present in imported files are picked up
  if (sourceMap) { plugins.push(___dist_vendor_js.sourcemaps()); }

  // apply instrumentation before any other transforms
  if (istanbulOpts) { plugins.push(istanbulPlugin(istanbulOpts)); }

  // TODO: is it important to add commonjs here or could it be earlier as well?
  // e.g. does it need to be after buble?
  if (cjsOpts) { plugins.push(___dist_vendor_js.commonjs(cjsOpts)); }

  // if (nodeGlobalsOpts) plugins.push(nodeGlobals(nodeGlobalsOpts))

  // this turns on basic es6 transpilation
  if (bubleOpts) { plugins.push(buble$1(bubleOpts)); }

  if (jsonOpts) { plugins.push(json(jsonOpts)); }

  // TODO: need to discuss whether and how we want to allow custom rollup plugins
  // The order of plugins is critical in certain cases, thus as we do here, appending to
  // automatically added plugins, might lead to custom plugins not being called
  if (opts.plugins) {
    plugins = plugins.concat(opts.plugins);
  }
  delete opts.plugins;

  if (cleanupOpts) {
    plugins.push(cleanup(cleanupOpts));
  }

  this.plugins = plugins;

  this.opts = opts;
  this.cache = null;
};

var prototypeAccessors$8 = { id: {},name: {} };

prototypeAccessors$8.id.get = function () {
  return ['RollupCommand', this.src, this.targets.map(function(target) {
    return target.dest
  })]
};

prototypeAccessors$8.name.get = function () {
  return 'js'
};

RollupCommand.prototype.execute = function execute (bundler) {
  var src = this.src;
  // turn src into an absolute path, but only
  // if it does not start with "\0" as it used by rollup-glob.ENTRY
  if (src.charCodeAt(0)!==ZERO && !isAbsolute$1(src)) { src = path.join(bundler.rootDir, src); }
  var plugins = this.plugins;
  var targets = this.targets;
  var opts = this.opts;
  var action = new RollupAction(bundler, src, plugins, targets, opts);
  bundler._registerAction(action);
  return action.execute(bundler)
};

Object.defineProperties( RollupCommand.prototype, prototypeAccessors$8 );

var RollupAction = (function (Action$$1) {
  function RollupAction(bundler, src, plugins, targets, opts) {
    Action$$1.call(this);
    this.bundler = bundler;
    this.src = src;
    this.plugins = plugins;
    this.targets = targets;
    this.opts = opts;
    this.sourceMap = (opts.sourceMap !== false);
    this.rootDir = bundler.rootDir;

    this._cache = null;
    this._watched = {};

    this.outputs = this._getOutputs();
  }

  if ( Action$$1 ) RollupAction.__proto__ = Action$$1;
  RollupAction.prototype = Object.create( Action$$1 && Action$$1.prototype );
  RollupAction.prototype.constructor = RollupAction;

  var prototypeAccessors$1 = { id: {} };

  prototypeAccessors$1.id.get = function () {
    return ['Rollup:', this.src, '->'].concat(this._getBundles().join('|')).join(' ')
  };

  RollupAction.prototype.execute = function execute (bundler) {
    var this$1 = this;

    bundler._info(this.id);
    var t0 = Date.now();
    var cache = this._cache;
    var src = this.src;
    var targets = this.targets;
    var plugins = this.plugins;

    var opts = Object.assign({
      input: src,
      plugins: plugins,
      treeshake: true,
      cache: cache,
      onwarn: function (warning) {
        bundler._info(___dist_vendor_js.colors.yellow(warning.message));
        bundler._info(___dist_vendor_js.colors.grey(warning.url));
      }
    }, this.opts);

    log$1('RollupAction: starting rollup...');
    return ___dist_vendor_js.rollup.rollup(opts)
    .then(function (bundle) {
      log$1('RollupAction: received bundle...');
      this$1.cache = bundle;
      log$1('RollupAction: generating targets...');
      return Promise.all(targets.map(function (target) {
        return this$1._generate(bundle, target)
      })).then(function () {
        bundler._info(___dist_vendor_js.colors.green('..finished in %s ms.'), Date.now()-t0);
        this$1._updateWatchers(bundle);
      })
    })
    .catch(function (err) {
      if (err.loc) {
        console.error(___dist_vendor_js.colors.red('Rollup failed with %s in %s, line %2, column %s'), err.code, err.loc.file, err.loc.line, err.loc.column);
      } else {
        console.error(___dist_vendor_js.colors.red('Rollup failed with %s'), err.code, err);
      }
      if (err.frame) {
        console.error(___dist_vendor_js.colors.grey(err.frame));
      }
      throw err
    })
  };

  RollupAction.prototype.invalidate = function invalidate () {
    Action$$1.removeOutputs(this);
  };

  RollupAction.prototype._generate = function _generate (bundle, target) {
    var this$1 = this;

    var rootDir = this.rootDir;
    var absDest = isAbsolute$1(target.dest) ? target.dest : path.join(rootDir, target.dest);
    var opts = Object.assign({}, target);
    // HACK: do globals really need to go here?
    // maybe we should copy them previously
    if (this.opts.globals) {
      opts.globals = this.opts.globals;
    }
    if (this.sourceMap) {
      opts.sourceMap = true;
      opts.sourceMapFile = absDest;
    }
    // NOTE: with the latest rollup version,
    // some options have been renamed
    // const RENAMED
    var RENAMED = {
      'dest': 'file',
      'moduleName': 'name',
      'sourceMap': 'sourcemap',
      'sourceMapFile': 'sourcemapFile',
    };
    ___dist_vendor_js.forEach(RENAMED, function (newName, oldName) {
      if (opts.hasOwnProperty(oldName)) {
        opts[newName] = opts[oldName];
        delete opts[oldName];
      }
    });
    return bundle.generate(opts)
    .then(function (result) {
      // write the map file first so that a file watcher for the bundle
      // is not triggered too early
      if (this$1.sourceMap) {
        var sourceMap = result.map.toString();
        if (target.sourceMapRoot) {
          var data = JSON.parse(sourceMap);
          data.sources = data.sources.map(function(srcPath) {
            var absSrcPath = path.join(path.dirname(absDest), srcPath);
            var relSrcPath = path.relative(target.sourceMapRoot, absSrcPath);
            relSrcPath = relSrcPath.replace(/\\/g, "/");
            // console.log('### source file:', srcPath)
            // HACK: hard coded pattern for source path transformation
            if (target.sourceMapPrefix) { relSrcPath = target.sourceMapPrefix + '/' + relSrcPath; }
            return relSrcPath
          });
          sourceMap = JSON.stringify(data);
        }
        writeSync(absDest+'.map', sourceMap);
        writeSync(absDest,
          [
            result.code,
            // HACK: buble has troubles with '//' in a string
            "\n","/","/# sourceMappingURL=./", path.basename(absDest)+".map"
          ].join('')
        );
      } else {
        writeSync(absDest, result.code);
      }
    })
  };

  RollupAction.prototype._updateWatchers = function _updateWatchers (bundle) {
    var bundler = this.bundler;
    var watcher = bundler.watcher;
    var watched = this._watched;
    var self = this;

    bundle.modules.forEach(function(m) {
      var file = m.id;
      // skip fake modules which usually do not have a qualified path
      if (!isAbsolute$1(file)) { return }
      if (!watched[file]) {
        watcher.watch(file, {
          change: _onChange,
          unlink: _invalidate
        });
        watched[file] = true;
      }
    });

    function _onChange() {
      _invalidate();
      bundler._schedule(self);
    }

    function _invalidate() {
      self.invalidate();
      self.outputs.forEach(function(file) {
        bundler._invalidate(file);
      });
    }
  };

  RollupAction.prototype._getOutputs = function _getOutputs () {
    return this._getBundles().concat(this._getSourceMaps())
  };

  RollupAction.prototype._getBundles = function _getBundles () {
    var rootDir = this.rootDir;
    var targets = this.targets;
    return targets.map(function(target) {
      return isAbsolute$1(target.dest) ? target.dest : path.join(rootDir, target.dest)
    })
  };

  RollupAction.prototype._getSourceMaps = function _getSourceMaps () {
    var rootDir = this.rootDir;
    var targets = this.targets;
    return targets.map(function(target) {
      if (target.sourceMap === false) { return null }
      var dest = target.dest + ".map";
      return isAbsolute$1(dest) ? dest : path.join(rootDir, dest)
    }).filter(Boolean)
  };

  Object.defineProperties( RollupAction.prototype, prototypeAccessors$1 );

  return RollupAction;
}(Action));

var BrowserifyCommand = function BrowserifyCommand(src, opts) {
  if ( opts === void 0 ) opts = {};

  this.src = src;
  if (!this.src) { throw new Error("'src' is mandatory") }
  this.dest = opts.dest;
  if (!this.dest) { throw new Error("'dest' is mandatory") }

  var options = Object.assign({}, opts);
  var bOpts = Object.assign({}, opts.browserify);
  options.browserify = bOpts;

  // interpret options and transfer to browserify options
  if (opts.server) {
    // settings for a bundle that will be executed in nodejs
    // i.e., no replacement of nodejs built-ins necessary
    bOpts.insertGlobalVars = Object.assign({
      'process': undefined,
      'global': undefined,
      '__dirname': "",
      '__filename': "",
    }, bOpts.insertGlobalVars);
    bOpts.browserField = false;
    bOpts.builtins = false;
    bOpts.commondir = false;
    bOpts.fullPaths = false;
  }

  // for convenience as this is often necessary for web-bundles
  if (opts.moduleName) {
    bOpts.standalone = opts.moduleName;
  }
  if (opts.hasOwnProperty('sourceMaps')) {
    bOpts.debug = opts.sourceMaps;
  }

  this.options = options;
};

var prototypeAccessors$9 = { id: {},name: {} };

prototypeAccessors$9.id.get = function () {
  return ['BrowserifyCommand', this.src, this.dest ].join('')
};

prototypeAccessors$9.name.get = function () {
  return 'browserify'
};

BrowserifyCommand.prototype.execute = function execute (bundler) {
  var src = this.src;
  if (!isAbsolute$1(src)) { src = path.join(bundler.rootDir, src); }
  var action = new BrowserifyAction(bundler, src, this.dest, this.options);
  bundler._registerAction(action);
  return action.execute(bundler)
};

Object.defineProperties( BrowserifyCommand.prototype, prototypeAccessors$9 );

var BrowserifyAction = (function (Action$$1) {
  function BrowserifyAction(bundler, src, dest, options) {
    if ( options === void 0 ) options = {};

    Action$$1.call(this);

    this.src = src;
    this.dest = dest;
    this.options = options;
    this.rootDir = bundler.rootDir;
  }

  if ( Action$$1 ) BrowserifyAction.__proto__ = Action$$1;
  BrowserifyAction.prototype = Object.create( Action$$1 && Action$$1.prototype );
  BrowserifyAction.prototype.constructor = BrowserifyAction;

  var prototypeAccessors$1 = { id: {} };

  prototypeAccessors$1.id.get = function () {
    return ['Browserify:', this.src, '->', this.dest].join(' ')
  };

  BrowserifyAction.prototype.execute = function execute (bundler) {
    var this$1 = this;

    bundler._info(this.id);
    var options = this.options;
    var t0 = Date.now();
    return new Promise(function (resolve, reject) {
      // browserify can not be bundled due to dynamic requires
      var browserify = require('browserify');

      // TODO: maybe we need to clone these
      var bOpts = Object.assign({}, options.browserify);
      var b = browserify(this$1.src, bOpts);
      if (options.external) {
        options.external.forEach(function (name) {
          // console.log('### external: ', name)
          b.external(name);
        });
      }
      if (options.ignore) {
        options.ignore.forEach(function (name) {
          // console.log('### ignore: ', name)
          b.ignore(name);
        });
      }
      b.bundle(function (err, code) {
        if(err) {
          return reject(err)
        }
        // TODO: deal with sourceMaps
        if (this$1.options.exports) {
          var exports = this$1.options.exports;
          code = String(code);

          var lines = code.split(/\r?\n/g);
          // Handling the last line which is either empty or
          var lastLine = lines.pop();
          if (/^\s*$/.exec(lastLine)) {
            // nothing
          } else if(/^\/\/#/.exec(lastLine)) {
            // TODO: do something with the source map
          } else {
            lines.push(lastLine);
          }
          lastLine = lines.pop();
          // HACK: extracting the entry id by extracting a valid expression from the last generated line of code
          // evaluating it in a Function
          // Example: },{}]},{},[1])
          var f = new Function('return [{ "foo": [{'+lastLine.slice(0, -2)+']');
          // console.log('#### ', f.toString())
          var iifeArgs = f();
          var entry = iifeArgs[2][0];
          lines.push([lastLine.slice(0,-1),'(',entry,')'].join(''));
          // generate es6 exports
          code = ['let _exports = '+lines.join('\n')];
          exports.forEach(function (name) {
            if (name === 'default') {
              code.push('export default _exports');
            } else {
              code.push('let '+name+' = _exports.'+name);
              code.push('export {'+name+'}');
            }
          });
          code = code.join('\n');
        }
        var absDest = isAbsolute$1(this$1.dest) ? this$1.dest : path.join(this$1.rootDir, this$1.dest);
        writeSync(absDest, code);
        bundler._info(___dist_vendor_js.colors.green('..finished in %s ms'), Date.now()-t0);
        resolve();
      });
    })
  };

  BrowserifyAction.prototype.invalidate = function invalidate () {
    Action$$1.removeOutputs(this);
  };

  Object.defineProperties( BrowserifyAction.prototype, prototypeAccessors$1 );

  return BrowserifyAction;
}(Action));

var PostCSSCommand = function PostCSSCommand(src, dest, opts) {
  this.src = src;
  this.dest = dest;
  this.opts = opts || {};
};

var prototypeAccessors$10 = { id: {},name: {} };

prototypeAccessors$10.id.get = function () {
  return ['PostCSSCommand', this.src, this.dest]
};

prototypeAccessors$10.name.get = function () {
  return 'css'
};

PostCSSCommand.prototype.execute = function execute (bundler) {
  var src = this.src;
  var dest = this.dest;
  if (!isAbsolute$1(src)) { src = path.join(bundler.rootDir, src); }
  if (!isAbsolute$1(dest)) { dest = path.join(bundler.rootDir, dest); }
  var action = new PostCSSAction(bundler, src, dest, this.opts);
  bundler._registerAction(action);
  return action.execute(bundler)
};

Object.defineProperties( PostCSSCommand.prototype, prototypeAccessors$10 );

var PostCSSAction = (function (Action$$1) {
  function PostCSSAction(bundler, src, dest, opts) {
    Action$$1.call(this);
    this.bundler = bundler;
    this.src = src;
    this.dest = dest;
    this.opts = opts;
    this._watched = {};
  }

  if ( Action$$1 ) PostCSSAction.__proto__ = Action$$1;
  PostCSSAction.prototype = Object.create( Action$$1 && Action$$1.prototype );
  PostCSSAction.prototype.constructor = PostCSSAction;

  var prototypeAccessors$1 = { id: {} };

  prototypeAccessors$1.id.get = function () {
    return ['PostCSS:', this.src, '->', this.dest].join('')
  };

  PostCSSAction.prototype.execute = function execute (bundler) {
    var this$1 = this;

    bundler._info(this.id);
    var t0 = Date.now();
    var src = this.src;
    var dest = this.dest;
    // const opts = this.opts
    var plugins = this.opts.plugins ? this.opts.plugins.slice() : [];
    // allow to deactivate the use of predefined plugins
    // so that can use other import plugins such
    // as postcss-sassy-import, for instance
    if (this.opts.builtins !== false) {
      if (this.opts.import !== false) {
        // make sure that postcss-import is the first one
        plugins.unshift(___dist_vendor_js.postcssImport({
          onImport: function (files) {
            this$1._onImport(files);
          }
        }));
      }
      if (this.opts.variables) {
        plugins.push(___dist_vendor_js.postcssVariables({
          throwError: true
        }));
      }
      plugins.push(___dist_vendor_js.postcssReporter());
    }
    var postcssOpts = {
      from: src,
      to: dest,
      map: { inline: false }
    };
    if (this.opts.parser) {
      postcssOpts.parser = this.opts.parser;
    }
    var css = fs.readFileSync(this.src, 'utf8');
    return ___dist_vendor_js.postcss(plugins)
    .process(css, postcssOpts)
    .then(function (result) {
      writeSync(dest+'.map', JSON.stringify(result.map));
      writeSync(dest, result.css);
      bundler._info(___dist_vendor_js.colors.green('..finished in %s ms.'), Date.now()-t0);
    })
  };

  PostCSSAction.prototype.invalidate = function invalidate () {
    Action$$1.removeOutputs(this);
  };

  PostCSSAction.prototype._onImport = function _onImport (files) {
    var bundler = this.bundler;
    var watcher = bundler.watcher;
    var watched = this._watched;
    var self = this;

    files.forEach(function(file) {
      // skip fake modules which usually do not have a qualified path
      if (!isAbsolute$1(file)) { return }
      if (!watched[file]) {
        watcher.watch(file, {
          change: _onChange,
          unlink: _invalidate
        });
        watched[file] = true;
      }
    });

    function _onChange() {
      _invalidate();
      bundler._schedule(self);
    }

    function _invalidate() {
      self.invalidate();
      bundler._invalidate(self.dest);
    }
  };

  Object.defineProperties( PostCSSAction.prototype, prototypeAccessors$1 );

  return PostCSSAction;
}(Action));

var Bundler = (function (EventEmitter$$1) {
  function Bundler(opts) {
    EventEmitter$$1.call(this);

    this.opts = opts || {};
    this.rootDir = process.cwd();

    this.watcher = new Watcher();
    this.server = new ___dist_vendor_js.express();
    this._serverPort = 4000;

    // an action is registerd via a file id
    // whenever the file changes the action gets scheduled
    this._actions = {};
    this._actionsByInput = {};
    this._generatedFiles = {};

    // a task is just a function executing commands
    // or registering actions
    this._tasks = {};

    // a queue for sequencing actions
    this._scheduledActions = [];
    this._scheduledActionIds = {};

    // flags
    this._started = false;
    this._running = false;
    this._firstRun = true;

    process.on('SIGINT', function() {
      process.exit(0);
    });
  }

  if ( EventEmitter$$1 ) Bundler.__proto__ = EventEmitter$$1;
  Bundler.prototype = Object.create( EventEmitter$$1 && EventEmitter$$1.prototype );
  Bundler.prototype.constructor = Bundler;

  Bundler.prototype.make = function make (other) {
    var tasks = [], len = arguments.length - 1;
    while ( len-- > 0 ) tasks[ len ] = arguments[ len + 1 ];

    return this._scheduleCommand(new MakeCommand(other, tasks))
  };

  Bundler.prototype.copy = function copy (src, dest, opts) {
    return this._scheduleCommand(new CopyCommand(src, dest, opts))
  };

  Bundler.prototype.cp = function cp () {
    var args = [], len = arguments.length;
    while ( len-- ) args[ len ] = arguments[ len ];

    return (ref = this).copy.apply(ref, args)
    var ref;
  };

  Bundler.prototype.custom = function custom (description, params) {
    return this._scheduleCommand(new CustomCommand(description, params))
  };

  Bundler.prototype.exec = function exec (cmd, options) {
    return this._scheduleCommand(new ExecCommand(cmd, options))
  };

  Bundler.prototype.forEach = function forEach$$1 (pattern, handler) {
    return this._scheduleCommand(new ForEachCommand(pattern, handler))
  };

  Bundler.prototype.js = function js (src, opts) {
    return this._scheduleCommand(new RollupCommand(src, opts, this))
  };

  Bundler.prototype.browserify = function browserify (src, opts) {
    return this._scheduleCommand(new BrowserifyCommand(src, opts))
  };

  Bundler.prototype.css = function css (src, dest, opts) {
    return this._scheduleCommand(new PostCSSCommand(src, dest, opts))
  };

  Bundler.prototype.rm = function rm (rmPath) {
    return this._scheduleCommand(new RemoveCommand(rmPath))
  };

  Bundler.prototype.minify = function minify (src, opts) {
    return this._scheduleCommand(new MinifyCommand(src, opts))
  };

  Bundler.prototype.task = function task (name, deps, fn) {
    log$1('Registering task', name);
    if (___dist_vendor_js.isFunction(deps)) {
      fn = deps;
      deps = [];
    }
    var task = new Task(name, fn, deps);
    this._tasks[name] = task;
    return task
  };

  Bundler.prototype.setServerPort = function setServerPort (port) {
    this._serverPort = port;
  };

  Bundler.prototype.serve = function serve (params) {
    var server = this.server;
    var rootDir = this.rootDir;
    if (params.static) {
      var route = params.route;
      var folder = params.folder;
      if (!route || !folder) {
        throw new Error("Parameters 'route' and 'folder' required.")
      }
      folder = path.join(rootDir, folder);
      log$1('Adding static route %s -> %s', route, folder);
      server.use(route, ___dist_vendor_js.express.static(folder));
    }
  };

  Bundler.prototype.writeSync = function writeSync$$1 (dest, buf) {
    console.warn('DEPRECATED: use b.writeFileSync()');
    this.writeFileSync(dest, buf);
  };

  Bundler.prototype.writeFileSync = function writeFileSync$$1 (dest, buf) {
    writeSync(dest, buf);
  };

  Bundler.prototype.isDirectory = function isDirectory$$1 (p) {
    return isDirectory(p)
  };

  Bundler.prototype._scheduleCommand = function _scheduleCommand (cmd) {
    var entry = this._schedule(cmd);
    return entry.promise
  };

  Bundler.prototype._info = function _info () {
    var args = [], len = arguments.length;
    while ( len-- ) args[ len ] = arguments[ len ];

    if (!this.silent) {
      console.info.apply(console, args);
    }
  };

  Bundler.prototype._hasScheduledActions = function _hasScheduledActions () {
    return this._scheduledActions.length > 0
  };

  Bundler.prototype._registerAction = function _registerAction (action) {
    var this$1 = this;

    var id = action.id;
    // skip if the same action is already registered
    if (this._actions[id]) { return }
    this._actions[id] = action;
    action.inputs.forEach(function (input) {
      this$1._registerActionInput(action, input);
    });
    action.outputs.forEach(function (output) {
      this$1._registerActionOutput(action, output);
    });
  };

  Bundler.prototype._registerActionInput = function _registerActionInput (action, input) {
    var watcher = this.watcher;
    // if no other action has been registered as generator
    // then we add a file watcher
    if (!this._generatedFiles[input]) {
      log$1('Watching ', input);
      watcher.watch(input, {
        change: this._onChange.bind(this),
        unlink: this._onUnlink.bind(this)
      });
    }
    if (!this._actionsByInput[input]) {
      this._actionsByInput[input] = [];
    }
    this._actionsByInput[input].push(action);
    this._actionsByInput[input] = ___dist_vendor_js.uniq(this._actionsByInput[input]);
  };

  Bundler.prototype._registerActionOutput = function _registerActionOutput (action, output) {
    this._generatedFiles[output] = true;
  };

  Bundler.prototype._onChange = function _onChange (file) {
    this._invalidate(file);
    var actions = this._actionsByInput[file] || [];
    actions.forEach(function(action) {
      log$1('Rescheduling action', action.id);
      this._schedule(action);
    }.bind(this));
  };

  Bundler.prototype._onUnlink = function _onUnlink (file) {
    // TODO: maybe we should unregister the action
    // when the file is deleted
    this._invalidate(file);
  };

  Bundler.prototype._invalidate = function _invalidate (file) {
    log$1('Invalidating', file);
    var actions = this._getAllActions(file);
    actions.forEach(function(action) {
      action.invalidate();
    });
  };

  // find all actions by investigating action input-output dependencies
  Bundler.prototype._getAllActions = function _getAllActions (file) {
    var this$1 = this;

    var visited = {};
    var queue = [file];
    var actions = [];
    while(queue.length > 0) {
      var next = queue.shift();
      var nextActions = this$1._actionsByInput[next];
      for (var id in nextActions) {
        if (!nextActions.hasOwnProperty(id)) { continue }
        if (visited[id]) { continue }
        var action = nextActions[id];
        visited[id] = true;
        actions.push(action);
        queue = queue.concat(action.outputs);
      }
    }
    return actions
  };

  Bundler.prototype._startWatching = function _startWatching () {
    this.watcher.start();
  };

  Bundler.prototype._startServing = function _startServing () {
    this._info('Starting server on port %s...', this._serverPort);
    this.server.listen(this._serverPort);
  };

  Bundler.prototype._schedule = function _schedule (action) {
    var id = action.id;
    var schedule = this._scheduledActions;
    var scheduledIds = this._scheduledActionIds;
    // action is already scheduled
    if (scheduledIds[id]) {
      var idx = -1;
      for (var i = 0; i < schedule.length; i++) {
        if (schedule[i].action.id === id) {
          idx = i;
          break
        }
      }
      if (idx < 0) {
        console.error('Internal Error: tried to reschedule an action with id "%s"',id);
        process.exit(1);
      }
      schedule.splice(idx, 1);
    }

    log$1('Scheduling action: %s', id);
    var entry = { action: action };
    // return a promise so that you
    // can do things such as b.js().then(...)
    entry.promise = new Promise(function (resolve, reject) {
      entry.resolve = resolve;
      entry.reject = reject;
    });
    if (!this._started) {
      schedule.push(entry);
      scheduledIds[id] = true;
    } else {
      process.nextTick(function() {
        schedule.push(entry);
        scheduledIds[id] = true;
        if (!this._running) {
          this._running = true;
          this._next();
        }
      }.bind(this));
    }
    return entry
  };

  Bundler.prototype._start = function _start () {
    this._started = true;
    this._running = true;
    this._step();
  };

  Bundler.prototype._next = function _next () {
    var self = this;
    var entry = this._scheduledActions.shift();
    var action = entry.action;
    var id = action.id;
    var _step = this._step.bind(this);
    delete this._scheduledActionIds[id];
    try {
      Promise.resolve(action.execute(this))
        .then(_next)
        .catch(_catch);
    } catch (err) {
      _catch(err);
    }

    function _next() {
      var outputs = action.outputs || [];
      outputs.forEach(function(output) {
        var nextActions = self._actionsByInput[output] || [];
        nextActions.forEach(function(action) {
          self._schedule(action);
        });
      });
      entry.resolve();
      process.nextTick(_step);
    }

    function _catch(err) {
      if (err) {
        if (err.stack) {
          console.error(___dist_vendor_js.colors.red('\nError during execution of Command '), ___dist_vendor_js.colors.white(action.name));
          console.error(___dist_vendor_js.colors.red(err.toString()));
          console.error('Stacktrace:');
          console.error(err.stack);
        } else {
          console.error(err.toString());
        }
      }
      if (self._firstRun) {
        process.exit(1);
      } else {
        entry.reject(err);
        _next();
      }
    }
  };

  Bundler.prototype._step = function _step () {
    if (this._scheduledActions.length > 0) {
      this._next();
    } else {
      this._running = false;
      this._firstRun = false;
      this.emit('done');
    }
  };

  Bundler.prototype._runTasks = function _runTasks (names) {
    names.forEach(function(name) {
      this._runTask(name);
    }.bind(this));
  };

  Bundler.prototype._runTask = function _runTask (name, state) {
    state = state || {};
    if (state[name] === 'done') { return }
    var task = this._tasks[name];
    if (!task) {
      console.error("Unknown task: '%s'", name);
      process.exit();
    }
    state[name] = 'visiting';
    if (task.deps && !this.opts.nodeps) {
      task.deps.forEach(function(dep) {
        if (state[dep] === 'visiting') {
          throw new Error('Cyclic dependency detected in task ' + dep)
        } else if (state[dep] === 'done') {
          return
        } else {
          this._runTask(dep, state);
        }
      }.bind(this));
    }
    if (task.fn) { task.fn(); }
    state[name] = 'done';
  };

  return Bundler;
}(events.EventEmitter));

// enabling source maps so that errors in bundler can be traced
require('source-map-support').install();

var argv = ___dist_vendor_js.yargs
  // use this to start watcher
  .boolean('h').alias('h', 'help').default('h', false)
  .boolean('w').alias('w', 'watch').default('w', false)
  .boolean('s').alias('s', 'serve').default('s', false)
  .boolean('t').default('t', false)
  .boolean('n').alias('n', 'nodeps').default('n', false)
  .argv;

var showHelp = argv.h;
var showTasks = argv.t;

var bundler = new Bundler({
  watch: argv.watch,
  serve: argv.serve,
  nodeps: argv.nodeps
});
bundler.yargs = ___dist_vendor_js.yargs;
bundler.argv = argv;
bundler.autorun = true;
var tasks = argv._;

bundler.usage = "\n  node make --help\n    shows this help\n\n  node make -t\n    shows a summary of all available tasks\n\n  node make [-w] [-s] ...<task>\n    runs one or multiple tasks and all their dependencies\n\n  Options:\n    -w:     watch for file changes\n    -s:     start http server\n";
function _start() {
  if (bundler.autorun) {
    if(showHelp) {
      console.info('Usage:');
      console.info(bundler.usage);
      return
    } else if(showTasks) {
      var tasks$1 = bundler._tasks;
      console.info('Available tasks:');
      console.info(Object.keys(tasks$1).map(function (name) {
        var task = tasks$1[name];
        var frags = ["  - ", ___dist_vendor_js.colors.green(name)];
        if (task.description) {
          frags.push(___dist_vendor_js.colors.white(": "));
          frags.push(task.description);
        }
        return frags.join('')
      }).join('\n'));
      return
    }
    if (tasks.length > 0) {
      bundler._runTasks(tasks);
    } else if (bundler._tasks['default']) {
      bundler._runTask('default');
    }
    if (!bundler._hasScheduledActions()) {
      console.error('No action. ');
    }
  }
  bundler._start();
}

process.once('beforeExit', _start);
bundler.once('done', function() {
  if (showHelp || showTasks || !bundler.autorun) { return }
  var watch = bundler.opts.watch;
  var serve = bundler.opts.serve;
  var remote = argv.remote;
  if (serve) {
    bundler._startServing();
  }
  if (watch) {
    // start watching if this has been requested (default is false)
    if (!remote) {
      console.info('Watching for changes... Press CTRL-C to exit.');
    }
    bundler._startWatching();
  }
  if (!remote && !watch && !serve) {
    // TODO: why do exit here?
    // If some child process is still running, it is maybe
    // better to wait?
    // process.exit(0)
  }
});

if (argv.remote) {
  bundler.once('done', function() {
    process.send('done');
  });
}

module.exports = bundler;

//# sourceMappingURL=./bundler.js.map