1/** 2 * @fileoverview Define utility functions for token store. 3 * @author Toru Nagashima 4 */ 5"use strict"; 6 7//------------------------------------------------------------------------------ 8// Requirements 9//------------------------------------------------------------------------------ 10 11const lodash = require("lodash"); 12 13//------------------------------------------------------------------------------ 14// Helpers 15//------------------------------------------------------------------------------ 16 17/** 18 * Gets `token.range[0]` from the given token. 19 * @param {Node|Token|Comment} token The token to get. 20 * @returns {number} The start location. 21 * @private 22 */ 23function getStartLocation(token) { 24 return token.range[0]; 25} 26 27//------------------------------------------------------------------------------ 28// Exports 29//------------------------------------------------------------------------------ 30 31/** 32 * Binary-searches the index of the first token which is after the given location. 33 * If it was not found, this returns `tokens.length`. 34 * @param {(Token|Comment)[]} tokens It searches the token in this list. 35 * @param {number} location The location to search. 36 * @returns {number} The found index or `tokens.length`. 37 */ 38exports.search = function search(tokens, location) { 39 return lodash.sortedIndexBy( 40 tokens, 41 { range: [location] }, 42 getStartLocation 43 ); 44}; 45 46/** 47 * Gets the index of the `startLoc` in `tokens`. 48 * `startLoc` can be the value of `node.range[1]`, so this checks about `startLoc - 1` as well. 49 * @param {(Token|Comment)[]} tokens The tokens to find an index. 50 * @param {Object} indexMap The map from locations to indices. 51 * @param {number} startLoc The location to get an index. 52 * @returns {number} The index. 53 */ 54exports.getFirstIndex = function getFirstIndex(tokens, indexMap, startLoc) { 55 if (startLoc in indexMap) { 56 return indexMap[startLoc]; 57 } 58 if ((startLoc - 1) in indexMap) { 59 const index = indexMap[startLoc - 1]; 60 const token = (index >= 0 && index < tokens.length) ? tokens[index] : null; 61 62 /* 63 * For the map of "comment's location -> token's index", it points the next token of a comment. 64 * In that case, +1 is unnecessary. 65 */ 66 if (token && token.range[0] >= startLoc) { 67 return index; 68 } 69 return index + 1; 70 } 71 return 0; 72}; 73 74/** 75 * Gets the index of the `endLoc` in `tokens`. 76 * The information of end locations are recorded at `endLoc - 1` in `indexMap`, so this checks about `endLoc - 1` as well. 77 * @param {(Token|Comment)[]} tokens The tokens to find an index. 78 * @param {Object} indexMap The map from locations to indices. 79 * @param {number} endLoc The location to get an index. 80 * @returns {number} The index. 81 */ 82exports.getLastIndex = function getLastIndex(tokens, indexMap, endLoc) { 83 if (endLoc in indexMap) { 84 return indexMap[endLoc] - 1; 85 } 86 if ((endLoc - 1) in indexMap) { 87 const index = indexMap[endLoc - 1]; 88 const token = (index >= 0 && index < tokens.length) ? tokens[index] : null; 89 90 /* 91 * For the map of "comment's location -> token's index", it points the next token of a comment. 92 * In that case, -1 is necessary. 93 */ 94 if (token && token.range[1] > endLoc) { 95 return index - 1; 96 } 97 return index; 98 } 99 return tokens.length - 1; 100}; 101