@opensumi/ide-utils 2.21.13 → 2.22.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.
Files changed (114) hide show
  1. package/lib/arrays.d.ts +3 -3
  2. package/lib/arrays.d.ts.map +1 -1
  3. package/lib/arrays.js.map +1 -1
  4. package/lib/async.d.ts +3 -3
  5. package/lib/async.d.ts.map +1 -1
  6. package/lib/buffer.js +4 -4
  7. package/lib/buffer.js.map +1 -1
  8. package/lib/character-classifier.js +3 -3
  9. package/lib/character-classifier.js.map +1 -1
  10. package/lib/decorators.d.ts +1 -1
  11. package/lib/decorators.d.ts.map +1 -1
  12. package/lib/encoding.d.ts +7 -1
  13. package/lib/encoding.d.ts.map +1 -1
  14. package/lib/encoding.js +15 -2
  15. package/lib/encoding.js.map +1 -1
  16. package/lib/errors.d.ts +2 -2
  17. package/lib/errors.d.ts.map +1 -1
  18. package/lib/event.d.ts +2 -2
  19. package/lib/event.d.ts.map +1 -1
  20. package/lib/filters.d.ts +3 -3
  21. package/lib/filters.d.ts.map +1 -1
  22. package/lib/filters.js +25 -25
  23. package/lib/filters.js.map +1 -1
  24. package/lib/glob.d.ts +2 -2
  25. package/lib/glob.d.ts.map +1 -1
  26. package/lib/glob.js +1 -1
  27. package/lib/glob.js.map +1 -1
  28. package/lib/hash.js +10 -10
  29. package/lib/hash.js.map +1 -1
  30. package/lib/iterator.d.ts +1 -1
  31. package/lib/iterator.d.ts.map +1 -1
  32. package/lib/linked-text.d.ts +1 -1
  33. package/lib/linked-text.d.ts.map +1 -1
  34. package/lib/linked-text.js.map +1 -1
  35. package/lib/map.js +17 -17
  36. package/lib/map.js.map +1 -1
  37. package/lib/objects.d.ts +1 -0
  38. package/lib/objects.d.ts.map +1 -1
  39. package/lib/objects.js +38 -1
  40. package/lib/objects.js.map +1 -1
  41. package/lib/os.d.ts +1 -8
  42. package/lib/os.d.ts.map +1 -1
  43. package/lib/os.js +4 -8
  44. package/lib/os.js.map +1 -1
  45. package/lib/path.d.ts +1 -1
  46. package/lib/path.d.ts.map +1 -1
  47. package/lib/path.js +29 -29
  48. package/lib/path.js.map +1 -1
  49. package/lib/platform.js +8 -8
  50. package/lib/platform.js.map +1 -1
  51. package/lib/process.d.ts.map +1 -1
  52. package/lib/process.js +28 -13
  53. package/lib/process.js.map +1 -1
  54. package/lib/progress.js +3 -3
  55. package/lib/progress.js.map +1 -1
  56. package/lib/strings.js +9 -9
  57. package/lib/strings.js.map +1 -1
  58. package/lib/types.d.ts +5 -1
  59. package/lib/types.d.ts.map +1 -1
  60. package/lib/types.js +8 -1
  61. package/lib/types.js.map +1 -1
  62. package/lib/uint.js +4 -4
  63. package/lib/uint.js.map +1 -1
  64. package/lib/uri.js +8 -8
  65. package/lib/uri.js.map +1 -1
  66. package/lib/uuid.d.ts +1 -1
  67. package/lib/uuid.d.ts.map +1 -1
  68. package/lib/uuid.js +3 -2
  69. package/lib/uuid.js.map +1 -1
  70. package/package.json +8 -6
  71. package/src/ansi.ts +10 -0
  72. package/src/argv.ts +57 -0
  73. package/src/arrays.ts +328 -0
  74. package/src/async.ts +580 -0
  75. package/src/buffer.ts +290 -0
  76. package/src/cache.ts +37 -0
  77. package/src/cancellation.ts +136 -0
  78. package/src/charCode.ts +425 -0
  79. package/src/character-classifier.ts +82 -0
  80. package/src/const/encoding.ts +242 -0
  81. package/src/const/index.ts +1 -0
  82. package/src/date.ts +36 -0
  83. package/src/decorators.ts +166 -0
  84. package/src/disposable.ts +377 -0
  85. package/src/encoding.ts +278 -0
  86. package/src/errors.ts +192 -0
  87. package/src/event.ts +1024 -0
  88. package/src/file-uri.ts +41 -0
  89. package/src/filters.ts +887 -0
  90. package/src/functional.ts +43 -0
  91. package/src/glob.ts +752 -0
  92. package/src/hash.ts +336 -0
  93. package/src/iconLabels.ts +149 -0
  94. package/src/index.ts +40 -0
  95. package/src/iterator.ts +36 -0
  96. package/src/lifecycle.ts +48 -0
  97. package/src/linked-list.ts +144 -0
  98. package/src/linked-text.ts +55 -0
  99. package/src/lru-map.ts +133 -0
  100. package/src/map.ts +934 -0
  101. package/src/marshalling.ts +62 -0
  102. package/src/objects.ts +145 -0
  103. package/src/os.ts +76 -0
  104. package/src/path.ts +1885 -0
  105. package/src/platform.ts +194 -0
  106. package/src/process.ts +43 -0
  107. package/src/progress.ts +83 -0
  108. package/src/promises.ts +23 -0
  109. package/src/sequence.ts +28 -0
  110. package/src/strings.ts +1002 -0
  111. package/src/types.ts +214 -0
  112. package/src/uint.ts +59 -0
  113. package/src/uri.ts +298 -0
  114. package/src/uuid.ts +6 -0
