@weborigami/async-tree 0.5.7 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/browser.js +1 -1
- package/index.ts +31 -35
- package/main.js +1 -2
- package/package.json +4 -7
- package/shared.js +77 -12
- package/src/Tree.js +8 -2
- package/src/drivers/AsyncMap.js +210 -0
- package/src/drivers/{BrowserFileTree.js → BrowserFileMap.js} +36 -27
- package/src/drivers/{calendarTree.js → CalendarMap.js} +81 -62
- package/src/drivers/ConstantMap.js +30 -0
- package/src/drivers/DeepObjectMap.js +27 -0
- package/src/drivers/{ExplorableSiteTree.js → ExplorableSiteMap.js} +7 -7
- package/src/drivers/FileMap.js +245 -0
- package/src/drivers/{FunctionTree.js → FunctionMap.js} +19 -22
- package/src/drivers/ObjectMap.js +139 -0
- package/src/drivers/SetMap.js +13 -0
- package/src/drivers/{SiteTree.js → SiteMap.js} +16 -17
- package/src/drivers/SyncMap.js +245 -0
- package/src/jsonKeys.d.ts +2 -2
- package/src/jsonKeys.js +6 -5
- package/src/operations/addNextPrevious.js +35 -36
- package/src/operations/assign.js +30 -21
- package/src/operations/cache.js +29 -35
- package/src/operations/cachedKeyFunctions.js +1 -1
- package/src/operations/calendar.js +5 -0
- package/src/operations/clear.js +13 -12
- package/src/operations/constant.js +5 -0
- package/src/operations/deepEntries.js +23 -0
- package/src/operations/deepMap.js +9 -9
- package/src/operations/deepMerge.js +36 -25
- package/src/operations/deepReverse.js +23 -16
- package/src/operations/deepTake.js +7 -7
- package/src/operations/deepText.js +4 -4
- package/src/operations/deepValues.js +3 -6
- package/src/operations/deepValuesIterator.js +11 -11
- package/src/operations/delete.js +8 -12
- package/src/operations/entries.js +17 -10
- package/src/operations/filter.js +9 -7
- package/src/operations/first.js +12 -10
- package/src/operations/forEach.js +10 -13
- package/src/operations/from.js +31 -39
- package/src/operations/globKeys.js +22 -17
- package/src/operations/group.js +2 -2
- package/src/operations/groupBy.js +24 -22
- package/src/operations/has.js +7 -9
- package/src/operations/indent.js +2 -2
- package/src/operations/inners.js +19 -15
- package/src/operations/invokeFunctions.js +22 -10
- package/src/operations/isAsyncMutableTree.js +5 -12
- package/src/operations/isAsyncTree.js +5 -20
- package/src/operations/isMap.js +39 -0
- package/src/operations/isMaplike.js +34 -0
- package/src/operations/isReadOnlyMap.js +14 -0
- package/src/operations/isTraversable.js +3 -3
- package/src/operations/isTreelike.js +5 -30
- package/src/operations/json.js +4 -12
- package/src/operations/keys.js +17 -8
- package/src/operations/length.js +9 -8
- package/src/operations/map.js +27 -30
- package/src/operations/mapExtension.js +20 -16
- package/src/operations/mapReduce.js +22 -17
- package/src/operations/mask.js +31 -22
- package/src/operations/match.js +13 -9
- package/src/operations/merge.js +43 -35
- package/src/operations/paginate.js +26 -18
- package/src/operations/parent.js +7 -7
- package/src/operations/paths.js +8 -8
- package/src/operations/plain.js +6 -6
- package/src/operations/regExpKeys.js +21 -12
- package/src/operations/reverse.js +21 -15
- package/src/operations/root.js +6 -5
- package/src/operations/scope.js +31 -26
- package/src/operations/shuffle.js +23 -16
- package/src/operations/size.js +13 -0
- package/src/operations/sort.js +55 -40
- package/src/operations/sync.js +21 -0
- package/src/operations/take.js +23 -11
- package/src/operations/text.js +4 -4
- package/src/operations/toFunction.js +7 -7
- package/src/operations/traverse.js +4 -4
- package/src/operations/traverseOrThrow.js +13 -9
- package/src/operations/traversePath.js +2 -2
- package/src/operations/values.js +18 -9
- package/src/operations/withKeys.js +22 -16
- package/src/symbols.js +1 -0
- package/src/utilities/castArraylike.js +10 -2
- package/src/utilities/getMapArgument.js +38 -0
- package/src/utilities/getParent.js +2 -2
- package/src/utilities/isStringlike.js +7 -5
- package/src/utilities/setParent.js +7 -7
- package/src/utilities/toFunction.js +2 -2
- package/src/utilities/toPlainValue.js +22 -18
- package/test/SampleAsyncMap.js +34 -0
- package/test/browser/assert.js +20 -0
- package/test/browser/index.html +54 -21
- package/test/drivers/AsyncMap.test.js +119 -0
- package/test/drivers/{BrowserFileTree.test.js → BrowserFileMap.test.js} +42 -23
- package/test/drivers/{calendarTree.test.js → CalendarMap.test.js} +17 -19
- package/test/drivers/ConstantMap.test.js +15 -0
- package/test/drivers/DeepObjectMap.test.js +36 -0
- package/test/drivers/{ExplorableSiteTree.test.js → ExplorableSiteMap.test.js} +29 -14
- package/test/drivers/FileMap.test.js +185 -0
- package/test/drivers/FunctionMap.test.js +56 -0
- package/test/drivers/ObjectMap.test.js +166 -0
- package/test/drivers/SetMap.test.js +35 -0
- package/test/drivers/{SiteTree.test.js → SiteMap.test.js} +14 -10
- package/test/drivers/SyncMap.test.js +321 -0
- package/test/jsonKeys.test.js +2 -2
- package/test/operations/addNextPrevious.test.js +3 -2
- package/test/operations/assign.test.js +30 -35
- package/test/operations/cache.test.js +8 -6
- package/test/operations/cachedKeyFunctions.test.js +6 -5
- package/test/operations/clear.test.js +6 -27
- package/test/operations/deepEntries.test.js +32 -0
- package/test/operations/deepMerge.test.js +6 -5
- package/test/operations/deepReverse.test.js +2 -2
- package/test/operations/deepTake.test.js +2 -2
- package/test/operations/deepText.test.js +4 -4
- package/test/operations/deepValuesIterator.test.js +2 -2
- package/test/operations/delete.test.js +2 -2
- package/test/operations/extensionKeyFunctions.test.js +6 -5
- package/test/operations/filter.test.js +3 -3
- package/test/operations/from.test.js +23 -31
- package/test/operations/globKeys.test.js +9 -9
- package/test/operations/groupBy.test.js +6 -5
- package/test/operations/inners.test.js +4 -4
- package/test/operations/invokeFunctions.test.js +2 -2
- package/test/operations/isMap.test.js +15 -0
- package/test/operations/isMaplike.test.js +15 -0
- package/test/operations/json.test.js +2 -2
- package/test/operations/keys.test.js +16 -3
- package/test/operations/map.test.js +20 -18
- package/test/operations/mapExtension.test.js +6 -6
- package/test/operations/mapReduce.test.js +2 -2
- package/test/operations/mask.test.js +4 -3
- package/test/operations/match.test.js +2 -2
- package/test/operations/merge.test.js +15 -11
- package/test/operations/paginate.test.js +5 -5
- package/test/operations/parent.test.js +3 -3
- package/test/operations/paths.test.js +6 -6
- package/test/operations/plain.test.js +8 -8
- package/test/operations/regExpKeys.test.js +12 -11
- package/test/operations/reverse.test.js +4 -3
- package/test/operations/scope.test.js +6 -5
- package/test/operations/shuffle.test.js +3 -2
- package/test/operations/sort.test.js +7 -10
- package/test/operations/sync.test.js +43 -0
- package/test/operations/take.test.js +2 -2
- package/test/operations/toFunction.test.js +2 -2
- package/test/operations/traverse.test.js +4 -5
- package/test/operations/withKeys.test.js +2 -2
- package/test/utilities/setParent.test.js +6 -6
- package/test/utilities/toFunction.test.js +2 -2
- package/test/utilities/toPlainValue.test.js +51 -12
- package/src/drivers/DeepMapTree.js +0 -23
- package/src/drivers/DeepObjectTree.js +0 -18
- package/src/drivers/DeferredTree.js +0 -81
- package/src/drivers/FileTree.js +0 -276
- package/src/drivers/MapTree.js +0 -70
- package/src/drivers/ObjectTree.js +0 -158
- package/src/drivers/SetTree.js +0 -34
- package/src/drivers/constantTree.js +0 -19
- package/src/drivers/limitConcurrency.js +0 -63
- package/src/internal.js +0 -16
- package/src/utilities/getTreeArgument.js +0 -43
- package/test/drivers/DeepMapTree.test.js +0 -17
- package/test/drivers/DeepObjectTree.test.js +0 -35
- package/test/drivers/DeferredTree.test.js +0 -22
- package/test/drivers/FileTree.test.js +0 -192
- package/test/drivers/FunctionTree.test.js +0 -46
- package/test/drivers/MapTree.test.js +0 -59
- package/test/drivers/ObjectTree.test.js +0 -163
- package/test/drivers/SetTree.test.js +0 -44
- package/test/drivers/constantTree.test.js +0 -13
- package/test/drivers/limitConcurrency.test.js +0 -41
- package/test/operations/isAsyncMutableTree.test.js +0 -17
- package/test/operations/isAsyncTree.test.js +0 -26
- package/test/operations/isTreelike.test.js +0 -13
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import ObjectMap from "../../src/drivers/ObjectMap.js";
|
|
4
|
+
import * as symbols from "../../src/symbols.js";
|
|
5
|
+
|
|
6
|
+
describe("ObjectMap", () => {
|
|
7
|
+
test("can get the keys of the tree", () => {
|
|
8
|
+
const fixture = createFixture();
|
|
9
|
+
assert.deepEqual(Array.from(fixture.keys()), [
|
|
10
|
+
"Alice.md",
|
|
11
|
+
"Bob.md",
|
|
12
|
+
"Carol.md",
|
|
13
|
+
]);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("can get the value for a key", () => {
|
|
17
|
+
const map = createFixture();
|
|
18
|
+
const alice = map.get("Alice.md");
|
|
19
|
+
assert.equal(alice, "Hello, **Alice**.");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("getting an unsupported key returns undefined", () => {
|
|
23
|
+
const map = createFixture();
|
|
24
|
+
assert.equal(map.get("xyz"), undefined);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("getting a null/undefined key throws an exception", async () => {
|
|
28
|
+
const map = createFixture();
|
|
29
|
+
await assert.rejects(async () => {
|
|
30
|
+
map.get(null);
|
|
31
|
+
});
|
|
32
|
+
await assert.rejects(async () => {
|
|
33
|
+
map.get(undefined);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("can set a value", () => {
|
|
38
|
+
const map = new ObjectMap({
|
|
39
|
+
a: 1,
|
|
40
|
+
b: 2,
|
|
41
|
+
c: 3,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Update existing key
|
|
45
|
+
map.set("a", 4);
|
|
46
|
+
|
|
47
|
+
// Delete key
|
|
48
|
+
map.delete("b");
|
|
49
|
+
|
|
50
|
+
// Overwrite key with trailing slash
|
|
51
|
+
map.set("c/", {});
|
|
52
|
+
|
|
53
|
+
// New key
|
|
54
|
+
map.set("d", 5);
|
|
55
|
+
|
|
56
|
+
const entries = Array.from(map.entries());
|
|
57
|
+
assert.deepEqual(entries, [
|
|
58
|
+
["a", 4],
|
|
59
|
+
["c/", {}],
|
|
60
|
+
["d", 5],
|
|
61
|
+
]);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("can wrap a class instance", () => {
|
|
65
|
+
class Foo {
|
|
66
|
+
constructor() {
|
|
67
|
+
this.a = 1;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get prop() {
|
|
71
|
+
return this._prop;
|
|
72
|
+
}
|
|
73
|
+
set prop(prop) {
|
|
74
|
+
this._prop = prop;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
class Bar extends Foo {
|
|
78
|
+
method() {}
|
|
79
|
+
}
|
|
80
|
+
const bar = new Bar();
|
|
81
|
+
/** @type {any} */ (bar).extra = "Hello";
|
|
82
|
+
|
|
83
|
+
const map = new ObjectMap(bar);
|
|
84
|
+
const entries = Array.from(map.entries());
|
|
85
|
+
assert.deepEqual(entries, [
|
|
86
|
+
["a", 1],
|
|
87
|
+
["extra", "Hello"],
|
|
88
|
+
["prop", undefined],
|
|
89
|
+
]);
|
|
90
|
+
assert.equal(map.get("a"), 1);
|
|
91
|
+
map.set("prop", "Goodbye");
|
|
92
|
+
assert.equal(bar.prop, "Goodbye");
|
|
93
|
+
assert.equal(map.get("prop"), "Goodbye");
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("sets parent symbol on subobjects", () => {
|
|
97
|
+
const map = new ObjectMap({
|
|
98
|
+
sub: {},
|
|
99
|
+
});
|
|
100
|
+
const sub = map.get("sub");
|
|
101
|
+
assert.equal(sub[symbols.parent], map);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("sets parent on subtrees", () => {
|
|
105
|
+
const map = new ObjectMap({
|
|
106
|
+
a: 1,
|
|
107
|
+
more: new ObjectMap({
|
|
108
|
+
b: 2,
|
|
109
|
+
}),
|
|
110
|
+
});
|
|
111
|
+
const more = map.get("more");
|
|
112
|
+
assert.equal(more.parent, map);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("adds trailing slashes to keys for subtrees", () => {
|
|
116
|
+
const map = new ObjectMap({
|
|
117
|
+
a1: 1,
|
|
118
|
+
a2: new ObjectMap({
|
|
119
|
+
b1: 2,
|
|
120
|
+
}),
|
|
121
|
+
a3: 3,
|
|
122
|
+
a4: new ObjectMap({
|
|
123
|
+
b2: 4,
|
|
124
|
+
}),
|
|
125
|
+
});
|
|
126
|
+
const keys = Array.from(map.keys());
|
|
127
|
+
assert.deepEqual(keys, ["a1", "a2/", "a3", "a4/"]);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("can retrieve values with optional trailing slash", () => {
|
|
131
|
+
const subMap = {
|
|
132
|
+
get(key) {},
|
|
133
|
+
keys() {},
|
|
134
|
+
};
|
|
135
|
+
const map = new ObjectMap({
|
|
136
|
+
a: 1,
|
|
137
|
+
subMap,
|
|
138
|
+
});
|
|
139
|
+
assert.equal(map.get("a"), 1);
|
|
140
|
+
assert.equal(map.get("a/"), 1);
|
|
141
|
+
assert.equal(map.get("subMap"), subMap);
|
|
142
|
+
assert.equal(map.get("subMap/"), subMap);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("method on an object is bound to the object", () => {
|
|
146
|
+
const n = new Number(123);
|
|
147
|
+
const map = new ObjectMap(n);
|
|
148
|
+
const method = map.get("toString");
|
|
149
|
+
assert.equal(method(), "123");
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("defers to symbols.keys for keys if defined", () => {
|
|
153
|
+
const map = new ObjectMap({
|
|
154
|
+
[symbols.keys]: () => ["a", "b", "c"],
|
|
155
|
+
});
|
|
156
|
+
assert.deepEqual(Array.from(map.keys()), ["a", "b", "c"]);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
function createFixture() {
|
|
161
|
+
return new ObjectMap({
|
|
162
|
+
"Alice.md": "Hello, **Alice**.",
|
|
163
|
+
"Bob.md": "Hello, **Bob**.",
|
|
164
|
+
"Carol.md": "Hello, **Carol**.",
|
|
165
|
+
});
|
|
166
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import SetMap from "../../src/drivers/SetMap.js";
|
|
4
|
+
|
|
5
|
+
describe("SetMap", () => {
|
|
6
|
+
test("can get the keys of the map", async () => {
|
|
7
|
+
const set = new Set(["a", "b", "c"]);
|
|
8
|
+
const fixture = new SetMap(set);
|
|
9
|
+
assert.deepEqual(Array.from(await fixture.keys()), ["a", "b", "c"]);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("can get the value for a key", async () => {
|
|
13
|
+
const set = new Set(["a", "b", "c"]);
|
|
14
|
+
const fixture = new SetMap(set);
|
|
15
|
+
const a = await fixture.get("a");
|
|
16
|
+
assert.equal(a, "a");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("getting an unsupported key returns undefined", async () => {
|
|
20
|
+
const set = new Set(["a", "b", "c"]);
|
|
21
|
+
const fixture = new SetMap(set);
|
|
22
|
+
assert.equal(await fixture.get("d"), undefined);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("getting a null/undefined key throws an exception", async () => {
|
|
26
|
+
const set = new Set(["a", "b", "c"]);
|
|
27
|
+
const fixture = new SetMap(set);
|
|
28
|
+
await assert.rejects(async () => {
|
|
29
|
+
await fixture.get(null);
|
|
30
|
+
});
|
|
31
|
+
await assert.rejects(async () => {
|
|
32
|
+
await fixture.get(undefined);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { beforeEach, describe, mock, test } from "node:test";
|
|
3
|
-
import
|
|
3
|
+
import SiteMap from "../../src/drivers/SiteMap.js";
|
|
4
4
|
|
|
5
5
|
const textDecoder = new TextDecoder();
|
|
6
6
|
const textEncoder = new TextEncoder();
|
|
@@ -27,38 +27,42 @@ const mockResponses = {
|
|
|
27
27
|
},
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
describe("
|
|
30
|
+
describe("SiteMap", () => {
|
|
31
31
|
beforeEach(() => {
|
|
32
32
|
mock.method(global, "fetch", mockFetch);
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
test("returns an empty array as the keys of a tree", async () => {
|
|
36
|
-
const fixture = new
|
|
37
|
-
const keys =
|
|
38
|
-
|
|
36
|
+
const fixture = new SiteMap(mockHost);
|
|
37
|
+
const keys = [];
|
|
38
|
+
for await (const key of fixture.keys()) {
|
|
39
|
+
keys.push(key);
|
|
40
|
+
}
|
|
41
|
+
assert.deepEqual(keys, []);
|
|
39
42
|
});
|
|
40
43
|
|
|
41
44
|
test("can get a plain value for a key", async () => {
|
|
42
|
-
const fixture = new
|
|
45
|
+
const fixture = new SiteMap(mockHost);
|
|
46
|
+
/** @type {any} */
|
|
43
47
|
const arrayBuffer = await fixture.get("index.html");
|
|
44
48
|
const text = textDecoder.decode(arrayBuffer);
|
|
45
49
|
assert.equal(text, "Home page");
|
|
46
50
|
});
|
|
47
51
|
|
|
48
52
|
test("immediately return a new tree for a key with a trailing slash", async () => {
|
|
49
|
-
const fixture = new
|
|
53
|
+
const fixture = new SiteMap(mockHost);
|
|
50
54
|
const about = await fixture.get("about/");
|
|
51
|
-
assert(about instanceof
|
|
55
|
+
assert(about instanceof SiteMap);
|
|
52
56
|
assert.equal(about.href, "https://mock/about/");
|
|
53
57
|
});
|
|
54
58
|
|
|
55
59
|
test("getting an unsupported key returns undefined", async () => {
|
|
56
|
-
const fixture = new
|
|
60
|
+
const fixture = new SiteMap(mockHost);
|
|
57
61
|
assert.equal(await fixture.get("xyz"), undefined);
|
|
58
62
|
});
|
|
59
63
|
|
|
60
64
|
test("getting a null/undefined key throws an exception", async () => {
|
|
61
|
-
const fixture = new
|
|
65
|
+
const fixture = new SiteMap(mockHost);
|
|
62
66
|
await assert.rejects(async () => {
|
|
63
67
|
await fixture.get(null);
|
|
64
68
|
});
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import SyncMap from "../../src/drivers/SyncMap.js";
|
|
4
|
+
|
|
5
|
+
describe("SyncMap", () => {
|
|
6
|
+
test("passes instanceof Map", () => {
|
|
7
|
+
const map = new SyncMap();
|
|
8
|
+
assert(map instanceof Map);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test("can be constructed with an iterable", () => {
|
|
12
|
+
const map = new SyncMap([
|
|
13
|
+
["a", 1],
|
|
14
|
+
["b", 2],
|
|
15
|
+
]);
|
|
16
|
+
assert.strictEqual(map.size, 2);
|
|
17
|
+
assert.strictEqual(map.get("a"), 1);
|
|
18
|
+
assert.strictEqual(map.get("b"), 2);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("can be constructed with another SyncMap", () => {
|
|
22
|
+
const map1 = new SyncMap([
|
|
23
|
+
["a", 1],
|
|
24
|
+
["b", 2],
|
|
25
|
+
]);
|
|
26
|
+
const map2 = new SyncMap(map1);
|
|
27
|
+
const entries = Array.from(map2.entries());
|
|
28
|
+
assert.deepStrictEqual(entries, [
|
|
29
|
+
["a", 1],
|
|
30
|
+
["b", 2],
|
|
31
|
+
]);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("clear calls delete for each key", () => {
|
|
35
|
+
const deletedKeys = [];
|
|
36
|
+
const keys = ["a", "b", "c"];
|
|
37
|
+
class Fixture extends SyncMap {
|
|
38
|
+
delete(key) {
|
|
39
|
+
deletedKeys.push(key);
|
|
40
|
+
return keys.includes(key);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
keys() {
|
|
44
|
+
return keys[Symbol.iterator]();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const map = new Fixture();
|
|
48
|
+
map.clear();
|
|
49
|
+
assert.deepStrictEqual(deletedKeys, ["a", "b", "c"]);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("delete", () => {
|
|
53
|
+
const map = new SyncMap([
|
|
54
|
+
["a", 1],
|
|
55
|
+
["b", 2],
|
|
56
|
+
]);
|
|
57
|
+
assert.strictEqual(map.size, 2);
|
|
58
|
+
assert.strictEqual(map.delete("a"), true);
|
|
59
|
+
assert.strictEqual(map.size, 1);
|
|
60
|
+
assert.strictEqual(map.get("a"), undefined);
|
|
61
|
+
assert.strictEqual(map.delete("a"), false);
|
|
62
|
+
assert.strictEqual(map.size, 1);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("delete on read-only map throws", () => {
|
|
66
|
+
class Fixture extends SyncMap {
|
|
67
|
+
get(key) {
|
|
68
|
+
return super.get(key);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const map = new Fixture([
|
|
72
|
+
["a", 1],
|
|
73
|
+
["b", 2],
|
|
74
|
+
]);
|
|
75
|
+
assert.throws(() => map.delete("a"), {
|
|
76
|
+
name: "TypeError",
|
|
77
|
+
message: "delete() can't be called on a read-only map",
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("entries", () => {
|
|
82
|
+
const map = new SyncMap([
|
|
83
|
+
["a", 1],
|
|
84
|
+
["b", 2],
|
|
85
|
+
]);
|
|
86
|
+
const entries = Array.from(map.entries());
|
|
87
|
+
assert.deepStrictEqual(entries, [
|
|
88
|
+
["a", 1],
|
|
89
|
+
["b", 2],
|
|
90
|
+
]);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("forEach", () => {
|
|
94
|
+
const map = new SyncMap([
|
|
95
|
+
["a", 1],
|
|
96
|
+
["b", 2],
|
|
97
|
+
]);
|
|
98
|
+
const calls = [];
|
|
99
|
+
map.forEach((value, key, theMap) => {
|
|
100
|
+
calls.push([key, value, theMap]);
|
|
101
|
+
});
|
|
102
|
+
assert.deepStrictEqual(calls, [
|
|
103
|
+
["a", 1, map],
|
|
104
|
+
["b", 2, map],
|
|
105
|
+
]);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("get", () => {
|
|
109
|
+
const map = new SyncMap([
|
|
110
|
+
["a", 1],
|
|
111
|
+
["b", 2],
|
|
112
|
+
]);
|
|
113
|
+
assert.strictEqual(map.get("a"), 1);
|
|
114
|
+
assert.strictEqual(map.get("b"), 2);
|
|
115
|
+
assert.strictEqual(map.get("c"), undefined);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("get with trailing slash", () => {
|
|
119
|
+
const subMap = new SyncMap();
|
|
120
|
+
const map = new SyncMap([
|
|
121
|
+
["a", 1],
|
|
122
|
+
["b/", subMap],
|
|
123
|
+
]);
|
|
124
|
+
assert.strictEqual(map.get("a"), 1);
|
|
125
|
+
|
|
126
|
+
const b = map.get("b/");
|
|
127
|
+
assert.strictEqual(b, subMap);
|
|
128
|
+
assert.strictEqual(b.parent, map);
|
|
129
|
+
|
|
130
|
+
// Trailing slash optional
|
|
131
|
+
assert.strictEqual(map.get("b"), subMap);
|
|
132
|
+
|
|
133
|
+
assert.strictEqual(map.get("c"), undefined);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test("has returns true if key exists in keys()", () => {
|
|
137
|
+
const map = new SyncMap();
|
|
138
|
+
map.keys = () => {
|
|
139
|
+
return ["a", "b/"][Symbol.iterator]();
|
|
140
|
+
};
|
|
141
|
+
assert.strictEqual(map.has("a"), true);
|
|
142
|
+
assert.strictEqual(map.has("b"), true); // trailing slash optional
|
|
143
|
+
assert.strictEqual(map.has("b/"), true);
|
|
144
|
+
assert.strictEqual(map.has("c"), false);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("readOnly if get() is overridden but not delete() and set()", () => {
|
|
148
|
+
const map4 = new SyncMap();
|
|
149
|
+
assert.strictEqual(map4.readOnly, false);
|
|
150
|
+
|
|
151
|
+
class ReadOnly1 extends SyncMap {
|
|
152
|
+
get(key) {
|
|
153
|
+
return super.get(key);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const map1 = new ReadOnly1();
|
|
157
|
+
assert.strictEqual(map1.readOnly, true);
|
|
158
|
+
|
|
159
|
+
class ReadOnly2 extends SyncMap {
|
|
160
|
+
get(key) {
|
|
161
|
+
return super.get(key);
|
|
162
|
+
}
|
|
163
|
+
set(key, value) {
|
|
164
|
+
return super.set(key, value);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const map2 = new ReadOnly2();
|
|
168
|
+
assert.strictEqual(map2.readOnly, true);
|
|
169
|
+
|
|
170
|
+
class ReadWrite extends SyncMap {
|
|
171
|
+
get(key) {
|
|
172
|
+
return super.get(key);
|
|
173
|
+
}
|
|
174
|
+
set(key, value) {
|
|
175
|
+
return super.set(key, value);
|
|
176
|
+
}
|
|
177
|
+
delete(key) {
|
|
178
|
+
return super.delete(key);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const map3 = new ReadWrite();
|
|
182
|
+
assert.strictEqual(map3.readOnly, false);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("Symbol.iterator", () => {
|
|
186
|
+
const map = new SyncMap([
|
|
187
|
+
["a", 1],
|
|
188
|
+
["b", 2],
|
|
189
|
+
]);
|
|
190
|
+
const entries = Array.from(map[Symbol.iterator]());
|
|
191
|
+
assert.deepStrictEqual(entries, [
|
|
192
|
+
["a", 1],
|
|
193
|
+
["b", 2],
|
|
194
|
+
]);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test("keys", () => {
|
|
198
|
+
const map = new SyncMap([
|
|
199
|
+
["a", 1],
|
|
200
|
+
["b", 2],
|
|
201
|
+
]);
|
|
202
|
+
const keys = Array.from(map.keys());
|
|
203
|
+
assert.deepStrictEqual(keys, ["a", "b"]);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("set", () => {
|
|
207
|
+
const map = new SyncMap();
|
|
208
|
+
assert.strictEqual(map.size, 0);
|
|
209
|
+
map.set("a", 1);
|
|
210
|
+
assert.strictEqual(map.size, 1);
|
|
211
|
+
assert.strictEqual(map.get("a"), 1);
|
|
212
|
+
map.set("a", 2);
|
|
213
|
+
assert.strictEqual(map.size, 1);
|
|
214
|
+
assert.strictEqual(map.get("a"), 2);
|
|
215
|
+
map.set("b", 3);
|
|
216
|
+
assert.strictEqual(map.size, 2);
|
|
217
|
+
assert.strictEqual(map.get("b"), 3);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test("set with EMPTY value creates empty subtree", () => {
|
|
221
|
+
const map = new SyncMap();
|
|
222
|
+
map.set("subtree", SyncMap.EMPTY);
|
|
223
|
+
const subtree = map.get("subtree");
|
|
224
|
+
assert(subtree instanceof SyncMap);
|
|
225
|
+
assert.strictEqual(subtree.size, 0);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test("set on read-only map throws", () => {
|
|
229
|
+
class Fixture extends SyncMap {
|
|
230
|
+
get(key) {
|
|
231
|
+
return super.get(key);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const map = new Fixture();
|
|
235
|
+
assert.throws(() => map.set("a", 1), {
|
|
236
|
+
name: "TypeError",
|
|
237
|
+
message: "set() can't be called on a read-only map",
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test("size", () => {
|
|
242
|
+
const map = new SyncMap();
|
|
243
|
+
assert.strictEqual(map.size, 0);
|
|
244
|
+
map.set("a", 1);
|
|
245
|
+
assert.strictEqual(map.size, 1);
|
|
246
|
+
map.set("b", 2);
|
|
247
|
+
assert.strictEqual(map.size, 2);
|
|
248
|
+
map.delete("a");
|
|
249
|
+
assert.strictEqual(map.size, 1);
|
|
250
|
+
map.clear();
|
|
251
|
+
assert.strictEqual(map.size, 0);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test("values", () => {
|
|
255
|
+
const map = new SyncMap([
|
|
256
|
+
["a", 1],
|
|
257
|
+
["b", 2],
|
|
258
|
+
]);
|
|
259
|
+
const values = Array.from(map.values());
|
|
260
|
+
assert.deepStrictEqual(values, [1, 2]);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
test("all methods work with prototype chain extension", () => {
|
|
264
|
+
const map = new SyncMap([
|
|
265
|
+
["a", 1],
|
|
266
|
+
["b", 2],
|
|
267
|
+
]);
|
|
268
|
+
const map2 = Object.create(map);
|
|
269
|
+
assert.strictEqual(map2.get("a"), 1);
|
|
270
|
+
assert.strictEqual(map2.has("b"), true);
|
|
271
|
+
assert.strictEqual(map2.size, 2);
|
|
272
|
+
|
|
273
|
+
const entries = Array.from(map2.entries());
|
|
274
|
+
assert.deepStrictEqual(entries, [
|
|
275
|
+
["a", 1],
|
|
276
|
+
["b", 2],
|
|
277
|
+
]);
|
|
278
|
+
|
|
279
|
+
const keys = Array.from(map2.keys());
|
|
280
|
+
assert.deepStrictEqual(keys, ["a", "b"]);
|
|
281
|
+
|
|
282
|
+
const values = Array.from(map2.values());
|
|
283
|
+
assert.deepStrictEqual(values, [1, 2]);
|
|
284
|
+
|
|
285
|
+
const iteratedEntries = Array.from(map2[Symbol.iterator]());
|
|
286
|
+
assert.deepStrictEqual(iteratedEntries, [
|
|
287
|
+
["a", 1],
|
|
288
|
+
["b", 2],
|
|
289
|
+
]);
|
|
290
|
+
|
|
291
|
+
const forEachCalls = [];
|
|
292
|
+
map2.forEach((value, key, thisArg) => {
|
|
293
|
+
forEachCalls.push([key, value, thisArg]);
|
|
294
|
+
});
|
|
295
|
+
assert.deepStrictEqual(forEachCalls, [
|
|
296
|
+
["a", 1, map2],
|
|
297
|
+
["b", 2, map2],
|
|
298
|
+
]);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
if ("groupBy" in Map) {
|
|
302
|
+
test("acceptable to Map.groupBy", () => {
|
|
303
|
+
const map = new SyncMap([
|
|
304
|
+
["a", 1],
|
|
305
|
+
["b", 2],
|
|
306
|
+
["c", 3],
|
|
307
|
+
]);
|
|
308
|
+
// @ts-ignore
|
|
309
|
+
const grouped = Map.groupBy(map, ([key, value]) =>
|
|
310
|
+
value % 2 === 0 ? "even" : "odd"
|
|
311
|
+
);
|
|
312
|
+
assert(grouped instanceof Map);
|
|
313
|
+
assert.strictEqual(grouped.size, 2);
|
|
314
|
+
assert.deepStrictEqual(grouped.get("odd"), [
|
|
315
|
+
["a", 1],
|
|
316
|
+
["c", 3],
|
|
317
|
+
]);
|
|
318
|
+
assert.deepStrictEqual(grouped.get("even"), [["b", 2]]);
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
});
|
package/test/jsonKeys.test.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { describe, test } from "node:test";
|
|
3
|
-
import
|
|
3
|
+
import DeepObjectMap from "../src/drivers/DeepObjectMap.js";
|
|
4
4
|
import * as jsonKeys from "../src/jsonKeys.js";
|
|
5
5
|
|
|
6
6
|
describe("jsonKeys", () => {
|
|
7
7
|
test("stringifies JSON Keys", async () => {
|
|
8
|
-
const tree = new
|
|
8
|
+
const tree = new DeepObjectMap({
|
|
9
9
|
about: {},
|
|
10
10
|
"index.html": "Home",
|
|
11
11
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { describe, test } from "node:test";
|
|
3
3
|
import addNextPrevious from "../../src/operations/addNextPrevious.js";
|
|
4
|
+
import plain from "../../src/operations/plain.js";
|
|
4
5
|
|
|
5
6
|
describe("addNextPrevious", () => {
|
|
6
7
|
test("adds next/previous properties to values", async () => {
|
|
@@ -16,7 +17,7 @@ describe("addNextPrevious", () => {
|
|
|
16
17
|
},
|
|
17
18
|
};
|
|
18
19
|
const result = await addNextPrevious(tree);
|
|
19
|
-
assert.deepEqual(result, {
|
|
20
|
+
assert.deepEqual(await plain(result), {
|
|
20
21
|
alice: {
|
|
21
22
|
name: "Alice",
|
|
22
23
|
nextKey: "bob",
|
|
@@ -36,7 +37,7 @@ describe("addNextPrevious", () => {
|
|
|
36
37
|
test("returns a non-object value as a 'value' property", async () => {
|
|
37
38
|
const array = ["Alice", "Bob", "Carol"];
|
|
38
39
|
const result = await addNextPrevious(array);
|
|
39
|
-
assert.deepEqual(result, [
|
|
40
|
+
assert.deepEqual(await plain(result), [
|
|
40
41
|
{
|
|
41
42
|
value: "Alice",
|
|
42
43
|
nextKey: "1",
|