Last active
January 29, 2021 03:51
-
-
Save alizbazar/d1b140453f6da35896b66acae0ee8daf to your computer and use it in GitHub Desktop.
Gradually rolling out eslint rules resulting in many errors in a legacy project
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This script is meant to be used with lint-staged receiving changed files as arguments. | |
It checks if file has "rules-disabled-on" header present with date in the past. | |
If yes, it reports files that need to be reformatted. | |
*/ | |
const _ = require('lodash') | |
const fs = require('fs') | |
const moment = require('moment') | |
const errors = [] | |
process.argv.slice(2).forEach(filepath => { | |
const lines = fs.readFileSync(filepath, 'utf8').split('\n') | |
const rulesDisabledPattern = /^\/\* rules-disabled-on ([0-9-]+) \*\/$/ | |
const rulesDisabledLineIndex = _.findIndex(lines, line => rulesDisabledPattern.test(line)) | |
if (rulesDisabledLineIndex === -1) { | |
return | |
} | |
const date = rulesDisabledPattern.exec(lines[rulesDisabledLineIndex])[1] | |
if (moment().format('YYYY-MM-DD') === date) { | |
return | |
} | |
const ruleLinePattern = /^\/\* eslint-disable ([^ ]+) \*\/$/ | |
const rules = lines | |
.slice(0, rulesDisabledLineIndex) | |
.filter(line => line.trim()) | |
.map(line => ruleLinePattern.exec(line)) | |
.map(m => m && m[1]) | |
.filter(_.identity) | |
errors.push({ filepath, rules }) | |
}) | |
const formatError = ({ filepath, rules }) => [`${filepath}:`, ...rules.map(rule => `\t${rule}`)].join('\n') | |
if (errors.length) { | |
const rulesReport = errors.map(formatError).join('\n\n') | |
// eslint-disable-next-line no-console | |
console.error(`Legacy disabled eslint rules found in: | |
${rulesReport} | |
Remove disabled rules and fix the issues before committing! | |
`) | |
process.exit(1) | |
} | |
process.exit() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This script prepends all JS files containing eslint errors with a header like this: | |
*/ | |
/* eslint-disable func-names */ | |
/* eslint-disable no-underscore-dangle */ | |
/* eslint-disable no-fallthrough */ | |
/* rules-disabled-on 2019-11-11 */ | |
/* | |
Run the script from the root of the project directory. | |
Pass eslint errors JSON file as argument. | |
Save errors in JSON by running `eslint --format=json-with-metadata` | |
*/ | |
const { map, filter, orderBy, flow } = require('lodash/fp') | |
const fs = require('fs') | |
const path = require('path') | |
const moment = require('moment') | |
const errorJSONFilePath = process.argv[2] | |
const errors = JSON.parse(fs.readFileSync(path.resolve(__dirname, errorJSONFilePath), 'utf8')).results | |
const getFilesWithErrors = flow( | |
filter((d) => d.errorCount + d.warningCount > 0), | |
map(({ filePath, messages }) => { | |
const rules = messages.reduce((acc, { ruleId }) => { | |
acc.add(ruleId) | |
return acc | |
}, new Set()) | |
return { filePath, rules } | |
}), | |
orderBy([(d) => d.rules.size], ['desc']) | |
) | |
const constructHeaderFactory = (dateToday) => | |
flow( | |
(rules) => rules.map((rule) => `/* eslint-disable ${rule} */`), | |
(lines) => [...lines, `/* rules-disabled-on ${dateToday} */`], | |
(lines) => lines.join('\n') | |
) | |
const constructHeader = constructHeaderFactory(moment().format('YYYY-MM-DD')) | |
const prependFile = (txt, filePath) => { | |
const content = fs.readFileSync(filePath, 'utf8') | |
fs.writeFileSync(filePath, `${txt}${content}`) | |
} | |
console.log('files with errors', getFilesWithErrors(errors)) | |
// eslint-disable-next-line no-restricted-syntax | |
for (const file of getFilesWithErrors(errors)) { | |
const { filePath, rules } = file | |
const header = constructHeader(Array.from(rules)) | |
prependFile(`${header}\n\n`, filePath) | |
// eslint-disable-next-line no-console | |
console.log('wrote', filePath) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const formatAndLint = ['node scripts/check-for-legacy-headers.js', 'prettier --write', 'eslint --max-warnings 0 --fix'] | |
module.exports = { | |
'*.graphql': 'prettier --write', | |
// unfortunately, tsc cannot be run for specific files and still respect tsconfig :'( | |
'*.{ts,tsx}': [...formatAndLint, () => 'yarn tsc -p ./tsconfig.json --noEmit'], | |
'*.{js,jsx}': [...formatAndLint], | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment