@colyseus/schema 3.0.0-alpha.3 → 3.0.0-alpha.31
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/README.md +131 -61
- package/build/cjs/index.js +966 -563
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +965 -562
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +966 -563
- package/lib/Metadata.d.ts +15 -4
- package/lib/Metadata.js +86 -18
- package/lib/Metadata.js.map +1 -1
- package/lib/Reflection.d.ts +2 -3
- package/lib/Reflection.js +24 -28
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.d.ts +2 -2
- package/lib/Schema.js +28 -41
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.d.ts +1 -21
- package/lib/annotations.js +73 -153
- package/lib/annotations.js.map +1 -1
- package/lib/bench_encode.d.ts +1 -0
- package/lib/bench_encode.js +142 -0
- package/lib/bench_encode.js.map +1 -0
- package/lib/codegen/api.js +1 -2
- package/lib/codegen/api.js.map +1 -1
- package/lib/codegen/languages/cpp.js +1 -2
- package/lib/codegen/languages/cpp.js.map +1 -1
- package/lib/codegen/languages/csharp.js +1 -2
- package/lib/codegen/languages/csharp.js.map +1 -1
- package/lib/codegen/languages/haxe.js +1 -2
- package/lib/codegen/languages/haxe.js.map +1 -1
- package/lib/codegen/languages/java.js +1 -2
- package/lib/codegen/languages/java.js.map +1 -1
- package/lib/codegen/languages/js.js +1 -2
- package/lib/codegen/languages/js.js.map +1 -1
- package/lib/codegen/languages/lua.js +1 -2
- package/lib/codegen/languages/lua.js.map +1 -1
- package/lib/codegen/languages/ts.js +1 -2
- package/lib/codegen/languages/ts.js.map +1 -1
- package/lib/codegen/parser.js +2 -3
- package/lib/codegen/parser.js.map +1 -1
- package/lib/codegen/types.js +3 -3
- package/lib/codegen/types.js.map +1 -1
- package/lib/debug.d.ts +1 -0
- package/lib/debug.js +52 -0
- package/lib/debug.js.map +1 -0
- package/lib/decoder/DecodeOperation.d.ts +0 -1
- package/lib/decoder/DecodeOperation.js +23 -11
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/decoder/Decoder.d.ts +6 -7
- package/lib/decoder/Decoder.js +8 -8
- package/lib/decoder/Decoder.js.map +1 -1
- package/lib/decoder/ReferenceTracker.js +3 -2
- package/lib/decoder/ReferenceTracker.js.map +1 -1
- package/lib/decoder/strategy/RawChanges.js +1 -2
- package/lib/decoder/strategy/RawChanges.js.map +1 -1
- package/lib/decoder/strategy/StateCallbacks.d.ts +44 -11
- package/lib/decoder/strategy/StateCallbacks.js +75 -65
- package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
- package/lib/encoder/ChangeTree.d.ts +9 -19
- package/lib/encoder/ChangeTree.js +129 -145
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/EncodeOperation.d.ts +1 -5
- package/lib/encoder/EncodeOperation.js +74 -58
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.d.ts +10 -8
- package/lib/encoder/Encoder.js +89 -56
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.d.ts +17 -0
- package/lib/encoder/Root.js +44 -0
- package/lib/encoder/Root.js.map +1 -0
- package/lib/encoder/StateView.d.ts +2 -2
- package/lib/encoder/StateView.js +49 -59
- package/lib/encoder/StateView.js.map +1 -1
- package/lib/encoding/assert.d.ts +2 -1
- package/lib/encoding/assert.js +5 -5
- package/lib/encoding/assert.js.map +1 -1
- package/lib/encoding/decode.js +21 -22
- package/lib/encoding/decode.js.map +1 -1
- package/lib/encoding/encode.d.ts +2 -2
- package/lib/encoding/encode.js +40 -39
- package/lib/encoding/encode.js.map +1 -1
- package/lib/encoding/spec.d.ts +2 -1
- package/lib/encoding/spec.js +1 -0
- package/lib/encoding/spec.js.map +1 -1
- package/lib/index.d.ts +6 -3
- package/lib/index.js +18 -13
- package/lib/index.js.map +1 -1
- package/lib/types/TypeContext.d.ts +23 -0
- package/lib/types/TypeContext.js +102 -0
- package/lib/types/TypeContext.js.map +1 -0
- package/lib/types/custom/ArraySchema.d.ts +2 -2
- package/lib/types/custom/ArraySchema.js +6 -9
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/lib/types/custom/CollectionSchema.js +1 -0
- package/lib/types/custom/CollectionSchema.js.map +1 -1
- package/lib/types/custom/MapSchema.js +5 -0
- package/lib/types/custom/MapSchema.js.map +1 -1
- package/lib/types/custom/SetSchema.js +1 -0
- package/lib/types/custom/SetSchema.js.map +1 -1
- package/lib/types/registry.js +3 -4
- package/lib/types/registry.js.map +1 -1
- package/lib/types/symbols.d.ts +1 -0
- package/lib/types/symbols.js +2 -1
- package/lib/types/symbols.js.map +1 -1
- package/lib/types/utils.js +1 -2
- package/lib/types/utils.js.map +1 -1
- package/lib/utils.js +3 -4
- package/lib/utils.js.map +1 -1
- package/package.json +5 -5
- package/src/Metadata.ts +104 -26
- package/src/Reflection.ts +26 -28
- package/src/Schema.ts +35 -47
- package/src/annotations.ts +82 -176
- package/src/bench_encode.ts +121 -0
- package/src/debug.ts +56 -0
- package/src/decoder/DecodeOperation.ts +28 -11
- package/src/decoder/Decoder.ts +13 -11
- package/src/decoder/ReferenceTracker.ts +3 -2
- package/src/decoder/strategy/StateCallbacks.ts +152 -81
- package/src/encoder/ChangeTree.ts +147 -166
- package/src/encoder/EncodeOperation.ts +93 -70
- package/src/encoder/Encoder.ts +111 -65
- package/src/encoder/Root.ts +51 -0
- package/src/encoder/StateView.ts +53 -69
- package/src/encoding/assert.ts +4 -3
- package/src/encoding/decode.ts +1 -2
- package/src/encoding/encode.ts +25 -22
- package/src/encoding/spec.ts +1 -0
- package/src/index.ts +8 -14
- package/src/types/TypeContext.ts +122 -0
- package/src/types/custom/ArraySchema.ts +10 -2
- package/src/types/custom/CollectionSchema.ts +1 -0
- package/src/types/custom/MapSchema.ts +6 -0
- package/src/types/custom/SetSchema.ts +1 -0
- package/src/types/symbols.ts +2 -0
|
@@ -7,10 +7,10 @@ import type { ArraySchema } from "../types/custom/ArraySchema";
|
|
|
7
7
|
import type { CollectionSchema } from "../types/custom/CollectionSchema";
|
|
8
8
|
import type { SetSchema } from "../types/custom/SetSchema";
|
|
9
9
|
|
|
10
|
+
import { Root } from "./Root";
|
|
10
11
|
import { Metadata } from "../Metadata";
|
|
11
12
|
import type { EncodeOperation } from "./EncodeOperation";
|
|
12
13
|
import type { DecodeOperation } from "../decoder/DecodeOperation";
|
|
13
|
-
import type { StateView } from "./StateView";
|
|
14
14
|
|
|
15
15
|
declare global {
|
|
16
16
|
interface Object {
|
|
@@ -27,121 +27,85 @@ export type Ref = Schema
|
|
|
27
27
|
| CollectionSchema
|
|
28
28
|
| SetSchema;
|
|
29
29
|
|
|
30
|
-
export class Root {
|
|
31
|
-
protected nextUniqueId: number = 0;
|
|
32
|
-
refCount = new WeakMap<ChangeTree, number>();
|
|
33
|
-
|
|
34
|
-
// all changes
|
|
35
|
-
allChanges = new Map<ChangeTree, Map<number, OPERATION>>();
|
|
36
|
-
allFilteredChanges = new Map<ChangeTree, Map<number, OPERATION>>();
|
|
37
|
-
|
|
38
|
-
// pending changes to be encoded
|
|
39
|
-
changes = new Map<ChangeTree, Map<number, OPERATION>>();
|
|
40
|
-
filteredChanges = new Map<ChangeTree, Map<number, OPERATION>>();
|
|
41
|
-
|
|
42
|
-
getNextUniqueId() {
|
|
43
|
-
return this.nextUniqueId++;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
add (changeTree: ChangeTree) {
|
|
47
|
-
const refCount = this.refCount.get(changeTree) || 0;
|
|
48
|
-
this.refCount.set(changeTree, refCount + 1);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
remove(changeTree: ChangeTree) {
|
|
52
|
-
const refCount = this.refCount.get(changeTree);
|
|
53
|
-
if (refCount <= 1) {
|
|
54
|
-
this.allChanges.delete(changeTree);
|
|
55
|
-
this.changes.delete(changeTree);
|
|
56
|
-
|
|
57
|
-
if (changeTree.isFiltered || changeTree.isPartiallyFiltered) {
|
|
58
|
-
this.allFilteredChanges.delete(changeTree);
|
|
59
|
-
this.filteredChanges.delete(changeTree);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
this.refCount.delete(changeTree);
|
|
63
|
-
|
|
64
|
-
} else {
|
|
65
|
-
this.refCount.set(changeTree, refCount - 1);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
changeTree.forEachChild((child, _) =>
|
|
69
|
-
this.remove(child));
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
clear() {
|
|
73
|
-
this.changes.clear();
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
30
|
export class ChangeTree<T extends Ref=any> {
|
|
78
31
|
ref: T;
|
|
79
32
|
refId: number;
|
|
80
33
|
|
|
81
34
|
root?: Root;
|
|
82
|
-
|
|
83
|
-
isFiltered?: boolean;
|
|
84
|
-
isPartiallyFiltered?: boolean;
|
|
85
|
-
|
|
86
35
|
parent?: Ref;
|
|
87
36
|
parentIndex?: number;
|
|
88
37
|
|
|
89
|
-
|
|
38
|
+
isFiltered: boolean = false;
|
|
39
|
+
isPartiallyFiltered: boolean = false;
|
|
40
|
+
|
|
90
41
|
currentOperationIndex: number = 0;
|
|
91
42
|
|
|
43
|
+
changes = new Map<number, OPERATION>();
|
|
92
44
|
allChanges = new Map<number, OPERATION>();
|
|
93
|
-
allFilteredChanges = new Map<number, OPERATION>();
|
|
94
45
|
|
|
95
|
-
|
|
96
|
-
filteredChanges
|
|
46
|
+
allFilteredChanges: Map<number, OPERATION>;
|
|
47
|
+
filteredChanges: Map<number, OPERATION>;
|
|
48
|
+
|
|
49
|
+
indexes: {[index: string]: any}; // TODO: remove this, only used by MapSchema/SetSchema/CollectionSchema (`encodeKeyValueOperation`)
|
|
97
50
|
|
|
98
51
|
[$isNew] = true;
|
|
99
52
|
|
|
100
53
|
constructor(ref: T) {
|
|
101
54
|
this.ref = ref;
|
|
55
|
+
|
|
56
|
+
//
|
|
57
|
+
// Does this structure have "filters" declared?
|
|
58
|
+
//
|
|
59
|
+
if (ref.constructor[Symbol.metadata]?.[-2]) {
|
|
60
|
+
this.allFilteredChanges = new Map<number, OPERATION>();
|
|
61
|
+
this.filteredChanges = new Map<number, OPERATION>();
|
|
62
|
+
}
|
|
102
63
|
}
|
|
103
64
|
|
|
104
65
|
setRoot(root: Root) {
|
|
105
66
|
this.root = root;
|
|
106
67
|
this.root.add(this);
|
|
107
68
|
|
|
108
|
-
|
|
109
|
-
// At Schema initialization, the "root" structure might not be available
|
|
110
|
-
// yet, as it only does once the "Encoder" has been set up.
|
|
111
|
-
//
|
|
112
|
-
// So the "parent" may be already set without a "root".
|
|
113
|
-
//
|
|
114
|
-
this.checkIsFiltered(this.parent, this.parentIndex);
|
|
69
|
+
const metadata: Metadata = this.ref.constructor[Symbol.metadata];
|
|
115
70
|
|
|
116
|
-
|
|
117
|
-
|
|
71
|
+
if (this.root.types.hasFilters) {
|
|
72
|
+
//
|
|
73
|
+
// At Schema initialization, the "root" structure might not be available
|
|
74
|
+
// yet, as it only does once the "Encoder" has been set up.
|
|
75
|
+
//
|
|
76
|
+
// So the "parent" may be already set without a "root".
|
|
77
|
+
//
|
|
78
|
+
this.checkIsFiltered(metadata, this.parent, this.parentIndex);
|
|
79
|
+
|
|
80
|
+
if (this.isFiltered || this.isPartiallyFiltered) {
|
|
81
|
+
this.root.allFilteredChanges.set(this, this.allFilteredChanges);
|
|
82
|
+
this.root.filteredChanges.set(this, this.filteredChanges);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
118
85
|
|
|
119
86
|
if (!this.isFiltered) {
|
|
120
87
|
this.root.changes.set(this, this.changes);
|
|
88
|
+
this.root.allChanges.set(this, this.allChanges);
|
|
121
89
|
}
|
|
122
90
|
|
|
123
|
-
|
|
124
|
-
this.root.allFilteredChanges.set(this, this.allFilteredChanges);
|
|
125
|
-
this.root.filteredChanges.set(this, this.filteredChanges);
|
|
91
|
+
this.ensureRefId();
|
|
126
92
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
93
|
+
if (metadata) {
|
|
94
|
+
metadata[-4]?.forEach((index) => {
|
|
95
|
+
const field = metadata[index as any as number];
|
|
96
|
+
const value = this.ref[field.name];
|
|
97
|
+
if (value) {
|
|
98
|
+
value[$changes].setRoot(root);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
130
101
|
|
|
131
|
-
if (
|
|
132
|
-
|
|
102
|
+
} else if (this.ref[$childType] && typeof(this.ref[$childType]) !== "string") {
|
|
103
|
+
// MapSchema / ArraySchema, etc.
|
|
104
|
+
(this.ref as MapSchema).forEach((value, key) => {
|
|
105
|
+
value[$changes].setRoot(root);
|
|
106
|
+
});
|
|
133
107
|
}
|
|
134
108
|
|
|
135
|
-
this.forEachChild((changeTree, _) => {
|
|
136
|
-
changeTree.setRoot(root);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
// this.allChanges.forEach((_, index) => {
|
|
140
|
-
// const childRef = this.ref[$getByIndex](index);
|
|
141
|
-
// if (childRef && childRef[$changes]) {
|
|
142
|
-
// childRef[$changes].setRoot(root);
|
|
143
|
-
// }
|
|
144
|
-
// });
|
|
145
109
|
}
|
|
146
110
|
|
|
147
111
|
setParent(
|
|
@@ -157,57 +121,71 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
157
121
|
|
|
158
122
|
root.add(this);
|
|
159
123
|
|
|
124
|
+
const metadata: Metadata = this.ref.constructor[Symbol.metadata];
|
|
125
|
+
|
|
160
126
|
// skip if parent is already set
|
|
161
|
-
if (root
|
|
162
|
-
this.
|
|
163
|
-
changeTree.setParent(this.ref, root, atIndex);
|
|
164
|
-
});
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
127
|
+
if (root !== this.root) {
|
|
128
|
+
this.root = root;
|
|
167
129
|
|
|
168
|
-
|
|
169
|
-
|
|
130
|
+
if (root.types.hasFilters) {
|
|
131
|
+
this.checkIsFiltered(metadata, parent, parentIndex);
|
|
170
132
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
133
|
+
if (this.isFiltered || this.isPartiallyFiltered) {
|
|
134
|
+
this.root.filteredChanges.set(this, this.filteredChanges);
|
|
135
|
+
this.root.allFilteredChanges.set(this, this.filteredChanges);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
174
138
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
139
|
+
if (!this.isFiltered) {
|
|
140
|
+
this.root.changes.set(this, this.changes);
|
|
141
|
+
this.root.allChanges.set(this, this.allChanges);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
this.ensureRefId();
|
|
180
145
|
}
|
|
181
146
|
|
|
182
|
-
|
|
147
|
+
// assign same parent on child structures
|
|
148
|
+
if (metadata) {
|
|
149
|
+
metadata[-4]?.forEach((index) => {
|
|
150
|
+
const field = metadata[index as any as number];
|
|
151
|
+
const value = this.ref[field.name];
|
|
152
|
+
value?.[$changes].setParent(this.ref, root, index);
|
|
153
|
+
|
|
154
|
+
// console.log(this.ref.constructor.name, field.name, value);
|
|
155
|
+
|
|
156
|
+
// try { throw new Error(); } catch (e) {
|
|
157
|
+
// console.log(e.stack);
|
|
158
|
+
// }
|
|
159
|
+
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
} else if (this.ref[$childType] && typeof(this.ref[$childType]) !== "string") {
|
|
163
|
+
// MapSchema / ArraySchema, etc.
|
|
164
|
+
(this.ref as MapSchema).forEach((value, key) => {
|
|
165
|
+
value[$changes].setParent(this.ref, root, this.indexes[key] ?? key);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
183
168
|
|
|
184
|
-
this.forEachChild((changeTree, atIndex) => {
|
|
185
|
-
changeTree.setParent(this.ref, root, atIndex);
|
|
186
|
-
});
|
|
187
169
|
}
|
|
188
170
|
|
|
189
171
|
forEachChild(callback: (change: ChangeTree, atIndex: number) => void) {
|
|
190
172
|
//
|
|
191
173
|
// assign same parent on child structures
|
|
192
174
|
//
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if (value && value[$changes]) {
|
|
201
|
-
callback(value[$changes], metadata[field].index);
|
|
175
|
+
const metadata: Metadata = this.ref.constructor[Symbol.metadata];
|
|
176
|
+
if (metadata) {
|
|
177
|
+
metadata[-4]?.forEach((index) => {
|
|
178
|
+
const field = metadata[index as any as number];
|
|
179
|
+
const value = this.ref[field.name];
|
|
180
|
+
if (value) {
|
|
181
|
+
callback(value[$changes], index);
|
|
202
182
|
}
|
|
203
|
-
}
|
|
183
|
+
});
|
|
204
184
|
|
|
205
|
-
} else if (typeof
|
|
185
|
+
} else if (this.ref[$childType] && typeof(this.ref[$childType]) !== "string") {
|
|
206
186
|
// MapSchema / ArraySchema, etc.
|
|
207
187
|
(this.ref as MapSchema).forEach((value, key) => {
|
|
208
|
-
|
|
209
|
-
callback(value[$changes], this.ref[$changes].indexes[key]);
|
|
210
|
-
}
|
|
188
|
+
callback(value[$changes], this.indexes[key] ?? key);
|
|
211
189
|
});
|
|
212
190
|
}
|
|
213
191
|
}
|
|
@@ -218,9 +196,9 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
218
196
|
}
|
|
219
197
|
|
|
220
198
|
change(index: number, operation: OPERATION = OPERATION.ADD) {
|
|
221
|
-
const metadata = this.ref
|
|
199
|
+
const metadata = this.ref.constructor[Symbol.metadata] as Metadata;
|
|
222
200
|
|
|
223
|
-
const isFiltered = this.isFiltered || (metadata
|
|
201
|
+
const isFiltered = this.isFiltered || (metadata?.[index]?.tag !== undefined);
|
|
224
202
|
const changeSet = (isFiltered)
|
|
225
203
|
? this.filteredChanges
|
|
226
204
|
: this.changes;
|
|
@@ -232,16 +210,16 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
232
210
|
: (previousOperation === OPERATION.DELETE)
|
|
233
211
|
? OPERATION.DELETE_AND_ADD
|
|
234
212
|
: operation
|
|
213
|
+
//
|
|
214
|
+
// TODO: are DELETE operations being encoded as ADD here ??
|
|
215
|
+
//
|
|
235
216
|
changeSet.set(index, op);
|
|
236
217
|
}
|
|
237
218
|
|
|
238
|
-
//
|
|
239
|
-
// TODO: are DELETE operations being encoded as ADD here ??
|
|
240
|
-
//
|
|
241
|
-
|
|
242
219
|
if (isFiltered) {
|
|
243
220
|
this.allFilteredChanges.set(index, OPERATION.ADD);
|
|
244
221
|
this.root?.filteredChanges.set(this, this.filteredChanges);
|
|
222
|
+
this.root?.allFilteredChanges.set(this, this.allFilteredChanges);
|
|
245
223
|
|
|
246
224
|
} else {
|
|
247
225
|
this.allChanges.set(index, OPERATION.ADD);
|
|
@@ -285,7 +263,6 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
285
263
|
|
|
286
264
|
private _shiftAllChangeIndexes(shiftIndex: number, startIndex: number = 0, allChangeSet: Map<number, OPERATION>) {
|
|
287
265
|
Array.from(allChangeSet.entries()).forEach(([index, op]) => {
|
|
288
|
-
// console.log('shiftAllChangeIndexes', index >= startIndex, { index, op, shiftIndex, startIndex })
|
|
289
266
|
if (index >= startIndex) {
|
|
290
267
|
allChangeSet.delete(index);
|
|
291
268
|
allChangeSet.set(index + shiftIndex, op);
|
|
@@ -294,10 +271,7 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
294
271
|
}
|
|
295
272
|
|
|
296
273
|
indexedOperation(index: number, operation: OPERATION, allChangesIndex = index) {
|
|
297
|
-
|
|
298
|
-
const isFiltered = this.isFiltered || (metadata && metadata[metadata[index]].tag !== undefined);
|
|
299
|
-
|
|
300
|
-
if (isFiltered) {
|
|
274
|
+
if (this.filteredChanges !== undefined) {
|
|
301
275
|
this.allFilteredChanges.set(allChangesIndex, OPERATION.ADD);
|
|
302
276
|
this.filteredChanges.set(index, operation);
|
|
303
277
|
this.root?.filteredChanges.set(this, this.filteredChanges);
|
|
@@ -311,8 +285,8 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
311
285
|
|
|
312
286
|
getType(index?: number) {
|
|
313
287
|
if (Metadata.isValidInstance(this.ref)) {
|
|
314
|
-
const metadata = this.ref
|
|
315
|
-
return metadata[
|
|
288
|
+
const metadata = this.ref.constructor[Symbol.metadata] as Metadata;
|
|
289
|
+
return metadata[index].type;
|
|
316
290
|
|
|
317
291
|
} else {
|
|
318
292
|
//
|
|
@@ -327,7 +301,7 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
327
301
|
|
|
328
302
|
getChange(index: number) {
|
|
329
303
|
// TODO: optimize this. avoid checking against multiple instances
|
|
330
|
-
return this.changes.get(index) ?? this.filteredChanges
|
|
304
|
+
return this.changes.get(index) ?? this.filteredChanges?.get(index);
|
|
331
305
|
}
|
|
332
306
|
|
|
333
307
|
//
|
|
@@ -350,9 +324,7 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
350
324
|
return;
|
|
351
325
|
}
|
|
352
326
|
|
|
353
|
-
const
|
|
354
|
-
const isFiltered = this.isFiltered || (metadata && metadata[metadata[index]].tag !== undefined);
|
|
355
|
-
const changeSet = (isFiltered)
|
|
327
|
+
const changeSet = (this.filteredChanges)
|
|
356
328
|
? this.filteredChanges
|
|
357
329
|
: this.changes;
|
|
358
330
|
|
|
@@ -380,7 +352,7 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
380
352
|
//
|
|
381
353
|
// FIXME: this is looking a bit ugly (and repeated from `.change()`)
|
|
382
354
|
//
|
|
383
|
-
if (
|
|
355
|
+
if (this.filteredChanges) {
|
|
384
356
|
this.root?.filteredChanges.set(this, this.filteredChanges);
|
|
385
357
|
this.allFilteredChanges.delete(allChangesIndex);
|
|
386
358
|
|
|
@@ -392,6 +364,8 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
392
364
|
|
|
393
365
|
endEncode() {
|
|
394
366
|
this.changes.clear();
|
|
367
|
+
|
|
368
|
+
// ArraySchema and MapSchema have a custom "encode end" method
|
|
395
369
|
this.ref[$onEncodeEnd]?.();
|
|
396
370
|
|
|
397
371
|
// Not a new instance anymore
|
|
@@ -407,14 +381,14 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
407
381
|
this.ref[$onEncodeEnd]?.();
|
|
408
382
|
|
|
409
383
|
this.changes.clear();
|
|
410
|
-
this.filteredChanges
|
|
384
|
+
this.filteredChanges?.clear();
|
|
411
385
|
|
|
412
386
|
// reset operation index
|
|
413
387
|
this.currentOperationIndex = 0;
|
|
414
388
|
|
|
415
389
|
if (discardAll) {
|
|
416
390
|
this.allChanges.clear();
|
|
417
|
-
this.allFilteredChanges
|
|
391
|
+
this.allFilteredChanges?.clear();
|
|
418
392
|
|
|
419
393
|
// remove children references
|
|
420
394
|
this.forEachChild((changeTree, _) =>
|
|
@@ -450,40 +424,47 @@ export class ChangeTree<T extends Ref=any> {
|
|
|
450
424
|
return this.changes.size > 0;
|
|
451
425
|
}
|
|
452
426
|
|
|
453
|
-
protected checkIsFiltered(parent: Ref, parentIndex: number) {
|
|
427
|
+
protected checkIsFiltered(metadata: Metadata, parent: Ref, parentIndex: number) {
|
|
454
428
|
// Detect if current structure has "filters" declared
|
|
455
|
-
this.isPartiallyFiltered =
|
|
456
|
-
|
|
457
|
-
// TODO: support "partially filtered", where the instance is visible, but only a field is not.
|
|
429
|
+
this.isPartiallyFiltered = metadata?.[-2] !== undefined;
|
|
458
430
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
const fieldName = metadata?.[parentIndex];
|
|
464
|
-
const isParentOwned = metadata?.[fieldName]?.tag !== undefined;
|
|
431
|
+
if (this.isPartiallyFiltered) {
|
|
432
|
+
this.filteredChanges = this.filteredChanges || new Map<number, OPERATION>();
|
|
433
|
+
this.allFilteredChanges = this.allFilteredChanges || new Map<number, OPERATION>();
|
|
434
|
+
}
|
|
465
435
|
|
|
466
|
-
|
|
436
|
+
if (parent) {
|
|
437
|
+
if (!Metadata.isValidInstance(parent)) {
|
|
438
|
+
const parentChangeTree = parent[$changes];
|
|
439
|
+
parent = parentChangeTree.parent;
|
|
440
|
+
parentIndex = parentChangeTree.parentIndex;
|
|
441
|
+
}
|
|
467
442
|
|
|
468
|
-
|
|
469
|
-
|
|
443
|
+
const parentMetadata = parent?.constructor?.[Symbol.metadata];
|
|
444
|
+
this.isFiltered = (parent && parentMetadata?.[-2]?.includes(parentIndex));
|
|
470
445
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
446
|
+
//
|
|
447
|
+
// TODO: refactor this!
|
|
448
|
+
//
|
|
449
|
+
// swapping `changes` and `filteredChanges` is required here
|
|
450
|
+
// because "isFiltered" may not be imedialely available on `change()`
|
|
451
|
+
//
|
|
452
|
+
if (this.isFiltered) {
|
|
453
|
+
this.filteredChanges = new Map<number, OPERATION>();
|
|
454
|
+
this.allFilteredChanges = new Map<number, OPERATION>();
|
|
455
|
+
|
|
456
|
+
if (this.changes.size > 0) {
|
|
457
|
+
// swap changes reference
|
|
458
|
+
const changes = this.changes;
|
|
459
|
+
this.changes = this.filteredChanges;
|
|
460
|
+
this.filteredChanges = changes;
|
|
461
|
+
|
|
462
|
+
// swap "all changes" reference
|
|
463
|
+
const allFilteredChanges = this.allFilteredChanges;
|
|
464
|
+
this.allFilteredChanges = this.allChanges;
|
|
465
|
+
this.allChanges = allFilteredChanges;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
487
468
|
}
|
|
488
469
|
}
|
|
489
470
|
|