footprintjs 9.23.0 → 9.23.2
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/dist/esm/lib/memory/TransactionBuffer.d.ts +18 -0
- package/dist/esm/lib/memory/TransactionBuffer.js +125 -86
- package/dist/esm/lib/reactive/arrayTraps.d.ts +23 -3
- package/dist/esm/lib/reactive/arrayTraps.js +149 -188
- package/dist/esm/lib/reactive/createTypedScope.js +150 -283
- package/dist/esm/lib/reactive/liveView.d.ts +51 -0
- package/dist/esm/lib/reactive/liveView.js +83 -1
- package/dist/esm/lib/reactive/writeTraps.d.ts +59 -0
- package/dist/esm/lib/reactive/writeTraps.js +132 -0
- package/dist/lib/memory/TransactionBuffer.js +125 -86
- package/dist/lib/reactive/arrayTraps.js +149 -187
- package/dist/lib/reactive/createTypedScope.js +147 -280
- package/dist/lib/reactive/liveView.js +87 -2
- package/dist/lib/reactive/writeTraps.js +139 -0
- package/dist/types/lib/memory/TransactionBuffer.d.ts +18 -0
- package/dist/types/lib/reactive/arrayTraps.d.ts +23 -3
- package/dist/types/lib/reactive/liveView.d.ts +51 -0
- package/dist/types/lib/reactive/writeTraps.d.ts +59 -0
- package/package.json +1 -1
|
@@ -9,9 +9,60 @@
|
|
|
9
9
|
* found on element proxies, then the same root on nested and terminal ones).
|
|
10
10
|
* So every read trap resolves through the CURRENT value and falls back to the
|
|
11
11
|
* captured object only when the path is gone or no longer holds an object.
|
|
12
|
+
*
|
|
13
|
+
* The READ side of every object proxy lives here — {@link liveObject},
|
|
14
|
+
* {@link liveGetTrap}, {@link liveInspectionTraps}, and the ONE per-member
|
|
15
|
+
* proxy cache {@link cachedMember} (9.23.2); the WRITE side is
|
|
16
|
+
* `writeTraps.ts`. A factory only wires them (9.23.1).
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* A proxy per member NAME under one parent proxy, validated by the raw
|
|
20
|
+
* member's identity. The map is allocated on the FIRST insert: an element
|
|
21
|
+
* proxy over `{ id, n }` reads only primitives and must not pay for one
|
|
22
|
+
* (10,000 of them in the naive re-read loop — measured, `bench/nested-reads.ts`).
|
|
12
23
|
*/
|
|
24
|
+
export declare class MemberCache {
|
|
25
|
+
private entries?;
|
|
26
|
+
/** The proxy cached under `prop`, if it was built over exactly this raw `value`. */
|
|
27
|
+
hit(prop: string, value: object): unknown;
|
|
28
|
+
remember(prop: string, value: object, proxy: unknown): void;
|
|
29
|
+
/** Forget `prop` — a write replaced its value, so the next read must build over the new one. */
|
|
30
|
+
delete(prop: string): void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* WHY the cache: `o.arr === o.arr` must hold within a stage, and
|
|
34
|
+
* `for (i < N) s.k.arr[i]` must build ONE array proxy — whose element cache
|
|
35
|
+
* then serves every index — not N (the 9.22.0 perf review, finding 4: the
|
|
36
|
+
* nested get trap built a fresh array proxy, with a fresh empty element
|
|
37
|
+
* cache, on every `.arr`). The top-level scope has cached its child proxies
|
|
38
|
+
* this way since before 9.22.0; this is that leaf, shared by all four.
|
|
39
|
+
*
|
|
40
|
+
* Validated by IDENTITY, invalidated by replacement: every write through a
|
|
41
|
+
* proxy rebuilds the containers on its path (`structuralWrite.setInPath`),
|
|
42
|
+
* so after `s.k.arr[0].n = 1` the raw `arr` is a new array, the ref check
|
|
43
|
+
* misses, and the next read builds a proxy over the NEW value. A hit can
|
|
44
|
+
* never be stale — every proxy reads live (`liveGetTrap`), so the cached one
|
|
45
|
+
* and a fresh one answer the same.
|
|
46
|
+
*
|
|
47
|
+
* Keyed by NAME under THIS parent, never by the raw value alone: a diamond
|
|
48
|
+
* (one array under `k.a` and `k.b`) needs two proxies, each bound to its own
|
|
49
|
+
* path and sink. Only what `build` actually WRAPPED is kept — a member handed
|
|
50
|
+
* back raw (a `Date`, a frozen object, a cycle edge) is not worth an entry.
|
|
51
|
+
* `build` is the caller's stable child step, not a closure made per read: a
|
|
52
|
+
* hit allocates nothing, and a primitive member skips the cache entirely.
|
|
53
|
+
*/
|
|
54
|
+
export declare function cachedMember(cache: MemberCache, prop: string, value: unknown, build: (value: unknown, path: string[]) => unknown, segments: readonly string[]): unknown;
|
|
13
55
|
/** The object at `segments` under the current root, or `raw` when it is gone. */
|
|
14
56
|
export declare function liveObject(raw: Record<string, unknown>, current: unknown): Record<string, unknown>;
|
|
57
|
+
/**
|
|
58
|
+
* WHY one get trap: the names a proxy answers ITSELF (promise/matcher guards,
|
|
59
|
+
* `constructor`, and the JSON law — serializing a proxied value equals
|
|
60
|
+
* serializing the raw one, `jsonProjection.ts`) must be the same three lines
|
|
61
|
+
* on every object proxy; any other member is handed to `child` with its full
|
|
62
|
+
* path — through the parent's {@link cachedMember} — and only THAT step
|
|
63
|
+
* differs per factory (the cycle policy).
|
|
64
|
+
*/
|
|
65
|
+
export declare function liveGetTrap(live: () => Record<string, unknown>, segments: readonly string[], child: (value: unknown, path: string[]) => unknown, members: MemberCache): ProxyHandler<object>['get'];
|
|
15
66
|
/**
|
|
16
67
|
* The three inspection traps (`in`, `Object.keys`, descriptors) answered from
|
|
17
68
|
* the live object. The one Proxy invariant that could bite — a non-extensible
|
|
@@ -9,13 +9,95 @@
|
|
|
9
9
|
* found on element proxies, then the same root on nested and terminal ones).
|
|
10
10
|
* So every read trap resolves through the CURRENT value and falls back to the
|
|
11
11
|
* captured object only when the path is gone or no longer holds an object.
|
|
12
|
+
*
|
|
13
|
+
* The READ side of every object proxy lives here — {@link liveObject},
|
|
14
|
+
* {@link liveGetTrap}, {@link liveInspectionTraps}, and the ONE per-member
|
|
15
|
+
* proxy cache {@link cachedMember} (9.23.2); the WRITE side is
|
|
16
|
+
* `writeTraps.ts`. A factory only wires them (9.23.1).
|
|
17
|
+
*/
|
|
18
|
+
import { toJSONView } from './jsonProjection.js';
|
|
19
|
+
/**
|
|
20
|
+
* A proxy per member NAME under one parent proxy, validated by the raw
|
|
21
|
+
* member's identity. The map is allocated on the FIRST insert: an element
|
|
22
|
+
* proxy over `{ id, n }` reads only primitives and must not pay for one
|
|
23
|
+
* (10,000 of them in the naive re-read loop — measured, `bench/nested-reads.ts`).
|
|
12
24
|
*/
|
|
25
|
+
export class MemberCache {
|
|
26
|
+
entries;
|
|
27
|
+
/** The proxy cached under `prop`, if it was built over exactly this raw `value`. */
|
|
28
|
+
hit(prop, value) {
|
|
29
|
+
const cached = this.entries?.get(prop);
|
|
30
|
+
return cached !== undefined && cached.ref === value ? cached.proxy : undefined;
|
|
31
|
+
}
|
|
32
|
+
remember(prop, value, proxy) {
|
|
33
|
+
(this.entries ??= new Map()).set(prop, { ref: value, proxy });
|
|
34
|
+
}
|
|
35
|
+
/** Forget `prop` — a write replaced its value, so the next read must build over the new one. */
|
|
36
|
+
delete(prop) {
|
|
37
|
+
this.entries?.delete(prop);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* WHY the cache: `o.arr === o.arr` must hold within a stage, and
|
|
42
|
+
* `for (i < N) s.k.arr[i]` must build ONE array proxy — whose element cache
|
|
43
|
+
* then serves every index — not N (the 9.22.0 perf review, finding 4: the
|
|
44
|
+
* nested get trap built a fresh array proxy, with a fresh empty element
|
|
45
|
+
* cache, on every `.arr`). The top-level scope has cached its child proxies
|
|
46
|
+
* this way since before 9.22.0; this is that leaf, shared by all four.
|
|
47
|
+
*
|
|
48
|
+
* Validated by IDENTITY, invalidated by replacement: every write through a
|
|
49
|
+
* proxy rebuilds the containers on its path (`structuralWrite.setInPath`),
|
|
50
|
+
* so after `s.k.arr[0].n = 1` the raw `arr` is a new array, the ref check
|
|
51
|
+
* misses, and the next read builds a proxy over the NEW value. A hit can
|
|
52
|
+
* never be stale — every proxy reads live (`liveGetTrap`), so the cached one
|
|
53
|
+
* and a fresh one answer the same.
|
|
54
|
+
*
|
|
55
|
+
* Keyed by NAME under THIS parent, never by the raw value alone: a diamond
|
|
56
|
+
* (one array under `k.a` and `k.b`) needs two proxies, each bound to its own
|
|
57
|
+
* path and sink. Only what `build` actually WRAPPED is kept — a member handed
|
|
58
|
+
* back raw (a `Date`, a frozen object, a cycle edge) is not worth an entry.
|
|
59
|
+
* `build` is the caller's stable child step, not a closure made per read: a
|
|
60
|
+
* hit allocates nothing, and a primitive member skips the cache entirely.
|
|
61
|
+
*/
|
|
62
|
+
export function cachedMember(cache, prop, value, build, segments) {
|
|
63
|
+
if (value === null || typeof value !== 'object')
|
|
64
|
+
return build(value, [...segments, prop]);
|
|
65
|
+
const hit = cache.hit(prop, value);
|
|
66
|
+
if (hit !== undefined)
|
|
67
|
+
return hit;
|
|
68
|
+
const proxy = build(value, [...segments, prop]);
|
|
69
|
+
if (proxy !== value)
|
|
70
|
+
cache.remember(prop, value, proxy);
|
|
71
|
+
return proxy;
|
|
72
|
+
}
|
|
13
73
|
/** The object at `segments` under the current root, or `raw` when it is gone. */
|
|
14
74
|
export function liveObject(raw, current) {
|
|
15
75
|
return current !== null && typeof current === 'object' && !Array.isArray(current)
|
|
16
76
|
? current
|
|
17
77
|
: raw;
|
|
18
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* WHY one get trap: the names a proxy answers ITSELF (promise/matcher guards,
|
|
81
|
+
* `constructor`, and the JSON law — serializing a proxied value equals
|
|
82
|
+
* serializing the raw one, `jsonProjection.ts`) must be the same three lines
|
|
83
|
+
* on every object proxy; any other member is handed to `child` with its full
|
|
84
|
+
* path — through the parent's {@link cachedMember} — and only THAT step
|
|
85
|
+
* differs per factory (the cycle policy).
|
|
86
|
+
*/
|
|
87
|
+
export function liveGetTrap(live, segments, child, members) {
|
|
88
|
+
return (_target, prop) => {
|
|
89
|
+
const raw = live();
|
|
90
|
+
if (typeof prop === 'symbol')
|
|
91
|
+
return raw[prop];
|
|
92
|
+
if (prop === 'then' || prop === 'asymmetricMatch')
|
|
93
|
+
return undefined;
|
|
94
|
+
if (prop === 'constructor')
|
|
95
|
+
return Object;
|
|
96
|
+
if (prop === 'toJSON')
|
|
97
|
+
return () => toJSONView(raw);
|
|
98
|
+
return cachedMember(members, prop, raw[prop], child, segments);
|
|
99
|
+
};
|
|
100
|
+
}
|
|
19
101
|
/**
|
|
20
102
|
* The three inspection traps (`in`, `Object.keys`, descriptors) answered from
|
|
21
103
|
* the live object. The one Proxy invariant that could bite — a non-extensible
|
|
@@ -40,4 +122,4 @@ export function liveInspectionTraps(live) {
|
|
|
40
122
|
},
|
|
41
123
|
};
|
|
42
124
|
}
|
|
43
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGl2ZVZpZXcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3JlYWN0aXZlL2xpdmVWaWV3LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7OztHQVdHO0FBRUgsaUZBQWlGO0FBQ2pGLE1BQU0sVUFBVSxVQUFVLENBQUMsR0FBNEIsRUFBRSxPQUFnQjtJQUN2RSxPQUFPLE9BQU8sS0FBSyxJQUFJLElBQUksT0FBTyxPQUFPLEtBQUssUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUM7UUFDL0UsQ0FBQyxDQUFFLE9BQW1DO1FBQ3RDLENBQUMsQ0FBQyxHQUFHLENBQUM7QUFDVixDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILE1BQU0sVUFBVSxtQkFBbUIsQ0FDakMsSUFBa0I7SUFFbEIsT0FBTztRQUNMLEdBQUcsQ0FBQyxNQUFNLEVBQUUsSUFBSTtZQUNkLE9BQU8sT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQzFFLENBQUM7UUFDRCxPQUFPLENBQUMsTUFBTTtZQUNaLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDeEUsQ0FBQztRQUNELHdCQUF3QixDQUFDLE1BQU0sRUFBRSxJQUFJO1lBQ25DLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQztnQkFBRSxPQUFPLE1BQU0sQ0FBQyx3QkFBd0IsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDdkYsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLHdCQUF3QixDQUFDLElBQUksRUFBRSxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQ2pFLE9BQU8sVUFBVSxJQUFJLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLFVBQVUsRUFBRSxZQUFZLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQztRQUNyRyxDQUFDO0tBQ0YsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIHJlYWN0aXZlL2xpdmVWaWV3IOKAlCB3aGF0IGEgcHJveHkgc3RhbmRzIGZvciwgQVMgSVQgU1RBTkRTIE5PVy5cbiAqXG4gKiBFdmVyeSB3cml0ZSB0aHJvdWdoIHRoZSB0eXBlZCBzY29wZSByZWJ1aWxkcyB0aGUgcm9vdCBpbW11dGFibHlcbiAqIChgc3RydWN0dXJhbFdyaXRlLnNldEluUGF0aGAsIGEgZnJlc2ggbWVyZ2UpLCBzbyB0aGUgb2JqZWN0IGEgcHJveHkgd2FzXG4gKiBjcmVhdGVkIG92ZXIgaXMgdGhlIFBSRS13cml0ZSB2YWx1ZSBmb3IgZXZlciBhZnRlci4gQSBoZWxkIHByb3h5IHRoYXQgcmVhZFxuICogZnJvbSBpdCBzYXcgaXRzIG93biB3cml0ZXMgdmFuaXNoOiBgby54ICs9IDFgIHR3aWNlIGdhdmUgMiwgYG8uYiA9IG8uYSAqIDEwYFxuICogdXNlZCB0aGUgb2xkIGBhYCwgYCd4JyBpbiBvYCB3YXMgZmFsc2UgcmlnaHQgYWZ0ZXIgYG8ueCA9IDFgICg5LjIyLjAg4oCUIGZpcnN0XG4gKiBmb3VuZCBvbiBlbGVtZW50IHByb3hpZXMsIHRoZW4gdGhlIHNhbWUgcm9vdCBvbiBuZXN0ZWQgYW5kIHRlcm1pbmFsIG9uZXMpLlxuICogU28gZXZlcnkgcmVhZCB0cmFwIHJlc29sdmVzIHRocm91Z2ggdGhlIENVUlJFTlQgdmFsdWUgYW5kIGZhbGxzIGJhY2sgdG8gdGhlXG4gKiBjYXB0dXJlZCBvYmplY3Qgb25seSB3aGVuIHRoZSBwYXRoIGlzIGdvbmUgb3Igbm8gbG9uZ2VyIGhvbGRzIGFuIG9iamVjdC5cbiAqL1xuXG4vKiogVGhlIG9iamVjdCBhdCBgc2VnbWVudHNgIHVuZGVyIHRoZSBjdXJyZW50IHJvb3QsIG9yIGByYXdgIHdoZW4gaXQgaXMgZ29uZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsaXZlT2JqZWN0KHJhdzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIGN1cnJlbnQ6IHVua25vd24pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gIHJldHVybiBjdXJyZW50ICE9PSBudWxsICYmIHR5cGVvZiBjdXJyZW50ID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShjdXJyZW50KVxuICAgID8gKGN1cnJlbnQgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pXG4gICAgOiByYXc7XG59XG5cbi8qKlxuICogVGhlIHRocmVlIGluc3BlY3Rpb24gdHJhcHMgKGBpbmAsIGBPYmplY3Qua2V5c2AsIGRlc2NyaXB0b3JzKSBhbnN3ZXJlZCBmcm9tXG4gKiB0aGUgbGl2ZSBvYmplY3QuIFRoZSBvbmUgUHJveHkgaW52YXJpYW50IHRoYXQgY291bGQgYml0ZSDigJQgYSBub24tZXh0ZW5zaWJsZVxuICogdGFyZ2V0IG11c3QgcmVwb3J0IGV4YWN0bHkgaXRzIG93biBrZXlzLCBhbmQgYSBwcm9wZXJ0eSB0aGUgdGFyZ2V0IGxhY2tzXG4gKiBtdXN0IGJlIHJlcG9ydGVkIGNvbmZpZ3VyYWJsZSDigJQgaXMgaG9ub3VyZWQ6IHRoZSBhbGxvd2xpc3QgYWxyZWFkeSByZWZ1c2VzXG4gKiBmcm96ZW4gYW5kIHNlYWxlZCB2YWx1ZXMsIHNvIHRoZSBgcHJldmVudEV4dGVuc2lvbnNgLW9ubHkgY29ybmVyIGFuc3dlcnNcbiAqIGZyb20gdGhlIHRhcmdldCwgYW5kIGEgbGl2ZSBkZXNjcmlwdG9yIGlzIGFsd2F5cyByZXBvcnRlZCBjb25maWd1cmFibGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsaXZlSW5zcGVjdGlvblRyYXBzKFxuICBsaXZlOiAoKSA9PiBvYmplY3QsXG4pOiBQaWNrPFByb3h5SGFuZGxlcjxvYmplY3Q+LCAnaGFzJyB8ICdvd25LZXlzJyB8ICdnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3InPiB7XG4gIHJldHVybiB7XG4gICAgaGFzKHRhcmdldCwgcHJvcCkge1xuICAgICAgcmV0dXJuIFJlZmxlY3QuaGFzKE9iamVjdC5pc0V4dGVuc2libGUodGFyZ2V0KSA/IGxpdmUoKSA6IHRhcmdldCwgcHJvcCk7XG4gICAgfSxcbiAgICBvd25LZXlzKHRhcmdldCkge1xuICAgICAgcmV0dXJuIFJlZmxlY3Qub3duS2V5cyhPYmplY3QuaXNFeHRlbnNpYmxlKHRhcmdldCkgPyBsaXZlKCkgOiB0YXJnZXQpO1xuICAgIH0sXG4gICAgZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHRhcmdldCwgcHJvcCkge1xuICAgICAgaWYgKCFPYmplY3QuaXNFeHRlbnNpYmxlKHRhcmdldCkpIHJldHVybiBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHRhcmdldCwgcHJvcCk7XG4gICAgICBjb25zdCBkZXNjcmlwdG9yID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihsaXZlKCksIHByb3ApO1xuICAgICAgcmV0dXJuIGRlc2NyaXB0b3IgJiYgIWRlc2NyaXB0b3IuY29uZmlndXJhYmxlID8geyAuLi5kZXNjcmlwdG9yLCBjb25maWd1cmFibGU6IHRydWUgfSA6IGRlc2NyaXB0b3I7XG4gICAgfSxcbiAgfTtcbn1cbiJdfQ==
|
|
125
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGl2ZVZpZXcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3JlYWN0aXZlL2xpdmVWaWV3LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7O0dBZ0JHO0FBRUgsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRWpEOzs7OztHQUtHO0FBQ0gsTUFBTSxPQUFPLFdBQVc7SUFDZCxPQUFPLENBQWdEO0lBRS9ELG9GQUFvRjtJQUNwRixHQUFHLENBQUMsSUFBWSxFQUFFLEtBQWE7UUFDN0IsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDdkMsT0FBTyxNQUFNLEtBQUssU0FBUyxJQUFJLE1BQU0sQ0FBQyxHQUFHLEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFDakYsQ0FBQztJQUVELFFBQVEsQ0FBQyxJQUFZLEVBQUUsS0FBYSxFQUFFLEtBQWM7UUFDbEQsQ0FBQyxJQUFJLENBQUMsT0FBTyxLQUFLLElBQUksR0FBRyxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBQ2hFLENBQUM7SUFFRCxnR0FBZ0c7SUFDaEcsTUFBTSxDQUFDLElBQVk7UUFDakIsSUFBSSxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDN0IsQ0FBQztDQUNGO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFCRztBQUNILE1BQU0sVUFBVSxZQUFZLENBQzFCLEtBQWtCLEVBQ2xCLElBQVksRUFDWixLQUFjLEVBQ2QsS0FBa0QsRUFDbEQsUUFBMkI7SUFFM0IsSUFBSSxLQUFLLEtBQUssSUFBSSxJQUFJLE9BQU8sS0FBSyxL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RUFBRSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUM7UUFDckcsQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiByZWFjdGl2ZS9saXZlVmlldyDigJQgd2hhdCBhIHByb3h5IHN0YW5kcyBmb3IsIEFTIElUIFNUQU5EUyBOT1cuXG4gKlxuICogRXZlcnkgd3JpdGUgdGhyb3VnaCB0aGUgdHlwZWQgc2NvcGUgcmVidWlsZHMgdGhlIHJvb3QgaW1tdXRhYmx5XG4gKiAoYHN0cnVjdHVyYWxXcml0ZS5zZXRJblBhdGhgLCBhIGZyZXNoIG1lcmdlKSwgc28gdGhlIG9iamVjdCBhIHByb3h5IHdhc1xuICogY3JlYXRlZCBvdmVyIGlzIHRoZSBQUkUtd3JpdGUgdmFsdWUgZm9yIGV2ZXIgYWZ0ZXIuIEEgaGVsZCBwcm94eSB0aGF0IHJlYWRcbiAqIGZyb20gaXQgc2F3IGl0cyBvd24gd3JpdGVzIHZhbmlzaDogYG8ueCArPSAxYCB0d2ljZSBnYXZlIDIsIGBvLmIgPSBvLmEgKiAxMGBcbiAqIHVzZWQgdGhlIG9sZCBgYWAsIGAneCcgaW4gb2Agd2FzIGZhbHNlIHJpZ2h0IGFmdGVyIGBvLnggPSAxYCAoOS4yMi4wIOKAlCBmaXJzdFxuICogZm91bmQgb24gZWxlbWVudCBwcm94aWVzLCB0aGVuIHRoZSBzYW1lIHJvb3Qgb24gbmVzdGVkIGFuZCB0ZXJtaW5hbCBvbmVzKS5cbiAqIFNvIGV2ZXJ5IHJlYWQgdHJhcCByZXNvbHZlcyB0aHJvdWdoIHRoZSBDVVJSRU5UIHZhbHVlIGFuZCBmYWxscyBiYWNrIHRvIHRoZVxuICogY2FwdHVyZWQgb2JqZWN0IG9ubHkgd2hlbiB0aGUgcGF0aCBpcyBnb25lIG9yIG5vIGxvbmdlciBob2xkcyBhbiBvYmplY3QuXG4gKlxuICogVGhlIFJFQUQgc2lkZSBvZiBldmVyeSBvYmplY3QgcHJveHkgbGl2ZXMgaGVyZSDigJQge0BsaW5rIGxpdmVPYmplY3R9LFxuICoge0BsaW5rIGxpdmVHZXRUcmFwfSwge0BsaW5rIGxpdmVJbnNwZWN0aW9uVHJhcHN9LCBhbmQgdGhlIE9ORSBwZXItbWVtYmVyXG4gKiBwcm94eSBjYWNoZSB7QGxpbmsgY2FjaGVkTWVtYmVyfSAoOS4yMy4yKTsgdGhlIFdSSVRFIHNpZGUgaXNcbiAqIGB3cml0ZVRyYXBzLnRzYC4gQSBmYWN0b3J5IG9ubHkgd2lyZXMgdGhlbSAoOS4yMy4xKS5cbiAqL1xuXG5pbXBvcnQgeyB0b0pTT05WaWV3IH0gZnJvbSAnLi9qc29uUHJvamVjdGlvbi5qcyc7XG5cbi8qKlxuICogQSBwcm94eSBwZXIgbWVtYmVyIE5BTUUgdW5kZXIgb25lIHBhcmVudCBwcm94eSwgdmFsaWRhdGVkIGJ5IHRoZSByYXdcbiAqIG1lbWJlcidzIGlkZW50aXR5LiBUaGUgbWFwIGlzIGFsbG9jYXRlZCBvbiB0aGUgRklSU1QgaW5zZXJ0OiBhbiBlbGVtZW50XG4gKiBwcm94eSBvdmVyIGB7IGlkLCBuIH1gIHJlYWRzIG9ubHkgcHJpbWl0aXZlcyBhbmQgbXVzdCBub3QgcGF5IGZvciBvbmVcbiAqICgxMCwwMDAgb2YgdGhlbSBpbiB0aGUgbmFpdmUgcmUtcmVhZCBsb29wIOKAlCBtZWFzdXJlZCwgYGJlbmNoL25lc3RlZC1yZWFkcy50c2ApLlxuICovXG5leHBvcnQgY2xhc3MgTWVtYmVyQ2FjaGUge1xuICBwcml2YXRlIGVudHJpZXM/OiBNYXA8c3RyaW5nLCB7IHJlZjogb2JqZWN0OyBwcm94eTogdW5rbm93biB9PjtcblxuICAvKiogVGhlIHByb3h5IGNhY2hlZCB1bmRlciBgcHJvcGAsIGlmIGl0IHdhcyBidWlsdCBvdmVyIGV4YWN0bHkgdGhpcyByYXcgYHZhbHVlYC4gKi9cbiAgaGl0KHByb3A6IHN0cmluZywgdmFsdWU6IG9iamVjdCk6IHVua25vd24ge1xuICAgIGNvbnN0IGNhY2hlZCA9IHRoaXMuZW50cmllcz8uZ2V0KHByb3ApO1xuICAgIHJldHVybiBjYWNoZWQgIT09IHVuZGVmaW5lZCAmJiBjYWNoZWQucmVmID09PSB2YWx1ZSA/IGNhY2hlZC5wcm94eSA6IHVuZGVmaW5lZDtcbiAgfVxuXG4gIHJlbWVtYmVyKHByb3A6IHN0cmluZywgdmFsdWU6IG9iamVjdCwgcHJveHk6IHVua25vd24pOiB2b2lkIHtcbiAgICAodGhpcy5lbnRyaWVzID8/PSBuZXcgTWFwKCkpLnNldChwcm9wLCB7IHJlZjogdmFsdWUsIHByb3h5IH0pO1xuICB9XG5cbiAgLyoqIEZvcmdldCBgcHJvcGAg4oCUIGEgd3JpdGUgcmVwbGFjZWQgaXRzIHZhbHVlLCBzbyB0aGUgbmV4dCByZWFkIG11c3QgYnVpbGQgb3ZlciB0aGUgbmV3IG9uZS4gKi9cbiAgZGVsZXRlKHByb3A6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMuZW50cmllcz8uZGVsZXRlKHByb3ApO1xuICB9XG59XG5cbi8qKlxuICogV0hZIHRoZSBjYWNoZTogYG8uYXJyID09PSBvLmFycmAgbXVzdCBob2xkIHdpdGhpbiBhIHN0YWdlLCBhbmRcbiAqIGBmb3IgKGkgPCBOKSBzLmsuYXJyW2ldYCBtdXN0IGJ1aWxkIE9ORSBhcnJheSBwcm94eSDigJQgd2hvc2UgZWxlbWVudCBjYWNoZVxuICogdGhlbiBzZXJ2ZXMgZXZlcnkgaW5kZXgg4oCUIG5vdCBOICh0aGUgOS4yMi4wIHBlcmYgcmV2aWV3LCBmaW5kaW5nIDQ6IHRoZVxuICogbmVzdGVkIGdldCB0cmFwIGJ1aWx0IGEgZnJlc2ggYXJyYXkgcHJveHksIHdpdGggYSBmcmVzaCBlbXB0eSBlbGVtZW50XG4gKiBjYWNoZSwgb24gZXZlcnkgYC5hcnJgKS4gVGhlIHRvcC1sZXZlbCBzY29wZSBoYXMgY2FjaGVkIGl0cyBjaGlsZCBwcm94aWVzXG4gKiB0aGlzIHdheSBzaW5jZSBiZWZvcmUgOS4yMi4wOyB0aGlzIGlzIHRoYXQgbGVhZiwgc2hhcmVkIGJ5IGFsbCBmb3VyLlxuICpcbiAqIFZhbGlkYXRlZCBieSBJREVOVElUWSwgaW52YWxpZGF0ZWQgYnkgcmVwbGFjZW1lbnQ6IGV2ZXJ5IHdyaXRlIHRocm91Z2ggYVxuICogcHJveHkgcmVidWlsZHMgdGhlIGNvbnRhaW5lcnMgb24gaXRzIHBhdGggKGBzdHJ1Y3R1cmFsV3JpdGUuc2V0SW5QYXRoYCksXG4gKiBzbyBhZnRlciBgcy5rLmFyclswXS5uID0gMWAgdGhlIHJhdyBgYXJyYCBpcyBhIG5ldyBhcnJheSwgdGhlIHJlZiBjaGVja1xuICogbWlzc2VzLCBhbmQgdGhlIG5leHQgcmVhZCBidWlsZHMgYSBwcm94eSBvdmVyIHRoZSBORVcgdmFsdWUuIEEgaGl0IGNhblxuICogbmV2ZXIgYmUgc3RhbGUg4oCUIGV2ZXJ5IHByb3h5IHJlYWRzIGxpdmUgKGBsaXZlR2V0VHJhcGApLCBzbyB0aGUgY2FjaGVkIG9uZVxuICogYW5kIGEgZnJlc2ggb25lIGFuc3dlciB0aGUgc2FtZS5cbiAqXG4gKiBLZXllZCBieSBOQU1FIHVuZGVyIFRISVMgcGFyZW50LCBuZXZlciBieSB0aGUgcmF3IHZhbHVlIGFsb25lOiBhIGRpYW1vbmRcbiAqIChvbmUgYXJyYXkgdW5kZXIgYGsuYWAgYW5kIGBrLmJgKSBuZWVkcyB0d28gcHJveGllcywgZWFjaCBib3VuZCB0byBpdHMgb3duXG4gKiBwYXRoIGFuZCBzaW5rLiBPbmx5IHdoYXQgYGJ1aWxkYCBhY3R1YWxseSBXUkFQUEVEIGlzIGtlcHQg4oCUIGEgbWVtYmVyIGhhbmRlZFxuICogYmFjayByYXcgKGEgYERhdGVgLCBhIGZyb3plbiBvYmplY3QsIGEgY3ljbGUgZWRnZSkgaXMgbm90IHdvcnRoIGFuIGVudHJ5LlxuICogYGJ1aWxkYCBpcyB0aGUgY2FsbGVyJ3Mgc3RhYmxlIGNoaWxkIHN0ZXAsIG5vdCBhIGNsb3N1cmUgbWFkZSBwZXIgcmVhZDogYVxuICogaGl0IGFsbG9jYXRlcyBub3RoaW5nLCBhbmQgYSBwcmltaXRpdmUgbWVtYmVyIHNraXBzIHRoZSBjYWNoZSBlbnRpcmVseS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNhY2hlZE1lbWJlcihcbiAgY2FjaGU6IE1lbWJlckNhY2hlLFxuICBwcm9wOiBzdHJpbmcsXG4gIHZhbHVlOiB1bmtub3duLFxuICBidWlsZDogKHZhbHVlOiB1bmtub3duLCBwYXRoOiBzdHJpbmdbXSkgPT4gdW5rbm93bixcbiAgc2VnbWVudHM6IHJlYWRvbmx5IHN0cmluZ1tdLFxuKTogdW5rbm93biB7XG4gIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB0eXBlb2YgdmFsdWUgIT09ICdvYmplY3QnKSByZXR1cm4gYnVpbGQodmFsdWUsIFsuLi5zZWdtZW50cywgcHJvcF0pO1xuICBjb25zdCBoaXQgPSBjYWNoZS5oaXQocHJvcCwgdmFsdWUpO1xuICBpZiAoaGl0ICE9PSB1bmRlZmluZWQpIHJldHVybiBoaXQ7XG4gIGNvbnN0IHByb3h5ID0gYnVpbGQodmFsdWUsIFsuLi5zZWdtZW50cywgcHJvcF0pO1xuICBpZiAocHJveHkgIT09IHZhbHVlKSBjYWNoZS5yZW1lbWJlcihwcm9wLCB2YWx1ZSwgcHJveHkpO1xuICByZXR1cm4gcHJveHk7XG59XG5cbi8qKiBUaGUgb2JqZWN0IGF0IGBzZWdtZW50c2AgdW5kZXIgdGhlIGN1cnJlbnQgcm9vdCwgb3IgYHJhd2Agd2hlbiBpdCBpcyBnb25lLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxpdmVPYmplY3QocmF3OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiwgY3VycmVudDogdW5rbm93bik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgcmV0dXJuIGN1cnJlbnQgIT09IG51bGwgJiYgdHlwZW9mIGN1cnJlbnQgPT09ICdvYmplY3QnICYmICFBcnJheS5pc0FycmF5KGN1cnJlbnQpXG4gICAgPyAoY3VycmVudCBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPilcbiAgICA6IHJhdztcbn1cblxuLyoqXG4gKiBXSFkgb25lIGdldCB0cmFwOiB0aGUgbmFtZXMgYSBwcm94eSBhbnN3ZXJzIElUU0VMRiAocHJvbWlzZS9tYXRjaGVyIGd1YXJkcyxcbiAqIGBjb25zdHJ1Y3RvcmAsIGFuZCB0aGUgSlNPTiBsYXcg4oCUIHNlcmlhbGl6aW5nIGEgcHJveGllZCB2YWx1ZSBlcXVhbHNcbiAqIHNlcmlhbGl6aW5nIHRoZSByYXcgb25lLCBganNvblByb2plY3Rpb24udHNgKSBtdXN0IGJlIHRoZSBzYW1lIHRocmVlIGxpbmVzXG4gKiBvbiBldmVyeSBvYmplY3QgcHJveHk7IGFueSBvdGhlciBtZW1iZXIgaXMgaGFuZGVkIHRvIGBjaGlsZGAgd2l0aCBpdHMgZnVsbFxuICogcGF0aCDigJQgdGhyb3VnaCB0aGUgcGFyZW50J3Mge0BsaW5rIGNhY2hlZE1lbWJlcn0g4oCUIGFuZCBvbmx5IFRIQVQgc3RlcFxuICogZGlmZmVycyBwZXIgZmFjdG9yeSAodGhlIGN5Y2xlIHBvbGljeSkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsaXZlR2V0VHJhcChcbiAgbGl2ZTogKCkgPT4gUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIHNlZ21lbnRzOiByZWFkb25seSBzdHJpbmdbXSxcbiAgY2hpbGQ6ICh2YWx1ZTogdW5rbm93biwgcGF0aDogc3RyaW5nW10pID0+IHVua25vd24sXG4gIG1lbWJlcnM6IE1lbWJlckNhY2hlLFxuKTogUHJveHlIYW5kbGVyPG9iamVjdD5bJ2dldCddIHtcbiAgcmV0dXJuIChfdGFyZ2V0LCBwcm9wKSA9PiB7XG4gICAgY29uc3QgcmF3ID0gbGl2ZSgpO1xuICAgIGlmICh0eXBlb2YgcHJvcCA9PT0gJ3N5bWJvbCcpIHJldHVybiAocmF3IGFzIGFueSlbcHJvcF07XG4gICAgaWYgKHByb3AgPT09ICd0aGVuJyB8fCBwcm9wID09PSAnYXN5bW1ldHJpY01hdGNoJykgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICBpZiAocHJvcCA9PT0gJ2NvbnN0cnVjdG9yJykgcmV0dXJuIE9iamVjdDtcbiAgICBpZiAocHJvcCA9PT0gJ3RvSlNPTicpIHJldHVybiAoKSA9PiB0b0pTT05WaWV3KHJhdyk7XG4gICAgcmV0dXJuIGNhY2hlZE1lbWJlcihtZW1iZXJzLCBwcm9wLCByYXdbcHJvcF0sIGNoaWxkLCBzZWdtZW50cyk7XG4gIH07XG59XG5cbi8qKlxuICogVGhlIHRocmVlIGluc3BlY3Rpb24gdHJhcHMgKGBpbmAsIGBPYmplY3Qua2V5c2AsIGRlc2NyaXB0b3JzKSBhbnN3ZXJlZCBmcm9tXG4gKiB0aGUgbGl2ZSBvYmplY3QuIFRoZSBvbmUgUHJveHkgaW52YXJpYW50IHRoYXQgY291bGQgYml0ZSDigJQgYSBub24tZXh0ZW5zaWJsZVxuICogdGFyZ2V0IG11c3QgcmVwb3J0IGV4YWN0bHkgaXRzIG93biBrZXlzLCBhbmQgYSBwcm9wZXJ0eSB0aGUgdGFyZ2V0IGxhY2tzXG4gKiBtdXN0IGJlIHJlcG9ydGVkIGNvbmZpZ3VyYWJsZSDigJQgaXMgaG9ub3VyZWQ6IHRoZSBhbGxvd2xpc3QgYWxyZWFkeSByZWZ1c2VzXG4gKiBmcm96ZW4gYW5kIHNlYWxlZCB2YWx1ZXMsIHNvIHRoZSBgcHJldmVudEV4dGVuc2lvbnNgLW9ubHkgY29ybmVyIGFuc3dlcnNcbiAqIGZyb20gdGhlIHRhcmdldCwgYW5kIGEgbGl2ZSBkZXNjcmlwdG9yIGlzIGFsd2F5cyByZXBvcnRlZCBjb25maWd1cmFibGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsaXZlSW5zcGVjdGlvblRyYXBzKFxuICBsaXZlOiAoKSA9PiBvYmplY3QsXG4pOiBQaWNrPFByb3h5SGFuZGxlcjxvYmplY3Q+LCAnaGFzJyB8ICdvd25LZXlzJyB8ICdnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3InPiB7XG4gIHJldHVybiB7XG4gICAgaGFzKHRhcmdldCwgcHJvcCkge1xuICAgICAgcmV0dXJuIFJlZmxlY3QuaGFzKE9iamVjdC5pc0V4dGVuc2libGUodGFyZ2V0KSA/IGxpdmUoKSA6IHRhcmdldCwgcHJvcCk7XG4gICAgfSxcbiAgICBvd25LZXlzKHRhcmdldCkge1xuICAgICAgcmV0dXJuIFJlZmxlY3Qub3duS2V5cyhPYmplY3QuaXNFeHRlbnNpYmxlKHRhcmdldCkgPyBsaXZlKCkgOiB0YXJnZXQpO1xuICAgIH0sXG4gICAgZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHRhcmdldCwgcHJvcCkge1xuICAgICAgaWYgKCFPYmplY3QuaXNFeHRlbnNpYmxlKHRhcmdldCkpIHJldHVybiBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHRhcmdldCwgcHJvcCk7XG4gICAgICBjb25zdCBkZXNjcmlwdG9yID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihsaXZlKCksIHByb3ApO1xuICAgICAgcmV0dXJuIGRlc2NyaXB0b3IgJiYgIWRlc2NyaXB0b3IuY29uZmlndXJhYmxlID8geyAuLi5kZXNjcmlwdG9yLCBjb25maWd1cmFibGU6IHRydWUgfSA6IGRlc2NyaXB0b3I7XG4gICAgfSxcbiAgfTtcbn1cbiJdfQ==
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* reactive/writeTraps — where a proxy's writes LAND, and the two traps that
|
|
3
|
+
* send them there.
|
|
4
|
+
*
|
|
5
|
+
* Every object proxy in this folder (nested, terminal, element) intercepts
|
|
6
|
+
* the same three things — a property set, a property delete, and an array
|
|
7
|
+
* mutation somewhere below it — and differs only in where the write goes:
|
|
8
|
+
* a nested/terminal proxy commits under a TOP-LEVEL KEY (an object write as
|
|
9
|
+
* `merge` of a patch, an array write or a delete as `set` of the rebuilt
|
|
10
|
+
* root); an element proxy commits the WHOLE OWNING ARRAY back through the
|
|
11
|
+
* array proxy's own callback. That difference is a {@link WriteSink}; the
|
|
12
|
+
* traps are written once over it (9.23.1 — the 9.22.0 stale-read bug was
|
|
13
|
+
* fixed in one copy of these traps and then found again in the other two).
|
|
14
|
+
*/
|
|
15
|
+
import type { MemberCache } from './liveView.js';
|
|
16
|
+
/**
|
|
17
|
+
* The seam between a proxy and state. `path` is measured from the sink's
|
|
18
|
+
* root — the key's value for {@link rootKeySink}, the element for
|
|
19
|
+
* {@link elementSink}; `[]` is the root itself.
|
|
20
|
+
*/
|
|
21
|
+
export interface WriteSink {
|
|
22
|
+
/** The value at `path`, as it stands NOW (read-your-writes; never a tracked read). */
|
|
23
|
+
readAt(path: readonly string[]): unknown;
|
|
24
|
+
/** Put an already-unwrapped `value` at `path`. The sink chooses the verb. */
|
|
25
|
+
put(path: readonly string[], value: unknown): void;
|
|
26
|
+
/** Remove the key at `path`. */
|
|
27
|
+
remove(path: readonly string[]): void;
|
|
28
|
+
}
|
|
29
|
+
/** The two ways a value reaches a state key: what the sink writes through. */
|
|
30
|
+
export interface RootKeyTarget {
|
|
31
|
+
setValue(key: string, value: unknown): void;
|
|
32
|
+
updateValue(key: string, value: unknown): void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* WHY: a write below a top-level key has TWO verbs (reactive/README.md, law
|
|
36
|
+
* 3) — an object leaf is a `merge` of a nested patch, an array leaf or a
|
|
37
|
+
* delete rebuilds the root immutably and commits a `set` of the key. Only the
|
|
38
|
+
* sink knows that; the traps do not. Every write drops the key's cached child
|
|
39
|
+
* proxy (`cache`), so the next read is built over the new value.
|
|
40
|
+
*/
|
|
41
|
+
export declare function rootKeySink(target: RootKeyTarget, readSilent: (key: string) => unknown, rootKey: string, cache: Pick<MemberCache, 'delete'>): WriteSink;
|
|
42
|
+
/**
|
|
43
|
+
* WHY: a write inside an array element is an array write — it rebuilds the
|
|
44
|
+
* owning array immutably and hands the WHOLE new array to the array proxy's
|
|
45
|
+
* commit, the funnel `push` already uses. `path` is measured from the
|
|
46
|
+
* element; `[]` is the element slot itself.
|
|
47
|
+
*/
|
|
48
|
+
export declare function elementSink(getCurrent: () => unknown[], commit: (next: unknown[]) => void, index: number): WriteSink;
|
|
49
|
+
/**
|
|
50
|
+
* WHY one set trap: the assigned value is unwrapped HERE (landmine 1 — the
|
|
51
|
+
* JSON round-trip applies to what the caller handed in, never to the
|
|
52
|
+
* surrounding state) and handed to the sink at the proxy's path plus the key.
|
|
53
|
+
*/
|
|
54
|
+
export declare function sinkSetTrap(sink: WriteSink, segments: readonly string[]): ProxyHandler<object>['set'];
|
|
55
|
+
/**
|
|
56
|
+
* WHY one delete trap: `merge` cannot express a removal (a patch of
|
|
57
|
+
* `undefined` reads as absent), so a delete always rebuilds through the sink.
|
|
58
|
+
*/
|
|
59
|
+
export declare function sinkDeleteTrap(sink: WriteSink, segments: readonly string[]): ProxyHandler<object>['deleteProperty'];
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* reactive/writeTraps — where a proxy's writes LAND, and the two traps that
|
|
3
|
+
* send them there.
|
|
4
|
+
*
|
|
5
|
+
* Every object proxy in this folder (nested, terminal, element) intercepts
|
|
6
|
+
* the same three things — a property set, a property delete, and an array
|
|
7
|
+
* mutation somewhere below it — and differs only in where the write goes:
|
|
8
|
+
* a nested/terminal proxy commits under a TOP-LEVEL KEY (an object write as
|
|
9
|
+
* `merge` of a patch, an array write or a delete as `set` of the rebuilt
|
|
10
|
+
* root); an element proxy commits the WHOLE OWNING ARRAY back through the
|
|
11
|
+
* array proxy's own callback. That difference is a {@link WriteSink}; the
|
|
12
|
+
* traps are written once over it (9.23.1 — the 9.22.0 stale-read bug was
|
|
13
|
+
* fixed in one copy of these traps and then found again in the other two).
|
|
14
|
+
*/
|
|
15
|
+
import { nativeGet } from '../memory/pathOps.js';
|
|
16
|
+
import { buildNestedPatch } from './pathBuilder.js';
|
|
17
|
+
import { deleteInPath, setInPath, unwrapProxy } from './structuralWrite.js';
|
|
18
|
+
/**
|
|
19
|
+
* WHY: a write below a top-level key has TWO verbs (reactive/README.md, law
|
|
20
|
+
* 3) — an object leaf is a `merge` of a nested patch, an array leaf or a
|
|
21
|
+
* delete rebuilds the root immutably and commits a `set` of the key. Only the
|
|
22
|
+
* sink knows that; the traps do not. Every write drops the key's cached child
|
|
23
|
+
* proxy (`cache`), so the next read is built over the new value.
|
|
24
|
+
*/
|
|
25
|
+
export function rootKeySink(target, readSilent, rootKey, cache) {
|
|
26
|
+
return new RootKeySink(target, readSilent, rootKey, cache);
|
|
27
|
+
}
|
|
28
|
+
/** One allocation per top-level read miss (the methods live on the prototype). */
|
|
29
|
+
class RootKeySink {
|
|
30
|
+
target;
|
|
31
|
+
readSilent;
|
|
32
|
+
rootKey;
|
|
33
|
+
cache;
|
|
34
|
+
constructor(target, readSilent, rootKey, cache) {
|
|
35
|
+
this.target = target;
|
|
36
|
+
this.readSilent = readSilent;
|
|
37
|
+
this.rootKey = rootKey;
|
|
38
|
+
this.cache = cache;
|
|
39
|
+
}
|
|
40
|
+
/** An empty path is the key's own value — `nativeGet(v, [])` would return it unchanged, so the walk is skipped. */
|
|
41
|
+
readAt(path) {
|
|
42
|
+
const root = this.readSilent(this.rootKey);
|
|
43
|
+
return path.length === 0 ? root : nativeGet(root, path);
|
|
44
|
+
}
|
|
45
|
+
put(path, value) {
|
|
46
|
+
if (!Array.isArray(value))
|
|
47
|
+
this.target.updateValue(this.rootKey, buildNestedPatch(path, value));
|
|
48
|
+
else
|
|
49
|
+
this.target.setValue(this.rootKey, path.length === 0 ? value : setInPath(this.readAt([]), path, value));
|
|
50
|
+
this.cache.delete(this.rootKey);
|
|
51
|
+
}
|
|
52
|
+
remove(path) {
|
|
53
|
+
this.target.setValue(this.rootKey, deleteInPath(this.readAt([]), path));
|
|
54
|
+
this.cache.delete(this.rootKey);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* WHY: a write inside an array element is an array write — it rebuilds the
|
|
59
|
+
* owning array immutably and hands the WHOLE new array to the array proxy's
|
|
60
|
+
* commit, the funnel `push` already uses. `path` is measured from the
|
|
61
|
+
* element; `[]` is the element slot itself.
|
|
62
|
+
*/
|
|
63
|
+
export function elementSink(getCurrent, commit, index) {
|
|
64
|
+
return new ElementSink(getCurrent, commit, index);
|
|
65
|
+
}
|
|
66
|
+
/** One allocation per element proxy (the methods live on the prototype) — a 10k-element loop builds 10k of these. */
|
|
67
|
+
class ElementSink {
|
|
68
|
+
getCurrent;
|
|
69
|
+
commit;
|
|
70
|
+
index;
|
|
71
|
+
constructor(getCurrent, commit, index) {
|
|
72
|
+
this.getCurrent = getCurrent;
|
|
73
|
+
this.commit = commit;
|
|
74
|
+
this.index = index;
|
|
75
|
+
}
|
|
76
|
+
readAt(path) {
|
|
77
|
+
return readInElement(this.getCurrent, this.index, path);
|
|
78
|
+
}
|
|
79
|
+
put(path, value) {
|
|
80
|
+
replaceInElement(this.getCurrent, this.commit, this.index, path, value);
|
|
81
|
+
}
|
|
82
|
+
remove(path) {
|
|
83
|
+
removeInElement(this.getCurrent, this.commit, this.index, path);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** The value at `path` inside element `index`, as it stands NOW (read-your-writes). */
|
|
87
|
+
function readInElement(getCurrent, index, path) {
|
|
88
|
+
const element = getCurrent()[index];
|
|
89
|
+
return path.length === 0 ? element : nativeGet(element, path);
|
|
90
|
+
}
|
|
91
|
+
/** A copy of the array with `value` at `path` inside element `index`; a gone element has nothing to write into. */
|
|
92
|
+
function replaceInElement(getCurrent, commit, index, path, value) {
|
|
93
|
+
const next = [...getCurrent()];
|
|
94
|
+
if (index >= next.length)
|
|
95
|
+
return;
|
|
96
|
+
next[index] = path.length === 0 ? value : setInPath(next[index], path, value);
|
|
97
|
+
commit(next);
|
|
98
|
+
}
|
|
99
|
+
/** A copy of the array with the key at `path` inside element `index` removed. */
|
|
100
|
+
function removeInElement(getCurrent, commit, index, path) {
|
|
101
|
+
const next = [...getCurrent()];
|
|
102
|
+
if (index >= next.length)
|
|
103
|
+
return;
|
|
104
|
+
next[index] = deleteInPath(next[index], path);
|
|
105
|
+
commit(next);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* WHY one set trap: the assigned value is unwrapped HERE (landmine 1 — the
|
|
109
|
+
* JSON round-trip applies to what the caller handed in, never to the
|
|
110
|
+
* surrounding state) and handed to the sink at the proxy's path plus the key.
|
|
111
|
+
*/
|
|
112
|
+
export function sinkSetTrap(sink, segments) {
|
|
113
|
+
return (_target, prop, value) => {
|
|
114
|
+
if (typeof prop !== 'string')
|
|
115
|
+
return true;
|
|
116
|
+
sink.put([...segments, prop], unwrapProxy(value));
|
|
117
|
+
return true;
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* WHY one delete trap: `merge` cannot express a removal (a patch of
|
|
122
|
+
* `undefined` reads as absent), so a delete always rebuilds through the sink.
|
|
123
|
+
*/
|
|
124
|
+
export function sinkDeleteTrap(sink, segments) {
|
|
125
|
+
return (_target, prop) => {
|
|
126
|
+
if (typeof prop !== 'string')
|
|
127
|
+
return true;
|
|
128
|
+
sink.remove([...segments, prop]);
|
|
129
|
+
return true;
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid3JpdGVUcmFwcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvcmVhY3RpdmUvd3JpdGVUcmFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7OztHQWFHO0FBRUgsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBRWpELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxZQUFZLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBc0I1RTs7Ozs7O0dBTUc7QUFDSCxNQUFNLFVBQVUsV0FBVyxDQUN6QixNQUFxQixFQUNyQixVQUFvQyxFQUNwQyxPQUFlLEVBQ2YsS0FBa0M7SUFFbEMsT0FBTyxJQUFJLFdBQVcsQ0FBQyxNQUFNLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQztBQUM3RCxDQUFDO0FBRUQsa0ZBQWtGO0FBQ2xGLE1BQU0sV0FBVztJQUVJO0lBQ0E7SUFDQTtJQUNBO0lBSm5CLFlBQ21CLE1BQXFCLEVBQ3JCLFVBQW9DLEVBQ3BDLE9BQWUsRUFDZixLQUFrQztRQUhsQyxXQUFNLEdBQU4sTUFBTSxDQUFlO1FBQ3JCLGVBQVUsR0FBVixVQUFVLENBQTBCO1FBQ3BDLFlBQU8sR0FBUCxPQUFPLENBQVE7UUFDZixVQUFLLEdBQUwsS0FBSyxDQUE2QjtJQUNsRCxDQUFDO0lBRUosbUhBQW1IO0lBQ25ILE1BQU0sQ0FBQyxJQUF1QjtRQUM1QixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMzQyxPQUFPLElBQUksQ0FBQyxNQUFNLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUUsSUFBZ0IsQ0FBQyxDQUFDO0lBQ3RFLENB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Q0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLFFBQVEsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQ2pDLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQyxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogcmVhY3RpdmUvd3JpdGVUcmFwcyDigJQgd2hlcmUgYSBwcm94eSdzIHdyaXRlcyBMQU5ELCBhbmQgdGhlIHR3byB0cmFwcyB0aGF0XG4gKiBzZW5kIHRoZW0gdGhlcmUuXG4gKlxuICogRXZlcnkgb2JqZWN0IHByb3h5IGluIHRoaXMgZm9sZGVyIChuZXN0ZWQsIHRlcm1pbmFsLCBlbGVtZW50KSBpbnRlcmNlcHRzXG4gKiB0aGUgc2FtZSB0aHJlZSB0aGluZ3Mg4oCUIGEgcHJvcGVydHkgc2V0LCBhIHByb3BlcnR5IGRlbGV0ZSwgYW5kIGFuIGFycmF5XG4gKiBtdXRhdGlvbiBzb21ld2hlcmUgYmVsb3cgaXQg4oCUIGFuZCBkaWZmZXJzIG9ubHkgaW4gd2hlcmUgdGhlIHdyaXRlIGdvZXM6XG4gKiBhIG5lc3RlZC90ZXJtaW5hbCBwcm94eSBjb21taXRzIHVuZGVyIGEgVE9QLUxFVkVMIEtFWSAoYW4gb2JqZWN0IHdyaXRlIGFzXG4gKiBgbWVyZ2VgIG9mIGEgcGF0Y2gsIGFuIGFycmF5IHdyaXRlIG9yIGEgZGVsZXRlIGFzIGBzZXRgIG9mIHRoZSByZWJ1aWx0XG4gKiByb290KTsgYW4gZWxlbWVudCBwcm94eSBjb21taXRzIHRoZSBXSE9MRSBPV05JTkcgQVJSQVkgYmFjayB0aHJvdWdoIHRoZVxuICogYXJyYXkgcHJveHkncyBvd24gY2FsbGJhY2suIFRoYXQgZGlmZmVyZW5jZSBpcyBhIHtAbGluayBXcml0ZVNpbmt9OyB0aGVcbiAqIHRyYXBzIGFyZSB3cml0dGVuIG9uY2Ugb3ZlciBpdCAoOS4yMy4xIOKAlCB0aGUgOS4yMi4wIHN0YWxlLXJlYWQgYnVnIHdhc1xuICogZml4ZWQgaW4gb25lIGNvcHkgb2YgdGhlc2UgdHJhcHMgYW5kIHRoZW4gZm91bmQgYWdhaW4gaW4gdGhlIG90aGVyIHR3bykuXG4gKi9cblxuaW1wb3J0IHsgbmF0aXZlR2V0IH0gZnJvbSAnLi4vbWVtb3J5L3BhdGhPcHMuanMnO1xuaW1wb3J0IHR5cGUgeyBNZW1iZXJDYWNoZSB9IGZyb20gJy4vbGl2ZVZpZXcuanMnO1xuaW1wb3J0IHsgYnVpbGROZXN0ZWRQYXRjaCB9IGZyb20gJy4vcGF0aEJ1aWxkZXIuanMnO1xuaW1wb3J0IHsgZGVsZXRlSW5QYXRoLCBzZXRJblBhdGgsIHVud3JhcFByb3h5IH0gZnJvbSAnLi9zdHJ1Y3R1cmFsV3JpdGUuanMnO1xuXG4vKipcbiAqIFRoZSBzZWFtIGJldHdlZW4gYSBwcm94eSBhbmQgc3RhdGUuIGBwYXRoYCBpcyBtZWFzdXJlZCBmcm9tIHRoZSBzaW5rJ3NcbiAqIHJvb3Qg4oCUIHRoZSBrZXkncyB2YWx1ZSBmb3Ige0BsaW5rIHJvb3RLZXlTaW5rfSwgdGhlIGVsZW1lbnQgZm9yXG4gKiB7QGxpbmsgZWxlbWVudFNpbmt9OyBgW11gIGlzIHRoZSByb290IGl0c2VsZi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBXcml0ZVNpbmsge1xuICAvKiogVGhlIHZhbHVlIGF0IGBwYXRoYCwgYXMgaXQgc3RhbmRzIE5PVyAocmVhZC15b3VyLXdyaXRlczsgbmV2ZXIgYSB0cmFja2VkIHJlYWQpLiAqL1xuICByZWFkQXQocGF0aDogcmVhZG9ubHkgc3RyaW5nW10pOiB1bmtub3duO1xuICAvKiogUHV0IGFuIGFscmVhZHktdW53cmFwcGVkIGB2YWx1ZWAgYXQgYHBhdGhgLiBUaGUgc2luayBjaG9vc2VzIHRoZSB2ZXJiLiAqL1xuICBwdXQocGF0aDogcmVhZG9ubHkgc3RyaW5nW10sIHZhbHVlOiB1bmtub3duKTogdm9pZDtcbiAgLyoqIFJlbW92ZSB0aGUga2V5IGF0IGBwYXRoYC4gKi9cbiAgcmVtb3ZlKHBhdGg6IHJlYWRvbmx5IHN0cmluZ1tdKTogdm9pZDtcbn1cblxuLyoqIFRoZSB0d28gd2F5cyBhIHZhbHVlIHJlYWNoZXMgYSBzdGF0ZSBrZXk6IHdoYXQgdGhlIHNpbmsgd3JpdGVzIHRocm91Z2guICovXG5leHBvcnQgaW50ZXJmYWNlIFJvb3RLZXlUYXJnZXQge1xuICBzZXRWYWx1ZShrZXk6IHN0cmluZywgdmFsdWU6IHVua25vd24pOiB2b2lkO1xuICB1cGRhdGVWYWx1ZShrZXk6IHN0cmluZywgdmFsdWU6IHVua25vd24pOiB2b2lkO1xufVxuXG4vKipcbiAqIFdIWTogYSB3cml0ZSBiZWxvdyBhIHRvcC1sZXZlbCBrZXkgaGFzIFRXTyB2ZXJicyAocmVhY3RpdmUvUkVBRE1FLm1kLCBsYXdcbiAqIDMpIOKAlCBhbiBvYmplY3QgbGVhZiBpcyBhIGBtZXJnZWAgb2YgYSBuZXN0ZWQgcGF0Y2gsIGFuIGFycmF5IGxlYWYgb3IgYVxuICogZGVsZXRlIHJlYnVpbGRzIHRoZSByb290IGltbXV0YWJseSBhbmQgY29tbWl0cyBhIGBzZXRgIG9mIHRoZSBrZXkuIE9ubHkgdGhlXG4gKiBzaW5rIGtub3dzIHRoYXQ7IHRoZSB0cmFwcyBkbyBub3QuIEV2ZXJ5IHdyaXRlIGRyb3BzIHRoZSBrZXkncyBjYWNoZWQgY2hpbGRcbiAqIHByb3h5IChgY2FjaGVgKSwgc28gdGhlIG5leHQgcmVhZCBpcyBidWlsdCBvdmVyIHRoZSBuZXcgdmFsdWUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByb290S2V5U2luayhcbiAgdGFyZ2V0OiBSb290S2V5VGFyZ2V0LFxuICByZWFkU2lsZW50OiAoa2V5OiBzdHJpbmcpID0+IHVua25vd24sXG4gIHJvb3RLZXk6IHN0cmluZyxcbiAgY2FjaGU6IFBpY2s8TWVtYmVyQ2FjaGUsICdkZWxldGUnPixcbik6IFdyaXRlU2luayB7XG4gIHJldHVybiBuZXcgUm9vdEtleVNpbmsodGFyZ2V0LCByZWFkU2lsZW50LCByb290S2V5LCBjYWNoZSk7XG59XG5cbi8qKiBPbmUgYWxsb2NhdGlvbiBwZXIgdG9wLWxldmVsIHJlYWQgbWlzcyAodGhlIG1ldGhvZHMgbGl2ZSBvbiB0aGUgcHJvdG90eXBlKS4gKi9cbmNsYXNzIFJvb3RLZXlTaW5rIGltcGxlbWVudHMgV3JpdGVTaW5rIHtcbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSB0YXJnZXQ6IFJvb3RLZXlUYXJnZXQsXG4gICAgcHJpdmF0ZSByZWFkb25seSByZWFkU2lsZW50OiAoa2V5OiBzdHJpbmcpID0+IHVua25vd24sXG4gICAgcHJpdmF0ZSByZWFkb25seSByb290S2V5OiBzdHJpbmcsXG4gICAgcHJpdmF0ZSByZWFkb25seSBjYWNoZTogUGljazxNZW1iZXJDYWNoZSwgJ2RlbGV0ZSc+LFxuICApIHt9XG5cbiAgLyoqIEFuIGVtcHR5IHBhdGggaXMgdGhlIGtleSdzIG93biB2YWx1ZSDigJQgYG5hdGl2ZUdldCh2LCBbXSlgIHdvdWxkIHJldHVybiBpdCB1bmNoYW5nZWQsIHNvIHRoZSB3YWxrIGlzIHNraXBwZWQuICovXG4gIHJlYWRBdChwYXRoOiByZWFkb25seSBzdHJpbmdbXSk6IHVua25vd24ge1xuICAgIGNvbnN0IHJvb3QgPSB0aGlzLnJlYWRTaWxlbnQodGhpcy5yb290S2V5KTtcbiAgICByZXR1cm4gcGF0aC5sZW5ndGggPT09IDAgPyByb290IDogbmF0aXZlR2V0KHJvb3QsIHBhdGggYXMgc3RyaW5nW10pO1xuICB9XG5cbiAgcHV0KHBhdGg6IHJlYWRvbmx5IHN0cmluZ1tdLCB2YWx1ZTogdW5rbm93bik6IHZvaWQge1xuICAgIGlmICghQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHRoaXMudGFyZ2V0LnVwZGF0ZVZhbHVlKHRoaXMucm9vdEtleSwgYnVpbGROZXN0ZWRQYXRjaChwYXRoIGFzIHN0cmluZ1tdLCB2YWx1ZSkpO1xuICAgIGVsc2UgdGhpcy50YXJnZXQuc2V0VmFsdWUodGhpcy5yb290S2V5LCBwYXRoLmxlbmd0aCA9PT0gMCA/IHZhbHVlIDogc2V0SW5QYXRoKHRoaXMucmVhZEF0KFtdKSwgcGF0aCwgdmFsdWUpKTtcbiAgICB0aGlzLmNhY2hlLmRlbGV0ZSh0aGlzLnJvb3RLZXkpO1xuICB9XG5cbiAgcmVtb3ZlKHBhdGg6IHJlYWRvbmx5IHN0cmluZ1tdKTogdm9pZCB7XG4gICAgdGhpcy50YXJnZXQuc2V0VmFsdWUodGhpcy5yb290S2V5LCBkZWxldGVJblBhdGgodGhpcy5yZWFkQXQoW10pLCBwYXRoKSk7XG4gICAgdGhpcy5jYWNoZS5kZWxldGUodGhpcy5yb290S2V5KTtcbiAgfVxufVxuXG4vKipcbiAqIFdIWTogYSB3cml0ZSBpbnNpZGUgYW4gYXJyYXkgZWxlbWVudCBpcyBhbiBhcnJheSB3cml0ZSDigJQgaXQgcmVidWlsZHMgdGhlXG4gKiBvd25pbmcgYXJyYXkgaW1tdXRhYmx5IGFuZCBoYW5kcyB0aGUgV0hPTEUgbmV3IGFycmF5IHRvIHRoZSBhcnJheSBwcm94eSdzXG4gKiBjb21taXQsIHRoZSBmdW5uZWwgYHB1c2hgIGFscmVhZHkgdXNlcy4gYHBhdGhgIGlzIG1lYXN1cmVkIGZyb20gdGhlXG4gKiBlbGVtZW50OyBgW11gIGlzIHRoZSBlbGVtZW50IHNsb3QgaXRzZWxmLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZWxlbWVudFNpbmsoZ2V0Q3VycmVudDogKCkgPT4gdW5rbm93bltdLCBjb21taXQ6IChuZXh0OiB1bmtub3duW10pID0+IHZvaWQsIGluZGV4OiBudW1iZXIpOiBXcml0ZVNpbmsge1xuICByZXR1cm4gbmV3IEVsZW1lbnRTaW5rKGdldEN1cnJlbnQsIGNvbW1pdCwgaW5kZXgpO1xufVxuXG4vKiogT25lIGFsbG9jYXRpb24gcGVyIGVsZW1lbnQgcHJveHkgKHRoZSBtZXRob2RzIGxpdmUgb24gdGhlIHByb3RvdHlwZSkg4oCUIGEgMTBrLWVsZW1lbnQgbG9vcCBidWlsZHMgMTBrIG9mIHRoZXNlLiAqL1xuY2xhc3MgRWxlbWVudFNpbmsgaW1wbGVtZW50cyBXcml0ZVNpbmsge1xuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IGdldEN1cnJlbnQ6ICgpID0+IHVua25vd25bXSxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGNvbW1pdDogKG5leHQ6IHVua25vd25bXSkgPT4gdm9pZCxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGluZGV4OiBudW1iZXIsXG4gICkge31cblxuICByZWFkQXQocGF0aDogcmVhZG9ubHkgc3RyaW5nW10pOiB1bmtub3duIHtcbiAgICByZXR1cm4gcmVhZEluRWxlbWVudCh0aGlzLmdldEN1cnJlbnQsIHRoaXMuaW5kZXgsIHBhdGgpO1xuICB9XG5cbiAgcHV0KHBhdGg6IHJlYWRvbmx5IHN0cmluZ1tdLCB2YWx1ZTogdW5rbm93bik6IHZvaWQge1xuICAgIHJlcGxhY2VJbkVsZW1lbnQodGhpcy5nZXRDdXJyZW50LCB0aGlzLmNvbW1pdCwgdGhpcy5pbmRleCwgcGF0aCwgdmFsdWUpO1xuICB9XG5cbiAgcmVtb3ZlKHBhdGg6IHJlYWRvbmx5IHN0cmluZ1tdKTogdm9pZCB7XG4gICAgcmVtb3ZlSW5FbGVtZW50KHRoaXMuZ2V0Q3VycmVudCwgdGhpcy5jb21taXQsIHRoaXMuaW5kZXgsIHBhdGgpO1xuICB9XG59XG5cbi8qKiBUaGUgdmFsdWUgYXQgYHBhdGhgIGluc2lkZSBlbGVtZW50IGBpbmRleGAsIGFzIGl0IHN0YW5kcyBOT1cgKHJlYWQteW91ci13cml0ZXMpLiAqL1xuZnVuY3Rpb24gcmVhZEluRWxlbWVudChnZXRDdXJyZW50OiAoKSA9PiB1bmtub3duW10sIGluZGV4OiBudW1iZXIsIHBhdGg6IHJlYWRvbmx5IHN0cmluZ1tdKTogdW5rbm93biB7XG4gIGNvbnN0IGVsZW1lbnQgPSBnZXRDdXJyZW50KClbaW5kZXhdO1xuICByZXR1cm4gcGF0aC5sZW5ndGggPT09IDAgPyBlbGVtZW50IDogbmF0aXZlR2V0KGVsZW1lbnQsIHBhdGggYXMgc3RyaW5nW10pO1xufVxuXG4vKiogQSBjb3B5IG9mIHRoZSBhcnJheSB3aXRoIGB2YWx1ZWAgYXQgYHBhdGhgIGluc2lkZSBlbGVtZW50IGBpbmRleGA7IGEgZ29uZSBlbGVtZW50IGhhcyBub3RoaW5nIHRvIHdyaXRlIGludG8uICovXG5mdW5jdGlvbiByZXBsYWNlSW5FbGVtZW50KFxuICBnZXRDdXJyZW50OiAoKSA9PiB1bmtub3duW10sXG4gIGNvbW1pdDogKG5leHQ6IHVua25vd25bXSkgPT4gdm9pZCxcbiAgaW5kZXg6IG51bWJlcixcbiAgcGF0aDogcmVhZG9ubHkgc3RyaW5nW10sXG4gIHZhbHVlOiB1bmtub3duLFxuKTogdm9pZCB7XG4gIGNvbnN0IG5leHQgPSBbLi4uZ2V0Q3VycmVudCgpXTtcbiAgaWYgKGluZGV4ID49IG5leHQubGVuZ3RoKSByZXR1cm47XG4gIG5leHRbaW5kZXhdID0gcGF0aC5sZW5ndGggPT09IDAgPyB2YWx1ZSA6IHNldEluUGF0aChuZXh0W2luZGV4XSwgcGF0aCwgdmFsdWUpO1xuICBjb21taXQobmV4dCk7XG59XG5cbi8qKiBBIGNvcHkgb2YgdGhlIGFycmF5IHdpdGggdGhlIGtleSBhdCBgcGF0aGAgaW5zaWRlIGVsZW1lbnQgYGluZGV4YCByZW1vdmVkLiAqL1xuZnVuY3Rpb24gcmVtb3ZlSW5FbGVtZW50KFxuICBnZXRDdXJyZW50OiAoKSA9PiB1bmtub3duW10sXG4gIGNvbW1pdDogKG5leHQ6IHVua25vd25bXSkgPT4gdm9pZCxcbiAgaW5kZXg6IG51bWJlcixcbiAgcGF0aDogcmVhZG9ubHkgc3RyaW5nW10sXG4pOiB2b2lkIHtcbiAgY29uc3QgbmV4dCA9IFsuLi5nZXRDdXJyZW50KCldO1xuICBpZiAoaW5kZXggPj0gbmV4dC5sZW5ndGgpIHJldHVybjtcbiAgbmV4dFtpbmRleF0gPSBkZWxldGVJblBhdGgobmV4dFtpbmRleF0sIHBhdGgpO1xuICBjb21taXQobmV4dCk7XG59XG5cbi8qKlxuICogV0hZIG9uZSBzZXQgdHJhcDogdGhlIGFzc2lnbmVkIHZhbHVlIGlzIHVud3JhcHBlZCBIRVJFIChsYW5kbWluZSAxIOKAlCB0aGVcbiAqIEpTT04gcm91bmQtdHJpcCBhcHBsaWVzIHRvIHdoYXQgdGhlIGNhbGxlciBoYW5kZWQgaW4sIG5ldmVyIHRvIHRoZVxuICogc3Vycm91bmRpbmcgc3RhdGUpIGFuZCBoYW5kZWQgdG8gdGhlIHNpbmsgYXQgdGhlIHByb3h5J3MgcGF0aCBwbHVzIHRoZSBrZXkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzaW5rU2V0VHJhcChzaW5rOiBXcml0ZVNpbmssIHNlZ21lbnRzOiByZWFkb25seSBzdHJpbmdbXSk6IFByb3h5SGFuZGxlcjxvYmplY3Q+WydzZXQnXSB7XG4gIHJldHVybiAoX3RhcmdldCwgcHJvcCwgdmFsdWUpID0+IHtcbiAgICBpZiAodHlwZW9mIHByb3AgIT09ICdzdHJpbmcnKSByZXR1cm4gdHJ1ZTtcbiAgICBzaW5rLnB1dChbLi4uc2VnbWVudHMsIHByb3BdLCB1bndyYXBQcm94eSh2YWx1ZSkpO1xuICAgIHJldHVybiB0cnVlO1xuICB9O1xufVxuXG4vKipcbiAqIFdIWSBvbmUgZGVsZXRlIHRyYXA6IGBtZXJnZWAgY2Fubm90IGV4cHJlc3MgYSByZW1vdmFsIChhIHBhdGNoIG9mXG4gKiBgdW5kZWZpbmVkYCByZWFkcyBhcyBhYnNlbnQpLCBzbyBhIGRlbGV0ZSBhbHdheXMgcmVidWlsZHMgdGhyb3VnaCB0aGUgc2luay5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNpbmtEZWxldGVUcmFwKHNpbms6IFdyaXRlU2luaywgc2VnbWVudHM6IHJlYWRvbmx5IHN0cmluZ1tdKTogUHJveHlIYW5kbGVyPG9iamVjdD5bJ2RlbGV0ZVByb3BlcnR5J10ge1xuICByZXR1cm4gKF90YXJnZXQsIHByb3ApID0+IHtcbiAgICBpZiAodHlwZW9mIHByb3AgIT09ICdzdHJpbmcnKSByZXR1cm4gdHJ1ZTtcbiAgICBzaW5rLnJlbW92ZShbLi4uc2VnbWVudHMsIHByb3BdKTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfTtcbn1cbiJdfQ==
|