diff --git a/docs/usage/configuration/index.md b/docs/usage/configuration/index.md index 94622c22a96..62284a1c6aa 100644 --- a/docs/usage/configuration/index.md +++ b/docs/usage/configuration/index.md @@ -29,7 +29,7 @@ A path to a directory or an array of paths to directories of [custom rules][2]. - A boolean value may be specified instead of the above object, and is equivalent to setting no options with default severity. - Any rules specified in this block will override those configured in any base configuration being extended. - [Check out the full rules list here][3]. -* `jsRules?: any`: Same format as `rules`. These rules are applied to `.js` and `.jsx` files. +* `jsRules?: any | boolean`: Same format as `rules` or explicit `true` to copy all valid active rules from rules. These rules are applied to `.js` and `.jsx` files. * `defaultSeverity?: "error" | "warning" | "off"`: The severity level that is applied to rules in this config file as well as rules in any inherited config files which have their severity set to "default". If undefined, "error" is used as the defaultSeverity. * `linterOptions?: { exclude?: string[] }`: - `exclude: string[]`: An array of globs. Any file matching these globs will not be linted. All exclude patterns are relative to the configuration file they were specified in. diff --git a/src/configuration.ts b/src/configuration.ts index 6de1dd575a6..9c315d59c64 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -23,6 +23,7 @@ import * as resolve from "resolve"; import { FatalError, showWarningOnce } from "./error"; import { IOptions, RuleSeverity } from "./language/rule/rule"; +import { findRule } from "./ruleLoader"; import { arrayify, hasOwnProperty, stripComments } from "./utils"; export interface IConfigurationFile { @@ -462,7 +463,7 @@ export interface RawConfigFile { rulesDirectory?: string | string[]; defaultSeverity?: string; rules?: RawRulesConfig; - jsRules?: RawRulesConfig; + jsRules?: RawRulesConfig | boolean; } export interface RawRulesConfig { [key: string]: RawRuleConfig; @@ -510,12 +511,18 @@ export function parseConfigFile( } function parse(config: RawConfigFile, dir?: string): IConfigurationFile { + const rulesDirectory: string | string[] = getRulesDirectories(config.rulesDirectory, dir); + const rules = parseRules(config.rules); + const jsRules = typeof config.jsRules === "boolean" ? + filterValidJsRules(rules, config.jsRules, rulesDirectory) : + parseRules(config.jsRules); + return { extends: arrayify(config.extends), - jsRules: parseRules(config.jsRules), + jsRules, linterOptions: parseLinterOptions(config.linterOptions, dir), - rules: parseRules(config.rules), - rulesDirectory: getRulesDirectories(config.rulesDirectory, dir), + rules, + rulesDirectory, }; } @@ -531,6 +538,24 @@ export function parseConfigFile( return map; } + function filterValidJsRules(rules: Map>, + copyRulestoJsRules = false, + rulesDirectory?: string | string[]): Map> { + const validJsRules = new Map>(); + if (copyRulestoJsRules) { + rules.forEach((ruleOptions, ruleName) => { + if (ruleOptions.ruleSeverity !== "off") { + const Rule = findRule(ruleName, rulesDirectory); + if ((Rule !== undefined && (Rule.metadata === undefined || !Rule.metadata.typescriptOnly))) { + validJsRules.set(ruleName, ruleOptions); + } + } + }); + } + + return validJsRules; + } + function parseLinterOptions(raw: RawConfigFile["linterOptions"], dir?: string): IConfigurationFile["linterOptions"] { if (raw === undefined || raw.exclude === undefined) { return {}; diff --git a/test/configurationTests.ts b/test/configurationTests.ts index 3d98ef68609..36e9c90b597 100644 --- a/test/configurationTests.ts +++ b/test/configurationTests.ts @@ -119,6 +119,53 @@ describe("Configuration", () => { }, ); }); + + it("parses jsRules when jsRules is a config", () => { + const rawConfig: RawConfigFile = { + jsRules: { + a: true, + }, + }; + + const expected = getEmptyConfig(); + expected.jsRules.set("a", { ruleArguments: [], ruleSeverity: "error" }); + assertConfigEquals(parseConfigFile(rawConfig), expected); + }); + + it("copies valid rules to jsRules when jsRules is a boolean", () => { + let rawConfig: RawConfigFile = { + jsRules: true, + rules: {}, + }; + + const expected = getEmptyConfig(); + assertConfigEquals(parseConfigFile(rawConfig), expected); + + rawConfig = { + jsRules: true, + rules: { + eofline: true, + }, + }; + + let {rules, jsRules} = parseConfigFile(rawConfig); + assert.deepEqual(demap(rules), demap(jsRules)); + + rawConfig = { + jsRules: true, + rules: { + eofline: true, + typedef: true, + }, + }; + + ({rules, jsRules} = parseConfigFile(rawConfig)); + assert(jsRules.has("eofline")); + assert(!jsRules.has("typedef")); + + rules.delete("typedef"); + assert.deepEqual(demap(rules), demap(jsRules)); + }); }); describe("defaultSeverity", () => {