react-deepwatch 1.0.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/LICENSE +21 -0
- package/Util.d.ts +66 -0
- package/Util.d.ts.map +1 -0
- package/Util.js +178 -0
- package/Util.js.map +1 -0
- package/Util.ts +190 -0
- package/dist/mjs/Util.d.ts +66 -0
- package/dist/mjs/Util.d.ts.map +1 -0
- package/dist/mjs/Util.js +164 -0
- package/dist/mjs/Util.js.map +1 -0
- package/dist/mjs/index.d.ts +218 -0
- package/dist/mjs/index.d.ts.map +1 -0
- package/dist/mjs/index.js +821 -0
- package/dist/mjs/index.js.map +1 -0
- package/dist/mjs/preserve.d.ts +72 -0
- package/dist/mjs/preserve.d.ts.map +1 -0
- package/dist/mjs/preserve.js +374 -0
- package/dist/mjs/preserve.js.map +1 -0
- package/index.d.ts +218 -0
- package/index.d.ts.map +1 -0
- package/index.js +830 -0
- package/index.js.map +1 -0
- package/index.ts +1237 -0
- package/index_esm.mjs +6 -0
- package/mechanics.md +47 -0
- package/package.json +59 -0
- package/preserve.d.ts +72 -0
- package/preserve.d.ts.map +1 -0
- package/preserve.js +385 -0
- package/preserve.js.map +1 -0
- package/preserve.ts +492 -0
- package/readme.md +109 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-present Boris Gingold
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/Util.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { RecordedRead } from "proxy-facades";
|
|
2
|
+
export declare function throwError(e: string | Error): void;
|
|
3
|
+
export declare function reThrowWithHint(e: unknown, hint: string): void;
|
|
4
|
+
export declare function isObject(value: unknown): value is object;
|
|
5
|
+
/**
|
|
6
|
+
* A Map<K, Set<V>>. But automatically add a new Set if needed
|
|
7
|
+
*/
|
|
8
|
+
export declare class MapSet<K, V> {
|
|
9
|
+
map: Map<K, Set<V>>;
|
|
10
|
+
add(key: K, value: V): void;
|
|
11
|
+
delete(key: K, value: V): void;
|
|
12
|
+
get(key: K): Set<V> | undefined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A WeakMap<K, Set<V>>. But automatically add a new Set if needed
|
|
16
|
+
*/
|
|
17
|
+
export declare class WeakMapSet<K, V> extends MapSet<K, V> {
|
|
18
|
+
map: WeakMap<K, Set<V>>;
|
|
19
|
+
}
|
|
20
|
+
export declare function arraysAreEqualsByPredicateFn<A, B>(a: A[], b: B[], equalsFn: (a: A, b: B) => boolean): boolean;
|
|
21
|
+
export type PromiseState<T> = {
|
|
22
|
+
state: "pending";
|
|
23
|
+
promise: Promise<T>;
|
|
24
|
+
} | {
|
|
25
|
+
state: "resolved";
|
|
26
|
+
resolvedValue: T;
|
|
27
|
+
} | {
|
|
28
|
+
state: "rejected";
|
|
29
|
+
rejectReason: any;
|
|
30
|
+
};
|
|
31
|
+
type VisitReplaceContext = {
|
|
32
|
+
/**
|
|
33
|
+
* Not safely escaped. Should be used for diag only !
|
|
34
|
+
*/
|
|
35
|
+
diagnosis_path?: string;
|
|
36
|
+
parentObject?: object;
|
|
37
|
+
key?: unknown;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Usage:
|
|
41
|
+
* <pre><code>
|
|
42
|
+
* const result = visitReplace(target, (value, visitChilds, context) => {
|
|
43
|
+
* return value === 'needle' ? 'replaced' : visitChilds(value, context)
|
|
44
|
+
* });
|
|
45
|
+
* </code></pre>
|
|
46
|
+
*
|
|
47
|
+
* @param value
|
|
48
|
+
* @param visitor
|
|
49
|
+
* @param trackPath whether to pass on the context object. This hurts performance because the path is concatted every time, so use it only when needed. Setting this to "onError" re-executes the visitprelace with the concetxt when an error was thrown
|
|
50
|
+
*/
|
|
51
|
+
export declare function visitReplace<O>(value: O, visitor: (value: unknown, visitChilds: (value: unknown, context: VisitReplaceContext) => unknown, context: VisitReplaceContext) => unknown, trackPath?: boolean | "onError"): O;
|
|
52
|
+
/**
|
|
53
|
+
* Just do something the runtime can't optimize away
|
|
54
|
+
* @param value
|
|
55
|
+
*/
|
|
56
|
+
export declare function read(value: any): void;
|
|
57
|
+
export declare function arraysAreShallowlyEqual(a: unknown[], b: unknown[]): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Like arraysAreShallowlyEqual but this time for an array of entries (tuple of 2 values) like from Map#entries()
|
|
60
|
+
* @param a
|
|
61
|
+
* @param b
|
|
62
|
+
*/
|
|
63
|
+
export declare function arraysWithEntriesAreShallowlyEqual(a: Array<[unknown, unknown]>, b: Array<[unknown, unknown]>): boolean;
|
|
64
|
+
export declare function recordedReadsArraysAreEqual(a: RecordedRead[], b: RecordedRead[]): boolean;
|
|
65
|
+
export {};
|
|
66
|
+
//# sourceMappingURL=Util.d.ts.map
|
package/Util.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Util.d.ts","sourceRoot":"","sources":["Util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,eAAe,CAAC;AAE3C,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,KAAK,QAK3C;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,QAUvD;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,mBAEtC;AAED;;GAEG;AACH,qBAAa,MAAM,CAAC,CAAC,EAAE,CAAC;IACpB,GAAG,iBAAuB;IAE1B,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC;IASpB,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC;IAUvB,GAAG,CAAC,GAAG,EAAE,CAAC;CAGb;AAED;;GAEG;AACH,qBAAa,UAAU,CAAC,CAAC,EAAE,CAAC,CAAE,SAAQ,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;IAE9C,GAAG,qBAA4B;CAClC;AAED,wBAAgB,4BAA4B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAC,CAAC,EAAE,CAAC,KAAK,OAAO,WAUlG;AACD,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;IAAC,KAAK,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;CAAC,GAAG;IAAC,KAAK,EAAE,UAAU,CAAC;IAAC,aAAa,EAAE,CAAC,CAAA;CAAC,GAAG;IAAC,KAAK,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,GAAG,CAAA;CAAC,CAAC;AAGvJ,KAAK,mBAAmB,GAAG;IACvB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IAEvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,GAAG,CAAC,EAAE,OAAO,CAAA;CAChB,CAAA;AASD;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,KAAK,OAAO,EAAE,OAAO,EAAE,mBAAmB,KAAK,OAAO,EAAG,SAAS,GAAE,OAAO,GAAG,SAAiB,GAAG,CAAC,CAqChO;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,GAAG,QAI9B;AAED,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,WAUjE;AAED;;;;GAIG;AACH,wBAAgB,kCAAkC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,WAa5G;AAED,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,CAAC,EAAE,YAAY,EAAE,WAE/E"}
|
package/Util.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WeakMapSet = exports.MapSet = void 0;
|
|
4
|
+
exports.throwError = throwError;
|
|
5
|
+
exports.reThrowWithHint = reThrowWithHint;
|
|
6
|
+
exports.isObject = isObject;
|
|
7
|
+
exports.arraysAreEqualsByPredicateFn = arraysAreEqualsByPredicateFn;
|
|
8
|
+
exports.visitReplace = visitReplace;
|
|
9
|
+
exports.read = read;
|
|
10
|
+
exports.arraysAreShallowlyEqual = arraysAreShallowlyEqual;
|
|
11
|
+
exports.arraysWithEntriesAreShallowlyEqual = arraysWithEntriesAreShallowlyEqual;
|
|
12
|
+
exports.recordedReadsArraysAreEqual = recordedReadsArraysAreEqual;
|
|
13
|
+
function throwError(e) {
|
|
14
|
+
if (e !== null && e instanceof Error) {
|
|
15
|
+
throw e;
|
|
16
|
+
}
|
|
17
|
+
throw new Error(e);
|
|
18
|
+
}
|
|
19
|
+
function reThrowWithHint(e, hint) {
|
|
20
|
+
try {
|
|
21
|
+
if (e instanceof Error) {
|
|
22
|
+
// Add hint to error:
|
|
23
|
+
e.message += `\n${hint}`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch (x) {
|
|
27
|
+
}
|
|
28
|
+
throw e;
|
|
29
|
+
}
|
|
30
|
+
function isObject(value) {
|
|
31
|
+
return value !== null && typeof value === "object";
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A Map<K, Set<V>>. But automatically add a new Set if needed
|
|
35
|
+
*/
|
|
36
|
+
class MapSet {
|
|
37
|
+
constructor() {
|
|
38
|
+
this.map = new Map();
|
|
39
|
+
}
|
|
40
|
+
add(key, value) {
|
|
41
|
+
let set = this.map.get(key);
|
|
42
|
+
if (set === undefined) {
|
|
43
|
+
set = new Set();
|
|
44
|
+
this.map.set(key, set);
|
|
45
|
+
}
|
|
46
|
+
set.add(value);
|
|
47
|
+
}
|
|
48
|
+
delete(key, value) {
|
|
49
|
+
let set = this.map.get(key);
|
|
50
|
+
if (set !== undefined) {
|
|
51
|
+
set.delete(value);
|
|
52
|
+
if (set.size === 0) {
|
|
53
|
+
this.map.delete(key); // Clean up
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
get(key) {
|
|
58
|
+
return this.map.get(key);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.MapSet = MapSet;
|
|
62
|
+
/**
|
|
63
|
+
* A WeakMap<K, Set<V>>. But automatically add a new Set if needed
|
|
64
|
+
*/
|
|
65
|
+
class WeakMapSet extends MapSet {
|
|
66
|
+
constructor() {
|
|
67
|
+
super(...arguments);
|
|
68
|
+
//@ts-ignore
|
|
69
|
+
this.map = new WeakMap();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.WeakMapSet = WeakMapSet;
|
|
73
|
+
function arraysAreEqualsByPredicateFn(a, b, equalsFn) {
|
|
74
|
+
if (a.length !== b.length) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
for (const k in a) {
|
|
78
|
+
if (!equalsFn(a[k], b[k])) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
function diagnosis_jsonPath(key) {
|
|
85
|
+
if (!Number.isNaN(Number(key))) {
|
|
86
|
+
return `[${key}]`;
|
|
87
|
+
}
|
|
88
|
+
return `.${key}`;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Usage:
|
|
92
|
+
* <pre><code>
|
|
93
|
+
* const result = visitReplace(target, (value, visitChilds, context) => {
|
|
94
|
+
* return value === 'needle' ? 'replaced' : visitChilds(value, context)
|
|
95
|
+
* });
|
|
96
|
+
* </code></pre>
|
|
97
|
+
*
|
|
98
|
+
* @param value
|
|
99
|
+
* @param visitor
|
|
100
|
+
* @param trackPath whether to pass on the context object. This hurts performance because the path is concatted every time, so use it only when needed. Setting this to "onError" re-executes the visitprelace with the concetxt when an error was thrown
|
|
101
|
+
*/
|
|
102
|
+
function visitReplace(value, visitor, trackPath = false) {
|
|
103
|
+
const visisitedObjects = new Set();
|
|
104
|
+
function visitChilds(value, context) {
|
|
105
|
+
if (value === null) {
|
|
106
|
+
return value;
|
|
107
|
+
}
|
|
108
|
+
else if (typeof value === "object") {
|
|
109
|
+
const obj = value;
|
|
110
|
+
if (visisitedObjects.has(obj)) {
|
|
111
|
+
return value; // don't iterate again
|
|
112
|
+
}
|
|
113
|
+
visisitedObjects.add(obj);
|
|
114
|
+
for (let k in obj) {
|
|
115
|
+
const keyInParent = k;
|
|
116
|
+
const childValue = obj[keyInParent];
|
|
117
|
+
let newValue = visitor(childValue, visitChilds, Object.assign(Object.assign({}, context), { parentObject: value, key: keyInParent, diagnosis_path: (context.diagnosis_path !== undefined ? `${context.diagnosis_path}${diagnosis_jsonPath(keyInParent)}` : undefined) }));
|
|
118
|
+
if (newValue !== childValue) { // Only if childValue really has changed. We don't want to interfer with setting a readonly property and trigger a proxy
|
|
119
|
+
// @ts-ignore
|
|
120
|
+
obj[keyInParent] = newValue;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
if (trackPath === "onError") {
|
|
127
|
+
try {
|
|
128
|
+
return visitor(value, visitChilds, {}); // Fast try without context
|
|
129
|
+
}
|
|
130
|
+
catch (e) {
|
|
131
|
+
return visitReplace(value, visitor, true); // Try again with context
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return visitor(value, visitChilds, { diagnosis_path: trackPath ? "" : undefined });
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Just do something the runtime can't optimize away
|
|
138
|
+
* @param value
|
|
139
|
+
*/
|
|
140
|
+
function read(value) {
|
|
141
|
+
if (("" + value) == "blaaxyxzzzsdf") {
|
|
142
|
+
throw new Error("should never get here");
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function arraysAreShallowlyEqual(a, b) {
|
|
146
|
+
if (a.length !== b.length) {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
for (let i = 0; i < a.length; i++) {
|
|
150
|
+
if (a[i] !== b[i]) { // TODO add option for object instance equality
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Like arraysAreShallowlyEqual but this time for an array of entries (tuple of 2 values) like from Map#entries()
|
|
158
|
+
* @param a
|
|
159
|
+
* @param b
|
|
160
|
+
*/
|
|
161
|
+
function arraysWithEntriesAreShallowlyEqual(a, b) {
|
|
162
|
+
if (a.length !== b.length) {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
for (let i = 0; i < a.length; i++) {
|
|
166
|
+
if (a[i][0] !== b[i][0]) { // TODO add option for object instance equality
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
if (a[i][1] !== b[i][1]) { // TODO add option for object instance equality
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
function recordedReadsArraysAreEqual(a, b) {
|
|
176
|
+
return arraysAreEqualsByPredicateFn(a, b, (a, b) => a.equals(b));
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=Util.js.map
|
package/Util.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Util.js","sourceRoot":"","sources":["Util.ts"],"names":[],"mappings":"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"}
|
package/Util.ts
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import {RecordedRead} from "proxy-facades";
|
|
2
|
+
|
|
3
|
+
export function throwError(e: string | Error) {
|
|
4
|
+
if(e !== null && e instanceof Error) {
|
|
5
|
+
throw e;
|
|
6
|
+
}
|
|
7
|
+
throw new Error(e);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function reThrowWithHint(e: unknown, hint: string) {
|
|
11
|
+
try {
|
|
12
|
+
if(e instanceof Error) {
|
|
13
|
+
// Add hint to error:
|
|
14
|
+
e.message+= `\n${hint}`;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
catch (x) {
|
|
18
|
+
}
|
|
19
|
+
throw e;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function isObject(value: unknown) {
|
|
23
|
+
return value !== null && typeof value === "object";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A Map<K, Set<V>>. But automatically add a new Set if needed
|
|
28
|
+
*/
|
|
29
|
+
export class MapSet<K, V> {
|
|
30
|
+
map = new Map<K, Set<V>>()
|
|
31
|
+
|
|
32
|
+
add(key: K, value: V) {
|
|
33
|
+
let set = this.map.get(key);
|
|
34
|
+
if(set === undefined) {
|
|
35
|
+
set = new Set<V>();
|
|
36
|
+
this.map.set(key, set);
|
|
37
|
+
}
|
|
38
|
+
set.add(value);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
delete(key: K, value: V) {
|
|
42
|
+
let set = this.map.get(key);
|
|
43
|
+
if(set !== undefined) {
|
|
44
|
+
set.delete(value);
|
|
45
|
+
if(set.size === 0) {
|
|
46
|
+
this.map.delete(key); // Clean up
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get(key: K) {
|
|
52
|
+
return this.map.get(key);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* A WeakMap<K, Set<V>>. But automatically add a new Set if needed
|
|
58
|
+
*/
|
|
59
|
+
export class WeakMapSet<K, V> extends MapSet<K, V> {
|
|
60
|
+
//@ts-ignore
|
|
61
|
+
map = new WeakMap<K, Set<V>>();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function arraysAreEqualsByPredicateFn<A, B>(a: A[], b: B[], equalsFn: (a: A,b: B) => boolean) {
|
|
65
|
+
if(a.length !== b.length) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
for(const k in a) {
|
|
69
|
+
if(!equalsFn(a[k], b[k])) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
export type PromiseState<T> = {state: "pending", promise: Promise<T>} | {state: "resolved", resolvedValue: T} | {state: "rejected", rejectReason: any};
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
type VisitReplaceContext = {
|
|
79
|
+
/**
|
|
80
|
+
* Not safely escaped. Should be used for diag only !
|
|
81
|
+
*/
|
|
82
|
+
diagnosis_path?: string
|
|
83
|
+
|
|
84
|
+
parentObject?: object
|
|
85
|
+
key?: unknown
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function diagnosis_jsonPath(key: unknown) {
|
|
89
|
+
if(!Number.isNaN(Number(key))) {
|
|
90
|
+
return `[${key}]`;
|
|
91
|
+
}
|
|
92
|
+
return `.${key}`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Usage:
|
|
97
|
+
* <pre><code>
|
|
98
|
+
* const result = visitReplace(target, (value, visitChilds, context) => {
|
|
99
|
+
* return value === 'needle' ? 'replaced' : visitChilds(value, context)
|
|
100
|
+
* });
|
|
101
|
+
* </code></pre>
|
|
102
|
+
*
|
|
103
|
+
* @param value
|
|
104
|
+
* @param visitor
|
|
105
|
+
* @param trackPath whether to pass on the context object. This hurts performance because the path is concatted every time, so use it only when needed. Setting this to "onError" re-executes the visitprelace with the concetxt when an error was thrown
|
|
106
|
+
*/
|
|
107
|
+
export function visitReplace<O>(value: O, visitor: (value: unknown, visitChilds: (value: unknown, context: VisitReplaceContext) => unknown, context: VisitReplaceContext) => unknown , trackPath: boolean | "onError" = false): O {
|
|
108
|
+
const visisitedObjects = new Set<object>()
|
|
109
|
+
|
|
110
|
+
function visitChilds(value: unknown, context: VisitReplaceContext) {
|
|
111
|
+
if(value === null) {
|
|
112
|
+
return value;
|
|
113
|
+
}
|
|
114
|
+
else if(typeof value === "object") {
|
|
115
|
+
const obj = value as object;
|
|
116
|
+
if(visisitedObjects.has(obj)) {
|
|
117
|
+
return value; // don't iterate again
|
|
118
|
+
}
|
|
119
|
+
visisitedObjects.add(obj);
|
|
120
|
+
|
|
121
|
+
for (let k in obj) {
|
|
122
|
+
const keyInParent = k as keyof object;
|
|
123
|
+
const childValue = obj[keyInParent];
|
|
124
|
+
let newValue = visitor(childValue, visitChilds, {...context, parentObject: value, key: keyInParent, diagnosis_path: (context.diagnosis_path !== undefined?`${context.diagnosis_path!}${diagnosis_jsonPath(keyInParent)}`:undefined)});
|
|
125
|
+
if(newValue !== childValue) { // Only if childValue really has changed. We don't want to interfer with setting a readonly property and trigger a proxy
|
|
126
|
+
// @ts-ignore
|
|
127
|
+
obj[keyInParent] = newValue;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return value;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if(trackPath === "onError") {
|
|
135
|
+
try {
|
|
136
|
+
return visitor(value, visitChilds, {}) as O; // Fast try without context
|
|
137
|
+
}
|
|
138
|
+
catch (e) {
|
|
139
|
+
return visitReplace(value, visitor, true); // Try again with context
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return visitor(value, visitChilds,{diagnosis_path: trackPath?"":undefined}) as O;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Just do something the runtime can't optimize away
|
|
148
|
+
* @param value
|
|
149
|
+
*/
|
|
150
|
+
export function read(value: any) {
|
|
151
|
+
if( ("" + value) == "blaaxyxzzzsdf" ) {
|
|
152
|
+
throw new Error("should never get here")
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function arraysAreShallowlyEqual(a: unknown[], b: unknown[]) {
|
|
157
|
+
if(a.length !== b.length) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
for(let i = 0;i<a.length;i++) {
|
|
161
|
+
if(a[i] !== b[i]) { // TODO add option for object instance equality
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Like arraysAreShallowlyEqual but this time for an array of entries (tuple of 2 values) like from Map#entries()
|
|
170
|
+
* @param a
|
|
171
|
+
* @param b
|
|
172
|
+
*/
|
|
173
|
+
export function arraysWithEntriesAreShallowlyEqual(a: Array<[unknown, unknown]>, b: Array<[unknown, unknown]>) {
|
|
174
|
+
if(a.length !== b.length) {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
for(let i = 0;i<a.length;i++) {
|
|
178
|
+
if(a[i][0] !== b[i][0]) { // TODO add option for object instance equality
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
if(a[i][1] !== b[i][1]) { // TODO add option for object instance equality
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function recordedReadsArraysAreEqual(a: RecordedRead[], b: RecordedRead[]) {
|
|
189
|
+
return arraysAreEqualsByPredicateFn(a, b, (a, b) => a.equals(b));
|
|
190
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { RecordedRead } from "proxy-facades";
|
|
2
|
+
export declare function throwError(e: string | Error): void;
|
|
3
|
+
export declare function reThrowWithHint(e: unknown, hint: string): void;
|
|
4
|
+
export declare function isObject(value: unknown): value is object;
|
|
5
|
+
/**
|
|
6
|
+
* A Map<K, Set<V>>. But automatically add a new Set if needed
|
|
7
|
+
*/
|
|
8
|
+
export declare class MapSet<K, V> {
|
|
9
|
+
map: Map<K, Set<V>>;
|
|
10
|
+
add(key: K, value: V): void;
|
|
11
|
+
delete(key: K, value: V): void;
|
|
12
|
+
get(key: K): Set<V> | undefined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A WeakMap<K, Set<V>>. But automatically add a new Set if needed
|
|
16
|
+
*/
|
|
17
|
+
export declare class WeakMapSet<K, V> extends MapSet<K, V> {
|
|
18
|
+
map: WeakMap<K, Set<V>>;
|
|
19
|
+
}
|
|
20
|
+
export declare function arraysAreEqualsByPredicateFn<A, B>(a: A[], b: B[], equalsFn: (a: A, b: B) => boolean): boolean;
|
|
21
|
+
export type PromiseState<T> = {
|
|
22
|
+
state: "pending";
|
|
23
|
+
promise: Promise<T>;
|
|
24
|
+
} | {
|
|
25
|
+
state: "resolved";
|
|
26
|
+
resolvedValue: T;
|
|
27
|
+
} | {
|
|
28
|
+
state: "rejected";
|
|
29
|
+
rejectReason: any;
|
|
30
|
+
};
|
|
31
|
+
type VisitReplaceContext = {
|
|
32
|
+
/**
|
|
33
|
+
* Not safely escaped. Should be used for diag only !
|
|
34
|
+
*/
|
|
35
|
+
diagnosis_path?: string;
|
|
36
|
+
parentObject?: object;
|
|
37
|
+
key?: unknown;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Usage:
|
|
41
|
+
* <pre><code>
|
|
42
|
+
* const result = visitReplace(target, (value, visitChilds, context) => {
|
|
43
|
+
* return value === 'needle' ? 'replaced' : visitChilds(value, context)
|
|
44
|
+
* });
|
|
45
|
+
* </code></pre>
|
|
46
|
+
*
|
|
47
|
+
* @param value
|
|
48
|
+
* @param visitor
|
|
49
|
+
* @param trackPath whether to pass on the context object. This hurts performance because the path is concatted every time, so use it only when needed. Setting this to "onError" re-executes the visitprelace with the concetxt when an error was thrown
|
|
50
|
+
*/
|
|
51
|
+
export declare function visitReplace<O>(value: O, visitor: (value: unknown, visitChilds: (value: unknown, context: VisitReplaceContext) => unknown, context: VisitReplaceContext) => unknown, trackPath?: boolean | "onError"): O;
|
|
52
|
+
/**
|
|
53
|
+
* Just do something the runtime can't optimize away
|
|
54
|
+
* @param value
|
|
55
|
+
*/
|
|
56
|
+
export declare function read(value: any): void;
|
|
57
|
+
export declare function arraysAreShallowlyEqual(a: unknown[], b: unknown[]): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Like arraysAreShallowlyEqual but this time for an array of entries (tuple of 2 values) like from Map#entries()
|
|
60
|
+
* @param a
|
|
61
|
+
* @param b
|
|
62
|
+
*/
|
|
63
|
+
export declare function arraysWithEntriesAreShallowlyEqual(a: Array<[unknown, unknown]>, b: Array<[unknown, unknown]>): boolean;
|
|
64
|
+
export declare function recordedReadsArraysAreEqual(a: RecordedRead[], b: RecordedRead[]): boolean;
|
|
65
|
+
export {};
|
|
66
|
+
//# sourceMappingURL=Util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Util.d.ts","sourceRoot":"","sources":["../../Util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,eAAe,CAAC;AAE3C,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,KAAK,QAK3C;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,QAUvD;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,mBAEtC;AAED;;GAEG;AACH,qBAAa,MAAM,CAAC,CAAC,EAAE,CAAC;IACpB,GAAG,iBAAuB;IAE1B,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC;IASpB,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC;IAUvB,GAAG,CAAC,GAAG,EAAE,CAAC;CAGb;AAED;;GAEG;AACH,qBAAa,UAAU,CAAC,CAAC,EAAE,CAAC,CAAE,SAAQ,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;IAE9C,GAAG,qBAA4B;CAClC;AAED,wBAAgB,4BAA4B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAC,CAAC,EAAE,CAAC,KAAK,OAAO,WAUlG;AACD,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;IAAC,KAAK,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;CAAC,GAAG;IAAC,KAAK,EAAE,UAAU,CAAC;IAAC,aAAa,EAAE,CAAC,CAAA;CAAC,GAAG;IAAC,KAAK,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,GAAG,CAAA;CAAC,CAAC;AAGvJ,KAAK,mBAAmB,GAAG;IACvB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IAEvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,GAAG,CAAC,EAAE,OAAO,CAAA;CAChB,CAAA;AASD;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,KAAK,OAAO,EAAE,OAAO,EAAE,mBAAmB,KAAK,OAAO,EAAG,SAAS,GAAE,OAAO,GAAG,SAAiB,GAAG,CAAC,CAqChO;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,GAAG,QAI9B;AAED,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,WAUjE;AAED;;;;GAIG;AACH,wBAAgB,kCAAkC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,WAa5G;AAED,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,CAAC,EAAE,YAAY,EAAE,WAE/E"}
|