@tslite/parser 1.10.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +55 -0
- package/NOTICE +14 -0
- package/dist/_namespaces/ts.d.ts +18 -0
- package/dist/_namespaces/ts.js +21 -0
- package/dist/_namespaces/ts.performance.d.ts +1 -0
- package/dist/_namespaces/ts.performance.js +2 -0
- package/dist/core.d.ts +450 -0
- package/dist/core.js +1394 -0
- package/dist/corePublic.d.ts +62 -0
- package/dist/corePublic.js +31 -0
- package/dist/debug.d.ts +74 -0
- package/dist/debug.js +326 -0
- package/dist/diagnosticInformationMap.generated.d.ts +1435 -0
- package/dist/diagnosticInformationMap.generated.js +1441 -0
- package/dist/factory.d.ts +78 -0
- package/dist/factory.js +622 -0
- package/dist/factoryPublic.d.ts +314 -0
- package/dist/factoryPublic.js +1796 -0
- package/dist/index.d.ts +1 -249
- package/dist/index.js +4 -6
- package/dist/parser.d.ts +59 -0
- package/dist/parser.js +5075 -0
- package/dist/path.d.ts +312 -0
- package/dist/path.js +475 -0
- package/dist/perfLogger.d.ts +4 -0
- package/dist/perfLogger.js +38 -0
- package/dist/performance.d.ts +20 -0
- package/dist/performance.js +49 -0
- package/dist/performanceTimestamp.d.ts +2 -0
- package/dist/performanceTimestamp.js +2 -0
- package/dist/scanner.d.ts +80 -0
- package/dist/scanner.js +1984 -0
- package/dist/shims/mapShim.d.ts +23 -0
- package/dist/shims/mapShim.js +156 -0
- package/dist/types.d.ts +2626 -0
- package/dist/types.js +1074 -0
- package/dist/utilities.d.ts +473 -0
- package/dist/utilities.js +2632 -0
- package/dist/utilitiesPublic.d.ts +274 -0
- package/dist/utilitiesPublic.js +1049 -0
- package/dist/visitor.d.ts +15 -0
- package/dist/visitor.js +64 -0
- package/dist/visitorPublic.d.ts +82 -0
- package/dist/visitorPublic.js +352 -0
- package/package.json +14 -42
- package/dist/index.cjs +0 -6
- package/dist/index.d.cts +0 -249
package/dist/core.js
ADDED
|
@@ -0,0 +1,1394 @@
|
|
|
1
|
+
// Modificado de microsoft/TypeScript v3.9.10, src/compiler/core.ts: o namespace virou módulo ES, com os imports explícitos.
|
|
2
|
+
import { Debug, Map, } from "./_namespaces/ts.js";
|
|
3
|
+
export const emptyArray = [];
|
|
4
|
+
/** Create a new map. */
|
|
5
|
+
export function createMap() {
|
|
6
|
+
return new Map();
|
|
7
|
+
}
|
|
8
|
+
/** Create a new map from an array of entries. */
|
|
9
|
+
export function createMapFromEntries(entries) {
|
|
10
|
+
const map = createMap();
|
|
11
|
+
for (const [key, value] of entries) {
|
|
12
|
+
map.set(key, value);
|
|
13
|
+
}
|
|
14
|
+
return map;
|
|
15
|
+
}
|
|
16
|
+
/** Create a new map from a template object is provided, the map will copy entries from it. */
|
|
17
|
+
export function createMapFromTemplate(template) {
|
|
18
|
+
const map = new Map();
|
|
19
|
+
// Copies keys/values from template. Note that for..in will not throw if
|
|
20
|
+
// template is undefined, and instead will just exit the loop.
|
|
21
|
+
for (const key in template) {
|
|
22
|
+
if (hasOwnProperty.call(template, key)) {
|
|
23
|
+
map.set(key, template[key]);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return map;
|
|
27
|
+
}
|
|
28
|
+
export function length(array) {
|
|
29
|
+
return array ? array.length : 0;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Iterates through 'array' by index and performs the callback on each element of array until the callback
|
|
33
|
+
* returns a truthy value, then returns that value.
|
|
34
|
+
* If no such value is found, the callback is applied to each element of array and undefined is returned.
|
|
35
|
+
*/
|
|
36
|
+
export function forEach(array, callback) {
|
|
37
|
+
if (array) {
|
|
38
|
+
for (let i = 0; i < array.length; i++) {
|
|
39
|
+
const result = callback(array[i], i);
|
|
40
|
+
if (result) {
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Like `forEach`, but iterates in reverse order.
|
|
49
|
+
*/
|
|
50
|
+
export function forEachRight(array, callback) {
|
|
51
|
+
if (array) {
|
|
52
|
+
for (let i = array.length - 1; i >= 0; i--) {
|
|
53
|
+
const result = callback(array[i], i);
|
|
54
|
+
if (result) {
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
/** Like `forEach`, but suitable for use with numbers and strings (which may be falsy). */
|
|
62
|
+
export function firstDefined(array, callback) {
|
|
63
|
+
if (array === undefined) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
for (let i = 0; i < array.length; i++) {
|
|
67
|
+
const result = callback(array[i], i);
|
|
68
|
+
if (result !== undefined) {
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Iterates through `array` by index and performs the callback on each element of array until the callback
|
|
76
|
+
* returns a falsey value, then returns false.
|
|
77
|
+
* If no such value is found, the callback is applied to each element of array and `true` is returned.
|
|
78
|
+
*/
|
|
79
|
+
export function every(array, callback) {
|
|
80
|
+
if (array) {
|
|
81
|
+
for (let i = 0; i < array.length; i++) {
|
|
82
|
+
if (!callback(array[i], i)) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
export function find(array, predicate) {
|
|
90
|
+
for (let i = 0; i < array.length; i++) {
|
|
91
|
+
const value = array[i];
|
|
92
|
+
if (predicate(value, i)) {
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
export function findLast(array, predicate) {
|
|
99
|
+
for (let i = array.length - 1; i >= 0; i--) {
|
|
100
|
+
const value = array[i];
|
|
101
|
+
if (predicate(value, i)) {
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
/** Works like Array.prototype.findIndex, returning `-1` if no element satisfying the predicate is found. */
|
|
108
|
+
export function findIndex(array, predicate, startIndex) {
|
|
109
|
+
for (let i = startIndex || 0; i < array.length; i++) {
|
|
110
|
+
if (predicate(array[i], i)) {
|
|
111
|
+
return i;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return -1;
|
|
115
|
+
}
|
|
116
|
+
export function findLastIndex(array, predicate, startIndex) {
|
|
117
|
+
for (let i = startIndex === undefined ? array.length - 1 : startIndex; i >= 0; i--) {
|
|
118
|
+
if (predicate(array[i], i)) {
|
|
119
|
+
return i;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return -1;
|
|
123
|
+
}
|
|
124
|
+
export function contains(array, value, equalityComparer = equateValues) {
|
|
125
|
+
if (array) {
|
|
126
|
+
for (const v of array) {
|
|
127
|
+
if (equalityComparer(v, value)) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
export function arraysEqual(a, b, equalityComparer = equateValues) {
|
|
135
|
+
return a.length === b.length && a.every((x, i) => equalityComparer(x, b[i]));
|
|
136
|
+
}
|
|
137
|
+
export function countWhere(array, predicate) {
|
|
138
|
+
let count = 0;
|
|
139
|
+
if (array) {
|
|
140
|
+
for (let i = 0; i < array.length; i++) {
|
|
141
|
+
const v = array[i];
|
|
142
|
+
if (predicate(v, i)) {
|
|
143
|
+
count++;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return count;
|
|
148
|
+
}
|
|
149
|
+
export function filter(array, f) {
|
|
150
|
+
if (array) {
|
|
151
|
+
const len = array.length;
|
|
152
|
+
let i = 0;
|
|
153
|
+
while (i < len && f(array[i]))
|
|
154
|
+
i++;
|
|
155
|
+
if (i < len) {
|
|
156
|
+
const result = array.slice(0, i);
|
|
157
|
+
i++;
|
|
158
|
+
while (i < len) {
|
|
159
|
+
const item = array[i];
|
|
160
|
+
if (f(item)) {
|
|
161
|
+
result.push(item);
|
|
162
|
+
}
|
|
163
|
+
i++;
|
|
164
|
+
}
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return array;
|
|
169
|
+
}
|
|
170
|
+
export function filterMutate(array, f) {
|
|
171
|
+
let outIndex = 0;
|
|
172
|
+
for (let i = 0; i < array.length; i++) {
|
|
173
|
+
if (f(array[i], i, array)) {
|
|
174
|
+
array[outIndex] = array[i];
|
|
175
|
+
outIndex++;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
array.length = outIndex;
|
|
179
|
+
}
|
|
180
|
+
export function clear(array) {
|
|
181
|
+
array.length = 0;
|
|
182
|
+
}
|
|
183
|
+
export function map(array, f) {
|
|
184
|
+
let result;
|
|
185
|
+
if (array) {
|
|
186
|
+
result = [];
|
|
187
|
+
for (let i = 0; i < array.length; i++) {
|
|
188
|
+
result.push(f(array[i], i));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return result;
|
|
192
|
+
}
|
|
193
|
+
export function sameMap(array, f) {
|
|
194
|
+
if (array) {
|
|
195
|
+
for (let i = 0; i < array.length; i++) {
|
|
196
|
+
const item = array[i];
|
|
197
|
+
const mapped = f(item, i);
|
|
198
|
+
if (item !== mapped) {
|
|
199
|
+
const result = array.slice(0, i);
|
|
200
|
+
result.push(mapped);
|
|
201
|
+
for (i++; i < array.length; i++) {
|
|
202
|
+
result.push(f(array[i], i));
|
|
203
|
+
}
|
|
204
|
+
return result;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return array;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Flattens an array containing a mix of array or non-array elements.
|
|
212
|
+
*
|
|
213
|
+
* @param array The array to flatten.
|
|
214
|
+
*/
|
|
215
|
+
export function flatten(array) {
|
|
216
|
+
const result = [];
|
|
217
|
+
for (const v of array) {
|
|
218
|
+
if (v) {
|
|
219
|
+
if (isArray(v)) {
|
|
220
|
+
addRange(result, v);
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
result.push(v);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return result;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Maps an array. If the mapped value is an array, it is spread into the result.
|
|
231
|
+
*
|
|
232
|
+
* @param array The array to map.
|
|
233
|
+
* @param mapfn The callback used to map the result into one or more values.
|
|
234
|
+
*/
|
|
235
|
+
export function flatMap(array, mapfn) {
|
|
236
|
+
let result;
|
|
237
|
+
if (array) {
|
|
238
|
+
for (let i = 0; i < array.length; i++) {
|
|
239
|
+
const v = mapfn(array[i], i);
|
|
240
|
+
if (v) {
|
|
241
|
+
if (isArray(v)) {
|
|
242
|
+
result = addRange(result, v);
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
result = append(result, v);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return result || emptyArray;
|
|
251
|
+
}
|
|
252
|
+
export function flatMapToMutable(array, mapfn) {
|
|
253
|
+
const result = [];
|
|
254
|
+
if (array) {
|
|
255
|
+
for (let i = 0; i < array.length; i++) {
|
|
256
|
+
const v = mapfn(array[i], i);
|
|
257
|
+
if (v) {
|
|
258
|
+
if (isArray(v)) {
|
|
259
|
+
addRange(result, v);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
result.push(v);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
export function flatMapIterator(iter, mapfn) {
|
|
270
|
+
const first = iter.next();
|
|
271
|
+
if (first.done) {
|
|
272
|
+
return emptyIterator;
|
|
273
|
+
}
|
|
274
|
+
let currentIter = getIterator(first.value);
|
|
275
|
+
return {
|
|
276
|
+
next() {
|
|
277
|
+
while (true) {
|
|
278
|
+
const currentRes = currentIter.next();
|
|
279
|
+
if (!currentRes.done) {
|
|
280
|
+
return currentRes;
|
|
281
|
+
}
|
|
282
|
+
const iterRes = iter.next();
|
|
283
|
+
if (iterRes.done) {
|
|
284
|
+
return iterRes;
|
|
285
|
+
}
|
|
286
|
+
currentIter = getIterator(iterRes.value);
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
function getIterator(x) {
|
|
291
|
+
const res = mapfn(x);
|
|
292
|
+
return res === undefined ? emptyIterator : isArray(res) ? arrayIterator(res) : res;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
export function sameFlatMap(array, mapfn) {
|
|
296
|
+
let result;
|
|
297
|
+
if (array) {
|
|
298
|
+
for (let i = 0; i < array.length; i++) {
|
|
299
|
+
const item = array[i];
|
|
300
|
+
const mapped = mapfn(item, i);
|
|
301
|
+
if (result || item !== mapped || isArray(mapped)) {
|
|
302
|
+
if (!result) {
|
|
303
|
+
result = array.slice(0, i);
|
|
304
|
+
}
|
|
305
|
+
if (isArray(mapped)) {
|
|
306
|
+
addRange(result, mapped);
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
result.push(mapped);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return result || array;
|
|
315
|
+
}
|
|
316
|
+
export function mapDefined(array, mapFn) {
|
|
317
|
+
const result = [];
|
|
318
|
+
if (array) {
|
|
319
|
+
for (let i = 0; i < array.length; i++) {
|
|
320
|
+
const mapped = mapFn(array[i], i);
|
|
321
|
+
if (mapped !== undefined) {
|
|
322
|
+
result.push(mapped);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return result;
|
|
327
|
+
}
|
|
328
|
+
export const emptyIterator = { next: () => ({ value: undefined, done: true }) };
|
|
329
|
+
export function mapEntries(map, f) {
|
|
330
|
+
if (!map) {
|
|
331
|
+
return undefined;
|
|
332
|
+
}
|
|
333
|
+
const result = createMap();
|
|
334
|
+
map.forEach((value, key) => {
|
|
335
|
+
const [newKey, newValue] = f(key, value);
|
|
336
|
+
result.set(newKey, newValue);
|
|
337
|
+
});
|
|
338
|
+
return result;
|
|
339
|
+
}
|
|
340
|
+
export function some(array, predicate) {
|
|
341
|
+
if (array) {
|
|
342
|
+
if (predicate) {
|
|
343
|
+
for (const v of array) {
|
|
344
|
+
if (predicate(v)) {
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
return array.length > 0;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
/** Calls the callback with (start, afterEnd) index pairs for each range where 'pred' is true. */
|
|
356
|
+
export function getRangesWhere(arr, pred, cb) {
|
|
357
|
+
let start;
|
|
358
|
+
for (let i = 0; i < arr.length; i++) {
|
|
359
|
+
if (pred(arr[i])) {
|
|
360
|
+
start = start === undefined ? i : start;
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
if (start !== undefined) {
|
|
364
|
+
cb(start, i);
|
|
365
|
+
start = undefined;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
if (start !== undefined)
|
|
370
|
+
cb(start, arr.length);
|
|
371
|
+
}
|
|
372
|
+
export function concatenate(array1, array2) {
|
|
373
|
+
if (!some(array2))
|
|
374
|
+
return array1;
|
|
375
|
+
if (!some(array1))
|
|
376
|
+
return array2;
|
|
377
|
+
return [...array1, ...array2];
|
|
378
|
+
}
|
|
379
|
+
function selectIndex(_, i) {
|
|
380
|
+
return i;
|
|
381
|
+
}
|
|
382
|
+
export function indicesOf(array) {
|
|
383
|
+
return array.map(selectIndex);
|
|
384
|
+
}
|
|
385
|
+
function deduplicateRelational(array, equalityComparer, comparer) {
|
|
386
|
+
// Perform a stable sort of the array. This ensures the first entry in a list of
|
|
387
|
+
// duplicates remains the first entry in the result.
|
|
388
|
+
const indices = indicesOf(array);
|
|
389
|
+
stableSortIndices(array, indices, comparer);
|
|
390
|
+
let last = array[indices[0]];
|
|
391
|
+
const deduplicated = [indices[0]];
|
|
392
|
+
for (let i = 1; i < indices.length; i++) {
|
|
393
|
+
const index = indices[i];
|
|
394
|
+
const item = array[index];
|
|
395
|
+
if (!equalityComparer(last, item)) {
|
|
396
|
+
deduplicated.push(index);
|
|
397
|
+
last = item;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
// restore original order
|
|
401
|
+
deduplicated.sort();
|
|
402
|
+
return deduplicated.map(i => array[i]);
|
|
403
|
+
}
|
|
404
|
+
function deduplicateEquality(array, equalityComparer) {
|
|
405
|
+
const result = [];
|
|
406
|
+
for (const item of array) {
|
|
407
|
+
pushIfUnique(result, item, equalityComparer);
|
|
408
|
+
}
|
|
409
|
+
return result;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Deduplicates an unsorted array.
|
|
413
|
+
* @param equalityComparer An `EqualityComparer` used to determine if two values are duplicates.
|
|
414
|
+
* @param comparer An optional `Comparer` used to sort entries before comparison, though the
|
|
415
|
+
* result will remain in the original order in `array`.
|
|
416
|
+
*/
|
|
417
|
+
export function deduplicate(array, equalityComparer, comparer) {
|
|
418
|
+
return array.length === 0 ? [] :
|
|
419
|
+
array.length === 1 ? array.slice() :
|
|
420
|
+
comparer ? deduplicateRelational(array, equalityComparer, comparer) :
|
|
421
|
+
deduplicateEquality(array, equalityComparer);
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Deduplicates an array that has already been sorted.
|
|
425
|
+
*/
|
|
426
|
+
function deduplicateSorted(array, comparer) {
|
|
427
|
+
if (array.length === 0)
|
|
428
|
+
return emptyArray;
|
|
429
|
+
let last = array[0];
|
|
430
|
+
const deduplicated = [last];
|
|
431
|
+
for (let i = 1; i < array.length; i++) {
|
|
432
|
+
const next = array[i];
|
|
433
|
+
switch (comparer(next, last)) {
|
|
434
|
+
// equality comparison
|
|
435
|
+
case true:
|
|
436
|
+
// relational comparison
|
|
437
|
+
// falls through
|
|
438
|
+
case 0 /* Comparison.EqualTo */:
|
|
439
|
+
continue;
|
|
440
|
+
case -1 /* Comparison.LessThan */:
|
|
441
|
+
// If `array` is sorted, `next` should **never** be less than `last`.
|
|
442
|
+
return Debug.fail("Array is unsorted.");
|
|
443
|
+
}
|
|
444
|
+
deduplicated.push(last = next);
|
|
445
|
+
}
|
|
446
|
+
return deduplicated;
|
|
447
|
+
}
|
|
448
|
+
export function insertSorted(array, insert, compare) {
|
|
449
|
+
if (array.length === 0) {
|
|
450
|
+
array.push(insert);
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
const insertIndex = binarySearch(array, insert, identity, compare);
|
|
454
|
+
if (insertIndex < 0) {
|
|
455
|
+
array.splice(~insertIndex, 0, insert);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
export function sortAndDeduplicate(array, comparer, equalityComparer) {
|
|
459
|
+
return deduplicateSorted(sort(array, comparer), equalityComparer || comparer || compareStringsCaseSensitive);
|
|
460
|
+
}
|
|
461
|
+
export function arrayIsEqualTo(array1, array2, equalityComparer = equateValues) {
|
|
462
|
+
if (!array1 || !array2) {
|
|
463
|
+
return array1 === array2;
|
|
464
|
+
}
|
|
465
|
+
if (array1.length !== array2.length) {
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
for (let i = 0; i < array1.length; i++) {
|
|
469
|
+
if (!equalityComparer(array1[i], array2[i], i)) {
|
|
470
|
+
return false;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return true;
|
|
474
|
+
}
|
|
475
|
+
export function compact(array) {
|
|
476
|
+
let result;
|
|
477
|
+
if (array) {
|
|
478
|
+
for (let i = 0; i < array.length; i++) {
|
|
479
|
+
const v = array[i];
|
|
480
|
+
if (result || !v) {
|
|
481
|
+
if (!result) {
|
|
482
|
+
result = array.slice(0, i);
|
|
483
|
+
}
|
|
484
|
+
if (v) {
|
|
485
|
+
result.push(v);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
return result || array;
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Gets the relative complement of `arrayA` with respect to `arrayB`, returning the elements that
|
|
494
|
+
* are not present in `arrayA` but are present in `arrayB`. Assumes both arrays are sorted
|
|
495
|
+
* based on the provided comparer.
|
|
496
|
+
*/
|
|
497
|
+
export function relativeComplement(arrayA, arrayB, comparer) {
|
|
498
|
+
if (!arrayB || !arrayA || arrayB.length === 0 || arrayA.length === 0)
|
|
499
|
+
return arrayB;
|
|
500
|
+
const result = [];
|
|
501
|
+
loopB: for (let offsetA = 0, offsetB = 0; offsetB < arrayB.length; offsetB++) {
|
|
502
|
+
if (offsetB > 0) {
|
|
503
|
+
// Ensure `arrayB` is properly sorted.
|
|
504
|
+
Debug.assertGreaterThanOrEqual(comparer(arrayB[offsetB], arrayB[offsetB - 1]), 0 /* Comparison.EqualTo */);
|
|
505
|
+
}
|
|
506
|
+
loopA: for (const startA = offsetA; offsetA < arrayA.length; offsetA++) {
|
|
507
|
+
if (offsetA > startA) {
|
|
508
|
+
// Ensure `arrayA` is properly sorted. We only need to perform this check if
|
|
509
|
+
// `offsetA` has changed since we entered the loop.
|
|
510
|
+
Debug.assertGreaterThanOrEqual(comparer(arrayA[offsetA], arrayA[offsetA - 1]), 0 /* Comparison.EqualTo */);
|
|
511
|
+
}
|
|
512
|
+
switch (comparer(arrayB[offsetB], arrayA[offsetA])) {
|
|
513
|
+
case -1 /* Comparison.LessThan */:
|
|
514
|
+
// If B is less than A, B does not exist in arrayA. Add B to the result and
|
|
515
|
+
// move to the next element in arrayB without changing the current position
|
|
516
|
+
// in arrayA.
|
|
517
|
+
result.push(arrayB[offsetB]);
|
|
518
|
+
continue loopB;
|
|
519
|
+
case 0 /* Comparison.EqualTo */:
|
|
520
|
+
// If B is equal to A, B exists in arrayA. Move to the next element in
|
|
521
|
+
// arrayB without adding B to the result or changing the current position
|
|
522
|
+
// in arrayA.
|
|
523
|
+
continue loopB;
|
|
524
|
+
case 1 /* Comparison.GreaterThan */:
|
|
525
|
+
// If B is greater than A, we need to keep looking for B in arrayA. Move to
|
|
526
|
+
// the next element in arrayA and recheck.
|
|
527
|
+
continue loopA;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
return result;
|
|
532
|
+
}
|
|
533
|
+
export function append(to, value) {
|
|
534
|
+
// Com um `Push` (a sobrecarga que devolve `void`), quem chama ignora o retorno.
|
|
535
|
+
if (value === undefined)
|
|
536
|
+
return to;
|
|
537
|
+
if (to === undefined)
|
|
538
|
+
return [value];
|
|
539
|
+
to.push(value);
|
|
540
|
+
return to;
|
|
541
|
+
}
|
|
542
|
+
export function combine(xs, ys) {
|
|
543
|
+
if (xs === undefined)
|
|
544
|
+
return ys;
|
|
545
|
+
if (ys === undefined)
|
|
546
|
+
return xs;
|
|
547
|
+
if (isArray(xs))
|
|
548
|
+
return isArray(ys) ? concatenate(xs, ys) : append(xs, ys);
|
|
549
|
+
if (isArray(ys))
|
|
550
|
+
return append(ys, xs);
|
|
551
|
+
return [xs, ys];
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Gets the actual offset into an array for a relative offset. Negative offsets indicate a
|
|
555
|
+
* position offset from the end of the array.
|
|
556
|
+
*/
|
|
557
|
+
function toOffset(array, offset) {
|
|
558
|
+
return offset < 0 ? array.length + offset : offset;
|
|
559
|
+
}
|
|
560
|
+
export function addRange(to, from, start, end) {
|
|
561
|
+
if (from === undefined || from.length === 0)
|
|
562
|
+
return to;
|
|
563
|
+
if (to === undefined)
|
|
564
|
+
return from.slice(start, end);
|
|
565
|
+
start = start === undefined ? 0 : toOffset(from, start);
|
|
566
|
+
end = end === undefined ? from.length : toOffset(from, end);
|
|
567
|
+
for (let i = start; i < end && i < from.length; i++) {
|
|
568
|
+
if (from[i] !== undefined) {
|
|
569
|
+
to.push(from[i]);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return to;
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* @return Whether the value was added.
|
|
576
|
+
*/
|
|
577
|
+
export function pushIfUnique(array, toAdd, equalityComparer) {
|
|
578
|
+
if (contains(array, toAdd, equalityComparer)) {
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
else {
|
|
582
|
+
array.push(toAdd);
|
|
583
|
+
return true;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Unlike `pushIfUnique`, this can take `undefined` as an input, and returns a new array.
|
|
588
|
+
*/
|
|
589
|
+
export function appendIfUnique(array, toAdd, equalityComparer) {
|
|
590
|
+
if (array) {
|
|
591
|
+
pushIfUnique(array, toAdd, equalityComparer);
|
|
592
|
+
return array;
|
|
593
|
+
}
|
|
594
|
+
else {
|
|
595
|
+
return [toAdd];
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
function stableSortIndices(array, indices, comparer) {
|
|
599
|
+
// sort indices by value then position
|
|
600
|
+
indices.sort((x, y) => comparer(array[x], array[y]) || compareValues(x, y));
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Returns a new sorted array.
|
|
604
|
+
*/
|
|
605
|
+
export function sort(array, comparer) {
|
|
606
|
+
return (array.length === 0 ? array : array.slice().sort(comparer));
|
|
607
|
+
}
|
|
608
|
+
export function arrayIterator(array) {
|
|
609
|
+
let i = 0;
|
|
610
|
+
return { next: () => {
|
|
611
|
+
if (i === array.length) {
|
|
612
|
+
return { value: undefined, done: true };
|
|
613
|
+
}
|
|
614
|
+
else {
|
|
615
|
+
i++;
|
|
616
|
+
return { value: array[i - 1], done: false };
|
|
617
|
+
}
|
|
618
|
+
} };
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Stable sort of an array. Elements equal to each other maintain their relative position in the array.
|
|
622
|
+
*/
|
|
623
|
+
export function stableSort(array, comparer) {
|
|
624
|
+
const indices = indicesOf(array);
|
|
625
|
+
stableSortIndices(array, indices, comparer);
|
|
626
|
+
return indices.map(i => array[i]);
|
|
627
|
+
}
|
|
628
|
+
export function rangeEquals(array1, array2, pos, end) {
|
|
629
|
+
while (pos < end) {
|
|
630
|
+
if (array1[pos] !== array2[pos]) {
|
|
631
|
+
return false;
|
|
632
|
+
}
|
|
633
|
+
pos++;
|
|
634
|
+
}
|
|
635
|
+
return true;
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Returns the element at a specific offset in an array if non-empty, `undefined` otherwise.
|
|
639
|
+
* A negative offset indicates the element should be retrieved from the end of the array.
|
|
640
|
+
*/
|
|
641
|
+
export function elementAt(array, offset) {
|
|
642
|
+
if (array) {
|
|
643
|
+
offset = toOffset(array, offset);
|
|
644
|
+
if (offset < array.length) {
|
|
645
|
+
return array[offset];
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
return undefined;
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Returns the first element of an array if non-empty, `undefined` otherwise.
|
|
652
|
+
*/
|
|
653
|
+
export function firstOrUndefined(array) {
|
|
654
|
+
return array.length === 0 ? undefined : array[0];
|
|
655
|
+
}
|
|
656
|
+
export function first(array) {
|
|
657
|
+
Debug.assert(array.length !== 0);
|
|
658
|
+
return array[0];
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Returns the last element of an array if non-empty, `undefined` otherwise.
|
|
662
|
+
*/
|
|
663
|
+
export function lastOrUndefined(array) {
|
|
664
|
+
return array.length === 0 ? undefined : array[array.length - 1];
|
|
665
|
+
}
|
|
666
|
+
export function last(array) {
|
|
667
|
+
Debug.assert(array.length !== 0);
|
|
668
|
+
return array[array.length - 1];
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Returns the only element of an array if it contains only one element, `undefined` otherwise.
|
|
672
|
+
*/
|
|
673
|
+
export function singleOrUndefined(array) {
|
|
674
|
+
return array && array.length === 1
|
|
675
|
+
? array[0]
|
|
676
|
+
: undefined;
|
|
677
|
+
}
|
|
678
|
+
export function replaceElement(array, index, value) {
|
|
679
|
+
const result = array.slice(0);
|
|
680
|
+
result[index] = value;
|
|
681
|
+
return result;
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Performs a binary search, finding the index at which `value` occurs in `array`.
|
|
685
|
+
* If no such index is found, returns the 2's-complement of first index at which
|
|
686
|
+
* `array[index]` exceeds `value`.
|
|
687
|
+
* @param array A sorted array whose first element must be no larger than number
|
|
688
|
+
* @param value The value to be searched for in the array.
|
|
689
|
+
* @param keySelector A callback used to select the search key from `value` and each element of
|
|
690
|
+
* `array`.
|
|
691
|
+
* @param keyComparer A callback used to compare two keys in a sorted array.
|
|
692
|
+
* @param offset An offset into `array` at which to start the search.
|
|
693
|
+
*/
|
|
694
|
+
export function binarySearch(array, value, keySelector, keyComparer, offset) {
|
|
695
|
+
return binarySearchKey(array, keySelector(value), keySelector, keyComparer, offset);
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Performs a binary search, finding the index at which an object with `key` occurs in `array`.
|
|
699
|
+
* If no such index is found, returns the 2's-complement of first index at which
|
|
700
|
+
* `array[index]` exceeds `key`.
|
|
701
|
+
* @param array A sorted array whose first element must be no larger than number
|
|
702
|
+
* @param key The key to be searched for in the array.
|
|
703
|
+
* @param keySelector A callback used to select the search key from each element of `array`.
|
|
704
|
+
* @param keyComparer A callback used to compare two keys in a sorted array.
|
|
705
|
+
* @param offset An offset into `array` at which to start the search.
|
|
706
|
+
*/
|
|
707
|
+
export function binarySearchKey(array, key, keySelector, keyComparer, offset) {
|
|
708
|
+
if (!some(array)) {
|
|
709
|
+
return -1;
|
|
710
|
+
}
|
|
711
|
+
let low = offset || 0;
|
|
712
|
+
let high = array.length - 1;
|
|
713
|
+
while (low <= high) {
|
|
714
|
+
const middle = low + ((high - low) >> 1);
|
|
715
|
+
const midKey = keySelector(array[middle]);
|
|
716
|
+
switch (keyComparer(midKey, key)) {
|
|
717
|
+
case -1 /* Comparison.LessThan */:
|
|
718
|
+
low = middle + 1;
|
|
719
|
+
break;
|
|
720
|
+
case 0 /* Comparison.EqualTo */:
|
|
721
|
+
return middle;
|
|
722
|
+
case 1 /* Comparison.GreaterThan */:
|
|
723
|
+
high = middle - 1;
|
|
724
|
+
break;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
return ~low;
|
|
728
|
+
}
|
|
729
|
+
export function reduceLeft(array, f, initial, start, count) {
|
|
730
|
+
if (array && array.length > 0) {
|
|
731
|
+
const size = array.length;
|
|
732
|
+
if (size > 0) {
|
|
733
|
+
let pos = start === undefined || start < 0 ? 0 : start;
|
|
734
|
+
const end = count === undefined || pos + count > size - 1 ? size - 1 : pos + count;
|
|
735
|
+
let result;
|
|
736
|
+
if (arguments.length <= 2) {
|
|
737
|
+
result = array[pos];
|
|
738
|
+
pos++;
|
|
739
|
+
}
|
|
740
|
+
else {
|
|
741
|
+
result = initial;
|
|
742
|
+
}
|
|
743
|
+
while (pos <= end) {
|
|
744
|
+
result = f(result, array[pos], pos);
|
|
745
|
+
pos++;
|
|
746
|
+
}
|
|
747
|
+
return result;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
return initial;
|
|
751
|
+
}
|
|
752
|
+
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
753
|
+
/**
|
|
754
|
+
* Indicates whether a map-like contains an own property with the specified key.
|
|
755
|
+
*
|
|
756
|
+
* @param map A map-like.
|
|
757
|
+
* @param key A property key.
|
|
758
|
+
*/
|
|
759
|
+
export function hasProperty(map, key) {
|
|
760
|
+
return hasOwnProperty.call(map, key);
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Gets the value of an owned property in a map-like.
|
|
764
|
+
*
|
|
765
|
+
* @param map A map-like.
|
|
766
|
+
* @param key A property key.
|
|
767
|
+
*/
|
|
768
|
+
export function getProperty(map, key) {
|
|
769
|
+
return hasOwnProperty.call(map, key) ? map[key] : undefined;
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Gets the owned, enumerable property keys of a map-like.
|
|
773
|
+
*/
|
|
774
|
+
export function getOwnKeys(map) {
|
|
775
|
+
const keys = [];
|
|
776
|
+
for (const key in map) {
|
|
777
|
+
if (hasOwnProperty.call(map, key)) {
|
|
778
|
+
keys.push(key);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
return keys;
|
|
782
|
+
}
|
|
783
|
+
export function getOwnValues(sparseArray) {
|
|
784
|
+
const values = [];
|
|
785
|
+
for (const key in sparseArray) {
|
|
786
|
+
if (hasOwnProperty.call(sparseArray, key)) {
|
|
787
|
+
values.push(sparseArray[key]);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
return values;
|
|
791
|
+
}
|
|
792
|
+
export function arrayFrom(iterator, map) {
|
|
793
|
+
const result = [];
|
|
794
|
+
for (let iterResult = iterator.next(); !iterResult.done; iterResult = iterator.next()) {
|
|
795
|
+
result.push(map ? map(iterResult.value) : iterResult.value);
|
|
796
|
+
}
|
|
797
|
+
return result;
|
|
798
|
+
}
|
|
799
|
+
export function assign(t, ...args) {
|
|
800
|
+
for (const arg of args) {
|
|
801
|
+
if (arg === undefined)
|
|
802
|
+
continue;
|
|
803
|
+
for (const p in arg) {
|
|
804
|
+
if (hasProperty(arg, p)) {
|
|
805
|
+
t[p] = arg[p];
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
return t;
|
|
810
|
+
}
|
|
811
|
+
export function arrayToMap(array, makeKey, makeValue = identity) {
|
|
812
|
+
const result = createMap();
|
|
813
|
+
for (const value of array) {
|
|
814
|
+
const key = makeKey(value);
|
|
815
|
+
if (key !== undefined)
|
|
816
|
+
result.set(key, makeValue(value));
|
|
817
|
+
}
|
|
818
|
+
return result;
|
|
819
|
+
}
|
|
820
|
+
export function arrayToMultiMap(values, makeKey, makeValue = identity) {
|
|
821
|
+
const result = createMultiMap();
|
|
822
|
+
for (const value of values) {
|
|
823
|
+
result.add(makeKey(value), makeValue(value));
|
|
824
|
+
}
|
|
825
|
+
return result;
|
|
826
|
+
}
|
|
827
|
+
export function group(values, getGroupId, resultSelector = identity) {
|
|
828
|
+
return arrayFrom(arrayToMultiMap(values, getGroupId).values(), resultSelector);
|
|
829
|
+
}
|
|
830
|
+
export function clone(object) {
|
|
831
|
+
const result = {};
|
|
832
|
+
for (const id in object) {
|
|
833
|
+
if (hasOwnProperty.call(object, id)) {
|
|
834
|
+
result[id] = object[id];
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
return result;
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* Creates a new object by adding the own properties of `second`, then the own properties of `first`.
|
|
841
|
+
*
|
|
842
|
+
* NOTE: This means that if a property exists in both `first` and `second`, the property in `first` will be chosen.
|
|
843
|
+
*/
|
|
844
|
+
export function extend(first, second) {
|
|
845
|
+
const result = {};
|
|
846
|
+
for (const id in second) {
|
|
847
|
+
if (hasOwnProperty.call(second, id)) {
|
|
848
|
+
result[id] = second[id];
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
for (const id in first) {
|
|
852
|
+
if (hasOwnProperty.call(first, id)) {
|
|
853
|
+
result[id] = first[id];
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
return result;
|
|
857
|
+
}
|
|
858
|
+
export function maybeBind(obj, fn) {
|
|
859
|
+
return fn ? fn.bind(obj) : undefined;
|
|
860
|
+
}
|
|
861
|
+
export function createMultiMap() {
|
|
862
|
+
const map = createMap();
|
|
863
|
+
map.add = multiMapAdd;
|
|
864
|
+
map.remove = multiMapRemove;
|
|
865
|
+
return map;
|
|
866
|
+
}
|
|
867
|
+
function multiMapAdd(key, value) {
|
|
868
|
+
let values = this.get(key);
|
|
869
|
+
if (values) {
|
|
870
|
+
values.push(value);
|
|
871
|
+
}
|
|
872
|
+
else {
|
|
873
|
+
this.set(key, values = [value]);
|
|
874
|
+
}
|
|
875
|
+
return values;
|
|
876
|
+
}
|
|
877
|
+
function multiMapRemove(key, value) {
|
|
878
|
+
const values = this.get(key);
|
|
879
|
+
if (values) {
|
|
880
|
+
unorderedRemoveItem(values, value);
|
|
881
|
+
if (!values.length) {
|
|
882
|
+
this.delete(key);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
export function createUnderscoreEscapedMultiMap() {
|
|
887
|
+
return createMultiMap();
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* Tests whether a value is an array.
|
|
891
|
+
*/
|
|
892
|
+
// `unknown`, e não `{}`: no 3.9 o `{}` aceitava `null` e `undefined`, e desde o 4.8 não aceita — um
|
|
893
|
+
// `readonly T[]` de `T` sem restrição deixou de caber em `readonly {}[]`, e o ramo falso não tirava mais
|
|
894
|
+
// o array.
|
|
895
|
+
export function isArray(value) {
|
|
896
|
+
return Array.isArray ? Array.isArray(value) : value instanceof Array;
|
|
897
|
+
}
|
|
898
|
+
export function toArray(value) {
|
|
899
|
+
return isArray(value) ? value : [value];
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Tests whether a value is string
|
|
903
|
+
*/
|
|
904
|
+
export function isString(text) {
|
|
905
|
+
return typeof text === "string";
|
|
906
|
+
}
|
|
907
|
+
export function isNumber(x) {
|
|
908
|
+
return typeof x === "number";
|
|
909
|
+
}
|
|
910
|
+
export function tryCast(value, test) {
|
|
911
|
+
return value !== undefined && test(value) ? value : undefined;
|
|
912
|
+
}
|
|
913
|
+
export function cast(value, test) {
|
|
914
|
+
if (value !== undefined && test(value))
|
|
915
|
+
return value;
|
|
916
|
+
return Debug.fail(`Invalid cast. The supplied value ${value} did not pass the test '${Debug.getFunctionName(test)}'.`);
|
|
917
|
+
}
|
|
918
|
+
/** Does nothing. */
|
|
919
|
+
export function noop(_) { }
|
|
920
|
+
export function returnTrue() { return true; }
|
|
921
|
+
/** Do nothing and return undefined */
|
|
922
|
+
export function returnUndefined() { return undefined; }
|
|
923
|
+
/** Returns its argument. */
|
|
924
|
+
export function identity(x) { return x; }
|
|
925
|
+
/** Returns lower case string */
|
|
926
|
+
export function toLowerCase(x) { return x.toLowerCase(); }
|
|
927
|
+
// We convert the file names to lower case as key for file name on case insensitive file system
|
|
928
|
+
// While doing so we need to handle special characters (eg \u0130) to ensure that we dont convert
|
|
929
|
+
// it to lower case, fileName with its lowercase form can exist along side it.
|
|
930
|
+
// Handle special characters and make those case sensitive instead
|
|
931
|
+
//
|
|
932
|
+
// |-#--|-Unicode--|-Char code-|-Desc-------------------------------------------------------------------|
|
|
933
|
+
// | 1. | i | 105 | Ascii i |
|
|
934
|
+
// | 2. | I | 73 | Ascii I |
|
|
935
|
+
// |-------- Special characters ------------------------------------------------------------------------|
|
|
936
|
+
// | 3. | \u0130 | 304 | Uppper case I with dot above |
|
|
937
|
+
// | 4. | i,\u0307 | 105,775 | i, followed by 775: Lower case of (3rd item) |
|
|
938
|
+
// | 5. | I,\u0307 | 73,775 | I, followed by 775: Upper case of (4th item), lower case is (4th item) |
|
|
939
|
+
// | 6. | \u0131 | 305 | Lower case i without dot, upper case is I (2nd item) |
|
|
940
|
+
// | 7. | \u00DF | 223 | Lower case sharp s |
|
|
941
|
+
//
|
|
942
|
+
// Because item 3 is special where in its lowercase character has its own
|
|
943
|
+
// upper case form we cant convert its case.
|
|
944
|
+
// Rest special characters are either already in lower case format or
|
|
945
|
+
// they have corresponding upper case character so they dont need special handling
|
|
946
|
+
//
|
|
947
|
+
// But to avoid having to do string building for most common cases, also ignore
|
|
948
|
+
// a-z, 0-9, \u0131, \u00DF, \, /, ., : and space
|
|
949
|
+
const fileNameLowerCaseRegExp = /[^\u0130\u0131\u00DFa-z0-9\\/:\-_\. ]+/g;
|
|
950
|
+
/**
|
|
951
|
+
* Case insensitive file systems have descripencies in how they handle some characters (eg. turkish Upper case I with dot on top - \u0130)
|
|
952
|
+
* This function is used in places where we want to make file name as a key on these systems
|
|
953
|
+
* It is possible on mac to be able to refer to file name with I with dot on top as a fileName with its lower case form
|
|
954
|
+
* But on windows we cannot. Windows can have fileName with I with dot on top next to its lower case and they can not each be referred with the lowercase forms
|
|
955
|
+
* Technically we would want this function to be platform sepcific as well but
|
|
956
|
+
* our api has till now only taken caseSensitive as the only input and just for some characters we dont want to update API and ensure all customers use those api
|
|
957
|
+
* We could use upper case and we would still need to deal with the descripencies but
|
|
958
|
+
* we want to continue using lower case since in most cases filenames are lowercasewe and wont need any case changes and avoid having to store another string for the key
|
|
959
|
+
* So for this function purpose, we go ahead and assume character I with dot on top it as case sensitive since its very unlikely to use lower case form of that special character
|
|
960
|
+
*/
|
|
961
|
+
export function toFileNameLowerCase(x) {
|
|
962
|
+
return fileNameLowerCaseRegExp.test(x) ?
|
|
963
|
+
x.replace(fileNameLowerCaseRegExp, toLowerCase) :
|
|
964
|
+
x;
|
|
965
|
+
}
|
|
966
|
+
/** Throws an error because a function is not implemented. */
|
|
967
|
+
export function notImplemented() {
|
|
968
|
+
throw new Error("Not implemented");
|
|
969
|
+
}
|
|
970
|
+
export function memoize(callback) {
|
|
971
|
+
let value;
|
|
972
|
+
return () => {
|
|
973
|
+
if (callback) {
|
|
974
|
+
value = callback();
|
|
975
|
+
callback = undefined;
|
|
976
|
+
}
|
|
977
|
+
return value;
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
export function compose(a, b, c, d, e) {
|
|
981
|
+
if (!!e) {
|
|
982
|
+
const args = [];
|
|
983
|
+
for (let i = 0; i < arguments.length; i++) {
|
|
984
|
+
args[i] = arguments[i];
|
|
985
|
+
}
|
|
986
|
+
return t => reduceLeft(args, (u, f) => f(u), t);
|
|
987
|
+
}
|
|
988
|
+
else if (d) {
|
|
989
|
+
return t => d(c(b(a(t))));
|
|
990
|
+
}
|
|
991
|
+
else if (c) {
|
|
992
|
+
return t => c(b(a(t)));
|
|
993
|
+
}
|
|
994
|
+
else if (b) {
|
|
995
|
+
return t => b(a(t));
|
|
996
|
+
}
|
|
997
|
+
else if (a) {
|
|
998
|
+
return t => a(t);
|
|
999
|
+
}
|
|
1000
|
+
else {
|
|
1001
|
+
return t => t;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
export var AssertionLevel;
|
|
1005
|
+
(function (AssertionLevel) {
|
|
1006
|
+
AssertionLevel[AssertionLevel["None"] = 0] = "None";
|
|
1007
|
+
AssertionLevel[AssertionLevel["Normal"] = 1] = "Normal";
|
|
1008
|
+
AssertionLevel[AssertionLevel["Aggressive"] = 2] = "Aggressive";
|
|
1009
|
+
AssertionLevel[AssertionLevel["VeryAggressive"] = 3] = "VeryAggressive";
|
|
1010
|
+
})(AssertionLevel || (AssertionLevel = {}));
|
|
1011
|
+
export function equateValues(a, b) {
|
|
1012
|
+
return a === b;
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Compare the equality of two strings using a case-sensitive ordinal comparison.
|
|
1016
|
+
*
|
|
1017
|
+
* Case-sensitive comparisons compare both strings one code-point at a time using the integer
|
|
1018
|
+
* value of each code-point after applying `toUpperCase` to each string. We always map both
|
|
1019
|
+
* strings to their upper-case form as some unicode characters do not properly round-trip to
|
|
1020
|
+
* lowercase (such as `ẞ` (German sharp capital s)).
|
|
1021
|
+
*/
|
|
1022
|
+
export function equateStringsCaseInsensitive(a, b) {
|
|
1023
|
+
return a === b
|
|
1024
|
+
|| a !== undefined
|
|
1025
|
+
&& b !== undefined
|
|
1026
|
+
&& a.toUpperCase() === b.toUpperCase();
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Compare the equality of two strings using a case-sensitive ordinal comparison.
|
|
1030
|
+
*
|
|
1031
|
+
* Case-sensitive comparisons compare both strings one code-point at a time using the
|
|
1032
|
+
* integer value of each code-point.
|
|
1033
|
+
*/
|
|
1034
|
+
export function equateStringsCaseSensitive(a, b) {
|
|
1035
|
+
return equateValues(a, b);
|
|
1036
|
+
}
|
|
1037
|
+
function compareComparableValues(a, b) {
|
|
1038
|
+
return a === b ? 0 /* Comparison.EqualTo */ :
|
|
1039
|
+
a === undefined ? -1 /* Comparison.LessThan */ :
|
|
1040
|
+
b === undefined ? 1 /* Comparison.GreaterThan */ :
|
|
1041
|
+
a < b ? -1 /* Comparison.LessThan */ :
|
|
1042
|
+
1 /* Comparison.GreaterThan */;
|
|
1043
|
+
}
|
|
1044
|
+
/**
|
|
1045
|
+
* Compare two numeric values for their order relative to each other.
|
|
1046
|
+
* To compare strings, use any of the `compareStrings` functions.
|
|
1047
|
+
*/
|
|
1048
|
+
export function compareValues(a, b) {
|
|
1049
|
+
return compareComparableValues(a, b);
|
|
1050
|
+
}
|
|
1051
|
+
export function min(a, b, compare) {
|
|
1052
|
+
return compare(a, b) === -1 /* Comparison.LessThan */ ? a : b;
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Compare two strings using a case-insensitive ordinal comparison.
|
|
1056
|
+
*
|
|
1057
|
+
* Ordinal comparisons are based on the difference between the unicode code points of both
|
|
1058
|
+
* strings. Characters with multiple unicode representations are considered unequal. Ordinal
|
|
1059
|
+
* comparisons provide predictable ordering, but place "a" after "B".
|
|
1060
|
+
*
|
|
1061
|
+
* Case-insensitive comparisons compare both strings one code-point at a time using the integer
|
|
1062
|
+
* value of each code-point after applying `toUpperCase` to each string. We always map both
|
|
1063
|
+
* strings to their upper-case form as some unicode characters do not properly round-trip to
|
|
1064
|
+
* lowercase (such as `ẞ` (German sharp capital s)).
|
|
1065
|
+
*/
|
|
1066
|
+
export function compareStringsCaseInsensitive(a, b) {
|
|
1067
|
+
if (a === b)
|
|
1068
|
+
return 0 /* Comparison.EqualTo */;
|
|
1069
|
+
if (a === undefined)
|
|
1070
|
+
return -1 /* Comparison.LessThan */;
|
|
1071
|
+
if (b === undefined)
|
|
1072
|
+
return 1 /* Comparison.GreaterThan */;
|
|
1073
|
+
a = a.toUpperCase();
|
|
1074
|
+
b = b.toUpperCase();
|
|
1075
|
+
return a < b ? -1 /* Comparison.LessThan */ : a > b ? 1 /* Comparison.GreaterThan */ : 0 /* Comparison.EqualTo */;
|
|
1076
|
+
}
|
|
1077
|
+
/**
|
|
1078
|
+
* Compare two strings using a case-sensitive ordinal comparison.
|
|
1079
|
+
*
|
|
1080
|
+
* Ordinal comparisons are based on the difference between the unicode code points of both
|
|
1081
|
+
* strings. Characters with multiple unicode representations are considered unequal. Ordinal
|
|
1082
|
+
* comparisons provide predictable ordering, but place "a" after "B".
|
|
1083
|
+
*
|
|
1084
|
+
* Case-sensitive comparisons compare both strings one code-point at a time using the integer
|
|
1085
|
+
* value of each code-point.
|
|
1086
|
+
*/
|
|
1087
|
+
export function compareStringsCaseSensitive(a, b) {
|
|
1088
|
+
return compareComparableValues(a, b);
|
|
1089
|
+
}
|
|
1090
|
+
export function getStringComparer(ignoreCase) {
|
|
1091
|
+
return ignoreCase ? compareStringsCaseInsensitive : compareStringsCaseSensitive;
|
|
1092
|
+
}
|
|
1093
|
+
/**
|
|
1094
|
+
* Creates a string comparer for use with string collation in the UI.
|
|
1095
|
+
*/
|
|
1096
|
+
const createUIStringComparer = (() => {
|
|
1097
|
+
let defaultComparer;
|
|
1098
|
+
let enUSComparer;
|
|
1099
|
+
const stringComparerFactory = getStringComparerFactory();
|
|
1100
|
+
return createStringComparer;
|
|
1101
|
+
function compareWithCallback(a, b, comparer) {
|
|
1102
|
+
if (a === b)
|
|
1103
|
+
return 0 /* Comparison.EqualTo */;
|
|
1104
|
+
if (a === undefined)
|
|
1105
|
+
return -1 /* Comparison.LessThan */;
|
|
1106
|
+
if (b === undefined)
|
|
1107
|
+
return 1 /* Comparison.GreaterThan */;
|
|
1108
|
+
const value = comparer(a, b);
|
|
1109
|
+
return value < 0 ? -1 /* Comparison.LessThan */ : value > 0 ? 1 /* Comparison.GreaterThan */ : 0 /* Comparison.EqualTo */;
|
|
1110
|
+
}
|
|
1111
|
+
function createIntlCollatorStringComparer(locale) {
|
|
1112
|
+
// Intl.Collator.prototype.compare is bound to the collator. See NOTE in
|
|
1113
|
+
// http://www.ecma-international.org/ecma-402/2.0/#sec-Intl.Collator.prototype.compare
|
|
1114
|
+
const comparer = new Intl.Collator(locale, { usage: "sort", sensitivity: "variant" }).compare;
|
|
1115
|
+
return (a, b) => compareWithCallback(a, b, comparer);
|
|
1116
|
+
}
|
|
1117
|
+
function createLocaleCompareStringComparer(locale) {
|
|
1118
|
+
// if the locale is not the default locale (`undefined`), use the fallback comparer.
|
|
1119
|
+
if (locale !== undefined)
|
|
1120
|
+
return createFallbackStringComparer();
|
|
1121
|
+
return (a, b) => compareWithCallback(a, b, compareStrings);
|
|
1122
|
+
function compareStrings(a, b) {
|
|
1123
|
+
return a.localeCompare(b);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
function createFallbackStringComparer() {
|
|
1127
|
+
// An ordinal comparison puts "A" after "b", but for the UI we want "A" before "b".
|
|
1128
|
+
// We first sort case insensitively. So "Aaa" will come before "baa".
|
|
1129
|
+
// Then we sort case sensitively, so "aaa" will come before "Aaa".
|
|
1130
|
+
//
|
|
1131
|
+
// For case insensitive comparisons we always map both strings to their
|
|
1132
|
+
// upper-case form as some unicode characters do not properly round-trip to
|
|
1133
|
+
// lowercase (such as `ẞ` (German sharp capital s)).
|
|
1134
|
+
return (a, b) => compareWithCallback(a, b, compareDictionaryOrder);
|
|
1135
|
+
function compareDictionaryOrder(a, b) {
|
|
1136
|
+
return compareStrings(a.toUpperCase(), b.toUpperCase()) || compareStrings(a, b);
|
|
1137
|
+
}
|
|
1138
|
+
function compareStrings(a, b) {
|
|
1139
|
+
return a < b ? -1 /* Comparison.LessThan */ : a > b ? 1 /* Comparison.GreaterThan */ : 0 /* Comparison.EqualTo */;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
function getStringComparerFactory() {
|
|
1143
|
+
// If the host supports Intl, we use it for comparisons using the default locale.
|
|
1144
|
+
if (typeof Intl === "object" && typeof Intl.Collator === "function") {
|
|
1145
|
+
return createIntlCollatorStringComparer;
|
|
1146
|
+
}
|
|
1147
|
+
// If the host does not support Intl, we fall back to localeCompare.
|
|
1148
|
+
// localeCompare in Node v0.10 is just an ordinal comparison, so don't use it.
|
|
1149
|
+
if (typeof String.prototype.localeCompare === "function" &&
|
|
1150
|
+
typeof String.prototype.toLocaleUpperCase === "function" &&
|
|
1151
|
+
"a".localeCompare("B") < 0) {
|
|
1152
|
+
return createLocaleCompareStringComparer;
|
|
1153
|
+
}
|
|
1154
|
+
// Otherwise, fall back to ordinal comparison:
|
|
1155
|
+
return createFallbackStringComparer;
|
|
1156
|
+
}
|
|
1157
|
+
function createStringComparer(locale) {
|
|
1158
|
+
// Hold onto common string comparers. This avoids constantly reallocating comparers during
|
|
1159
|
+
// tests.
|
|
1160
|
+
if (locale === undefined) {
|
|
1161
|
+
return defaultComparer || (defaultComparer = stringComparerFactory(locale));
|
|
1162
|
+
}
|
|
1163
|
+
else if (locale === "en-US") {
|
|
1164
|
+
return enUSComparer || (enUSComparer = stringComparerFactory(locale));
|
|
1165
|
+
}
|
|
1166
|
+
else {
|
|
1167
|
+
return stringComparerFactory(locale);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
})();
|
|
1171
|
+
let uiComparerCaseSensitive;
|
|
1172
|
+
let uiLocale;
|
|
1173
|
+
/**
|
|
1174
|
+
* Compare two strings in a using the case-sensitive sort behavior of the UI locale.
|
|
1175
|
+
*
|
|
1176
|
+
* Ordering is not predictable between different host locales, but is best for displaying
|
|
1177
|
+
* ordered data for UI presentation. Characters with multiple unicode representations may
|
|
1178
|
+
* be considered equal.
|
|
1179
|
+
*
|
|
1180
|
+
* Case-sensitive comparisons compare strings that differ in base characters, or
|
|
1181
|
+
* accents/diacritic marks, or case as unequal.
|
|
1182
|
+
*/
|
|
1183
|
+
export function compareStringsCaseSensitiveUI(a, b) {
|
|
1184
|
+
const comparer = uiComparerCaseSensitive || (uiComparerCaseSensitive = createUIStringComparer(uiLocale));
|
|
1185
|
+
return comparer(a, b);
|
|
1186
|
+
}
|
|
1187
|
+
// `T extends {}`: no 3.9, um `T` sem restrição não era `null`; desde o 4.8 pode ser, e o `a[key]` depois
|
|
1188
|
+
// do `a === undefined` passaria a ser acusado.
|
|
1189
|
+
export function compareProperties(a, b, key, comparer) {
|
|
1190
|
+
return a === b ? 0 /* Comparison.EqualTo */ :
|
|
1191
|
+
a === undefined ? -1 /* Comparison.LessThan */ :
|
|
1192
|
+
b === undefined ? 1 /* Comparison.GreaterThan */ :
|
|
1193
|
+
comparer(a[key], b[key]);
|
|
1194
|
+
}
|
|
1195
|
+
/** True is greater than false. */
|
|
1196
|
+
export function compareBooleans(a, b) {
|
|
1197
|
+
return compareValues(a ? 1 : 0, b ? 1 : 0);
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* Given a name and a list of names that are *not* equal to the name, return a spelling suggestion if there is one that is close enough.
|
|
1201
|
+
* Names less than length 3 only check for case-insensitive equality, not Levenshtein distance.
|
|
1202
|
+
*
|
|
1203
|
+
* If there is a candidate that's the same except for case, return that.
|
|
1204
|
+
* If there is a candidate that's within one edit of the name, return that.
|
|
1205
|
+
* Otherwise, return the candidate with the smallest Levenshtein distance,
|
|
1206
|
+
* except for candidates:
|
|
1207
|
+
* * With no name
|
|
1208
|
+
* * Whose length differs from the target name by more than 0.34 of the length of the name.
|
|
1209
|
+
* * Whose levenshtein distance is more than 0.4 of the length of the name
|
|
1210
|
+
* (0.4 allows 1 substitution/transposition for every 5 characters,
|
|
1211
|
+
* and 1 insertion/deletion at 3 characters)
|
|
1212
|
+
*/
|
|
1213
|
+
export function getSpellingSuggestion(name, candidates, getName) {
|
|
1214
|
+
const maximumLengthDifference = Math.min(2, Math.floor(name.length * 0.34));
|
|
1215
|
+
let bestDistance = Math.floor(name.length * 0.4) + 1; // If the best result isn't better than this, don't bother.
|
|
1216
|
+
let bestCandidate;
|
|
1217
|
+
let justCheckExactMatches = false;
|
|
1218
|
+
const nameLowerCase = name.toLowerCase();
|
|
1219
|
+
for (const candidate of candidates) {
|
|
1220
|
+
const candidateName = getName(candidate);
|
|
1221
|
+
if (candidateName !== undefined && Math.abs(candidateName.length - nameLowerCase.length) <= maximumLengthDifference) {
|
|
1222
|
+
const candidateNameLowerCase = candidateName.toLowerCase();
|
|
1223
|
+
if (candidateNameLowerCase === nameLowerCase) {
|
|
1224
|
+
if (candidateName === name) {
|
|
1225
|
+
continue;
|
|
1226
|
+
}
|
|
1227
|
+
return candidate;
|
|
1228
|
+
}
|
|
1229
|
+
if (justCheckExactMatches) {
|
|
1230
|
+
continue;
|
|
1231
|
+
}
|
|
1232
|
+
if (candidateName.length < 3) {
|
|
1233
|
+
// Don't bother, user would have noticed a 2-character name having an extra character
|
|
1234
|
+
continue;
|
|
1235
|
+
}
|
|
1236
|
+
// Only care about a result better than the best so far.
|
|
1237
|
+
const distance = levenshteinWithMax(nameLowerCase, candidateNameLowerCase, bestDistance - 1);
|
|
1238
|
+
if (distance === undefined) {
|
|
1239
|
+
continue;
|
|
1240
|
+
}
|
|
1241
|
+
if (distance < 3) {
|
|
1242
|
+
justCheckExactMatches = true;
|
|
1243
|
+
bestCandidate = candidate;
|
|
1244
|
+
}
|
|
1245
|
+
else {
|
|
1246
|
+
Debug.assert(distance < bestDistance); // Else `levenshteinWithMax` should return undefined
|
|
1247
|
+
bestDistance = distance;
|
|
1248
|
+
bestCandidate = candidate;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
return bestCandidate;
|
|
1253
|
+
}
|
|
1254
|
+
function levenshteinWithMax(s1, s2, max) {
|
|
1255
|
+
let previous = new Array(s2.length + 1);
|
|
1256
|
+
let current = new Array(s2.length + 1);
|
|
1257
|
+
/** Represents any value > max. We don't care about the particular value. */
|
|
1258
|
+
const big = max + 1;
|
|
1259
|
+
for (let i = 0; i <= s2.length; i++) {
|
|
1260
|
+
previous[i] = i;
|
|
1261
|
+
}
|
|
1262
|
+
for (let i = 1; i <= s1.length; i++) {
|
|
1263
|
+
const c1 = s1.charCodeAt(i - 1);
|
|
1264
|
+
const minJ = i > max ? i - max : 1;
|
|
1265
|
+
const maxJ = s2.length > max + i ? max + i : s2.length;
|
|
1266
|
+
current[0] = i;
|
|
1267
|
+
/** Smallest value of the matrix in the ith column. */
|
|
1268
|
+
let colMin = i;
|
|
1269
|
+
for (let j = 1; j < minJ; j++) {
|
|
1270
|
+
current[j] = big;
|
|
1271
|
+
}
|
|
1272
|
+
for (let j = minJ; j <= maxJ; j++) {
|
|
1273
|
+
const dist = c1 === s2.charCodeAt(j - 1)
|
|
1274
|
+
? previous[j - 1]
|
|
1275
|
+
: Math.min(/*delete*/ previous[j] + 1, /*insert*/ current[j - 1] + 1, /*substitute*/ previous[j - 1] + 2);
|
|
1276
|
+
current[j] = dist;
|
|
1277
|
+
colMin = Math.min(colMin, dist);
|
|
1278
|
+
}
|
|
1279
|
+
for (let j = maxJ + 1; j <= s2.length; j++) {
|
|
1280
|
+
current[j] = big;
|
|
1281
|
+
}
|
|
1282
|
+
if (colMin > max) {
|
|
1283
|
+
// Give up -- everything in this column is > max and it can't get better in future columns.
|
|
1284
|
+
return undefined;
|
|
1285
|
+
}
|
|
1286
|
+
const temp = previous;
|
|
1287
|
+
previous = current;
|
|
1288
|
+
current = temp;
|
|
1289
|
+
}
|
|
1290
|
+
const res = previous[s2.length];
|
|
1291
|
+
return res > max ? undefined : res;
|
|
1292
|
+
}
|
|
1293
|
+
export function endsWith(str, suffix) {
|
|
1294
|
+
const expectedPos = str.length - suffix.length;
|
|
1295
|
+
return expectedPos >= 0 && str.indexOf(suffix, expectedPos) === expectedPos;
|
|
1296
|
+
}
|
|
1297
|
+
export function removeSuffix(str, suffix) {
|
|
1298
|
+
return endsWith(str, suffix) ? str.slice(0, str.length - suffix.length) : str;
|
|
1299
|
+
}
|
|
1300
|
+
export function tryRemoveSuffix(str, suffix) {
|
|
1301
|
+
return endsWith(str, suffix) ? str.slice(0, str.length - suffix.length) : undefined;
|
|
1302
|
+
}
|
|
1303
|
+
export function stringContains(str, substring) {
|
|
1304
|
+
return str.indexOf(substring) !== -1;
|
|
1305
|
+
}
|
|
1306
|
+
/** Remove an item by index from an array, moving everything to its right one space left. */
|
|
1307
|
+
export function orderedRemoveItemAt(array, index) {
|
|
1308
|
+
// This seems to be faster than either `array.splice(i, 1)` or `array.copyWithin(i, i+ 1)`.
|
|
1309
|
+
for (let i = index; i < array.length - 1; i++) {
|
|
1310
|
+
array[i] = array[i + 1];
|
|
1311
|
+
}
|
|
1312
|
+
array.pop();
|
|
1313
|
+
}
|
|
1314
|
+
export function unorderedRemoveItemAt(array, index) {
|
|
1315
|
+
// Fill in the "hole" left at `index`.
|
|
1316
|
+
array[index] = array[array.length - 1];
|
|
1317
|
+
array.pop();
|
|
1318
|
+
}
|
|
1319
|
+
/** Remove the *first* occurrence of `item` from the array. */
|
|
1320
|
+
export function unorderedRemoveItem(array, item) {
|
|
1321
|
+
return unorderedRemoveFirstItemWhere(array, element => element === item);
|
|
1322
|
+
}
|
|
1323
|
+
/** Remove the *first* element satisfying `predicate`. */
|
|
1324
|
+
function unorderedRemoveFirstItemWhere(array, predicate) {
|
|
1325
|
+
for (let i = 0; i < array.length; i++) {
|
|
1326
|
+
if (predicate(array[i])) {
|
|
1327
|
+
unorderedRemoveItemAt(array, i);
|
|
1328
|
+
return true;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
return false;
|
|
1332
|
+
}
|
|
1333
|
+
export function createGetCanonicalFileName(useCaseSensitiveFileNames) {
|
|
1334
|
+
return useCaseSensitiveFileNames ? identity : toFileNameLowerCase;
|
|
1335
|
+
}
|
|
1336
|
+
export function startsWith(str, prefix) {
|
|
1337
|
+
return str.lastIndexOf(prefix, 0) === 0;
|
|
1338
|
+
}
|
|
1339
|
+
export function removePrefix(str, prefix) {
|
|
1340
|
+
return startsWith(str, prefix) ? str.substr(prefix.length) : str;
|
|
1341
|
+
}
|
|
1342
|
+
export function tryRemovePrefix(str, prefix, getCanonicalFileName = identity) {
|
|
1343
|
+
return startsWith(getCanonicalFileName(str), getCanonicalFileName(prefix)) ? str.substring(prefix.length) : undefined;
|
|
1344
|
+
}
|
|
1345
|
+
export function and(f, g) {
|
|
1346
|
+
return (arg) => f(arg) && g(arg);
|
|
1347
|
+
}
|
|
1348
|
+
export function or(...fs) {
|
|
1349
|
+
return (...args) => {
|
|
1350
|
+
for (const f of fs) {
|
|
1351
|
+
if (f(...args)) {
|
|
1352
|
+
return true;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
return false;
|
|
1356
|
+
};
|
|
1357
|
+
}
|
|
1358
|
+
export function not(fn) {
|
|
1359
|
+
return (...args) => !fn(...args);
|
|
1360
|
+
}
|
|
1361
|
+
export function assertType(_) { }
|
|
1362
|
+
export function singleElementArray(t) {
|
|
1363
|
+
return t === undefined ? undefined : [t];
|
|
1364
|
+
}
|
|
1365
|
+
export function fill(length, cb) {
|
|
1366
|
+
const result = Array(length);
|
|
1367
|
+
for (let i = 0; i < length; i++) {
|
|
1368
|
+
result[i] = cb(i);
|
|
1369
|
+
}
|
|
1370
|
+
return result;
|
|
1371
|
+
}
|
|
1372
|
+
export function cartesianProduct(arrays) {
|
|
1373
|
+
const result = [];
|
|
1374
|
+
cartesianProductWorker(arrays, result, /*outer*/ undefined, 0);
|
|
1375
|
+
return result;
|
|
1376
|
+
}
|
|
1377
|
+
function cartesianProductWorker(arrays, result, outer, index) {
|
|
1378
|
+
for (const element of arrays[index]) {
|
|
1379
|
+
let inner;
|
|
1380
|
+
if (outer) {
|
|
1381
|
+
inner = outer.slice();
|
|
1382
|
+
inner.push(element);
|
|
1383
|
+
}
|
|
1384
|
+
else {
|
|
1385
|
+
inner = [element];
|
|
1386
|
+
}
|
|
1387
|
+
if (index === arrays.length - 1) {
|
|
1388
|
+
result.push(inner);
|
|
1389
|
+
}
|
|
1390
|
+
else {
|
|
1391
|
+
cartesianProductWorker(arrays, result, inner, index + 1);
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
}
|