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
package/lib/token-store/utils.js
CHANGED
@@ -62,8 +62,10 @@ exports.getFirstIndex = function getFirstIndex(tokens, indexMap, startLoc) {
|
|
62
62
|
const index = indexMap[startLoc - 1];
|
63
63
|
const token = (index >= 0 && index < tokens.length) ? tokens[index] : null;
|
64
64
|
|
65
|
-
|
66
|
-
|
65
|
+
/*
|
66
|
+
* For the map of "comment's location -> token's index", it points the next token of a comment.
|
67
|
+
* In that case, +1 is unnecessary.
|
68
|
+
*/
|
67
69
|
if (token && token.range[0] >= startLoc) {
|
68
70
|
return index;
|
69
71
|
}
|
@@ -89,8 +91,10 @@ exports.getLastIndex = function getLastIndex(tokens, indexMap, endLoc) {
|
|
89
91
|
const index = indexMap[endLoc - 1];
|
90
92
|
const token = (index >= 0 && index < tokens.length) ? tokens[index] : null;
|
91
93
|
|
92
|
-
|
93
|
-
|
94
|
+
/*
|
95
|
+
* For the map of "comment's location -> token's index", it points the next token of a comment.
|
96
|
+
* In that case, -1 is necessary.
|
97
|
+
*/
|
94
98
|
if (token && token.range[1] > endLoc) {
|
95
99
|
return index - 1;
|
96
100
|
}
|
@@ -19,20 +19,24 @@ function compareLocations(itemA, itemB) {
|
|
19
19
|
}
|
20
20
|
|
21
21
|
/**
|
22
|
-
* This is the same as the exported function, except that it
|
23
|
-
*
|
24
|
-
*
|
22
|
+
* This is the same as the exported function, except that it
|
23
|
+
* doesn't handle disable-line and disable-next-line directives, and it always reports unused
|
24
|
+
* disable directives.
|
25
|
+
* @param {Object} options options for applying directives. This is the same as the options
|
26
|
+
* for the exported function, except that `reportUnusedDisableDirectives` is not supported
|
27
|
+
* (this function always reports unused disable directives).
|
28
|
+
* @returns {{problems: Problem[], unusedDisableDirectives: Problem[]}} An object with a list
|
29
|
+
* of filtered problems and unused eslint-disable directives
|
25
30
|
*/
|
26
31
|
function applyDirectives(options) {
|
27
32
|
const problems = [];
|
28
33
|
let nextDirectiveIndex = 0;
|
29
|
-
let
|
34
|
+
let currentGlobalDisableDirective = null;
|
35
|
+
const disabledRuleMap = new Map();
|
30
36
|
|
31
|
-
//
|
32
|
-
const disabledRules = new Set();
|
33
|
-
|
34
|
-
// enabledRules is only used when there is an active global /* eslint-disable */ comment.
|
37
|
+
// enabledRules is only used when there is a current global disable directive.
|
35
38
|
const enabledRules = new Set();
|
39
|
+
const usedDisableDirectives = new Set();
|
36
40
|
|
37
41
|
for (const problem of options.problems) {
|
38
42
|
while (
|
@@ -44,23 +48,26 @@ function applyDirectives(options) {
|
|
44
48
|
switch (directive.type) {
|
45
49
|
case "disable":
|
46
50
|
if (directive.ruleId === null) {
|
47
|
-
|
51
|
+
currentGlobalDisableDirective = directive;
|
52
|
+
disabledRuleMap.clear();
|
48
53
|
enabledRules.clear();
|
49
|
-
} else if (
|
54
|
+
} else if (currentGlobalDisableDirective) {
|
50
55
|
enabledRules.delete(directive.ruleId);
|
56
|
+
disabledRuleMap.set(directive.ruleId, directive);
|
51
57
|
} else {
|
52
|
-
|
58
|
+
disabledRuleMap.set(directive.ruleId, directive);
|
53
59
|
}
|
54
60
|
break;
|
55
61
|
|
56
62
|
case "enable":
|
57
63
|
if (directive.ruleId === null) {
|
58
|
-
|
59
|
-
|
60
|
-
} else if (
|
64
|
+
currentGlobalDisableDirective = null;
|
65
|
+
disabledRuleMap.clear();
|
66
|
+
} else if (currentGlobalDisableDirective) {
|
61
67
|
enabledRules.add(directive.ruleId);
|
68
|
+
disabledRuleMap.delete(directive.ruleId);
|
62
69
|
} else {
|
63
|
-
|
70
|
+
disabledRuleMap.delete(directive.ruleId);
|
64
71
|
}
|
65
72
|
break;
|
66
73
|
|
@@ -68,15 +75,30 @@ function applyDirectives(options) {
|
|
68
75
|
}
|
69
76
|
}
|
70
77
|
|
71
|
-
if (
|
72
|
-
|
73
|
-
|
74
|
-
|
78
|
+
if (disabledRuleMap.has(problem.ruleId)) {
|
79
|
+
usedDisableDirectives.add(disabledRuleMap.get(problem.ruleId));
|
80
|
+
} else if (currentGlobalDisableDirective && !enabledRules.has(problem.ruleId)) {
|
81
|
+
usedDisableDirectives.add(currentGlobalDisableDirective);
|
82
|
+
} else {
|
75
83
|
problems.push(problem);
|
76
84
|
}
|
77
85
|
}
|
78
86
|
|
79
|
-
|
87
|
+
const unusedDisableDirectives = options.directives
|
88
|
+
.filter(directive => directive.type === "disable" && !usedDisableDirectives.has(directive))
|
89
|
+
.map(directive => ({
|
90
|
+
ruleId: null,
|
91
|
+
message: directive.ruleId
|
92
|
+
? `Unused eslint-disable directive (no problems were reported from '${directive.ruleId}').`
|
93
|
+
: "Unused eslint-disable directive (no problems were reported).",
|
94
|
+
line: directive.unprocessedDirective.line,
|
95
|
+
column: directive.unprocessedDirective.column,
|
96
|
+
severity: 2,
|
97
|
+
source: null,
|
98
|
+
nodeType: null
|
99
|
+
}));
|
100
|
+
|
101
|
+
return { problems, unusedDisableDirectives };
|
80
102
|
}
|
81
103
|
|
82
104
|
/**
|
@@ -93,12 +115,14 @@ function applyDirectives(options) {
|
|
93
115
|
* comment for two different rules is represented as two directives).
|
94
116
|
* @param {{ruleId: (string|null), line: number, column: number}[]} options.problems
|
95
117
|
* A list of problems reported by rules, sorted by increasing location in the file, with one-based columns.
|
118
|
+
* @param {boolean} options.reportUnusedDisableDirectives If `true`, adds additional problems for unused directives
|
96
119
|
* @returns {{ruleId: (string|null), line: number, column: number}[]}
|
97
120
|
* A list of reported problems that were not disabled by the directive comments.
|
98
121
|
*/
|
99
122
|
module.exports = options => {
|
100
123
|
const blockDirectives = options.directives
|
101
124
|
.filter(directive => directive.type === "disable" || directive.type === "enable")
|
125
|
+
.map(directive => Object.assign({}, directive, { unprocessedDirective: directive }))
|
102
126
|
.sort(compareLocations);
|
103
127
|
|
104
128
|
const lineDirectives = lodash.flatMap(options.directives, directive => {
|
@@ -109,14 +133,14 @@ module.exports = options => {
|
|
109
133
|
|
110
134
|
case "disable-line":
|
111
135
|
return [
|
112
|
-
{ type: "disable", line: directive.line, column: 1, ruleId: directive.ruleId },
|
113
|
-
{ type: "enable", line: directive.line + 1, column: 0, ruleId: directive.ruleId }
|
136
|
+
{ type: "disable", line: directive.line, column: 1, ruleId: directive.ruleId, unprocessedDirective: directive },
|
137
|
+
{ type: "enable", line: directive.line + 1, column: 0, ruleId: directive.ruleId, unprocessedDirective: directive }
|
114
138
|
];
|
115
139
|
|
116
140
|
case "disable-next-line":
|
117
141
|
return [
|
118
|
-
{ type: "disable", line: directive.line + 1, column: 1, ruleId: directive.ruleId },
|
119
|
-
{ type: "enable", line: directive.line + 2, column: 0, ruleId: directive.ruleId }
|
142
|
+
{ type: "disable", line: directive.line + 1, column: 1, ruleId: directive.ruleId, unprocessedDirective: directive },
|
143
|
+
{ type: "enable", line: directive.line + 2, column: 0, ruleId: directive.ruleId, unprocessedDirective: directive }
|
120
144
|
];
|
121
145
|
|
122
146
|
default:
|
@@ -124,8 +148,13 @@ module.exports = options => {
|
|
124
148
|
}
|
125
149
|
}).sort(compareLocations);
|
126
150
|
|
127
|
-
const
|
128
|
-
const
|
151
|
+
const blockDirectivesResult = applyDirectives({ problems: options.problems, directives: blockDirectives });
|
152
|
+
const lineDirectivesResult = applyDirectives({ problems: blockDirectivesResult.problems, directives: lineDirectives });
|
129
153
|
|
130
|
-
return
|
154
|
+
return options.reportUnusedDisableDirectives
|
155
|
+
? lineDirectivesResult.problems
|
156
|
+
.concat(blockDirectivesResult.unusedDisableDirectives)
|
157
|
+
.concat(lineDirectivesResult.unusedDisableDirectives)
|
158
|
+
.sort(compareLocations)
|
159
|
+
: lineDirectivesResult.problems;
|
131
160
|
};
|
package/lib/util/glob.js
CHANGED
@@ -47,7 +47,7 @@ GlobSync.prototype._readdir = function(abs, inGlobStar) {
|
|
47
47
|
* `options.nodir` makes `options.mark` as `true`.
|
48
48
|
* Mark `abs` first
|
49
49
|
* to make sure `"node_modules"` will be ignored immediately with ignore pattern `"node_modules/"`.
|
50
|
-
|
50
|
+
*
|
51
51
|
* There is a built-in cache about marked `File.Stat` in `glob`, so that we could not worry about the extra invocation of `this._mark()`
|
52
52
|
*/
|
53
53
|
const marked = this._mark(abs);
|
@@ -0,0 +1,112 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Common helpers for naming of plugins, formatters and configs
|
3
|
+
*/
|
4
|
+
"use strict";
|
5
|
+
|
6
|
+
//------------------------------------------------------------------------------
|
7
|
+
// Requirements
|
8
|
+
//------------------------------------------------------------------------------
|
9
|
+
|
10
|
+
const pathUtil = require("../util/path-util");
|
11
|
+
|
12
|
+
//------------------------------------------------------------------------------
|
13
|
+
// Private
|
14
|
+
//------------------------------------------------------------------------------
|
15
|
+
|
16
|
+
const NAMESPACE_REGEX = /^@.*\//i;
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Brings package name to correct format based on prefix
|
20
|
+
* @param {string} name The name of the package.
|
21
|
+
* @param {string} prefix Can be either "eslint-plugin", "eslint-config" or "eslint-formatter"
|
22
|
+
* @returns {string} Normalized name of the package
|
23
|
+
* @private
|
24
|
+
*/
|
25
|
+
function normalizePackageName(name, prefix) {
|
26
|
+
|
27
|
+
/**
|
28
|
+
* On Windows, name can come in with Windows slashes instead of Unix slashes.
|
29
|
+
* Normalize to Unix first to avoid errors later on.
|
30
|
+
* https://github.com/eslint/eslint/issues/5644
|
31
|
+
*/
|
32
|
+
if (name.indexOf("\\") > -1) {
|
33
|
+
name = pathUtil.convertPathToPosix(name);
|
34
|
+
}
|
35
|
+
|
36
|
+
if (name.charAt(0) === "@") {
|
37
|
+
|
38
|
+
/**
|
39
|
+
* it's a scoped package
|
40
|
+
* package name is the prefix, or just a username
|
41
|
+
*/
|
42
|
+
const scopedPackageShortcutRegex = new RegExp(`^(@[^/]+)(?:/(?:${prefix})?)?$`),
|
43
|
+
scopedPackageNameRegex = new RegExp(`^${prefix}(-|$)`);
|
44
|
+
|
45
|
+
if (scopedPackageShortcutRegex.test(name)) {
|
46
|
+
name = name.replace(scopedPackageShortcutRegex, `$1/${prefix}`);
|
47
|
+
} else if (!scopedPackageNameRegex.test(name.split("/")[1])) {
|
48
|
+
|
49
|
+
/**
|
50
|
+
* for scoped packages, insert the prefix after the first / unless
|
51
|
+
* the path is already @scope/eslint or @scope/eslint-xxx-yyy
|
52
|
+
*/
|
53
|
+
name = name.replace(/^@([^/]+)\/(.*)$/, `@$1/${prefix}-$2`);
|
54
|
+
}
|
55
|
+
} else if (name.indexOf(`${prefix}-`) !== 0) {
|
56
|
+
name = `${prefix}-${name}`;
|
57
|
+
}
|
58
|
+
|
59
|
+
return name;
|
60
|
+
}
|
61
|
+
|
62
|
+
/**
|
63
|
+
* Removes the prefix from a term.
|
64
|
+
* @param {string} prefix The prefix to remove.
|
65
|
+
* @param {string} term The term which may have the prefix.
|
66
|
+
* @returns {string} The term without prefix.
|
67
|
+
*/
|
68
|
+
function removePrefixFromTerm(prefix, term) {
|
69
|
+
return term.startsWith(prefix) ? term.slice(prefix.length) : term;
|
70
|
+
}
|
71
|
+
|
72
|
+
/**
|
73
|
+
* Adds a prefix to a term.
|
74
|
+
* @param {string} prefix The prefix to add.
|
75
|
+
* @param {string} term The term which may not have the prefix.
|
76
|
+
* @returns {string} The term with prefix.
|
77
|
+
*/
|
78
|
+
function addPrefixToTerm(prefix, term) {
|
79
|
+
return term.startsWith(prefix) ? term : `${prefix}${term}`;
|
80
|
+
}
|
81
|
+
|
82
|
+
/**
|
83
|
+
* Gets the scope (namespace) of a term.
|
84
|
+
* @param {string} term The term which may have the namespace.
|
85
|
+
* @returns {string} The namepace of the term if it has one.
|
86
|
+
*/
|
87
|
+
function getNamespaceFromTerm(term) {
|
88
|
+
const match = term.match(NAMESPACE_REGEX);
|
89
|
+
|
90
|
+
return match ? match[0] : "";
|
91
|
+
}
|
92
|
+
|
93
|
+
/**
|
94
|
+
* Removes the namespace from a term.
|
95
|
+
* @param {string} term The term which may have the namespace.
|
96
|
+
* @returns {string} The name of the plugin without the namespace.
|
97
|
+
*/
|
98
|
+
function removeNamespaceFromTerm(term) {
|
99
|
+
return term.replace(NAMESPACE_REGEX, "");
|
100
|
+
}
|
101
|
+
|
102
|
+
//------------------------------------------------------------------------------
|
103
|
+
// Public Interface
|
104
|
+
//------------------------------------------------------------------------------
|
105
|
+
|
106
|
+
module.exports = {
|
107
|
+
normalizePackageName,
|
108
|
+
removePrefixFromTerm,
|
109
|
+
addPrefixToTerm,
|
110
|
+
getNamespaceFromTerm,
|
111
|
+
removeNamespaceFromTerm
|
112
|
+
};
|
@@ -33,10 +33,10 @@ const lodash = require("lodash");
|
|
33
33
|
//------------------------------------------------------------------------------
|
34
34
|
|
35
35
|
/**
|
36
|
-
* Gets the possible types of a selector
|
37
|
-
* @param {Object} parsedSelector An object (from esquery) describing the matching behavior of the selector
|
38
|
-
* @returns {string[]|null} The node types that could possibly trigger this selector, or `null` if all node types could trigger it
|
39
|
-
*/
|
36
|
+
* Gets the possible types of a selector
|
37
|
+
* @param {Object} parsedSelector An object (from esquery) describing the matching behavior of the selector
|
38
|
+
* @returns {string[]|null} The node types that could possibly trigger this selector, or `null` if all node types could trigger it
|
39
|
+
*/
|
40
40
|
function getPossibleTypes(parsedSelector) {
|
41
41
|
switch (parsedSelector.type) {
|
42
42
|
case "identifier":
|
@@ -160,7 +160,7 @@ function tryParseSelector(rawSelector) {
|
|
160
160
|
return esquery.parse(rawSelector.replace(/:exit$/, ""));
|
161
161
|
} catch (err) {
|
162
162
|
if (typeof err.offset === "number") {
|
163
|
-
throw new
|
163
|
+
throw new SyntaxError(`Syntax error in selector "${rawSelector}" at position ${err.offset}: ${err.message}`);
|
164
164
|
}
|
165
165
|
throw err;
|
166
166
|
}
|
@@ -194,7 +194,7 @@ const parseSelector = lodash.memoize(rawSelector => {
|
|
194
194
|
*
|
195
195
|
* ```ts
|
196
196
|
* interface EventGenerator {
|
197
|
-
* emitter:
|
197
|
+
* emitter: SafeEmitter;
|
198
198
|
* enterNode(node: ASTNode): void;
|
199
199
|
* leaveNode(node: ASTNode): void;
|
200
200
|
* }
|
@@ -203,10 +203,12 @@ const parseSelector = lodash.memoize(rawSelector => {
|
|
203
203
|
class NodeEventGenerator {
|
204
204
|
|
205
205
|
/**
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
206
|
+
* @param {SafeEmitter} emitter
|
207
|
+
* An SafeEmitter which is the destination of events. This emitter must already
|
208
|
+
* have registered listeners for all of the events that it needs to listen for.
|
209
|
+
* (See lib/util/safe-emitter.js for more details on `SafeEmitter`.)
|
210
|
+
* @returns {NodeEventGenerator} new instance
|
211
|
+
*/
|
210
212
|
constructor(emitter) {
|
211
213
|
this.emitter = emitter;
|
212
214
|
this.currentAncestry = [];
|
@@ -215,23 +217,7 @@ class NodeEventGenerator {
|
|
215
217
|
this.anyTypeEnterSelectors = [];
|
216
218
|
this.anyTypeExitSelectors = [];
|
217
219
|
|
218
|
-
|
219
|
-
|
220
|
-
// Use the built-in eventNames() function if available (Node 6+)
|
221
|
-
? emitter.eventNames()
|
222
|
-
|
223
|
-
/*
|
224
|
-
* Otherwise, use the private _events property.
|
225
|
-
* Using a private property isn't ideal here, but this seems to
|
226
|
-
* be the best way to get a list of event names without overriding
|
227
|
-
* addEventListener, which would hurt performance. This property
|
228
|
-
* is widely used and unlikely to be removed in a future version
|
229
|
-
* (see https://github.com/nodejs/node/issues/1817). Also, future
|
230
|
-
* node versions will have eventNames() anyway.
|
231
|
-
*/
|
232
|
-
: Object.keys(emitter._events); // eslint-disable-line no-underscore-dangle
|
233
|
-
|
234
|
-
eventNames.forEach(rawSelector => {
|
220
|
+
emitter.eventNames().forEach(rawSelector => {
|
235
221
|
const selector = parseSelector(rawSelector);
|
236
222
|
|
237
223
|
if (selector.listenerTypes) {
|
@@ -0,0 +1,54 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview A variant of EventEmitter which does not give listeners information about each other
|
3
|
+
* @author Teddy Katz
|
4
|
+
*/
|
5
|
+
|
6
|
+
"use strict";
|
7
|
+
|
8
|
+
//------------------------------------------------------------------------------
|
9
|
+
// Typedefs
|
10
|
+
//------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
/**
|
13
|
+
* An event emitter
|
14
|
+
* @typedef {Object} SafeEmitter
|
15
|
+
* @property {function(eventName: string, listenerFunc: Function): void} on Adds a listener for a given event name
|
16
|
+
* @property {function(eventName: string, arg1?: any, arg2?: any, arg3?: any)} emit Emits an event with a given name.
|
17
|
+
* This calls all the listeners that were listening for that name, with `arg1`, `arg2`, and `arg3` as arguments.
|
18
|
+
* @property {function(): string[]} eventNames Gets the list of event names that have registered listeners.
|
19
|
+
*/
|
20
|
+
|
21
|
+
/**
|
22
|
+
* Creates an object which can listen for and emit events.
|
23
|
+
* This is similar to the EventEmitter API in Node's standard library, but it has a few differences.
|
24
|
+
* The goal is to allow multiple modules to attach arbitrary listeners to the same emitter, without
|
25
|
+
* letting the modules know about each other at all.
|
26
|
+
* 1. It has no special keys like `error` and `newListener`, which would allow modules to detect when
|
27
|
+
* another module throws an error or registers a listener.
|
28
|
+
* 2. It calls listener functions without any `this` value. (`EventEmitter` calls listeners with a
|
29
|
+
* `this` value of the emitter instance, which would give listeners access to other listeners.)
|
30
|
+
* 3. Events can be emitted with at most 3 arguments. (For example: when using `emitter.emit('foo', a, b, c)`,
|
31
|
+
* the arguments `a`, `b`, and `c` will be passed to the listener functions.)
|
32
|
+
* @returns {SafeEmitter} An emitter
|
33
|
+
*/
|
34
|
+
module.exports = () => {
|
35
|
+
const listeners = Object.create(null);
|
36
|
+
|
37
|
+
return Object.freeze({
|
38
|
+
on(eventName, listener) {
|
39
|
+
if (eventName in listeners) {
|
40
|
+
listeners[eventName].push(listener);
|
41
|
+
} else {
|
42
|
+
listeners[eventName] = [listener];
|
43
|
+
}
|
44
|
+
},
|
45
|
+
emit(eventName, a, b, c) {
|
46
|
+
if (eventName in listeners) {
|
47
|
+
listeners[eventName].forEach(listener => listener(a, b, c));
|
48
|
+
}
|
49
|
+
},
|
50
|
+
eventNames() {
|
51
|
+
return Object.keys(listeners);
|
52
|
+
}
|
53
|
+
});
|
54
|
+
};
|
@@ -122,8 +122,10 @@ SourceCodeFixer.applyFixes = function(sourceText, messages, shouldFix) {
|
|
122
122
|
if (typeof shouldFix !== "function" || shouldFix(problem)) {
|
123
123
|
attemptFix(problem);
|
124
124
|
|
125
|
-
|
126
|
-
|
125
|
+
/*
|
126
|
+
* The only time attemptFix will fail is if a previous fix was
|
127
|
+
* applied which conflicts with it. So we can mark this as true.
|
128
|
+
*/
|
127
129
|
fixesWereApplied = true;
|
128
130
|
} else {
|
129
131
|
remainingMessages.push(problem);
|