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.
Files changed (139) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/README.md +34 -19
  3. package/conf/default-cli-options.js +7 -4
  4. package/conf/eslint-recommended.js +2 -0
  5. package/lib/ast-utils.js +83 -42
  6. package/lib/cli-engine.js +53 -17
  7. package/lib/cli.js +17 -9
  8. package/lib/code-path-analysis/code-path-analyzer.js +8 -4
  9. package/lib/code-path-analysis/code-path-segment.js +43 -41
  10. package/lib/code-path-analysis/code-path-state.js +7 -2
  11. package/lib/config/autoconfig.js +14 -12
  12. package/lib/config/config-file.js +8 -51
  13. package/lib/config/config-initializer.js +10 -6
  14. package/lib/config/config-ops.js +21 -21
  15. package/lib/config/config-rule.js +24 -24
  16. package/lib/config/config-validator.js +38 -36
  17. package/lib/config/plugins.js +8 -35
  18. package/lib/config.js +12 -8
  19. package/lib/formatters/html-template-message.html +1 -1
  20. package/lib/formatters/html-template-page.html +3 -1
  21. package/lib/formatters/html.js +2 -1
  22. package/lib/formatters/junit.js +21 -15
  23. package/lib/formatters/tap.js +5 -3
  24. package/lib/ignored-paths.js +5 -3
  25. package/lib/linter.js +42 -42
  26. package/lib/logging.js +2 -2
  27. package/lib/options.js +12 -0
  28. package/lib/rules/.eslintrc.yml +2 -2
  29. package/lib/rules/array-bracket-newline.js +39 -25
  30. package/lib/rules/array-bracket-spacing.js +28 -28
  31. package/lib/rules/array-callback-return.js +13 -9
  32. package/lib/rules/array-element-newline.js +8 -8
  33. package/lib/rules/arrow-body-style.js +12 -6
  34. package/lib/rules/arrow-parens.js +4 -2
  35. package/lib/rules/block-spacing.js +1 -1
  36. package/lib/rules/brace-style.js +14 -14
  37. package/lib/rules/callback-return.js +2 -1
  38. package/lib/rules/capitalized-comments.js +2 -1
  39. package/lib/rules/comma-style.js +3 -1
  40. package/lib/rules/computed-property-spacing.js +22 -22
  41. package/lib/rules/consistent-return.js +4 -4
  42. package/lib/rules/consistent-this.js +4 -2
  43. package/lib/rules/curly.js +13 -9
  44. package/lib/rules/dot-notation.js +56 -35
  45. package/lib/rules/func-call-spacing.js +4 -2
  46. package/lib/rules/generator-star-spacing.js +3 -3
  47. package/lib/rules/getter-return.js +2 -1
  48. package/lib/rules/indent-legacy.js +25 -14
  49. package/lib/rules/indent.js +101 -91
  50. package/lib/rules/key-spacing.js +5 -3
  51. package/lib/rules/lines-around-comment.js +33 -4
  52. package/lib/rules/lines-around-directive.js +16 -12
  53. package/lib/rules/lines-between-class-members.js +91 -0
  54. package/lib/rules/max-len.js +2 -3
  55. package/lib/rules/max-statements-per-line.js +5 -3
  56. package/lib/rules/multiline-comment-style.js +294 -0
  57. package/lib/rules/new-cap.js +2 -1
  58. package/lib/rules/newline-after-var.js +8 -6
  59. package/lib/rules/newline-before-return.js +13 -9
  60. package/lib/rules/no-alert.js +7 -15
  61. package/lib/rules/no-await-in-loop.js +17 -9
  62. package/lib/rules/no-bitwise.js +5 -3
  63. package/lib/rules/no-catch-shadow.js +4 -2
  64. package/lib/rules/no-console.js +2 -1
  65. package/lib/rules/no-constant-condition.js +2 -2
  66. package/lib/rules/no-control-regex.js +2 -1
  67. package/lib/rules/no-else-return.js +60 -19
  68. package/lib/rules/no-empty-character-class.js +11 -11
  69. package/lib/rules/no-extra-parens.js +22 -11
  70. package/lib/rules/no-extra-semi.js +5 -3
  71. package/lib/rules/no-global-assign.js +4 -2
  72. package/lib/rules/no-implicit-coercion.js +6 -6
  73. package/lib/rules/no-implied-eval.js +2 -1
  74. package/lib/rules/no-label-var.js +4 -2
  75. package/lib/rules/no-lone-blocks.js +3 -3
  76. package/lib/rules/no-lonely-if.js +2 -1
  77. package/lib/rules/no-loop-func.js +10 -7
  78. package/lib/rules/no-mixed-requires.js +8 -4
  79. package/lib/rules/no-native-reassign.js +4 -2
  80. package/lib/rules/no-param-reassign.js +4 -2
  81. package/lib/rules/no-regex-spaces.js +1 -1
  82. package/lib/rules/no-restricted-imports.js +86 -17
  83. package/lib/rules/no-restricted-modules.js +84 -15
  84. package/lib/rules/no-restricted-properties.js +10 -10
  85. package/lib/rules/no-return-await.js +6 -6
  86. package/lib/rules/no-self-assign.js +4 -2
  87. package/lib/rules/no-sequences.js +6 -4
  88. package/lib/rules/no-trailing-spaces.js +14 -8
  89. package/lib/rules/no-unneeded-ternary.js +3 -1
  90. package/lib/rules/no-unreachable.js +4 -2
  91. package/lib/rules/no-unused-labels.js +2 -1
  92. package/lib/rules/no-use-before-define.js +13 -11
  93. package/lib/rules/no-useless-call.js +1 -25
  94. package/lib/rules/no-useless-computed-key.js +2 -1
  95. package/lib/rules/no-useless-escape.js +31 -23
  96. package/lib/rules/no-useless-return.js +14 -8
  97. package/lib/rules/no-var.js +11 -0
  98. package/lib/rules/no-whitespace-before-property.js +4 -2
  99. package/lib/rules/object-curly-newline.js +9 -2
  100. package/lib/rules/object-curly-spacing.js +20 -20
  101. package/lib/rules/object-shorthand.js +47 -35
  102. package/lib/rules/operator-assignment.js +9 -9
  103. package/lib/rules/operator-linebreak.js +15 -11
  104. package/lib/rules/padding-line-between-statements.js +6 -4
  105. package/lib/rules/prefer-arrow-callback.js +12 -10
  106. package/lib/rules/prefer-const.js +18 -10
  107. package/lib/rules/prefer-destructuring.js +4 -2
  108. package/lib/rules/prefer-numeric-literals.js +4 -2
  109. package/lib/rules/prefer-promise-reject-errors.js +16 -16
  110. package/lib/rules/prefer-rest-params.js +4 -2
  111. package/lib/rules/prefer-spread.js +1 -25
  112. package/lib/rules/prefer-template.js +33 -29
  113. package/lib/rules/quote-props.js +8 -8
  114. package/lib/rules/require-jsdoc.js +11 -18
  115. package/lib/rules/semi-style.js +44 -19
  116. package/lib/rules/semi.js +5 -3
  117. package/lib/rules/sort-imports.js +11 -6
  118. package/lib/rules/space-unary-ops.js +67 -69
  119. package/lib/rules/strict.js +8 -8
  120. package/lib/rules/valid-jsdoc.js +39 -33
  121. package/lib/rules/valid-typeof.js +4 -4
  122. package/lib/rules/wrap-iife.js +4 -4
  123. package/lib/rules/yoda.js +9 -7
  124. package/lib/testers/rule-tester.js +63 -40
  125. package/lib/token-store/backward-token-cursor.js +5 -3
  126. package/lib/token-store/forward-token-cursor.js +5 -3
  127. package/lib/token-store/utils.js +8 -4
  128. package/lib/util/apply-disable-directives.js +56 -27
  129. package/lib/util/glob.js +1 -1
  130. package/lib/util/naming.js +112 -0
  131. package/lib/util/node-event-generator.js +13 -27
  132. package/lib/util/safe-emitter.js +54 -0
  133. package/lib/util/source-code-fixer.js +4 -2
  134. package/lib/util/source-code.js +70 -65
  135. package/messages/no-config-found.txt +1 -1
  136. package/package.json +8 -8
  137. package/lib/internal-rules/.eslintrc.yml +0 -3
  138. package/lib/internal-rules/internal-consistent-docs-description.js +0 -130
  139. package/lib/internal-rules/internal-no-invalid-meta.js +0 -188
