@colyseus/schema 4.0.1 → 4.0.3
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/{lib → build}/Metadata.d.ts +2 -2
- package/{lib → build}/Reflection.d.ts +13 -13
- package/{lib → build}/Schema.d.ts +10 -10
- package/{lib → build}/annotations.d.ts +10 -10
- package/build/codegen/languages/cpp.d.ts +3 -0
- package/build/codegen/languages/csharp.d.ts +4 -0
- package/build/codegen/languages/haxe.d.ts +3 -0
- package/{lib → build}/codegen/languages/java.d.ts +2 -2
- package/build/codegen/languages/js.d.ts +3 -0
- package/build/codegen/languages/lua.d.ts +3 -0
- package/build/codegen/languages/ts.d.ts +3 -0
- package/{lib → build}/codegen/parser.d.ts +1 -1
- package/{lib → build}/decoder/DecodeOperation.d.ts +5 -5
- package/{lib → build}/decoder/Decoder.d.ts +7 -7
- package/{lib → build}/decoder/ReferenceTracker.d.ts +1 -1
- package/{lib → build}/decoder/strategy/Callbacks.d.ts +11 -11
- package/{lib → build}/decoder/strategy/RawChanges.d.ts +2 -2
- package/{lib → build}/decoder/strategy/getDecoderStateCallbacks.d.ts +3 -3
- package/{lib → build}/encoder/ChangeTree.d.ts +11 -11
- package/{lib → build}/encoder/EncodeOperation.d.ts +5 -5
- package/{lib → build}/encoder/Encoder.d.ts +6 -6
- package/{lib → build}/encoder/Root.d.ts +2 -2
- package/{lib → build}/encoder/StateView.d.ts +1 -1
- package/{lib → build}/encoding/assert.d.ts +6 -6
- package/{lib → build}/encoding/decode.d.ts +1 -1
- package/{lib → build}/encoding/encode.d.ts +1 -1
- package/build/{cjs/index.js → index.cjs} +1 -1
- package/build/index.cjs.map +1 -0
- package/build/index.d.ts +32 -0
- package/build/index.mjs.map +1 -0
- package/{lib → build}/types/HelperTypes.d.ts +6 -6
- package/{lib → build}/types/TypeContext.d.ts +1 -1
- package/{lib → build}/types/custom/ArraySchema.d.ts +8 -8
- package/{lib → build}/types/custom/CollectionSchema.d.ts +7 -7
- package/{lib → build}/types/custom/MapSchema.d.ts +7 -7
- package/{lib → build}/types/custom/SetSchema.d.ts +7 -7
- package/{lib → build}/types/registry.d.ts +2 -2
- package/{lib → build}/utils.d.ts +1 -1
- package/package.json +15 -14
- package/src/Metadata.ts +5 -5
- package/src/Reflection.ts +7 -7
- package/src/Schema.ts +11 -11
- package/src/annotations.ts +13 -13
- package/src/codegen/api.ts +10 -3
- package/src/codegen/cli.ts +2 -2
- package/src/codegen/languages/cpp.ts +2 -2
- package/src/codegen/languages/csharp.ts +3 -3
- package/src/codegen/languages/haxe.ts +2 -2
- package/src/codegen/languages/java.ts +2 -2
- package/src/codegen/languages/js.ts +2 -2
- package/src/codegen/languages/lua.ts +2 -2
- package/src/codegen/languages/ts.ts +2 -2
- package/src/codegen/parser.ts +7 -2
- package/src/codegen/types.ts +5 -0
- package/src/decoder/DecodeOperation.ts +14 -14
- package/src/decoder/Decoder.ts +11 -11
- package/src/decoder/ReferenceTracker.ts +8 -8
- package/src/decoder/strategy/Callbacks.ts +12 -12
- package/src/decoder/strategy/RawChanges.ts +2 -2
- package/src/decoder/strategy/getDecoderStateCallbacks.ts +10 -10
- package/src/encoder/ChangeTree.ts +13 -13
- package/src/encoder/EncodeOperation.ts +9 -9
- package/src/encoder/Encoder.ts +10 -10
- package/src/encoder/Root.ts +4 -4
- package/src/encoder/StateView.ts +7 -7
- package/src/encoding/assert.ts +6 -6
- package/src/encoding/decode.ts +1 -1
- package/src/encoding/encode.ts +1 -1
- package/src/index.ts +27 -27
- package/src/types/HelperTypes.ts +6 -6
- package/src/types/TypeContext.ts +3 -3
- package/src/types/custom/ArraySchema.ts +11 -11
- package/src/types/custom/CollectionSchema.ts +9 -9
- package/src/types/custom/MapSchema.ts +10 -10
- package/src/types/custom/SetSchema.ts +9 -9
- package/src/types/registry.ts +3 -3
- package/src/utils.ts +3 -3
- package/src/v3_bench.ts +1 -1
- package/build/cjs/index.js.map +0 -1
- package/build/esm/index.mjs.map +0 -1
- package/lib/Metadata.js +0 -260
- package/lib/Metadata.js.map +0 -1
- package/lib/Reflection.js +0 -182
- package/lib/Reflection.js.map +0 -1
- package/lib/Schema.js +0 -356
- package/lib/Schema.js.map +0 -1
- package/lib/annotations.js +0 -484
- package/lib/annotations.js.map +0 -1
- package/lib/bench_encode.d.ts +0 -1
- package/lib/bench_encode.js +0 -126
- package/lib/bench_encode.js.map +0 -1
- package/lib/codegen/api.js +0 -87
- package/lib/codegen/api.js.map +0 -1
- package/lib/codegen/argv.js +0 -41
- package/lib/codegen/argv.js.map +0 -1
- package/lib/codegen/cli.js +0 -63
- package/lib/codegen/cli.js.map +0 -1
- package/lib/codegen/languages/cpp.d.ts +0 -3
- package/lib/codegen/languages/cpp.js +0 -261
- package/lib/codegen/languages/cpp.js.map +0 -1
- package/lib/codegen/languages/csharp.d.ts +0 -4
- package/lib/codegen/languages/csharp.js +0 -157
- package/lib/codegen/languages/csharp.js.map +0 -1
- package/lib/codegen/languages/haxe.d.ts +0 -3
- package/lib/codegen/languages/haxe.js +0 -103
- package/lib/codegen/languages/haxe.js.map +0 -1
- package/lib/codegen/languages/java.js +0 -103
- package/lib/codegen/languages/java.js.map +0 -1
- package/lib/codegen/languages/js.d.ts +0 -3
- package/lib/codegen/languages/js.js +0 -104
- package/lib/codegen/languages/js.js.map +0 -1
- package/lib/codegen/languages/lua.d.ts +0 -3
- package/lib/codegen/languages/lua.js +0 -106
- package/lib/codegen/languages/lua.js.map +0 -1
- package/lib/codegen/languages/ts.d.ts +0 -3
- package/lib/codegen/languages/ts.js +0 -119
- package/lib/codegen/languages/ts.js.map +0 -1
- package/lib/codegen/parser.js +0 -364
- package/lib/codegen/parser.js.map +0 -1
- package/lib/codegen/types.js +0 -181
- package/lib/codegen/types.js.map +0 -1
- package/lib/decoder/DecodeOperation.js +0 -255
- package/lib/decoder/DecodeOperation.js.map +0 -1
- package/lib/decoder/Decoder.js +0 -118
- package/lib/decoder/Decoder.js.map +0 -1
- package/lib/decoder/ReferenceTracker.js +0 -139
- package/lib/decoder/ReferenceTracker.js.map +0 -1
- package/lib/decoder/strategy/Callbacks.js +0 -340
- package/lib/decoder/strategy/Callbacks.js.map +0 -1
- package/lib/decoder/strategy/RawChanges.js +0 -7
- package/lib/decoder/strategy/RawChanges.js.map +0 -1
- package/lib/decoder/strategy/getDecoderStateCallbacks.js +0 -277
- package/lib/decoder/strategy/getDecoderStateCallbacks.js.map +0 -1
- package/lib/encoder/ChangeTree.js +0 -542
- package/lib/encoder/ChangeTree.js.map +0 -1
- package/lib/encoder/EncodeOperation.js +0 -139
- package/lib/encoder/EncodeOperation.js.map +0 -1
- package/lib/encoder/Encoder.js +0 -208
- package/lib/encoder/Encoder.js.map +0 -1
- package/lib/encoder/Root.js +0 -233
- package/lib/encoder/Root.js.map +0 -1
- package/lib/encoder/StateView.js +0 -284
- package/lib/encoder/StateView.js.map +0 -1
- package/lib/encoding/assert.js +0 -55
- package/lib/encoding/assert.js.map +0 -1
- package/lib/encoding/decode.js +0 -221
- package/lib/encoding/decode.js.map +0 -1
- package/lib/encoding/encode.js +0 -282
- package/lib/encoding/encode.js.map +0 -1
- package/lib/encoding/spec.js +0 -29
- package/lib/encoding/spec.js.map +0 -1
- package/lib/index.d.ts +0 -32
- package/lib/index.js +0 -81
- package/lib/index.js.map +0 -1
- package/lib/symbol.shim.js +0 -4
- package/lib/symbol.shim.js.map +0 -1
- package/lib/types/HelperTypes.js +0 -3
- package/lib/types/HelperTypes.js.map +0 -1
- package/lib/types/TypeContext.js +0 -147
- package/lib/types/TypeContext.js.map +0 -1
- package/lib/types/custom/ArraySchema.js +0 -737
- package/lib/types/custom/ArraySchema.js.map +0 -1
- package/lib/types/custom/CollectionSchema.js +0 -174
- package/lib/types/custom/CollectionSchema.js.map +0 -1
- package/lib/types/custom/MapSchema.js +0 -226
- package/lib/types/custom/MapSchema.js.map +0 -1
- package/lib/types/custom/SetSchema.js +0 -182
- package/lib/types/custom/SetSchema.js.map +0 -1
- package/lib/types/registry.js +0 -37
- package/lib/types/registry.js.map +0 -1
- package/lib/types/symbols.js +0 -37
- package/lib/types/symbols.js.map +0 -1
- package/lib/types/utils.js +0 -16
- package/lib/types/utils.js.map +0 -1
- package/lib/utils.js +0 -54
- package/lib/utils.js.map +0 -1
- package/lib/v3_bench.js +0 -130
- package/lib/v3_bench.js.map +0 -1
- package/src/bench_encode.ts +0 -64
- /package/{lib → build}/codegen/api.d.ts +0 -0
- /package/{lib → build}/codegen/argv.d.ts +0 -0
- /package/{lib → build}/codegen/cli.d.ts +0 -0
- /package/{lib → build}/codegen/types.d.ts +0 -0
- /package/{lib → build}/encoding/spec.d.ts +0 -0
- /package/build/{umd/index.js → index.js} +0 -0
- /package/build/{esm/index.mjs → index.mjs} +0 -0
- /package/{lib → build}/symbol.shim.d.ts +0 -0
- /package/{lib → build}/types/symbols.d.ts +0 -0
- /package/{lib → build}/types/utils.d.ts +0 -0
- /package/{lib → build}/v3_bench.d.ts +0 -0
|
@@ -1,542 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ChangeTree = void 0;
|
|
4
|
-
exports.createChangeTreeList = createChangeTreeList;
|
|
5
|
-
exports.setOperationAtIndex = setOperationAtIndex;
|
|
6
|
-
exports.deleteOperationAtIndex = deleteOperationAtIndex;
|
|
7
|
-
exports.debugChangeSet = debugChangeSet;
|
|
8
|
-
const spec_1 = require("../encoding/spec");
|
|
9
|
-
const symbols_1 = require("../types/symbols");
|
|
10
|
-
const Metadata_1 = require("../Metadata");
|
|
11
|
-
function createChangeSet(queueRootNode) {
|
|
12
|
-
return { indexes: {}, operations: [], queueRootNode };
|
|
13
|
-
}
|
|
14
|
-
// Linked list helper functions
|
|
15
|
-
function createChangeTreeList() {
|
|
16
|
-
return { next: undefined, tail: undefined };
|
|
17
|
-
}
|
|
18
|
-
function setOperationAtIndex(changeSet, index) {
|
|
19
|
-
const operationsIndex = changeSet.indexes[index];
|
|
20
|
-
if (operationsIndex === undefined) {
|
|
21
|
-
changeSet.indexes[index] = changeSet.operations.push(index) - 1;
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
changeSet.operations[operationsIndex] = index;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
function deleteOperationAtIndex(changeSet, index) {
|
|
28
|
-
let operationsIndex = changeSet.indexes[index];
|
|
29
|
-
if (operationsIndex === undefined) {
|
|
30
|
-
//
|
|
31
|
-
// if index is not found, we need to find the last operation
|
|
32
|
-
// FIXME: this is not very efficient
|
|
33
|
-
//
|
|
34
|
-
// > See "should allow consecutive splices (same place)" tests
|
|
35
|
-
//
|
|
36
|
-
operationsIndex = Object.values(changeSet.indexes).at(-1);
|
|
37
|
-
index = Object.entries(changeSet.indexes).find(([_, value]) => value === operationsIndex)?.[0];
|
|
38
|
-
}
|
|
39
|
-
changeSet.operations[operationsIndex] = undefined;
|
|
40
|
-
delete changeSet.indexes[index];
|
|
41
|
-
}
|
|
42
|
-
function debugChangeSet(label, changeSet) {
|
|
43
|
-
let indexes = [];
|
|
44
|
-
let operations = [];
|
|
45
|
-
for (const index in changeSet.indexes) {
|
|
46
|
-
indexes.push(`\t${index} => [${changeSet.indexes[index]}]`);
|
|
47
|
-
}
|
|
48
|
-
for (let i = 0; i < changeSet.operations.length; i++) {
|
|
49
|
-
const index = changeSet.operations[i];
|
|
50
|
-
if (index !== undefined) {
|
|
51
|
-
operations.push(`\t[${i}] => ${index}`);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
console.log(`${label} =>\nindexes (${Object.keys(changeSet.indexes).length}) {`);
|
|
55
|
-
console.log(indexes.join("\n"), "\n}");
|
|
56
|
-
console.log(`operations (${changeSet.operations.filter(op => op !== undefined).length}) {`);
|
|
57
|
-
console.log(operations.join("\n"), "\n}");
|
|
58
|
-
}
|
|
59
|
-
class ChangeTree {
|
|
60
|
-
constructor(ref) {
|
|
61
|
-
/**
|
|
62
|
-
* Whether this structure is parent of a filtered structure.
|
|
63
|
-
*/
|
|
64
|
-
this.isFiltered = false;
|
|
65
|
-
this.indexedOperations = {};
|
|
66
|
-
//
|
|
67
|
-
// TODO:
|
|
68
|
-
// try storing the index + operation per item.
|
|
69
|
-
// example: 1024 & 1025 => ADD, 1026 => DELETE
|
|
70
|
-
//
|
|
71
|
-
// => https://chatgpt.com/share/67107d0c-bc20-8004-8583-83b17dd7c196
|
|
72
|
-
//
|
|
73
|
-
this.changes = { indexes: {}, operations: [] };
|
|
74
|
-
this.allChanges = { indexes: {}, operations: [] };
|
|
75
|
-
/**
|
|
76
|
-
* Is this a new instance? Used on ArraySchema to determine OPERATION.MOVE_AND_ADD operation.
|
|
77
|
-
*/
|
|
78
|
-
this.isNew = true;
|
|
79
|
-
this.ref = ref;
|
|
80
|
-
this.metadata = ref.constructor[Symbol.metadata];
|
|
81
|
-
//
|
|
82
|
-
// Does this structure have "filters" declared?
|
|
83
|
-
//
|
|
84
|
-
if (this.metadata?.[symbols_1.$viewFieldIndexes]) {
|
|
85
|
-
this.allFilteredChanges = { indexes: {}, operations: [] };
|
|
86
|
-
this.filteredChanges = { indexes: {}, operations: [] };
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
setRoot(root) {
|
|
90
|
-
this.root = root;
|
|
91
|
-
const isNewChangeTree = this.root.add(this);
|
|
92
|
-
this.checkIsFiltered(this.parent, this.parentIndex, isNewChangeTree);
|
|
93
|
-
// Recursively set root on child structures
|
|
94
|
-
if (isNewChangeTree) {
|
|
95
|
-
this.forEachChild((child, _) => {
|
|
96
|
-
if (child.root !== root) {
|
|
97
|
-
child.setRoot(root);
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
root.add(child); // increment refCount
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
setParent(parent, root, parentIndex) {
|
|
106
|
-
this.addParent(parent, parentIndex);
|
|
107
|
-
// avoid setting parents with empty `root`
|
|
108
|
-
if (!root) {
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
const isNewChangeTree = root.add(this);
|
|
112
|
-
// skip if parent is already set
|
|
113
|
-
if (root !== this.root) {
|
|
114
|
-
this.root = root;
|
|
115
|
-
this.checkIsFiltered(parent, parentIndex, isNewChangeTree);
|
|
116
|
-
}
|
|
117
|
-
// assign same parent on child structures
|
|
118
|
-
if (isNewChangeTree) {
|
|
119
|
-
//
|
|
120
|
-
// assign same parent on child structures
|
|
121
|
-
//
|
|
122
|
-
this.forEachChild((child, index) => {
|
|
123
|
-
if (child.root === root) {
|
|
124
|
-
//
|
|
125
|
-
// re-assigning a child of the same root, move it next to parent
|
|
126
|
-
// so encoding order is preserved
|
|
127
|
-
//
|
|
128
|
-
root.add(child);
|
|
129
|
-
root.moveNextToParent(child);
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
child.setParent(this.ref, root, index);
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
forEachChild(callback) {
|
|
137
|
-
//
|
|
138
|
-
// assign same parent on child structures
|
|
139
|
-
//
|
|
140
|
-
if (this.ref[symbols_1.$childType]) {
|
|
141
|
-
if (typeof (this.ref[symbols_1.$childType]) !== "string") {
|
|
142
|
-
// MapSchema / ArraySchema, etc.
|
|
143
|
-
for (const [key, value] of this.ref.entries()) {
|
|
144
|
-
if (!value) {
|
|
145
|
-
continue;
|
|
146
|
-
} // sparse arrays can have undefined values
|
|
147
|
-
callback(value[symbols_1.$changes], this.indexes?.[key] ?? key);
|
|
148
|
-
}
|
|
149
|
-
;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
for (const index of this.metadata?.[symbols_1.$refTypeFieldIndexes] ?? []) {
|
|
154
|
-
const field = this.metadata[index];
|
|
155
|
-
const value = this.ref[field.name];
|
|
156
|
-
if (!value) {
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
callback(value[symbols_1.$changes], index);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
operation(op) {
|
|
164
|
-
// operations without index use negative values to represent them
|
|
165
|
-
// this is checked during .encode() time.
|
|
166
|
-
if (this.filteredChanges !== undefined) {
|
|
167
|
-
this.filteredChanges.operations.push(-op);
|
|
168
|
-
this.root?.enqueueChangeTree(this, 'filteredChanges');
|
|
169
|
-
}
|
|
170
|
-
else {
|
|
171
|
-
this.changes.operations.push(-op);
|
|
172
|
-
this.root?.enqueueChangeTree(this, 'changes');
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
change(index, operation = spec_1.OPERATION.ADD) {
|
|
176
|
-
const isFiltered = this.isFiltered || (this.metadata?.[index]?.tag !== undefined);
|
|
177
|
-
const changeSet = (isFiltered)
|
|
178
|
-
? this.filteredChanges
|
|
179
|
-
: this.changes;
|
|
180
|
-
const previousOperation = this.indexedOperations[index];
|
|
181
|
-
if (!previousOperation || previousOperation === spec_1.OPERATION.DELETE) {
|
|
182
|
-
const op = (!previousOperation)
|
|
183
|
-
? operation
|
|
184
|
-
: (previousOperation === spec_1.OPERATION.DELETE)
|
|
185
|
-
? spec_1.OPERATION.DELETE_AND_ADD
|
|
186
|
-
: operation;
|
|
187
|
-
//
|
|
188
|
-
// TODO: are DELETE operations being encoded as ADD here ??
|
|
189
|
-
//
|
|
190
|
-
this.indexedOperations[index] = op;
|
|
191
|
-
}
|
|
192
|
-
setOperationAtIndex(changeSet, index);
|
|
193
|
-
if (isFiltered) {
|
|
194
|
-
setOperationAtIndex(this.allFilteredChanges, index);
|
|
195
|
-
if (this.root) {
|
|
196
|
-
this.root.enqueueChangeTree(this, 'filteredChanges');
|
|
197
|
-
this.root.enqueueChangeTree(this, 'allFilteredChanges');
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
else {
|
|
201
|
-
setOperationAtIndex(this.allChanges, index);
|
|
202
|
-
this.root?.enqueueChangeTree(this, 'changes');
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
shiftChangeIndexes(shiftIndex) {
|
|
206
|
-
//
|
|
207
|
-
// Used only during:
|
|
208
|
-
//
|
|
209
|
-
// - ArraySchema#unshift()
|
|
210
|
-
//
|
|
211
|
-
const changeSet = (this.isFiltered)
|
|
212
|
-
? this.filteredChanges
|
|
213
|
-
: this.changes;
|
|
214
|
-
const newIndexedOperations = {};
|
|
215
|
-
const newIndexes = {};
|
|
216
|
-
for (const index in this.indexedOperations) {
|
|
217
|
-
newIndexedOperations[Number(index) + shiftIndex] = this.indexedOperations[index];
|
|
218
|
-
newIndexes[Number(index) + shiftIndex] = changeSet.indexes[index];
|
|
219
|
-
}
|
|
220
|
-
this.indexedOperations = newIndexedOperations;
|
|
221
|
-
changeSet.indexes = newIndexes;
|
|
222
|
-
changeSet.operations = changeSet.operations.map((index) => index + shiftIndex);
|
|
223
|
-
}
|
|
224
|
-
shiftAllChangeIndexes(shiftIndex, startIndex = 0) {
|
|
225
|
-
//
|
|
226
|
-
// Used only during:
|
|
227
|
-
//
|
|
228
|
-
// - ArraySchema#splice()
|
|
229
|
-
//
|
|
230
|
-
if (this.filteredChanges !== undefined) {
|
|
231
|
-
this._shiftAllChangeIndexes(shiftIndex, startIndex, this.allFilteredChanges);
|
|
232
|
-
this._shiftAllChangeIndexes(shiftIndex, startIndex, this.allChanges);
|
|
233
|
-
}
|
|
234
|
-
else {
|
|
235
|
-
this._shiftAllChangeIndexes(shiftIndex, startIndex, this.allChanges);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
_shiftAllChangeIndexes(shiftIndex, startIndex = 0, changeSet) {
|
|
239
|
-
const newIndexes = {};
|
|
240
|
-
let newKey = 0;
|
|
241
|
-
for (const key in changeSet.indexes) {
|
|
242
|
-
newIndexes[newKey++] = changeSet.indexes[key];
|
|
243
|
-
}
|
|
244
|
-
changeSet.indexes = newIndexes;
|
|
245
|
-
for (let i = 0; i < changeSet.operations.length; i++) {
|
|
246
|
-
const index = changeSet.operations[i];
|
|
247
|
-
if (index > startIndex) {
|
|
248
|
-
changeSet.operations[i] = index + shiftIndex;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
indexedOperation(index, operation, allChangesIndex = index) {
|
|
253
|
-
this.indexedOperations[index] = operation;
|
|
254
|
-
if (this.filteredChanges !== undefined) {
|
|
255
|
-
setOperationAtIndex(this.allFilteredChanges, allChangesIndex);
|
|
256
|
-
setOperationAtIndex(this.filteredChanges, index);
|
|
257
|
-
this.root?.enqueueChangeTree(this, 'filteredChanges');
|
|
258
|
-
}
|
|
259
|
-
else {
|
|
260
|
-
setOperationAtIndex(this.allChanges, allChangesIndex);
|
|
261
|
-
setOperationAtIndex(this.changes, index);
|
|
262
|
-
this.root?.enqueueChangeTree(this, 'changes');
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
getType(index) {
|
|
266
|
-
return (
|
|
267
|
-
//
|
|
268
|
-
// Get the child type from parent structure.
|
|
269
|
-
// - ["string"] => "string"
|
|
270
|
-
// - { map: "string" } => "string"
|
|
271
|
-
// - { set: "string" } => "string"
|
|
272
|
-
//
|
|
273
|
-
this.ref[symbols_1.$childType] || // ArraySchema | MapSchema | SetSchema | CollectionSchema
|
|
274
|
-
this.metadata[index].type // Schema
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
getChange(index) {
|
|
278
|
-
return this.indexedOperations[index];
|
|
279
|
-
}
|
|
280
|
-
//
|
|
281
|
-
// used during `.encode()`
|
|
282
|
-
//
|
|
283
|
-
getValue(index, isEncodeAll = false) {
|
|
284
|
-
//
|
|
285
|
-
// `isEncodeAll` param is only used by ArraySchema
|
|
286
|
-
//
|
|
287
|
-
return this.ref[symbols_1.$getByIndex](index, isEncodeAll);
|
|
288
|
-
}
|
|
289
|
-
delete(index, operation, allChangesIndex = index) {
|
|
290
|
-
if (index === undefined) {
|
|
291
|
-
try {
|
|
292
|
-
throw new Error(`@colyseus/schema ${this.ref.constructor.name}: trying to delete non-existing index '${index}'`);
|
|
293
|
-
}
|
|
294
|
-
catch (e) {
|
|
295
|
-
console.warn(e);
|
|
296
|
-
}
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
const changeSet = (this.filteredChanges !== undefined)
|
|
300
|
-
? this.filteredChanges
|
|
301
|
-
: this.changes;
|
|
302
|
-
this.indexedOperations[index] = operation ?? spec_1.OPERATION.DELETE;
|
|
303
|
-
setOperationAtIndex(changeSet, index);
|
|
304
|
-
deleteOperationAtIndex(this.allChanges, allChangesIndex);
|
|
305
|
-
const previousValue = this.getValue(index);
|
|
306
|
-
// remove `root` reference
|
|
307
|
-
if (previousValue && previousValue[symbols_1.$changes]) {
|
|
308
|
-
//
|
|
309
|
-
// FIXME: this.root is "undefined"
|
|
310
|
-
//
|
|
311
|
-
// This method is being called at decoding time when a DELETE operation is found.
|
|
312
|
-
//
|
|
313
|
-
// - This is due to using the concrete Schema class at decoding time.
|
|
314
|
-
// - "Reflected" structures do not have this problem.
|
|
315
|
-
//
|
|
316
|
-
// (The property descriptors should NOT be used at decoding time. only at encoding time.)
|
|
317
|
-
//
|
|
318
|
-
this.root?.remove(previousValue[symbols_1.$changes]);
|
|
319
|
-
}
|
|
320
|
-
//
|
|
321
|
-
// FIXME: this is looking a ugly and repeated
|
|
322
|
-
//
|
|
323
|
-
if (this.filteredChanges !== undefined) {
|
|
324
|
-
deleteOperationAtIndex(this.allFilteredChanges, allChangesIndex);
|
|
325
|
-
this.root?.enqueueChangeTree(this, 'filteredChanges');
|
|
326
|
-
}
|
|
327
|
-
else {
|
|
328
|
-
this.root?.enqueueChangeTree(this, 'changes');
|
|
329
|
-
}
|
|
330
|
-
return previousValue;
|
|
331
|
-
}
|
|
332
|
-
endEncode(changeSetName) {
|
|
333
|
-
this.indexedOperations = {};
|
|
334
|
-
// clear changeset
|
|
335
|
-
this[changeSetName] = createChangeSet();
|
|
336
|
-
// ArraySchema and MapSchema have a custom "encode end" method
|
|
337
|
-
this.ref[symbols_1.$onEncodeEnd]?.();
|
|
338
|
-
// Not a new instance anymore
|
|
339
|
-
this.isNew = false;
|
|
340
|
-
}
|
|
341
|
-
discard(discardAll = false) {
|
|
342
|
-
//
|
|
343
|
-
// > MapSchema:
|
|
344
|
-
// Remove cached key to ensure ADD operations is unsed instead of
|
|
345
|
-
// REPLACE in case same key is used on next patches.
|
|
346
|
-
//
|
|
347
|
-
this.ref[symbols_1.$onEncodeEnd]?.();
|
|
348
|
-
this.indexedOperations = {};
|
|
349
|
-
this.changes = createChangeSet(this.changes.queueRootNode);
|
|
350
|
-
if (this.filteredChanges !== undefined) {
|
|
351
|
-
this.filteredChanges = createChangeSet(this.filteredChanges.queueRootNode);
|
|
352
|
-
}
|
|
353
|
-
if (discardAll) {
|
|
354
|
-
// preserve queueRootNode references
|
|
355
|
-
this.allChanges = createChangeSet(this.allChanges.queueRootNode);
|
|
356
|
-
if (this.allFilteredChanges !== undefined) {
|
|
357
|
-
this.allFilteredChanges = createChangeSet(this.allFilteredChanges.queueRootNode);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
/**
|
|
362
|
-
* Recursively discard all changes from this, and child structures.
|
|
363
|
-
* (Used in tests only)
|
|
364
|
-
*/
|
|
365
|
-
discardAll() {
|
|
366
|
-
const keys = Object.keys(this.indexedOperations);
|
|
367
|
-
for (let i = 0, len = keys.length; i < len; i++) {
|
|
368
|
-
const value = this.getValue(Number(keys[i]));
|
|
369
|
-
if (value && value[symbols_1.$changes]) {
|
|
370
|
-
value[symbols_1.$changes].discardAll();
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
this.discard();
|
|
374
|
-
}
|
|
375
|
-
get changed() {
|
|
376
|
-
return (Object.entries(this.indexedOperations).length > 0);
|
|
377
|
-
}
|
|
378
|
-
checkIsFiltered(parent, parentIndex, isNewChangeTree) {
|
|
379
|
-
if (this.root.types.hasFilters) {
|
|
380
|
-
//
|
|
381
|
-
// At Schema initialization, the "root" structure might not be available
|
|
382
|
-
// yet, as it only does once the "Encoder" has been set up.
|
|
383
|
-
//
|
|
384
|
-
// So the "parent" may be already set without a "root".
|
|
385
|
-
//
|
|
386
|
-
this._checkFilteredByParent(parent, parentIndex);
|
|
387
|
-
if (this.filteredChanges !== undefined) {
|
|
388
|
-
this.root?.enqueueChangeTree(this, 'filteredChanges');
|
|
389
|
-
if (isNewChangeTree) {
|
|
390
|
-
this.root?.enqueueChangeTree(this, 'allFilteredChanges');
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
if (!this.isFiltered) {
|
|
395
|
-
this.root?.enqueueChangeTree(this, 'changes');
|
|
396
|
-
if (isNewChangeTree) {
|
|
397
|
-
this.root?.enqueueChangeTree(this, 'allChanges');
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
_checkFilteredByParent(parent, parentIndex) {
|
|
402
|
-
// skip if parent is not set
|
|
403
|
-
if (!parent) {
|
|
404
|
-
return;
|
|
405
|
-
}
|
|
406
|
-
//
|
|
407
|
-
// ArraySchema | MapSchema - get the child type
|
|
408
|
-
// (if refType is typeof string, the parentFiltered[key] below will always be invalid)
|
|
409
|
-
//
|
|
410
|
-
const refType = Metadata_1.Metadata.isValidInstance(this.ref)
|
|
411
|
-
? this.ref.constructor
|
|
412
|
-
: this.ref[symbols_1.$childType];
|
|
413
|
-
let parentChangeTree;
|
|
414
|
-
let parentIsCollection = !Metadata_1.Metadata.isValidInstance(parent);
|
|
415
|
-
if (parentIsCollection) {
|
|
416
|
-
parentChangeTree = parent[symbols_1.$changes];
|
|
417
|
-
parent = parentChangeTree.parent;
|
|
418
|
-
parentIndex = parentChangeTree.parentIndex;
|
|
419
|
-
}
|
|
420
|
-
else {
|
|
421
|
-
parentChangeTree = parent[symbols_1.$changes];
|
|
422
|
-
}
|
|
423
|
-
const parentConstructor = parent.constructor;
|
|
424
|
-
let key = `${this.root.types.getTypeId(refType)}`;
|
|
425
|
-
if (parentConstructor) {
|
|
426
|
-
key += `-${this.root.types.schemas.get(parentConstructor)}`;
|
|
427
|
-
}
|
|
428
|
-
key += `-${parentIndex}`;
|
|
429
|
-
const fieldHasViewTag = Metadata_1.Metadata.hasViewTagAtIndex(parentConstructor?.[Symbol.metadata], parentIndex);
|
|
430
|
-
this.isFiltered = parent[symbols_1.$changes].isFiltered // in case parent is already filtered
|
|
431
|
-
|| this.root.types.parentFiltered[key]
|
|
432
|
-
|| fieldHasViewTag;
|
|
433
|
-
//
|
|
434
|
-
// "isFiltered" may not be imedialely available during `change()` due to the instance not being attached to the root yet.
|
|
435
|
-
// when it's available, we need to enqueue the "changes" changeset into the "filteredChanges" changeset.
|
|
436
|
-
//
|
|
437
|
-
if (this.isFiltered) {
|
|
438
|
-
this.isVisibilitySharedWithParent = (parentChangeTree.isFiltered &&
|
|
439
|
-
typeof (refType) !== "string" &&
|
|
440
|
-
!fieldHasViewTag &&
|
|
441
|
-
parentIsCollection);
|
|
442
|
-
if (!this.filteredChanges) {
|
|
443
|
-
this.filteredChanges = createChangeSet();
|
|
444
|
-
this.allFilteredChanges = createChangeSet();
|
|
445
|
-
}
|
|
446
|
-
if (this.changes.operations.length > 0) {
|
|
447
|
-
this.changes.operations.forEach((index) => setOperationAtIndex(this.filteredChanges, index));
|
|
448
|
-
this.allChanges.operations.forEach((index) => setOperationAtIndex(this.allFilteredChanges, index));
|
|
449
|
-
this.changes = createChangeSet();
|
|
450
|
-
this.allChanges = createChangeSet();
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
/**
|
|
455
|
-
* Get the immediate parent
|
|
456
|
-
*/
|
|
457
|
-
get parent() {
|
|
458
|
-
return this.parentChain?.ref;
|
|
459
|
-
}
|
|
460
|
-
/**
|
|
461
|
-
* Get the immediate parent index
|
|
462
|
-
*/
|
|
463
|
-
get parentIndex() {
|
|
464
|
-
return this.parentChain?.index;
|
|
465
|
-
}
|
|
466
|
-
/**
|
|
467
|
-
* Add a parent to the chain
|
|
468
|
-
*/
|
|
469
|
-
addParent(parent, index) {
|
|
470
|
-
// Check if this parent already exists in the chain
|
|
471
|
-
if (this.hasParent((p, _) => p[symbols_1.$changes] === parent[symbols_1.$changes])) {
|
|
472
|
-
// if (this.hasParent((p, i) => p[$changes] === parent[$changes] && i === index)) {
|
|
473
|
-
this.parentChain.index = index;
|
|
474
|
-
return;
|
|
475
|
-
}
|
|
476
|
-
this.parentChain = {
|
|
477
|
-
ref: parent,
|
|
478
|
-
index,
|
|
479
|
-
next: this.parentChain
|
|
480
|
-
};
|
|
481
|
-
}
|
|
482
|
-
/**
|
|
483
|
-
* Remove a parent from the chain
|
|
484
|
-
* @param parent - The parent to remove
|
|
485
|
-
* @returns true if parent was removed
|
|
486
|
-
*/
|
|
487
|
-
removeParent(parent = this.parent) {
|
|
488
|
-
let current = this.parentChain;
|
|
489
|
-
let previous = null;
|
|
490
|
-
while (current) {
|
|
491
|
-
//
|
|
492
|
-
// FIXME: it is required to check against `$changes` here because
|
|
493
|
-
// ArraySchema is instance of Proxy
|
|
494
|
-
//
|
|
495
|
-
if (current.ref[symbols_1.$changes] === parent[symbols_1.$changes]) {
|
|
496
|
-
if (previous) {
|
|
497
|
-
previous.next = current.next;
|
|
498
|
-
}
|
|
499
|
-
else {
|
|
500
|
-
this.parentChain = current.next;
|
|
501
|
-
}
|
|
502
|
-
return true;
|
|
503
|
-
}
|
|
504
|
-
previous = current;
|
|
505
|
-
current = current.next;
|
|
506
|
-
}
|
|
507
|
-
return this.parentChain === undefined;
|
|
508
|
-
}
|
|
509
|
-
/**
|
|
510
|
-
* Find a specific parent in the chain
|
|
511
|
-
*/
|
|
512
|
-
findParent(predicate) {
|
|
513
|
-
let current = this.parentChain;
|
|
514
|
-
while (current) {
|
|
515
|
-
if (predicate(current.ref, current.index)) {
|
|
516
|
-
return current;
|
|
517
|
-
}
|
|
518
|
-
current = current.next;
|
|
519
|
-
}
|
|
520
|
-
return undefined;
|
|
521
|
-
}
|
|
522
|
-
/**
|
|
523
|
-
* Check if this ChangeTree has a specific parent
|
|
524
|
-
*/
|
|
525
|
-
hasParent(predicate) {
|
|
526
|
-
return this.findParent(predicate) !== undefined;
|
|
527
|
-
}
|
|
528
|
-
/**
|
|
529
|
-
* Get all parents as an array (for debugging/testing)
|
|
530
|
-
*/
|
|
531
|
-
getAllParents() {
|
|
532
|
-
const parents = [];
|
|
533
|
-
let current = this.parentChain;
|
|
534
|
-
while (current) {
|
|
535
|
-
parents.push({ ref: current.ref, index: current.index });
|
|
536
|
-
current = current.next;
|
|
537
|
-
}
|
|
538
|
-
return parents;
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
exports.ChangeTree = ChangeTree;
|
|
542
|
-
//# sourceMappingURL=ChangeTree.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ChangeTree.js","sourceRoot":"","sources":["../../src/encoder/ChangeTree.ts"],"names":[],"mappings":"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","sourcesContent":["import { OPERATION } from \"../encoding/spec\";\nimport { Schema } from \"../Schema\";\nimport { $changes, $childType, $decoder, $onEncodeEnd, $encoder, $getByIndex, $refId, $refTypeFieldIndexes, $viewFieldIndexes, type $deleteByIndex } from \"../types/symbols\";\n\nimport type { MapSchema } from \"../types/custom/MapSchema\";\nimport type { ArraySchema } from \"../types/custom/ArraySchema\";\nimport type { CollectionSchema } from \"../types/custom/CollectionSchema\";\nimport type { SetSchema } from \"../types/custom/SetSchema\";\n\nimport { Root } from \"./Root\";\nimport { Metadata } from \"../Metadata\";\nimport type { EncodeOperation } from \"./EncodeOperation\";\nimport type { DecodeOperation } from \"../decoder/DecodeOperation\";\n\ndeclare global {\n interface Object {\n // FIXME: not a good practice to extend globals here\n [$changes]?: ChangeTree;\n // [$refId]?: number;\n [$encoder]?: EncodeOperation,\n [$decoder]?: DecodeOperation,\n }\n}\n\nexport interface IRef {\n [$changes]?: ChangeTree;\n [$refId]?: number;\n [$getByIndex]?: (index: number, isEncodeAll?: boolean) => any;\n [$deleteByIndex]?: (index: number) => void;\n}\n\nexport type Ref = Schema | ArraySchema | MapSchema | CollectionSchema | SetSchema;\n\nexport type ChangeSetName = \"changes\"\n | \"allChanges\"\n | \"filteredChanges\"\n | \"allFilteredChanges\";\n\nexport interface IndexedOperations {\n [index: number]: OPERATION;\n}\n\n// Linked list node for change trees\nexport interface ChangeTreeNode {\n changeTree: ChangeTree;\n next?: ChangeTreeNode;\n prev?: ChangeTreeNode;\n position: number; // Cached position in the linked list for O(1) lookup\n}\n\n// Linked list for change trees\nexport interface ChangeTreeList {\n next?: ChangeTreeNode;\n tail?: ChangeTreeNode;\n}\n\nexport interface ChangeSet {\n // field index -> operation index\n indexes: { [index: number]: number };\n operations: number[];\n queueRootNode?: ChangeTreeNode; // direct reference to ChangeTreeNode in the linked list\n}\n\nfunction createChangeSet(queueRootNode?: ChangeTreeNode): ChangeSet {\n return { indexes: {}, operations: [], queueRootNode };\n}\n\n// Linked list helper functions\nexport function createChangeTreeList(): ChangeTreeList {\n return { next: undefined, tail: undefined };\n}\n\nexport function setOperationAtIndex(changeSet: ChangeSet, index: number) {\n const operationsIndex = changeSet.indexes[index];\n if (operationsIndex === undefined) {\n changeSet.indexes[index] = changeSet.operations.push(index) - 1;\n } else {\n changeSet.operations[operationsIndex] = index;\n }\n}\n\nexport function deleteOperationAtIndex(changeSet: ChangeSet, index: number | string) {\n let operationsIndex = changeSet.indexes[index as any as number];\n if (operationsIndex === undefined) {\n //\n // if index is not found, we need to find the last operation\n // FIXME: this is not very efficient\n //\n // > See \"should allow consecutive splices (same place)\" tests\n //\n operationsIndex = Object.values(changeSet.indexes).at(-1);\n index = Object.entries(changeSet.indexes).find(([_, value]) => value === operationsIndex)?.[0];\n }\n changeSet.operations[operationsIndex] = undefined;\n delete changeSet.indexes[index as any as number];\n}\n\nexport function debugChangeSet(label: string, changeSet: ChangeSet) {\n let indexes: string[] = [];\n let operations: string[] = [];\n\n for (const index in changeSet.indexes) {\n indexes.push(`\\t${index} => [${changeSet.indexes[index]}]`);\n }\n\n for (let i = 0; i < changeSet.operations.length; i++) {\n const index = changeSet.operations[i];\n if (index !== undefined) {\n operations.push(`\\t[${i}] => ${index}`);\n }\n }\n\n console.log(`${label} =>\\nindexes (${Object.keys(changeSet.indexes).length}) {`);\n console.log(indexes.join(\"\\n\"), \"\\n}\");\n console.log(`operations (${changeSet.operations.filter(op => op !== undefined).length}) {`);\n console.log(operations.join(\"\\n\"), \"\\n}\");\n}\n\nexport interface ParentChain {\n ref: Ref;\n index: number;\n next?: ParentChain;\n}\n\nexport class ChangeTree<T extends Ref = any> {\n ref: T;\n metadata: Metadata;\n\n root?: Root;\n parentChain?: ParentChain; // Linked list for tracking parents\n\n /**\n * Whether this structure is parent of a filtered structure.\n */\n isFiltered: boolean = false;\n isVisibilitySharedWithParent?: boolean; // See test case: 'should not be required to manually call view.add() items to child arrays without @view() tag'\n\n indexedOperations: IndexedOperations = {};\n\n //\n // TODO:\n // try storing the index + operation per item.\n // example: 1024 & 1025 => ADD, 1026 => DELETE\n //\n // => https://chatgpt.com/share/67107d0c-bc20-8004-8583-83b17dd7c196\n //\n changes: ChangeSet = { indexes: {}, operations: [] };\n allChanges: ChangeSet = { indexes: {}, operations: [] };\n filteredChanges: ChangeSet;\n allFilteredChanges: ChangeSet;\n\n indexes: { [index: string]: any }; // TODO: remove this, only used by MapSchema/SetSchema/CollectionSchema (`encodeKeyValueOperation`)\n\n /**\n * Is this a new instance? Used on ArraySchema to determine OPERATION.MOVE_AND_ADD operation.\n */\n isNew = true;\n\n constructor(ref: T) {\n this.ref = ref;\n this.metadata = (ref.constructor as typeof Schema)[Symbol.metadata];\n\n //\n // Does this structure have \"filters\" declared?\n //\n if (this.metadata?.[$viewFieldIndexes]) {\n this.allFilteredChanges = { indexes: {}, operations: [] };\n this.filteredChanges = { indexes: {}, operations: [] };\n }\n }\n\n setRoot(root: Root) {\n this.root = root;\n\n const isNewChangeTree = this.root.add(this);\n\n this.checkIsFiltered(this.parent, this.parentIndex, isNewChangeTree);\n\n // Recursively set root on child structures\n if (isNewChangeTree) {\n this.forEachChild((child, _) => {\n if (child.root !== root) {\n child.setRoot(root);\n } else {\n root.add(child); // increment refCount\n }\n });\n }\n }\n\n setParent(\n parent: Ref,\n root?: Root,\n parentIndex?: number,\n ) {\n this.addParent(parent, parentIndex);\n\n // avoid setting parents with empty `root`\n if (!root) { return; }\n\n const isNewChangeTree = root.add(this);\n\n // skip if parent is already set\n if (root !== this.root) {\n this.root = root;\n this.checkIsFiltered(parent, parentIndex, isNewChangeTree);\n }\n\n // assign same parent on child structures\n if (isNewChangeTree) {\n //\n // assign same parent on child structures\n //\n this.forEachChild((child, index) => {\n if (child.root === root) {\n //\n // re-assigning a child of the same root, move it next to parent\n // so encoding order is preserved\n //\n root.add(child);\n root.moveNextToParent(child);\n return;\n }\n child.setParent(this.ref, root, index);\n });\n }\n }\n\n forEachChild(callback: (change: ChangeTree, at: any) => void) {\n //\n // assign same parent on child structures\n //\n if ((this.ref as any)[$childType]) {\n if (typeof ((this.ref as any)[$childType]) !== \"string\") {\n // MapSchema / ArraySchema, etc.\n for (const [key, value] of (this.ref as MapSchema).entries()) {\n if (!value) { continue; } // sparse arrays can have undefined values\n callback(value[$changes], this.indexes?.[key] ?? key);\n };\n }\n\n } else {\n for (const index of this.metadata?.[$refTypeFieldIndexes] ?? []) {\n const field = this.metadata[index as any as number];\n const value = this.ref[field.name as keyof Ref];\n if (!value) { continue; }\n callback(value[$changes], index);\n }\n }\n }\n\n operation(op: OPERATION) {\n // operations without index use negative values to represent them\n // this is checked during .encode() time.\n if (this.filteredChanges !== undefined) {\n this.filteredChanges.operations.push(-op);\n this.root?.enqueueChangeTree(this, 'filteredChanges');\n\n } else {\n this.changes.operations.push(-op);\n this.root?.enqueueChangeTree(this, 'changes');\n }\n }\n\n change(index: number, operation: OPERATION = OPERATION.ADD) {\n const isFiltered = this.isFiltered || (this.metadata?.[index]?.tag !== undefined);\n const changeSet = (isFiltered)\n ? this.filteredChanges\n : this.changes;\n\n const previousOperation = this.indexedOperations[index];\n if (!previousOperation || previousOperation === OPERATION.DELETE) {\n const op = (!previousOperation)\n ? operation\n : (previousOperation === OPERATION.DELETE)\n ? OPERATION.DELETE_AND_ADD\n : operation\n //\n // TODO: are DELETE operations being encoded as ADD here ??\n //\n this.indexedOperations[index] = op;\n }\n\n setOperationAtIndex(changeSet, index);\n\n if (isFiltered) {\n setOperationAtIndex(this.allFilteredChanges, index);\n\n if (this.root) {\n this.root.enqueueChangeTree(this, 'filteredChanges');\n this.root.enqueueChangeTree(this, 'allFilteredChanges');\n }\n\n } else {\n setOperationAtIndex(this.allChanges, index);\n this.root?.enqueueChangeTree(this, 'changes');\n }\n }\n\n shiftChangeIndexes(shiftIndex: number) {\n //\n // Used only during:\n //\n // - ArraySchema#unshift()\n //\n const changeSet = (this.isFiltered)\n ? this.filteredChanges\n : this.changes;\n\n const newIndexedOperations: any = {};\n const newIndexes: { [index: number]: number } = {};\n for (const index in this.indexedOperations) {\n newIndexedOperations[Number(index) + shiftIndex] = this.indexedOperations[index];\n newIndexes[Number(index) + shiftIndex] = changeSet.indexes[index];\n }\n this.indexedOperations = newIndexedOperations;\n changeSet.indexes = newIndexes;\n\n changeSet.operations = changeSet.operations.map((index) => index + shiftIndex);\n }\n\n shiftAllChangeIndexes(shiftIndex: number, startIndex: number = 0) {\n //\n // Used only during:\n //\n // - ArraySchema#splice()\n //\n if (this.filteredChanges !== undefined) {\n this._shiftAllChangeIndexes(shiftIndex, startIndex, this.allFilteredChanges);\n this._shiftAllChangeIndexes(shiftIndex, startIndex, this.allChanges);\n\n } else {\n this._shiftAllChangeIndexes(shiftIndex, startIndex, this.allChanges);\n }\n }\n\n private _shiftAllChangeIndexes(shiftIndex: number, startIndex: number = 0, changeSet: ChangeSet) {\n const newIndexes: { [index: number]: number } = {};\n let newKey = 0;\n for (const key in changeSet.indexes) {\n newIndexes[newKey++] = changeSet.indexes[key];\n }\n changeSet.indexes = newIndexes;\n\n for (let i = 0; i < changeSet.operations.length; i++) {\n const index = changeSet.operations[i];\n if (index > startIndex) {\n changeSet.operations[i] = index + shiftIndex;\n }\n }\n }\n\n indexedOperation(index: number, operation: OPERATION, allChangesIndex: number = index) {\n this.indexedOperations[index] = operation;\n\n if (this.filteredChanges !== undefined) {\n setOperationAtIndex(this.allFilteredChanges, allChangesIndex);\n setOperationAtIndex(this.filteredChanges, index);\n this.root?.enqueueChangeTree(this, 'filteredChanges');\n\n } else {\n setOperationAtIndex(this.allChanges, allChangesIndex);\n setOperationAtIndex(this.changes, index);\n this.root?.enqueueChangeTree(this, 'changes');\n }\n }\n\n getType(index?: number) {\n return (\n //\n // Get the child type from parent structure.\n // - [\"string\"] => \"string\"\n // - { map: \"string\" } => \"string\"\n // - { set: \"string\" } => \"string\"\n //\n (this.ref as any)[$childType] || // ArraySchema | MapSchema | SetSchema | CollectionSchema\n this.metadata[index].type // Schema\n );\n }\n\n getChange(index: number) {\n return this.indexedOperations[index];\n }\n\n //\n // used during `.encode()`\n //\n getValue(index: number, isEncodeAll: boolean = false) {\n //\n // `isEncodeAll` param is only used by ArraySchema\n //\n return (this.ref as any)[$getByIndex](index, isEncodeAll);\n }\n\n delete(index: number, operation?: OPERATION, allChangesIndex = index) {\n if (index === undefined) {\n try {\n throw new Error(`@colyseus/schema ${this.ref.constructor.name}: trying to delete non-existing index '${index}'`);\n } catch (e) {\n console.warn(e);\n }\n return;\n }\n\n const changeSet = (this.filteredChanges !== undefined)\n ? this.filteredChanges\n : this.changes;\n\n this.indexedOperations[index] = operation ?? OPERATION.DELETE;\n setOperationAtIndex(changeSet, index);\n deleteOperationAtIndex(this.allChanges, allChangesIndex);\n\n const previousValue = this.getValue(index);\n\n // remove `root` reference\n if (previousValue && previousValue[$changes]) {\n //\n // FIXME: this.root is \"undefined\"\n //\n // This method is being called at decoding time when a DELETE operation is found.\n //\n // - This is due to using the concrete Schema class at decoding time.\n // - \"Reflected\" structures do not have this problem.\n //\n // (The property descriptors should NOT be used at decoding time. only at encoding time.)\n //\n this.root?.remove(previousValue[$changes]);\n }\n\n //\n // FIXME: this is looking a ugly and repeated\n //\n if (this.filteredChanges !== undefined) {\n deleteOperationAtIndex(this.allFilteredChanges, allChangesIndex);\n this.root?.enqueueChangeTree(this, 'filteredChanges');\n\n } else {\n this.root?.enqueueChangeTree(this, 'changes');\n }\n\n return previousValue;\n }\n\n endEncode(changeSetName: ChangeSetName) {\n this.indexedOperations = {};\n\n // clear changeset\n this[changeSetName] = createChangeSet();\n\n // ArraySchema and MapSchema have a custom \"encode end\" method\n (this.ref as any)[$onEncodeEnd]?.();\n\n // Not a new instance anymore\n this.isNew = false;\n }\n\n discard(discardAll: boolean = false) {\n //\n // > MapSchema:\n // Remove cached key to ensure ADD operations is unsed instead of\n // REPLACE in case same key is used on next patches.\n //\n (this.ref as any)[$onEncodeEnd]?.();\n\n this.indexedOperations = {};\n this.changes = createChangeSet(this.changes.queueRootNode);\n\n if (this.filteredChanges !== undefined) {\n this.filteredChanges = createChangeSet(this.filteredChanges.queueRootNode);\n }\n\n if (discardAll) {\n // preserve queueRootNode references\n this.allChanges = createChangeSet(this.allChanges.queueRootNode);\n\n if (this.allFilteredChanges !== undefined) {\n this.allFilteredChanges = createChangeSet(this.allFilteredChanges.queueRootNode);\n }\n }\n }\n\n /**\n * Recursively discard all changes from this, and child structures.\n * (Used in tests only)\n */\n discardAll() {\n const keys = Object.keys(this.indexedOperations);\n for (let i = 0, len = keys.length; i < len; i++) {\n const value = this.getValue(Number(keys[i]));\n\n if (value && value[$changes]) {\n value[$changes].discardAll();\n }\n }\n\n this.discard();\n }\n\n get changed() {\n return (Object.entries(this.indexedOperations).length > 0);\n }\n\n protected checkIsFiltered(parent: Ref, parentIndex: number, isNewChangeTree: boolean) {\n if (this.root.types.hasFilters) {\n //\n // At Schema initialization, the \"root\" structure might not be available\n // yet, as it only does once the \"Encoder\" has been set up.\n //\n // So the \"parent\" may be already set without a \"root\".\n //\n this._checkFilteredByParent(parent, parentIndex);\n\n if (this.filteredChanges !== undefined) {\n this.root?.enqueueChangeTree(this, 'filteredChanges');\n\n if (isNewChangeTree) {\n this.root?.enqueueChangeTree(this, 'allFilteredChanges');\n }\n }\n }\n\n if (!this.isFiltered) {\n this.root?.enqueueChangeTree(this, 'changes');\n\n if (isNewChangeTree) {\n this.root?.enqueueChangeTree(this, 'allChanges');\n }\n }\n }\n\n protected _checkFilteredByParent(parent: Ref, parentIndex: number) {\n // skip if parent is not set\n if (!parent) { return; }\n\n //\n // ArraySchema | MapSchema - get the child type\n // (if refType is typeof string, the parentFiltered[key] below will always be invalid)\n //\n const refType = Metadata.isValidInstance(this.ref)\n ? this.ref.constructor\n : (this.ref as any)[$childType];\n\n let parentChangeTree: ChangeTree;\n\n let parentIsCollection = !Metadata.isValidInstance(parent);\n if (parentIsCollection) {\n parentChangeTree = parent[$changes];\n parent = parentChangeTree.parent;\n parentIndex = parentChangeTree.parentIndex;\n\n } else {\n parentChangeTree = parent[$changes]\n }\n\n const parentConstructor = parent.constructor as typeof Schema;\n\n let key = `${this.root.types.getTypeId(refType as typeof Schema)}`;\n if (parentConstructor) {\n key += `-${this.root.types.schemas.get(parentConstructor)}`;\n }\n key += `-${parentIndex}`;\n\n const fieldHasViewTag = Metadata.hasViewTagAtIndex(parentConstructor?.[Symbol.metadata], parentIndex);\n\n this.isFiltered = parent[$changes].isFiltered // in case parent is already filtered\n || this.root.types.parentFiltered[key]\n || fieldHasViewTag;\n\n //\n // \"isFiltered\" may not be imedialely available during `change()` due to the instance not being attached to the root yet.\n // when it's available, we need to enqueue the \"changes\" changeset into the \"filteredChanges\" changeset.\n //\n if (this.isFiltered) {\n\n this.isVisibilitySharedWithParent = (\n parentChangeTree.isFiltered &&\n typeof (refType) !== \"string\" &&\n !fieldHasViewTag &&\n parentIsCollection\n );\n\n if (!this.filteredChanges) {\n this.filteredChanges = createChangeSet();\n this.allFilteredChanges = createChangeSet();\n }\n\n if (this.changes.operations.length > 0) {\n this.changes.operations.forEach((index) =>\n setOperationAtIndex(this.filteredChanges, index));\n\n this.allChanges.operations.forEach((index) =>\n setOperationAtIndex(this.allFilteredChanges, index));\n\n this.changes = createChangeSet();\n this.allChanges = createChangeSet();\n }\n }\n }\n\n /**\n * Get the immediate parent\n */\n get parent(): Ref | undefined {\n return this.parentChain?.ref;\n }\n\n /**\n * Get the immediate parent index\n */\n get parentIndex(): number | undefined {\n return this.parentChain?.index;\n }\n\n /**\n * Add a parent to the chain\n */\n addParent(parent: Ref, index: number) {\n // Check if this parent already exists in the chain\n if (this.hasParent((p, _) => p[$changes] === parent[$changes])) {\n // if (this.hasParent((p, i) => p[$changes] === parent[$changes] && i === index)) {\n this.parentChain.index = index;\n return;\n }\n\n this.parentChain = {\n ref: parent,\n index,\n next: this.parentChain\n };\n }\n\n /**\n * Remove a parent from the chain\n * @param parent - The parent to remove\n * @returns true if parent was removed\n */\n removeParent(parent: Ref = this.parent): boolean {\n let current = this.parentChain;\n let previous = null;\n while (current) {\n //\n // FIXME: it is required to check against `$changes` here because\n // ArraySchema is instance of Proxy\n //\n if (current.ref[$changes] === parent[$changes]) {\n if (previous) {\n previous.next = current.next;\n } else {\n this.parentChain = current.next;\n }\n return true;\n }\n previous = current;\n current = current.next;\n }\n return this.parentChain === undefined;\n }\n\n /**\n * Find a specific parent in the chain\n */\n findParent(predicate: (parent: Ref, index: number) => boolean): ParentChain | undefined {\n let current = this.parentChain;\n while (current) {\n if (predicate(current.ref, current.index)) {\n return current;\n }\n current = current.next;\n }\n return undefined;\n }\n\n /**\n * Check if this ChangeTree has a specific parent\n */\n hasParent(predicate: (parent: Ref, index: number) => boolean): boolean {\n return this.findParent(predicate) !== undefined;\n }\n\n /**\n * Get all parents as an array (for debugging/testing)\n */\n getAllParents(): Array<{ ref: Ref, index: number }> {\n const parents: Array<{ ref: Ref, index: number }> = [];\n let current = this.parentChain;\n while (current) {\n parents.push({ ref: current.ref, index: current.index });\n current = current.next;\n }\n return parents;\n }\n\n}\n"]}
|