@siteimprove/alfa-map 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-map
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 "./map.js";
2
+ export * from "./node.js";
3
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./map.js";
2
+ export * from "./node.js";
3
+ //# sourceMappingURL=index.js.map
package/dist/map.d.ts ADDED
@@ -0,0 +1,104 @@
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 type { Hash } from "@siteimprove/alfa-hash";
5
+ import { Iterable } from "@siteimprove/alfa-iterable";
6
+ import { Serializable } from "@siteimprove/alfa-json";
7
+ import type { Mapper } from "@siteimprove/alfa-mapper";
8
+ import type { Option } from "@siteimprove/alfa-option";
9
+ import { Predicate } from "@siteimprove/alfa-predicate";
10
+ import type { Reducer } from "@siteimprove/alfa-reducer";
11
+ import type { Refinement } from "@siteimprove/alfa-refinement";
12
+ /**
13
+ * @public
14
+ */
15
+ export declare class Map<K, V> implements Collection.Keyed<K, V> {
16
+ static of<K, V>(...entries: Array<readonly [K, V]>): Map<K, V>;
17
+ private static _empty;
18
+ static empty<K = never, V = never>(): Map<K, V>;
19
+ private readonly _root;
20
+ private readonly _size;
21
+ private constructor();
22
+ get size(): number;
23
+ isEmpty(): this is Map<K, never>;
24
+ forEach(callback: Callback<V, void, [key: K]>): void;
25
+ map<U>(mapper: Mapper<V, U, [key: K]>): Map<K, U>;
26
+ /**
27
+ * Apply a map of functions to each corresponding value of this map.
28
+ *
29
+ * @remarks
30
+ * Keys without a corresponding function or value are dropped from the
31
+ * resulting map.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * Map.of(["a", 1], ["b", 2])
36
+ * .apply(Map.of(["a", (x) => x + 1], ["b", (x) => x * 2]))
37
+ * .toArray();
38
+ * // => [["a", 2], ["b", 4]]
39
+ * ```
40
+ */
41
+ apply<U>(mapper: Map<K, Mapper<V, U>>): Map<K, U>;
42
+ /**
43
+ * @remarks
44
+ * As the order of maps is undefined, it is also undefined which keys are
45
+ * kept when duplicate keys are encountered.
46
+ */
47
+ flatMap<L, U>(mapper: Mapper<V, Map<L, U>, [key: K]>): Map<L, U>;
48
+ /**
49
+ * @remarks
50
+ * As the order of maps is undefined, it is also undefined which keys are
51
+ * kept when duplicate keys are encountered.
52
+ */
53
+ flatten<K, V>(this: Map<K, Map<K, V>>): Map<K, V>;
54
+ reduce<R>(reducer: Reducer<V, R, [key: K]>, accumulator: R): R;
55
+ filter<U extends V>(refinement: Refinement<V, U, [key: K]>): Map<K, U>;
56
+ filter(predicate: Predicate<V, [key: K]>): Map<K, V>;
57
+ reject<U extends V>(refinement: Refinement<V, U, [key: K]>): Map<K, Exclude<V, U>>;
58
+ reject(predicate: Predicate<V, [key: K]>): Map<K, V>;
59
+ find<U extends V>(refinement: Refinement<V, U, [key: K]>): Option<U>;
60
+ find(predicate: Predicate<V, [key: K]>): Option<V>;
61
+ includes(value: V): boolean;
62
+ collect<U>(mapper: Mapper<V, Option<U>, [key: K]>): Map<K, U>;
63
+ collectFirst<U>(mapper: Mapper<V, Option<U>, [key: K]>): Option<U>;
64
+ some(predicate: Predicate<V, [key: K]>): boolean;
65
+ none(predicate: Predicate<V, [key: K]>): boolean;
66
+ every(predicate: Predicate<V, [key: K]>): boolean;
67
+ count(predicate: Predicate<V, [key: K]>): number;
68
+ /**
69
+ * @remarks
70
+ * As the order of maps is undefined, it is also undefined which keys are
71
+ * kept when duplicate values are encountered.
72
+ */
73
+ distinct(): Map<K, V>;
74
+ get(key: K): Option<V>;
75
+ has(key: K): boolean;
76
+ set(key: K, value: V): Map<K, V>;
77
+ delete(key: K): Map<K, V>;
78
+ concat(iterable: Iterable<readonly [K, V]>): Map<K, V>;
79
+ subtract(iterable: Iterable<readonly [K, V]>): Map<K, V>;
80
+ intersect(iterable: Iterable<readonly [K, V]>): Map<K, V>;
81
+ tee<A extends Array<unknown> = []>(callback: Callback<this, void, [...args: A]>, ...args: A): this;
82
+ equals<K, V>(value: Map<K, V>): boolean;
83
+ equals(value: unknown): value is this;
84
+ hash(hash: Hash): void;
85
+ keys(): Iterable<K>;
86
+ values(): Iterable<V>;
87
+ iterator(): Iterator<[K, V]>;
88
+ [Symbol.iterator](): Iterator<[K, V]>;
89
+ toArray(): Array<[K, V]>;
90
+ toJSON(options?: Serializable.Options): Map.JSON<K, V>;
91
+ toString(): string;
92
+ }
93
+ /**
94
+ * @public
95
+ */
96
+ export declare namespace Map {
97
+ type JSON<K, V> = Collection.Keyed.JSON<K, V>;
98
+ function isMap<K, V>(value: Iterable<readonly [K, V]>): value is Map<K, V>;
99
+ function isMap<K, V>(value: unknown): value is Map<K, V>;
100
+ function from<K, V>(iterable: Iterable<readonly [K, V]>): Map<K, V>;
101
+ function fromArray<K, V>(array: ReadonlyArray<readonly [K, V]>): Map<K, V>;
102
+ function fromIterable<K, V>(iterable: Iterable<readonly [K, V]>): Map<K, V>;
103
+ }
104
+ //# sourceMappingURL=map.d.ts.map
package/dist/map.js ADDED
@@ -0,0 +1,227 @@
1
+ import { Array } from "@siteimprove/alfa-array";
2
+ import { FNV } from "@siteimprove/alfa-fnv";
3
+ import { Iterable } from "@siteimprove/alfa-iterable";
4
+ import { Serializable } from "@siteimprove/alfa-json";
5
+ import { Predicate } from "@siteimprove/alfa-predicate";
6
+ import { Empty } from "./node.js";
7
+ const { not } = Predicate;
8
+ /**
9
+ * @public
10
+ */
11
+ export class Map {
12
+ static of(...entries) {
13
+ return entries.reduce((map, [key, value]) => map.set(key, value), Map.empty());
14
+ }
15
+ static _empty = new Map(Empty, 0);
16
+ static empty() {
17
+ return this._empty;
18
+ }
19
+ _root;
20
+ _size;
21
+ constructor(root, size) {
22
+ this._root = root;
23
+ this._size = size;
24
+ }
25
+ get size() {
26
+ return this._size;
27
+ }
28
+ isEmpty() {
29
+ return this._size === 0;
30
+ }
31
+ forEach(callback) {
32
+ Iterable.forEach(this, ([key, value]) => callback(value, key));
33
+ }
34
+ map(mapper) {
35
+ return new Map(this._root.map(mapper), this._size);
36
+ }
37
+ /**
38
+ * Apply a map of functions to each corresponding value of this map.
39
+ *
40
+ * @remarks
41
+ * Keys without a corresponding function or value are dropped from the
42
+ * resulting map.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * Map.of(["a", 1], ["b", 2])
47
+ * .apply(Map.of(["a", (x) => x + 1], ["b", (x) => x * 2]))
48
+ * .toArray();
49
+ * // => [["a", 2], ["b", 4]]
50
+ * ```
51
+ */
52
+ apply(mapper) {
53
+ return this.collect((value, key) => mapper.get(key).map((mapper) => mapper(value)));
54
+ }
55
+ /**
56
+ * @remarks
57
+ * As the order of maps is undefined, it is also undefined which keys are
58
+ * kept when duplicate keys are encountered.
59
+ */
60
+ flatMap(mapper) {
61
+ return this.reduce((map, value, key) => map.concat(mapper(value, key)), Map.empty());
62
+ }
63
+ /**
64
+ * @remarks
65
+ * As the order of maps is undefined, it is also undefined which keys are
66
+ * kept when duplicate keys are encountered.
67
+ */
68
+ flatten() {
69
+ return this.flatMap((map) => map);
70
+ }
71
+ reduce(reducer, accumulator) {
72
+ return Iterable.reduce(this, (accumulator, [key, value]) => reducer(accumulator, value, key), accumulator);
73
+ }
74
+ filter(predicate) {
75
+ return this.reduce((map, value, key) => (predicate(value, key) ? map.set(key, value) : map), Map.empty());
76
+ }
77
+ reject(predicate) {
78
+ return this.filter(not(predicate));
79
+ }
80
+ find(predicate) {
81
+ return Iterable.find(this, ([key, value]) => predicate(value, key)).map(([, value]) => value);
82
+ }
83
+ includes(value) {
84
+ return Iterable.includes(this.values(), value);
85
+ }
86
+ collect(mapper) {
87
+ return Map.from(Iterable.collect(this, ([key, value]) => mapper(value, key).map((value) => [key, value])));
88
+ }
89
+ collectFirst(mapper) {
90
+ return Iterable.collectFirst(this, ([key, value]) => mapper(value, key));
91
+ }
92
+ some(predicate) {
93
+ return Iterable.some(this, ([key, value]) => predicate(value, key));
94
+ }
95
+ none(predicate) {
96
+ return Iterable.none(this, ([key, value]) => predicate(value, key));
97
+ }
98
+ every(predicate) {
99
+ return Iterable.every(this, ([key, value]) => predicate(value, key));
100
+ }
101
+ count(predicate) {
102
+ return Iterable.count(this, ([key, value]) => predicate(value, key));
103
+ }
104
+ /**
105
+ * @remarks
106
+ * As the order of maps is undefined, it is also undefined which keys are
107
+ * kept when duplicate values are encountered.
108
+ */
109
+ distinct() {
110
+ let seen = Map.empty();
111
+ // We optimize for the case where there are more distinct values than there
112
+ // are duplicate values by starting with the current map and removing
113
+ // duplicates as we find them.
114
+ let map = this;
115
+ for (const [key, value] of map) {
116
+ if (seen.has(value)) {
117
+ map = map.delete(key);
118
+ }
119
+ else {
120
+ seen = seen.set(value, value);
121
+ }
122
+ }
123
+ return map;
124
+ }
125
+ get(key) {
126
+ return this._root.get(key, hash(key), 0);
127
+ }
128
+ has(key) {
129
+ return this.get(key).isSome();
130
+ }
131
+ set(key, value) {
132
+ const { result: root, status } = this._root.set(key, value, hash(key), 0);
133
+ if (status === "unchanged") {
134
+ return this;
135
+ }
136
+ return new Map(root, this._size + (status === "updated" ? 0 : 1));
137
+ }
138
+ delete(key) {
139
+ const { result: root, status } = this._root.delete(key, hash(key), 0);
140
+ if (status === "unchanged") {
141
+ return this;
142
+ }
143
+ return new Map(root, this._size - 1);
144
+ }
145
+ concat(iterable) {
146
+ return Iterable.reduce(iterable, (map, [key, value]) => map.set(key, value), this);
147
+ }
148
+ subtract(iterable) {
149
+ return Iterable.reduce(iterable, (map, [key]) => map.delete(key), this);
150
+ }
151
+ intersect(iterable) {
152
+ return Map.fromIterable(Iterable.filter(iterable, ([key]) => this.has(key)));
153
+ }
154
+ tee(callback, ...args) {
155
+ callback(this, ...args);
156
+ return this;
157
+ }
158
+ equals(value) {
159
+ return (value instanceof Map &&
160
+ value._size === this._size &&
161
+ value._root.equals(this._root));
162
+ }
163
+ hash(hash) {
164
+ for (const [key, value] of this) {
165
+ hash.writeUnknown(key).writeUnknown(value);
166
+ }
167
+ hash.writeUint32(this._size);
168
+ }
169
+ keys() {
170
+ return Iterable.map(this._root, (entry) => entry[0]);
171
+ }
172
+ values() {
173
+ return Iterable.map(this._root, (entry) => entry[1]);
174
+ }
175
+ *iterator() {
176
+ yield* this._root;
177
+ }
178
+ [Symbol.iterator]() {
179
+ return this.iterator();
180
+ }
181
+ toArray() {
182
+ return [...this];
183
+ }
184
+ toJSON(options) {
185
+ return this.toArray().map(([key, value]) => [
186
+ Serializable.toJSON(key, options),
187
+ Serializable.toJSON(value, options),
188
+ ]);
189
+ }
190
+ toString() {
191
+ const entries = this.toArray()
192
+ .map(([key, value]) => `${key} => ${value}`)
193
+ .join(", ");
194
+ return `Map {${entries === "" ? "" : ` ${entries} `}}`;
195
+ }
196
+ }
197
+ /**
198
+ * @public
199
+ */
200
+ (function (Map) {
201
+ function isMap(value) {
202
+ return value instanceof Map;
203
+ }
204
+ Map.isMap = isMap;
205
+ function from(iterable) {
206
+ if (isMap(iterable)) {
207
+ return iterable;
208
+ }
209
+ if (Array.isArray(iterable)) {
210
+ return fromArray(iterable);
211
+ }
212
+ return fromIterable(iterable);
213
+ }
214
+ Map.from = from;
215
+ function fromArray(array) {
216
+ return Array.reduce(array, (map, [key, value]) => map.set(key, value), Map.empty());
217
+ }
218
+ Map.fromArray = fromArray;
219
+ function fromIterable(iterable) {
220
+ return Iterable.reduce(iterable, (map, [key, value]) => map.set(key, value), Map.empty());
221
+ }
222
+ Map.fromIterable = fromIterable;
223
+ })(Map || (Map = {}));
224
+ function hash(key) {
225
+ return FNV.empty().writeUnknown(key).finish();
226
+ }
227
+ //# sourceMappingURL=map.js.map
package/dist/node.d.ts ADDED
@@ -0,0 +1,106 @@
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
+ import { Status } from "./status.js";
7
+ /**
8
+ * Maps are stored as an hash-table of keys.
9
+ * The hash-table is stored as a tree where each internal node is a partial
10
+ * match of the hashes of its subtree.
11
+ *
12
+ * Nodes in the tree can be:
13
+ * * empty;
14
+ * * a Leaf, containing one single key;
15
+ * * a Collision, containing several keys with the same hash, this is
16
+ * effectively a leaf of the tree, even though it actually has several Leaf
17
+ * children (but no other kind);
18
+ * * a Sparse, which is an internal node. Sparses have masks and all hashes in
19
+ * this subtree share the same mask (partial hash collision). The matching of
20
+ * masks is done with a shift, which essentially take slices of n (=5) bits
21
+ * of the hash. The shift is automatically increased when looking down the
22
+ * tree, hence the same mask cannot be used at another level of a tree.
23
+ */
24
+ /**
25
+ * @internal
26
+ */
27
+ export interface Node<K, V> extends Functor<V>, Iterable<[K, V]>, Equatable {
28
+ isEmpty(): this is Empty;
29
+ isLeaf(): this is Leaf<K, V>;
30
+ get(key: K, hash: number, shift: number): Option<V>;
31
+ set(key: K, value: V, hash: number, shift: number): Status<Node<K, V>>;
32
+ delete(key: K, hash: number, shift: number): Status<Node<K, V>>;
33
+ map<U>(mapper: Mapper<V, U, [K]>): Node<K, U>;
34
+ }
35
+ /**
36
+ * @internal
37
+ */
38
+ export declare namespace Node {
39
+ const Bits = 5;
40
+ function fragment(hash: number, shift: number): number;
41
+ function index(fragment: number, mask: number): number;
42
+ }
43
+ /**
44
+ * @internal
45
+ */
46
+ export interface Empty extends Node<never, never> {
47
+ }
48
+ /**
49
+ * @internal
50
+ */
51
+ export declare const Empty: Empty;
52
+ /**
53
+ * @internal
54
+ */
55
+ export declare class Leaf<K, V> implements Node<K, V> {
56
+ static of<K, V>(hash: number, key: K, value: V): Leaf<K, V>;
57
+ private readonly _hash;
58
+ private readonly _key;
59
+ private readonly _value;
60
+ private constructor();
61
+ get key(): K;
62
+ get value(): V;
63
+ isEmpty(): this is Empty;
64
+ isLeaf(): this is Leaf<K, V>;
65
+ get(key: K, hash: number, shift: number): Option<V>;
66
+ set(key: K, value: V, hash: number, shift: number): Status<Node<K, V>>;
67
+ delete(key: K, hash: number): Status<Node<K, V>>;
68
+ map<U>(mapper: Mapper<V, U, [K]>): Leaf<K, U>;
69
+ equals(value: unknown): value is this;
70
+ [Symbol.iterator](): Iterator<[K, V]>;
71
+ }
72
+ /**
73
+ * @internal
74
+ */
75
+ export declare class Collision<K, V> implements Node<K, V> {
76
+ static of<K, V>(hash: number, nodes: Array<Leaf<K, V>>): Collision<K, V>;
77
+ private readonly _hash;
78
+ private readonly _nodes;
79
+ private constructor();
80
+ isEmpty(): this is Empty;
81
+ isLeaf(): this is Leaf<K, V>;
82
+ get(key: K, hash: number, shift: number): Option<V>;
83
+ set(key: K, value: V, hash: number, shift: number): Status<Node<K, V>>;
84
+ delete(key: K, hash: number): Status<Node<K, V>>;
85
+ map<U>(mapper: Mapper<V, U, [K]>): Collision<K, U>;
86
+ equals(value: unknown): value is this;
87
+ [Symbol.iterator](): Iterator<[K, V]>;
88
+ }
89
+ /**
90
+ * @internal
91
+ */
92
+ export declare class Sparse<K, V> implements Node<K, V> {
93
+ static of<K, V>(mask: number, nodes: Array<Node<K, V>>): Sparse<K, V>;
94
+ private readonly _mask;
95
+ private readonly _nodes;
96
+ private constructor();
97
+ isEmpty(): this is Empty;
98
+ isLeaf(): this is Leaf<K, V>;
99
+ get(key: K, hash: number, shift: number): Option<V>;
100
+ set(key: K, value: V, hash: number, shift: number): Status<Node<K, V>>;
101
+ delete(key: K, hash: number, shift: number): Status<Node<K, V>>;
102
+ map<U>(mapper: Mapper<V, U, [K]>): Sparse<K, U>;
103
+ equals(value: unknown): value is this;
104
+ [Symbol.iterator](): Iterator<[K, V]>;
105
+ }
106
+ //# sourceMappingURL=node.d.ts.map
package/dist/node.js ADDED
@@ -0,0 +1,311 @@
1
+ import { Bits } from "@siteimprove/alfa-bits";
2
+ import { Equatable } from "@siteimprove/alfa-equatable";
3
+ import { None, Option } from "@siteimprove/alfa-option";
4
+ import { Status } from "./status.js";
5
+ const { bit, take, skip, test, set, clear, popCount } = Bits;
6
+ /**
7
+ * @internal
8
+ */
9
+ export var Node;
10
+ (function (Node) {
11
+ Node.Bits = 5;
12
+ function fragment(hash, shift) {
13
+ return take(skip(hash, shift), Node.Bits);
14
+ }
15
+ Node.fragment = fragment;
16
+ function index(fragment, mask) {
17
+ return popCount(take(mask, fragment));
18
+ }
19
+ Node.index = index;
20
+ })(Node || (Node = {}));
21
+ /**
22
+ * @internal
23
+ */
24
+ export const Empty = new (class Empty {
25
+ isEmpty() {
26
+ return true;
27
+ }
28
+ isLeaf() {
29
+ return false;
30
+ }
31
+ get() {
32
+ return None;
33
+ }
34
+ set(key, value, hash) {
35
+ return Status.created(Leaf.of(hash, key, value));
36
+ }
37
+ delete() {
38
+ return Status.unchanged(this);
39
+ }
40
+ map() {
41
+ return this;
42
+ }
43
+ equals(value) {
44
+ return value instanceof Empty;
45
+ }
46
+ *[Symbol.iterator]() { }
47
+ })();
48
+ /**
49
+ * @internal
50
+ */
51
+ export class Leaf {
52
+ static of(hash, key, value) {
53
+ return new Leaf(hash, key, value);
54
+ }
55
+ _hash;
56
+ _key;
57
+ _value;
58
+ constructor(hash, key, value) {
59
+ this._hash = hash;
60
+ this._key = key;
61
+ this._value = value;
62
+ }
63
+ get key() {
64
+ return this._key;
65
+ }
66
+ get value() {
67
+ return this._value;
68
+ }
69
+ isEmpty() {
70
+ return false;
71
+ }
72
+ isLeaf() {
73
+ return true;
74
+ }
75
+ get(key, hash, shift) {
76
+ return hash === this._hash && Equatable.equals(key, this._key)
77
+ ? Option.of(this._value)
78
+ : None;
79
+ }
80
+ set(key, value, hash, shift) {
81
+ if (hash === this._hash) {
82
+ if (Equatable.equals(key, this._key)) {
83
+ if (Equatable.equals(value, this._value)) {
84
+ return Status.unchanged(this);
85
+ }
86
+ return Status.updated(Leaf.of(hash, key, value));
87
+ }
88
+ return Status.created(Collision.of(hash, [this, Leaf.of(hash, key, value)]));
89
+ }
90
+ const fragment = Node.fragment(this._hash, shift);
91
+ return Sparse.of(bit(fragment), [this]).set(key, value, hash, shift);
92
+ }
93
+ delete(key, hash) {
94
+ return hash === this._hash && Equatable.equals(key, this._key)
95
+ ? Status.deleted(Empty)
96
+ : Status.unchanged(this);
97
+ }
98
+ map(mapper) {
99
+ return Leaf.of(this._hash, this._key, mapper(this._value, this._key));
100
+ }
101
+ equals(value) {
102
+ return (value instanceof Leaf &&
103
+ value._hash === this._hash &&
104
+ Equatable.equals(value._key, this._key) &&
105
+ Equatable.equals(value._value, this._value));
106
+ }
107
+ *[Symbol.iterator]() {
108
+ yield [this._key, this._value];
109
+ }
110
+ }
111
+ /**
112
+ * @internal
113
+ */
114
+ export class Collision {
115
+ static of(hash, nodes) {
116
+ return new Collision(hash, nodes);
117
+ }
118
+ _hash;
119
+ _nodes;
120
+ constructor(hash, nodes) {
121
+ this._hash = hash;
122
+ this._nodes = nodes;
123
+ }
124
+ isEmpty() {
125
+ return false;
126
+ }
127
+ isLeaf() {
128
+ return false;
129
+ }
130
+ get(key, hash, shift) {
131
+ if (hash === this._hash) {
132
+ for (const node of this._nodes) {
133
+ const value = node.get(key, hash, shift);
134
+ if (value.isSome()) {
135
+ return value;
136
+ }
137
+ }
138
+ }
139
+ return None;
140
+ }
141
+ set(key, value, hash, shift) {
142
+ if (hash === this._hash) {
143
+ for (let i = 0, n = this._nodes.length; i < n; i++) {
144
+ const node = this._nodes[i];
145
+ if (Equatable.equals(key, node.key)) {
146
+ if (Equatable.equals(value, node.value)) {
147
+ return Status.unchanged(this);
148
+ }
149
+ return Status.updated(Collision.of(this._hash, replace(this._nodes, i, Leaf.of(hash, key, value))));
150
+ }
151
+ }
152
+ return Status.created(Collision.of(this._hash, this._nodes.concat(Leaf.of(hash, key, value))));
153
+ }
154
+ const fragment = Node.fragment(this._hash, shift);
155
+ return Sparse.of(bit(fragment), [this]).set(key, value, hash, shift);
156
+ }
157
+ delete(key, hash) {
158
+ if (hash === this._hash) {
159
+ for (let i = 0, n = this._nodes.length; i < n; i++) {
160
+ const node = this._nodes[i];
161
+ if (Equatable.equals(key, node.key)) {
162
+ const nodes = remove(this._nodes, i);
163
+ if (nodes.length === 1) {
164
+ // We just deleted the penultimate Leaf of the Collision, so we can
165
+ // remove the Collision and only keep the remaining Leaf.
166
+ return Status.deleted(nodes[0]);
167
+ }
168
+ return Status.deleted(Collision.of(this._hash, nodes));
169
+ }
170
+ }
171
+ }
172
+ return Status.unchanged(this);
173
+ }
174
+ map(mapper) {
175
+ return Collision.of(this._hash, this._nodes.map((node) => node.map(mapper)));
176
+ }
177
+ equals(value) {
178
+ return (value instanceof Collision &&
179
+ value._hash === this._hash &&
180
+ value._nodes.length === this._nodes.length &&
181
+ value._nodes.every((node, i) => node.equals(this._nodes[i])));
182
+ }
183
+ *[Symbol.iterator]() {
184
+ for (const node of this._nodes) {
185
+ yield* node;
186
+ }
187
+ }
188
+ }
189
+ /**
190
+ * @internal
191
+ */
192
+ export class Sparse {
193
+ static of(mask, nodes) {
194
+ return new Sparse(mask, nodes);
195
+ }
196
+ _mask;
197
+ _nodes;
198
+ constructor(mask, nodes) {
199
+ this._mask = mask;
200
+ this._nodes = nodes;
201
+ }
202
+ isEmpty() {
203
+ return false;
204
+ }
205
+ isLeaf() {
206
+ return false;
207
+ }
208
+ get(key, hash, shift) {
209
+ const fragment = Node.fragment(hash, shift);
210
+ if (test(this._mask, fragment)) {
211
+ const index = Node.index(fragment, this._mask);
212
+ return this._nodes[index].get(key, hash, shift + Node.Bits);
213
+ }
214
+ return None;
215
+ }
216
+ set(key, value, hash, shift) {
217
+ const fragment = Node.fragment(hash, shift);
218
+ const index = Node.index(fragment, this._mask);
219
+ if (test(this._mask, fragment)) {
220
+ const { result: node, status } = this._nodes[index].set(key, value, hash, shift + Node.Bits);
221
+ if (status === "unchanged") {
222
+ return Status.unchanged(this);
223
+ }
224
+ const sparse = Sparse.of(this._mask, replace(this._nodes, index, node));
225
+ switch (status) {
226
+ case "created":
227
+ return Status.created(sparse);
228
+ case "updated":
229
+ default:
230
+ return Status.updated(sparse);
231
+ }
232
+ }
233
+ return Status.created(Sparse.of(set(this._mask, fragment), insert(this._nodes, index, Leaf.of(hash, key, value))));
234
+ }
235
+ delete(key, hash, shift) {
236
+ const fragment = Node.fragment(hash, shift);
237
+ if (test(this._mask, fragment)) {
238
+ const index = Node.index(fragment, this._mask);
239
+ const { result: node, status } = this._nodes[index].delete(key, hash, shift + Node.Bits);
240
+ if (status === "unchanged") {
241
+ return Status.unchanged(this);
242
+ }
243
+ if (node.isEmpty()) {
244
+ const nodes = remove(this._nodes, index);
245
+ if (nodes.length === 1) {
246
+ // We deleted the penultimate child of the Sparse, we may be able to
247
+ // simplify the tree.
248
+ if (nodes[0].isLeaf() || nodes[0] instanceof Collision) {
249
+ // The last child is leaf-like, hence hashes will be fully matched
250
+ // against its key(s) and we can remove the current Sparse
251
+ return Status.deleted(nodes[0]);
252
+ }
253
+ // Otherwise, the last child is a Sparse. We can't simply collapse the
254
+ // tree by removing the current Sparse, since it will cause the child
255
+ // mask to be tested with the wrong shift (its depth in the tree would
256
+ // be different).
257
+ // We could do some further optimisations (e.g., if the child's
258
+ // children are all leaf-like, we could instead delete the lone child
259
+ // and connect directly to the grandchildren). This is, however,
260
+ // getting hairy to make all cases working fine, and we assume this
261
+ // kind of situation is not too frequent. So we pay the price of
262
+ // keeping a non-branching Sparse until we need to optimise that.
263
+ }
264
+ return Status.deleted(Sparse.of(clear(this._mask, fragment), nodes));
265
+ }
266
+ return Status.deleted(Sparse.of(this._mask, replace(this._nodes, index, node)));
267
+ }
268
+ return Status.unchanged(this);
269
+ }
270
+ map(mapper) {
271
+ return Sparse.of(this._mask, this._nodes.map((node) => node.map(mapper)));
272
+ }
273
+ equals(value) {
274
+ return (value instanceof Sparse &&
275
+ value._mask === this._mask &&
276
+ value._nodes.length === this._nodes.length &&
277
+ value._nodes.every((node, i) => node.equals(this._nodes[i])));
278
+ }
279
+ *[Symbol.iterator]() {
280
+ for (const node of this._nodes) {
281
+ yield* node;
282
+ }
283
+ }
284
+ }
285
+ function insert(array, index, value) {
286
+ const result = new Array(array.length + 1);
287
+ result[index] = value;
288
+ for (let i = 0, n = index; i < n; i++) {
289
+ result[i] = array[i];
290
+ }
291
+ for (let i = index, n = array.length; i < n; i++) {
292
+ result[i + 1] = array[i];
293
+ }
294
+ return result;
295
+ }
296
+ function remove(array, index) {
297
+ const result = new Array(array.length - 1);
298
+ for (let i = 0, n = index; i < n; i++) {
299
+ result[i] = array[i];
300
+ }
301
+ for (let i = index, n = result.length; i < n; i++) {
302
+ result[i] = array[i + 1];
303
+ }
304
+ return result;
305
+ }
306
+ function replace(array, index, value) {
307
+ const result = array.slice(0);
308
+ result[index] = value;
309
+ return result;
310
+ }
311
+ //# sourceMappingURL=node.js.map
@@ -0,0 +1,41 @@
1
+ /**
2
+ * @internal
3
+ */
4
+ export type Status<T> = Status.Created<T> | Status.Updated<T> | Status.Deleted<T> | Status.Unchanged<T>;
5
+ /**
6
+ * @internal
7
+ */
8
+ export declare namespace Status {
9
+ abstract class Status<T> {
10
+ protected readonly _result: T;
11
+ protected constructor(result: T);
12
+ get result(): T;
13
+ abstract get status(): string;
14
+ }
15
+ export class Created<T> extends Status<T> {
16
+ static of<T>(result: T): Created<T>;
17
+ private constructor();
18
+ get status(): "created";
19
+ }
20
+ export const created: typeof Created.of;
21
+ export class Updated<T> extends Status<T> {
22
+ static of<T>(result: T): Updated<T>;
23
+ private constructor();
24
+ get status(): "updated";
25
+ }
26
+ export const updated: typeof Updated.of;
27
+ export class Deleted<T> extends Status<T> {
28
+ static of<T>(result: T): Deleted<T>;
29
+ private constructor();
30
+ get status(): "deleted";
31
+ }
32
+ export const deleted: typeof Deleted.of;
33
+ export class Unchanged<T> extends Status<T> {
34
+ static of<T>(result: T): Unchanged<T>;
35
+ private constructor();
36
+ get status(): "unchanged";
37
+ }
38
+ export const unchanged: typeof Unchanged.of;
39
+ export {};
40
+ }
41
+ //# sourceMappingURL=status.d.ts.map
package/dist/status.js ADDED
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @internal
3
+ */
4
+ export var Status;
5
+ (function (Status_1) {
6
+ class Status {
7
+ _result;
8
+ constructor(result) {
9
+ this._result = result;
10
+ }
11
+ get result() {
12
+ return this._result;
13
+ }
14
+ }
15
+ class Created extends Status {
16
+ static of(result) {
17
+ return new Created(result);
18
+ }
19
+ constructor(result) {
20
+ super(result);
21
+ }
22
+ get status() {
23
+ return "created";
24
+ }
25
+ }
26
+ Status_1.Created = Created;
27
+ Status_1.created = Created.of;
28
+ class Updated extends Status {
29
+ static of(result) {
30
+ return new Updated(result);
31
+ }
32
+ constructor(result) {
33
+ super(result);
34
+ }
35
+ get status() {
36
+ return "updated";
37
+ }
38
+ }
39
+ Status_1.Updated = Updated;
40
+ Status_1.updated = Updated.of;
41
+ class Deleted extends Status {
42
+ static of(result) {
43
+ return new Deleted(result);
44
+ }
45
+ constructor(result) {
46
+ super(result);
47
+ }
48
+ get status() {
49
+ return "deleted";
50
+ }
51
+ }
52
+ Status_1.Deleted = Deleted;
53
+ Status_1.deleted = Deleted.of;
54
+ class Unchanged extends Status {
55
+ static of(result) {
56
+ return new Unchanged(result);
57
+ }
58
+ constructor(result) {
59
+ super(result);
60
+ }
61
+ get status() {
62
+ return "unchanged";
63
+ }
64
+ }
65
+ Status_1.Unchanged = Unchanged;
66
+ Status_1.unchanged = Unchanged.of;
67
+ })(Status || (Status = {}));
68
+ //# sourceMappingURL=status.js.map
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "$schema": "http://json.schemastore.org/package",
3
+ "name": "@siteimprove/alfa-map",
4
+ "homepage": "https://alfa.siteimprove.com",
5
+ "version": "0.89.5",
6
+ "license": "MIT",
7
+ "description": "An implementation of an immutable map structure, based on a hash array mapped trie",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "github:Siteimprove/alfa",
11
+ "directory": "packages/alfa-map"
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-equatable": "^0.89.5",
30
+ "@siteimprove/alfa-fnv": "^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-mapper": "^0.89.5",
36
+ "@siteimprove/alfa-option": "^0.89.5",
37
+ "@siteimprove/alfa-predicate": "^0.89.5",
38
+ "@siteimprove/alfa-reducer": "^0.89.5",
39
+ "@siteimprove/alfa-refinement": "^0.89.5"
40
+ },
41
+ "devDependencies": {
42
+ "@siteimprove/alfa-test": "^0.89.5"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public",
46
+ "registry": "https://npm.pkg.github.com/"
47
+ }
48
+ }