@@ -45,9 +45,11 @@ module.exports = class ForwardTokenCursor extends Cursor {
45
45
  return false;
46
46
  }
47
47
 
48
- //
49
- // Shorthand for performance.
50
- //
48
+ /*
49
+ *
50
+ * Shorthand for performance.
51
+ *
52
+ */
51
53
 
52
54
  /** @inheritdoc */
53
55
  getOneToken() {
@@ -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
- // For the map of "comment's location -> token's index", it points the next token of a comment.
66
- // In that case, +1 is unnecessary.
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
- // For the map of "comment's location -> token's index", it points the next token of a comment.
93
- // In that case, -1 is necessary.
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 doesn't handle disable-line and disable-next-line directives.
23
- * @param {Object} options options (see the exported function)
24
- * @returns {Problem[]} Filtered problems (see the exported function)
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 globalDisableActive = false;
34
+ let currentGlobalDisableDirective = null;
35
+ const disabledRuleMap = new Map();
30
36
 
31
- // disabledRules is only used when there is no active global /* eslint-disable */ comment.
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
- globalDisableActive = true;
51
+ currentGlobalDisableDirective = directive;
52
+ disabledRuleMap.clear();
48
53
  enabledRules.clear();
49
- } else if (globalDisableActive) {
54
+ } else if (currentGlobalDisableDirective) {
50
55
  enabledRules.delete(directive.ruleId);
56
+ disabledRuleMap.set(directive.ruleId, directive);
51
57
  } else {
52
- disabledRules.add(directive.ruleId);
58
+ disabledRuleMap.set(directive.ruleId, directive);
53
59
  }
