Last active
January 24, 2022 10:59
-
-
Save milichev/db3ea9fcb2fb086db57c3f2c4f770db2 to your computer and use it in GitHub Desktop.
Revisions
-
milichev revised this gist
Jan 24, 2022 . 1 changed file with 61 additions and 39 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -1,24 +1,42 @@ /** * Accepts eslint `stdout` and processes all error messages related to React Hooks, if any. * * Essentially, the "fix" is only about adding a respective `eslint-disable-line` comments to mute the error unless it is addressed appropriately. * * Requires the following modules available: * - lodash * * Usage: * * Run in console: * eslint client/components/ | node mute-eslint-hooks.js * * If something went wrong and the script should be fixed to proceed: * 1. Fix the script to edit the source file correctly, * 2. Run in console specifying the file to rollback and process again: * export FN=client/components/items/bulk-actions.js && git checkout -- $FN && eslint $FN | node mute-eslint-hooks.js */ /* eslint-disable @typescript-eslint/no-var-requires,no-console */ const readline = require("readline"); const fs = require("fs"); const $path = require("path"); const _ = require("lodash"); const { EOL } = require("os"); const cwd = process.cwd(); collectErrors() .then((errorsByFile) => Promise.all(errorsByFile.map(processFile))) .then((results) => results .filter(Boolean) .map(({ path, count, fixedCount }) => `\n${$path.relative(cwd, path)}\n fixed: ${fixedCount} / ${count}`) .join(EOL) ) .then((msg) => msg && console.log(msg)) .catch((err) => console.error(err)); function collectErrors() { return new Promise((resolve, reject) => { const result = []; const pathRe = /^(?:\/\w[-.\w]+)+\.(?:js|jsx|ts|tsx)$/; @@ -30,7 +48,7 @@ function collectErrors () { input: process.stdin, output: process.stdout, }) .on("line", function (line) { const pathMatch = line.match(pathRe); if (pathMatch) { current = { @@ -46,7 +64,7 @@ function collectErrors () { const type = errorMatch[3]; const name = errorMatch[5]; const message = errorMatch[4].trim(); const byLine = current.errors[ln] || (current.errors[ln] = []); byLine.push({ ln, ch, @@ -57,14 +75,14 @@ function collectErrors () { } } }) .on("close", function () { this.close(); resolve(result); }); }); } async function processFile({ path, errors }) { const lines = await readFileLines(path); let fixedCount = 0; @@ -73,23 +91,19 @@ async function processFile ({ path, errors }) { Object.keys(errors).forEach((key) => { const ln = Number(key); count += errors[ln].length; const toSuppress = _(errors[ln]).filter(({ name }) => name === "react-hooks/exhaustive-deps" || name === "react-hooks/rules-of-hooks"); if (!toSuppress.size()) { return; } const line = lines[ln - 1]; const nameList = toSuppress.map("name").uniq().value().join(","); lines[ln - 1] = fixBareArrayOpening({ line, nameList }) || fixArrayAfterBrace({ line, nameList }) || fixRuleStatement({ line, nameList }) || fixCallbackDef({ line, nameList }) || `${lines[ln - 1]} // eslint-disable-line ${nameList}`; fixedCount += toSuppress.size(); @@ -100,34 +114,42 @@ async function processFile ({ path, errors }) { return { path, fixedCount, count }; } function fixBareArrayOpening({ line, nameList }) { const match = line.match(/^(\s+)\[/); return match && `${match[1]}// eslint-disable-next-line ${nameList}${EOL}${line}`; } function fixArrayAfterBrace({ line, nameList }) { const match = line.match(/^(\s*)},\s*\[/); return match && `${match[1]}${match[1]}// eslint-disable-next-line ${nameList}${EOL}${line}`; } function fixRuleStatement({ line, nameList }) { const match = line.match(/^(\s*).*use[A-Z][\w]+(?:<[^>]+>)?\(/); return match && `${match[1]}// eslint-disable-next-line ${nameList}${EOL}${line}`; } function fixCallbackDef({ line, nameList }) { const match = line.match(/^(\s+)(?:(?:const|let|var)\s+)?\w+\s*=\s*(?:(?:function\s*\([^)]*\)\s*)|(?:\([^)]*\)\s*=>))/); return match && `${match[1]}// eslint-disable-next-line ${nameList}${EOL}${line}`; } async function readFileLines(path) { return new Promise((resolve) => { const lines = []; const stream = fs.createReadStream(path, { encoding: "utf8" }); readline .createInterface({ input: stream, }) .on("line", function (line) { lines.push(line); }) .on("close", function () { stream.close(); this.close(); lines.push(""); resolve(lines); }); }); } -
milichev revised this gist
Oct 5, 2021 . 1 changed file with 46 additions and 47 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -20,50 +20,47 @@ collectErrors() function collectErrors () { return new Promise((resolve, reject) => { const result = []; const pathRe = /^(?:\/\w[-.\w]+)+\.(?:js|jsx|ts|tsx)$/; const errorRe = /^\s+(\d+):(\d+)\s+(warning|error)\s+(.+)\s+([-@\/\w]+)$/; let current; readline .createInterface({ input: process.stdin, output: process.stdout, }) .on('line', function (line) { const pathMatch = line.match(pathRe); if (pathMatch) { current = { path: pathMatch[0], errors: {}, }; result.push(current); } else { const errorMatch = line.match(errorRe); if (errorMatch) { const ln = Number(errorMatch[1]); const ch = Number(errorMatch[2]); const type = errorMatch[3]; const name = errorMatch[5]; const message = errorMatch[4].trim(); const byLine = (current.errors[ln] || (current.errors[ln] = [])); byLine.push({ ln, ch, type, message, name, }); } } }) .on('close', function () { this.close(); resolve(result); }); }); } @@ -89,11 +86,10 @@ async function processFile ({ path, errors }) { .value() .join(','); lines[ln - 1] = fixBareArrayOpening({ line, nameList }) || fixArrayAfterBrace({ line, nameList }) || fixRuleStatement({ line, nameList }) || `${lines[ln - 1]} // eslint-disable-line ${nameList}`; fixedCount += toSuppress.size(); @@ -106,13 +102,16 @@ async function processFile ({ path, errors }) { function fixBareArrayOpening ({ line, nameList }) { const match = line.match(/^(\s+)\[/); return match && `${match[1]}// eslint-disable-next-line ${nameList}${EOL}${line}`; } function fixArrayAfterBrace ({ line, nameList }) { const match = line.match(/^(\s*)\},\s*\[/); return match && `${match[1]}${match[1]}// eslint-disable-next-line ${nameList}${EOL}${line}`; } function fixRuleStatement ({ line, nameList }) { const match = line.match(/^(\s*).*use[A-Z][\w]+(?:<[^>]+>)\(/); return match && `${match[1]}// eslint-disable-next-line ${nameList}${EOL}${line}`; } -
milichev created this gist
Oct 4, 2021 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,134 @@ /* eslint-disable @typescript-eslint/no-var-requires,no-console */ const readline = require('readline'); const fs = require('fs'); const $path = require('path'); const _ = require('lodash'); const { EOL } = require('os'); const cwd = process.cwd(); collectErrors() .then(errorsByFile => Promise.all(errorsByFile.map(processFile))) .then((results) => results .filter(Boolean) .map(({ path, count, fixedCount }) => `\n${$path.relative(cwd, path)}\n fixed: ${fixedCount} / ${count}`) .join(EOL), ) .then(msg => msg && console.log(msg)) .catch(err => console.error(err)); function collectErrors () { return new Promise((resolve, reject) => { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }) .on('line', onLine) .on('close', onClose); const result = []; const pathRe = /^(?:\/\w[-.\w]+)+\.(?:js|jsx|ts|tsx)$/; const errorRe = /^\s+(\d+):(\d+)\s+(warning|error)\s+(.+)\s+([-@\/\w]+)$/; let current; function onLine (line) { const pathMatch = line.match(pathRe); if (pathMatch) { current = { path: pathMatch[0], errors: {}, }; result.push(current); } else { const errorMatch = line.match(errorRe); if (errorMatch) { const ln = Number(errorMatch[1]); const ch = Number(errorMatch[2]); const type = errorMatch[3]; const name = errorMatch[5]; const message = errorMatch[4].trim(); const byLine = (current.errors[ln] || (current.errors[ln] = [])); byLine.push({ ln, ch, type, message, name, }); } } } function onClose () { rl.close(); resolve(result); } }); } async function processFile ({ path, errors }) { const lines = await readFileLines(path); let fixedCount = 0; let count = 0; Object.keys(errors).forEach((key) => { const ln = Number(key); count += errors[ln].length; const toSuppress = _(errors[ln]) .filter(({ name }) => name === 'react-hooks/exhaustive-deps' || name === 'react-hooks/rules-of-hooks'); if (!toSuppress.size()) { return; } const line = lines[ln - 1]; const nameList = toSuppress .map('name') .uniq() .value() .join(','); lines[ln - 1] = fixBareArrayOpening({ line, nameList }) || fixRuleStatement({ line, nameList, }) || `${lines[ln - 1]} // eslint-disable-line ${nameList}`; fixedCount += toSuppress.size(); }); await fs.promises.writeFile(path, lines.join(EOL), { encoding: "utf8" }); return { path, fixedCount, count }; } function fixBareArrayOpening ({ line, nameList }) { const match = line.match(/^(\s+)\[/); if (match) { return `${match[1]}// eslint-disable-next-line ${nameList}${EOL}${line}`; } } function fixRuleStatement ({ line, nameList }) { const match = line.match(/^(\s*).*use[A-Z][\w]+\(/); return match && `${match[1]}// eslint-disable-next-line ${nameList}${EOL}${line}`; } async function readFileLines (path) { return new Promise((resolve) => { const lines = []; const stream = fs.createReadStream(path, { encoding: 'utf8' }); readline.createInterface({ input: stream, }).on('line', function (line) { lines.push(line); }).on('close', function () { stream.close(); this.close(); lines.push(''); resolve(lines); }); }); }