build: update npm install command to use --legacy-peer-deps
This change modifies the build scripts to use --legacy-peer-deps flag when installing npm dependencies to resolve potential peer dependency conflicts during the build process. The change is applied to both bash (build.sh) and batch (build.bat) build scripts.
This commit is contained in:
Generated
Vendored
+57
@@ -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);
|
||||
}
|
||||
};
|
||||
Generated
Vendored
+58
@@ -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;
|
||||
}
|
||||
};
|
||||
+76
@@ -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
|
||||
*/
|
||||
/* c8 ignore next */
|
||||
moveNext() { // eslint-disable-line class-methods-use-this -- Unused
|
||||
throw new Error("Not implemented.");
|
||||
}
|
||||
};
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* @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);
|
||||
+39
@@ -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;
|
||||
}
|
||||
};
|
||||
+43
@@ -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;
|
||||
}
|
||||
};
|
||||
Generated
Vendored
+57
@@ -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);
|
||||
}
|
||||
};
|
||||
+63
@@ -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);
|
||||
}
|
||||
};
|
||||
+627
@@ -0,0 +1,627 @@
|
||||
/**
|
||||
* @fileoverview Object to handle access and retrieval of tokens.
|
||||
* @author Brandon Mills
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const assert = require("assert");
|
||||
const { isCommentToken } = require("@eslint-community/eslint-utils");
|
||||
const cursors = require("./cursors");
|
||||
const ForwardTokenCursor = require("./forward-token-cursor");
|
||||
const PaddedTokenCursor = require("./padded-token-cursor");
|
||||
const utils = require("./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 && 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: isCommentToken
|
||||
});
|
||||
}
|
||||
};
|
||||
+40
@@ -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;
|
||||
}
|
||||
};
|
||||
+38
@@ -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);
|
||||
}
|
||||
};
|
||||
+42
@@ -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();
|
||||
}
|
||||
};
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @fileoverview Define utility functions for token store.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exports
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Finds 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) {
|
||||
for (let minIndex = 0, maxIndex = tokens.length - 1; minIndex <= maxIndex;) {
|
||||
|
||||
/*
|
||||
* Calculate the index in the middle between minIndex and maxIndex.
|
||||
* `| 0` is used to round a fractional value down to the nearest integer: this is similar to
|
||||
* using `Math.trunc()` or `Math.floor()`, but performance tests have shown this method to
|
||||
* be faster.
|
||||
*/
|
||||
const index = (minIndex + maxIndex) / 2 | 0;
|
||||
const token = tokens[index];
|
||||
const tokenStartLocation = token.range[0];
|
||||
|
||||
if (location <= tokenStartLocation) {
|
||||
if (index === minIndex) {
|
||||
return index;
|
||||
}
|
||||
maxIndex = index;
|
||||
} else {
|
||||
minIndex = index + 1;
|
||||
}
|
||||
}
|
||||
return tokens.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 = tokens[index];
|
||||
|
||||
// If the mapped index is out of bounds, the returned cursor index will point after the end of the tokens array.
|
||||
if (!token) {
|
||||
return tokens.length;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.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 = tokens[index];
|
||||
|
||||
// If the mapped index is out of bounds, the returned cursor index will point before the end of the tokens array.
|
||||
if (!token) {
|
||||
return tokens.length - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.range[1] > endLoc) {
|
||||
return index - 1;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
return tokens.length - 1;
|
||||
};
|
||||
Reference in New Issue
Block a user