42Zavattas/generator-bangular

View on GitHub
util.js

Summary

Maintainability
A
3 hrs
Test Coverage
'use strict';

var os = require('os');
var fs = require('fs');
var path = require('path');
var glob = require('glob');
var chalk = require('chalk');
var _ = require('lodash');
var helpers = require('yeoman-generator').test;

function escapeRegExp (str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
}

function isPathAbsolute () {
  var filepath = path.join.apply(path, arguments);
  return path.resolve(filepath) === filepath;
}

function filterFile (template) {
  // Find matches for params
  var filterMatches = template.match(/\(([^)]+)\)/g);
  var filters = [];
  if (filterMatches) {
    filterMatches.forEach(function (filter) {
      filters.push(filter.replace('(', '').replace(')', ''));
      template = template.replace(filter, '');
    });
  }
  return { name: template, filters: filters };
}

function templateIsUsable (self, filteredFile) {
  var filters = self.config.get('filters');
  var enabledFilters = [];
  for (var key in filters) {
    if (filters[key]) {
      enabledFilters.push(key);
    }
  }
  var matchedFilters = _.intersection(filteredFile.filters, enabledFilters);
  // check that all filters on file are matched
  if (filteredFile.filters.length && matchedFilters.length !== filteredFile.filters.length) {
    return false;
  }
  return true;
}

var out = {
  bangLog: function (msg, color) {
    console.log('[' + chalk.blue('bangular') + ']: ' + chalk[color](msg));
  },
  scaffold: function (prompts, cb, opts) {
    if (!prompts) { return cb('No option given.'); }
    helpers.run(path.join(__dirname, './app'))
      .inDir(path.join(os.tmpdir(), './tmp'))
      .withOptions(opts || { skipInstall: true })
      .withPrompts(prompts)
      .on('end', cb);
  },
  fileExists: function (path) {
    if (fs.existsSync(path)) { return true; }
    return false;
  },
  appendTo: function (yeoman, opts) {
    var data = fs.readFileSync(opts.src).toString();

    fs.appendFile(opts.dest, data, function () {
      fs.unlinkSync(opts.src);
    });
  },
  appendOnTop: function (opts, cb) {
    fs.readFile(opts.dest, function (err, data) {
      if (err) { return cb(err, null); }
      fs.writeFile(opts.dest, opts.append + '\n', function (err) {
        if (err) { return cb(err, null); }
        fs.appendFile(opts.dest, data, function (err) {
          if (err) { return cb(err, null); }
          cb(null, true);
        });
      });
    });
  },
  appendNeedleOrOnTop: function (args, cb) {
    fs.readFile(args.file, function (err, data) {
      if (err || !data) { return cb(true); }
      if (data.toString().indexOf(args.needle) !== -1) {
        out.rewriteFile({
          file: args.file,
          needle: args.needle,
          splicable: [
            args.append
          ]
        }, cb);
      } else {
        out.appendOnTop({
          dest: args.file,
          append: args.append
        }, cb);
      }
    });
  },
  rewrite: function (args) {
    // check if splicable is already in the body text
    var re = new RegExp(args.splicable.map(function (line) {
      return '\s*' + escapeRegExp(line);
    }).join('\n'));

    if (re.test(args.haystack)) {
      return args.haystack;
    }

    var lines = args.haystack.split('\n');

    var otherwiseLineIndex = -1;
    lines.forEach(function (line, i) {
      if (line.indexOf(args.needle) !== -1) {
        otherwiseLineIndex = i;
      }
    });

    /* istanbul ignore if */
    if (otherwiseLineIndex === -1) {
      return lines.join('\n');
    }
    // Since we're not using the rewrite function directly but passing with the
    // appendNeedleOrOnTop function, this will never (h)append... Normally...

    var spaces = 0;
    while (lines[otherwiseLineIndex].charAt(spaces) === ' ') {
      spaces += 1;
    }

    var spaceStr = '';
    while ((spaces -= 1) >= 0) {
      spaceStr += ' ';
    }

    lines.splice(otherwiseLineIndex + 1, 0, args.splicable.map(function (line) {
      return spaceStr + line;
    }).join('\n'));

    return lines.join('\n');
  },
  rewriteFile: function (args, cb) {
    args.path = args.path || process.cwd();
    var fullPath = path.join(args.path, args.file);

    args.haystack = fs.readFileSync(fullPath, 'utf8');
    var body = out.rewrite(args);

    fs.writeFile(fullPath, body, function (err) {
      if (cb) { cb(err); }
    });
  },
  processDirectory: function (self, source, destination) {
    var root = isPathAbsolute(source) ? source : path.join(self.sourceRoot(), source);
    var files = glob.sync('**', { dot: true, nodir: true, cwd: root });
    var dest, src;

    files.forEach(function (f) {
      var filteredFile = filterFile(f);
      var name = filteredFile.name;
      var copy = false, stripped;

      src = path.join(root, f);
      dest = path.join(destination, name);

      if (path.basename(dest).indexOf('_') === 0) {
        stripped = path.basename(dest).replace(/^_/, '');
        dest = path.join(path.dirname(dest), stripped);
      }

      if (path.basename(dest).indexOf('#') === 0) {
        stripped = path.basename(dest).replace(/^#/, '');
        dest = path.join(path.dirname(dest), stripped);
        copy = true;
      }

      if (templateIsUsable(self, filteredFile)) {
        if (copy) {
          self.copy(src, dest);
        } else {
          self.template(src, dest);
        }
      }
    });
  }
};

module.exports = out;