• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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