UNPKG

3.64 kBJavaScriptView Raw
1/**
2 * Returns `i`th number from `base`, continuing from 0 when `max` is reached.
3 * Useful for shifting `for` loop by a fixed number but going over all items.
4 *
5 * @param {Number} i Current index in the loop
6 * @param {Number} base Start index for which to return 0
7 * @param {Number} max Array length
8 * @returns {Number} shiftedIndex
9 */
10
11"use strict";
12
13exports.__esModule = true;
14// istanbul ignore next
15
16function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
17
18function getLookupIndex(i, base, max) {
19 i += base;
20
21 if (i >= max) {
22 i -= max;
23 }
24
25 return i;
26}
27
28/**
29 * Get whitespace around tokens.
30 */
31
32var Whitespace = (function () {
33 function Whitespace(tokens) {
34 _classCallCheck(this, Whitespace);
35
36 this.tokens = tokens;
37 this.used = {};
38
39 // Profiling this code shows that while generator passes over it, indexes
40 // returned by `getNewlinesBefore` and `getNewlinesAfter` are always increasing.
41
42 // We use this implementation detail for an optimization: instead of always
43 // starting to look from `this.tokens[0]`, we will start `for` loops from the
44 // previous successful match. We will enumerate all tokens—but the common
45 // case will be much faster.
46
47 this._lastFoundIndex = 0;
48 }
49
50 /**
51 * Count all the newlines before a node.
52 */
53
54 Whitespace.prototype.getNewlinesBefore = function getNewlinesBefore(node) {
55 var startToken;
56 var endToken;
57 var tokens = this.tokens;
58
59 for (var j = 0; j < tokens.length; j++) {
60 // optimize for forward traversal by shifting for loop index
61 var i = getLookupIndex(j, this._lastFoundIndex, this.tokens.length);
62 var token = tokens[i];
63
64 // this is the token this node starts with
65 if (node.start === token.start) {
66 startToken = tokens[i - 1];
67 endToken = token;
68
69 this._lastFoundIndex = i;
70 break;
71 }
72 }
73
74 return this.getNewlinesBetween(startToken, endToken);
75 };
76
77 /**
78 * Count all the newlines after a node.
79 */
80
81 Whitespace.prototype.getNewlinesAfter = function getNewlinesAfter(node) {
82 var startToken;
83 var endToken;
84 var tokens = this.tokens;
85
86 for (var j = 0; j < tokens.length; j++) {
87 // optimize for forward traversal by shifting for loop index
88 var i = getLookupIndex(j, this._lastFoundIndex, this.tokens.length);
89 var token = tokens[i];
90
91 // this is the token this node ends with
92 if (node.end === token.end) {
93 startToken = token;
94 endToken = tokens[i + 1];
95 if (endToken.type.label === ",") endToken = tokens[i + 2];
96
97 this._lastFoundIndex = i;
98 break;
99 }
100 }
101
102 if (endToken && endToken.type.label === "eof") {
103 return 1;
104 } else {
105 var lines = this.getNewlinesBetween(startToken, endToken);
106 if (node.type === "CommentLine" && !lines) {
107 // line comment
108 return 1;
109 } else {
110 return lines;
111 }
112 }
113 };
114
115 /**
116 * Count all the newlines between two tokens.
117 */
118
119 Whitespace.prototype.getNewlinesBetween = function getNewlinesBetween(startToken, endToken) {
120 if (!endToken || !endToken.loc) return 0;
121
122 var start = startToken ? startToken.loc.end.line : 1;
123 var end = endToken.loc.start.line;
124 var lines = 0;
125
126 for (var line = start; line < end; line++) {
127 if (typeof this.used[line] === "undefined") {
128 this.used[line] = true;
129 lines++;
130 }
131 }
132
133 return lines;
134 };
135
136 return Whitespace;
137})();
138
139exports["default"] = Whitespace;
140module.exports = exports["default"];
\No newline at end of file