package/src/map.ts ADDED
@@ -0,0 +1,934 @@
1
+ import { URI as Uri } from 'vscode-uri';
2
+
3
+ import { CharCode } from './charCode';
4
+ import { Iterator, IteratorResult, FIN } from './iterator';
5
+
6
+ export function values<V = any>(set: Set<V>): V[];
7
+ export function values<K = any, V = any>(map: Map<K, V>): V[];
8
+ export function values<V>(forEachable: { forEach(callback: (value: V, ...more: any[]) => any): void }): V[] {
9
+ const result: V[] = [];
10
+ forEachable.forEach((value) => result.push(value));
11
+ return result;
12
+ }
13
+
14
+ export function keys<K, V>(map: Map<K, V>): K[] {
15
+ const result: K[] = [];
16
+ map.forEach((value, key) => result.push(key));
17
+
18
+ return result;
19
+ }
20
+
21
+ export function getOrSet<K, V>(map: Map<K, V>, key: K, value: V): V {
22
+ let result = map.get(key);
23
+ if (result === undefined) {
24
+ result = value;
25
+ map.set(key, result);
26
+ }
27
+
28
+ return result;
29
+ }
30
+
31
+ export function mapToString<K, V>(map: Map<K, V>): string {
32
+ const entries: string[] = [];
33
+ map.forEach((value, key) => {
34
+ entries.push(`${key} => ${value}`);
35
+ });
36
+
37
+ return `Map(${map.size}) {${entries.join(', ')}}`;
38
+ }
39
+
40
+ export function setToString<K>(set: Set<K>): string {
41
+ const entries: K[] = [];
42
+ set.forEach((value) => {
43
+ entries.push(value);
44
+ });
45
+
46
+ return `Set(${set.size}) {${entries.join(', ')}}`;
47
+ }
48
+
49
+ export function mapToSerializable<T = string>(map: Map<string, T>): [string, T][] {
50
+ const serializable: [string, T][] = [];
51
+
52
+ map.forEach((value, key) => {
53
+ serializable.push([key, value]);
54
+ });
55
+
56
+ return serializable;
57
+ }
58
+
59
+ export function serializableToMap<T = string>(serializable: [string, T][]): Map<string, T> {
60
+ const items = new Map<string, T>();
61
+
62
+ for (const [key, value] of serializable) {
63
+ items.set(key, value);
64
+ }
65
+
66
+ return items;
67
+ }
68
+
69
+ export interface IKeyIterator {
70
+ reset(key: string): this;
71
+ next(): this;
72
+
73
+ hasNext(): boolean;
74
+ cmp(a: string): number;
75
+ value(): string;
76
+ }
77
+
78
+ export class StringIterator implements IKeyIterator {
79
+ private _value = '';
80
+ private _pos = 0;
81
+
82
+ reset(key: string): this {
83
+ this._value = key;
84
+ this._pos = 0;
85
+ return this;
86
+ }
87
+
88
+ next(): this {
89
+ this._pos += 1;
90
+ return this;
91
+ }
92
+
93
+ hasNext(): boolean {
94
+ return this._pos < this._value.length - 1;
95
+ }
96
+
97
+ cmp(a: string): number {
98
+ const aCode = a.charCodeAt(0);
99
+ const thisCode = this._value.charCodeAt(this._pos);
100
+ return aCode - thisCode;
101
+ }
102
+
103
+ value(): string {
104
+ return this._value[this._pos];
105
+ }
106
+ }
107
+
108
+ export class PathIterator implements IKeyIterator {
109
+ private _value: string;
110
+ private _from: number;
111
+ private _to: number;
112
+
113
+ reset(key: string): this {
114
+ this._value = key.replace(/\\$|\/$/, '');
115
+ this._from = 0;
116
+ this._to = 0;
117
+ return this.next();
118
+ }
119
+
120
+ hasNext(): boolean {
121
+ return this._to < this._value.length;
122
+ }
123
+
124
+ next(): this {
125
+ // this._data = key.split(/[\\/]/).filter(s => !!s);
126
+ this._from = this._to;
127
+ let justSeps = true;
128
+ for (; this._to < this._value.length; this._to++) {
129
+ const ch = this._value.charCodeAt(this._to);
130
+ if (ch === CharCode.Slash || ch === CharCode.Backslash) {
131
+ if (justSeps) {
132
+ this._from++;
133
+ } else {
134
+ break;
135
+ }
136
+ } else {
137
+ justSeps = false;
138
+ }
139
+ }
140
+ return this;
141
+ }
142
+
143
+ cmp(a: string): number {
144
+ let aPos = 0;
145
+ const aLen = a.length;
146
+ let thisPos = this._from;
147
+
148
+ while (aPos < aLen && thisPos < this._to) {
149
+ const cmp = a.charCodeAt(aPos) - this._value.charCodeAt(thisPos);
150
+ if (cmp !== 0) {
151
+ return cmp;
152
+ }
153
+ aPos += 1;
154
+ thisPos += 1;
155
+ }
156
+
157
+ if (aLen === this._to - this._from) {
158
+ return 0;
159
+ } else if (aPos < aLen) {
160
+ return -1;
161
+ } else {
162
+ return 1;
163
+ }
164
+ }
165
+
166
+ value(): string {
167
+ return this._value.substring(this._from, this._to);
168
+ }
169
+ }
170
+
171
+ class TernarySearchTreeNode<E> {
172
+ segment: string;
173
+ value: E | undefined;
174
+ key: string;
175
+ left: TernarySearchTreeNode<E> | undefined;
176
+ mid: TernarySearchTreeNode<E> | undefined;
177
+ right: TernarySearchTreeNode<E> | undefined;
178
+
179
+ isEmpty(): boolean {
180
+ return !this.left && !this.mid && !this.right && !this.value;
181
+ }
182
+ }
183
+
184
+ export class TernarySearchTree<E> {
185
+ static forPaths<E>(): TernarySearchTree<E> {
186
+ return new TernarySearchTree<E>(new PathIterator());
187
+ }
188
+
189
+ static forStrings<E>(): TernarySearchTree<E> {
190
+ return new TernarySearchTree<E>(new StringIterator());
191
+ }
192
+
193
+ private _iter: IKeyIterator;
194
+ private _root: TernarySearchTreeNode<E> | undefined;
195
+
196
+ constructor(segments: IKeyIterator) {
197
+ this._iter = segments;
198
+ }
199
+
200
+ clear(): void {
201
+ this._root = undefined;
202
+ }
203
+
204
+ set(key: string, element: E): E | undefined {
205
+ const iter = this._iter.reset(key);
206
+ let node: TernarySearchTreeNode<E>;
207
+
208
+ if (!this._root) {
209
+ this._root = new TernarySearchTreeNode<E>();
210
+ this._root.segment = iter.value();
211
+ }
212
+
213
+ node = this._root;
214
+ while (true) {
215
+ const val = iter.cmp(node.segment);
216
+ if (val > 0) {
217
+ // left
218
+ if (!node.left) {
219
+ node.left = new TernarySearchTreeNode<E>();
220
+ node.left.segment = iter.value();
221
+ }
222
+ node = node.left;
223
+ } else if (val < 0) {
224
+ // right
225
+ if (!node.right) {
226
+ node.right = new TernarySearchTreeNode<E>();
227
+ node.right.segment = iter.value();
228
+ }
229
+ node = node.right;
230
+ } else if (iter.hasNext()) {
231
+ // mid
232
+ iter.next();
233
+ if (!node.mid) {
234
+ node.mid = new TernarySearchTreeNode<E>();
235
+ node.mid.segment = iter.value();
236
+ }
237
+ node = node.mid;
238
+ } else {
239
+ break;
240
+ }
241
+ }
242
+ const oldElement = node.value;
243
+ node.value = element;
244
+ node.key = key;
245
+ return oldElement;
246
+ }
247
+
248
+ get(key: string): E | undefined {
249
+ const iter = this._iter.reset(key);
250
+ let node = this._root;
251
+ while (node) {
252
+ const val = iter.cmp(node.segment);
253
+ if (val > 0) {
254
+ // left
255
+ node = node.left;
256
+ } else if (val < 0) {
257
+ // right
258
+ node = node.right;
259
+ } else if (iter.hasNext()) {
260
+ // mid
261
+ iter.next();
262
+ node = node.mid;
263
+ } else {
264
+ break;
265
+ }
266
+ }
267
+ return node ? node.value : undefined;
268
+ }
269
+
270
+ delete(key: string): void {
271
+ const iter = this._iter.reset(key);
272
+ const stack: [-1 | 0 | 1, TernarySearchTreeNode<E>][] = [];
273
+ let node = this._root;
274
+
275
+ // find and unset node
276
+ while (node) {
277
+ const val = iter.cmp(node.segment);
278
+ if (val > 0) {
279
+ // left
280
+ stack.push([1, node]);
281
+ node = node.left;
282
+ } else if (val < 0) {
283
+ // right
284
+ stack.push([-1, node]);
285
+ node = node.right;
286
+ } else if (iter.hasNext()) {
287
+ // mid
288
+ iter.next();
289
+ stack.push([0, node]);
290
+ node = node.mid;
291
+ } else {
292
+ // remove element
293
+ node.value = undefined;
294
+
295
+ // clean up empty nodes
296
+ while (stack.length > 0 && node.isEmpty()) {
297
+ const [dir, parent] = stack.pop()!;
298
+ switch (dir) {
299
+ case 1:
300
+ parent.left = undefined;
301
+ break;
302
+ case 0:
303
+ parent.mid = undefined;
304
+ break;
305
+ case -1:
306
+ parent.right = undefined;
307
+ break;
308
+ }
309
+ node = parent;
310
+ }
311
+ break;
312
+ }
313
+ }
314
+ }
315
+
316
+ findSubstr(key: string): E | undefined {
317
+ const iter = this._iter.reset(key);
318
+ let node = this._root;
319
+ let candidate: E | undefined;
320
+ while (node) {
321
+ const val = iter.cmp(node.segment);
322
+ if (val > 0) {
323
+ // left
324
+ node = node.left;
325
+ } else if (val < 0) {
326
+ // right
327
+ node = node.right;
328
+ } else if (iter.hasNext()) {
329
+ // mid
330
+ iter.next();
331
+ candidate = node.value || candidate;
332
+ node = node.mid;
333
+ } else {
334
+ break;
335
+ }
336
+ }
337
+ return (node && node.value) || candidate;
338
+ }
339
+
340
+ findSuperstr(key: string): Iterator<E> | undefined {
341
+ const iter = this._iter.reset(key);
342
+ let node = this._root;
343
+ while (node) {
344
+ const val = iter.cmp(node.segment);
345
+ if (val > 0) {
346
+ // left
347
+ node = node.left;
348
+ } else if (val < 0) {
349
+ // right
350
+ node = node.right;
351
+ } else if (iter.hasNext()) {
352
+ // mid
353
+ iter.next();
354
+ node = node.mid;
355
+ } else {
356
+ // collect
357
+ if (!node.mid) {
358
+ return undefined;
359
+ } else {
360
+ return this._nodeIterator(node.mid);
361
+ }
362
+ }
363
+ }
364
+ return undefined;
365
+ }
366
+
367
+ private _nodeIterator(node: TernarySearchTreeNode<E>): Iterator<E> {
368
+ let res: { done: false; value: E };
369
+ let idx: number;
370
+ let data: E[];
371
+ const next = (): IteratorResult<E> => {
372
+ if (!data) {
373
+ // lazy till first invocation
374
+ data = [];
375
+ idx = 0;
376
+ this._forEach(node, (value) => data.push(value));
377
+ }
378
+ if (idx >= data.length) {
379
+ return FIN;
380
+ }
381
+
382
+ if (!res) {
383
+ res = { done: false, value: data[idx++] };
384
+ } else {
385
+ res.value = data[idx++];
386
+ }
387
+ return res;
388
+ };
389
+ return { next };
390
+ }
391
+
392
+ forEach(callback: (value: E, index: string) => any) {
393
+ this._forEach(this._root, callback);
394
+ }
395
+
396
+ private _forEach(node: TernarySearchTreeNode<E> | undefined, callback: (value: E, index: string) => any) {
397
+ if (node) {
398
+ // left
399
+ this._forEach(node.left, callback);
400
+
401
+ // node
402
+ if (node.value) {
403
+ // callback(node.value, this._iter.join(parts));
404
+ callback(node.value, node.key);
405
+ }
406
+ // mid
407
+ this._forEach(node.mid, callback);
408
+
409
+ // right
410
+ this._forEach(node.right, callback);
411
+ }
412
+ }
413
+ }
414
+
415
+ export class ResourceMap<T> {
416
+ protected readonly map: Map<string, T>;
417
+ protected readonly ignoreCase?: boolean;
418
+
419
+ constructor() {
420
+ this.map = new Map<string, T>();
421
+ this.ignoreCase = false; // in the future this should be an uri-comparator
422
+ }
423
+
424
+ set(resource: Uri, value: T): void {
425
+ this.map.set(this.toKey(resource), value);
426
+ }
427
+
428
+ get(resource: Uri): T | undefined {
429
+ return this.map.get(this.toKey(resource));
430
+ }
431
+
432
+ has(resource: Uri): boolean {
433
+ return this.map.has(this.toKey(resource));
434
+ }
435
+
436
+ get size(): number {
437
+ return this.map.size;
438
+ }
439
+
440
+ clear(): void {
441
+ this.map.clear();
442
+ }
443
+
444
+ delete(resource: Uri): boolean {
445
+ return this.map.delete(this.toKey(resource));
446
+ }
447
+
448
+ forEach(clb: (value: T) => void): void {
449
+ this.map.forEach(clb);
450
+ }
451
+
452
+ values(): T[] {
453
+ return values(this.map);
454
+ }
455
+
456
+ private toKey(resource: Uri): string {
457
+ let key = resource.toString();
458
+ if (this.ignoreCase) {
459
+ key = key.toLowerCase();
460
+ }
461
+
462
+ return key;
463
+ }
464
+
465
+ keys(): Uri[] {
466
+ return keys(this.map).map((k) => Uri.parse(k));
467
+ }
468
+
469
+ clone(): ResourceMap<T> {
470
+ const resourceMap = new ResourceMap<T>();
471
+
472
+ this.map.forEach((value, key) => resourceMap.map.set(key, value));
473
+
474
+ return resourceMap;
475
+ }
476
+ }
477
+
478
+ // We should fold BoundedMap and LinkedMap. See https://github.com/Microsoft/vscode/issues/28496
479
+
480
+ interface Item<K, V> {
481
+ previous: Item<K, V> | undefined;
482
+ next: Item<K, V> | undefined;
483
+ key: K;
484
+ value: V;
485
+ }
486
+
487
+ export const enum Touch {
488
+ None = 0,
489
+ AsOld = 1,
490
+ AsNew = 2,
491
+ }
492
+
493
+ export class LinkedMap<K, V> {
494
+ private _map: Map<K, Item<K, V>>;
495
+ private _head: Item<K, V> | undefined;
496
+ private _tail: Item<K, V> | undefined;
497
+ private _size: number;
498
+
499
+ constructor() {
500
+ this._map = new Map<K, Item<K, V>>();
501
+ this._head = undefined;
502
+ this._tail = undefined;
503
+ this._size = 0;
504
+ }
505
+
506
+ clear(): void {
507
+ this._map.clear();
508
+ this._head = undefined;
509
+ this._tail = undefined;
510
+ this._size = 0;
511
+ }
512
+
513
+ isEmpty(): boolean {
514
+ return !this._head && !this._tail;
515
+ }
516
+
517
+ get size(): number {
518
+ return this._size;
519
+ }
520
+
521
+ has(key: K): boolean {
522
+ return this._map.has(key);
523
+ }
524
+
525
+ get(key: K, touch: Touch = Touch.None): V | undefined {
526
+ const item = this._map.get(key);
527
+ if (!item) {
528
+ return undefined;
529
+ }
530
+ if (touch !== Touch.None) {
531
+ this.touch(item, touch);
532
+ }
533
+ return item.value;
534
+ }
535
+
536
+ set(key: K, value: V, touch: Touch = Touch.None): void {
537
+ let item = this._map.get(key);
538
+ if (item) {
539
+ item.value = value;
540
+ if (touch !== Touch.None) {
541
+ this.touch(item, touch);
542
+ }
543
+ } else {
544
+ item = { key, value, next: undefined, previous: undefined };
545
+ switch (touch) {
546
+ case Touch.None:
547
+ this.addItemLast(item);
548
+ break;
549
+ case Touch.AsOld:
550
+ this.addItemFirst(item);
551
+ break;
552
+ case Touch.AsNew:
553
+ this.addItemLast(item);
554
+ break;
555
+ default:
556
+ this.addItemLast(item);
557
+ break;
558
+ }
559
+ this._map.set(key, item);
560
+ this._size++;
561
+ }
562
+ }
563
+
564
+ delete(key: K): boolean {
565
+ return !!this.remove(key);
566
+ }
567
+
568
+ remove(key: K): V | undefined {
569
+ const item = this._map.get(key);
570
+ if (!item) {
571
+ return undefined;
572
+ }
573
+ this._map.delete(key);
574
+ this.removeItem(item);
575
+ this._size--;
576
+ return item.value;
577
+ }
578
+
579
+ shift(): V | undefined {
580
+ if (!this._head && !this._tail) {
581
+ return undefined;
582
+ }
583
+ if (!this._head || !this._tail) {
584
+ throw new Error('Invalid list');
585
+ }
586
+ const item = this._head;
587
+ this._map.delete(item.key);
588
+ this.removeItem(item);
589
+ this._size--;
590
+ return item.value;
591
+ }
592
+
593
+ forEach(callbackfn: (value: V, key: K, map: LinkedMap<K, V>) => void, thisArg?: any): void {
594
+ let current = this._head;
595
+ while (current) {
596
+ if (thisArg) {
597
+ callbackfn.bind(thisArg)(current.value, current.key, this);
598
+ } else {
599
+ callbackfn(current.value, current.key, this);
600
+ }
601
+ current = current.next;
602
+ }
603
+ }
604
+
605
+ values(): V[] {
606
+ const result: V[] = [];
607
+ let current = this._head;
608
+ while (current) {
609
+ result.push(current.value);
610
+ current = current.next;
611
+ }
612
+ return result;
613
+ }
614
+
615
+ keys(): K[] {
616
+ const result: K[] = [];
617
+ let current = this._head;
618
+ while (current) {
619
+ result.push(current.key);
620
+ current = current.next;
621
+ }
622
+ return result;
623
+ }
624
+
625
+ /* VS Code / Monaco editor runs on es5 which has no Symbol.iterator
626
+ keys(): IterableIterator<K> {
627
+ const current = this._head;
628
+ const iterator: IterableIterator<K> = {
629
+ [Symbol.iterator]() {
630
+ return iterator;
631
+ },
632
+ next():IteratorResult<K> {
633
+ if (current) {
634
+ const result = { value: current.key, done: false };
635
+ current = current.next;
636
+ return result;
637
+ } else {
638
+ return { value: undefined, done: true };
639
+ }
640
+ }
641
+ };
642
+ return iterator;
643
+ }
644
+
645
+ values(): IterableIterator<V> {
646
+ const current = this._head;
647
+ const iterator: IterableIterator<V> = {
648
+ [Symbol.iterator]() {
649
+ return iterator;
650
+ },
651
+ next():IteratorResult<V> {
652
+ if (current) {
653
+ const result = { value: current.value, done: false };
654
+ current = current.next;
655
+ return result;
656
+ } else {
657
+ return { value: undefined, done: true };
658
+ }
659
+ }
660
+ };
661
+ return iterator;
662
+ }
663
+ */
664
+
665
+ protected trimOld(newSize: number) {
666
+ if (newSize >= this.size) {
667
+ return;
668
+ }
669
+ if (newSize === 0) {
670
+ this.clear();
671
+ return;
672
+ }
673
+ let current = this._head;
674
+ let currentSize = this.size;
675
+ while (current && currentSize > newSize) {
676
+ this._map.delete(current.key);
677
+ current = current.next;
678
+ currentSize--;
679
+ }
680
+ this._head = current;
681
+ this._size = currentSize;
682
+ if (current) {
683
+ current.previous = undefined;
684
+ }
685
+ }
686
+
687
+ private addItemFirst(item: Item<K, V>): void {
688
+ // First time Insert
689
+ if (!this._head && !this._tail) {
690
+ this._tail = item;
691
+ } else if (!this._head) {
692
+ throw new Error('Invalid list');
693
+ } else {
694
+ item.next = this._head;
695
+ this._head.previous = item;
696
+ }
697
+ this._head = item;
698
+ }
699
+
700
+ private addItemLast(item: Item<K, V>): void {
701
+ // First time Insert
702
+ if (!this._head && !this._tail) {
703
+ this._head = item;
704
+ } else if (!this._tail) {
705
+ throw new Error('Invalid list');
706
+ } else {
707
+ item.previous = this._tail;
708
+ this._tail.next = item;
709
+ }
710
+ this._tail = item;
711
+ }
712
+
713
+ private removeItem(item: Item<K, V>): void {
714
+ if (item === this._head && item === this._tail) {
715
+ this._head = undefined;
716
+ this._tail = undefined;
717
+ } else if (item === this._head) {
718
+ // This can only happend if size === 1 which is handle
719
+ // by the case above.
720
+ if (!item.next) {
721
+ throw new Error('Invalid list');
722
+ }
723
+ item.next.previous = undefined;
724
+ this._head = item.next;
725
+ } else if (item === this._tail) {
726
+ // This can only happend if size === 1 which is handle
727
+ // by the case above.
728
+ if (!item.previous) {
729
+ throw new Error('Invalid list');
730
+ }
731
+ item.previous.next = undefined;
732
+ this._tail = item.previous;
733
+ } else {
734
+ const next = item.next;
735
+ const previous = item.previous;
736
+ if (!next || !previous) {
737
+ throw new Error('Invalid list');
738
+ }
739
+ next.previous = previous;
740
+ previous.next = next;
741
+ }
742
+ item.next = undefined;
743
+ item.previous = undefined;
744
+ }
745
+
746
+ private touch(item: Item<K, V>, touch: Touch): void {
747
+ if (!this._head || !this._tail) {
748
+ throw new Error('Invalid list');
749
+ }
750
+ if (touch !== Touch.AsOld && touch !== Touch.AsNew) {
751
+ return;
752
+ }
753
+
754
+ if (touch === Touch.AsOld) {
755
+ if (item === this._head) {
756
+ return;
757
+ }
758
+
759
+ const next = item.next;
760
+ const previous = item.previous;
761
+
762
+ // Unlink the item
763
+ if (item === this._tail) {
764
+ // previous must be defined since item was not head but is tail
765
+ // So there are more than on item in the map
766
+ previous!.next = undefined;
767
+ this._tail = previous;
768
+ } else {
769
+ // Both next and previous are not undefined since item was neither head nor tail.
770
+ next!.previous = previous;
771
+ previous!.next = next;
772
+ }
773
+
774
+ // Insert the node at head
775
+ item.previous = undefined;
776
+ item.next = this._head;
777
+ this._head.previous = item;
778
+ this._head = item;
779
+ } else if (touch === Touch.AsNew) {
780
+ if (item === this._tail) {
781
+ return;
782
+ }
783
+
784
+ const next = item.next;
785
+ const previous = item.previous;
786
+
787
+ // Unlink the item.
788
+ if (item === this._head) {
789
+ // next must be defined since item was not tail but is head
790
+ // So there are more than on item in the map
791
+ next!.previous = undefined;
792
+ this._head = next;
793
+ } else {
794
+ // Both next and previous are not undefined since item was neither head nor tail.
795
+ next!.previous = previous;
796
+ previous!.next = next;
797
+ }
798
+ item.next = undefined;
799
+ item.previous = this._tail;
800
+ this._tail.next = item;
801
+ this._tail = item;
802
+ }
803
+ }
804
+
805
+ toJSON(): [K, V][] {
806
+ const data: [K, V][] = [];
807
+
808
+ this.forEach((value, key) => {
809
+ data.push([key, value]);
810
+ });
811
+
812
+ return data;
813
+ }
814
+
815
+ fromJSON(data: [K, V][]): void {
816
+ this.clear();
817
+
818
+ for (const [key, value] of data) {
819
+ this.set(key, value);
820
+ }
821
+ }
822
+ }
823
+
824
+ export class LRUCache<K, V> extends LinkedMap<K, V> {
825
+ private _limit: number;
826
+ private _ratio: number;
827
+
828
+ constructor(limit: number, ratio = 1) {
829
+ super();
830
+ this._limit = limit;
831
+ this._ratio = Math.min(Math.max(0, ratio), 1);
832
+ }
833
+
834
+ get limit(): number {
835
+ return this._limit;
836
+ }
837
+
838
+ set limit(limit: number) {
839
+ this._limit = limit;
840
+ this.checkTrim();
841
+ }
842
+
843
+ get ratio(): number {
844
+ return this._ratio;
845
+ }
846
+
847
+ set ratio(ratio: number) {
848
+ this._ratio = Math.min(Math.max(0, ratio), 1);
849
+ this.checkTrim();
850
+ }
851
+
852
+ get(key: K): V | undefined {
853
+ return super.get(key, Touch.AsNew);
854
+ }
855
+
856
+ peek(key: K): V | undefined {
857
+ return super.get(key, Touch.None);
858
+ }
859
+
860
+ set(key: K, value: V): void {
861
+ super.set(key, value, Touch.AsNew);
862
+ this.checkTrim();
863
+ }
864
+
865
+ private checkTrim() {
866
+ if (this.size > this._limit) {
867
+ this.trimOld(Math.round(this._limit * this._ratio));
868
+ }
869
+ }
870
+ }
871
+
872
+ export class SetMap<K, V> {
873
+ private map = new Map<K, Set<V>>();
874
+
875
+ add(key: K, value: V): void {
876
+ let values = this.map.get(key);
877
+
878
+ if (!values) {
879
+ values = new Set<V>();
880
+ this.map.set(key, values);
881
+ }
882
+
883
+ values.add(value);
884
+ }
885
+
886
+ delete(key: K, value: V): void {
887
+ const values = this.map.get(key);
888
+
889
+ if (!values) {
890
+ return;
891
+ }
892
+
893
+ values.delete(value);
894
+
895
+ if (values.size === 0) {
896
+ this.map.delete(key);
897
+ }
898
+ }
899
+
900
+ forEach(key: K, fn: (value: V) => void): void {
901
+ const values = this.map.get(key);
902
+
903
+ if (!values) {
904
+ return;
905
+ }
906
+
907
+ values.forEach(fn);
908
+ }
909
+ }
910
+
911
+ export class CaseInsensitiveMap<K, V> extends Map<K, V> {
912
+ set(key: K, value: V): this {
913
+ if (typeof key === 'string') {
914
+ key = key.toLowerCase() as any as K;
915
+ }
916
+ return super.set(key, value);
917
+ }
918
+
919
+ get(key: K): V | undefined {
920
+ if (typeof key === 'string') {
921
+ key = key.toLowerCase() as any as K;
922
+ }
923
+
924
+ return super.get(key);
925
+ }
926
+
927
+ has(key: K): boolean {
928
+ if (typeof key === 'string') {
929
+ key = key.toLowerCase() as any as K;
930
+ }
931
+
932
+ return super.has(key);
933
+ }
934
+ }