54
60
  break;
55
61
 
56
62
  case "enable":
57
63
  if (directive.ruleId === null) {
58
- globalDisableActive = false;
59
- disabledRules.clear();
60
- } else if (globalDisableActive) {
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
- disabledRules.delete(directive.ruleId);
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
- globalDisableActive && enabledRules.has(problem.ruleId) ||
73
- !globalDisableActive && !disabledRules.has(problem.ruleId)
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
- return problems;
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 problemsAfterBlockDirectives = applyDirectives({ problems: options.problems, directives: blockDirectives });
128
- const problemsAfterLineDirectives = applyDirectives({ problems: problemsAfterBlockDirectives, directives: lineDirectives });
151
+ const blockDirectivesResult = applyDirectives({ problems: options.problems, directives: blockDirectives });
152
+ const lineDirectivesResult = applyDirectives({ problems: blockDirectivesResult.problems, directives: lineDirectives });
129
153
 
130
- return problemsAfterLineDirectives.sort(compareLocations);
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 Error(`Syntax error in selector "${rawSelector}" at position ${err.offset}: ${err.message}`);
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: EventEmitter;
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
- * @param {EventEmitter} emitter - An event emitter which is the destination of events. This emitter must already
207
- * have registered listeners for all of the events that it needs to listen for.
208
- * @returns {NodeEventGenerator} new instance
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
- const eventNames = typeof emitter.eventNames === "function"
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
- // The only time attemptFix will fail is if a previous fix was
126
- // applied which conflicts with it. So we can mark this as true.
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);