Skip to content

Instantly share code, notes, and snippets.

@pauljz
Last active March 11, 2016 18:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pauljz/a2a45964f1494723a966 to your computer and use it in GitHub Desktop.
Save pauljz/a2a45964f1494723a966 to your computer and use it in GitHub Desktop.
#!/usr/bin/env node_modules/.bin/babel-node
/**
* This script is used to keep eslint passing as we upgrade our coding style.
*
* It will find all broken eslint rules in legacy code and automatically add eslint ignores for
* any rules the file breaks. It will also clean up rules that are no longer in violation.
*
* This approach lets us make sure we're writing new code strictly without needing to constantly
* rewrite our old code.
*/
const fs = require('fs');
const childProcess = require('child_process');
const util = require('util');
const ESLINT_CMD = 'node node_modules/eslint/bin/eslint.js';
const PATH = 'src/javascript';
const EXEC_OPTS = {
maxBuffer: 20 * 1024 * 1024,
encoding: 'utf-8'
};
function walk(dir) {
let results = [];
fs.readdirSync(dir).forEach(file => {
const path = `${dir}/${file}`;
const stat = fs.statSync(path);
if (stat && stat.isDirectory()) {
results = results.concat(walk(path));
} else {
results.push(path);
}
});
return results;
}
function stripIgnoreRules() {
const allFiles = walk(PATH);
const jsFiles = allFiles.filter(x => x.match(/\.jsx?$/));
jsFiles.forEach(f => {
const body = fs.readFileSync(f, { encoding: 'utf-8' });
const strippedBody = body.replace(/^\/\* eslint [\s\S]*?\*\/\s+/, '');
if (body !== strippedBody) {
fs.writeFileSync(f, strippedBody);
}
});
}
function addIgnoreRules(f) {
util.log(f.filePath);
const ruleIds = new Set(f.messages.map(m => m.ruleId));
const rules = [...ruleIds].map(x => `${x}:0`);
let comment = '';
let ruleLine = '/* eslint ';
for (let i = 0; i < rules.length; i++) {
const suffix = (i < rules.length - 1) ? ', ' : ' */';
const rule = rules[i] + suffix;
if (ruleLine.length + rule.length <= 100) {
ruleLine += rule;
} else {
comment += `${ruleLine.trimRight()}\n`;
ruleLine = ` ${rule}`;
}
}
comment += ruleLine;
const origBody = fs.readFileSync(f.filePath, { encoding: 'utf-8' });
const newBody = `${comment}\n${origBody}`;
fs.writeFileSync(f.filePath, newBody);
}
function lint() {
const cmd = `${ESLINT_CMD} -c .eslintrc.js --ext .js --ext .jsx -f json ${PATH}`;
childProcess.execSync(cmd, EXEC_OPTS);
}
function applyFixes() {
try {
const cmd = `${ESLINT_CMD} -c .eslintrc.js --ext .js --ext .jsx --fix ${PATH}`;
childProcess.execSync(cmd, EXEC_OPTS);
} catch (e) {
//
}
}
function main() {
util.log('Stripping existing ignore rules');
stripIgnoreRules();
for (let pass = 1; pass <= 2; pass++) {
util.log(`Applying automatic fixes, pass ${pass}`);
applyFixes();
}
try {
util.log('Linting');
lint();
util.log('No errors.');
} catch (e) {
util.log('Parsing eslint output');
const lintOutput = JSON.parse(e.stdout);
util.log('Commenting files');
lintOutput.filter(f => f.messages.length > 0).forEach(addIgnoreRules);
util.log('Commenting complete');
}
util.log('Confirming');
try {
lint();
util.log('Errors resolved');
} catch (e) {
util.log('Errors remain');
}
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment