codeclimate/codeclimate-fixme

View on GitHub
lib/fix-me.js

Summary

Maintainability
A
1 hr
Test Coverage
var readline = require('readline');
var spawn = require('child_process').spawn;
var fs = require('fs');

var DEFAULT_PATHS = ['./'];
var DEFAULT_STRINGS = ['BUG', 'FIXME', 'HACK', 'TODO', 'XXX'];
var GREP_OPTIONS = [
  '--binary-files=without-match',
  '--extended-regexp',
  '--line-number',
  '--only-matching',
  '--recursive',
  '--with-filename',
  '--word-regexp',
];

function FixMe(writable) {
  this.output = writable || process.stdout;
}

FixMe.prototype.run = function(engineConfig) {
  var paths, strings;

  if (engineConfig) {
    paths = engineConfig.include_paths;
  } else {
    paths = DEFAULT_PATHS;
  }

  if (engineConfig && engineConfig.config && engineConfig.config.strings) {
    strings = engineConfig.config.strings;
  } else {
    strings = DEFAULT_STRINGS;
  }

  this.find(paths, strings);
};

var isItsOwnConfigFile = function(path) {
  return path.indexOf(".codeclimate.yml") !== -1;
};

var isAYamlComment = function(path, lineNumber) {
  var lines = fs.readFileSync(path, "utf8").split("\n");
  var line = lines[lineNumber - 1] || "";
  return line.match(/^\s*#/);
};

FixMe.prototype.find = function(paths, strings, callback) {
  var pattern = `(${strings.join('|')})`;
  var grep = spawn('grep', [...GREP_OPTIONS, pattern, ...paths]);

  readline.createInterface({ input: grep.stdout }).on('line', (line) => {
    var parts = line.split(':');
    var path = parts[0].replace(/^\/code\//, '');
    var lineNumber = parseInt(parts[1], 10);
    var matchedString = parts[2];

    if (!path || !lineNumber || !matchedString) {
      process.stderr.write("Ignoring malformed output: " + line + "\n");
      return;
    }

    if(isItsOwnConfigFile(path) && !isAYamlComment(path, lineNumber)) { return; }

    var issue = {
      'categories': ['Bug Risk'],
      'check_name': matchedString,
      'description': `${matchedString} found`,
      'location': {
        'lines': {
          'begin': lineNumber,
          'end': lineNumber,
        },
        'path': path,
      },
      'type': 'issue',
    };

    this.output.write(JSON.stringify(issue) + '\0');
  });

  if (callback) {
    grep.stdout.on('close', _ => callback());
  }
};

module.exports = FixMe;