eslint 3.14.0 → 3.16.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 (119) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +1 -1
  3. package/conf/{eslint.json → eslint-recommended.js} +86 -71
  4. package/lib/ast-utils.js +192 -24
  5. package/lib/cli.js +2 -2
  6. package/lib/code-path-analysis/code-path-state.js +2 -2
  7. package/lib/config/autoconfig.js +3 -3
  8. package/lib/config/config-file.js +31 -24
  9. package/lib/config/config-initializer.js +1 -1
  10. package/lib/config/config-validator.js +6 -6
  11. package/lib/config.js +3 -2
  12. package/lib/eslint.js +18 -18
  13. package/lib/formatters/checkstyle.js +2 -2
  14. package/lib/formatters/compact.js +2 -2
  15. package/lib/formatters/junit.js +2 -2
  16. package/lib/formatters/tap.js +2 -2
  17. package/lib/formatters/unix.js +2 -2
  18. package/lib/formatters/visualstudio.js +2 -2
  19. package/lib/rules/arrow-body-style.js +7 -4
  20. package/lib/rules/arrow-spacing.js +7 -6
  21. package/lib/rules/block-spacing.js +2 -2
  22. package/lib/rules/brace-style.js +42 -22
  23. package/lib/rules/capitalized-comments.js +6 -6
  24. package/lib/rules/comma-spacing.js +16 -16
  25. package/lib/rules/consistent-return.js +1 -1
  26. package/lib/rules/constructor-super.js +3 -3
  27. package/lib/rules/curly.js +11 -7
  28. package/lib/rules/default-case.js +3 -3
  29. package/lib/rules/eqeqeq.js +15 -6
  30. package/lib/rules/func-call-spacing.js +10 -13
  31. package/lib/rules/func-name-matching.js +1 -1
  32. package/lib/rules/generator-star-spacing.js +18 -19
  33. package/lib/rules/global-require.js +2 -2
  34. package/lib/rules/id-blacklist.js +2 -2
  35. package/lib/rules/id-length.js +3 -3
  36. package/lib/rules/id-match.js +2 -2
  37. package/lib/rules/indent.js +21 -20
  38. package/lib/rules/key-spacing.js +20 -23
  39. package/lib/rules/keyword-spacing.js +2 -13
  40. package/lib/rules/line-comment-position.js +1 -1
  41. package/lib/rules/linebreak-style.js +7 -1
  42. package/lib/rules/lines-around-comment.js +4 -4
  43. package/lib/rules/lines-around-directive.js +3 -3
  44. package/lib/rules/max-lines.js +2 -2
  45. package/lib/rules/max-statements-per-line.js +7 -6
  46. package/lib/rules/new-cap.js +2 -2
  47. package/lib/rules/newline-after-var.js +7 -2
  48. package/lib/rules/newline-before-return.js +2 -2
  49. package/lib/rules/newline-per-chained-call.js +3 -1
  50. package/lib/rules/no-cond-assign.js +3 -3
  51. package/lib/rules/no-extend-native.js +3 -3
  52. package/lib/rules/no-extra-bind.js +3 -4
  53. package/lib/rules/no-extra-boolean-cast.js +8 -0
  54. package/lib/rules/no-extra-parens.js +29 -8
  55. package/lib/rules/no-inner-declarations.js +4 -4
  56. package/lib/rules/no-irregular-whitespace.js +7 -1
  57. package/lib/rules/no-lone-blocks.js +10 -10
  58. package/lib/rules/no-mixed-operators.js +1 -7
  59. package/lib/rules/no-mixed-requires.js +4 -4
  60. package/lib/rules/no-multi-spaces.js +4 -1
  61. package/lib/rules/no-multi-str.js +7 -3
  62. package/lib/rules/no-redeclare.js +7 -7
  63. package/lib/rules/no-return-assign.js +7 -14
  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 +34 -19
  71. package/lib/rules/no-use-before-define.js +33 -29
  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 +1 -1
  75. package/lib/rules/no-useless-return.js +1 -7
  76. package/lib/rules/no-var.js +11 -0
  77. package/lib/rules/no-whitespace-before-property.js +5 -16
  78. package/lib/rules/object-curly-newline.js +2 -2
  79. package/lib/rules/object-curly-spacing.js +7 -25
  80. package/lib/rules/object-property-newline.js +3 -3
  81. package/lib/rules/object-shorthand.js +10 -10
  82. package/lib/rules/operator-assignment.js +2 -2
  83. package/lib/rules/operator-linebreak.js +8 -10
  84. package/lib/rules/padded-blocks.js +7 -4
  85. package/lib/rules/prefer-spread.js +1 -1
  86. package/lib/rules/prefer-template.js +1 -1
  87. package/lib/rules/quotes.js +10 -6
  88. package/lib/rules/semi-spacing.js +4 -0
  89. package/lib/rules/sort-imports.js +4 -4
  90. package/lib/rules/sort-vars.js +2 -2
  91. package/lib/rules/space-before-function-paren.js +8 -5
  92. package/lib/rules/space-in-parens.js +8 -8
  93. package/lib/rules/spaced-comment.js +10 -10
  94. package/lib/rules/strict.js +2 -2
  95. package/lib/rules/template-tag-spacing.js +77 -0
  96. package/lib/rules/unicode-bom.js +1 -1
  97. package/lib/rules/wrap-iife.js +5 -5
  98. package/lib/rules/yoda.js +2 -7
  99. package/lib/rules.js +2 -2
  100. package/lib/testers/rule-tester.js +25 -18
  101. package/lib/token-store/backward-token-comment-cursor.js +57 -0
  102. package/lib/token-store/backward-token-cursor.js +56 -0
  103. package/lib/token-store/cursor.js +76 -0
  104. package/lib/token-store/cursors.js +92 -0
  105. package/lib/token-store/decorative-cursor.js +39 -0
  106. package/lib/token-store/filter-cursor.js +43 -0
  107. package/lib/token-store/forward-token-comment-cursor.js +57 -0
  108. package/lib/token-store/forward-token-cursor.js +61 -0
  109. package/lib/token-store/index.js +604 -0
  110. package/lib/token-store/limit-cursor.js +40 -0
  111. package/lib/token-store/padded-token-cursor.js +38 -0
  112. package/lib/token-store/skip-cursor.js +42 -0
  113. package/lib/token-store/utils.js +100 -0
  114. package/lib/util/glob.js +1 -1
  115. package/lib/util/source-code-fixer.js +46 -44
  116. package/lib/util/source-code.js +35 -19
  117. package/messages/extend-config-missing.txt +3 -0
  118. package/package.json +3 -3
  119. package/lib/token-store.js +0 -203
