UNPKG

eslint-config-prettier

Version:

Turns off all rules that are unnecessary or might conflict with Prettier.

199 lines (175 loc) 5.33 kB
#!/usr/bin/env node "use strict"; const getStdin = require("get-stdin"); const pkg = require("../package.json"); const validators = require("./validators"); const SPECIAL_RULES_URL = "https://github.com/prettier/eslint-config-prettier#special-rules"; if (module === require.main) { if (process.argv.length > 2 || process.stdin.isTTY) { console.error( [ "This tool checks whether an ESLint configuration contains rules that are", "unnecessary or conflict with Prettier. It’s supposed to be run like this:", "", " eslint --print-config .eslintrc.js | eslint-config-prettier-check", "", "(Swap out .eslintrc.js with the path to your config if needed.)", "", "Exit codes:", "", "0: No automatically detectable problems found.", "1: Unexpected error.", "2: Conflicting rules found.", "", "For more information, see:", "https://github.com/prettier/eslint-config-prettier#cli-helper-tool" ].join("\n") ); process.exit(1); } getStdin() .then(string => { const result = processString(string); if (result.stderr) { console.error(result.stderr); } if (result.stdout) { console.error(result.stdout); } process.exit(result.code); }) .catch(error => { console.error("Unexpected error", error); process.exit(1); }); } function processString(string) { let config; try { config = JSON.parse(string); } catch (error) { return { stderr: `Failed to parse JSON:\n${error.message}`, code: 1 }; } if ( !(Object.prototype.toString.call(config) === "[object Object]" && Object.prototype.toString.call(config.rules) === "[object Object]") ) { return { stderr: `Expected a \`{"rules: {...}"}\` JSON object, but got:\n${string}`, code: 1 }; } const allRules = Object.assign.apply( Object, [Object.create(null)].concat( pkg.files .filter(name => name.indexOf("/") === -1) .map(ruleFileName => require(`../${ruleFileName}`).rules) ) ); const regularRules = filterRules( allRules, (ruleName, value) => value === "off" ); const optionsRules = filterRules( allRules, (ruleName, value) => value === 0 && ruleName in validators ); const specialRules = filterRules( allRules, (ruleName, value) => value === 0 && !(ruleName in validators) ); const flaggedRules = Object.keys(config.rules) .map(ruleName => { const value = config.rules[ruleName]; const arrayValue = Array.isArray(value) ? value : [value]; const level = arrayValue[0]; const options = arrayValue.slice(1); const isOff = level === "off" || level === 0; return !isOff && ruleName in allRules ? { ruleName, options } : null; }) .filter(Boolean); const regularFlaggedRuleNames = filterRuleNames( flaggedRules, ruleName => ruleName in regularRules ); const optionsFlaggedRuleNames = filterRuleNames( flaggedRules, (ruleName, options) => ruleName in optionsRules && !validators[ruleName](options) ); const specialFlaggedRuleNames = filterRuleNames( flaggedRules, ruleName => ruleName in specialRules ); if ( regularFlaggedRuleNames.length === 0 && optionsFlaggedRuleNames.length === 0 ) { const baseMessage = "No rules that are unnecessary or conflict with Prettier were found."; const message = specialFlaggedRuleNames.length === 0 ? baseMessage : [ baseMessage, "", "However, the following rules are enabled but cannot be automatically checked. See:", SPECIAL_RULES_URL, "", printRuleNames(specialFlaggedRuleNames) ].join("\n"); return { stdout: message, code: 0 }; } const regularMessage = [ "The following rules are unnecessary or might conflict with Prettier:", "", printRuleNames(regularFlaggedRuleNames) ].join("\n"); const optionsMessage = [ "The following rules are enabled with options that might conflict with Prettier. See:", SPECIAL_RULES_URL, "", printRuleNames(optionsFlaggedRuleNames) ].join("\n"); const specialMessage = [ "The following rules are enabled but cannot be automatically checked. See:", SPECIAL_RULES_URL, "", printRuleNames(specialFlaggedRuleNames) ].join("\n"); const message = [ regularFlaggedRuleNames.length === 0 ? null : regularMessage, optionsFlaggedRuleNames.length === 0 ? null : optionsMessage, specialFlaggedRuleNames.length === 0 ? null : specialMessage ] .filter(Boolean) .join("\n\n"); return { stdout: message, code: 2 }; } function filterRules(rules, fn) { return Object.keys(rules) .filter(ruleName => fn(ruleName, rules[ruleName])) .reduce((obj, ruleName) => { obj[ruleName] = true; return obj; }, Object.create(null)); } function filterRuleNames(rules, fn) { return rules .filter(rule => fn(rule.ruleName, rule.options)) .map(rule => rule.ruleName); } function printRuleNames(ruleNames) { return ruleNames.slice().sort().map(ruleName => `- ${ruleName}`).join("\n"); } exports.processString = processString;