@colyseus/schema 4.0.1 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/{index.js → index.cjs} +1 -1
- package/build/cjs/index.cjs.map +1 -0
- package/build/esm/index.mjs.map +1 -1
- package/lib/Metadata.js +54 -58
- package/lib/Metadata.js.map +1 -1
- package/lib/Reflection.js +29 -32
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.js +41 -45
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.d.ts +1 -1
- package/lib/annotations.js +58 -69
- package/lib/annotations.js.map +1 -1
- package/lib/bench_encode.js +24 -59
- package/lib/bench_encode.js.map +1 -1
- package/lib/benchmark.d.ts +1 -0
- package/lib/benchmark.js +218 -0
- package/lib/benchmark.js.map +1 -0
- package/lib/codegen/api.js +10 -41
- package/lib/codegen/api.js.map +1 -1
- package/lib/codegen/argv.js +1 -3
- package/lib/codegen/argv.js.map +1 -1
- package/lib/codegen/cli.js +4 -9
- package/lib/codegen/cli.js.map +1 -1
- package/lib/codegen/languages/cpp.js +5 -8
- package/lib/codegen/languages/cpp.js.map +1 -1
- package/lib/codegen/languages/csharp.js +5 -8
- package/lib/codegen/languages/csharp.js.map +1 -1
- package/lib/codegen/languages/haxe.js +3 -6
- package/lib/codegen/languages/haxe.js.map +1 -1
- package/lib/codegen/languages/java.js +3 -6
- package/lib/codegen/languages/java.js.map +1 -1
- package/lib/codegen/languages/js.js +4 -7
- package/lib/codegen/languages/js.js.map +1 -1
- package/lib/codegen/languages/lua.js +4 -7
- package/lib/codegen/languages/lua.js.map +1 -1
- package/lib/codegen/languages/ts.js +5 -8
- package/lib/codegen/languages/ts.js.map +1 -1
- package/lib/codegen/parser.js +22 -59
- package/lib/codegen/parser.js.map +1 -1
- package/lib/codegen/types.js +12 -51
- package/lib/codegen/types.js.map +1 -1
- package/lib/decoder/DecodeOperation.js +44 -51
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/decoder/Decoder.js +24 -28
- package/lib/decoder/Decoder.js.map +1 -1
- package/lib/decoder/ReferenceTracker.js +10 -14
- package/lib/decoder/ReferenceTracker.js.map +1 -1
- package/lib/decoder/strategy/Callbacks.js +39 -43
- package/lib/decoder/strategy/Callbacks.js.map +1 -1
- package/lib/decoder/strategy/RawChanges.js +1 -4
- package/lib/decoder/strategy/RawChanges.js.map +1 -1
- package/lib/decoder/strategy/getDecoderStateCallbacks.js +24 -27
- package/lib/decoder/strategy/getDecoderStateCallbacks.js.map +1 -1
- package/lib/encoder/ChangeTree.js +36 -44
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/EncodeOperation.js +25 -32
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.js +25 -29
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.js +17 -21
- package/lib/encoder/Root.js.map +1 -1
- package/lib/encoder/StateView.js +40 -45
- package/lib/encoder/StateView.js.map +1 -1
- package/lib/encoding/assert.js +3 -9
- package/lib/encoding/assert.js.map +1 -1
- package/lib/encoding/decode.js +2 -6
- package/lib/encoding/decode.js.map +1 -1
- package/lib/encoding/encode.js +1 -4
- package/lib/encoding/encode.js.map +1 -1
- package/lib/encoding/spec.js +4 -7
- package/lib/encoding/spec.js.map +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.js +33 -75
- package/lib/index.js.map +1 -1
- package/lib/src/Metadata.d.ts +49 -0
- package/lib/src/Metadata.js +256 -0
- package/lib/src/Metadata.js.map +1 -0
- package/lib/src/Reflection.d.ts +71 -0
- package/lib/src/Reflection.js +179 -0
- package/lib/src/Reflection.js.map +1 -0
- package/lib/src/Schema.d.ts +86 -0
- package/lib/src/Schema.js +352 -0
- package/lib/src/Schema.js.map +1 -0
- package/lib/src/annotations.d.ts +109 -0
- package/lib/src/annotations.js +473 -0
- package/lib/src/annotations.js.map +1 -0
- package/lib/src/bench_encode.d.ts +1 -0
- package/lib/src/bench_encode.js +91 -0
- package/lib/src/bench_encode.js.map +1 -0
- package/lib/src/codegen/api.d.ts +7 -0
- package/lib/src/codegen/api.js +56 -0
- package/lib/src/codegen/api.js.map +1 -0
- package/lib/src/codegen/argv.d.ts +6 -0
- package/lib/src/codegen/argv.js +39 -0
- package/lib/src/codegen/argv.js.map +1 -0
- package/lib/src/codegen/cli.d.ts +1 -0
- package/lib/src/codegen/cli.js +58 -0
- package/lib/src/codegen/cli.js.map +1 -0
- package/lib/src/codegen/languages/cpp.d.ts +3 -0
- package/lib/src/codegen/languages/cpp.js +258 -0
- package/lib/src/codegen/languages/cpp.js.map +1 -0
- package/lib/src/codegen/languages/csharp.d.ts +4 -0
- package/lib/src/codegen/languages/csharp.js +154 -0
- package/lib/src/codegen/languages/csharp.js.map +1 -0
- package/lib/src/codegen/languages/haxe.d.ts +3 -0
- package/lib/src/codegen/languages/haxe.js +100 -0
- package/lib/src/codegen/languages/haxe.js.map +1 -0
- package/lib/src/codegen/languages/java.d.ts +6 -0
- package/lib/src/codegen/languages/java.js +100 -0
- package/lib/src/codegen/languages/java.js.map +1 -0
- package/lib/src/codegen/languages/js.d.ts +3 -0
- package/lib/src/codegen/languages/js.js +101 -0
- package/lib/src/codegen/languages/js.js.map +1 -0
- package/lib/src/codegen/languages/lua.d.ts +3 -0
- package/lib/src/codegen/languages/lua.js +103 -0
- package/lib/src/codegen/languages/lua.js.map +1 -0
- package/lib/src/codegen/languages/ts.d.ts +3 -0
- package/lib/src/codegen/languages/ts.js +116 -0
- package/lib/src/codegen/languages/ts.js.map +1 -0
- package/lib/src/codegen/parser.d.ts +13 -0
- package/lib/src/codegen/parser.js +327 -0
- package/lib/src/codegen/parser.js.map +1 -0
- package/lib/src/codegen/types.d.ts +52 -0
- package/lib/src/codegen/types.js +142 -0
- package/lib/src/codegen/types.js.map +1 -0
- package/lib/src/decoder/DecodeOperation.d.ts +23 -0
- package/lib/src/decoder/DecodeOperation.js +248 -0
- package/lib/src/decoder/DecodeOperation.js.map +1 -0
- package/lib/src/decoder/Decoder.d.ts +21 -0
- package/lib/src/decoder/Decoder.js +114 -0
- package/lib/src/decoder/Decoder.js.map +1 -0
- package/lib/src/decoder/ReferenceTracker.d.ts +25 -0
- package/lib/src/decoder/ReferenceTracker.js +135 -0
- package/lib/src/decoder/ReferenceTracker.js.map +1 -0
- package/lib/src/decoder/strategy/Callbacks.d.ts +154 -0
- package/lib/src/decoder/strategy/Callbacks.js +336 -0
- package/lib/src/decoder/strategy/Callbacks.js.map +1 -0
- package/lib/src/decoder/strategy/RawChanges.d.ts +3 -0
- package/lib/src/decoder/strategy/RawChanges.js +4 -0
- package/lib/src/decoder/strategy/RawChanges.js.map +1 -0
- package/lib/src/decoder/strategy/getDecoderStateCallbacks.d.ts +76 -0
- package/lib/src/decoder/strategy/getDecoderStateCallbacks.js +274 -0
- package/lib/src/decoder/strategy/getDecoderStateCallbacks.js.map +1 -0
- package/lib/src/encoder/ChangeTree.d.ts +135 -0
- package/lib/src/encoder/ChangeTree.js +534 -0
- package/lib/src/encoder/ChangeTree.js.map +1 -0
- package/lib/src/encoder/EncodeOperation.d.ts +22 -0
- package/lib/src/encoder/EncodeOperation.js +132 -0
- package/lib/src/encoder/EncodeOperation.js.map +1 -0
- package/lib/src/encoder/Encoder.d.ts +22 -0
- package/lib/src/encoder/Encoder.js +204 -0
- package/lib/src/encoder/Encoder.js.map +1 -0
- package/lib/src/encoder/Root.d.ts +28 -0
- package/lib/src/encoder/Root.js +229 -0
- package/lib/src/encoder/Root.js.map +1 -0
- package/lib/src/encoder/StateView.d.ts +34 -0
- package/lib/src/encoder/StateView.js +279 -0
- package/lib/src/encoder/StateView.js.map +1 -0
- package/lib/src/encoding/assert.d.ts +10 -0
- package/lib/src/encoding/assert.js +49 -0
- package/lib/src/encoding/assert.js.map +1 -0
- package/lib/src/encoding/decode.d.ts +67 -0
- package/lib/src/encoding/decode.js +217 -0
- package/lib/src/encoding/decode.js.map +1 -0
- package/lib/src/encoding/encode.d.ts +40 -0
- package/lib/src/encoding/encode.js +279 -0
- package/lib/src/encoding/encode.js.map +1 -0
- package/lib/src/encoding/spec.d.ts +24 -0
- package/lib/src/encoding/spec.js +26 -0
- package/lib/src/encoding/spec.js.map +1 -0
- package/lib/src/index.d.ts +32 -0
- package/lib/src/index.js +39 -0
- package/lib/src/index.js.map +1 -0
- package/lib/src/symbol.shim.d.ts +6 -0
- package/lib/src/symbol.shim.js +3 -0
- package/lib/src/symbol.shim.js.map +1 -0
- package/lib/src/types/HelperTypes.d.ts +77 -0
- package/lib/src/types/HelperTypes.js +2 -0
- package/lib/src/types/HelperTypes.js.map +1 -0
- package/lib/src/types/TypeContext.d.ts +31 -0
- package/lib/src/types/TypeContext.js +143 -0
- package/lib/src/types/TypeContext.js.map +1 -0
- package/lib/src/types/custom/ArraySchema.d.ts +270 -0
- package/lib/src/types/custom/ArraySchema.js +733 -0
- package/lib/src/types/custom/ArraySchema.js.map +1 -0
- package/lib/src/types/custom/CollectionSchema.d.ts +51 -0
- package/lib/src/types/custom/CollectionSchema.js +170 -0
- package/lib/src/types/custom/CollectionSchema.js.map +1 -0
- package/lib/src/types/custom/MapSchema.d.ts +51 -0
- package/lib/src/types/custom/MapSchema.js +222 -0
- package/lib/src/types/custom/MapSchema.js.map +1 -0
- package/lib/src/types/custom/SetSchema.d.ts +48 -0
- package/lib/src/types/custom/SetSchema.js +178 -0
- package/lib/src/types/custom/SetSchema.js.map +1 -0
- package/lib/src/types/registry.d.ts +16 -0
- package/lib/src/types/registry.js +30 -0
- package/lib/src/types/registry.js.map +1 -0
- package/lib/src/types/symbols.d.ts +33 -0
- package/lib/src/types/symbols.js +34 -0
- package/lib/src/types/symbols.js.map +1 -0
- package/lib/src/types/utils.d.ts +1 -0
- package/lib/src/types/utils.js +13 -0
- package/lib/src/types/utils.js.map +1 -0
- package/lib/src/utils.d.ts +13 -0
- package/lib/src/utils.js +49 -0
- package/lib/src/utils.js.map +1 -0
- package/lib/src/v3_bench.d.ts +1 -0
- package/lib/src/v3_bench.js +128 -0
- package/lib/src/v3_bench.js.map +1 -0
- package/lib/symbol.shim.js +1 -2
- package/lib/symbol.shim.js.map +1 -1
- package/lib/types/HelperTypes.js +1 -2
- package/lib/types/TypeContext.js +8 -12
- package/lib/types/TypeContext.js.map +1 -1
- package/lib/types/custom/ArraySchema.js +63 -67
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/lib/types/custom/CollectionSchema.js +27 -31
- package/lib/types/custom/CollectionSchema.js.map +1 -1
- package/lib/types/custom/MapSchema.js +37 -41
- package/lib/types/custom/MapSchema.js.map +1 -1
- package/lib/types/custom/SetSchema.js +28 -32
- package/lib/types/custom/SetSchema.js.map +1 -1
- package/lib/types/registry.js +13 -20
- package/lib/types/registry.js.map +1 -1
- package/lib/types/symbols.js +16 -19
- package/lib/types/symbols.js.map +1 -1
- package/lib/types/utils.js +1 -4
- package/lib/types/utils.js.map +1 -1
- package/lib/utils.js +9 -14
- package/lib/utils.js.map +1 -1
- package/lib/v3_bench.js +17 -19
- package/lib/v3_bench.js.map +1 -1
- package/package.json +9 -7
- package/src/codegen/api.ts +7 -0
- package/src/codegen/parser.ts +2 -2
- package/src/codegen/types.ts +5 -0
- package/src/index.ts +2 -2
- package/build/cjs/index.js.map +0 -1
- package/src/bench_encode.ts +0 -64
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { schema } from "./annotations";
|
|
2
|
+
import { TypeContext } from "./types/TypeContext";
|
|
3
|
+
import { Metadata } from "./Metadata";
|
|
4
|
+
import { Encoder } from "./encoder/Encoder";
|
|
5
|
+
import { Decoder } from "./decoder/Decoder";
|
|
6
|
+
import { Schema } from "./Schema";
|
|
7
|
+
/**
|
|
8
|
+
* Reflection
|
|
9
|
+
*/
|
|
10
|
+
export const ReflectionField = schema({
|
|
11
|
+
name: "string",
|
|
12
|
+
type: "string",
|
|
13
|
+
referencedType: "number",
|
|
14
|
+
});
|
|
15
|
+
export const ReflectionType = schema({
|
|
16
|
+
id: "number",
|
|
17
|
+
extendsId: "number",
|
|
18
|
+
fields: [ReflectionField],
|
|
19
|
+
});
|
|
20
|
+
export const Reflection = schema({
|
|
21
|
+
types: [ReflectionType],
|
|
22
|
+
rootType: "number",
|
|
23
|
+
});
|
|
24
|
+
Reflection.encode = function (encoder, it = { offset: 0 }) {
|
|
25
|
+
const context = encoder.context;
|
|
26
|
+
const reflection = new Reflection();
|
|
27
|
+
const reflectionEncoder = new Encoder(reflection);
|
|
28
|
+
// rootType is usually the first schema passed to the Encoder
|
|
29
|
+
// (unless it inherits from another schema)
|
|
30
|
+
const rootType = context.schemas.get(encoder.state.constructor);
|
|
31
|
+
if (rootType > 0) {
|
|
32
|
+
reflection.rootType = rootType;
|
|
33
|
+
}
|
|
34
|
+
const includedTypeIds = new Set();
|
|
35
|
+
const pendingReflectionTypes = {};
|
|
36
|
+
// add type to reflection in a way that respects inheritance
|
|
37
|
+
// (parent types should be added before their children)
|
|
38
|
+
const addType = (type) => {
|
|
39
|
+
if (type.extendsId === undefined || includedTypeIds.has(type.extendsId)) {
|
|
40
|
+
includedTypeIds.add(type.id);
|
|
41
|
+
reflection.types.push(type);
|
|
42
|
+
const deps = pendingReflectionTypes[type.id];
|
|
43
|
+
if (deps !== undefined) {
|
|
44
|
+
delete pendingReflectionTypes[type.id];
|
|
45
|
+
deps.forEach((childType) => addType(childType));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
if (pendingReflectionTypes[type.extendsId] === undefined) {
|
|
50
|
+
pendingReflectionTypes[type.extendsId] = [];
|
|
51
|
+
}
|
|
52
|
+
pendingReflectionTypes[type.extendsId].push(type);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
context.schemas.forEach((typeid, klass) => {
|
|
56
|
+
const type = new ReflectionType();
|
|
57
|
+
type.id = Number(typeid);
|
|
58
|
+
// support inheritance
|
|
59
|
+
const inheritFrom = Object.getPrototypeOf(klass);
|
|
60
|
+
if (inheritFrom !== Schema) {
|
|
61
|
+
type.extendsId = context.schemas.get(inheritFrom);
|
|
62
|
+
}
|
|
63
|
+
const metadata = klass[Symbol.metadata];
|
|
64
|
+
//
|
|
65
|
+
// FIXME: this is a workaround for inherited types without additional fields
|
|
66
|
+
// if metadata is the same reference as the parent class - it means the class has no own metadata
|
|
67
|
+
//
|
|
68
|
+
if (metadata !== inheritFrom[Symbol.metadata]) {
|
|
69
|
+
for (const fieldIndex in metadata) {
|
|
70
|
+
const index = Number(fieldIndex);
|
|
71
|
+
const fieldName = metadata[index].name;
|
|
72
|
+
// skip fields from parent classes
|
|
73
|
+
if (!Object.prototype.hasOwnProperty.call(metadata, fieldName)) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const reflectionField = new ReflectionField();
|
|
77
|
+
reflectionField.name = fieldName;
|
|
78
|
+
let fieldType;
|
|
79
|
+
const field = metadata[index];
|
|
80
|
+
if (typeof (field.type) === "string") {
|
|
81
|
+
fieldType = field.type;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
let childTypeSchema;
|
|
85
|
+
//
|
|
86
|
+
// TODO: refactor below.
|
|
87
|
+
//
|
|
88
|
+
if (Schema.is(field.type)) {
|
|
89
|
+
fieldType = "ref";
|
|
90
|
+
childTypeSchema = field.type;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
fieldType = Object.keys(field.type)[0];
|
|
94
|
+
if (typeof (field.type[fieldType]) === "string") {
|
|
95
|
+
fieldType += ":" + field.type[fieldType]; // array:string
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
childTypeSchema = field.type[fieldType];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
reflectionField.referencedType = (childTypeSchema)
|
|
102
|
+
? context.getTypeId(childTypeSchema)
|
|
103
|
+
: -1;
|
|
104
|
+
}
|
|
105
|
+
reflectionField.type = fieldType;
|
|
106
|
+
type.fields.push(reflectionField);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
addType(type);
|
|
110
|
+
});
|
|
111
|
+
// in case there are types that were not added due to inheritance
|
|
112
|
+
for (const typeid in pendingReflectionTypes) {
|
|
113
|
+
pendingReflectionTypes[typeid].forEach((type) => reflection.types.push(type));
|
|
114
|
+
}
|
|
115
|
+
const buf = reflectionEncoder.encodeAll(it);
|
|
116
|
+
return buf.slice(0, it.offset);
|
|
117
|
+
};
|
|
118
|
+
Reflection.decode = function (bytes, it) {
|
|
119
|
+
const reflection = new Reflection();
|
|
120
|
+
const reflectionDecoder = new Decoder(reflection);
|
|
121
|
+
reflectionDecoder.decode(bytes, it);
|
|
122
|
+
const typeContext = new TypeContext();
|
|
123
|
+
// 1st pass, initialize metadata + inheritance
|
|
124
|
+
reflection.types.forEach((reflectionType) => {
|
|
125
|
+
const parentClass = typeContext.get(reflectionType.extendsId) ?? Schema;
|
|
126
|
+
const schema = class _ extends parentClass {
|
|
127
|
+
};
|
|
128
|
+
// register for inheritance support
|
|
129
|
+
TypeContext.register(schema);
|
|
130
|
+
typeContext.add(schema, reflectionType.id);
|
|
131
|
+
}, {});
|
|
132
|
+
// define fields
|
|
133
|
+
const addFields = (metadata, reflectionType, parentFieldIndex) => {
|
|
134
|
+
reflectionType.fields.forEach((field, i) => {
|
|
135
|
+
const fieldIndex = parentFieldIndex + i;
|
|
136
|
+
if (field.referencedType !== undefined) {
|
|
137
|
+
let fieldType = field.type;
|
|
138
|
+
let refType = typeContext.get(field.referencedType);
|
|
139
|
+
// map or array of primitive type (-1)
|
|
140
|
+
if (!refType) {
|
|
141
|
+
const typeInfo = field.type.split(":");
|
|
142
|
+
fieldType = typeInfo[0];
|
|
143
|
+
refType = typeInfo[1]; // string
|
|
144
|
+
}
|
|
145
|
+
if (fieldType === "ref") {
|
|
146
|
+
Metadata.addField(metadata, fieldIndex, field.name, refType);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
Metadata.addField(metadata, fieldIndex, field.name, { [fieldType]: refType });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
Metadata.addField(metadata, fieldIndex, field.name, field.type);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
// 2nd pass, set fields
|
|
158
|
+
reflection.types.forEach((reflectionType) => {
|
|
159
|
+
const schema = typeContext.get(reflectionType.id);
|
|
160
|
+
// for inheritance support
|
|
161
|
+
const metadata = Metadata.initialize(schema);
|
|
162
|
+
const inheritedTypes = [];
|
|
163
|
+
let parentType = reflectionType;
|
|
164
|
+
do {
|
|
165
|
+
inheritedTypes.push(parentType);
|
|
166
|
+
parentType = reflection.types.find((t) => t.id === parentType.extendsId);
|
|
167
|
+
} while (parentType);
|
|
168
|
+
let parentFieldIndex = 0;
|
|
169
|
+
inheritedTypes.reverse().forEach((reflectionType) => {
|
|
170
|
+
// add fields from all inherited classes
|
|
171
|
+
// TODO: refactor this to avoid adding fields from parent classes
|
|
172
|
+
addFields(metadata, reflectionType, parentFieldIndex);
|
|
173
|
+
parentFieldIndex += reflectionType.fields.length;
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
const state = new (typeContext.get(reflection.rootType || 0))();
|
|
177
|
+
return new Decoder(state, typeContext);
|
|
178
|
+
};
|
|
179
|
+
//# sourceMappingURL=Reflection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Reflection.js","sourceRoot":"","sources":["../../src/Reflection.ts"],"names":[],"mappings":"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","sourcesContent":["import { PrimitiveType, schema, SchemaType } from \"./annotations\";\nimport { TypeContext } from \"./types/TypeContext\";\nimport { Metadata } from \"./Metadata\";\nimport { Iterator } from \"./encoding/decode\";\nimport { Encoder } from \"./encoder/Encoder\";\nimport { Decoder } from \"./decoder/Decoder\";\nimport { Schema } from \"./Schema\";\n\n/**\n * Static methods available on Reflection\n */\ninterface ReflectionStatic {\n /**\n * Encodes the TypeContext of an Encoder into a buffer.\n *\n * @param encoder Encoder instance\n * @param it\n * @returns\n */\n encode: (encoder: Encoder, it?: Iterator) => Uint8Array;\n\n /**\n * Decodes the TypeContext from a buffer into a Decoder instance.\n *\n * @param bytes Reflection.encode() output\n * @param it\n * @returns Decoder instance\n */\n decode: <T extends Schema = Schema>(bytes: Uint8Array, it?: Iterator) => Decoder<T>;\n}\n\n/**\n * Reflection\n */\nexport const ReflectionField = schema({\n name: \"string\",\n type: \"string\",\n referencedType: \"number\",\n})\nexport type ReflectionField = SchemaType<typeof ReflectionField>;\n\nexport const ReflectionType = schema({\n id: \"number\",\n extendsId: \"number\",\n fields: [ ReflectionField ],\n})\nexport type ReflectionType = SchemaType<typeof ReflectionType>;\n\nexport const Reflection = schema({\n types: [ ReflectionType ],\n rootType: \"number\",\n}) as ReturnType<typeof schema<{\n types: [typeof ReflectionType];\n rootType: \"number\";\n}>> & ReflectionStatic;\n\nexport type Reflection = SchemaType<typeof Reflection>;\n\nReflection.encode = function (encoder: Encoder, it: Iterator = { offset: 0 }) {\n const context = encoder.context;\n\n const reflection = new Reflection();\n const reflectionEncoder = new Encoder(reflection);\n\n // rootType is usually the first schema passed to the Encoder\n // (unless it inherits from another schema)\n const rootType = context.schemas.get(encoder.state.constructor);\n if (rootType > 0) { reflection.rootType = rootType; }\n\n const includedTypeIds = new Set<number>();\n const pendingReflectionTypes: { [typeid: number]: ReflectionType[] } = {};\n\n // add type to reflection in a way that respects inheritance\n // (parent types should be added before their children)\n const addType = (type: ReflectionType) => {\n if (type.extendsId === undefined || includedTypeIds.has(type.extendsId)) {\n includedTypeIds.add(type.id);\n\n reflection.types.push(type);\n\n const deps = pendingReflectionTypes[type.id];\n if (deps !== undefined) {\n delete pendingReflectionTypes[type.id];\n deps.forEach((childType) => addType(childType));\n }\n } else {\n if (pendingReflectionTypes[type.extendsId] === undefined) {\n pendingReflectionTypes[type.extendsId] = [];\n }\n pendingReflectionTypes[type.extendsId].push(type);\n }\n };\n\n context.schemas.forEach((typeid, klass) => {\n const type = new ReflectionType();\n type.id = Number(typeid);\n\n // support inheritance\n const inheritFrom = Object.getPrototypeOf(klass);\n if (inheritFrom !== Schema) {\n type.extendsId = context.schemas.get(inheritFrom);\n }\n\n const metadata = klass[Symbol.metadata];\n\n //\n // FIXME: this is a workaround for inherited types without additional fields\n // if metadata is the same reference as the parent class - it means the class has no own metadata\n //\n if (metadata !== inheritFrom[Symbol.metadata]) {\n for (const fieldIndex in metadata) {\n const index = Number(fieldIndex);\n const fieldName = metadata[index].name;\n\n // skip fields from parent classes\n if (!Object.prototype.hasOwnProperty.call(metadata, fieldName)) {\n continue;\n }\n\n const reflectionField = new ReflectionField();\n reflectionField.name = fieldName;\n\n let fieldType: string;\n\n const field = metadata[index];\n\n if (typeof (field.type) === \"string\") {\n fieldType = field.type;\n\n } else {\n let childTypeSchema: typeof Schema;\n\n //\n // TODO: refactor below.\n //\n if (Schema.is(field.type)) {\n fieldType = \"ref\";\n childTypeSchema = field.type as typeof Schema;\n\n } else {\n fieldType = Object.keys(field.type)[0];\n\n if (typeof (field.type[fieldType as keyof typeof field.type]) === \"string\") {\n fieldType += \":\" + field.type[fieldType as keyof typeof field.type]; // array:string\n\n } else {\n childTypeSchema = field.type[fieldType as keyof typeof field.type];\n }\n }\n\n reflectionField.referencedType = (childTypeSchema)\n ? context.getTypeId(childTypeSchema)\n : -1;\n }\n\n reflectionField.type = fieldType;\n type.fields.push(reflectionField);\n }\n }\n\n addType(type);\n });\n\n // in case there are types that were not added due to inheritance\n for (const typeid in pendingReflectionTypes) {\n pendingReflectionTypes[typeid].forEach((type) =>\n reflection.types.push(type))\n }\n\n const buf = reflectionEncoder.encodeAll(it);\n return buf.slice(0, it.offset);\n};\n\nReflection.decode = function <T extends Schema = Schema>(bytes: Uint8Array, it?: Iterator): Decoder<T> {\n const reflection = new Reflection();\n\n const reflectionDecoder = new Decoder(reflection);\n reflectionDecoder.decode(bytes, it);\n\n const typeContext = new TypeContext();\n\n // 1st pass, initialize metadata + inheritance\n reflection.types.forEach((reflectionType) => {\n const parentClass: typeof Schema = typeContext.get(reflectionType.extendsId) ?? Schema;\n const schema: typeof Schema = class _ extends parentClass { };\n\n // register for inheritance support\n TypeContext.register(schema);\n\n typeContext.add(schema, reflectionType.id);\n }, {});\n\n // define fields\n const addFields = (metadata: Metadata, reflectionType: ReflectionType, parentFieldIndex: number) => {\n reflectionType.fields.forEach((field, i) => {\n const fieldIndex = parentFieldIndex + i;\n\n if (field.referencedType !== undefined) {\n let fieldType = field.type;\n let refType: PrimitiveType = typeContext.get(field.referencedType);\n\n // map or array of primitive type (-1)\n if (!refType) {\n const typeInfo = field.type.split(\":\");\n fieldType = typeInfo[0];\n refType = typeInfo[1] as PrimitiveType; // string\n }\n\n if (fieldType === \"ref\") {\n Metadata.addField(metadata, fieldIndex, field.name, refType);\n\n } else {\n Metadata.addField(metadata, fieldIndex, field.name, { [fieldType]: refType });\n }\n\n } else {\n Metadata.addField(metadata, fieldIndex, field.name, field.type as PrimitiveType);\n }\n });\n };\n\n // 2nd pass, set fields\n reflection.types.forEach((reflectionType) => {\n const schema = typeContext.get(reflectionType.id);\n\n // for inheritance support\n const metadata = Metadata.initialize(schema);\n\n const inheritedTypes: ReflectionType[] = [];\n\n let parentType: ReflectionType = reflectionType;\n do {\n inheritedTypes.push(parentType);\n parentType = reflection.types.find((t) => t.id === parentType.extendsId);\n } while (parentType);\n\n let parentFieldIndex = 0;\n\n inheritedTypes.reverse().forEach((reflectionType) => {\n // add fields from all inherited classes\n // TODO: refactor this to avoid adding fields from parent classes\n addFields(metadata, reflectionType, parentFieldIndex);\n parentFieldIndex += reflectionType.fields.length;\n });\n });\n\n const state: T = new (typeContext.get(reflection.rootType || 0) as unknown as any)();\n\n return new Decoder<T>(state, typeContext);\n}"]}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { OPERATION } from './encoding/spec';
|
|
2
|
+
import { type DefinitionType } from "./annotations";
|
|
3
|
+
import { AssignableProps, NonFunctionPropNames, ToJSON } from './types/HelperTypes';
|
|
4
|
+
import { ChangeSetName, ChangeTree, IRef, Ref } from './encoder/ChangeTree';
|
|
5
|
+
import { $decoder, $deleteByIndex, $encoder, $filter, $getByIndex, $refId, $track } from './types/symbols';
|
|
6
|
+
import { StateView } from './encoder/StateView';
|
|
7
|
+
import type { Decoder } from './decoder/Decoder';
|
|
8
|
+
import type { Metadata } from './Metadata';
|
|
9
|
+
/**
|
|
10
|
+
* Schema encoder / decoder
|
|
11
|
+
*/
|
|
12
|
+
export declare class Schema<C = any> implements IRef {
|
|
13
|
+
static [Symbol.metadata]: Metadata;
|
|
14
|
+
static [$encoder]: import("./encoder/EncodeOperation").EncodeOperation<any>;
|
|
15
|
+
static [$decoder]: import("./decoder/DecodeOperation").DecodeOperation<any>;
|
|
16
|
+
[$refId]?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Assign the property descriptors required to track changes on this instance.
|
|
19
|
+
* @param instance
|
|
20
|
+
*/
|
|
21
|
+
static initialize(instance: any): void;
|
|
22
|
+
static is(type: DefinitionType): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Track property changes
|
|
25
|
+
*/
|
|
26
|
+
static [$track](changeTree: ChangeTree, index: number, operation?: OPERATION): void;
|
|
27
|
+
/**
|
|
28
|
+
* Determine if a property must be filtered.
|
|
29
|
+
* - If returns false, the property is NOT going to be encoded.
|
|
30
|
+
* - If returns true, the property is going to be encoded.
|
|
31
|
+
*
|
|
32
|
+
* Encoding with "filters" happens in two steps:
|
|
33
|
+
* - First, the encoder iterates over all "not owned" properties and encodes them.
|
|
34
|
+
* - Then, the encoder iterates over all "owned" properties per instance and encodes them.
|
|
35
|
+
*/
|
|
36
|
+
static [$filter](ref: Schema, index: number, view: StateView): boolean;
|
|
37
|
+
constructor(arg?: C);
|
|
38
|
+
/**
|
|
39
|
+
* Assign properties to the instance.
|
|
40
|
+
* @param props Properties to assign to the instance
|
|
41
|
+
* @returns
|
|
42
|
+
*/
|
|
43
|
+
assign<T extends Partial<this>>(props: AssignableProps<T>): this;
|
|
44
|
+
/**
|
|
45
|
+
* Restore the instance from JSON data.
|
|
46
|
+
* @param jsonData JSON data to restore the instance from
|
|
47
|
+
* @returns
|
|
48
|
+
*/
|
|
49
|
+
restore(jsonData: ToJSON<this>): this;
|
|
50
|
+
/**
|
|
51
|
+
* (Server-side): Flag a property to be encoded for the next patch.
|
|
52
|
+
* @param instance Schema instance
|
|
53
|
+
* @param property string representing the property name, or number representing the index of the property.
|
|
54
|
+
* @param operation OPERATION to perform (detected automatically)
|
|
55
|
+
*/
|
|
56
|
+
setDirty<K extends NonFunctionPropNames<this>>(property: K | number, operation?: OPERATION): void;
|
|
57
|
+
clone(): this;
|
|
58
|
+
toJSON(this: any): ToJSON<this>;
|
|
59
|
+
/**
|
|
60
|
+
* Used in tests only
|
|
61
|
+
* @internal
|
|
62
|
+
*/
|
|
63
|
+
discardAllChanges(): void;
|
|
64
|
+
[$getByIndex](index: number): any;
|
|
65
|
+
[$deleteByIndex](index: number): void;
|
|
66
|
+
/**
|
|
67
|
+
* Inspect the `refId` of all Schema instances in the tree. Optionally display the contents of the instance.
|
|
68
|
+
*
|
|
69
|
+
* @param ref Schema instance
|
|
70
|
+
* @param showContents display JSON contents of the instance
|
|
71
|
+
* @returns
|
|
72
|
+
*/
|
|
73
|
+
static debugRefIds<T extends Schema>(ref: T, showContents?: boolean, level?: number, decoder?: Decoder, keyPrefix?: string): string;
|
|
74
|
+
static debugRefIdEncodingOrder<T extends Ref>(ref: T, changeSet?: ChangeSetName): number[];
|
|
75
|
+
static debugRefIdsFromDecoder(decoder: Decoder): string;
|
|
76
|
+
/**
|
|
77
|
+
* Return a string representation of the changes on a Schema instance.
|
|
78
|
+
* The list of changes is cleared after each encode.
|
|
79
|
+
*
|
|
80
|
+
* @param instance Schema instance
|
|
81
|
+
* @param isEncodeAll Return "full encode" instead of current change set.
|
|
82
|
+
* @returns
|
|
83
|
+
*/
|
|
84
|
+
static debugChanges<T extends Ref>(instance: T, isEncodeAll?: boolean): string;
|
|
85
|
+
static debugChangesDeep<T extends Schema>(ref: T, changeSetName?: "changes" | "allChanges" | "allFilteredChanges" | "filteredChanges"): string;
|
|
86
|
+
}
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
var _a, _b;
|
|
2
|
+
import { OPERATION } from './encoding/spec';
|
|
3
|
+
import { DEFAULT_VIEW_TAG } from "./annotations";
|
|
4
|
+
import { ChangeTree } from './encoder/ChangeTree';
|
|
5
|
+
import { $changes, $decoder, $deleteByIndex, $descriptors, $encoder, $filter, $getByIndex, $refId, $track } from './types/symbols';
|
|
6
|
+
import { encodeSchemaOperation } from './encoder/EncodeOperation';
|
|
7
|
+
import { decodeSchemaOperation } from './decoder/DecodeOperation';
|
|
8
|
+
import { getIndent } from './utils';
|
|
9
|
+
/**
|
|
10
|
+
* Schema encoder / decoder
|
|
11
|
+
*/
|
|
12
|
+
export class Schema {
|
|
13
|
+
static { this[_a] = encodeSchemaOperation; }
|
|
14
|
+
static { this[_b] = decodeSchemaOperation; }
|
|
15
|
+
/**
|
|
16
|
+
* Assign the property descriptors required to track changes on this instance.
|
|
17
|
+
* @param instance
|
|
18
|
+
*/
|
|
19
|
+
static initialize(instance) {
|
|
20
|
+
Object.defineProperty(instance, $changes, {
|
|
21
|
+
value: new ChangeTree(instance),
|
|
22
|
+
enumerable: false,
|
|
23
|
+
writable: true
|
|
24
|
+
});
|
|
25
|
+
Object.defineProperties(instance, instance.constructor[Symbol.metadata]?.[$descriptors] || {});
|
|
26
|
+
}
|
|
27
|
+
static is(type) {
|
|
28
|
+
return typeof (type[Symbol.metadata]) === "object";
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Track property changes
|
|
32
|
+
*/
|
|
33
|
+
static [(Symbol.metadata, _a = $encoder, _b = $decoder, $track)](changeTree, index, operation = OPERATION.ADD) {
|
|
34
|
+
changeTree.change(index, operation);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Determine if a property must be filtered.
|
|
38
|
+
* - If returns false, the property is NOT going to be encoded.
|
|
39
|
+
* - If returns true, the property is going to be encoded.
|
|
40
|
+
*
|
|
41
|
+
* Encoding with "filters" happens in two steps:
|
|
42
|
+
* - First, the encoder iterates over all "not owned" properties and encodes them.
|
|
43
|
+
* - Then, the encoder iterates over all "owned" properties per instance and encodes them.
|
|
44
|
+
*/
|
|
45
|
+
static [$filter](ref, index, view) {
|
|
46
|
+
const metadata = ref.constructor[Symbol.metadata];
|
|
47
|
+
const tag = metadata[index]?.tag;
|
|
48
|
+
if (view === undefined) {
|
|
49
|
+
// shared pass/encode: encode if doesn't have a tag
|
|
50
|
+
return tag === undefined;
|
|
51
|
+
}
|
|
52
|
+
else if (tag === undefined) {
|
|
53
|
+
// view pass: no tag
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
else if (tag === DEFAULT_VIEW_TAG) {
|
|
57
|
+
// view pass: default tag
|
|
58
|
+
return view.isChangeTreeVisible(ref[$changes]);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
// view pass: custom tag
|
|
62
|
+
const tags = view.tags?.get(ref[$changes]);
|
|
63
|
+
return tags && tags.has(tag);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// allow inherited classes to have a constructor
|
|
67
|
+
constructor(arg) {
|
|
68
|
+
//
|
|
69
|
+
// inline
|
|
70
|
+
// Schema.initialize(this);
|
|
71
|
+
//
|
|
72
|
+
Schema.initialize(this);
|
|
73
|
+
//
|
|
74
|
+
// Assign initial values
|
|
75
|
+
//
|
|
76
|
+
if (arg) {
|
|
77
|
+
Object.assign(this, arg);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Assign properties to the instance.
|
|
82
|
+
* @param props Properties to assign to the instance
|
|
83
|
+
* @returns
|
|
84
|
+
*/
|
|
85
|
+
assign(props) {
|
|
86
|
+
Object.assign(this, props);
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Restore the instance from JSON data.
|
|
91
|
+
* @param jsonData JSON data to restore the instance from
|
|
92
|
+
* @returns
|
|
93
|
+
*/
|
|
94
|
+
restore(jsonData) {
|
|
95
|
+
const metadata = this.constructor[Symbol.metadata];
|
|
96
|
+
for (const fieldIndex in metadata) {
|
|
97
|
+
const field = metadata[fieldIndex];
|
|
98
|
+
const fieldName = field.name;
|
|
99
|
+
const fieldType = field.type;
|
|
100
|
+
const value = jsonData[fieldName];
|
|
101
|
+
if (value === undefined || value === null) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (typeof fieldType === "string") {
|
|
105
|
+
// Primitive type: assign directly
|
|
106
|
+
this[fieldName] = value;
|
|
107
|
+
}
|
|
108
|
+
else if (Schema.is(fieldType)) {
|
|
109
|
+
// Schema type: create instance and restore
|
|
110
|
+
const instance = new fieldType();
|
|
111
|
+
instance.restore(value);
|
|
112
|
+
this[fieldName] = instance;
|
|
113
|
+
}
|
|
114
|
+
else if (typeof fieldType === "object") {
|
|
115
|
+
// Collection types: { map: ... }, { array: ... }, etc.
|
|
116
|
+
const collectionType = Object.keys(fieldType)[0];
|
|
117
|
+
const childType = fieldType[collectionType];
|
|
118
|
+
if (collectionType === "map") {
|
|
119
|
+
const mapSchema = this[fieldName];
|
|
120
|
+
for (const key in value) {
|
|
121
|
+
if (Schema.is(childType)) {
|
|
122
|
+
const childInstance = new childType();
|
|
123
|
+
childInstance.restore(value[key]);
|
|
124
|
+
mapSchema.set(key, childInstance);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
mapSchema.set(key, value[key]);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else if (collectionType === "array") {
|
|
132
|
+
const arraySchema = this[fieldName];
|
|
133
|
+
for (let i = 0; i < value.length; i++) {
|
|
134
|
+
if (Schema.is(childType)) {
|
|
135
|
+
const childInstance = new childType();
|
|
136
|
+
childInstance.restore(value[i]);
|
|
137
|
+
arraySchema.push(childInstance);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
arraySchema.push(value[i]);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return this;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* (Server-side): Flag a property to be encoded for the next patch.
|
|
150
|
+
* @param instance Schema instance
|
|
151
|
+
* @param property string representing the property name, or number representing the index of the property.
|
|
152
|
+
* @param operation OPERATION to perform (detected automatically)
|
|
153
|
+
*/
|
|
154
|
+
setDirty(property, operation) {
|
|
155
|
+
const metadata = this.constructor[Symbol.metadata];
|
|
156
|
+
this[$changes].change(metadata[metadata[property]].index, operation);
|
|
157
|
+
}
|
|
158
|
+
clone() {
|
|
159
|
+
// Create instance without calling custom constructor
|
|
160
|
+
const cloned = Object.create(this.constructor.prototype);
|
|
161
|
+
Schema.initialize(cloned);
|
|
162
|
+
const metadata = this.constructor[Symbol.metadata];
|
|
163
|
+
//
|
|
164
|
+
// TODO: clone all properties, not only annotated ones
|
|
165
|
+
//
|
|
166
|
+
// for (const field in this) {
|
|
167
|
+
for (const fieldIndex in metadata) {
|
|
168
|
+
const field = metadata[fieldIndex].name;
|
|
169
|
+
if (typeof (this[field]) === "object" &&
|
|
170
|
+
typeof (this[field]?.clone) === "function") {
|
|
171
|
+
// deep clone
|
|
172
|
+
cloned[field] = this[field].clone();
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
// primitive values
|
|
176
|
+
cloned[field] = this[field];
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return cloned;
|
|
180
|
+
}
|
|
181
|
+
toJSON() {
|
|
182
|
+
const obj = {};
|
|
183
|
+
const metadata = this.constructor[Symbol.metadata];
|
|
184
|
+
for (const index in metadata) {
|
|
185
|
+
const field = metadata[index];
|
|
186
|
+
const fieldName = field.name;
|
|
187
|
+
if (!field.deprecated && this[fieldName] !== null && typeof (this[fieldName]) !== "undefined") {
|
|
188
|
+
obj[fieldName] = (typeof (this[fieldName]['toJSON']) === "function")
|
|
189
|
+
? this[fieldName]['toJSON']()
|
|
190
|
+
: this[fieldName];
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return obj;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Used in tests only
|
|
197
|
+
* @internal
|
|
198
|
+
*/
|
|
199
|
+
discardAllChanges() {
|
|
200
|
+
this[$changes].discardAll();
|
|
201
|
+
}
|
|
202
|
+
[$getByIndex](index) {
|
|
203
|
+
const metadata = this.constructor[Symbol.metadata];
|
|
204
|
+
return this[metadata[index].name];
|
|
205
|
+
}
|
|
206
|
+
[$deleteByIndex](index) {
|
|
207
|
+
const metadata = this.constructor[Symbol.metadata];
|
|
208
|
+
this[metadata[index].name] = undefined;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Inspect the `refId` of all Schema instances in the tree. Optionally display the contents of the instance.
|
|
212
|
+
*
|
|
213
|
+
* @param ref Schema instance
|
|
214
|
+
* @param showContents display JSON contents of the instance
|
|
215
|
+
* @returns
|
|
216
|
+
*/
|
|
217
|
+
static debugRefIds(ref, showContents = false, level = 0, decoder, keyPrefix = "") {
|
|
218
|
+
const contents = (showContents) ? ` - ${JSON.stringify(ref.toJSON())}` : "";
|
|
219
|
+
const changeTree = ref[$changes];
|
|
220
|
+
const refId = ref[$refId];
|
|
221
|
+
const root = (decoder) ? decoder.root : changeTree.root;
|
|
222
|
+
// log reference count if > 1
|
|
223
|
+
const refCount = (root?.refCount?.[refId] > 1)
|
|
224
|
+
? ` [×${root.refCount[refId]}]`
|
|
225
|
+
: '';
|
|
226
|
+
let output = `${getIndent(level)}${keyPrefix}${ref.constructor.name} (refId: ${refId})${refCount}${contents}\n`;
|
|
227
|
+
changeTree.forEachChild((childChangeTree, indexOrKey) => {
|
|
228
|
+
let key = indexOrKey;
|
|
229
|
+
if (typeof indexOrKey === 'number' && ref['$indexes']) {
|
|
230
|
+
// MapSchema
|
|
231
|
+
key = ref['$indexes'].get(indexOrKey) ?? indexOrKey;
|
|
232
|
+
}
|
|
233
|
+
const keyPrefix = (ref['forEach'] !== undefined && key !== undefined) ? `["${key}"]: ` : "";
|
|
234
|
+
output += this.debugRefIds(childChangeTree.ref, showContents, level + 1, decoder, keyPrefix);
|
|
235
|
+
});
|
|
236
|
+
return output;
|
|
237
|
+
}
|
|
238
|
+
static debugRefIdEncodingOrder(ref, changeSet = 'allChanges') {
|
|
239
|
+
let encodeOrder = [];
|
|
240
|
+
let current = ref[$changes].root[changeSet].next;
|
|
241
|
+
while (current) {
|
|
242
|
+
if (current.changeTree) {
|
|
243
|
+
encodeOrder.push(current.changeTree.ref[$refId]);
|
|
244
|
+
}
|
|
245
|
+
current = current.next;
|
|
246
|
+
}
|
|
247
|
+
return encodeOrder;
|
|
248
|
+
}
|
|
249
|
+
static debugRefIdsFromDecoder(decoder) {
|
|
250
|
+
return this.debugRefIds(decoder.state, false, 0, decoder);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Return a string representation of the changes on a Schema instance.
|
|
254
|
+
* The list of changes is cleared after each encode.
|
|
255
|
+
*
|
|
256
|
+
* @param instance Schema instance
|
|
257
|
+
* @param isEncodeAll Return "full encode" instead of current change set.
|
|
258
|
+
* @returns
|
|
259
|
+
*/
|
|
260
|
+
static debugChanges(instance, isEncodeAll = false) {
|
|
261
|
+
const changeTree = instance[$changes];
|
|
262
|
+
const changeSet = (isEncodeAll) ? changeTree.allChanges : changeTree.changes;
|
|
263
|
+
const changeSetName = (isEncodeAll) ? "allChanges" : "changes";
|
|
264
|
+
let output = `${instance.constructor.name} (${instance[$refId]}) -> .${changeSetName}:\n`;
|
|
265
|
+
function dumpChangeSet(changeSet) {
|
|
266
|
+
changeSet.operations
|
|
267
|
+
.filter(op => op)
|
|
268
|
+
.forEach((index) => {
|
|
269
|
+
const operation = changeTree.indexedOperations[index];
|
|
270
|
+
output += `- [${index}]: ${OPERATION[operation]} (${JSON.stringify(changeTree.getValue(Number(index), isEncodeAll))})\n`;
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
dumpChangeSet(changeSet);
|
|
274
|
+
// display filtered changes
|
|
275
|
+
if (!isEncodeAll &&
|
|
276
|
+
changeTree.filteredChanges &&
|
|
277
|
+
(changeTree.filteredChanges.operations).filter(op => op).length > 0) {
|
|
278
|
+
output += `${instance.constructor.name} (${instance[$refId]}) -> .filteredChanges:\n`;
|
|
279
|
+
dumpChangeSet(changeTree.filteredChanges);
|
|
280
|
+
}
|
|
281
|
+
// display filtered changes
|
|
282
|
+
if (isEncodeAll &&
|
|
283
|
+
changeTree.allFilteredChanges &&
|
|
284
|
+
(changeTree.allFilteredChanges.operations).filter(op => op).length > 0) {
|
|
285
|
+
output += `${instance.constructor.name} (${instance[$refId]}) -> .allFilteredChanges:\n`;
|
|
286
|
+
dumpChangeSet(changeTree.allFilteredChanges);
|
|
287
|
+
}
|
|
288
|
+
return output;
|
|
289
|
+
}
|
|
290
|
+
static debugChangesDeep(ref, changeSetName = "changes") {
|
|
291
|
+
let output = "";
|
|
292
|
+
const rootChangeTree = ref[$changes];
|
|
293
|
+
const root = rootChangeTree.root;
|
|
294
|
+
const changeTrees = new Map();
|
|
295
|
+
const instanceRefIds = [];
|
|
296
|
+
let totalOperations = 0;
|
|
297
|
+
// TODO: FIXME: this method is not working as expected
|
|
298
|
+
for (const [refId, changes] of Object.entries(root[changeSetName])) {
|
|
299
|
+
const changeTree = root.changeTrees[refId];
|
|
300
|
+
if (!changeTree) {
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
let includeChangeTree = false;
|
|
304
|
+
let parentChangeTrees = [];
|
|
305
|
+
let parentChangeTree = changeTree.parent?.[$changes];
|
|
306
|
+
if (changeTree === rootChangeTree) {
|
|
307
|
+
includeChangeTree = true;
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
while (parentChangeTree !== undefined) {
|
|
311
|
+
parentChangeTrees.push(parentChangeTree);
|
|
312
|
+
if (parentChangeTree.ref === ref) {
|
|
313
|
+
includeChangeTree = true;
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
parentChangeTree = parentChangeTree.parent?.[$changes];
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (includeChangeTree) {
|
|
320
|
+
instanceRefIds.push(changeTree.ref[$refId]);
|
|
321
|
+
totalOperations += Object.keys(changes).length;
|
|
322
|
+
changeTrees.set(changeTree, parentChangeTrees.reverse());
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
output += "---\n";
|
|
326
|
+
output += `root refId: ${rootChangeTree.ref[$refId]}\n`;
|
|
327
|
+
output += `Total instances: ${instanceRefIds.length} (refIds: ${instanceRefIds.join(", ")})\n`;
|
|
328
|
+
output += `Total changes: ${totalOperations}\n`;
|
|
329
|
+
output += "---\n";
|
|
330
|
+
// based on root.changes, display a tree of changes that has the "ref" instance as parent
|
|
331
|
+
const visitedParents = new WeakSet();
|
|
332
|
+
for (const [changeTree, parentChangeTrees] of changeTrees.entries()) {
|
|
333
|
+
parentChangeTrees.forEach((parentChangeTree, level) => {
|
|
334
|
+
if (!visitedParents.has(parentChangeTree)) {
|
|
335
|
+
output += `${getIndent(level)}${parentChangeTree.ref.constructor.name} (refId: ${parentChangeTree.ref[$refId]})\n`;
|
|
336
|
+
visitedParents.add(parentChangeTree);
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
const changes = changeTree.indexedOperations;
|
|
340
|
+
const level = parentChangeTrees.length;
|
|
341
|
+
const indent = getIndent(level);
|
|
342
|
+
const parentIndex = (level > 0) ? `(${changeTree.parentIndex}) ` : "";
|
|
343
|
+
output += `${indent}${parentIndex}${changeTree.ref.constructor.name} (refId: ${changeTree.ref[$refId]}) - changes: ${Object.keys(changes).length}\n`;
|
|
344
|
+
for (const index in changes) {
|
|
345
|
+
const operation = changes[index];
|
|
346
|
+
output += `${getIndent(level + 1)}${OPERATION[operation]}: ${index}\n`;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return `${output}`;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
//# sourceMappingURL=Schema.js.map
|