@@ -132,9 +132,9 @@ module.exports = {
132
132
  return false;
133
133
  }
134
134
  return !isOpenerException(right);
135
- } else {
136
- return isOpenerException(right);
137
135
  }
136
+ return isOpenerException(right);
137
+
138
138
  }
139
139
 
140
140
  /**
@@ -154,9 +154,9 @@ module.exports = {
154
154
 
155
155
  if (ALWAYS) {
156
156
  return !isCloserException(left);
157
- } else {
158
- return isCloserException(left);
159
157
  }
158
+ return isCloserException(left);
159
+
160
160
  }
161
161
 
162
162
  /**
@@ -180,9 +180,9 @@ module.exports = {
180
180
 
181
181
  if (ALWAYS) {
182
182
  return isOpenerException(right);
183
- } else {
184
- return !isOpenerException(right);
185
183
  }
184
+ return !isOpenerException(right);
185
+
186
186
  }
187
187
 
188
188
  /**
@@ -206,9 +206,9 @@ module.exports = {
206
206
 
207
207
  if (ALWAYS) {
208
208
  return isCloserException(left);
209
- } else {
210
- return !isCloserException(left);
211
209
  }
210
+ return !isCloserException(left);
211
+
212
212
  }
213
213
 
214
214
  //--------------------------------------------------------------------------
@@ -5,6 +5,7 @@
5
5
  "use strict";
6
6
 
7
7
  const lodash = require("lodash");
8
+ const astUtils = require("../ast-utils");
8
9
 
9
10
  //------------------------------------------------------------------------------
10
11
  // Helpers
@@ -88,8 +89,7 @@ function createExceptionsPattern(exceptions) {
88
89
  pattern += exceptions.map(escapeAndRepeat).join("|");
89
90
  pattern += ")";
90
91
  }
91
-
92
- pattern += "(?:$|[\n\r]))";
92
+ pattern += `(?:$|[${Array.from(astUtils.LINEBREAKS).join("")}]))`;
93
93
  }
94
94
 
95
95
  return pattern;
@@ -279,10 +279,10 @@ module.exports = {
279
279
  end += match[0].length;
280
280
  }
281
281
  return fixer.insertTextAfterRange([start, end], " ");
282
- } else {
283
- end += match[0].length;
284
- return fixer.replaceTextRange([start, end], commentIdentifier + (match[1] ? match[1] : ""));
285
282
  }
283
+ end += match[0].length;
284
+ return fixer.replaceTextRange([start, end], commentIdentifier + (match[1] ? match[1] : ""));
285
+
286
286
  },
287
287
  message,
288
288
  data: { refChar }
@@ -302,12 +302,12 @@ module.exports = {
302
302
  fix(fixer) {
303
303
  if (requireSpace) {
304
304
  return fixer.insertTextAfterRange([node.start, node.end - 2], " ");
305
- } else {
306
- const end = node.end - 2,
307
- start = end - match[0].length;
308
-
309
- return fixer.replaceTextRange([start, end], "");
310
305
  }
306
+ const end = node.end - 2,
307
+ start = end - match[0].length;
308
+
309
+ return fixer.replaceTextRange([start, end], "");
310
+
311
311
  },
312
312
  message
313
313
  });
@@ -212,8 +212,8 @@ module.exports = {
212
212
  */
