|
| 1 | +#!/usr/bin/env node |
| 2 | +import {execFile} from 'child_process' |
| 3 | +import {readFileSync, writeFileSync} from 'fs' |
| 4 | + |
| 5 | +const files = process.argv.slice(2) |
| 6 | +if (files.length === 0) { |
| 7 | + files.push('app/assets/stylesheets') |
| 8 | +} |
| 9 | + |
| 10 | +// we use an empty "marker" to delineate removed lines |
| 11 | +const REMOVED = `===REMOVED@${Date.now()}===` |
| 12 | + |
| 13 | +execFile('stylelint', ['--rd', '--quiet', '--formatter', 'json', process.argv[2]], (error, stdout) => { |
| 14 | + |
| 15 | + // Filter to only needless diables comments |
| 16 | + const results = JSON.parse(stdout) |
| 17 | + .filter(result => result.warnings.length > 0) |
| 18 | + .map(({source, warnings}) => { |
| 19 | + return { |
| 20 | + source, |
| 21 | + warnings: warnings.filter(warning => warning.rule === '--report-needless-disables') |
| 22 | + } |
| 23 | + }) |
| 24 | + |
| 25 | + for (const {source, warnings} of results) { |
| 26 | + console.log(`--- ${source}\n+++ ${source}`) |
| 27 | + const lines = readFileSync(source, 'utf8').split(/\n/) |
| 28 | + for (const {text, line: lineNum} of warnings) { |
| 29 | + const ruleName = text.match(/^Needless disable for "(.+)"$/)[1] |
| 30 | + const line = lines[lineNum - 1] |
| 31 | + let disableComment = parseDisableComment(line) |
| 32 | + |
| 33 | + if (disableComment) { |
| 34 | + const rules = new Set(disableComment.rules) |
| 35 | + rules.delete(ruleName) |
| 36 | + let replacementLine = line |
| 37 | + if (rules.size === 0) { |
| 38 | + console.log(`@@ ${lineNum},${lineNum - 1} @@`) |
| 39 | + replacementLine = line.replace(`// ${disableComment.content}`, REMOVED) |
| 40 | + } else { |
| 41 | + console.log(`@@ ${lineNum},${lineNum} @@`) |
| 42 | + replacementLine = line.replace(disableComment.content, `${disableComment.type} ${Array.from(rules).join(', ')}`) |
| 43 | + } |
| 44 | + lines[lineNum - 1] = replacementLine |
| 45 | + |
| 46 | + if (lines[lineNum - 2]) { |
| 47 | + console.log(`${lines[lineNum - 2]}`) |
| 48 | + } |
| 49 | + console.log(`- ${line}`) |
| 50 | + if (!replacementLine.includes(REMOVED)) { |
| 51 | + console.log(`+ ${replacementLine}`) |
| 52 | + } |
| 53 | + if (lines[lineNum]) { |
| 54 | + console.log(`${lines[lineNum]}`) |
| 55 | + } |
| 56 | + } |
| 57 | + } |
| 58 | + console.log('') |
| 59 | + const output = lines.map(line => { |
| 60 | + if (line.trim() === REMOVED) { |
| 61 | + return null |
| 62 | + } else if (line.includes(REMOVED)) { |
| 63 | + line = line.replace(REMOVED, '').trimEnd() |
| 64 | + } |
| 65 | + |
| 66 | + return line |
| 67 | + }).filter(line => line !== null).join('\n') |
| 68 | + |
| 69 | + writeFileSync(source, output, 'utf8') |
| 70 | + } |
| 71 | +}) |
| 72 | + |
| 73 | +function parseDisableComment(str) { |
| 74 | + const match = str.match(/(stylelint-disable((-next)?-line)?)\s+(.+)$/) |
| 75 | + return match |
| 76 | + ? { |
| 77 | + content: match[0], |
| 78 | + type: match[1], |
| 79 | + rules: match[4].split(/,\s+/) |
| 80 | + } |
| 81 | + : false |
| 82 | +} |
0 commit comments