mirror of https://github.com/lukechilds/node.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
6.8 KiB
203 lines
6.8 KiB
/**
|
|
* @fileoverview Object to handle access and retrieval of tokens.
|
|
* @author Brandon Mills
|
|
*/
|
|
"use strict";
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Implementation
|
|
//------------------------------------------------------------------------------
|
|
|
|
module.exports = function(tokens) {
|
|
const api = {},
|
|
starts = Object.create(null),
|
|
ends = Object.create(null),
|
|
length = tokens.length;
|
|
|
|
/**
|
|
* Gets tokens in a given interval.
|
|
* @param {int} start Inclusive index of the first token. 0 if negative.
|
|
* @param {int} end Exclusive index of the last token.
|
|
* @returns {Token[]} Tokens in the interval.
|
|
*/
|
|
function get(start, end) {
|
|
const result = [];
|
|
|
|
for (let i = Math.max(0, start); i < end && i < length; i++) {
|
|
result.push(tokens[i]);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Gets the index in the tokens array of the last token belonging to a node.
|
|
* Usually a node ends exactly at a token, but due to ASI, sometimes a
|
|
* node's range extends beyond its last token.
|
|
* @param {ASTNode} node The node for which to find the last token's index.
|
|
* @returns {int} Index in the tokens array of the node's last token.
|
|
*/
|
|
function lastTokenIndex(node) {
|
|
const end = node.range[1];
|
|
let cursor = ends[end];
|
|
|
|
// If the node extends beyond its last token, get the token before the
|
|
// next token
|
|
if (typeof cursor === "undefined") {
|
|
cursor = starts[end] - 1;
|
|
}
|
|
|
|
// If there isn't a next token, the desired token is the last one in the
|
|
// array
|
|
if (isNaN(cursor)) {
|
|
cursor = length - 1;
|
|
}
|
|
|
|
return cursor;
|
|
}
|
|
|
|
// Map tokens' start and end range to the index in the tokens array
|
|
for (let i = 0; i < length; i++) {
|
|
const range = tokens[i].range;
|
|
|
|
starts[range[0]] = i;
|
|
ends[range[1]] = i;
|
|
}
|
|
|
|
/**
|
|
* Gets a number of tokens that precede a given node or token in the token
|
|
* stream.
|
|
* @param {(ASTNode|Token)} node The AST node or token.
|
|
* @param {int} [beforeCount=0] The number of tokens before the node or
|
|
* token to retrieve.
|
|
* @returns {Token[]} Array of objects representing tokens.
|
|
*/
|
|
api.getTokensBefore = function(node, beforeCount) {
|
|
const first = starts[node.range[0]];
|
|
|
|
return get(first - (beforeCount || 0), first);
|
|
};
|
|
|
|
/**
|
|
* Gets the token that precedes a given node or token in the token stream.
|
|
* @param {(ASTNode|Token)} node The AST node or token.
|
|
* @param {int} [skip=0] A number of tokens to skip before the given node or
|
|
* token.
|
|
* @returns {Token} An object representing the token.
|
|
*/
|
|
api.getTokenBefore = function(node, skip) {
|
|
return tokens[starts[node.range[0]] - (skip || 0) - 1];
|
|
};
|
|
|
|
/**
|
|
* Gets a number of tokens that follow a given node or token in the token
|
|
* stream.
|
|
* @param {(ASTNode|Token)} node The AST node or token.
|
|
* @param {int} [afterCount=0] The number of tokens after the node or token
|
|
* to retrieve.
|
|
* @returns {Token[]} Array of objects representing tokens.
|
|
*/
|
|
api.getTokensAfter = function(node, afterCount) {
|
|
const start = lastTokenIndex(node) + 1;
|
|
|
|
return get(start, start + (afterCount || 0));
|
|
};
|
|
|
|
/**
|
|
* Gets the token that follows a given node or token in the token stream.
|
|
* @param {(ASTNode|Token)} node The AST node or token.
|
|
* @param {int} [skip=0] A number of tokens to skip after the given node or
|
|
* token.
|
|
* @returns {Token} An object representing the token.
|
|
*/
|
|
api.getTokenAfter = function(node, skip) {
|
|
return tokens[lastTokenIndex(node) + (skip || 0) + 1];
|
|
};
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
api.getTokens = function(node, beforeCount, afterCount) {
|
|
return get(
|
|
starts[node.range[0]] - (beforeCount || 0),
|
|
lastTokenIndex(node) + (afterCount || 0) + 1
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Gets the first `count` tokens of the given node's token stream.
|
|
* @param {ASTNode} node The AST node.
|
|
* @param {int} [count=0] The number of tokens of the node to retrieve.
|
|
* @returns {Token[]} Array of objects representing tokens.
|
|
*/
|
|
api.getFirstTokens = function(node, count) {
|
|
const first = starts[node.range[0]];
|
|
|
|
return get(
|
|
first,
|
|
Math.min(lastTokenIndex(node) + 1, first + (count || 0))
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Gets the first token of the given node's token stream.
|
|
* @param {ASTNode} node The AST node.
|
|
* @param {int} [skip=0] A number of tokens to skip.
|
|
* @returns {Token} An object representing the token.
|
|
*/
|
|
api.getFirstToken = function(node, skip) {
|
|
return tokens[starts[node.range[0]] + (skip || 0)];
|
|
};
|
|
|
|
/**
|
|
* Gets the last `count` tokens of the given node.
|
|
* @param {ASTNode} node The AST node.
|
|
* @param {int} [count=0] The number of tokens of the node to retrieve.
|
|
* @returns {Token[]} Array of objects representing tokens.
|
|
*/
|
|
api.getLastTokens = function(node, count) {
|
|
const last = lastTokenIndex(node) + 1;
|
|
|
|
return get(Math.max(starts[node.range[0]], last - (count || 0)), last);
|
|
};
|
|
|
|
/**
|
|
* Gets the last token of the given node's token stream.
|
|
* @param {ASTNode} node The AST node.
|
|
* @param {int} [skip=0] A number of tokens to skip.
|
|
* @returns {Token} An object representing the token.
|
|
*/
|
|
api.getLastToken = function(node, skip) {
|
|
return tokens[lastTokenIndex(node) - (skip || 0)];
|
|
};
|
|
|
|
/**
|
|
* Gets all of the tokens between two non-overlapping nodes.
|
|
* @param {ASTNode} left Node before the desired token range.
|
|
* @param {ASTNode} 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 plus padding.
|
|
*/
|
|
api.getTokensBetween = function(left, right, padding) {
|
|
padding = padding || 0;
|
|
return get(
|
|
lastTokenIndex(left) + 1 - padding,
|
|
starts[right.range[0]] + padding
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Gets the token starting at the specified index.
|
|
* @param {int} startIndex Index of the start of the token's range.
|
|
* @returns {Token} The token starting at index, or null if no such token.
|
|
*/
|
|
api.getTokenByRangeStart = function(startIndex) {
|
|
return (tokens[starts[startIndex]] || null);
|
|
};
|
|
|
|
return api;
|
|
};
|
|
|