eslint 3.15.0 → 3.17.1

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 (118) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/conf/{eslint.json → eslint-recommended.js} +87 -71
  3. package/lib/ast-utils.js +182 -80
  4. package/lib/code-path-analysis/code-path-state.js +2 -2
  5. package/lib/config/autoconfig.js +3 -3
  6. package/lib/config/config-file.js +14 -7
  7. package/lib/config/config-initializer.js +1 -1
  8. package/lib/config.js +3 -2
  9. package/lib/eslint.js +4 -4
  10. package/lib/internal-rules/internal-no-invalid-meta.js +2 -40
  11. package/lib/rules/array-callback-return.js +15 -5
  12. package/lib/rules/arrow-body-style.js +7 -4
  13. package/lib/rules/arrow-spacing.js +7 -6
  14. package/lib/rules/block-spacing.js +2 -2
  15. package/lib/rules/brace-style.js +2 -6
  16. package/lib/rules/capitalized-comments.js +8 -7
  17. package/lib/rules/comma-spacing.js +3 -3
  18. package/lib/rules/complexity.js +14 -8
  19. package/lib/rules/consistent-return.js +18 -11
  20. package/lib/rules/constructor-super.js +3 -3
  21. package/lib/rules/curly.js +11 -7
  22. package/lib/rules/default-case.js +3 -3
  23. package/lib/rules/eqeqeq.js +15 -6
  24. package/lib/rules/func-call-spacing.js +10 -13
  25. package/lib/rules/func-names.js +20 -5
  26. package/lib/rules/generator-star-spacing.js +18 -19
  27. package/lib/rules/id-blacklist.js +2 -2
  28. package/lib/rules/id-length.js +3 -3
  29. package/lib/rules/id-match.js +2 -2
  30. package/lib/rules/indent.js +7 -6
  31. package/lib/rules/key-spacing.js +12 -16
  32. package/lib/rules/keyword-spacing.js +21 -17
  33. package/lib/rules/line-comment-position.js +16 -6
  34. package/lib/rules/linebreak-style.js +7 -1
  35. package/lib/rules/lines-around-comment.js +23 -4
  36. package/lib/rules/lines-around-directive.js +3 -3
  37. package/lib/rules/max-lines.js +2 -2
  38. package/lib/rules/max-params.js +17 -4
  39. package/lib/rules/max-statements-per-line.js +7 -6
  40. package/lib/rules/max-statements.js +11 -10
  41. package/lib/rules/newline-after-var.js +7 -2
  42. package/lib/rules/newline-per-chained-call.js +3 -1
  43. package/lib/rules/no-compare-neg-zero.js +53 -0
  44. package/lib/rules/no-cond-assign.js +3 -3
  45. package/lib/rules/no-else-return.js +13 -1
  46. package/lib/rules/no-empty-function.js +9 -16
  47. package/lib/rules/no-extend-native.js +3 -3
  48. package/lib/rules/no-extra-bind.js +3 -4
  49. package/lib/rules/no-extra-boolean-cast.js +8 -0
  50. package/lib/rules/no-extra-parens.js +1 -2
  51. package/lib/rules/no-extra-semi.js +13 -1
  52. package/lib/rules/no-inner-declarations.js +4 -4
  53. package/lib/rules/no-invalid-regexp.js +2 -1
  54. package/lib/rules/no-irregular-whitespace.js +7 -1
  55. package/lib/rules/no-lone-blocks.js +10 -10
  56. package/lib/rules/no-mixed-operators.js +1 -7
  57. package/lib/rules/no-multi-spaces.js +4 -1
  58. package/lib/rules/no-multi-str.js +7 -3
  59. package/lib/rules/no-multiple-empty-lines.js +2 -4
  60. package/lib/rules/no-param-reassign.js +29 -6
  61. package/lib/rules/no-restricted-properties.js +2 -0
  62. package/lib/rules/no-return-assign.js +7 -14
  63. package/lib/rules/no-return-await.js +1 -1
  64. package/lib/rules/no-sequences.js +7 -6
  65. package/lib/rules/no-trailing-spaces.js +8 -2
  66. package/lib/rules/no-undefined.js +45 -6
  67. package/lib/rules/no-unexpected-multiline.js +9 -8
  68. package/lib/rules/no-unneeded-ternary.js +5 -1
  69. package/lib/rules/no-unused-labels.js +17 -2
  70. package/lib/rules/no-unused-vars.js +13 -27
  71. package/lib/rules/no-use-before-define.js +1 -1
  72. package/lib/rules/no-useless-computed-key.js +8 -3
  73. package/lib/rules/no-useless-concat.js +10 -7
  74. package/lib/rules/no-useless-escape.js +2 -2
  75. package/lib/rules/no-useless-return.js +14 -9
  76. package/lib/rules/no-var.js +1 -3
  77. package/lib/rules/no-whitespace-before-property.js +5 -16
  78. package/lib/rules/nonblock-statement-body-position.js +114 -0
  79. package/lib/rules/object-curly-newline.js +2 -2
  80. package/lib/rules/object-curly-spacing.js +7 -25
  81. package/lib/rules/object-property-newline.js +3 -3
  82. package/lib/rules/object-shorthand.js +4 -3
  83. package/lib/rules/operator-assignment.js +2 -2
  84. package/lib/rules/operator-linebreak.js +8 -10
  85. package/lib/rules/padded-blocks.js +39 -30
  86. package/lib/rules/prefer-destructuring.js +1 -1
  87. package/lib/rules/prefer-spread.js +1 -1
  88. package/lib/rules/prefer-template.js +1 -1
  89. package/lib/rules/quotes.js +10 -6
  90. package/lib/rules/semi-spacing.js +4 -0
  91. package/lib/rules/semi.js +13 -1
  92. package/lib/rules/space-before-function-paren.js +8 -5
  93. package/lib/rules/space-unary-ops.js +19 -1
  94. package/lib/rules/spaced-comment.js +2 -2
  95. package/lib/rules/strict.js +10 -4
  96. package/lib/rules/unicode-bom.js +1 -1
  97. package/lib/rules/wrap-iife.js +5 -5
  98. package/lib/rules/yoda.js +4 -9
  99. package/lib/testers/rule-tester.js +46 -9
  100. package/lib/token-store/backward-token-comment-cursor.js +57 -0
  101. package/lib/token-store/backward-token-cursor.js +56 -0
  102. package/lib/token-store/cursor.js +76 -0
  103. package/lib/token-store/cursors.js +92 -0
  104. package/lib/token-store/decorative-cursor.js +39 -0
  105. package/lib/token-store/filter-cursor.js +43 -0
  106. package/lib/token-store/forward-token-comment-cursor.js +57 -0
  107. package/lib/token-store/forward-token-cursor.js +61 -0
  108. package/lib/token-store/index.js +604 -0
  109. package/lib/token-store/limit-cursor.js +40 -0
  110. package/lib/token-store/padded-token-cursor.js +38 -0
  111. package/lib/token-store/skip-cursor.js +42 -0
  112. package/lib/token-store/utils.js +100 -0
  113. package/lib/util/fix-tracker.js +121 -0
  114. package/lib/util/source-code-fixer.js +35 -39
  115. package/lib/util/source-code.js +129 -16
  116. package/messages/extend-config-missing.txt +3 -0
  117. package/package.json +5 -6
  118. package/lib/token-store.js +0 -203
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @fileoverview Define the cursor which ignores the first few tokens.
3
+ * @author Toru Nagashima
4
+ */
5
+ "use strict";
6
+
7
+ //------------------------------------------------------------------------------
8
+ // Requirements
9
+ //------------------------------------------------------------------------------
10
+
11
+ const DecorativeCursor = require("./decorative-cursor");
12
+
13
+ //------------------------------------------------------------------------------
14
+ // Exports
15
+ //------------------------------------------------------------------------------
16
+
17
+ /**
18
+ * The decorative cursor which ignores the first few tokens.
19
+ */
20
+ module.exports = class SkipCursor extends DecorativeCursor {
21
+
22
+ /**
23
+ * Initializes this cursor.
24
+ * @param {Cursor} cursor - The cursor to be decorated.
25
+ * @param {number} count - The count of tokens this cursor skips.
26
+ */
27
+ constructor(cursor, count) {
28
+ super(cursor);
29
+ this.count = count;
30
+ }
31
+
32
+ /** @inheritdoc */
33
+ moveNext() {
34
+ while (this.count > 0) {
35
+ this.count -= 1;
36
+ if (!super.moveNext()) {
37
+ return false;
38
+ }
39
+ }
40
+ return super.moveNext();
41
+ }
42
+ };
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @fileoverview Define utilify functions for token store.
3
+ * @author Toru Nagashima
4
+ */
5
+ "use strict";
6
+
7
+ //------------------------------------------------------------------------------
8
+ // Requirements
9
+ //------------------------------------------------------------------------------
10
+
11
+ const lodash = require("lodash");
12
+
13
+ //------------------------------------------------------------------------------
14
+ // Helpers
15
+ //------------------------------------------------------------------------------
16
+
17
+ /**
18
+ * Gets `token.range[0]` from the given token.
19
+ *
20
+ * @param {Node|Token|Comment} token - The token to get.
21
+ * @returns {number} The start location.
22
+ * @private
23
+ */
24
+ function getStartLocation(token) {
25
+ return token.range[0];
26
+ }
27
+
28
+ //------------------------------------------------------------------------------
29
+ // Exports
30
+ //------------------------------------------------------------------------------
31
+
32
+ /**
33
+ * Binary-searches the index of the first token which is after the given location.
34
+ * If it was not found, this returns `tokens.length`.
35
+ *
36
+ * @param {(Token|Comment)[]} tokens - It searches the token in this list.
37
+ * @param {number} location - The location to search.
38
+ * @returns {number} The found index or `tokens.length`.
39
+ */
40
+ exports.search = function search(tokens, location) {
41
+ return lodash.sortedIndexBy(
42
+ tokens,
43
+ { range: [location] },
44
+ getStartLocation
45
+ );
46
+ };
47
+
48
+ /**
49
+ * Gets the index of the `startLoc` in `tokens`.
50
+ * `startLoc` can be the value of `node.range[1]`, so this checks about `startLoc - 1` as well.
51
+ *
52
+ * @param {(Token|Comment)[]} tokens - The tokens to find an index.
53
+ * @param {Object} indexMap - The map from locations to indices.
54
+ * @param {number} startLoc - The location to get an index.
55
+ * @returns {number} The index.
56
+ */
57
+ exports.getFirstIndex = function getFirstIndex(tokens, indexMap, startLoc) {
58
+ if (startLoc in indexMap) {
59
+ return indexMap[startLoc];
60
+ }
61
+ if ((startLoc - 1) in indexMap) {
62
+ const index = indexMap[startLoc - 1];
63
+ const token = (index >= 0 && index < tokens.length) ? tokens[index] : null;
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.
67
+ if (token && token.range[0] >= startLoc) {
68
+ return index;
69
+ }
70
+ return index + 1;
71
+ }
72
+ return 0;
73
+ };
74
+
75
+ /**
76
+ * Gets the index of the `endLoc` in `tokens`.
77
+ * The information of end locations are recorded at `endLoc - 1` in `indexMap`, so this checks about `endLoc - 1` as well.
78
+ *
79
+ * @param {(Token|Comment)[]} tokens - The tokens to find an index.
80
+ * @param {Object} indexMap - The map from locations to indices.
81
+ * @param {number} endLoc - The location to get an index.
82
+ * @returns {number} The index.
83
+ */
84
+ exports.getLastIndex = function getLastIndex(tokens, indexMap, endLoc) {
85
+ if (endLoc in indexMap) {
86
+ return indexMap[endLoc] - 1;
87
+ }
88
+ if ((endLoc - 1) in indexMap) {
89
+ const index = indexMap[endLoc - 1];
90
+ const token = (index >= 0 && index < tokens.length) ? tokens[index] : null;
91
+
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
+ if (token && token.range[1] > endLoc) {
95
+ return index - 1;
96
+ }
97
+ return index;
98
+ }
99
+ return tokens.length - 1;
100
+ };
@@ -0,0 +1,121 @@
1
+ /**
2
+ * @fileoverview Helper class to aid in constructing fix commands.
3
+ * @author Alan Pierce
4
+ */
5
+ "use strict";
6
+
7
+ //------------------------------------------------------------------------------
8
+ // Requirements
9
+ //------------------------------------------------------------------------------
10
+
11
+ const astUtils = require("../ast-utils");
12
+
13
+ //------------------------------------------------------------------------------
14
+ // Public Interface
15
+ //------------------------------------------------------------------------------
16
+
17
+ /**
18
+ * A helper class to combine fix options into a fix command. Currently, it
19
+ * exposes some "retain" methods that extend the range of the text being
20
+ * replaced so that other fixes won't touch that region in the same pass.
21
+ */
22
+ class FixTracker {
23
+
24
+ /**
25
+ * Create a new FixTracker.
26
+ *
27
+ * @param {ruleFixer} fixer A ruleFixer instance.
28
+ * @param {SourceCode} sourceCode A SourceCode object for the current code.
29
+ */
30
+ constructor(fixer, sourceCode) {
31
+ this.fixer = fixer;
32
+ this.sourceCode = sourceCode;
33
+ this.retainedRange = null;
34
+ }
35
+
36
+ /**
37
+ * Mark the given range as "retained", meaning that other fixes may not
38
+ * may not modify this region in the same pass.
39
+ *
40
+ * @param {int[]} range The range to retain.
41
+ * @returns {FixTracker} The same RuleFixer, for chained calls.
42
+ */
43
+ retainRange(range) {
44
+ this.retainedRange = range;
45
+ return this;
46
+ }
47
+
48
+ /**
49
+ * Given a node, find the function containing it (or the entire program) and
50
+ * mark it as retained, meaning that other fixes may not modify it in this
51
+ * pass. This is useful for avoiding conflicts in fixes that modify control
52
+ * flow.
53
+ *
54
+ * @param {ASTNode} node The node to use as a starting point.
55
+ * @returns {FixTracker} The same RuleFixer, for chained calls.
56
+ */
57
+ retainEnclosingFunction(node) {
58
+ const functionNode = astUtils.getUpperFunction(node);
59
+
60
+ return this.retainRange(
61
+ functionNode ? functionNode.range : this.sourceCode.ast.range);
62
+ }
63
+
64
+ /**
65
+ * Given a node or token, find the token before and afterward, and mark that
66
+ * range as retained, meaning that other fixes may not modify it in this
67
+ * pass. This is useful for avoiding conflicts in fixes that make a small
68
+ * change to the code where the AST should not be changed.
69
+ *
70
+ * @param {ASTNode|Token} nodeOrToken The node or token to use as a starting
71
+ * point. The token to the left and right are use in the range.
72
+ * @returns {FixTracker} The same RuleFixer, for chained calls.
73
+ */
74
+ retainSurroundingTokens(nodeOrToken) {
75
+ const tokenBefore = this.sourceCode.getTokenBefore(nodeOrToken) || nodeOrToken;
76
+ const tokenAfter = this.sourceCode.getTokenAfter(nodeOrToken) || nodeOrToken;
77
+
78
+ return this.retainRange([tokenBefore.range[0], tokenAfter.range[1]]);
79
+ }
80
+
81
+ /**
82
+ * Create a fix command that replaces the given range with the given text,
83
+ * accounting for any retained ranges.
84
+ *
85
+ * @param {int[]} range The range to remove in the fix.
86
+ * @param {string} text The text to insert in place of the range.
87
+ * @returns {Object} The fix command.
88
+ */
89
+ replaceTextRange(range, text) {
90
+ let actualRange;
91
+
92
+ if (this.retainedRange) {
93
+ actualRange = [
94
+ Math.min(this.retainedRange[0], range[0]),
95
+ Math.max(this.retainedRange[1], range[1])
96
+ ];
97
+ } else {
98
+ actualRange = range;
99
+ }
100
+
101
+ return this.fixer.replaceTextRange(
102
+ actualRange,
103
+ this.sourceCode.text.slice(actualRange[0], range[0]) +
104
+ text +
105
+ this.sourceCode.text.slice(range[1], actualRange[1])
106
+ );
107
+ }
108
+
109
+ /**
110
+ * Create a fix command that removes the given node or token, accounting for
111
+ * any retained ranges.
112
+ *
113
+ * @param {ASTNode|Token} nodeOrToken The node or token to remove.
114
+ * @returns {Object} The fix command.
115
+ */
116
+ remove(nodeOrToken) {
117
+ return this.replaceTextRange(nodeOrToken.range, "");
118
+ }
119
+ }
120
+
121
+ module.exports = FixTracker;
@@ -16,6 +16,17 @@ const debug = require("debug")("eslint:text-fixer");
16
16
 
