-
-
Save mysticatea/ff83097cdebb0aad79fe6cccc29d4f50 to your computer and use it in GitHub Desktop.
Generators version of TokenStore. This was 15% slower than the cursor class version.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @fileoverview Object to handle access and retrieval of tokens. | |
* @author Brandon Mills | |
*/ | |
"use strict"; | |
//------------------------------------------------------------------------------ | |
// Implementation | |
//------------------------------------------------------------------------------ | |
const PUBLIC_METHODS = Object.freeze([ | |
"getTokenByRangeStart", | |
"getFirstToken", | |
"getLastToken", | |
"getTokenBefore", | |
"getTokenAfter", | |
"getFirstTokenBetween", | |
"getLastTokenBetween", | |
"getFirstTokens", | |
"getLastTokens", | |
"getTokensBefore", | |
"getTokensAfter", | |
"getFirstTokensBetween", | |
"getLastTokensBetween", | |
"getTokens", | |
"getTokensBetween", | |
"getTokenOrCommentBefore", | |
"getTokenOrCommentAfter" | |
]); | |
/** | |
* 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`. | |
* @private | |
*/ | |
function search(tokens, location) { | |
let left = 0; | |
let right = tokens.length - 1; | |
while (left <= right) { | |
const middle = (left + right) / 2 | 0; | |
const value = tokens[middle].range[0]; | |
if (value < location) { | |
left = middle + 1; | |
} else if (value > location) { | |
right = middle - 1; | |
} else { | |
return middle; | |
} | |
} | |
return Math.max(left, right); | |
} | |
function getStartOffset(tokens, index) { | |
return (index < tokens.length) ? tokens[index].range[0] : Number.MAX_SAFE_INTEGER; | |
} | |
function getEndOffset(tokens, index) { | |
return (index >= 0) ? tokens[index].range[1] : 0; | |
} | |
function isBefore(tokens, index, border, end) { | |
return ( | |
index < tokens.length && | |
tokens[index].range[0] < border && | |
tokens[index].range[1] <= end | |
); | |
} | |
function isAfter(tokens, index, border, start) { | |
return ( | |
index >= 0 && | |
tokens[index].range[1] > border && | |
tokens[index].range[0] >= start | |
); | |
} | |
const iterationFwd = { | |
*tokens(tokens, comments, imap, start, end) { | |
for (let i = imap.firstOf(start), last = imap.lastOf(end); i <= last; ++i) { | |
yield tokens[i]; | |
} | |
}, | |
*tokensAndComments(tokens, comments, imap, start, end) { | |
let t = imap.firstOf(start); | |
let c = search(comments, start); | |
let border = 0; | |
while ((t < tokens.length && tokens[t].range[1] <= end) || (c < comments.length && comments[c].range[1] <= end)) { | |
border = getStartOffset(comments, c); | |
while (isBefore(tokens, t, border, end)) { | |
yield tokens[t]; | |
t += 1; | |
} | |
border = getStartOffset(tokens, t); | |
while (isBefore(comments, c, border, end)) { | |
yield comments[c]; | |
c += 1; | |
} | |
} | |
} | |
}; | |
const iterationBwd = { | |
*tokens(tokens, comments, imap, start, end) { | |
for (let i = imap.lastOf(end), first = imap.firstOf(start); i >= first; --i) { | |
yield tokens[i]; | |
} | |
}, | |
*tokensAndComments(tokens, comments, imap, start, end) { | |
let t = imap.lastOf(end); | |
let c = search(comments, end) - 1; | |
let border = 0; | |
while ((t >= 0 && tokens[t].range[0] >= start) || (c >= 0 && comments[c].range[0] >= start)) { | |
border = getEndOffset(comments, c); | |
while (isAfter(tokens, t, border, start)) { | |
yield tokens[t]; | |
t -= 1; | |
} | |
border = getEndOffset(tokens, t); | |
while (isAfter(comments, c, border, start)) { | |
yield comments[c]; | |
c -= 1; | |
} | |
} | |
} | |
}; | |
function *iterateTokensPad(tokens, comments, imap, start, end, beforeCount, afterCount) { | |
for (let i = Math.max(0, imap.firstOf(start) - beforeCount), last = Math.min(tokens.length - 1, imap.lastOf(end) + afterCount); i <= last; ++i) { | |
yield tokens[i]; | |
} | |
} | |
function *filter(iterable, predicate) { | |
for (const token of iterable) { | |
if (predicate(token)) { | |
yield token; | |
} | |
} | |
} | |
function *skip(iterable, count) { | |
let i = 0; | |
for (const token of iterable) { | |
if (++i > count) { | |
yield token; | |
} | |
} | |
} | |
function *take(iterable, count) { | |
let i = 0; | |
for (const token of iterable) { | |
if (++i > count) { | |
break; | |
} | |
yield token; | |
} | |
} | |
/** | |
* Iterates tokens with normalized options. | |
* | |
* @param {Function} iterateTokens - The function iterate tokens only. | |
* @param {Function} iterateTokensAndComments - The function iterate tokens and comments. | |
* @param {Token[]} tokens - The array of tokens. | |
* @param {Comment[]} comments - The array of comments. | |
* @param {IndexMap} imap - The map from locations to indices in `this.tokens`. | |
* @param {number} start - The start location of the iteration range. | |
* @param {number} end - The end location of the iteration range. | |
* @param {boolean} includeComments - The flag to iterate comments as well. | |
* @param {Function|null} predicate - The predicate function to choose tokens. | |
* @param {number} skipCount - The count of tokens the iterator skips. | |
* @param {number} takeCount - The maximum count of tokens the iterator iterates. Zero is no iteration for backward compatibility. | |
* @returns {IterableIterator<(Token|Comment)>} The created iterator. | |
* @private | |
*/ | |
function iterateWith(iteration, tokens, comments, imap, start, end, includeComments, predicate, skipCount, takeCount) { | |
const iterate = includeComments ? iteration.tokensAndComments : iteration.tokens; | |
let it = iterate(tokens, comments, imap, start, end); | |
if (predicate) { | |
it = filter(it, predicate); | |
} | |
if (skipCount >= 1) { | |
it = skip(it, skipCount); | |
} | |
if (takeCount >= 0) { | |
it = take(it, takeCount); | |
} | |
return it; | |
} | |
/** | |
* Iterates tokens with skip options. | |
* | |
* @param {Function} iterateTokens - The function iterate tokens only. | |
* @param {Function} iterateTokensAndComments - The function iterate tokens and comments. | |
* @param {Token[]} tokens - The array of tokens. | |
* @param {Comment[]} comments - The array of comments. | |
* @param {Object} imap - The map from locations to indices in `this.tokens`. | |
* @param {number} start - The start location of the iteration range. | |
* @param {number} end - 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 iterator skips. | |
* @returns {IterableIterator<(Token|Comment)>} The created iterator. | |
* @private | |
*/ | |
function iterateWithSkip(iteration, tokens, comments, imap, start, end, opts) { | |
let includeComments = false; | |
let skipCount = 0; | |
let predicate = null; | |
if (typeof opts === "number") { | |
skipCount = opts | 0; | |
} else if (typeof opts === "function") { | |
predicate = opts; | |
} else if (opts) { | |
includeComments = !!opts.includeComments; | |
skipCount = opts.skip | 0; | |
predicate = opts.filter || null; | |
} | |
return iterateWith(iteration, tokens, comments, imap, start, end, includeComments, predicate, skipCount, -1); | |
} | |
/** | |
* Iterates tokens with count options. | |
* | |
* @param {Function} iterateTokens - The function iterate tokens only. | |
* @param {Function} iterateTokensAndComments - The function iterate tokens and comments. | |
* @param {Token[]} tokens - The array of tokens. | |
* @param {Comment[]} comments - The array of comments. | |
* @param {Object} imap - The map from locations to indices in `this.tokens`. | |
* @param {number} start - The start location of the iteration range. | |
* @param {number} end - 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 iterator iterates. Zero is no iteration for backward compatibility. | |
* @returns {IterableIterator<(Token|Comment)>} The created iterator. | |
* @private | |
*/ | |
function iterateWithCount(iteration, tokens, comments, imap, start, end, opts) { | |
let includeComments = false; | |
let count = 0; | |
let predicate = null; | |
if (typeof opts === "number") { | |
count = opts | 0; | |
} else if (typeof opts === "function") { | |
count = -1; | |
predicate = opts; | |
} else if (opts) { | |
includeComments = !!opts.includeComments; | |
count = (opts.count | 0) || -1; | |
predicate = opts.filter || null; | |
} | |
return iterateWith(iteration, tokens, comments, imap, start, end, includeComments, predicate, 0, count); | |
} | |
/** | |
* Iterates tokens with padding options. | |
* | |
* @param {Token[]} tokens - The array of tokens. | |
* @param {Comment[]} comments - The array of comments. | |
* @param {Object} imap - The map from locations to indices in `this.tokens`. | |
* @param {number} start - The start location of the iteration range. | |
* @param {number} end - 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 iterator iterates. Zero is no iteration for backward compatibility. | |
* @returns {IterableIterator<(Token|Comment)>} The created iterator. | |
* @private | |
*/ | |
/** | |
* Iterates tokens with padding options. | |
* | |
* @param {Token[]} tokens - The array of tokens. | |
* @param {Comment[]} comments - The array of comments. | |
* @param {Object} imap - The map from locations to indices in `this.tokens`. | |
* @param {number} start - The start location of the iteration range. | |
* @param {number} end - 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 {IterableIterator<(Token|Comment)>} The created iterator. | |
* @private | |
*/ | |
function iterateWithPadding(tokens, comments, imap, start, end, beforeCount, afterCount) { | |
if (typeof beforeCount === "undefined" && typeof afterCount === "undefined") { | |
return iterationFwd.tokens(tokens, comments, imap, start, end); | |
} | |
if (typeof beforeCount === "number" || typeof beforeCount === "undefined") { | |
return iterateTokensPad(tokens, comments, imap, start, end, beforeCount | 0, afterCount | 0); | |
} | |
return iterateWithCount(iterationFwd, tokens, comments, imap, start, end, beforeCount); | |
} | |
function getFirstItem(iterable) { | |
for (const token of iterable) { | |
return token; | |
} | |
return null; | |
} | |
class IndexMap { | |
constructor(tokens, comments) { | |
this.lastIndex = tokens.length - 1; | |
const map = this.map = Object.create(null); | |
let t = 0; | |
let c = 0; | |
let border = 0; | |
let range = null; | |
while (t < tokens.length || c < comments.length) { | |
border = getStartOffset(comments, c); | |
while (t < tokens.length && (range = tokens[t].range)[0] < border) { | |
map[range[0]] = t; | |
map[range[1] - 1] = t; | |
t += 1; | |
} | |
border = getStartOffset(tokens, t); | |
while (c < comments.length && (range = comments[c].range)[0] < border) { | |
map[range[0]] = t; | |
map[range[1] - 1] = t; | |
c += 1; | |
} | |
} | |
} | |
/** | |
* Gets the index of the location `offset` in `this.tokens`. | |
* `offset` can be the value of `node.range[1]`, so this checks about `offset - 1` as well. | |
*/ | |
firstOf(offset) { | |
if (typeof this.map[offset] !== "undefined") { | |
return this.map[offset]; | |
} | |
if (typeof this.map[offset - 1] !== "undefined") { | |
return this.map[offset - 1] + 1; | |
} | |
return 0; | |
} | |
/** | |
* Gets the index of the location `offset` in `this.tokens`. | |
* `offset` can be the value of `node.range[0]`, so this checks about `offset - 1` as well. | |
*/ | |
lastOf(offset) { | |
if (typeof this.map[offset] !== "undefined") { | |
return this.map[offset] - 1; | |
} | |
if (typeof this.map[offset - 1] !== "undefined") { | |
return this.map[offset - 1]; | |
} | |
return this.lastIndex; | |
} | |
} | |
class TokenStore { | |
/** | |
* Initializes this token store. | |
* | |
* ※ `comments` needs cloning for backward compatibility. | |
* After this initialization, ESLint removes a shebang's comment from `comments`. | |
* However, so far we had been concatenating 'tokens' and 'comments', | |
* so the shebang's comment had remained in the concatenated array. | |
* As the result, both `getTokenOrCommentAfter` and `getTokenOrCommentBefore` | |
* methods had been returning the shebang's comment. | |
* And some rules depends on this behavior. | |
* | |
* @param {Token[]} tokens - The array of tokens. | |
* @param {Comment[]} comments - The array of comments. | |
*/ | |
constructor(tokens, comments) { | |
this.tokens = tokens; | |
this.comments = comments.slice(0); // Needs cloning for backward compatibility! | |
this.imap = new IndexMap(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. | |
* @returns {Token|null} The token starting at index, or null if no such token. | |
*/ | |
getTokenByRangeStart(offset) { | |
const index = this.imap.firstOf(offset); | |
const token = this.tokens[index] || null; | |
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 getFirstItem(iterateWithSkip( | |
iterationFwd, | |
this.tokens, | |
this.comments, | |
this.imap, | |
node.range[0], | |
node.range[1], | |
options | |
)); | |
} | |
/** | |
* Gets the last 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. | |
*/ | |
getLastToken(node, options) { | |
return getFirstItem(iterateWithSkip( | |
iterationBwd, | |
this.tokens, | |
this.comments, | |
this.imap, | |
node.range[0], | |
node.range[1], | |
options | |
)); | |
} | |
/** | |
* 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. 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. | |
*/ | |
getTokenBefore(node, options) { | |
return getFirstItem(iterateWithSkip( | |
iterationBwd, | |
this.tokens, | |
this.comments, | |
this.imap, | |
0, | |
node.range[0], | |
options | |
)); | |
} | |
/** | |
* 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. 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. | |
*/ | |
getTokenAfter(node, options) { | |
return getFirstItem(iterateWithSkip( | |
iterationFwd, | |
this.tokens, | |
this.comments, | |
this.imap, | |
node.range[1], | |
Number.MAX_SAFE_INTEGER, | |
options | |
)); | |
} | |
/** | |
* 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. 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. | |
*/ | |
getFirstTokenBetween(left, right, options) { | |
return getFirstItem(iterateWithSkip( | |
iterationFwd, | |
this.tokens, | |
this.comments, | |
this.imap, | |
left.range[1], | |
right.range[0], | |
options | |
)); | |
} | |
/** | |
* 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. 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} Tokens between left and right. | |
*/ | |
getLastTokenBetween(left, right, options) { | |
return getFirstItem(iterateWithSkip( | |
iterationBwd, | |
this.tokens, | |
this.comments, | |
this.imap, | |
left.range[1], | |
right.range[0], | |
options | |
)); | |
} | |
/** | |
* Gets the token that precedes a given node or token in the token stream. | |
* @param {ASTNode|Token|Comment} node The AST node or token. | |
* @param {number} [skipCount=0] A number of tokens to skip. | |
* @returns {Token|null} An object representing the token. | |
*/ | |
getTokenOrCommentBefore(node, skipCount) { | |
return this.getTokenBefore(node, { includeComments: true, skip: skipCount }); | |
} | |
/** | |
* Gets the token that follows a given node or token in the token stream. | |
* @param {ASTNode|Token|Comment} node The AST node or token. | |
* @param {number} [skipCount=0] A number of tokens to skip. | |
* @returns {Token|null} An object representing the token. | |
*/ | |
getTokenOrCommentAfter(node, skipCount) { | |
return this.getTokenAfter(node, { includeComments: true, skip: skipCount }); | |
} | |
//-------------------------------------------------------------------------- | |
// 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 Array.from(iterateWithCount( | |
iterationFwd, | |
this.tokens, | |
this.comments, | |
this.imap, | |
node.range[0], | |
node.range[1], | |
options | |
)); | |
} | |
/** | |
* Gets the last `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. | |
*/ | |
getLastTokens(node, options) { | |
return Array.from(iterateWithCount( | |
iterationBwd, | |
this.tokens, | |
this.comments, | |
this.imap, | |
node.range[0], | |
node.range[1], | |
options | |
)).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. 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. | |
*/ | |
getTokensBefore(node, options) { | |
return Array.from(iterateWithCount( | |
iterationBwd, | |
this.tokens, | |
this.comments, | |
this.imap, | |
0, | |
node.range[0], | |
options | |
)).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. 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. | |
*/ | |
getTokensAfter(node, options) { | |
return Array.from(iterateWithCount( | |
iterationFwd, | |
this.tokens, | |
this.comments, | |
this.imap, | |
node.range[1], | |
Number.MAX_SAFE_INTEGER, | |
options | |
)); | |
} | |
/** | |
* 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. 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 between left and right. | |
*/ | |
getFirstTokensBetween(left, right, options) { | |
return Array.from(iterateWithCount( | |
iterationFwd, | |
this.tokens, | |
this.comments, | |
this.imap, | |
left.range[1], | |
right.range[0], | |
options | |
)); | |
} | |
/** | |
* 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. 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 between left and right. | |
*/ | |
getLastTokensBetween(left, right, options) { | |
return Array.from(iterateWithCount( | |
iterationBwd, | |
this.tokens, | |
this.comments, | |
this.imap, | |
left.range[1], | |
right.range[0], | |
options | |
)).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 Array.from(iterateWithPadding( | |
this.tokens, | |
this.comments, | |
this.imap, | |
node.range[0], | |
node.range[1], | |
beforeCount, | |
afterCount | |
)); | |
} | |
/** | |
* 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 Array.from(iterateWithPadding( | |
this.tokens, | |
this.comments, | |
this.imap, | |
left.range[1], | |
right.range[0], | |
padding, | |
padding | |
)); | |
} | |
} | |
//------------------------------------------------------------------------------ | |
// Exports | |
//------------------------------------------------------------------------------ | |
module.exports = TokenStore; | |
module.exports.PUBLIC_METHODS = PUBLIC_METHODS; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment