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 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"}