213
213
  function enterFunction(node) {
214
214
  const isBlock = node.body.type === "BlockStatement",
215
- useStrictDirectives = isBlock ?
216
- getUseStrictDirectives(node.body.body) : [];
215
+ useStrictDirectives = isBlock
216
+ ? getUseStrictDirectives(node.body.body) : [];
217
217
 
218
218
  if (mode === "function") {
219
219
  enterFunctionInFunctionMode(node, useStrictDirectives);
@@ -0,0 +1,77 @@
1
+ /**
2
+ * @fileoverview Rule to check spacing between template tags and their literals
3
+ * @author Jonathan Wilsson
4
+ */
5
+
6
+ "use strict";
7
+
8
+ //------------------------------------------------------------------------------
9
+ // Rule Definition
10
+ //------------------------------------------------------------------------------
11
+
12
+ module.exports = {
13
+ meta: {
14
+ docs: {
15
+ description: "require or disallow spacing between template tags and their literals",
16
+ category: "Stylistic Issues",
17
+ recommended: false
18
+ },
19
+
20
+ fixable: "whitespace",
21
+
22
+ schema: [
23
+ { enum: ["always", "never"] }
24
+ ]
25
+ },
26
+
27
+ create(context) {
28
+ const never = context.options[0] !== "always";
29
+ const sourceCode = context.getSourceCode();
30
+
31
+ /**
32
+ * Check if a space is present between a template tag and its literal
33
+ * @param {ASTNode} node node to evaluate
34
+ * @returns {void}
35
+ * @private
36
+ */
37
+ function checkSpacing(node) {
38
+ const tagToken = sourceCode.getTokenBefore(node.quasi);
39
+ const literalToken = sourceCode.getFirstToken(node.quasi);
40
+ const hasWhitespace = sourceCode.isSpaceBetweenTokens(tagToken, literalToken);
41
+
42
+ if (never && hasWhitespace) {
43
+ context.report({
44
+ node,
45
+ loc: tagToken.loc.start,
46
+ message: "Unexpected space between template tag and template literal.",
47
+ fix(fixer) {
48
+ const comments = sourceCode.getComments(node.quasi).leading;
49
+
50
+ // Don't fix anything if there's a single line comment after the template tag
51
+ if (comments.some(comment => comment.type === "Line")) {
52
+ return null;
53
+ }
54
+
55
+ return fixer.replaceTextRange(
56
+ [tagToken.range[1], literalToken.range[0]],
57
+ comments.reduce((text, comment) => text + sourceCode.getText(comment), "")
58
+ );
59
+ }
60
+ });
61
+ } else if (!never && !hasWhitespace) {
62
+ context.report({
63
+ node,
64
+ loc: tagToken.loc.start,
65
+ message: "Missing space between template tag and template literal.",
66
+ fix(fixer) {
67
+ return fixer.insertTextAfter(tagToken, " ");
68
+ }
69
+ });
70
+ }
71
+ }
72
+
73
+ return {
74
+ TaggedTemplateExpression: checkSpacing
75
+ };
76
+ }
77
+ };
@@ -45,7 +45,7 @@ module.exports = {
45
45
  loc: location,
46
46
  message: "Expected Unicode BOM (Byte Order Mark).",
47
47
  fix(fixer) {
48
- return fixer.insertTextBefore(node, "\uFEFF");
48
+ return fixer.insertTextBeforeRange([0, 1], "\uFEFF");
49
49
  }
50
50
  });
51
51
  } else if (sourceCode.hasBOM && (requireBOM === "never")) {
@@ -5,6 +5,10 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
8
12
  const astUtils = require("../ast-utils");
9
13
 
10
14
  //------------------------------------------------------------------------------
@@ -51,11 +55,7 @@ module.exports = {
51
55
  * @private
52
56
  */
53
57
  function wrapped(node) {
54
- const previousToken = sourceCode.getTokenBefore(node),
55
- nextToken = sourceCode.getTokenAfter(node);
56
-
57
- return previousToken && previousToken.value === "(" &&
58
- nextToken && nextToken.value === ")";
58
+ return astUtils.isParenthesised(sourceCode, node);
59
59
  }
60
60
 
61
61
  /**
package/lib/rules/yoda.js CHANGED
@@ -235,12 +235,7 @@ module.exports = {
235
235
  * paren token.
236
236
  */
237
237
  function isParenWrapped() {
238
- let tokenBefore, tokenAfter;
239
-
240
- return ((tokenBefore = sourceCode.getTokenBefore(node)) &&
241
- tokenBefore.value === "(" &&
242
- (tokenAfter = sourceCode.getTokenAfter(node)) &&
243
- tokenAfter.value === ")");
238
+ return astUtils.isParenthesised(sourceCode, node);
244
239
  }
245
240
 
246
241
  return (node.type === "LogicalExpression" &&
@@ -269,7 +264,7 @@ module.exports = {
269
264
  * @returns {string} A string representation of the node with the sides and operator flipped
270
265
  */
271
266
  function getFlippedString(node) {
272
- const operatorToken = sourceCode.getTokensBetween(node.left, node.right).find(token => token.value === node.operator);
267
+ const operatorToken = sourceCode.getFirstTokenBetween(node.left, node.right, token => token.value === node.operator);
273
268
  const textBeforeOperator = sourceCode.getText().slice(sourceCode.getTokenBefore(operatorToken).range[1], operatorToken.range[0]);
274
269
  const textAfterOperator = sourceCode.getText().slice(operatorToken.range[1], sourceCode.getTokenAfter(operatorToken).range[0]);
275
270
  const leftText = sourceCode.getText().slice(sourceCode.getFirstToken(node).range[0], sourceCode.getTokenBefore(operatorToken).range[1]);
package/lib/rules.js CHANGED
@@ -70,9 +70,9 @@ function importPlugin(plugin, pluginName) {
70
70
  function getHandler(ruleId) {
71
71
  if (typeof rules[ruleId] === "string") {
72
72
  return require(rules[ruleId]);
73
- } else {
74
- return rules[ruleId];
75
73
  }
74
+ return rules[ruleId];
75
+
76
76
  }
77
77
 
78
78
  /**
@@ -147,6 +147,12 @@ function RuleTester(testerConfig) {
147
147
  lodash.cloneDeep(defaultConfig),
148
148
  testerConfig
149
149
  );
150
+
151
+ /**
152
+ * Rule definitions to define before tests.
153
+ * @type {Object}
154
+ */
155
+ this.rules = {};
150
156
  }
151
157
 
152
158
  /**
@@ -239,7 +245,7 @@ RuleTester.prototype = {
239
245
  * @returns {void}
240
246
  */
241
247
  defineRule(name, rule) {
242
- eslint.defineRule(name, rule);
248
+ this.rules[name] = rule;
243
249
  },
244
250
 
245
251
  /**
@@ -361,19 +367,19 @@ RuleTester.prototype = {
361
367
 
362
368
  return rule(context);
363
369
  };
364
- } else {
365
- return {
366
- meta: rule.meta,
367
- create(context) {
368
- Object.freeze(context);
369
- freezeDeeply(context.options);
370
- freezeDeeply(context.settings);
371
- freezeDeeply(context.parserOptions);
372
-
373
- return rule.create(context);
374
- }
375
- };
376
370
  }
371
+ return {
372
+ meta: rule.meta,
373
+ create(context) {
374
+ Object.freeze(context);
375
+ freezeDeeply(context.options);
376
+ freezeDeeply(context.settings);
377
+ freezeDeeply(context.parserOptions);
378
+
379
+ return rule.create(context);
380
+ }
381
+ };
382
+
377
383
  };
378
384
 
379
385
  return {
@@ -488,13 +494,12 @@ RuleTester.prototype = {
488
494
  assert.fail(messages[i], null, "Error should be a string or object.");
489
495
  }
490
496
  }
497
+ }
491
498
 
492
- if (item.hasOwnProperty("output")) {
493
- const fixResult = SourceCodeFixer.applyFixes(eslint.getSourceCode(), messages);
494
-
495
- assert.equal(fixResult.output, item.output, "Output is incorrect.");
496
- }
499
+ if (item.hasOwnProperty("output")) {
500
+ const fixResult = SourceCodeFixer.applyFixes(eslint.getSourceCode(), messages);
497
501
 
502
+ assert.equal(fixResult.output, item.output, "Output is incorrect.");
498
503
  }
499
504
 
500
505
  assertASTDidntChange(result.beforeAST, result.afterAST);
@@ -508,6 +513,7 @@ RuleTester.prototype = {
508
513
  RuleTester.describe("valid", () => {
509
514
  test.valid.forEach(valid => {
510
515
  RuleTester.it(valid.code || valid, () => {
516
+ eslint.defineRules(this.rules);
511
517
  testValidTemplate(ruleName, valid);
512
518
  });
513
519
  });
@@ -516,6 +522,7 @@ RuleTester.prototype = {
516
522
  RuleTester.describe("invalid", () => {
517
523
  test.invalid.forEach(invalid => {
518
524
  RuleTester.it(invalid.code, () => {
525
+ eslint.defineRules(this.rules);
519
526
  testInvalidTemplate(ruleName, invalid);
520
527
  });
521
528
  });
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @fileoverview Define the cursor which iterates tokens and comments in reverse.
3
+ * @author Toru Nagashima
4
+ */
5
+ "use strict";
6
+
7
+ //------------------------------------------------------------------------------
8
+ // Requirements
9
+ //------------------------------------------------------------------------------
10
+
11
+ const Cursor = require("./cursor");
12
+ const utils = require("./utils");
13
+
14
+ //------------------------------------------------------------------------------
15
+ // Exports
16
+ //------------------------------------------------------------------------------
17
+
18
+ /**
19
+ * The cursor which iterates tokens and comments in reverse.
20
+ */
21
+ module.exports = class BackwardTokenCommentCursor extends Cursor {
22
+
23
+ /**
24
+ * Initializes this cursor.
25
+ * @param {Token[]} tokens - The array of tokens.
26
+ * @param {Comment[]} comments - The array of comments.
27
+ * @param {Object} indexMap - The map from locations to indices in `tokens`.
28
+ * @param {number} startLoc - The start location of the iteration range.
29
+ * @param {number} endLoc - The end location of the iteration range.
30
+ */
31
+ constructor(tokens, comments, indexMap, startLoc, endLoc) {
32
+ super();
33
+ this.tokens = tokens;
34
+ this.comments = comments;
35
+ this.tokenIndex = utils.getLastIndex(tokens, indexMap, endLoc);
36
+ this.commentIndex = utils.search(comments, endLoc) - 1;
37
+ this.border = startLoc;
38
+ }
39
+
40
+ /** @inheritdoc */
41
+ moveNext() {
42
+ const token = (this.tokenIndex >= 0) ? this.tokens[this.tokenIndex] : null;
43
+ const comment = (this.commentIndex >= 0) ? this.comments[this.commentIndex] : null;
44
+
45
+ if (token && (!comment || token.range[1] > comment.range[1])) {
46
+ this.current = token;
47
+ this.tokenIndex -= 1;
48
+ } else if (comment) {
49
+ this.current = comment;
50
+ this.commentIndex -= 1;
51
+ } else {
52
+ this.current = null;
53
+ }
54
+
55
+ return Boolean(this.current) && (this.border === -1 || this.current.range[0] >= this.border);
56
+ }
57
+ };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @fileoverview Define the cursor which iterates tokens only in reverse.
3
+ * @author Toru Nagashima
4
+ */
5
+ "use strict";
6
+
7
+ //------------------------------------------------------------------------------
8
+ // Requirements
9
+ //------------------------------------------------------------------------------
10
+
11
+ const Cursor = require("./cursor");
12
+ const utils = require("./utils");
13
+
14
+ //------------------------------------------------------------------------------
15
+ // Exports
16
+ //------------------------------------------------------------------------------
17
+
18
+ /**
19
+ * The cursor which iterates tokens only in reverse.
20
+ */
21
+ module.exports = class BackwardTokenCursor extends Cursor {
22
+
23
+ /**
24
+ * Initializes this cursor.
25
+ * @param {Token[]} tokens - The array of tokens.
26
+ * @param {Comment[]} comments - The array of comments.
27
+ * @param {Object} indexMap - The map from locations to indices in `tokens`.
28
+ * @param {number} startLoc - The start location of the iteration range.
29
+ * @param {number} endLoc - The end location of the iteration range.
30
+ */
31
+ constructor(tokens, comments, indexMap, startLoc, endLoc) {
32
+ super();
33
+ this.tokens = tokens;
34
+ this.index = utils.getLastIndex(tokens, indexMap, endLoc);
35
+ this.indexEnd = utils.getFirstIndex(tokens, indexMap, startLoc);
36
+ }
37
+
38
+ /** @inheritdoc */
39
+ moveNext() {
40
+ if (this.index >= this.indexEnd) {
41
+ this.current = this.tokens[this.index];
42
+ this.index -= 1;
43
+ return true;
44
+ }
45
+ return false;
46
+ }
47
+
48
+ //
49
+ // Shorthand for performance.
50
+ //
51
+
52
+ /** @inheritdoc */
53
+ getOneToken() {
54
+ return (this.index >= this.indexEnd) ? this.tokens[this.index] : null;
55
+ }
56
+ };
@@ -0,0 +1,76 @@
1
+ /**
2
+ * @fileoverview Define the abstract class about cursors which iterate tokens.
3
+ * @author Toru Nagashima
4
+ */
5
+ "use strict";
6
+
7
+ //------------------------------------------------------------------------------
8
+ // Exports
9
+ //------------------------------------------------------------------------------
10
+
11
+ /**
12
+ * The abstract class about cursors which iterate tokens.
13
+ *
14
+ * This class has 2 abstract methods.
15
+ *
16
+ * - `current: Token | Comment | null` ... The current token.
17
+ * - `moveNext(): boolean` ... Moves this cursor to the next token. If the next token didn't exist, it returns `false`.
18
+ *
19
+ * This is similar to ES2015 Iterators.
20
+ * However, Iterators were slow (at 2017-01), so I created this class as similar to C# IEnumerable.
21
+ *
22
+ * There are the following known sub classes.
23
+ *
24
+ * - ForwardTokenCursor .......... The cursor which iterates tokens only.
25
+ * - BackwardTokenCursor ......... The cursor which iterates tokens only in reverse.
26
+ * - ForwardTokenCommentCursor ... The cursor which iterates tokens and comments.
27
+ * - BackwardTokenCommentCursor .. The cursor which iterates tokens and comments in reverse.
28
+ * - DecorativeCursor
29
+ * - FilterCursor ............ The cursor which ignores the specified tokens.
30
+ * - SkipCursor .............. The cursor which ignores the first few tokens.
31
+ * - LimitCursor ............. The cursor which limits the count of tokens.
32
+ *
33
+ */
34
+ module.exports = class Cursor {
35
+
36
+ /**
37
+ * Initializes this cursor.
38
+ */
39
+ constructor() {
40
+ this.current = null;
41
+ }
42
+
43
+ /**
44
+ * Gets the first token.
45
+ * This consumes this cursor.
46
+ * @returns {Token|Comment} The first token or null.
47
+ */
48
+ getOneToken() {
49
+ return this.moveNext() ? this.current : null;
50
+ }
51
+
52
+ /**
53
+ * Gets the first tokens.
54
+ * This consumes this cursor.
55
+ * @returns {(Token|Comment)[]} All tokens.
56
+ */
57
+ getAllTokens() {
58
+ const tokens = [];
59
+
60
+ while (this.moveNext()) {
61
+ tokens.push(this.current);
62
+ }
63
+
64
+ return tokens;
65
+ }
66
+
67
+ /**
68
+ * Moves this cursor to the next token.
69
+ * @returns {boolean} `true` if the next token exists.
70
+ * @abstract
71
+ */
72
+ /* istanbul ignore next */
73
+ moveNext() { // eslint-disable-line class-methods-use-this
74
+ throw new Error("Not implemented.");
75
+ }
76
+ };
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @fileoverview Define 2 token factories; forward and backward.
3
+ * @author Toru Nagashima
4
+ */
5
+ "use strict";
6
+
7
+ //------------------------------------------------------------------------------
8
+ // Requirements
9
+ //------------------------------------------------------------------------------
10
+
11
+ const BackwardTokenCommentCursor = require("./backward-token-comment-cursor");
12
+ const BackwardTokenCursor = require("./backward-token-cursor");
13
+ const FilterCursor = require("./filter-cursor");
14
+ const ForwardTokenCommentCursor = require("./forward-token-comment-cursor");
15
+ const ForwardTokenCursor = require("./forward-token-cursor");
16
+ const LimitCursor = require("./limit-cursor");
17
+ const SkipCursor = require("./skip-cursor");
18
+
19
+ //------------------------------------------------------------------------------
20
+ // Helpers
21
+ //------------------------------------------------------------------------------
22
+
23
+ /**
24
+ * The cursor factory.
25
+ * @private
26
+ */
27
+ class CursorFactory {
28
+
29
+ /**
30
+ * Initializes this cursor.
31
+ * @param {Function} TokenCursor - The class of the cursor which iterates tokens only.
32
+ * @param {Function} TokenCommentCursor - The class of the cursor which iterates the mix of tokens and comments.
33
+ */
34
+ constructor(TokenCursor, TokenCommentCursor) {
35
+ this.TokenCursor = TokenCursor;
36
+ this.TokenCommentCursor = TokenCommentCursor;
37
+ }
38
+
39
+ /**
40
+ * Creates a base cursor instance that can be decorated by createCursor.
41
+ *
42
+ * @param {Token[]} tokens - The array of tokens.
43
+ * @param {Comment[]} comments - The array of comments.
44
+ * @param {Object} indexMap - The map from locations to indices in `tokens`.
45
+ * @param {number} startLoc - The start location of the iteration range.
46
+ * @param {number} endLoc - The end location of the iteration range.
47
+ * @param {boolean} includeComments - The flag to iterate comments as well.
48
+ * @returns {Cursor} The created base cursor.
49
+ */
50
+ createBaseCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments) {
51
+ const Cursor = includeComments ? this.TokenCommentCursor : this.TokenCursor;
52
+
53
+ return new Cursor(tokens, comments, indexMap, startLoc, endLoc);
54
+ }
55
+
56
+ /**
57
+ * Creates a cursor that iterates tokens with normalized options.
58
+ *
59
+ * @param {Token[]} tokens - The array of tokens.
60
+ * @param {Comment[]} comments - The array of comments.
61
+ * @param {Object} indexMap - The map from locations to indices in `tokens`.
62
+ * @param {number} startLoc - The start location of the iteration range.
63
+ * @param {number} endLoc - The end location of the iteration range.
64
+ * @param {boolean} includeComments - The flag to iterate comments as well.
65
+ * @param {Function|null} filter - The predicate function to choose tokens.
66
+ * @param {number} skip - The count of tokens the cursor skips.
67
+ * @param {number} count - The maximum count of tokens the cursor iterates. Zero is no iteration for backward compatibility.
68
+ * @returns {Cursor} The created cursor.
69
+ */
70
+ createCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments, filter, skip, count) {
71
+ let cursor = this.createBaseCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments);
72
+
73
+ if (filter) {
74
+ cursor = new FilterCursor(cursor, filter);
75
+ }
76
+ if (skip >= 1) {
77
+ cursor = new SkipCursor(cursor, skip);
78
+ }
79
+ if (count >= 0) {
80
+ cursor = new LimitCursor(cursor, count);
81
+ }
82
+
83
+ return cursor;
84
+ }
85
+ }
86
+
87
+ //------------------------------------------------------------------------------
88
+ // Exports
89
+ //------------------------------------------------------------------------------
90
+
91
+ exports.forward = new CursorFactory(ForwardTokenCursor, ForwardTokenCommentCursor);
92
+ exports.backward = new CursorFactory(BackwardTokenCursor, BackwardTokenCommentCursor);
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @fileoverview Define the abstract class about cursors which manipulate another cursor.
3
+ * @author Toru Nagashima
4
+ */
5
+ "use strict";
6
+
7
+ //------------------------------------------------------------------------------
8
+ // Requirements
9
+ //------------------------------------------------------------------------------
10
+
11
+ const Cursor = require("./cursor");
12
+
13
+ //------------------------------------------------------------------------------
14
+ // Exports
15
+ //------------------------------------------------------------------------------
16
+
17
+ /**
18
+ * The abstract class about cursors which manipulate another cursor.
19
+ */
20
+ module.exports = class DecorativeCursor extends Cursor {
21
+
22
+ /**
23
+ * Initializes this cursor.
24
+ * @param {Cursor} cursor - The cursor to be decorated.
25
+ */
26
+ constructor(cursor) {
27
+ super();
28
+ this.cursor = cursor;
29
+ }
30
+
31
+ /** @inheritdoc */
32
+ moveNext() {
33
+ const retv = this.cursor.moveNext();
34
+
35
+ this.current = this.cursor.current;
36
+
37
+ return retv;
38
+ }
39
+ };