17
17
  const BOM = "\uFEFF";
18
18
 
19
+ /**
20
+ * Compares items in a messages array by range.
21
+ * @param {Message} a The first message.
22
+ * @param {Message} b The second message.
23
+ * @returns {int} -1 if a comes before b, 1 if a comes after b, 0 if equal.
24
+ * @private
25
+ */
26
+ function compareMessagesByFixRange(a, b) {
27
+ return a.fix.range[0] - b.fix.range[0] || a.fix.range[1] - b.fix.range[1];
28
+ }
29
+
19
30
  /**
20
31
  * Compares items in a messages array by line and column.
21
32
  * @param {Message} a The first message.
@@ -24,13 +35,7 @@ const BOM = "\uFEFF";
24
35
  * @private
25
36
  */
26
37
  function compareMessagesByLocation(a, b) {
27
- const lineDiff = a.line - b.line;
28
-
29
- if (lineDiff === 0) {
30
- return a.column - b.column;
31
- }
32
- return lineDiff;
33
-
38
+ return a.line - b.line || a.column - b.column;
34
39
  }
35
40
 
36
41
  //------------------------------------------------------------------------------
@@ -68,9 +73,10 @@ SourceCodeFixer.applyFixes = function(sourceCode, messages) {
68
73
  // clone the array
69
74
  const remainingMessages = [],
70
75
  fixes = [],
76
+ bom = (sourceCode.hasBOM ? BOM : ""),
71
77
  text = sourceCode.text;
72
- let lastFixPos = text.length + 1,
73
- prefix = (sourceCode.hasBOM ? BOM : "");
78
+ let lastPos = Number.NEGATIVE_INFINITY,
79
+ output = bom;
74
80
 
75
81
  messages.forEach(problem => {
76
82
  if (problem.hasOwnProperty("fix")) {
@@ -83,51 +89,41 @@ SourceCodeFixer.applyFixes = function(sourceCode, messages) {
83
89
  if (fixes.length) {
84
90
  debug("Found fixes to apply");
85
91
 
86
- // sort in reverse order of occurrence
87
- fixes.sort((a, b) => b.fix.range[1] - a.fix.range[1] || b.fix.range[0] - a.fix.range[0]);
88
-
89
- // split into array of characters for easier manipulation
90
- const chars = text.split("");
91
-
92
- fixes.forEach(problem => {
92
+ for (const problem of fixes.sort(compareMessagesByFixRange)) {
93
93
  const fix = problem.fix;
94
- let start = fix.range[0];
94
+ const start = fix.range[0];
95
95
  const end = fix.range[1];
96
- let insertionText = fix.text;
97
-
98
- if (end < lastFixPos) {
99
- if (start < 0) {
100
-
101
- // Remove BOM.
102
- prefix = "";
103
- start = 0;
104
- }
105
-
106
- if (start === 0 && insertionText[0] === BOM) {
107
-
108
- // Set BOM.
109
- prefix = BOM;
110
- insertionText = insertionText.slice(1);
111
- }
112
96
 
113
- chars.splice(start, end - start, insertionText);
114
- lastFixPos = start;
115
- } else {
97
+ // Remain it as a problem if it's overlapped or it's a negative range
98
+ if (lastPos >= start || start > end) {
116
99
  remainingMessages.push(problem);
100
+ continue;
117
101
  }
118
- });
102
+
103
+ // Remove BOM.
104
+ if ((start < 0 && end >= 0) || (start === 0 && fix.text.startsWith(BOM))) {
105
+ output = "";
106
+ }
107
+
108
+ // Make output to this fix.
109
+ output += text.slice(Math.max(0, lastPos), Math.max(0, start));
110
+ output += fix.text;
111
+ lastPos = end;
112
+ }
113
+ output += text.slice(Math.max(0, lastPos));
119
114
 
120
115
  return {
121
116
  fixed: true,
122
117
  messages: remainingMessages.sort(compareMessagesByLocation),
123
- output: prefix + chars.join("")
118
+ output
124
119
  };
125
120
  }
121
+
126
122
  debug("No fixes to apply");
127
123
  return {
128
124
  fixed: false,
129
125
  messages,
130
- output: prefix + text
126
+ output: bom + text
131
127
  };
132
128
 
133
129
  };
@@ -8,8 +8,10 @@
8
8
  // Requirements
9
9
  //------------------------------------------------------------------------------
10
10
 
11
- const createTokenStore = require("../token-store.js"),
12
- Traverser = require("./traverser");
11
+ const TokenStore = require("../token-store"),
12
+ Traverser = require("./traverser"),
13
+ astUtils = require("../ast-utils"),
14
+ lodash = require("lodash");
13
15
 
14
16
  //------------------------------------------------------------------------------
15
17
  // Private
@@ -77,6 +79,28 @@ function looksLikeExport(astNode) {
77
79
  astNode.type === "ExportAllDeclaration" || astNode.type === "ExportSpecifier";
78
80
  }
79
81
 
82
+ /**
83
+ * Merges two sorted lists into a larger sorted list in O(n) time
84
+ * @param {Token[]} tokens The list of tokens
85
+ * @param {Token[]} comments The list of comments
86
+ * @returns {Token[]} A sorted list of tokens and comments
87
+ */
88
+ function sortedMerge(tokens, comments) {
89
+ const result = [];
90
+ let tokenIndex = 0;
91
+ let commentIndex = 0;
92
+
93
+ while (tokenIndex < tokens.length || commentIndex < comments.length) {
94
+ if (commentIndex >= comments.length || tokenIndex < tokens.length && tokens[tokenIndex].range[0] < comments[commentIndex].range[0]) {
95
+ result.push(tokens[tokenIndex++]);
96
+ } else {
97
+ result.push(comments[commentIndex++]);
98
+ }
99
+ }
100
+
101
+ return result;
102
+ }
103
+
80
104
 
81
105
  //------------------------------------------------------------------------------
82
106
  // Public Interface
@@ -115,23 +139,35 @@ function SourceCode(text, ast) {
115
139
  * This is done to avoid each rule needing to do so separately.
116
140
  * @type string[]
117
141
  */
118
- this.lines = SourceCode.splitLines(this.text);
142
+ this.lines = [];
143
+ this.lineStartIndices = [0];
144
+
145
+ const lineEndingPattern = astUtils.createGlobalLinebreakMatcher();
146
+ let match;
147
+
148
+ /*
149
+ * Previously, this was implemented using a regex that
150
+ * matched a sequence of non-linebreak characters followed by a
151
+ * linebreak, then adding the lengths of the matches. However,
152
+ * this caused a catastrophic backtracking issue when the end
153
+ * of a file contained a large number of non-newline characters.
154
+ * To avoid this, the current implementation just matches newlines
155
+ * and uses match.index to get the correct line start indices.
156
+ */
157
+ while ((match = lineEndingPattern.exec(this.text))) {
158
+ this.lines.push(this.text.slice(this.lineStartIndices[this.lineStartIndices.length - 1], match.index));
159
+ this.lineStartIndices.push(match.index + match[0].length);
160
+ }
161
+ this.lines.push(this.text.slice(this.lineStartIndices[this.lineStartIndices.length - 1]));
119
162
 
120
- this.tokensAndComments = ast.tokens
121
- .concat(ast.comments)
122
- .sort((left, right) => left.range[0] - right.range[0]);
163
+ this.tokensAndComments = sortedMerge(ast.tokens, ast.comments);
123
164
 
124
165
  // create token store methods
125
- const tokenStore = createTokenStore(ast.tokens);
126
-
127
- Object.keys(tokenStore).forEach(methodName => {
128
- this[methodName] = tokenStore[methodName];
129
- });
130
-
131
- const tokensAndCommentsStore = createTokenStore(this.tokensAndComments);
166
+ const tokenStore = new TokenStore(ast.tokens, ast.comments);
132
167
 
133
- this.getTokenOrCommentBefore = tokensAndCommentsStore.getTokenBefore;
134
- this.getTokenOrCommentAfter = tokensAndCommentsStore.getTokenAfter;
168
+ for (const methodName of TokenStore.PUBLIC_METHODS) {
169
+ this[methodName] = tokenStore[methodName].bind(tokenStore);
170
+ }
135
171
 
136
172
  // don't allow modification of this object
137
173
  Object.freeze(this);
@@ -145,7 +181,7 @@ function SourceCode(text, ast) {
145
181
  * @public
146
182
  */
147
183
  SourceCode.splitLines = function(text) {
148
- return text.split(/\r\n|\r|\n|\u2028|\u2029/g);
184
+ return text.split(astUtils.createGlobalLinebreakMatcher());
149
185
  };
150
186
 
151
187
  SourceCode.prototype = {
@@ -296,6 +332,83 @@ SourceCode.prototype = {
296
332
  const text = this.text.slice(first.range[1], second.range[0]);
297
333
 
298
334
  return /\s/.test(text.replace(/\/\*.*?\*\//g, ""));
335
+ },
336
+
337
+ /**
338
+ * Converts a source text index into a (line, column) pair.
339
+ * @param {number} index The index of a character in a file
340
+ * @returns {Object} A {line, column} location object with a 0-indexed column
341
+ */
342
+ getLocFromIndex(index) {
343
+ if (typeof index !== "number") {
344
+ throw new TypeError("Expected `index` to be a number.");
345
+ }
346
+
347
+ if (index < 0 || index > this.text.length) {
348
+ throw new RangeError(`Index out of range (requested index ${index}, but source text has length ${this.text.length}).`);
349
+ }
350
+
351
+ /*
352
+ * For an argument of this.text.length, return the location one "spot" past the last character
353
+ * of the file. If the last character is a linebreak, the location will be column 0 of the next
354
+ * line; otherwise, the location will be in the next column on the same line.
355
+ *
356
+ * See getIndexFromLoc for the motivation for this special case.
357
+ */
358
+ if (index === this.text.length) {
359
+ return { line: this.lines.length, column: this.lines[this.lines.length - 1].length };
360
+ }
361
+
362
+ /*
363
+ * To figure out which line rangeIndex is on, determine the last index at which rangeIndex could
364
+ * be inserted into lineIndices to keep the list sorted.
365
+ */
366
+ const lineNumber = lodash.sortedLastIndex(this.lineStartIndices, index);
367
+
368
+ return { line: lineNumber, column: index - this.lineStartIndices[lineNumber - 1] };
369
+
370
+ },
371
+
372
+ /**
373
+ * Converts a (line, column) pair into a range index.
374
+ * @param {Object} loc A line/column location
375
+ * @param {number} loc.line The line number of the location (1-indexed)
376
+ * @param {number} loc.column The column number of the location (0-indexed)
377
+ * @returns {number} The range index of the location in the file.
378
+ */
379
+ getIndexFromLoc(loc) {
380
+ if (typeof loc !== "object" || typeof loc.line !== "number" || typeof loc.column !== "number") {
381
+ throw new TypeError("Expected `loc` to be an object with numeric `line` and `column` properties.");
382
+ }
383
+
384
+ if (loc.line <= 0) {
385
+ throw new RangeError(`Line number out of range (line ${loc.line} requested). Line numbers should be 1-based.`);
386
+ }
387
+
388
+ if (loc.line > this.lineStartIndices.length) {
389
+ throw new RangeError(`Line number out of range (line ${loc.line} requested, but only ${this.lineStartIndices.length} lines present).`);
390
+ }
391
+
392
+ const lineStartIndex = this.lineStartIndices[loc.line - 1];
393
+ const lineEndIndex = loc.line === this.lineStartIndices.length ? this.text.length : this.lineStartIndices[loc.line];
394
+ const positionIndex = lineStartIndex + loc.column;
395
+
396
+ /*
397
+ * By design, getIndexFromLoc({ line: lineNum, column: 0 }) should return the start index of
398
+ * the given line, provided that the line number is valid element of this.lines. Since the
399
+ * last element of this.lines is an empty string for files with trailing newlines, add a
400
+ * special case where getting the index for the first location after the end of the file
401
+ * will return the length of the file, rather than throwing an error. This allows rules to
402
+ * use getIndexFromLoc consistently without worrying about edge cases at the end of a file.
403
+ */
404
+ if (
405
+ loc.line === this.lineStartIndices.length && positionIndex > lineEndIndex ||
406
+ loc.line < this.lineStartIndices.length && positionIndex >= lineEndIndex
407
+ ) {
408
+ throw new RangeError(`Column number out of range (column ${loc.column} requested, but the length of line ${loc.line} is ${lineEndIndex - lineStartIndex}).`);
409
+ }
410
+
411
+ return positionIndex;
299
412
  }
300
413
  };
301
414
 
@@ -0,0 +1,3 @@
1
+ ESLint couldn't find the config "<%- configName %>" to extend from. Please check that the name of the config is correct.
2
+
3
+ If you still have problems, please stop by https://gitter.im/eslint/eslint to chat with the team.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "3.15.0",
3
+ "version": "3.17.1",
4
4
  "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
5
5
  "description": "An AST-based pattern checker for JavaScript.",
6
6
  "bin": {
@@ -78,14 +78,14 @@
78
78
  "browserify": "^12.0.1",
79
79
  "chai": "^3.5.0",
80
80
  "cheerio": "^0.19.0",
81
- "coveralls": "2.11.4",
81
+ "coveralls": "^2.11.16",
82
82
  "dateformat": "^1.0.8",
83
83
  "ejs": "^2.3.3",
84
- "eslint-plugin-node": "^2.0.0",
84
+ "eslint-plugin-eslint-plugin": "^0.7.1",
85
+ "eslint-plugin-node": "^4.1.0",
85
86
  "eslint-release": "^0.10.0",
86
87
  "esprima": "^2.4.1",
87
88
  "esprima-fb": "^15001.1001.0-dev-harmony-fb",
88
- "gh-got": "^2.2.0",
89
89
  "istanbul": "^0.4.0",
90
90
  "jsdoc": "^3.3.0-beta1",
91
91
  "karma": "^0.13.22",
@@ -94,11 +94,10 @@
94
94
  "karma-mocha-reporter": "^2.0.3",
95
95
  "karma-phantomjs-launcher": "^1.0.0",
96
96
  "leche": "^2.1.1",
97
- "linefix": "^0.1.1",
98
97
  "load-perf": "^0.2.0",
99
98
  "markdownlint": "^0.3.1",
100
99
  "mocha": "^2.4.5",
101
- "mock-fs": "^3.12.1",
100
+ "mock-fs": "not-an-aardvark/mock-fs#06868bbd7724707f9324b237bdde28f05f7a01d5",
102
101
  "npm-license": "^0.3.2",
103
102
  "phantomjs-prebuilt": "^2.1.7",
104
103
  "proxyquire": "^1.7.10",