eslint 4.7.2 → 4.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +123 -0
- package/README.md +34 -19
- package/conf/default-cli-options.js +7 -4
- package/conf/eslint-recommended.js +2 -0
- package/lib/ast-utils.js +83 -42
- package/lib/cli-engine.js +53 -17
- package/lib/cli.js +17 -9
- package/lib/code-path-analysis/code-path-analyzer.js +8 -4
- package/lib/code-path-analysis/code-path-segment.js +43 -41
- package/lib/code-path-analysis/code-path-state.js +7 -2
- package/lib/config/autoconfig.js +14 -12
- package/lib/config/config-file.js +8 -51
- package/lib/config/config-initializer.js +10 -6
- package/lib/config/config-ops.js +21 -21
- package/lib/config/config-rule.js +24 -24
- package/lib/config/config-validator.js +38 -36
- package/lib/config/plugins.js +8 -35
- package/lib/config.js +12 -8
- package/lib/formatters/html-template-message.html +1 -1
- package/lib/formatters/html-template-page.html +3 -1
- package/lib/formatters/html.js +2 -1
- package/lib/formatters/junit.js +21 -15
- package/lib/formatters/tap.js +5 -3
- package/lib/ignored-paths.js +5 -3
- package/lib/linter.js +42 -42
- package/lib/logging.js +2 -2
- package/lib/options.js +12 -0
- package/lib/rules/.eslintrc.yml +2 -2
- package/lib/rules/array-bracket-newline.js +39 -25
- package/lib/rules/array-bracket-spacing.js +28 -28
- package/lib/rules/array-callback-return.js +13 -9
- package/lib/rules/array-element-newline.js +8 -8
- package/lib/rules/arrow-body-style.js +12 -6
- package/lib/rules/arrow-parens.js +4 -2
- package/lib/rules/block-spacing.js +1 -1
- package/lib/rules/brace-style.js +14 -14
- package/lib/rules/callback-return.js +2 -1
- package/lib/rules/capitalized-comments.js +2 -1
- package/lib/rules/comma-style.js +3 -1
- package/lib/rules/computed-property-spacing.js +22 -22
- package/lib/rules/consistent-return.js +4 -4
- package/lib/rules/consistent-this.js +4 -2
- package/lib/rules/curly.js +13 -9
- package/lib/rules/dot-notation.js +56 -35
- package/lib/rules/func-call-spacing.js +4 -2
- package/lib/rules/generator-star-spacing.js +3 -3
- package/lib/rules/getter-return.js +2 -1
- package/lib/rules/indent-legacy.js +25 -14
- package/lib/rules/indent.js +101 -91
- package/lib/rules/key-spacing.js +5 -3
- package/lib/rules/lines-around-comment.js +33 -4
- package/lib/rules/lines-around-directive.js +16 -12
- package/lib/rules/lines-between-class-members.js +91 -0
- package/lib/rules/max-len.js +2 -3
- package/lib/rules/max-statements-per-line.js +5 -3
- package/lib/rules/multiline-comment-style.js +294 -0
- package/lib/rules/new-cap.js +2 -1
- package/lib/rules/newline-after-var.js +8 -6
- package/lib/rules/newline-before-return.js +13 -9
- package/lib/rules/no-alert.js +7 -15
- package/lib/rules/no-await-in-loop.js +17 -9
- package/lib/rules/no-bitwise.js +5 -3
- package/lib/rules/no-catch-shadow.js +4 -2
- package/lib/rules/no-console.js +2 -1
- package/lib/rules/no-constant-condition.js +2 -2
- package/lib/rules/no-control-regex.js +2 -1
- package/lib/rules/no-else-return.js +60 -19
- package/lib/rules/no-empty-character-class.js +11 -11
- package/lib/rules/no-extra-parens.js +22 -11
- package/lib/rules/no-extra-semi.js +5 -3
- package/lib/rules/no-global-assign.js +4 -2
- package/lib/rules/no-implicit-coercion.js +6 -6
- package/lib/rules/no-implied-eval.js +2 -1
- package/lib/rules/no-label-var.js +4 -2
- package/lib/rules/no-lone-blocks.js +3 -3
- package/lib/rules/no-lonely-if.js +2 -1
- package/lib/rules/no-loop-func.js +10 -7
- package/lib/rules/no-mixed-requires.js +8 -4
- package/lib/rules/no-native-reassign.js +4 -2
- package/lib/rules/no-param-reassign.js +4 -2
- package/lib/rules/no-regex-spaces.js +1 -1
- package/lib/rules/no-restricted-imports.js +86 -17
- package/lib/rules/no-restricted-modules.js +84 -15
- package/lib/rules/no-restricted-properties.js +10 -10
- package/lib/rules/no-return-await.js +6 -6
- package/lib/rules/no-self-assign.js +4 -2
- package/lib/rules/no-sequences.js +6 -4
- package/lib/rules/no-trailing-spaces.js +14 -8
- package/lib/rules/no-unneeded-ternary.js +3 -1
- package/lib/rules/no-unreachable.js +4 -2
- package/lib/rules/no-unused-labels.js +2 -1
- package/lib/rules/no-use-before-define.js +13 -11
- package/lib/rules/no-useless-call.js +1 -25
- package/lib/rules/no-useless-computed-key.js +2 -1
- package/lib/rules/no-useless-escape.js +31 -23
- package/lib/rules/no-useless-return.js +14 -8
- package/lib/rules/no-var.js +11 -0
- package/lib/rules/no-whitespace-before-property.js +4 -2
- package/lib/rules/object-curly-newline.js +9 -2
- package/lib/rules/object-curly-spacing.js +20 -20
- package/lib/rules/object-shorthand.js +47 -35
- package/lib/rules/operator-assignment.js +9 -9
- package/lib/rules/operator-linebreak.js +15 -11
- package/lib/rules/padding-line-between-statements.js +6 -4
- package/lib/rules/prefer-arrow-callback.js +12 -10
- package/lib/rules/prefer-const.js +18 -10
- package/lib/rules/prefer-destructuring.js +4 -2
- package/lib/rules/prefer-numeric-literals.js +4 -2
- package/lib/rules/prefer-promise-reject-errors.js +16 -16
- package/lib/rules/prefer-rest-params.js +4 -2
- package/lib/rules/prefer-spread.js +1 -25
- package/lib/rules/prefer-template.js +33 -29
- package/lib/rules/quote-props.js +8 -8
- package/lib/rules/require-jsdoc.js +11 -18
- package/lib/rules/semi-style.js +44 -19
- package/lib/rules/semi.js +5 -3
- package/lib/rules/sort-imports.js +11 -6
- package/lib/rules/space-unary-ops.js +67 -69
- package/lib/rules/strict.js +8 -8
- package/lib/rules/valid-jsdoc.js +39 -33
- package/lib/rules/valid-typeof.js +4 -4
- package/lib/rules/wrap-iife.js +4 -4
- package/lib/rules/yoda.js +9 -7
- package/lib/testers/rule-tester.js +63 -40
- package/lib/token-store/backward-token-cursor.js +5 -3
- package/lib/token-store/forward-token-cursor.js +5 -3
- package/lib/token-store/utils.js +8 -4
- package/lib/util/apply-disable-directives.js +56 -27
- package/lib/util/glob.js +1 -1
- package/lib/util/naming.js +112 -0
- package/lib/util/node-event-generator.js +13 -27
- package/lib/util/safe-emitter.js +54 -0
- package/lib/util/source-code-fixer.js +4 -2
- package/lib/util/source-code.js +70 -65
- package/messages/no-config-found.txt +1 -1
- package/package.json +8 -8
- package/lib/internal-rules/.eslintrc.yml +0 -3
- package/lib/internal-rules/internal-consistent-docs-description.js +0 -130
- package/lib/internal-rules/internal-no-invalid-meta.js +0 -188
@@ -14,9 +14,7 @@ const ajv = require("../util/ajv"),
|
|
14
14
|
configSchema = require("../../conf/config-schema.js"),
|
15
15
|
util = require("util");
|
16
16
|
|
17
|
-
const
|
18
|
-
rules: Object.create(null)
|
19
|
-
};
|
17
|
+
const ruleValidators = new WeakMap();
|
20
18
|
|
21
19
|
//------------------------------------------------------------------------------
|
22
20
|
// Private
|
@@ -25,13 +23,11 @@ let validateSchema;
|
|
25
23
|
|
26
24
|
/**
|
27
25
|
* Gets a complete options schema for a rule.
|
28
|
-
* @param {
|
29
|
-
* @param {Rules} rulesContext Rule context
|
26
|
+
* @param {{create: Function, schema: (Array|null)}} rule A new-style rule object
|
30
27
|
* @returns {Object} JSON Schema for the rule's options.
|
31
28
|
*/
|
32
|
-
function getRuleOptionsSchema(
|
33
|
-
const
|
34
|
-
schema = rule && rule.schema || rule && rule.meta && rule.meta.schema;
|
29
|
+
function getRuleOptionsSchema(rule) {
|
30
|
+
const schema = rule.schema || rule.meta && rule.meta.schema;
|
35
31
|
|
36
32
|
// Given a tuple of schemas, insert warning level at the beginning
|
37
33
|
if (Array.isArray(schema)) {
|
@@ -56,10 +52,10 @@ function getRuleOptionsSchema(id, rulesContext) {
|
|
56
52
|
}
|
57
53
|
|
58
54
|
/**
|
59
|
-
* Validates a rule's severity and returns the severity value. Throws an error if the severity is invalid.
|
60
|
-
* @param {options} options The given options for the rule.
|
61
|
-
* @returns {number|string} The rule's severity value
|
62
|
-
*/
|
55
|
+
* Validates a rule's severity and returns the severity value. Throws an error if the severity is invalid.
|
56
|
+
* @param {options} options The given options for the rule.
|
57
|
+
* @returns {number|string} The rule's severity value
|
58
|
+
*/
|
63
59
|
function validateRuleSeverity(options) {
|
64
60
|
const severity = Array.isArray(options) ? options[0] : options;
|
65
61
|
|
@@ -71,46 +67,52 @@ function validateRuleSeverity(options) {
|
|
71
67
|
}
|
72
68
|
|
73
69
|
/**
|
74
|
-
* Validates the non-severity options passed to a rule, based on its schema.
|
75
|
-
* @param {
|
76
|
-
* @param {array} localOptions The options for the rule, excluding severity
|
77
|
-
* @
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
70
|
+
* Validates the non-severity options passed to a rule, based on its schema.
|
71
|
+
* @param {{create: Function}} rule The rule to validate
|
72
|
+
* @param {array} localOptions The options for the rule, excluding severity
|
73
|
+
* @returns {void}
|
74
|
+
*/
|
75
|
+
function validateRuleSchema(rule, localOptions) {
|
76
|
+
if (!ruleValidators.has(rule)) {
|
77
|
+
const schema = getRuleOptionsSchema(rule);
|
78
|
+
|
79
|
+
if (schema) {
|
80
|
+
ruleValidators.set(rule, ajv.compile(schema));
|
81
|
+
}
|
85
82
|
}
|
86
83
|
|
87
|
-
const validateRule =
|
84
|
+
const validateRule = ruleValidators.get(rule);
|
88
85
|
|
89
86
|
if (validateRule) {
|
90
87
|
validateRule(localOptions);
|
91
88
|
if (validateRule.errors) {
|
92
|
-
throw new Error(validateRule.errors.map(
|
89
|
+
throw new Error(validateRule.errors.map(
|
90
|
+
error => `\tValue ${JSON.stringify(error.data)} ${error.message}.\n`
|
91
|
+
).join(""));
|
93
92
|
}
|
94
93
|
}
|
95
94
|
}
|
96
95
|
|
97
96
|
/**
|
98
97
|
* Validates a rule's options against its schema.
|
99
|
-
* @param {
|
98
|
+
* @param {{create: Function}|null} rule The rule that the config is being validated for
|
99
|
+
* @param {string} ruleId The rule's unique name.
|
100
100
|
* @param {array|number} options The given options for the rule.
|
101
101
|
* @param {string} source The name of the configuration source to report in any errors.
|
102
|
-
* @param {Rules} rulesContext Rule context
|
103
102
|
* @returns {void}
|
104
103
|
*/
|
105
|
-
function validateRuleOptions(
|
104
|
+
function validateRuleOptions(rule, ruleId, options, source) {
|
105
|
+
if (!rule) {
|
106
|
+
return;
|
107
|
+
}
|
106
108
|
try {
|
107
109
|
const severity = validateRuleSeverity(options);
|
108
110
|
|
109
111
|
if (severity !== 0 && !(typeof severity === "string" && severity.toLowerCase() === "off")) {
|
110
|
-
validateRuleSchema(
|
112
|
+
validateRuleSchema(rule, Array.isArray(options) ? options.slice(1) : []);
|
111
113
|
}
|
112
114
|
} catch (err) {
|
113
|
-
throw new Error(`${source}:\n\tConfiguration for rule "${
|
115
|
+
throw new Error(`${source}:\n\tConfiguration for rule "${ruleId}" is invalid:\n${err.message}`);
|
114
116
|
}
|
115
117
|
}
|
116
118
|
|
@@ -141,16 +143,16 @@ function validateEnvironment(environment, source, envContext) {
|
|
141
143
|
* Validates a rules config object
|
142
144
|
* @param {Object} rulesConfig The rules config object to validate.
|
143
145
|
* @param {string} source The name of the configuration source to report in any errors.
|
144
|
-
* @param {
|
146
|
+
* @param {function(string): {create: Function}} ruleMapper A mapper function from strings to loaded rules
|
145
147
|
* @returns {void}
|
146
148
|
*/
|
147
|
-
function validateRules(rulesConfig, source,
|
149
|
+
function validateRules(rulesConfig, source, ruleMapper) {
|
148
150
|
if (!rulesConfig) {
|
149
151
|
return;
|
150
152
|
}
|
151
153
|
|
152
154
|
Object.keys(rulesConfig).forEach(id => {
|
153
|
-
validateRuleOptions(id, rulesConfig[id], source
|
155
|
+
validateRuleOptions(ruleMapper(id), id, rulesConfig[id], source);
|
154
156
|
});
|
155
157
|
}
|
156
158
|
|
@@ -221,13 +223,13 @@ function validateConfigSchema(config, source) {
|
|
221
223
|
* Validates an entire config object.
|
222
224
|
* @param {Object} config The config object to validate.
|
223
225
|
* @param {string} source The name of the configuration source to report in any errors.
|
224
|
-
* @param {
|
226
|
+
* @param {function(string): {create: Function}} ruleMapper A mapper function from rule IDs to defined rules
|
225
227
|
* @param {Environments} envContext The env context
|
226
228
|
* @returns {void}
|
227
229
|
*/
|
228
|
-
function validate(config, source,
|
230
|
+
function validate(config, source, ruleMapper, envContext) {
|
229
231
|
validateConfigSchema(config, source);
|
230
|
-
validateRules(config.rules, source,
|
232
|
+
validateRules(config.rules, source, ruleMapper);
|
231
233
|
validateEnvironment(config.env, source, envContext);
|
232
234
|
}
|
233
235
|
|
package/lib/config/plugins.js
CHANGED
@@ -9,13 +9,13 @@
|
|
9
9
|
//------------------------------------------------------------------------------
|
10
10
|
|
11
11
|
const debug = require("debug")("eslint:plugins");
|
12
|
+
const naming = require("../util/naming");
|
12
13
|
|
13
14
|
//------------------------------------------------------------------------------
|
14
15
|
// Private
|
15
16
|
//------------------------------------------------------------------------------
|
16
17
|
|
17
|
-
const PLUGIN_NAME_PREFIX = "eslint-plugin-"
|
18
|
-
NAMESPACE_REGEX = /^@.*\//i;
|
18
|
+
const PLUGIN_NAME_PREFIX = "eslint-plugin-";
|
19
19
|
|
20
20
|
//------------------------------------------------------------------------------
|
21
21
|
// Public Interface
|
@@ -37,33 +37,6 @@ class Plugins {
|
|
37
37
|
this._rules = rulesContext;
|
38
38
|
}
|
39
39
|
|
40
|
-
/**
|
41
|
-
* Removes the prefix `eslint-plugin-` from a plugin name.
|
42
|
-
* @param {string} pluginName The name of the plugin which may have the prefix.
|
43
|
-
* @returns {string} The name of the plugin without prefix.
|
44
|
-
*/
|
45
|
-
static removePrefix(pluginName) {
|
46
|
-
return pluginName.startsWith(PLUGIN_NAME_PREFIX) ? pluginName.slice(PLUGIN_NAME_PREFIX.length) : pluginName;
|
47
|
-
}
|
48
|
-
|
49
|
-
/**
|
50
|
-
* Gets the scope (namespace) of a plugin.
|
51
|
-
* @param {string} pluginName The name of the plugin which may have the prefix.
|
52
|
-
* @returns {string} The name of the plugins namepace if it has one.
|
53
|
-
*/
|
54
|
-
static getNamespace(pluginName) {
|
55
|
-
return pluginName.match(NAMESPACE_REGEX) ? pluginName.match(NAMESPACE_REGEX)[0] : "";
|
56
|
-
}
|
57
|
-
|
58
|
-
/**
|
59
|
-
* Removes the namespace from a plugin name.
|
60
|
-
* @param {string} pluginName The name of the plugin which may have the prefix.
|
61
|
-
* @returns {string} The name of the plugin without the namespace.
|
62
|
-
*/
|
63
|
-
static removeNamespace(pluginName) {
|
64
|
-
return pluginName.replace(NAMESPACE_REGEX, "");
|
65
|
-
}
|
66
|
-
|
67
40
|
/**
|
68
41
|
* Defines a plugin with a given name rather than loading from disk.
|
69
42
|
* @param {string} pluginName The name of the plugin to load.
|
@@ -71,9 +44,9 @@ class Plugins {
|
|
71
44
|
* @returns {void}
|
72
45
|
*/
|
73
46
|
define(pluginName, plugin) {
|
74
|
-
const pluginNamespace =
|
75
|
-
pluginNameWithoutNamespace =
|
76
|
-
pluginNameWithoutPrefix =
|
47
|
+
const pluginNamespace = naming.getNamespaceFromTerm(pluginName),
|
48
|
+
pluginNameWithoutNamespace = naming.removeNamespaceFromTerm(pluginName),
|
49
|
+
pluginNameWithoutPrefix = naming.removePrefixFromTerm(PLUGIN_NAME_PREFIX, pluginNameWithoutNamespace),
|
77
50
|
shortName = pluginNamespace + pluginNameWithoutPrefix;
|
78
51
|
|
79
52
|
// load up environments and rules
|
@@ -106,9 +79,9 @@ class Plugins {
|
|
106
79
|
* @throws {Error} If the plugin cannot be loaded.
|
107
80
|
*/
|
108
81
|
load(pluginName) {
|
109
|
-
const pluginNamespace =
|
110
|
-
pluginNameWithoutNamespace =
|
111
|
-
pluginNameWithoutPrefix =
|
82
|
+
const pluginNamespace = naming.getNamespaceFromTerm(pluginName),
|
83
|
+
pluginNameWithoutNamespace = naming.removeNamespaceFromTerm(pluginName),
|
84
|
+
pluginNameWithoutPrefix = naming.removePrefixFromTerm(PLUGIN_NAME_PREFIX, pluginNameWithoutNamespace),
|
112
85
|
shortName = pluginNamespace + pluginNameWithoutPrefix,
|
113
86
|
longName = pluginNamespace + PLUGIN_NAME_PREFIX + pluginNameWithoutPrefix;
|
114
87
|
let plugin = null;
|
package/lib/config.js
CHANGED
@@ -120,10 +120,10 @@ class Config {
|
|
120
120
|
}
|
121
121
|
|
122
122
|
/**
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
123
|
+
* Loads the config options from a config specified on the command line.
|
124
|
+
* @param {string} [config] A shareable named config or path to a config file.
|
125
|
+
* @returns {void}
|
126
|
+
*/
|
127
127
|
loadSpecificConfig(config) {
|
128
128
|
if (config) {
|
129
129
|
debug(`Using command line config ${config}`);
|
@@ -216,8 +216,10 @@ class Config {
|
|
216
216
|
return localConfigHierarchy;
|
217
217
|
}
|
218
218
|
|
219
|
-
|
220
|
-
|
219
|
+
/*
|
220
|
+
* Don't consider the personal config file in the home directory,
|
221
|
+
* except if the home directory is the same as the current working directory
|
222
|
+
*/
|
221
223
|
if (localConfigDirectory === PERSONAL_CONFIG_DIR && localConfigFile !== projectConfigPath) {
|
222
224
|
continue;
|
223
225
|
}
|
@@ -343,8 +345,10 @@ class Config {
|
|
343
345
|
this.plugins.loadAll(this.cliConfig.plugins);
|
344
346
|
}
|
345
347
|
|
346
|
-
|
347
|
-
|
348
|
+
/*
|
349
|
+
* Step 3: Override parser only if it is passed explicitly through the command line
|
350
|
+
* or if it's not defined yet (because the final object will at least have the parser key)
|
351
|
+
*/
|
348
352
|
if (this.parser || !config.parser) {
|
349
353
|
config = ConfigOps.merge(config, { parser: this.parser });
|
350
354
|
}
|
@@ -3,6 +3,6 @@
|
|
3
3
|
<td class="clr-<%= severityNumber %>"><%= severityName %></td>
|
4
4
|
<td><%- message %></td>
|
5
5
|
<td>
|
6
|
-
<a href="
|
6
|
+
<a href="https://eslint.org/docs/rules/<%= ruleId %>" target="_blank"><%= ruleId %></a>
|
7
7
|
</td>
|
8
8
|
</tr>
|
package/lib/formatters/html.js
CHANGED
package/lib/formatters/junit.js
CHANGED
@@ -39,22 +39,28 @@ module.exports = function(results) {
|
|
39
39
|
|
40
40
|
const messages = result.messages;
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
if (messages.length > 0) {
|
43
|
+
output += `<testsuite package="org.eslint" time="0" tests="${messages.length}" errors="${messages.length}" name="${result.filePath}">\n`;
|
44
|
+
messages.forEach(message => {
|
45
|
+
const type = message.fatal ? "error" : "failure";
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
47
|
+
output += `<testcase time="0" name="org.eslint.${message.ruleId || "unknown"}">`;
|
48
|
+
output += `<${type} message="${xmlEscape(message.message || "")}">`;
|
49
|
+
output += "<![CDATA[";
|
50
|
+
output += `line ${message.line || 0}, col `;
|
51
|
+
output += `${message.column || 0}, ${getMessageType(message)}`;
|
52
|
+
output += ` - ${xmlEscape(message.message || "")}`;
|
53
|
+
output += (message.ruleId ? ` (${message.ruleId})` : "");
|
54
|
+
output += "]]>";
|
55
|
+
output += `</${type}>`;
|
56
|
+
output += "</testcase>\n";
|
57
|
+
});
|
58
|
+
output += "</testsuite>\n";
|
59
|
+
} else {
|
60
|
+
output += `<testsuite package="org.eslint" time="0" tests="1" errors="0" name="${result.filePath}">\n`;
|
61
|
+
output += `<testcase time="0" name="${result.filePath}" />\n`;
|
62
|
+
output += "</testsuite>\n";
|
63
|
+
}
|
58
64
|
|
59
65
|
});
|
60
66
|
|
package/lib/formatters/tap.js
CHANGED
@@ -63,9 +63,11 @@ module.exports = function(results) {
|
|
63
63
|
}
|
64
64
|
};
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
66
|
+
/*
|
67
|
+
* If we have multiple messages place them under a messages key
|
68
|
+
* The first error will be logged as message key
|
69
|
+
* This is to adhere to TAP 13 loosely defined specification of having a message key
|
70
|
+
*/
|
69
71
|
if ("message" in diagnostics) {
|
70
72
|
if (typeof diagnostics.messages === "undefined") {
|
71
73
|
diagnostics.messages = [];
|
package/lib/ignored-paths.js
CHANGED
@@ -114,8 +114,10 @@ class IgnoredPaths {
|
|
114
114
|
default: ignore()
|
115
115
|
};
|
116
116
|
|
117
|
-
|
118
|
-
|
117
|
+
/*
|
118
|
+
* Add a way to keep track of ignored files. This was present in node-ignore
|
119
|
+
* 2.x, but dropped for now as of 3.0.10.
|
120
|
+
*/
|
119
121
|
this.ig.custom.ignoreFiles = [];
|
120
122
|
this.ig.default.ignoreFiles = [];
|
121
123
|
|
@@ -184,7 +186,7 @@ class IgnoredPaths {
|
|
184
186
|
addPattern(this.ig.default, pattern);
|
185
187
|
});
|
186
188
|
} else {
|
187
|
-
throw new
|
189
|
+
throw new TypeError("Package.json eslintIgnore property requires an array of paths");
|
188
190
|
}
|
189
191
|
}
|
190
192
|
}
|
package/lib/linter.js
CHANGED
@@ -9,8 +9,7 @@
|
|
9
9
|
// Requirements
|
10
10
|
//------------------------------------------------------------------------------
|
11
11
|
|
12
|
-
const
|
13
|
-
eslintScope = require("eslint-scope"),
|
12
|
+
const eslintScope = require("eslint-scope"),
|
14
13
|
levn = require("levn"),
|
15
14
|
lodash = require("lodash"),
|
16
15
|
blankScriptAST = require("../conf/blank-script.json"),
|
@@ -20,6 +19,7 @@ const EventEmitter = require("events").EventEmitter,
|
|
20
19
|
validator = require("./config/config-validator"),
|
21
20
|
Environments = require("./config/environments"),
|
22
21
|
applyDisableDirectives = require("./util/apply-disable-directives"),
|
22
|
+
createEmitter = require("./util/safe-emitter"),
|
23
23
|
NodeEventGenerator = require("./util/node-event-generator"),
|
24
24
|
SourceCode = require("./util/source-code"),
|
25
25
|
Traverser = require("./util/traverser"),
|
@@ -111,8 +111,10 @@ function parseJsonConfig(string, location) {
|
|
111
111
|
// ignore to parse the string by a fallback.
|
112
112
|
}
|
113
113
|
|
114
|
-
|
115
|
-
|
114
|
+
/*
|
115
|
+
* Optionator cannot parse commaless notations.
|
116
|
+
* But we are supporting that. So this is a fallback for that.
|
117
|
+
*/
|
116
118
|
items = {};
|
117
119
|
string = string.replace(/([a-zA-Z0-9\-/]+):/g, "\"$1\":").replace(/(]|[0-9])\s+(?=")/, "$1,");
|
118
120
|
try {
|
@@ -164,13 +166,12 @@ function parseListConfig(string) {
|
|
164
166
|
* Ensures that variables representing built-in properties of the Global Object,
|
165
167
|
* and any globals declared by special block comments, are present in the global
|
166
168
|
* scope.
|
167
|
-
* @param {ASTNode} program The top node of the AST.
|
168
169
|
* @param {Scope} globalScope The global scope.
|
169
170
|
* @param {Object} config The existing configuration data.
|
170
171
|
* @param {Environments} envContext Env context
|
171
172
|
* @returns {void}
|
172
173
|
*/
|
173
|
-
function addDeclaredGlobals(
|
174
|
+
function addDeclaredGlobals(globalScope, config, envContext) {
|
174
175
|
const declaredGlobals = {},
|
175
176
|
exportedGlobals = {},
|
176
177
|
explicitGlobals = {},
|
@@ -277,7 +278,7 @@ function createDisableDirectives(type, loc, value) {
|
|
277
278
|
* @param {string} filename The file being checked.
|
278
279
|
* @param {ASTNode} ast The top node of the AST.
|
279
280
|
* @param {Object} config The existing configuration data.
|
280
|
-
* @param {
|
281
|
+
* @param {function(string): {create: Function}} ruleMapper A map from rule IDs to defined rules
|
281
282
|
* @returns {{
|
282
283
|
* config: Object,
|
283
284
|
* problems: Problem[],
|
@@ -290,9 +291,9 @@ function createDisableDirectives(type, loc, value) {
|
|
290
291
|
* }} Modified config object, along with any problems encountered
|
291
292
|
* while parsing config comments
|
292
293
|
*/
|
293
|
-
function modifyConfigsFromComments(filename, ast, config,
|
294
|
+
function modifyConfigsFromComments(filename, ast, config, ruleMapper) {
|
294
295
|
|
295
|
-
|
296
|
+
const commentConfig = {
|
296
297
|
exported: {},
|
297
298
|
astGlobals: {},
|
298
299
|
rules: {},
|
@@ -321,10 +322,6 @@ function modifyConfigsFromComments(filename, ast, config, linterContext) {
|
|
321
322
|
Object.assign(commentConfig.astGlobals, parseBooleanConfig(value, comment));
|
322
323
|
break;
|
323
324
|
|
324
|
-
case "eslint-env":
|
325
|
-
Object.assign(commentConfig.env, parseListConfig(value));
|
326
|
-
break;
|
327
|
-
|
328
325
|
case "eslint-disable":
|
329
326
|
[].push.apply(disableDirectives, createDisableDirectives("disable", comment.loc.start, value));
|
330
327
|
break;
|
@@ -340,7 +337,7 @@ function modifyConfigsFromComments(filename, ast, config, linterContext) {
|
|
340
337
|
Object.keys(parseResult.config).forEach(name => {
|
341
338
|
const ruleValue = parseResult.config[name];
|
342
339
|
|
343
|
-
validator.validateRuleOptions(name, ruleValue, `${filename} line ${comment.loc.start.line}
|
340
|
+
validator.validateRuleOptions(ruleMapper(name), name, ruleValue, `${filename} line ${comment.loc.start.line}`);
|
344
341
|
commentRules[name] = ruleValue;
|
345
342
|
});
|
346
343
|
} else {
|
@@ -362,14 +359,6 @@ function modifyConfigsFromComments(filename, ast, config, linterContext) {
|
|
362
359
|
}
|
363
360
|
});
|
364
361
|
|
365
|
-
// apply environment configs
|
366
|
-
Object.keys(commentConfig.env).forEach(name => {
|
367
|
-
const env = linterContext.environments.get(name);
|
368
|
-
|
369
|
-
if (env) {
|
370
|
-
commentConfig = ConfigOps.merge(commentConfig, env);
|
371
|
-
}
|
372
|
-
});
|
373
362
|
Object.assign(commentConfig.rules, commentRules);
|
374
363
|
|
375
364
|
return {
|
@@ -392,8 +381,10 @@ function normalizeEcmaVersion(ecmaVersion, isModule) {
|
|
392
381
|
ecmaVersion = 6;
|
393
382
|
}
|
394
383
|
|
395
|
-
|
396
|
-
|
384
|
+
/*
|
385
|
+
* Calculate ECMAScript edition number from official year version starting with
|
386
|
+
* ES2015, which corresponds with ES6 (or a difference of 2009).
|
387
|
+
*/
|
397
388
|
if (ecmaVersion >= 2015) {
|
398
389
|
ecmaVersion -= 2009;
|
399
390
|
}
|
@@ -698,6 +689,8 @@ const BASE_TRAVERSAL_CONTEXT = Object.freeze(
|
|
698
689
|
)
|
699
690
|
);
|
700
691
|
|
692
|
+
const lastSourceCodes = new WeakMap();
|
693
|
+
|
701
694
|
//------------------------------------------------------------------------------
|
702
695
|
// Public Interface
|
703
696
|
//------------------------------------------------------------------------------
|
@@ -709,7 +702,7 @@ const BASE_TRAVERSAL_CONTEXT = Object.freeze(
|
|
709
702
|
module.exports = class Linter {
|
710
703
|
|
711
704
|
constructor() {
|
712
|
-
this
|
705
|
+
lastSourceCodes.set(this, null);
|
713
706
|
this.version = pkg.version;
|
714
707
|
|
715
708
|
this.rules = new Rules();
|
@@ -734,20 +727,24 @@ module.exports = class Linter {
|
|
734
727
|
* @param {(string|Object)} [filenameOrOptions] The optional filename of the file being checked.
|
735
728
|
* If this is not set, the filename will default to '<input>' in the rule context. If
|
736
729
|
* an object, then it has "filename", "saveState", and "allowInlineConfig" properties.
|
737
|
-
* @param {boolean} [filenameOrOptions.allowInlineConfig] Allow/disallow inline comments' ability to change config once it is set. Defaults to true if not supplied.
|
730
|
+
* @param {boolean} [filenameOrOptions.allowInlineConfig=true] Allow/disallow inline comments' ability to change config once it is set. Defaults to true if not supplied.
|
738
731
|
* Useful if you want to validate JS without comments overriding rules.
|
732
|
+
* @param {boolean} [filenameOrOptions.reportUnusedDisableDirectives=false] Adds reported errors for unused
|
733
|
+
* eslint-disable directives
|
739
734
|
* @returns {Object[]} The results as an array of messages or null if no messages.
|
740
735
|
*/
|
741
736
|
_verifyWithoutProcessors(textOrSourceCode, config, filenameOrOptions) {
|
742
737
|
let text,
|
743
738
|
parserServices,
|
744
739
|
allowInlineConfig,
|
745
|
-
providedFilename
|
740
|
+
providedFilename,
|
741
|
+
reportUnusedDisableDirectives;
|
746
742
|
|
747
743
|
// evaluate arguments
|
748
744
|
if (typeof filenameOrOptions === "object") {
|
749
745
|
providedFilename = filenameOrOptions.filename;
|
750
746
|
allowInlineConfig = filenameOrOptions.allowInlineConfig;
|
747
|
+
reportUnusedDisableDirectives = filenameOrOptions.reportUnusedDisableDirectives;
|
751
748
|
} else {
|
752
749
|
providedFilename = filenameOrOptions;
|
753
750
|
}
|
@@ -755,11 +752,11 @@ module.exports = class Linter {
|
|
755
752
|
const filename = typeof providedFilename === "string" ? providedFilename : "<input>";
|
756
753
|
|
757
754
|
if (typeof textOrSourceCode === "string") {
|
758
|
-
this
|
755
|
+
lastSourceCodes.set(this, null);
|
759
756
|
text = textOrSourceCode;
|
760
757
|
} else {
|
761
|
-
this
|
762
|
-
text =
|
758
|
+
lastSourceCodes.set(this, textOrSourceCode);
|
759
|
+
text = textOrSourceCode.text;
|
763
760
|
}
|
764
761
|
|
765
762
|
// search and apply "eslint-env *".
|
@@ -778,13 +775,13 @@ module.exports = class Linter {
|
|
778
775
|
// process initial config to make it safe to extend
|
779
776
|
config = prepareConfig(config, this.environments);
|
780
777
|
|
781
|
-
if (this
|
778
|
+
if (lastSourceCodes.get(this)) {
|
782
779
|
parserServices = {};
|
783
780
|
} else {
|
784
781
|
|
785
782
|
// there's no input, just exit here
|
786
783
|
if (text.trim().length === 0) {
|
787
|
-
this
|
784
|
+
lastSourceCodes.set(this, new SourceCode(text, blankScriptAST));
|
788
785
|
return [];
|
789
786
|
}
|
790
787
|
|
@@ -800,16 +797,16 @@ module.exports = class Linter {
|
|
800
797
|
}
|
801
798
|
|
802
799
|
parserServices = parseResult.services;
|
803
|
-
this
|
800
|
+
lastSourceCodes.set(this, new SourceCode(text, parseResult.ast));
|
804
801
|
}
|
805
802
|
|
806
803
|
const problems = [];
|
807
|
-
const sourceCode = this
|
804
|
+
const sourceCode = lastSourceCodes.get(this);
|
808
805
|
let disableDirectives;
|
809
806
|
|
810
807
|
// parse global comments and modify config
|
811
808
|
if (allowInlineConfig !== false) {
|
812
|
-
const modifyConfigResult = modifyConfigsFromComments(filename, sourceCode.ast, config, this);
|
809
|
+
const modifyConfigResult = modifyConfigsFromComments(filename, sourceCode.ast, config, ruleId => this.rules.get(ruleId));
|
813
810
|
|
814
811
|
config = modifyConfigResult.config;
|
815
812
|
modifyConfigResult.problems.forEach(problem => problems.push(problem));
|
@@ -818,7 +815,7 @@ module.exports = class Linter {
|
|
818
815
|
disableDirectives = [];
|
819
816
|
}
|
820
817
|
|
821
|
-
const emitter =
|
818
|
+
const emitter = createEmitter();
|
822
819
|
const traverser = new Traverser();
|
823
820
|
const ecmaFeatures = config.parserOptions.ecmaFeatures || {};
|
824
821
|
const ecmaVersion = config.parserOptions.ecmaVersion || 5;
|
@@ -861,7 +858,7 @@ module.exports = class Linter {
|
|
861
858
|
*/
|
862
859
|
_linter: {
|
863
860
|
report() {},
|
864
|
-
on: emitter.on
|
861
|
+
on: emitter.on
|
865
862
|
}
|
866
863
|
}
|
867
864
|
)
|
@@ -946,7 +943,7 @@ module.exports = class Linter {
|
|
946
943
|
});
|
947
944
|
|
948
945
|
// augment global scope with declared global variables
|
949
|
-
addDeclaredGlobals(
|
946
|
+
addDeclaredGlobals(scopeManager.scopes[0], config, this.environments);
|
950
947
|
|
951
948
|
const eventGenerator = new CodePathAnalyzer(new NodeEventGenerator(emitter));
|
952
949
|
|
@@ -968,7 +965,8 @@ module.exports = class Linter {
|
|
968
965
|
|
969
966
|
return applyDisableDirectives({
|
970
967
|
directives: disableDirectives,
|
971
|
-
problems: problems.sort((problemA, problemB) => problemA.line - problemB.line || problemA.column - problemB.column)
|
968
|
+
problems: problems.sort((problemA, problemB) => problemA.line - problemB.line || problemA.column - problemB.column),
|
969
|
+
reportUnusedDisableDirectives
|
972
970
|
});
|
973
971
|
}
|
974
972
|
|
@@ -1006,7 +1004,7 @@ module.exports = class Linter {
|
|
1006
1004
|
* @returns {SourceCode} The SourceCode object.
|
1007
1005
|
*/
|
1008
1006
|
getSourceCode() {
|
1009
|
-
return this
|
1007
|
+
return lastSourceCodes.get(this);
|
1010
1008
|
}
|
1011
1009
|
|
1012
1010
|
/**
|
@@ -1082,8 +1080,10 @@ module.exports = class Linter {
|
|
1082
1080
|
debug(`Generating fixed text for ${debugTextDescription} (pass ${passNumber})`);
|
1083
1081
|
fixedResult = SourceCodeFixer.applyFixes(text, messages, shouldFix);
|
1084
1082
|
|
1085
|
-
|
1086
|
-
|
1083
|
+
/*
|
1084
|
+
* stop if there are any syntax errors.
|
1085
|
+
* 'fixedResult.output' is a empty string.
|
1086
|
+
*/
|
1087
1087
|
if (messages.length === 1 && messages[0].fatal) {
|
1088
1088
|
break;
|
1089
1089
|
}
|