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.
- package/CHANGELOG.md +68 -0
- package/README.md +1 -1
- package/conf/{eslint.json → eslint-recommended.js} +86 -71
- package/lib/ast-utils.js +192 -24
- package/lib/cli.js +2 -2
- package/lib/code-path-analysis/code-path-state.js +2 -2
- package/lib/config/autoconfig.js +3 -3
- package/lib/config/config-file.js +31 -24
- package/lib/config/config-initializer.js +1 -1
- package/lib/config/config-validator.js +6 -6
- package/lib/config.js +3 -2
- package/lib/eslint.js +18 -18
- package/lib/formatters/checkstyle.js +2 -2
- package/lib/formatters/compact.js +2 -2
- package/lib/formatters/junit.js +2 -2
- package/lib/formatters/tap.js +2 -2
- package/lib/formatters/unix.js +2 -2
- package/lib/formatters/visualstudio.js +2 -2
- package/lib/rules/arrow-body-style.js +7 -4
- package/lib/rules/arrow-spacing.js +7 -6
- package/lib/rules/block-spacing.js +2 -2
- package/lib/rules/brace-style.js +42 -22
- package/lib/rules/capitalized-comments.js +6 -6
- package/lib/rules/comma-spacing.js +16 -16
- package/lib/rules/consistent-return.js +1 -1
- package/lib/rules/constructor-super.js +3 -3
- package/lib/rules/curly.js +11 -7
- package/lib/rules/default-case.js +3 -3
- package/lib/rules/eqeqeq.js +15 -6
- package/lib/rules/func-call-spacing.js +10 -13
- package/lib/rules/func-name-matching.js +1 -1
- package/lib/rules/generator-star-spacing.js +18 -19
- package/lib/rules/global-require.js +2 -2
- package/lib/rules/id-blacklist.js +2 -2
- package/lib/rules/id-length.js +3 -3
- package/lib/rules/id-match.js +2 -2
- package/lib/rules/indent.js +21 -20
- package/lib/rules/key-spacing.js +20 -23
- package/lib/rules/keyword-spacing.js +2 -13
- package/lib/rules/line-comment-position.js +1 -1
- package/lib/rules/linebreak-style.js +7 -1
- package/lib/rules/lines-around-comment.js +4 -4
- package/lib/rules/lines-around-directive.js +3 -3
- package/lib/rules/max-lines.js +2 -2
- package/lib/rules/max-statements-per-line.js +7 -6
- package/lib/rules/new-cap.js +2 -2
- package/lib/rules/newline-after-var.js +7 -2
- package/lib/rules/newline-before-return.js +2 -2
- package/lib/rules/newline-per-chained-call.js +3 -1
- package/lib/rules/no-cond-assign.js +3 -3
- package/lib/rules/no-extend-native.js +3 -3
- package/lib/rules/no-extra-bind.js +3 -4
- package/lib/rules/no-extra-boolean-cast.js +8 -0
- package/lib/rules/no-extra-parens.js +29 -8
- package/lib/rules/no-inner-declarations.js +4 -4
- package/lib/rules/no-irregular-whitespace.js +7 -1
- package/lib/rules/no-lone-blocks.js +10 -10
- package/lib/rules/no-mixed-operators.js +1 -7
- package/lib/rules/no-mixed-requires.js +4 -4
- package/lib/rules/no-multi-spaces.js +4 -1
- package/lib/rules/no-multi-str.js +7 -3
- package/lib/rules/no-redeclare.js +7 -7
- package/lib/rules/no-return-assign.js +7 -14
- package/lib/rules/no-sequences.js +7 -6
- package/lib/rules/no-trailing-spaces.js +8 -2
- package/lib/rules/no-undefined.js +45 -6
- package/lib/rules/no-unexpected-multiline.js +9 -8
- package/lib/rules/no-unneeded-ternary.js +5 -1
- package/lib/rules/no-unused-labels.js +17 -2
- package/lib/rules/no-unused-vars.js +34 -19
- package/lib/rules/no-use-before-define.js +33 -29
- package/lib/rules/no-useless-computed-key.js +8 -3
- package/lib/rules/no-useless-concat.js +10 -7
- package/lib/rules/no-useless-escape.js +1 -1
- package/lib/rules/no-useless-return.js +1 -7
- package/lib/rules/no-var.js +11 -0
- package/lib/rules/no-whitespace-before-property.js +5 -16
- package/lib/rules/object-curly-newline.js +2 -2
- package/lib/rules/object-curly-spacing.js +7 -25
- package/lib/rules/object-property-newline.js +3 -3
- package/lib/rules/object-shorthand.js +10 -10
- package/lib/rules/operator-assignment.js +2 -2
- package/lib/rules/operator-linebreak.js +8 -10
- package/lib/rules/padded-blocks.js +7 -4
- package/lib/rules/prefer-spread.js +1 -1
- package/lib/rules/prefer-template.js +1 -1
- package/lib/rules/quotes.js +10 -6
- package/lib/rules/semi-spacing.js +4 -0
- package/lib/rules/sort-imports.js +4 -4
- package/lib/rules/sort-vars.js +2 -2
- package/lib/rules/space-before-function-paren.js +8 -5
- package/lib/rules/space-in-parens.js +8 -8
- package/lib/rules/spaced-comment.js +10 -10
- package/lib/rules/strict.js +2 -2
- package/lib/rules/template-tag-spacing.js +77 -0
- package/lib/rules/unicode-bom.js +1 -1
- package/lib/rules/wrap-iife.js +5 -5
- package/lib/rules/yoda.js +2 -7
- package/lib/rules.js +2 -2
- package/lib/testers/rule-tester.js +25 -18
- package/lib/token-store/backward-token-comment-cursor.js +57 -0
- package/lib/token-store/backward-token-cursor.js +56 -0
- package/lib/token-store/cursor.js +76 -0
- package/lib/token-store/cursors.js +92 -0
- package/lib/token-store/decorative-cursor.js +39 -0
- package/lib/token-store/filter-cursor.js +43 -0
- package/lib/token-store/forward-token-comment-cursor.js +57 -0
- package/lib/token-store/forward-token-cursor.js +61 -0
- package/lib/token-store/index.js +604 -0
- package/lib/token-store/limit-cursor.js +40 -0
- package/lib/token-store/padded-token-cursor.js +38 -0
- package/lib/token-store/skip-cursor.js +42 -0
- package/lib/token-store/utils.js +100 -0
- package/lib/util/glob.js +1 -1
- package/lib/util/source-code-fixer.js +46 -44
- package/lib/util/source-code.js +35 -19
- package/messages/extend-config-missing.txt +3 -0
- package/package.json +3 -3
- 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
|
});
|
package/lib/rules/strict.js
CHANGED
@@ -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
|
+
};
|
package/lib/rules/unicode-bom.js
CHANGED
@@ -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.
|
48
|
+
return fixer.insertTextBeforeRange([0, 1], "\uFEFF");
|
49
49
|
}
|
50
50
|
});
|
51
51
|
} else if (sourceCode.hasBOM && (requireBOM === "never")) {
|
package/lib/rules/wrap-iife.js
CHANGED
@@ -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
|
-
|
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
|
-
|
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.
|
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
@@ -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
|
-
|
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
|
-
|
493
|
-
|
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
|
+
};
|