summaryrefslogtreecommitdiff
path: root/tools/node_modules/eslint/lib/token-store
diff options
context:
space:
mode:
Diffstat (limited to 'tools/node_modules/eslint/lib/token-store')
-rw-r--r--tools/node_modules/eslint/lib/token-store/backward-token-comment-cursor.js57
-rw-r--r--tools/node_modules/eslint/lib/token-store/backward-token-cursor.js58
-rw-r--r--tools/node_modules/eslint/lib/token-store/cursor.js76
-rw-r--r--tools/node_modules/eslint/lib/token-store/cursors.js92
-rw-r--r--tools/node_modules/eslint/lib/token-store/decorative-cursor.js39
-rw-r--r--tools/node_modules/eslint/lib/token-store/filter-cursor.js43
-rw-r--r--tools/node_modules/eslint/lib/token-store/forward-token-comment-cursor.js57
-rw-r--r--tools/node_modules/eslint/lib/token-store/forward-token-cursor.js63
-rw-r--r--tools/node_modules/eslint/lib/token-store/index.js633
-rw-r--r--tools/node_modules/eslint/lib/token-store/limit-cursor.js40
-rw-r--r--tools/node_modules/eslint/lib/token-store/padded-token-cursor.js38
-rw-r--r--tools/node_modules/eslint/lib/token-store/skip-cursor.js42
-rw-r--r--tools/node_modules/eslint/lib/token-store/utils.js104
13 files changed, 1342 insertions, 0 deletions
diff --git a/tools/node_modules/eslint/lib/token-store/backward-token-comment-cursor.js b/tools/node_modules/eslint/lib/token-store/backward-token-comment-cursor.js
new file mode 100644
index 0000000000..7c2137a176
--- /dev/null
+++ b/tools/node_modules/eslint/lib/token-store/backward-token-comment-cursor.js
@@ -0,0 +1,57 @@
+/**
+ * @fileoverview Define the cursor which iterates tokens and comments in reverse.
+ * @author Toru Nagashima
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const Cursor = require("./cursor");
+const utils = require("./utils");
+
+//------------------------------------------------------------------------------
+// Exports
+//------------------------------------------------------------------------------
+
+/**
+ * The cursor which iterates tokens and comments in reverse.
+ */
+module.exports = class BackwardTokenCommentCursor extends Cursor {
+
+ /**
+ * Initializes this cursor.
+ * @param {Token[]} tokens - The array of tokens.
+ * @param {Comment[]} comments - The array of comments.
+ * @param {Object} indexMap - The map from locations to indices in `tokens`.
+ * @param {number} startLoc - The start location of the iteration range.
+ * @param {number} endLoc - The end location of the iteration range.
+ */
+ constructor(tokens, comments, indexMap, startLoc, endLoc) {
+ super();
+ this.tokens = tokens;
+ this.comments = comments;
+ this.tokenIndex = utils.getLastIndex(tokens, indexMap, endLoc);
+ this.commentIndex = utils.search(comments, endLoc) - 1;
+ this.border = startLoc;
+ }
+
+ /** @inheritdoc */
+ moveNext() {
+ const token = (this.tokenIndex >= 0) ? this.tokens[this.tokenIndex] : null;
+ const comment = (this.commentIndex >= 0) ? this.comments[this.commentIndex] : null;
+
+ if (token && (!comment || token.range[1] > comment.range[1])) {
+ this.current = token;
+ this.tokenIndex -= 1;
+ } else if (comment) {
+ this.current = comment;
+ this.commentIndex -= 1;
+ } else {
+ this.current = null;
+ }
+
+ return Boolean(this.current) && (this.border === -1 || this.current.range[0] >= this.border);
+ }
+};
diff --git a/tools/node_modules/eslint/lib/token-store/backward-token-cursor.js b/tools/node_modules/eslint/lib/token-store/backward-token-cursor.js
new file mode 100644
index 0000000000..93973bce44
--- /dev/null
+++ b/tools/node_modules/eslint/lib/token-store/backward-token-cursor.js
@@ -0,0 +1,58 @@
+/**
+ * @fileoverview Define the cursor which iterates tokens only in reverse.
+ * @author Toru Nagashima
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const Cursor = require("./cursor");
+const utils = require("./utils");
+
+//------------------------------------------------------------------------------
+// Exports
+//------------------------------------------------------------------------------
+
+/**
+ * The cursor which iterates tokens only in reverse.
+ */
+module.exports = class BackwardTokenCursor extends Cursor {
+
+ /**
+ * Initializes this cursor.
+ * @param {Token[]} tokens - The array of tokens.
+ * @param {Comment[]} comments - The array of comments.
+ * @param {Object} indexMap - The map from locations to indices in `tokens`.
+ * @param {number} startLoc - The start location of the iteration range.
+ * @param {number} endLoc - The end location of the iteration range.
+ */
+ constructor(tokens, comments, indexMap, startLoc, endLoc) {
+ super();
+ this.tokens = tokens;
+ this.index = utils.getLastIndex(tokens, indexMap, endLoc);
+ this.indexEnd = utils.getFirstIndex(tokens, indexMap, startLoc);
+ }
+
+ /** @inheritdoc */
+ moveNext() {
+ if (this.index >= this.indexEnd) {
+ this.current = this.tokens[this.index];
+ this.index -= 1;
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ *
+ * Shorthand for performance.
+ *
+ */
+
+ /** @inheritdoc */
+ getOneToken() {
+ return (this.index >= this.indexEnd) ? this.tokens[this.index] : null;
+ }
+};
diff --git a/tools/node_modules/eslint/lib/token-store/cursor.js b/tools/node_modules/eslint/lib/token-store/cursor.js
new file mode 100644
index 0000000000..4e1595c6dc
--- /dev/null
+++ b/tools/node_modules/eslint/lib/token-store/cursor.js
@@ -0,0 +1,76 @@
+/**
+ * @fileoverview Define the abstract class about cursors which iterate tokens.
+ * @author Toru Nagashima
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Exports
+//------------------------------------------------------------------------------
+
+/**
+ * The abstract class about cursors which iterate tokens.
+ *
+ * This class has 2 abstract methods.
+ *
+ * - `current: Token | Comment | null` ... The current token.
+ * - `moveNext(): boolean` ... Moves this cursor to the next token. If the next token didn't exist, it returns `false`.
+ *
+ * This is similar to ES2015 Iterators.
+ * However, Iterators were slow (at 2017-01), so I created this class as similar to C# IEnumerable.
+ *
+ * There are the following known sub classes.
+ *
+ * - ForwardTokenCursor .......... The cursor which iterates tokens only.
+ * - BackwardTokenCursor ......... The cursor which iterates tokens only in reverse.
+ * - ForwardTokenCommentCursor ... The cursor which iterates tokens and comments.
+ * - BackwardTokenCommentCursor .. The cursor which iterates tokens and comments in reverse.
+ * - DecorativeCursor
+ * - FilterCursor ............ The cursor which ignores the specified tokens.
+ * - SkipCursor .............. The cursor which ignores the first few tokens.
+ * - LimitCursor ............. The cursor which limits the count of tokens.
+ *
+ */
+module.exports = class Cursor {
+
+ /**
+ * Initializes this cursor.
+ */
+ constructor() {
+ this.current = null;
+ }
+
+ /**
+ * Gets the first token.
+ * This consumes this cursor.
+ * @returns {Token|Comment} The first token or null.
+ */
+ getOneToken() {
+ return this.moveNext() ? this.current : null;
+ }
+
+ /**
+ * Gets the first tokens.
+ * This consumes this cursor.
+ * @returns {(Token|Comment)[]} All tokens.
+ */
+ getAllTokens() {
+ const tokens = [];
+
+ while (this.moveNext()) {
+ tokens.push(this.current);
+ }
+
+ return tokens;
+ }
+
+ /**
+ * Moves this cursor to the next token.
+ * @returns {boolean} `true` if the next token exists.
+ * @abstract
+ */
+ /* istanbul ignore next */
+ moveNext() { // eslint-disable-line class-methods-use-this
+ throw new Error("Not implemented.");
+ }
+};
diff --git a/tools/node_modules/eslint/lib/token-store/cursors.js b/tools/node_modules/eslint/lib/token-store/cursors.js
new file mode 100644
index 0000000000..b315c7e65e
--- /dev/null
+++ b/tools/node_modules/eslint/lib/token-store/cursors.js
@@ -0,0 +1,92 @@
+/**
+ * @fileoverview Define 2 token factories; forward and backward.
+ * @author Toru Nagashima
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const BackwardTokenCommentCursor = require("./backward-token-comment-cursor");
+const BackwardTokenCursor = require("./backward-token-cursor");
+const FilterCursor = require("./filter-cursor");
+const ForwardTokenCommentCursor = require("./forward-token-comment-cursor");
+const ForwardTokenCursor = require("./forward-token-cursor");
+const LimitCursor = require("./limit-cursor");
+const SkipCursor = require("./skip-cursor");
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+/**
+ * The cursor factory.
+ * @private
+ */
+class CursorFactory {
+
+ /**
+ * Initializes this cursor.
+ * @param {Function} TokenCursor - The class of the cursor which iterates tokens only.
+ * @param {Function} TokenCommentCursor - The class of the cursor which iterates the mix of tokens and comments.
+ */
+ constructor(TokenCursor, TokenCommentCursor) {
+ this.TokenCursor = TokenCursor;
+ this.TokenCommentCursor = TokenCommentCursor;
+ }
+
+ /**
+ * Creates a base cursor instance that can be decorated by createCursor.
+ *
+ * @param {Token[]} tokens - The array of tokens.
+ * @param {Comment[]} comments - The array of comments.
+ * @param {Object} indexMap - The map from locations to indices in `tokens`.
+ * @param {number} startLoc - The start location of the iteration range.
+ * @param {number} endLoc - The end location of the iteration range.
+ * @param {boolean} includeComments - The flag to iterate comments as well.
+ * @returns {Cursor} The created base cursor.
+ */
+ createBaseCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments) {
+ const Cursor = includeComments ? this.TokenCommentCursor : this.TokenCursor;
+
+ return new Cursor(tokens, comments, indexMap, startLoc, endLoc);
+ }
+
+ /**
+ * Creates a cursor that iterates tokens with normalized options.
+ *
+ * @param {Token[]} tokens - The array of tokens.
+ * @param {Comment[]} comments - The array of comments.
+ * @param {Object} indexMap - The map from locations to indices in `tokens`.
+ * @param {number} startLoc - The start location of the iteration range.
+ * @param {number} endLoc - The end location of the iteration range.
+ * @param {boolean} includeComments - The flag to iterate comments as well.
+ * @param {Function|null} filter - The predicate function to choose tokens.
+ * @param {number} skip - The count of tokens the cursor skips.
+ * @param {number} count - The maximum count of tokens the cursor iterates. Zero is no iteration for backward compatibility.
+ * @returns {Cursor} The created cursor.
+ */
+ createCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments, filter, skip, count) {
+ let cursor = this.createBaseCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments);
+
+ if (filter) {
+ cursor = new FilterCursor(cursor, filter);
+ }
+ if (skip >= 1) {
+ cursor = new SkipCursor(cursor, skip);
+ }
+ if (count >= 0) {
+ cursor = new LimitCursor(cursor, count);
+ }
+
+ return cursor;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Exports
+//------------------------------------------------------------------------------
+
+exports.forward = new CursorFactory(ForwardTokenCursor, ForwardTokenCommentCursor);
+exports.backward = new CursorFactory(BackwardTokenCursor, BackwardTokenCommentCursor);
diff --git a/tools/node_modules/eslint/lib/token-store/decorative-cursor.js b/tools/node_modules/eslint/lib/token-store/decorative-cursor.js
new file mode 100644
index 0000000000..f0bff9c51d
--- /dev/null
+++ b/tools/node_modules/eslint/lib/token-store/decorative-cursor.js
@@ -0,0 +1,39 @@
+/**
+ * @fileoverview Define the abstract class about cursors which manipulate another cursor.
+ * @author Toru Nagashima
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const Cursor = require("./cursor");
+
+//------------------------------------------------------------------------------
+// Exports
+//------------------------------------------------------------------------------
+
+/**
+ * The abstract class about cursors which manipulate another cursor.
+ */
+module.exports = class DecorativeCursor extends Cursor {
+
+ /**
+ * Initializes this cursor.
+ * @param {Cursor} cursor - The cursor to be decorated.
+ */
+ constructor(cursor) {
+ super();
+ this.cursor = cursor;
+ }
+
+ /** @inheritdoc */
+ moveNext() {
+ const retv = this.cursor.moveNext();
+
+ this.current = this.cursor.current;
+
+ return retv;
+ }
+};
diff --git a/tools/node_modules/eslint/lib/token-store/filter-cursor.js b/tools/node_modules/eslint/lib/token-store/filter-cursor.js
new file mode 100644
index 0000000000..7133627bd3
--- /dev/null
+++ b/tools/node_modules/eslint/lib/token-store/filter-cursor.js
@@ -0,0 +1,43 @@
+/**
+ * @fileoverview Define the cursor which ignores specified tokens.
+ * @author Toru Nagashima
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const DecorativeCursor = require("./decorative-cursor");
+
+//------------------------------------------------------------------------------
+// Exports
+//------------------------------------------------------------------------------
+
+/**
+ * The decorative cursor which ignores specified tokens.
+ */
+module.exports = class FilterCursor extends DecorativeCursor {
+
+ /**
+ * Initializes this cursor.
+ * @param {Cursor} cursor - The cursor to be decorated.
+ * @param {Function} predicate - The predicate function to decide tokens this cursor iterates.
+ */
+ constructor(cursor, predicate) {
+ super(cursor);
+ this.predicate = predicate;
+ }
+
+ /** @inheritdoc */
+ moveNext() {
+ const predicate = this.predicate;
+
+ while (super.moveNext()) {
+ if (predicate(this.current)) {
+ return true;
+ }
+ }
+ return false;
+ }
+};
diff --git a/tools/node_modules/eslint/lib/token-store/forward-token-comment-cursor.js b/tools/node_modules/eslint/lib/token-store/forward-token-comment-cursor.js
new file mode 100644
index 0000000000..be08552970
--- /dev/null
+++ b/tools/node_modules/eslint/lib/token-store/forward-token-comment-cursor.js
@@ -0,0 +1,57 @@
+/**
+ * @fileoverview Define the cursor which iterates tokens and comments.
+ * @author Toru Nagashima
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const Cursor = require("./cursor");
+const utils = require("./utils");
+
+//------------------------------------------------------------------------------
+// Exports
+//------------------------------------------------------------------------------
+
+/**
+ * The cursor which iterates tokens and comments.
+ */
+module.exports = class ForwardTokenCommentCursor extends Cursor {
+
+ /**
+ * Initializes this cursor.
+ * @param {Token[]} tokens - The array of tokens.
+ * @param {Comment[]} comments - The array of comments.
+ * @param {Object} indexMap - The map from locations to indices in `tokens`.
+ * @param {number} startLoc - The start location of the iteration range.
+ * @param {number} endLoc - The end location of the iteration range.
+ */
+ constructor(tokens, comments, indexMap, startLoc, endLoc) {
+ super();
+ this.tokens = tokens;
+ this.comments = comments;
+ this.tokenIndex = utils.getFirstIndex(tokens, indexMap, startLoc);
+ this.commentIndex = utils.search(comments, startLoc);
+ this.border = endLoc;
+ }
+
+ /** @inheritdoc */
+ moveNext() {
+ const token = (this.tokenIndex < this.tokens.length) ? this.tokens[this.tokenIndex] : null;
+ const comment = (this.commentIndex < this.comments.length) ? this.comments[this.commentIndex] : null;
+
+ if (token && (!comment || token.range[0] < comment.range[0])) {
+ this.current = token;
+ this.tokenIndex += 1;
+ } else if (comment) {
+ this.current = comment;
+ this.commentIndex += 1;
+ } else {
+ this.current = null;
+ }
+
+ return Boolean(this.current) && (this.border === -1 || this.current.range[1] <= this.border);
+ }
+};
diff --git a/tools/node_modules/eslint/lib/token-store/forward-token-cursor.js b/tools/node_modules/eslint/lib/token-store/forward-token-cursor.js
new file mode 100644
index 0000000000..523ed398fa
--- /dev/null
+++ b/tools/node_modules/eslint/lib/token-store/forward-token-cursor.js
@@ -0,0 +1,63 @@
+/**
+ * @fileoverview Define the cursor which iterates tokens only.
+ * @author Toru Nagashima
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const Cursor = require("./cursor");
+const utils = require("./utils");
+
+//------------------------------------------------------------------------------
+// Exports
+//------------------------------------------------------------------------------
+
+/**
+ * The cursor which iterates tokens only.
+ */
+module.exports = class ForwardTokenCursor extends Cursor {
+
+ /**
+ * Initializes this cursor.
+ * @param {Token[]} tokens - The array of tokens.
+ * @param {Comment[]} comments - The array of comments.
+ * @param {Object} indexMap - The map from locations to indices in `tokens`.
+ * @param {number} startLoc - The start location of the iteration range.
+ * @param {number} endLoc - The end location of the iteration range.
+ */
+ constructor(tokens, comments, indexMap, startLoc, endLoc) {
+ super();
+ this.tokens = tokens;
+ this.index = utils.getFirstIndex(tokens, indexMap, startLoc);
+ this.indexEnd = utils.getLastIndex(tokens, indexMap, endLoc);
+ }
+
+ /** @inheritdoc */
+ moveNext() {
+ if (this.index <= this.indexEnd) {
+ this.current = this.tokens[this.index];
+ this.index += 1;
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ *
+ * Shorthand for performance.
+ *
+ */
+
+ /** @inheritdoc */
+ getOneToken() {
+ return (this.index <= this.indexEnd) ? this.tokens[this.index] : null;
+ }
+
+ /** @inheritdoc */
+ getAllTokens() {
+ return this.tokens.slice(this.index, this.indexEnd + 1);
+ }
+};
diff --git a/tools/node_modules/eslint/lib/token-store/index.js b/tools/node_modules/eslint/lib/token-store/index.js
new file mode 100644
index 0000000000..1446b9ff02
--- /dev/null
+++ b/tools/node_modules/eslint/lib/token-store/index.js
@@ -0,0 +1,633 @@
+/**
+ * @fileoverview Object to handle access and retrieval of tokens.
+ * @author Brandon Mills
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const assert = require("assert");
+const cursors = require("./cursors");
+const ForwardTokenCursor = require("./forward-token-cursor");
+const PaddedTokenCursor = require("./padded-token-cursor");
+const utils = require("./utils");
+const astUtils = require("../ast-utils");
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+const TOKENS = Symbol("tokens");
+const COMMENTS = Symbol("comments");
+const INDEX_MAP = Symbol("indexMap");
+
+/**
+ * Creates the map from locations to indices in `tokens`.
+ *
+ * The first/last location of tokens is mapped to the index of the token.
+ * The first/last location of comments is mapped to the index of the next token of each comment.
+ *
+ * @param {Token[]} tokens - The array of tokens.
+ * @param {Comment[]} comments - The array of comments.
+ * @returns {Object} The map from locations to indices in `tokens`.
+ * @private
+ */
+function createIndexMap(tokens, comments) {
+ const map = Object.create(null);
+ let tokenIndex = 0;
+ let commentIndex = 0;
+ let nextStart = 0;
+ let range = null;
+
+ while (tokenIndex < tokens.length || commentIndex < comments.length) {
+ nextStart = (commentIndex < comments.length) ? comments[commentIndex].range[0] : Number.MAX_SAFE_INTEGER;
+ while (tokenIndex < tokens.length && (range = tokens[tokenIndex].range)[0] < nextStart) {
+ map[range[0]] = tokenIndex;
+ map[range[1] - 1] = tokenIndex;
+ tokenIndex += 1;
+ }
+
+ nextStart = (tokenIndex < tokens.length) ? tokens[tokenIndex].range[0] : Number.MAX_SAFE_INTEGER;
+ while (commentIndex < comments.length && (range = comments[commentIndex].range)[0] < nextStart) {
+ map[range[0]] = tokenIndex;
+ map[range[1] - 1] = tokenIndex;
+ commentIndex += 1;
+ }
+ }
+
+ return map;
+}
+
+/**
+ * Creates the cursor iterates tokens with options.
+ *
+ * @param {CursorFactory} factory - The cursor factory to initialize cursor.
+ * @param {Token[]} tokens - The array of tokens.
+ * @param {Comment[]} comments - The array of comments.
+ * @param {Object} indexMap - The map from locations to indices in `tokens`.
+ * @param {number} startLoc - The start location of the iteration range.
+ * @param {number} endLoc - The end location of the iteration range.
+ * @param {number|Function|Object} [opts=0] - The option object. If this is a number then it's `opts.skip`. If this is a function then it's `opts.filter`.
+ * @param {boolean} [opts.includeComments=false] - The flag to iterate comments as well.
+ * @param {Function|null} [opts.filter=null] - The predicate function to choose tokens.
+ * @param {number} [opts.skip=0] - The count of tokens the cursor skips.
+ * @returns {Cursor} The created cursor.
+ * @private
+ */
+function createCursorWithSkip(factory, tokens, comments, indexMap, startLoc, endLoc, opts) {
+ let includeComments = false;
+ let skip = 0;
+ let filter = null;
+
+ if (typeof opts === "number") {
+ skip = opts | 0;
+ } else if (typeof opts === "function") {
+ filter = opts;
+ } else if (opts) {
+ includeComments = !!opts.includeComments;
+ skip = opts.skip | 0;
+ filter = opts.filter || null;
+ }
+ assert(skip >= 0, "options.skip should be zero or a positive integer.");
+ assert(!filter || typeof filter === "function", "options.filter should be a function.");
+
+ return factory.createCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments, filter, skip, -1);
+}
+
+/**
+ * Creates the cursor iterates tokens with options.
+ *
+ * @param {CursorFactory} factory - The cursor factory to initialize cursor.
+ * @param {Token[]} tokens - The array of tokens.
+ * @param {Comment[]} comments - The array of comments.
+ * @param {Object} indexMap - The map from locations to indices in `tokens`.
+ * @param {number} startLoc - The start location of the iteration range.
+ * @param {number} endLoc - The end location of the iteration range.
+ * @param {number|Function|Object} [opts=0] - The option object. If this is a number then it's `opts.count`. If this is a function then it's `opts.filter`.
+ * @param {boolean} [opts.includeComments] - The flag to iterate comments as well.
+ * @param {Function|null} [opts.filter=null] - The predicate function to choose tokens.
+ * @param {number} [opts.count=0] - The maximum count of tokens the cursor iterates. Zero is no iteration for backward compatibility.
+ * @returns {Cursor} The created cursor.
+ * @private
+ */
+function createCursorWithCount(factory, tokens, comments, indexMap, startLoc, endLoc, opts) {
+ let includeComments = false;
+ let count = 0;
+ let countExists = false;
+ let filter = null;
+
+ if (typeof opts === "number") {
+ count = opts | 0;
+ countExists = true;
+ } else if (typeof opts === "function") {
+ filter = opts;
+ } else if (opts) {
+ includeComments = !!opts.includeComments;
+ count = opts.count | 0;
+ countExists = typeof opts.count === "number";
+ filter = opts.filter || null;
+ }
+ assert(count >= 0, "options.count should be zero or a positive integer.");
+ assert(!filter || typeof filter === "function", "options.filter should be a function.");
+
+ return factory.createCursor(tokens, comments, indexMap, startLoc, endLoc, includeComments, filter, 0, countExists ? count : -1);
+}
+
+/**
+ * Creates the cursor iterates tokens with options.
+ * This is overload function of the below.
+ *
+ * @param {Token[]} tokens - The array of tokens.
+ * @param {Comment[]} comments - The array of comments.
+ * @param {Object} indexMap - The map from locations to indices in `tokens`.
+ * @param {number} startLoc - The start location of the iteration range.
+ * @param {number} endLoc - The end location of the iteration range.
+ * @param {Function|Object} opts - The option object. If this is a function then it's `opts.filter`.
+ * @param {boolean} [opts.includeComments] - The flag to iterate comments as well.
+ * @param {Function|null} [opts.filter=null] - The predicate function to choose tokens.
+ * @param {number} [opts.count=0] - The maximum count of tokens the cursor iterates. Zero is no iteration for backward compatibility.
+ * @returns {Cursor} The created cursor.
+ * @private
+ */
+/**
+ * Creates the cursor iterates tokens with options.
+ *
+ * @param {Token[]} tokens - The array of tokens.
+ * @param {Comment[]} comments - The array of comments.
+ * @param {Object} indexMap - The map from locations to indices in `tokens`.
+ * @param {number} startLoc - The start location of the iteration range.
+ * @param {number} endLoc - The end location of the iteration range.
+ * @param {number} [beforeCount=0] - The number of tokens before the node to retrieve.
+ * @param {boolean} [afterCount=0] - The number of tokens after the node to retrieve.
+ * @returns {Cursor} The created cursor.
+ * @private
+ */
+function createCursorWithPadding(tokens, comments, indexMap, startLoc, endLoc, beforeCount, afterCount) {
+ if (typeof beforeCount === "undefined" && typeof afterCount === "undefined") {
+ return new ForwardTokenCursor(tokens, comments, indexMap, startLoc, endLoc);
+ }
+ if (typeof beforeCount === "number" || typeof beforeCount === "undefined") {
+ return new PaddedTokenCursor(tokens, comments, indexMap, startLoc, endLoc, beforeCount | 0, afterCount | 0);
+ }
+ return createCursorWithCount(cursors.forward, tokens, comments, indexMap, startLoc, endLoc, beforeCount);
+}
+
+/**
+ * Gets comment tokens that are adjacent to the current cursor position.
+ * @param {Cursor} cursor - A cursor instance.
+ * @returns {Array} An array of comment tokens adjacent to the current cursor position.
+ * @private
+ */
+function getAdjacentCommentTokensFromCursor(cursor) {
+ const tokens = [];
+ let currentToken = cursor.getOneToken();
+
+ while (currentToken && astUtils.isCommentToken(currentToken)) {
+ tokens.push(currentToken);
+ currentToken = cursor.getOneToken();
+ }
+
+ return tokens;
+}
+
+//------------------------------------------------------------------------------
+// Exports
+//------------------------------------------------------------------------------
+
+/**
+ * The token store.
+ *
+ * This class provides methods to get tokens by locations as fast as possible.
+ * The methods are a part of public API, so we should be careful if it changes this class.
+ *
+ * People can get tokens in O(1) by the hash map which is mapping from the location of tokens/comments to tokens.
+ * Also people can get a mix of tokens and comments in O(log k), the k is the number of comments.
+ * Assuming that comments to be much fewer than tokens, this does not make hash map from token's locations to comments to reduce memory cost.
+ * This uses binary-searching instead for comments.
+ */
+module.exports = class TokenStore {
+
+ /**
+ * Initializes this token store.
+ * @param {Token[]} tokens - The array of tokens.
+ * @param {Comment[]} comments - The array of comments.
+ */
+ constructor(tokens, comments) {
+ this[TOKENS] = tokens;
+ this[COMMENTS] = comments;
+ this[INDEX_MAP] = createIndexMap(tokens, comments);
+ }
+
+ //--------------------------------------------------------------------------
+ // Gets single token.
+ //--------------------------------------------------------------------------
+
+ /**
+ * Gets the token starting at the specified index.
+ * @param {number} offset - Index of the start of the token's range.
+ * @param {Object} [options=0] - The option object.
+ * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
+ * @returns {Token|null} The token starting at index, or null if no such token.
+ */
+ getTokenByRangeStart(offset, options) {
+ const includeComments = options && options.includeComments;
+ const token = cursors.forward.createBaseCursor(
+ this[TOKENS],
+ this[COMMENTS],
+ this[INDEX_MAP],
+ offset,
+ -1,
+ includeComments
+ ).getOneToken();
+
+ if (token && token.range[0] === offset) {
+ return token;
+ }
+ return null;
+ }
+
+ /**
+ * Gets the first token of the given node.
+ * @param {ASTNode} node - The AST node.
+ * @param {number|Function|Object} [options=0] - The option object. If this is a number then it's `options.skip`. If this is a function then it's `options.filter`.
+ * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
+ * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
+ * @param {number} [options.skip=0] - The count of tokens the cursor skips.
+ * @returns {Token|null} An object representing the token.
+ */
+ getFirstToken(node, options) {
+ return createCursorWithSkip(
+ cursors.forward,
+ this[TOKENS],
+ this[COMMENTS],
+ this[INDEX_MAP],
+ node.range[0],
+ node.range[1],
+ options
+ ).getOneToken();
+ }
+
+ /**
+ * Gets the last token of the given node.
+ * @param {ASTNode} node - The AST node.
+ * @param {number|Function|Object} [options=0] - The option object. Same options as getFirstToken()
+ * @returns {Token|null} An object representing the token.
+ */
+ getLastToken(node, options) {
+ return createCursorWithSkip(
+ cursors.backward,
+ this[TOKENS],
+ this[COMMENTS],
+ this[INDEX_MAP],
+ node.range[0],
+ node.range[1],
+ options
+ ).getOneToken();
+ }
+
+ /**
+ * Gets the token that precedes a given node or token.
+ * @param {ASTNode|Token|Comment} node - The AST node or token.
+ * @param {number|Function|Object} [options=0] - The option object. Same options as getFirstToken()
+ * @returns {Token|null} An object representing the token.
+ */
+ getTokenBefore(node, options) {
+ return createCursorWithSkip(
+ cursors.backward,
+ this[TOKENS],
+ this[COMMENTS],
+ this[INDEX_MAP],
+ -1,
+ node.range[0],
+ options
+ ).getOneToken();
+ }
+
+ /**
+ * Gets the token that follows a given node or token.
+ * @param {ASTNode|Token|Comment} node - The AST node or token.
+ * @param {number|Function|Object} [options=0] - The option object. Same options as getFirstToken()
+ * @returns {Token|null} An object representing the token.
+ */
+ getTokenAfter(node, options) {
+ return createCursorWithSkip(
+ cursors.forward,
+ this[TOKENS],
+ this[COMMENTS],
+ this[INDEX_MAP],
+ node.range[1],
+ -1,
+ options
+ ).getOneToken();
+ }
+
+ /**
+ * Gets the first token between two non-overlapping nodes.
+ * @param {ASTNode|Token|Comment} left - Node before the desired token range.
+ * @param {ASTNode|Token|Comment} right - Node after the desired token range.
+ * @param {number|Function|Object} [options=0] - The option object. Same options as getFirstToken()
+ * @returns {Token|null} An object representing the token.
+ */
+ getFirstTokenBetween(left, right, options) {
+ return createCursorWithSkip(
+ cursors.forward,
+ this[TOKENS],
+ this[COMMENTS],
+ this[INDEX_MAP],
+ left.range[1],
+ right.range[0],
+ options
+ ).getOneToken();
+ }
+
+ /**
+ * Gets the last token between two non-overlapping nodes.
+ * @param {ASTNode|Token|Comment} left Node before the desired token range.
+ * @param {ASTNode|Token|Comment} right Node after the desired token range.
+ * @param {number|Function|Object} [options=0] - The option object. Same options as getFirstToken()
+ * @returns {Token|null} An object representing the token.
+ */
+ getLastTokenBetween(left, right, options) {
+ return createCursorWithSkip(
+ cursors.backward,
+ this[TOKENS],
+ this[COMMENTS],
+ this[INDEX_MAP],
+ left.range[1],
+ right.range[0],
+ options
+ ).getOneToken();
+ }
+
+ /**
+ * Gets the token that precedes a given node or token in the token stream.
+ * This is defined for backward compatibility. Use `includeComments` option instead.
+ * TODO: We have a plan to remove this in a future major version.
+ * @param {ASTNode|Token|Comment} node The AST node or token.
+ * @param {number} [skip=0] A number of tokens to skip.
+ * @returns {Token|null} An object representing the token.
+ * @deprecated
+ */
+ getTokenOrCommentBefore(node, skip) {
+ return this.getTokenBefore(node, { includeComments: true, skip });
+ }
+
+ /**
+ * Gets the token that follows a given node or token in the token stream.
+ * This is defined for backward compatibility. Use `includeComments` option instead.
+ * TODO: We have a plan to remove this in a future major version.
+ * @param {ASTNode|Token|Comment} node The AST node or token.
+ * @param {number} [skip=0] A number of tokens to skip.
+ * @returns {Token|null} An object representing the token.
+ * @deprecated
+ */
+ getTokenOrCommentAfter(node, skip) {
+ return this.getTokenAfter(node, { includeComments: true, skip });
+ }
+
+ //--------------------------------------------------------------------------
+ // Gets multiple tokens.
+ //--------------------------------------------------------------------------
+
+ /**
+ * Gets the first `count` tokens of the given node.
+ * @param {ASTNode} node - The AST node.
+ * @param {number|Function|Object} [options=0] - The option object. If this is a number then it's `options.count`. If this is a function then it's `options.filter`.
+ * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
+ * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
+ * @param {number} [options.count=0] - The maximum count of tokens the cursor iterates.
+ * @returns {Token[]} Tokens.
+ */
+ getFirstTokens(node, options) {
+ return createCursorWithCount(
+ cursors.forward,
+ this[TOKENS],
+ this[COMMENTS],
+ this[INDEX_MAP],
+ node.range[0],
+ node.range[1],
+ options
+ ).getAllTokens();
+ }
+
+ /**
+ * Gets the last `count` tokens of the given node.
+ * @param {ASTNode} node - The AST node.
+ * @param {number|Function|Object} [options=0] - The option object. Same options as getFirstTokens()
+ * @returns {Token[]} Tokens.
+ */
+ getLastTokens(node, options) {
+ return createCursorWithCount(
+ cursors.backward,
+ this[TOKENS],
+ this[COMMENTS],
+ this[INDEX_MAP],
+ node.range[0],
+ node.range[1],
+ options
+ ).getAllTokens().reverse();
+ }
+
+ /**
+ * Gets the `count` tokens that precedes a given node or token.
+ * @param {ASTNode|Token|Comment} node - The AST node or token.
+ * @param {number|Function|Object} [options=0] - The option object. Same options as getFirstTokens()
+ * @returns {Token[]} Tokens.
+ */
+ getTokensBefore(node, options) {
+ return createCursorWithCount(
+ cursors.backward,
+ this[TOKENS],
+ this[COMMENTS],
+ this[INDEX_MAP],
+ -1,
+ node.range[0],
+ options
+ ).getAllTokens().reverse();
+ }
+
+ /**
+ * Gets the `count` tokens that follows a given node or token.
+ * @param {ASTNode|Token|Comment} node - The AST node or token.
+ * @param {number|Function|Object} [options=0] - The option object. Same options as getFirstTokens()
+ * @returns {Token[]} Tokens.
+ */
+ getTokensAfter(node, options) {
+ return createCursorWithCount(
+ cursors.forward,
+ this[TOKENS],
+ this[COMMENTS],
+ this[INDEX_MAP],
+ node.range[1],
+ -1,
+ options
+ ).getAllTokens();
+ }
+
+ /**
+ * Gets the first `count` tokens between two non-overlapping nodes.
+ * @param {ASTNode|Token|Comment} left - Node before the desired token range.
+ * @param {ASTNode|Token|Comment} right - Node after the desired token range.
+ * @param {number|Function|Object} [options=0] - The option object. Same options as getFirstTokens()
+ * @returns {Token[]} Tokens between left and right.
+ */
+ getFirstTokensBetween(left, right, options) {
+ return createCursorWithCount(
+ cursors.forward,
+ this[TOKENS],
+ this[COMMENTS],
+ this[INDEX_MAP],
+ left.range[1],
+ right.range[0],
+ options
+ ).getAllTokens();
+ }
+
+ /**
+ * Gets the last `count` tokens between two non-overlapping nodes.
+ * @param {ASTNode|Token|Comment} left Node before the desired token range.
+ * @param {ASTNode|Token|Comment} right Node after the desired token range.
+ * @param {number|Function|Object} [options=0] - The option object. Same options as getFirstTokens()
+ * @returns {Token[]} Tokens between left and right.
+ */
+ getLastTokensBetween(left, right, options) {
+ return createCursorWithCount(
+ cursors.backward,
+ this[TOKENS],
+ this[COMMENTS],
+ this[INDEX_MAP],
+ left.range[1],
+ right.range[0],
+ options
+ ).getAllTokens().reverse();
+ }
+
+ /**
+ * Gets all tokens that are related to the given node.
+ * @param {ASTNode} node - The AST node.
+ * @param {Function|Object} options The option object. If this is a function then it's `options.filter`.
+ * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
+ * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
+ * @param {number} [options.count=0] - The maximum count of tokens the cursor iterates.
+ * @returns {Token[]} Array of objects representing tokens.
+ */
+ /**
+ * Gets all tokens that are related to the given node.
+ * @param {ASTNode} node - The AST node.
+ * @param {int} [beforeCount=0] - The number of tokens before the node to retrieve.
+ * @param {int} [afterCount=0] - The number of tokens after the node to retrieve.
+ * @returns {Token[]} Array of objects representing tokens.
+ */
+ getTokens(node, beforeCount, afterCount) {
+ return createCursorWithPadding(
+ this[TOKENS],
+ this[COMMENTS],
+ this[INDEX_MAP],
+ node.range[0],
+ node.range[1],
+ beforeCount,
+ afterCount
+ ).getAllTokens();
+ }
+
+ /**
+ * Gets all of the tokens between two non-overlapping nodes.
+ * @param {ASTNode|Token|Comment} left Node before the desired token range.
+ * @param {ASTNode|Token|Comment} right Node after the desired token range.
+ * @param {Function|Object} options The option object. If this is a function then it's `options.filter`.
+ * @param {boolean} [options.includeComments=false] - The flag to iterate comments as well.
+ * @param {Function|null} [options.filter=null] - The predicate function to choose tokens.
+ * @param {number} [options.count=0] - The maximum count of tokens the cursor iterates.
+ * @returns {Token[]} Tokens between left and right.
+ */
+ /**
+ * Gets all of the tokens between two non-overlapping nodes.
+ * @param {ASTNode|Token|Comment} left Node before the desired token range.
+ * @param {ASTNode|Token|Comment} right Node after the desired token range.
+ * @param {int} [padding=0] Number of extra tokens on either side of center.
+ * @returns {Token[]} Tokens between left and right.
+ */
+ getTokensBetween(left, right, padding) {
+ return createCursorWithPadding(
+ this[TOKENS],
+ this[COMMENTS],
+ this[INDEX_MAP],
+ left.range[1],
+ right.range[0],
+ padding,
+ padding
+ ).getAllTokens();
+ }
+
+ //--------------------------------------------------------------------------
+ // Others.
+ //--------------------------------------------------------------------------
+
+ /**
+ * Checks whether any comments exist or not between the given 2 nodes.
+ *
+ * @param {ASTNode} left - The node to check.
+ * @param {ASTNode} right - The node to check.
+ * @returns {boolean} `true` if one or more comments exist.
+ */
+ commentsExistBetween(left, right) {
+ const index = utils.search(this[COMMENTS], left.range[1]);
+
+ return (
+ index < this[COMMENTS].length &&
+ this[COMMENTS][index].range[1] <= right.range[0]
+ );
+ }
+
+ /**
+ * Gets all comment tokens directly before the given node or token.
+ * @param {ASTNode|token} nodeOrToken The AST node or token to check for adjacent comment tokens.
+ * @returns {Array} An array of comments in occurrence order.
+ */
+ getCommentsBefore(nodeOrToken) {
+ const cursor = createCursorWithCount(
+ cursors.backward,
+ this[TOKENS],
+ this[COMMENTS],
+ this[INDEX_MAP],
+ -1,
+ nodeOrToken.range[0],
+ { includeComments: true }
+ );
+
+ return getAdjacentCommentTokensFromCursor(cursor).reverse();
+ }
+
+ /**
+ * Gets all comment tokens directly after the given node or token.
+ * @param {ASTNode|token} nodeOrToken The AST node or token to check for adjacent comment tokens.
+ * @returns {Array} An array of comments in occurrence order.
+ */
+ getCommentsAfter(nodeOrToken) {
+ const cursor = createCursorWithCount(
+ cursors.forward,
+ this[TOKENS],
+ this[COMMENTS],
+ this[INDEX_MAP],
+ nodeOrToken.range[1],
+ -1,
+ { includeComments: true }
+ );
+
+ return getAdjacentCommentTokensFromCursor(cursor);
+ }
+
+ /**
+ * Gets all comment tokens inside the given node.
+ * @param {ASTNode} node The AST node to get the comments for.
+ * @returns {Array} An array of comments in occurrence order.
+ */
+ getCommentsInside(node) {
+ return this.getTokens(node, {
+ includeComments: true,
+ filter: astUtils.isCommentToken
+ });
+ }
+};
diff --git a/tools/node_modules/eslint/lib/token-store/limit-cursor.js b/tools/node_modules/eslint/lib/token-store/limit-cursor.js
new file mode 100644
index 0000000000..efb46cf0e3
--- /dev/null
+++ b/tools/node_modules/eslint/lib/token-store/limit-cursor.js
@@ -0,0 +1,40 @@
+/**
+ * @fileoverview Define the cursor which limits the number of tokens.
+ * @author Toru Nagashima
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const DecorativeCursor = require("./decorative-cursor");
+
+//------------------------------------------------------------------------------
+// Exports
+//------------------------------------------------------------------------------
+
+/**
+ * The decorative cursor which limits the number of tokens.
+ */
+module.exports = class LimitCursor extends DecorativeCursor {
+
+ /**
+ * Initializes this cursor.
+ * @param {Cursor} cursor - The cursor to be decorated.
+ * @param {number} count - The count of tokens this cursor iterates.
+ */
+ constructor(cursor, count) {
+ super(cursor);
+ this.count = count;
+ }
+
+ /** @inheritdoc */
+ moveNext() {
+ if (this.count > 0) {
+ this.count -= 1;
+ return super.moveNext();
+ }
+ return false;
+ }
+};
diff --git a/tools/node_modules/eslint/lib/token-store/padded-token-cursor.js b/tools/node_modules/eslint/lib/token-store/padded-token-cursor.js
new file mode 100644
index 0000000000..c083aed1e9
--- /dev/null
+++ b/tools/node_modules/eslint/lib/token-store/padded-token-cursor.js
@@ -0,0 +1,38 @@
+/**
+ * @fileoverview Define the cursor which iterates tokens only, with inflated range.
+ * @author Toru Nagashima
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const ForwardTokenCursor = require("./forward-token-cursor");
+
+//------------------------------------------------------------------------------
+// Exports
+//------------------------------------------------------------------------------
+
+/**
+ * The cursor which iterates tokens only, with inflated range.
+ * This is for the backward compatibility of padding options.
+ */
+module.exports = class PaddedTokenCursor extends ForwardTokenCursor {
+
+ /**
+ * Initializes this cursor.
+ * @param {Token[]} tokens - The array of tokens.
+ * @param {Comment[]} comments - The array of comments.
+ * @param {Object} indexMap - The map from locations to indices in `tokens`.
+ * @param {number} startLoc - The start location of the iteration range.
+ * @param {number} endLoc - The end location of the iteration range.
+ * @param {number} beforeCount - The number of tokens this cursor iterates before start.
+ * @param {number} afterCount - The number of tokens this cursor iterates after end.
+ */
+ constructor(tokens, comments, indexMap, startLoc, endLoc, beforeCount, afterCount) {
+ super(tokens, comments, indexMap, startLoc, endLoc);
+ this.index = Math.max(0, this.index - beforeCount);
+ this.indexEnd = Math.min(tokens.length - 1, this.indexEnd + afterCount);
+ }
+};
diff --git a/tools/node_modules/eslint/lib/token-store/skip-cursor.js b/tools/node_modules/eslint/lib/token-store/skip-cursor.js
new file mode 100644
index 0000000000..ab34dfab0d
--- /dev/null
+++ b/tools/node_modules/eslint/lib/token-store/skip-cursor.js
@@ -0,0 +1,42 @@
+/**
+ * @fileoverview Define the cursor which ignores the first few tokens.
+ * @author Toru Nagashima
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const DecorativeCursor = require("./decorative-cursor");
+
+//------------------------------------------------------------------------------
+// Exports
+//------------------------------------------------------------------------------
+
+/**
+ * The decorative cursor which ignores the first few tokens.
+ */
+module.exports = class SkipCursor extends DecorativeCursor {
+
+ /**
+ * Initializes this cursor.
+ * @param {Cursor} cursor - The cursor to be decorated.
+ * @param {number} count - The count of tokens this cursor skips.
+ */
+ constructor(cursor, count) {
+ super(cursor);
+ this.count = count;
+ }
+
+ /** @inheritdoc */
+ moveNext() {
+ while (this.count > 0) {
+ this.count -= 1;
+ if (!super.moveNext()) {
+ return false;
+ }
+ }
+ return super.moveNext();
+ }
+};
diff --git a/tools/node_modules/eslint/lib/token-store/utils.js b/tools/node_modules/eslint/lib/token-store/utils.js
new file mode 100644
index 0000000000..34b0a9af6d
--- /dev/null
+++ b/tools/node_modules/eslint/lib/token-store/utils.js
@@ -0,0 +1,104 @@
+/**
+ * @fileoverview Define utilify functions for token store.
+ * @author Toru Nagashima
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const lodash = require("lodash");
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+/**
+ * Gets `token.range[0]` from the given token.
+ *
+ * @param {Node|Token|Comment} token - The token to get.
+ * @returns {number} The start location.
+ * @private
+ */
+function getStartLocation(token) {
+ return token.range[0];
+}
+
+//------------------------------------------------------------------------------
+// Exports
+//------------------------------------------------------------------------------
+
+/**
+ * Binary-searches the index of the first token which is after the given location.
+ * If it was not found, this returns `tokens.length`.
+ *
+ * @param {(Token|Comment)[]} tokens - It searches the token in this list.
+ * @param {number} location - The location to search.
+ * @returns {number} The found index or `tokens.length`.
+ */
+exports.search = function search(tokens, location) {
+ return lodash.sortedIndexBy(
+ tokens,
+ { range: [location] },
+ getStartLocation
+ );
+};
+
+/**
+ * Gets the index of the `startLoc` in `tokens`.
+ * `startLoc` can be the value of `node.range[1]`, so this checks about `startLoc - 1` as well.
+ *
+ * @param {(Token|Comment)[]} tokens - The tokens to find an index.
+ * @param {Object} indexMap - The map from locations to indices.
+ * @param {number} startLoc - The location to get an index.
+ * @returns {number} The index.
+ */
+exports.getFirstIndex = function getFirstIndex(tokens, indexMap, startLoc) {
+ if (startLoc in indexMap) {
+ return indexMap[startLoc];
+ }
+ if ((startLoc - 1) in indexMap) {
+ const index = indexMap[startLoc - 1];
+ const token = (index >= 0 && index < tokens.length) ? tokens[index] : null;
+
+ /*
+ * For the map of "comment's location -> token's index", it points the next token of a comment.
+ * In that case, +1 is unnecessary.
+ */
+ if (token && token.range[0] >= startLoc) {
+ return index;
+ }
+ return index + 1;
+ }
+ return 0;
+};
+
+/**
+ * Gets the index of the `endLoc` in `tokens`.
+ * The information of end locations are recorded at `endLoc - 1` in `indexMap`, so this checks about `endLoc - 1` as well.
+ *
+ * @param {(Token|Comment)[]} tokens - The tokens to find an index.
+ * @param {Object} indexMap - The map from locations to indices.
+ * @param {number} endLoc - The location to get an index.
+ * @returns {number} The index.
+ */
+exports.getLastIndex = function getLastIndex(tokens, indexMap, endLoc) {
+ if (endLoc in indexMap) {
+ return indexMap[endLoc] - 1;
+ }
+ if ((endLoc - 1) in indexMap) {
+ const index = indexMap[endLoc - 1];
+ const token = (index >= 0 && index < tokens.length) ? tokens[index] : null;
+
+ /*
+ * For the map of "comment's location -> token's index", it points the next token of a comment.
+ * In that case, -1 is necessary.
+ */
+ if (token && token.range[1] > endLoc) {
+ return index - 1;
+ }
+ return index;
+ }
+ return tokens.length - 1;
+};