@siteimprove/alfa-list 0.89.5

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/CHANGELOG.md ADDED
@@ -0,0 +1,157 @@
1
+ # @siteimprove/alfa-list
2
+
3
+ ## 0.89.3
4
+
5
+ ## 0.89.2
6
+
7
+ ### Patch Changes
8
+
9
+ - **Changed:** Trying to fix a problem in generating provenance statements ([#1674](https://github.com/Siteimprove/alfa/pull/1674))
10
+
11
+ ## 0.89.1
12
+
13
+ ### Patch Changes
14
+
15
+ - **Added:** Trying to publish Alfa packages on the npm registry ([#1673](https://github.com/Siteimprove/alfa/pull/1673))
16
+
17
+ ## 0.89.0
18
+
19
+ ## 0.88.0
20
+
21
+ ### Minor Changes
22
+
23
+ - **Fixed:** The publish flow was updated to a new version. ([`a2f19cf9a6c7c72b8bf085597e4f1a95ac3e4eb2`](https://github.com/Siteimprove/alfa/commit/a2f19cf9a6c7c72b8bf085597e4f1a95ac3e4eb2))
24
+
25
+ Some 0.87.\* versions were generating uninstallable package. This should be fixed now.
26
+
27
+ ## 0.87.12
28
+
29
+ ## 0.87.11
30
+
31
+ ## 0.87.10
32
+
33
+ ## 0.87.7
34
+
35
+ ## 0.87.6
36
+
37
+ ## 0.87.5
38
+
39
+ ## 0.87.4
40
+
41
+ ## 0.87.3
42
+
43
+ ## 0.87.2
44
+
45
+ ## 0.87.1
46
+
47
+ ## 0.87.0
48
+
49
+ ### Minor Changes
50
+
51
+ - **Breaking:** Optional serialization type parameters have been removed. ([#1651](https://github.com/Siteimprove/alfa/pull/1651))
52
+
53
+ ## 0.86.2
54
+
55
+ ## 0.86.1
56
+
57
+ ## 0.86.0
58
+
59
+ ### Minor Changes
60
+
61
+ - **Breaking:** TS resolution has been changed to `Node16`, target to `es2022`. ([#1636](https://github.com/Siteimprove/alfa/pull/1636))
62
+
63
+ - **Breaking:** Alfa is now distributed as ESM rather than CJS modules; projects using it must be ESM or use dynamic `import()`. ([#1636](https://github.com/Siteimprove/alfa/pull/1636))
64
+
65
+ ⚠️ This is the last of a series of changes on the internal structure and build process of distributed packages that was started with v0.85.0.
66
+
67
+ ## 0.85.1
68
+
69
+ ## 0.85.0
70
+
71
+ ### Minor Changes
72
+
73
+ - **Breaking:** The .js files are now built in the `dist` folder rather than in `src`. ([#1628](https://github.com/Siteimprove/alfa/pull/1628))
74
+
75
+ ⚠️ This is the first of a series of changes on the internal structure and build process of distributed packages. It is probably better to not use this version and wait until more of these internal changes have been done to jump directly to the final result. We are internally releasing these changes for validation purpose only.
76
+
77
+ This should not impact consumers, the `package.json` files should be set correctly to consume these files.
78
+
79
+ ## 0.84.0
80
+
81
+ ## 0.83.1
82
+
83
+ ## 0.83.0
84
+
85
+ ## 0.82.0
86
+
87
+ ### Minor Changes
88
+
89
+ - **Added:** Serialization options are now accepted, and passed on, by `toJSON()` on these types. ([#1622](https://github.com/Siteimprove/alfa/pull/1622))
90
+
91
+ - **Breaking:** Node 18 is no longer supported. ([#1618](https://github.com/Siteimprove/alfa/pull/1618))
92
+
93
+ ## 0.81.0
94
+
95
+ ### Patch Changes
96
+
97
+ - **Added:** Each package now contains its internal dependency graph in its `docs` directory. ([#1610](https://github.com/Siteimprove/alfa/pull/1610))
98
+
99
+ ## 0.80.0
100
+
101
+ ## 0.79.1
102
+
103
+ ## 0.79.0
104
+
105
+ ## 0.78.2
106
+
107
+ ## 0.78.1
108
+
109
+ ## 0.78.0
110
+
111
+ ## 0.77.0
112
+
113
+ ## 0.76.0
114
+
115
+ ## 0.75.2
116
+
117
+ ## 0.75.1
118
+
119
+ ## 0.75.0
120
+
121
+ ## 0.74.0
122
+
123
+ ## 0.73.0
124
+
125
+ ## 0.72.0
126
+
127
+ ## 0.71.1
128
+
129
+ ## 0.71.0
130
+
131
+ ## 0.70.0
132
+
133
+ ## 0.69.0
134
+
135
+ ## 0.68.0
136
+
137
+ ## 0.67.0
138
+
139
+ ## 0.66.0
140
+
141
+ ## 0.65.1
142
+
143
+ ## 0.65.0
144
+
145
+ ## 0.64.0
146
+
147
+ ## 0.63.3
148
+
149
+ ## 0.63.2
150
+
151
+ ## 0.63.1
152
+
153
+ ## 0.63.0
154
+
155
+ ## 0.62.2
156
+
157
+ ## 0.62.1
@@ -0,0 +1,3 @@
1
+ export * from "./list.js";
2
+ export * from "./node.js";
3
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./list.js";
2
+ export * from "./node.js";
3
+ //# sourceMappingURL=index.js.map
package/dist/list.d.ts ADDED
@@ -0,0 +1,111 @@
1
+ import { Array } from "@siteimprove/alfa-array";
2
+ import type { Callback } from "@siteimprove/alfa-callback";
3
+ import type { Collection } from "@siteimprove/alfa-collection";
4
+ import { Comparable, type Comparer, type Comparison } from "@siteimprove/alfa-comparable";
5
+ import type { Hash } from "@siteimprove/alfa-hash";
6
+ import { Iterable } from "@siteimprove/alfa-iterable";
7
+ import { Serializable } from "@siteimprove/alfa-json";
8
+ import { Map } from "@siteimprove/alfa-map";
9
+ import type { Mapper } from "@siteimprove/alfa-mapper";
10
+ import { Option } from "@siteimprove/alfa-option";
11
+ import { Predicate } from "@siteimprove/alfa-predicate";
12
+ import type { Reducer } from "@siteimprove/alfa-reducer";
13
+ import type { Refinement } from "@siteimprove/alfa-refinement";
14
+ /**
15
+ * @public
16
+ */
17
+ export declare class List<T> implements Collection.Indexed<T> {
18
+ static of<T>(...values: Array<T>): List<T>;
19
+ private static _empty;
20
+ static empty<T = never>(): List<T>;
21
+ private readonly _head;
22
+ private readonly _tail;
23
+ private readonly _shift;
24
+ private readonly _size;
25
+ private constructor();
26
+ get size(): number;
27
+ isEmpty(): this is List<never>;
28
+ forEach(callback: Callback<T, void, [index: number]>): void;
29
+ map<U>(mapper: Mapper<T, U, [index: number]>): List<U>;
30
+ apply<U>(mapper: List<Mapper<T, U>>): List<U>;
31
+ flatMap<U>(mapper: Mapper<T, List<U>, [index: number]>): List<U>;
32
+ flatten<T>(this: List<List<T>>): List<T>;
33
+ reduce<U>(reducer: Reducer<T, U, [index: number]>, accumulator: U): U;
34
+ reduceWhile<U>(predicate: Predicate<T, [index: number]>, reducer: Reducer<T, U, [index: number]>, accumulator: U): U;
35
+ reduceUntil<U>(predicate: Predicate<T, [index: number]>, reducer: Reducer<T, U, [index: number]>, accumulator: U): U;
36
+ filter<U extends T>(refinement: Refinement<T, U, [index: number]>): List<U>;
37
+ filter(predicate: Predicate<T, [index: number]>): List<T>;
38
+ reject<U extends T>(refinement: Refinement<T, U, [index: number]>): List<Exclude<T, U>>;
39
+ reject(predicate: Predicate<T, [index: number]>): List<T>;
40
+ find<U extends T>(refinement: Refinement<T, U, [index: number]>): Option<U>;
41
+ find(predicate: Predicate<T, [index: number]>): Option<T>;
42
+ includes(value: T): boolean;
43
+ collect<U>(mapper: Mapper<T, Option<U>, [index: number]>): List<U>;
44
+ collectFirst<U>(mapper: Mapper<T, Option<U>, [index: number]>): Option<U>;
45
+ some(predicate: Predicate<T, [index: number]>): boolean;
46
+ none(predicate: Predicate<T, [index: number]>): boolean;
47
+ every(predicate: Predicate<T, [index: number]>): boolean;
48
+ count(predicate: Predicate<T, [index: number]>): number;
49
+ distinct(): List<T>;
50
+ get(index: number): Option<T>;
51
+ has(index: number): boolean;
52
+ set(index: number, value: T): List<T>;
53
+ insert(index: number, value: T): List<T>;
54
+ append(value: T): List<T>;
55
+ prepend(value: T): List<T>;
56
+ concat(iterable: Iterable<T>): List<T>;
57
+ subtract(iterable: Iterable<T>): List<T>;
58
+ intersect(iterable: Iterable<T>): List<T>;
59
+ tee<A extends Array<unknown> = []>(callback: Callback<this, void, [...args: A]>, ...args: A): this;
60
+ zip<U>(iterable: Iterable<U>): List<[T, U]>;
61
+ first(): Option<T>;
62
+ last(): Option<T>;
63
+ take(count: number): List<T>;
64
+ takeWhile<U extends T>(refinement: Refinement<T, U, [index: number]>): List<U>;
65
+ takeWhile(predicate: Predicate<T, [index: number]>): List<T>;
66
+ takeUntil(predicate: Predicate<T, [index: number]>): List<T>;
67
+ takeLast(count?: number): List<T>;
68
+ takeLastWhile<U extends T>(refinement: Refinement<T, U, [index: number]>): List<U>;
69
+ takeLastWhile(predicate: Predicate<T, [index: number]>): List<T>;
70
+ takeLastUntil(predicate: Predicate<T, [index: number]>): List<T>;
71
+ skip(count: number): List<T>;
72
+ skipWhile(predicate: Predicate<T, [index: number]>): List<T>;
73
+ skipUntil(predicate: Predicate<T, [index: number]>): List<T>;
74
+ skipLast(count?: number): List<T>;
75
+ skipLastWhile(predicate: Predicate<T, [index: number]>): List<T>;
76
+ skipLastUntil(predicate: Predicate<T, [index: number]>): List<T>;
77
+ trim(predicate: Predicate<T, [index: number]>): List<T>;
78
+ trimLeading(predicate: Predicate<T, [index: number]>): List<T>;
79
+ trimTrailing(predicate: Predicate<T, [index: number]>): List<T>;
80
+ rest(): List<T>;
81
+ slice(start: number, end?: number): List<T>;
82
+ reverse(): List<T>;
83
+ join(separator: string): string;
84
+ sort<T extends Comparable<T>>(this: List<T>): List<T>;
85
+ sortWith(comparer: Comparer<T>): List<T>;
86
+ sortWith<T, U extends T = T>(this: List<U>, comparer: Comparer<T>): List<U>;
87
+ compare<T>(this: List<Comparable<T>>, iterable: Iterable<T>): Comparison;
88
+ compareWith<U = T>(iterable: Iterable<U>, comparer: Comparer<T, U, [index: number]>): Comparison;
89
+ groupBy<K>(grouper: Mapper<T, K>): Map<K, List<T>>;
90
+ equals<T>(value: List<T>): boolean;
91
+ equals(value: unknown): value is this;
92
+ hash(hash: Hash): void;
93
+ [Symbol.iterator](): Iterator<T>;
94
+ toArray(): Array<T>;
95
+ toJSON(options?: Serializable.Options): List.JSON<T>;
96
+ toString(): string;
97
+ private _push;
98
+ private _pop;
99
+ }
100
+ /**
101
+ * @public
102
+ */
103
+ export declare namespace List {
104
+ type JSON<T> = Collection.Indexed.JSON<T>;
105
+ function isList<T>(value: Iterable<T>): value is List<T>;
106
+ function isList<T>(value: unknown): value is List<T>;
107
+ function from<T>(iterable: Iterable<T>): List<T>;
108
+ function fromArray<T>(array: ReadonlyArray<T>): List<T>;
109
+ function fromIterable<T>(iterable: Iterable<T>): List<T>;
110
+ }
111
+ //# sourceMappingURL=list.d.ts.map
package/dist/list.js ADDED
@@ -0,0 +1,475 @@
1
+ import { Array } from "@siteimprove/alfa-array";
2
+ import { Comparable } from "@siteimprove/alfa-comparable";
3
+ import { Iterable } from "@siteimprove/alfa-iterable";
4
+ import { Serializable } from "@siteimprove/alfa-json";
5
+ import { Map } from "@siteimprove/alfa-map";
6
+ import { None, Option } from "@siteimprove/alfa-option";
7
+ import { Predicate } from "@siteimprove/alfa-predicate";
8
+ import { Set } from "@siteimprove/alfa-set";
9
+ import { Branch, Empty, Leaf, Node } from "./node.js";
10
+ const { not } = Predicate;
11
+ const { compareComparable } = Comparable;
12
+ /**
13
+ * @public
14
+ */
15
+ export class List {
16
+ static of(...values) {
17
+ const size = values.length;
18
+ // Fast path: The values fit within the tail.
19
+ if (size <= Node.Capacity) {
20
+ return new List(Empty, Leaf.of(values), 0, size);
21
+ }
22
+ return values.reduce((list, value) => list._push(value), List.empty());
23
+ }
24
+ static _empty = new List(Empty, Empty, 0, 0);
25
+ static empty() {
26
+ return this._empty;
27
+ }
28
+ _head;
29
+ _tail;
30
+ _shift;
31
+ _size;
32
+ constructor(head, tail, shift, size) {
33
+ this._head = head;
34
+ this._tail = tail;
35
+ this._shift = shift;
36
+ this._size = size;
37
+ }
38
+ get size() {
39
+ return this._size;
40
+ }
41
+ isEmpty() {
42
+ return this._tail.isEmpty();
43
+ }
44
+ forEach(callback) {
45
+ Iterable.forEach(this, callback);
46
+ }
47
+ map(mapper) {
48
+ let index = 0;
49
+ const tail = this._tail.map((value) => mapper(value, index++));
50
+ const head = this._head.map((value) => mapper(value, index++));
51
+ return new List(head, tail, this._shift, this._size);
52
+ }
53
+ apply(mapper) {
54
+ return mapper.flatMap((mapper) => this.map(mapper));
55
+ }
56
+ flatMap(mapper) {
57
+ return this.reduce((list, value, index) => list.concat(mapper(value, index)), List.empty());
58
+ }
59
+ flatten() {
60
+ return this.flatMap((list) => list);
61
+ }
62
+ reduce(reducer, accumulator) {
63
+ return Iterable.reduce(this, reducer, accumulator);
64
+ }
65
+ reduceWhile(predicate, reducer, accumulator) {
66
+ return Iterable.reduceWhile(this, predicate, reducer, accumulator);
67
+ }
68
+ reduceUntil(predicate, reducer, accumulator) {
69
+ return Iterable.reduceUntil(this, predicate, reducer, accumulator);
70
+ }
71
+ filter(predicate) {
72
+ return List.from(Iterable.filter(this, predicate));
73
+ }
74
+ reject(predicate) {
75
+ return this.filter(not(predicate));
76
+ }
77
+ find(predicate) {
78
+ return Iterable.find(this, predicate);
79
+ }
80
+ includes(value) {
81
+ return Iterable.includes(this, value);
82
+ }
83
+ collect(mapper) {
84
+ return List.from(Iterable.collect(this, mapper));
85
+ }
86
+ collectFirst(mapper) {
87
+ return Iterable.collectFirst(this, mapper);
88
+ }
89
+ some(predicate) {
90
+ return Iterable.some(this, predicate);
91
+ }
92
+ none(predicate) {
93
+ return Iterable.none(this, predicate);
94
+ }
95
+ every(predicate) {
96
+ return Iterable.every(this, predicate);
97
+ }
98
+ count(predicate) {
99
+ return Iterable.count(this, predicate);
100
+ }
101
+ distinct() {
102
+ let seen = Set.empty();
103
+ let list = List.empty();
104
+ for (const value of this) {
105
+ if (seen.has(value)) {
106
+ continue;
107
+ }
108
+ seen = seen.add(value);
109
+ list = list.append(value);
110
+ }
111
+ return list;
112
+ }
113
+ get(index) {
114
+ if (index < 0 || index >= this._size || this._tail.isEmpty()) {
115
+ return None;
116
+ }
117
+ const offset = this._size - this._tail.values.length;
118
+ let value;
119
+ if (index < offset) {
120
+ value = this._head.get(index, this._shift - Node.Bits);
121
+ }
122
+ else {
123
+ value = this._tail.get(index - offset);
124
+ }
125
+ return value;
126
+ }
127
+ has(index) {
128
+ return index >= 0 && index < this._size;
129
+ }
130
+ set(index, value) {
131
+ if (index < 0 || index >= this._size || this._tail.isEmpty()) {
132
+ return this;
133
+ }
134
+ const offset = this._size - this._tail.values.length;
135
+ let head = this._head;
136
+ let tail = this._tail;
137
+ if (index < offset) {
138
+ if (head.isEmpty()) {
139
+ return this;
140
+ }
141
+ head = head.set(index, value, this._shift);
142
+ if (head === this._head) {
143
+ return this;
144
+ }
145
+ }
146
+ else {
147
+ tail = tail.set(index - offset, value);
148
+ if (tail === this._tail) {
149
+ return this;
150
+ }
151
+ }
152
+ return new List(head, tail, this._shift, this._size);
153
+ }
154
+ insert(index, value) {
155
+ if (index < 0 || index > this.size) {
156
+ return this;
157
+ }
158
+ if (index === 0) {
159
+ return this.prepend(value);
160
+ }
161
+ if (index === this.size) {
162
+ return this.append(value);
163
+ }
164
+ return List.from(Iterable.concat(Iterable.take(this, index), Iterable.from([value]), Iterable.skip(this, index)));
165
+ }
166
+ append(value) {
167
+ return this._push(value);
168
+ }
169
+ prepend(value) {
170
+ return List.of(value).concat(this);
171
+ }
172
+ concat(iterable) {
173
+ return Iterable.reduce(iterable, (list, value) => list._push(value), this);
174
+ }
175
+ subtract(iterable) {
176
+ return List.from(Iterable.subtract(this, iterable));
177
+ }
178
+ intersect(iterable) {
179
+ return List.from(Iterable.intersect(this, iterable));
180
+ }
181
+ tee(callback, ...args) {
182
+ callback(this, ...args);
183
+ return this;
184
+ }
185
+ zip(iterable) {
186
+ return List.from(Iterable.zip(this, iterable));
187
+ }
188
+ first() {
189
+ return this._tail.isEmpty() ? None : Option.of(this._tail.values[0]);
190
+ }
191
+ last() {
192
+ return Iterable.last(this);
193
+ }
194
+ take(count) {
195
+ return List.from(Iterable.take(this, count));
196
+ }
197
+ takeWhile(predicate) {
198
+ return List.from(Iterable.takeWhile(this, predicate));
199
+ }
200
+ takeUntil(predicate) {
201
+ return this.takeWhile(not(predicate));
202
+ }
203
+ takeLast(count = 1) {
204
+ return List.from(Iterable.takeLast(this, count));
205
+ }
206
+ takeLastWhile(predicate) {
207
+ return List.from(Iterable.takeLastWhile(this, predicate));
208
+ }
209
+ takeLastUntil(predicate) {
210
+ return this.takeLastWhile(not(predicate));
211
+ }
212
+ skip(count) {
213
+ return List.from(Iterable.skip(this, count));
214
+ }
215
+ skipWhile(predicate) {
216
+ return List.from(Iterable.skipWhile(this, predicate));
217
+ }
218
+ skipUntil(predicate) {
219
+ return this.skipWhile(not(predicate));
220
+ }
221
+ skipLast(count = 1) {
222
+ let list = this;
223
+ while (count-- > 0) {
224
+ list = list._pop();
225
+ }
226
+ return list;
227
+ }
228
+ skipLastWhile(predicate) {
229
+ return List.from(Iterable.skipLastWhile(this, predicate));
230
+ }
231
+ skipLastUntil(predicate) {
232
+ return this.skipLastWhile(not(predicate));
233
+ }
234
+ trim(predicate) {
235
+ return this.trimLeading(predicate).trimTrailing(predicate);
236
+ }
237
+ trimLeading(predicate) {
238
+ return this.skipWhile(predicate);
239
+ }
240
+ trimTrailing(predicate) {
241
+ return this.skipLastWhile(predicate);
242
+ }
243
+ rest() {
244
+ return this.skip(1);
245
+ }
246
+ slice(start, end) {
247
+ return List.from(Iterable.slice(this, start, end));
248
+ }
249
+ reverse() {
250
+ return List.from(Iterable.reverse(this));
251
+ }
252
+ join(separator) {
253
+ return Iterable.join(this, separator);
254
+ }
255
+ sort() {
256
+ return this.sortWith(compareComparable);
257
+ }
258
+ sortWith(comparer) {
259
+ return List.from(Iterable.sortWith(this, comparer));
260
+ }
261
+ compare(iterable) {
262
+ return this.compareWith(iterable, compareComparable);
263
+ }
264
+ compareWith(iterable, comparer) {
265
+ return Iterable.compareWith(this, iterable, comparer);
266
+ }
267
+ groupBy(grouper) {
268
+ return this.reduce((groups, value) => {
269
+ const group = grouper(value);
270
+ return groups.set(group, groups
271
+ .get(group)
272
+ .getOrElse(() => List.empty())
273
+ ._push(value));
274
+ }, Map.empty());
275
+ }
276
+ equals(value) {
277
+ return (value instanceof List &&
278
+ value._size === this._size &&
279
+ value._head.equals(this._head) &&
280
+ value._tail.equals(this._tail));
281
+ }
282
+ hash(hash) {
283
+ for (const value of this) {
284
+ hash.writeUnknown(value);
285
+ }
286
+ hash.writeUint32(this._size);
287
+ }
288
+ *[Symbol.iterator]() {
289
+ yield* this._head;
290
+ yield* this._tail;
291
+ }
292
+ toArray() {
293
+ return [...this];
294
+ }
295
+ toJSON(options) {
296
+ return this.toArray().map((value) => Serializable.toJSON(value, options));
297
+ }
298
+ toString() {
299
+ const values = this.join(", ");
300
+ return `List [${values === "" ? "" : ` ${values} `}]`;
301
+ }
302
+ _push(value) {
303
+ // If no tail exists yet, this means that the list is empty. We therefore
304
+ // create a new tail with the pushed value. As the current list is empty,
305
+ // it won't have a head. As such, there's no need to pass the head along.
306
+ //
307
+ // In: List { head: Empty, tail: Empty }
308
+ // Out: List { head: Empty, tail: Leaf(value) }
309
+ //
310
+ if (this._tail.isEmpty()) {
311
+ return new List(Empty, Leaf.of([value]), 0, 1);
312
+ }
313
+ // If the tail has capacity for another value, we concatenate the pushed
314
+ // value onto the current tail. The current list may or may not have a head,
315
+ // so we pass the head along as-is.
316
+ //
317
+ // In: List { head, tail }
318
+ // Out: List { head, tail: Leaf(...tail, value) }
319
+ //
320
+ if (this._tail.hasCapacity()) {
321
+ return new List(this._head, Leaf.of([...this._tail.values, value]), this._shift, this._size + 1);
322
+ }
323
+ // If the tail does not have capacity for another value, we need to add it
324
+ // to the head to make room for a new tail. If the current list does not
325
+ // have a head, we use the current tail as the new head and create a new
326
+ // tail with the pushed value.
327
+ //
328
+ // In: List { head: Empty, tail }
329
+ // Out: List { head: tail, tail: Leaf(value) }
330
+ //
331
+ if (this._head.isEmpty()) {
332
+ return new List(this._tail, Leaf.of([value]), this._shift + Node.Bits, this._size + 1);
333
+ }
334
+ const index = this._size - Node.Capacity;
335
+ let head = this._head;
336
+ let shift = this._shift;
337
+ // If the head has overflown, we need to split it which in turn increases
338
+ // the depth of the list.
339
+ if (head.isLeaf() || index === Node.overflow(shift)) {
340
+ head = Branch.of([head]);
341
+ shift += Node.Bits;
342
+ }
343
+ else {
344
+ head = head.clone();
345
+ }
346
+ let prev = head;
347
+ let level = shift - Node.Bits;
348
+ // We now add the tail to the head in order to make room for a new tail.
349
+ while (level > 0) {
350
+ const i = Node.fragment(index, level);
351
+ level -= Node.Bits;
352
+ const next = prev.nodes[i];
353
+ if (next === undefined) {
354
+ if (level === 0) {
355
+ prev.nodes[i] = this._tail;
356
+ }
357
+ else {
358
+ prev.nodes[i] = prev = Branch.empty();
359
+ }
360
+ }
361
+ else {
362
+ prev.nodes[i] = prev = next.clone();
363
+ }
364
+ }
365
+ // With the current tail inserted into the new head, we can now make a new
366
+ // tail with the pushed value. Do note that the spread syntax is only used
367
+ // for illustrative purposes here; the tail is actually inserted in the
368
+ // rightmost branch of the head.
369
+ //
370
+ // In: List { head, tail }
371
+ // Out: List { head: Branch(...head, ...tail), tail: Leaf(value) }
372
+ //
373
+ return new List(head, Leaf.of([value]), shift, this._size + 1);
374
+ }
375
+ _pop() {
376
+ // If the list has no tail then it is empty. We therefore return the list
377
+ // itself as the pop has no effect.
378
+ if (this._tail.isEmpty()) {
379
+ return this;
380
+ }
381
+ // If the list has a size of 1 then the result of the popping its last
382
+ // element will be an empty list.
383
+ //
384
+ // In: List { head: Empty, tail: Leaf(value) }
385
+ // Out: List { head: Empty, tail: Empty }
386
+ //
387
+ if (this._size === 1) {
388
+ return List.empty();
389
+ }
390
+ // If the tail has more than one element, it will have a non-zero size after
391
+ // popping the last element. We can therefore get away with removing the
392
+ // last element from the tail and reuse the head.
393
+ //
394
+ // In: List { head, tail: Leaf(...tail, value) }
395
+ // Out: List { head, tail }
396
+ //
397
+ if (this._tail.values.length > 1) {
398
+ return new List(this._head, Leaf.of(this._tail.values.slice(0, this._tail.values.length - 1)), this._shift, this._size - 1);
399
+ }
400
+ if (this._head.isLeaf() || this._head.isEmpty()) {
401
+ return new List(Empty, this._head, this._shift - Node.Bits, this._size - 1);
402
+ }
403
+ let head = this._head.clone();
404
+ let tail = this._tail;
405
+ let shift = this._shift;
406
+ const index = this._size - Node.Capacity - 1;
407
+ let prev = head;
408
+ let level = shift - Node.Bits;
409
+ // We now remove the rightmost leaf of the head as this will be used as the
410
+ // new tail.
411
+ while (level > 0) {
412
+ const fragment = Node.fragment(index, level);
413
+ level -= Node.Bits;
414
+ const next = prev.nodes[fragment];
415
+ // Once we reach the rightmost leaf node, remove it as it will be used as
416
+ // the new tail.
417
+ if (next.isLeaf()) {
418
+ prev.nodes.pop();
419
+ tail = next;
420
+ }
421
+ else {
422
+ prev = prev.nodes[fragment] = next.clone();
423
+ }
424
+ }
425
+ // If the head has underflown, we unwrap its first child and use that as the
426
+ // new head which in turn decreases the depth of the list. If the head is a
427
+ // leaf node, we instead set the new head to null.
428
+ if (index === Node.underflow(shift)) {
429
+ head = head.nodes[0];
430
+ shift -= Node.Bits;
431
+ }
432
+ // With the rightmost branch of the head removed, we can now use it as the
433
+ // new tail and discard the old. Do note that the spread syntax is only used
434
+ // for illustrative purposes here; the tail is actually removed from the
435
+ // rightmost branch of the head.
436
+ //
437
+ // In: List { head: Branch(...head, tail), tail: Leaf(value) }
438
+ // Out: List { head, tail }
439
+ //
440
+ return new List(head, tail, shift, this._size - 1);
441
+ }
442
+ }
443
+ /**
444
+ * @public
445
+ */
446
+ (function (List) {
447
+ function isList(value) {
448
+ return value instanceof List;
449
+ }
450
+ List.isList = isList;
451
+ function from(iterable) {
452
+ if (isList(iterable)) {
453
+ return iterable;
454
+ }
455
+ if (Array.isArray(iterable)) {
456
+ return fromArray(iterable);
457
+ }
458
+ return fromIterable(iterable);
459
+ }
460
+ List.from = from;
461
+ function fromArray(array) {
462
+ const size = array.length;
463
+ // Fast path: The array fits within the tail.
464
+ if (size <= Node.Capacity) {
465
+ return List.of(...array);
466
+ }
467
+ return Array.reduce(array, (list, value) => list.append(value), List.empty());
468
+ }
469
+ List.fromArray = fromArray;
470
+ function fromIterable(iterable) {
471
+ return Iterable.reduce(iterable, (list, value) => list.append(value), List.empty());
472
+ }
473
+ List.fromIterable = fromIterable;
474
+ })(List || (List = {}));
475
+ //# sourceMappingURL=list.js.map
package/dist/node.d.ts ADDED
@@ -0,0 +1,70 @@
1
+ import { Equatable } from "@siteimprove/alfa-equatable";
2
+ import type { Functor } from "@siteimprove/alfa-functor";
3
+ import type { Iterable } from "@siteimprove/alfa-iterable";
4
+ import type { Mapper } from "@siteimprove/alfa-mapper";
5
+ import { Option } from "@siteimprove/alfa-option";
6
+ /**
7
+ * @internal
8
+ */
9
+ export interface Node<T> extends Functor<T>, Iterable<T>, Equatable {
10
+ isEmpty(): this is Empty;
11
+ isLeaf(): this is Leaf<T>;
12
+ get(index: number, shift: number): Option<T>;
13
+ set(index: number, value: T, shift: number): Node<T>;
14
+ map<U>(mapper: Mapper<T, U>): Node<U>;
15
+ }
16
+ /**
17
+ * @internal
18
+ */
19
+ export declare namespace Node {
20
+ const Bits = 5;
21
+ const Capacity: number;
22
+ function fragment(index: number, shift: number): number;
23
+ function overflow(shift: number): number;
24
+ function underflow(shift: number): number;
25
+ }
26
+ /**
27
+ * @internal
28
+ */
29
+ export interface Empty extends Node<never> {
30
+ }
31
+ /**
32
+ * @internal
33
+ */
34
+ export declare const Empty: Empty;
35
+ /**
36
+ * @internal
37
+ */
38
+ export declare class Leaf<T> implements Node<T> {
39
+ static of<T>(values: Array<T>): Leaf<T>;
40
+ private readonly _values;
41
+ private constructor();
42
+ get values(): Array<T>;
43
+ isEmpty(): this is Empty;
44
+ isLeaf(): this is Leaf<T>;
45
+ hasCapacity(): boolean;
46
+ get(index: number): Option<T>;
47
+ set(index: number, value: T): Leaf<T>;
48
+ map<U>(mapper: Mapper<T, U>): Leaf<U>;
49
+ equals(value: unknown): value is this;
50
+ [Symbol.iterator](): Iterator<T>;
51
+ }
52
+ /**
53
+ * @internal
54
+ */
55
+ export declare class Branch<T> implements Node<T> {
56
+ static of<T>(nodes: Array<Branch<T> | Leaf<T>>): Branch<T>;
57
+ static empty<T>(): Branch<T>;
58
+ private readonly _nodes;
59
+ private constructor();
60
+ get nodes(): Array<Branch<T> | Leaf<T>>;
61
+ isEmpty(): this is Empty;
62
+ isLeaf(): this is Leaf<T>;
63
+ clone(): Branch<T>;
64
+ get(index: number, shift: number): Option<T>;
65
+ set(index: number, value: T, shift: number): Branch<T>;
66
+ map<U>(mapper: Mapper<T, U>): Branch<U>;
67
+ equals(value: unknown): value is this;
68
+ [Symbol.iterator](): Iterator<T>;
69
+ }
70
+ //# sourceMappingURL=node.d.ts.map
package/dist/node.js ADDED
@@ -0,0 +1,151 @@
1
+ import { Bits } from "@siteimprove/alfa-bits";
2
+ import { Equatable } from "@siteimprove/alfa-equatable";
3
+ import { None, Option } from "@siteimprove/alfa-option";
4
+ const { bit, take, skip } = Bits;
5
+ /**
6
+ * @internal
7
+ */
8
+ export var Node;
9
+ (function (Node) {
10
+ Node.Bits = 5;
11
+ Node.Capacity = bit(Node.Bits);
12
+ function fragment(index, shift) {
13
+ return take(skip(index, shift), Node.Bits);
14
+ }
15
+ Node.fragment = fragment;
16
+ function overflow(shift) {
17
+ return Node.Capacity << (shift - Node.Bits);
18
+ }
19
+ Node.overflow = overflow;
20
+ function underflow(shift) {
21
+ return Node.Capacity << (shift - Node.Bits * 2);
22
+ }
23
+ Node.underflow = underflow;
24
+ })(Node || (Node = {}));
25
+ /**
26
+ * @internal
27
+ */
28
+ export const Empty = new (class Empty {
29
+ isEmpty() {
30
+ return true;
31
+ }
32
+ isLeaf() {
33
+ return false;
34
+ }
35
+ get() {
36
+ return None;
37
+ }
38
+ set() {
39
+ return this;
40
+ }
41
+ map() {
42
+ return this;
43
+ }
44
+ equals(value) {
45
+ return value instanceof Empty;
46
+ }
47
+ *[Symbol.iterator]() { }
48
+ })();
49
+ /**
50
+ * @internal
51
+ */
52
+ export class Leaf {
53
+ static of(values) {
54
+ return new Leaf(values);
55
+ }
56
+ _values;
57
+ constructor(values) {
58
+ this._values = values;
59
+ }
60
+ get values() {
61
+ return this._values;
62
+ }
63
+ isEmpty() {
64
+ return false;
65
+ }
66
+ isLeaf() {
67
+ return true;
68
+ }
69
+ hasCapacity() {
70
+ return this._values.length < Node.Capacity;
71
+ }
72
+ get(index) {
73
+ const fragment = take(index, Node.Bits);
74
+ return Option.of(this._values[fragment]);
75
+ }
76
+ set(index, value) {
77
+ const fragment = take(index, Node.Bits);
78
+ if (Equatable.equals(value, this._values[fragment])) {
79
+ return this;
80
+ }
81
+ const values = this._values.slice(0);
82
+ values[fragment] = value;
83
+ return Leaf.of(values);
84
+ }
85
+ map(mapper) {
86
+ return Leaf.of(this._values.map(mapper));
87
+ }
88
+ equals(value) {
89
+ return (value instanceof Leaf &&
90
+ value._values.length === this._values.length &&
91
+ value._values.every((value, i) => Equatable.equals(value, this._values[i])));
92
+ }
93
+ *[Symbol.iterator]() {
94
+ yield* this._values;
95
+ }
96
+ }
97
+ /**
98
+ * @internal
99
+ */
100
+ export class Branch {
101
+ static of(nodes) {
102
+ return new Branch(nodes);
103
+ }
104
+ static empty() {
105
+ return new Branch([]);
106
+ }
107
+ _nodes;
108
+ constructor(nodes) {
109
+ this._nodes = nodes;
110
+ }
111
+ get nodes() {
112
+ return this._nodes;
113
+ }
114
+ isEmpty() {
115
+ return false;
116
+ }
117
+ isLeaf() {
118
+ return false;
119
+ }
120
+ clone() {
121
+ return Branch.of(this._nodes.slice(0));
122
+ }
123
+ get(index, shift) {
124
+ const fragment = Node.fragment(index, shift);
125
+ return this._nodes[fragment].get(index, shift - Node.Bits);
126
+ }
127
+ set(index, value, shift) {
128
+ const fragment = Node.fragment(index, shift);
129
+ const node = this._nodes[fragment].set(index, value, shift - Node.Bits);
130
+ if (node === this._nodes[fragment]) {
131
+ return this;
132
+ }
133
+ const nodes = this._nodes.slice(0);
134
+ nodes[fragment] = node;
135
+ return Branch.of(nodes);
136
+ }
137
+ map(mapper) {
138
+ return Branch.of(this._nodes.map((node) => node.map(mapper)));
139
+ }
140
+ equals(value) {
141
+ return (value instanceof Branch &&
142
+ value._nodes.length === this._nodes.length &&
143
+ value._nodes.every((node, i) => node.equals(this._nodes[i])));
144
+ }
145
+ *[Symbol.iterator]() {
146
+ for (const node of this._nodes) {
147
+ yield* node;
148
+ }
149
+ }
150
+ }
151
+ //# sourceMappingURL=node.js.map
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "$schema": "http://json.schemastore.org/package",
3
+ "name": "@siteimprove/alfa-list",
4
+ "homepage": "https://alfa.siteimprove.com",
5
+ "version": "0.89.5",
6
+ "license": "MIT",
7
+ "description": "An implementation of an immutable list structure, based on a bit-partitioned vector trie",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "github:Siteimprove/alfa",
11
+ "directory": "packages/alfa-list"
12
+ },
13
+ "bugs": "https://github.com/siteimprove/alfa/issues",
14
+ "engines": {
15
+ "node": ">=20.0.0"
16
+ },
17
+ "type": "module",
18
+ "main": "dist/index.js",
19
+ "types": "dist/index.d.ts",
20
+ "files": [
21
+ "dist/**/*.js",
22
+ "dist/**/*.d.ts"
23
+ ],
24
+ "dependencies": {
25
+ "@siteimprove/alfa-array": "^0.89.5",
26
+ "@siteimprove/alfa-bits": "^0.89.5",
27
+ "@siteimprove/alfa-callback": "^0.89.5",
28
+ "@siteimprove/alfa-collection": "^0.89.5",
29
+ "@siteimprove/alfa-comparable": "^0.89.5",
30
+ "@siteimprove/alfa-equatable": "^0.89.5",
31
+ "@siteimprove/alfa-functor": "^0.89.5",
32
+ "@siteimprove/alfa-hash": "^0.89.5",
33
+ "@siteimprove/alfa-iterable": "^0.89.5",
34
+ "@siteimprove/alfa-json": "^0.89.5",
35
+ "@siteimprove/alfa-map": "^0.89.5",
36
+ "@siteimprove/alfa-mapper": "^0.89.5",
37
+ "@siteimprove/alfa-option": "^0.89.5",
38
+ "@siteimprove/alfa-predicate": "^0.89.5",
39
+ "@siteimprove/alfa-reducer": "^0.89.5",
40
+ "@siteimprove/alfa-refinement": "^0.89.5",
41
+ "@siteimprove/alfa-set": "^0.89.5"
42
+ },
43
+ "devDependencies": {
44
+ "@siteimprove/alfa-test": "^0.89.5"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public",
48
+ "registry": "https://npm.pkg.github.com/"
49
+ }
50
+ }