@colyseus/schema 3.0.0-alpha.3 → 3.0.0-alpha.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +131 -61
- package/build/cjs/index.js +966 -563
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +965 -562
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +966 -563
- package/lib/Metadata.d.ts +15 -4
- package/lib/Metadata.js +86 -18
- package/lib/Metadata.js.map +1 -1
- package/lib/Reflection.d.ts +2 -3
- package/lib/Reflection.js +24 -28
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.d.ts +2 -2
- package/lib/Schema.js +28 -41
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.d.ts +1 -21
- package/lib/annotations.js +73 -153
- package/lib/annotations.js.map +1 -1
- package/lib/bench_encode.d.ts +1 -0
- package/lib/bench_encode.js +142 -0
- package/lib/bench_encode.js.map +1 -0
- package/lib/codegen/api.js +1 -2
- package/lib/codegen/api.js.map +1 -1
- package/lib/codegen/languages/cpp.js +1 -2
- package/lib/codegen/languages/cpp.js.map +1 -1
- package/lib/codegen/languages/csharp.js +1 -2
- package/lib/codegen/languages/csharp.js.map +1 -1
- package/lib/codegen/languages/haxe.js +1 -2
- package/lib/codegen/languages/haxe.js.map +1 -1
- package/lib/codegen/languages/java.js +1 -2
- package/lib/codegen/languages/java.js.map +1 -1
- package/lib/codegen/languages/js.js +1 -2
- package/lib/codegen/languages/js.js.map +1 -1
- package/lib/codegen/languages/lua.js +1 -2
- package/lib/codegen/languages/lua.js.map +1 -1
- package/lib/codegen/languages/ts.js +1 -2
- package/lib/codegen/languages/ts.js.map +1 -1
- package/lib/codegen/parser.js +2 -3
- package/lib/codegen/parser.js.map +1 -1
- package/lib/codegen/types.js +3 -3
- package/lib/codegen/types.js.map +1 -1
- package/lib/debug.d.ts +1 -0
- package/lib/debug.js +52 -0
- package/lib/debug.js.map +1 -0
- package/lib/decoder/DecodeOperation.d.ts +0 -1
- package/lib/decoder/DecodeOperation.js +23 -11
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/decoder/Decoder.d.ts +6 -7
- package/lib/decoder/Decoder.js +8 -8
- package/lib/decoder/Decoder.js.map +1 -1
- package/lib/decoder/ReferenceTracker.js +3 -2
- package/lib/decoder/ReferenceTracker.js.map +1 -1
- package/lib/decoder/strategy/RawChanges.js +1 -2
- package/lib/decoder/strategy/RawChanges.js.map +1 -1
- package/lib/decoder/strategy/StateCallbacks.d.ts +44 -11
- package/lib/decoder/strategy/StateCallbacks.js +75 -65
- package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
- package/lib/encoder/ChangeTree.d.ts +9 -19
- package/lib/encoder/ChangeTree.js +129 -145
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/EncodeOperation.d.ts +1 -5
- package/lib/encoder/EncodeOperation.js +74 -58
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.d.ts +10 -8
- package/lib/encoder/Encoder.js +89 -56
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.d.ts +17 -0
- package/lib/encoder/Root.js +44 -0
- package/lib/encoder/Root.js.map +1 -0
- package/lib/encoder/StateView.d.ts +2 -2
- package/lib/encoder/StateView.js +49 -59
- package/lib/encoder/StateView.js.map +1 -1
- package/lib/encoding/assert.d.ts +2 -1
- package/lib/encoding/assert.js +5 -5
- package/lib/encoding/assert.js.map +1 -1
- package/lib/encoding/decode.js +21 -22
- package/lib/encoding/decode.js.map +1 -1
- package/lib/encoding/encode.d.ts +2 -2
- package/lib/encoding/encode.js +40 -39
- package/lib/encoding/encode.js.map +1 -1
- package/lib/encoding/spec.d.ts +2 -1
- package/lib/encoding/spec.js +1 -0
- package/lib/encoding/spec.js.map +1 -1
- package/lib/index.d.ts +6 -3
- package/lib/index.js +18 -13
- package/lib/index.js.map +1 -1
- package/lib/types/TypeContext.d.ts +23 -0
- package/lib/types/TypeContext.js +102 -0
- package/lib/types/TypeContext.js.map +1 -0
- package/lib/types/custom/ArraySchema.d.ts +2 -2
- package/lib/types/custom/ArraySchema.js +6 -9
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/lib/types/custom/CollectionSchema.js +1 -0
- package/lib/types/custom/CollectionSchema.js.map +1 -1
- package/lib/types/custom/MapSchema.js +5 -0
- package/lib/types/custom/MapSchema.js.map +1 -1
- package/lib/types/custom/SetSchema.js +1 -0
- package/lib/types/custom/SetSchema.js.map +1 -1
- package/lib/types/registry.js +3 -4
- package/lib/types/registry.js.map +1 -1
- package/lib/types/symbols.d.ts +1 -0
- package/lib/types/symbols.js +2 -1
- package/lib/types/symbols.js.map +1 -1
- package/lib/types/utils.js +1 -2
- package/lib/types/utils.js.map +1 -1
- package/lib/utils.js +3 -4
- package/lib/utils.js.map +1 -1
- package/package.json +5 -5
- package/src/Metadata.ts +104 -26
- package/src/Reflection.ts +26 -28
- package/src/Schema.ts +35 -47
- package/src/annotations.ts +82 -176
- package/src/bench_encode.ts +121 -0
- package/src/debug.ts +56 -0
- package/src/decoder/DecodeOperation.ts +28 -11
- package/src/decoder/Decoder.ts +13 -11
- package/src/decoder/ReferenceTracker.ts +3 -2
- package/src/decoder/strategy/StateCallbacks.ts +152 -81
- package/src/encoder/ChangeTree.ts +147 -166
- package/src/encoder/EncodeOperation.ts +93 -70
- package/src/encoder/Encoder.ts +111 -65
- package/src/encoder/Root.ts +51 -0
- package/src/encoder/StateView.ts +53 -69
- package/src/encoding/assert.ts +4 -3
- package/src/encoding/decode.ts +1 -2
- package/src/encoding/encode.ts +25 -22
- package/src/encoding/spec.ts +1 -0
- package/src/index.ts +8 -14
- package/src/types/TypeContext.ts +122 -0
- package/src/types/custom/ArraySchema.ts +10 -2
- package/src/types/custom/CollectionSchema.ts +1 -0
- package/src/types/custom/MapSchema.ts +6 -0
- package/src/types/custom/SetSchema.ts +1 -0
- package/src/types/symbols.ts +2 -0
package/src/encoder/StateView.ts
CHANGED
|
@@ -28,25 +28,23 @@ export class StateView {
|
|
|
28
28
|
changes = new Map<ChangeTree, Map<number, OPERATION>>();
|
|
29
29
|
|
|
30
30
|
// TODO: allow to set multiple tags at once
|
|
31
|
-
add(obj: Ref, tag: number = DEFAULT_VIEW_TAG) {
|
|
31
|
+
add(obj: Ref, tag: number = DEFAULT_VIEW_TAG, checkIncludeParent: boolean = true) {
|
|
32
32
|
if (!obj[$changes]) {
|
|
33
33
|
console.warn("StateView#add(), invalid object:", obj);
|
|
34
34
|
return this;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
this.items.add(changeTree);
|
|
39
|
-
|
|
40
|
-
// Add children of this ChangeTree to this view
|
|
41
|
-
changeTree.forEachChild((change, _) =>
|
|
42
|
-
this.add(change.ref, tag));
|
|
43
|
-
|
|
44
|
-
// FIXME: ArraySchema/MapSchema does not have metadata
|
|
37
|
+
// FIXME: ArraySchema/MapSchema do not have metadata
|
|
45
38
|
const metadata: Metadata = obj.constructor[Symbol.metadata];
|
|
39
|
+
const changeTree: ChangeTree = obj[$changes];
|
|
40
|
+
this.items.add(changeTree);
|
|
46
41
|
|
|
47
|
-
// add parent ChangeTree's
|
|
48
|
-
//
|
|
49
|
-
|
|
42
|
+
// add parent ChangeTree's
|
|
43
|
+
// - if it was invisible to this view
|
|
44
|
+
// - if it were previously filtered out
|
|
45
|
+
if (checkIncludeParent && changeTree.parent) {
|
|
46
|
+
this.addParent(changeTree.parent[$changes], changeTree.parentIndex, tag);
|
|
47
|
+
}
|
|
50
48
|
|
|
51
49
|
//
|
|
52
50
|
// TODO: when adding an item of a MapSchema, the changes may not
|
|
@@ -72,8 +70,6 @@ export class StateView {
|
|
|
72
70
|
}
|
|
73
71
|
tags.add(tag);
|
|
74
72
|
|
|
75
|
-
// console.log("BY TAG:", tag);
|
|
76
|
-
|
|
77
73
|
// Ref: add tagged properties
|
|
78
74
|
metadata?.[-3]?.[tag]?.forEach((index) => {
|
|
79
75
|
if (changeTree.getChange(index) !== OPERATION.DELETE) {
|
|
@@ -82,89 +78,77 @@ export class StateView {
|
|
|
82
78
|
});
|
|
83
79
|
|
|
84
80
|
} else {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
// // add default tag properties
|
|
89
|
-
// metadata?.[-3]?.[DEFAULT_VIEW_TAG]?.forEach((index) => {
|
|
90
|
-
// if (changeTree.getChange(index) !== OPERATION.DELETE) {
|
|
91
|
-
// changes.set(index, OPERATION.ADD);
|
|
92
|
-
// }
|
|
93
|
-
// });
|
|
94
|
-
|
|
95
|
-
const allChangesSet = (changeTree.isFiltered || changeTree.isPartiallyFiltered)
|
|
81
|
+
const isInvisible = this.invisible.has(changeTree);
|
|
82
|
+
const changeSet = (changeTree.isFiltered || changeTree.isPartiallyFiltered)
|
|
96
83
|
? changeTree.allFilteredChanges
|
|
97
84
|
: changeTree.allChanges;
|
|
98
|
-
const it = allChangesSet.keys();
|
|
99
|
-
const isInvisible = this.invisible.has(changeTree);
|
|
100
85
|
|
|
101
|
-
|
|
86
|
+
changeSet.forEach((op, index) => {
|
|
87
|
+
const tagAtIndex = metadata?.[index].tag;
|
|
102
88
|
if (
|
|
103
|
-
(
|
|
104
|
-
|
|
89
|
+
(
|
|
90
|
+
isInvisible || // if "invisible", include all
|
|
91
|
+
tagAtIndex === undefined || // "all change" with no tag
|
|
92
|
+
tagAtIndex === tag // tagged property
|
|
93
|
+
) &&
|
|
94
|
+
op !== OPERATION.DELETE
|
|
105
95
|
) {
|
|
106
|
-
changes.set(index,
|
|
96
|
+
changes.set(index, op);
|
|
107
97
|
}
|
|
108
|
-
}
|
|
98
|
+
});
|
|
109
99
|
}
|
|
110
100
|
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
this.
|
|
118
|
-
}
|
|
101
|
+
// Add children of this ChangeTree to this view
|
|
102
|
+
changeTree.forEachChild((change, index) => {
|
|
103
|
+
// Do not ADD children that don't have the same tag
|
|
104
|
+
if (metadata && metadata[index].tag !== tag) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
this.add(change.ref, tag, false);
|
|
108
|
+
});
|
|
119
109
|
|
|
120
110
|
return this;
|
|
121
111
|
}
|
|
122
112
|
|
|
123
|
-
protected addParent(changeTree: ChangeTree, tag: number) {
|
|
124
|
-
|
|
125
|
-
|
|
113
|
+
protected addParent(changeTree: ChangeTree, parentIndex: number, tag: number) {
|
|
114
|
+
// view must have all "changeTree" parent tree
|
|
115
|
+
this.items.add(changeTree);
|
|
126
116
|
|
|
127
|
-
|
|
128
|
-
const
|
|
117
|
+
// add parent's parent
|
|
118
|
+
const parentChangeTree = changeTree.parent?.[$changes];
|
|
119
|
+
if (parentChangeTree && (parentChangeTree.isFiltered || parentChangeTree.isPartiallyFiltered)) {
|
|
120
|
+
this.addParent(parentChangeTree, changeTree.parentIndex, tag);
|
|
121
|
+
}
|
|
129
122
|
|
|
130
|
-
|
|
131
|
-
|
|
123
|
+
// parent is already available, no need to add it!
|
|
124
|
+
if (!this.invisible.has(changeTree)) {
|
|
132
125
|
return;
|
|
133
126
|
}
|
|
134
127
|
|
|
135
|
-
this.addParent(parentChangeTree, tag);
|
|
136
|
-
|
|
137
128
|
// add parent's tag properties
|
|
138
|
-
if (
|
|
129
|
+
if (changeTree.getChange(parentIndex) !== OPERATION.DELETE) {
|
|
139
130
|
|
|
140
|
-
let
|
|
141
|
-
if (
|
|
142
|
-
|
|
143
|
-
this.changes.set(
|
|
131
|
+
let changes = this.changes.get(changeTree);
|
|
132
|
+
if (changes === undefined) {
|
|
133
|
+
changes = new Map<number, OPERATION>();
|
|
134
|
+
this.changes.set(changeTree, changes);
|
|
144
135
|
}
|
|
145
136
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
// parentChange: (
|
|
150
|
-
// parentChangeTree.getChange(parentIndex) &&
|
|
151
|
-
// OPERATION[parentChangeTree.getChange(parentIndex)]
|
|
152
|
-
// ),
|
|
153
|
-
// })
|
|
137
|
+
if (!this.tags) {
|
|
138
|
+
this.tags = new WeakMap<ChangeTree, Set<number>>();
|
|
139
|
+
}
|
|
154
140
|
|
|
155
|
-
if (!this.tags) { this.tags = new WeakMap<ChangeTree, Set<number>>(); }
|
|
156
141
|
let tags: Set<number>;
|
|
157
|
-
if (!this.tags.has(
|
|
142
|
+
if (!this.tags.has(changeTree)) {
|
|
158
143
|
tags = new Set<number>();
|
|
159
|
-
this.tags.set(
|
|
144
|
+
this.tags.set(changeTree, tags);
|
|
160
145
|
} else {
|
|
161
|
-
tags = this.tags.get(
|
|
146
|
+
tags = this.tags.get(changeTree);
|
|
162
147
|
}
|
|
163
148
|
tags.add(tag);
|
|
164
149
|
|
|
165
|
-
|
|
150
|
+
changes.set(parentIndex, OPERATION.ADD);
|
|
166
151
|
}
|
|
167
|
-
|
|
168
152
|
}
|
|
169
153
|
|
|
170
154
|
remove(obj: Ref, tag: number = DEFAULT_VIEW_TAG) {
|
|
@@ -182,7 +166,7 @@ export class StateView {
|
|
|
182
166
|
let changes = this.changes.get(changeTree);
|
|
183
167
|
if (changes === undefined) {
|
|
184
168
|
changes = new Map<number, OPERATION>();
|
|
185
|
-
this.changes.set(changeTree, changes)
|
|
169
|
+
this.changes.set(changeTree, changes);
|
|
186
170
|
}
|
|
187
171
|
|
|
188
172
|
if (tag === DEFAULT_VIEW_TAG) {
|
package/src/encoding/assert.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { CollectionSchema } from "../types/custom/CollectionSchema";
|
|
|
3
3
|
import { MapSchema } from "../types/custom/MapSchema";
|
|
4
4
|
import { SetSchema } from "../types/custom/SetSchema";
|
|
5
5
|
import { ArraySchema } from "../types/custom/ArraySchema";
|
|
6
|
+
import type { Ref } from "../encoder/ChangeTree";
|
|
6
7
|
|
|
7
8
|
export class EncodeSchemaError extends Error {}
|
|
8
9
|
|
|
@@ -43,16 +44,16 @@ export function assertType(value: any, type: string, klass: Schema, field: strin
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
export function assertInstanceType(
|
|
46
|
-
value:
|
|
47
|
+
value: Ref,
|
|
47
48
|
type: typeof Schema
|
|
48
49
|
| typeof ArraySchema
|
|
49
50
|
| typeof MapSchema
|
|
50
51
|
| typeof CollectionSchema
|
|
51
52
|
| typeof SetSchema,
|
|
52
|
-
|
|
53
|
+
instance: Ref,
|
|
53
54
|
field: string | number,
|
|
54
55
|
) {
|
|
55
56
|
if (!(value instanceof type)) {
|
|
56
|
-
throw new EncodeSchemaError(`a '${type.name}' was expected, but '${value && (value as any).constructor.name}' was provided in ${
|
|
57
|
+
throw new EncodeSchemaError(`a '${type.name}' was expected, but '${value && (value as any).constructor.name}' was provided in ${instance.constructor.name}#${field}`);
|
|
57
58
|
}
|
|
58
59
|
}
|
package/src/encoding/decode.ts
CHANGED
|
@@ -32,8 +32,6 @@ import type { BufferLike } from "./encode";
|
|
|
32
32
|
export interface Iterator { offset: number; }
|
|
33
33
|
|
|
34
34
|
export function utf8Read(bytes: BufferLike, it: Iterator, length: number) {
|
|
35
|
-
it.offset += length;
|
|
36
|
-
|
|
37
35
|
var string = '', chr = 0;
|
|
38
36
|
for (var i = it.offset, end = it.offset + length; i < end; i++) {
|
|
39
37
|
var byte = bytes[i];
|
|
@@ -74,6 +72,7 @@ export function utf8Read(bytes: BufferLike, it: Iterator, length: number) {
|
|
|
74
72
|
// (do not throw error to avoid server/client from crashing due to hack attemps)
|
|
75
73
|
// throw new Error('Invalid byte ' + byte.toString(16));
|
|
76
74
|
}
|
|
75
|
+
it.offset += length;
|
|
77
76
|
return string;
|
|
78
77
|
}
|
|
79
78
|
|
package/src/encoding/encode.ts
CHANGED
|
@@ -35,28 +35,32 @@ let textEncoder: TextEncoder;
|
|
|
35
35
|
// @ts-ignore
|
|
36
36
|
try { textEncoder = new TextEncoder(); } catch (e) { }
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
38
|
+
const hasBufferByteLength = (typeof Buffer !== 'undefined' && Buffer.byteLength);
|
|
39
|
+
|
|
40
|
+
export const utf8Length = (hasBufferByteLength)
|
|
41
|
+
? Buffer.byteLength // node
|
|
42
|
+
: function (str: string, _?: any) {
|
|
43
|
+
var c = 0, length = 0;
|
|
44
|
+
for (var i = 0, l = str.length; i < l; i++) {
|
|
45
|
+
c = str.charCodeAt(i);
|
|
46
|
+
if (c < 0x80) {
|
|
47
|
+
length += 1;
|
|
48
|
+
}
|
|
49
|
+
else if (c < 0x800) {
|
|
50
|
+
length += 2;
|
|
51
|
+
}
|
|
52
|
+
else if (c < 0xd800 || c >= 0xe000) {
|
|
53
|
+
length += 3;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
i++;
|
|
57
|
+
length += 4;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return length;
|
|
54
61
|
}
|
|
55
|
-
}
|
|
56
|
-
return length;
|
|
57
|
-
}
|
|
58
62
|
|
|
59
|
-
export function utf8Write(view, str, it) {
|
|
63
|
+
export function utf8Write(view: BufferLike, str: string, it: Iterator) {
|
|
60
64
|
var c = 0;
|
|
61
65
|
for (var i = 0, l = str.length; i < l; i++) {
|
|
62
66
|
c = str.charCodeAt(i);
|
|
@@ -166,8 +170,7 @@ export function string(bytes: BufferLike, value: string, it: Iterator) {
|
|
|
166
170
|
// encode `null` strings as empty.
|
|
167
171
|
if (!value) { value = ""; }
|
|
168
172
|
|
|
169
|
-
|
|
170
|
-
let length = Buffer.byteLength(value, "utf8");
|
|
173
|
+
let length = utf8Length(value, "utf8");
|
|
171
174
|
let size = 0;
|
|
172
175
|
|
|
173
176
|
// fixstr
|
package/src/encoding/spec.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
export { Schema } from "./Schema";
|
|
2
2
|
export type { DataChange } from "./decoder/DecodeOperation";
|
|
3
|
-
|
|
4
|
-
import { $track, $encoder, $decoder, $filter, $getByIndex, $deleteByIndex, $changes, $childType } from "./types/symbols";
|
|
5
|
-
export { $track, $encoder, $decoder, $filter, $getByIndex, $deleteByIndex, $changes, $childType };
|
|
3
|
+
export type { ToJSON } from "./types/HelperTypes";
|
|
6
4
|
|
|
7
5
|
import { MapSchema } from "./types/custom/MapSchema"
|
|
8
6
|
export { MapSchema };
|
|
@@ -28,6 +26,7 @@ registerType("collection", { constructor: CollectionSchema, });
|
|
|
28
26
|
export { dumpChanges } from "./utils";
|
|
29
27
|
|
|
30
28
|
// Encoder / Decoder
|
|
29
|
+
export { $track, $encoder, $decoder, $filter, $getByIndex, $deleteByIndex, $changes, $childType } from "./types/symbols";
|
|
31
30
|
export type { Iterator } from "./encoding/decode";
|
|
32
31
|
import * as encode from "./encoding/encode";
|
|
33
32
|
import * as decode from "./encoding/decode";
|
|
@@ -40,22 +39,17 @@ export {
|
|
|
40
39
|
ReflectionField,
|
|
41
40
|
} from "./Reflection";
|
|
42
41
|
|
|
42
|
+
// Annotations, Metadata and TypeContext
|
|
43
43
|
export { Metadata } from "./Metadata";
|
|
44
|
-
|
|
45
|
-
export {
|
|
46
|
-
// Annotations
|
|
47
|
-
type,
|
|
48
|
-
deprecated,
|
|
49
|
-
defineTypes,
|
|
50
|
-
view,
|
|
51
|
-
|
|
52
|
-
// Internals
|
|
53
|
-
TypeContext,
|
|
54
|
-
} from "./annotations";
|
|
44
|
+
export { type, deprecated, defineTypes, view, } from "./annotations";
|
|
45
|
+
export { TypeContext } from "./types/TypeContext";
|
|
55
46
|
|
|
56
47
|
// Annotation types
|
|
57
48
|
export type { DefinitionType, PrimitiveType, Definition, } from "./annotations";
|
|
58
49
|
|
|
50
|
+
export { getDecoderStateCallbacks, CallbackProxy, GetCallbackProxy } from "./decoder/strategy/StateCallbacks";
|
|
51
|
+
export { getRawChangesCallback } from "./decoder/strategy/RawChanges";
|
|
52
|
+
|
|
59
53
|
export { Encoder } from "./encoder/Encoder";
|
|
60
54
|
export { encodeSchemaOperation, encodeArray as encodeKeyValueOperation } from "./encoder/EncodeOperation";
|
|
61
55
|
export { ChangeTree, Ref } from "./encoder/ChangeTree";
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { Metadata } from "../Metadata";
|
|
2
|
+
import { Schema } from "../Schema";
|
|
3
|
+
|
|
4
|
+
export class TypeContext {
|
|
5
|
+
types: { [id: number]: typeof Schema; } = {};
|
|
6
|
+
schemas = new Map<typeof Schema, number>();
|
|
7
|
+
|
|
8
|
+
hasFilters: boolean = false;
|
|
9
|
+
parentFiltered: {[typeIdAndParentIndex: string]: boolean} = {};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* For inheritance support
|
|
13
|
+
* Keeps track of which classes extends which. (parent -> children)
|
|
14
|
+
*/
|
|
15
|
+
static inheritedTypes = new Map<typeof Schema, Set<typeof Schema>>();
|
|
16
|
+
|
|
17
|
+
static register(target: typeof Schema) {
|
|
18
|
+
const parent = Object.getPrototypeOf(target);
|
|
19
|
+
if (parent !== Schema) {
|
|
20
|
+
let inherits = TypeContext.inheritedTypes.get(parent);
|
|
21
|
+
if (!inherits) {
|
|
22
|
+
inherits = new Set<typeof Schema>();
|
|
23
|
+
TypeContext.inheritedTypes.set(parent, inherits);
|
|
24
|
+
}
|
|
25
|
+
inherits.add(target);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
constructor(rootClass?: typeof Schema) {
|
|
30
|
+
if (rootClass) {
|
|
31
|
+
this.discoverTypes(rootClass);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
has(schema: typeof Schema) {
|
|
36
|
+
return this.schemas.has(schema);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get(typeid: number) {
|
|
40
|
+
return this.types[typeid];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
add(schema: typeof Schema, typeid: number = this.schemas.size) {
|
|
44
|
+
// skip if already registered
|
|
45
|
+
if (this.schemas.has(schema)) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
this.types[typeid] = schema;
|
|
50
|
+
|
|
51
|
+
//
|
|
52
|
+
// Workaround to allow using an empty Schema (with no `@type()` fields)
|
|
53
|
+
//
|
|
54
|
+
if (schema[Symbol.metadata] === undefined) {
|
|
55
|
+
Metadata.init(schema);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.schemas.set(schema, typeid);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
getTypeId(klass: typeof Schema) {
|
|
63
|
+
return this.schemas.get(klass);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private discoverTypes(klass: typeof Schema, parentIndex?: number, parentFieldViewTag?: number) {
|
|
67
|
+
if (!this.add(klass)) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// add classes inherited from this base class
|
|
72
|
+
TypeContext.inheritedTypes.get(klass)?.forEach((child) => {
|
|
73
|
+
this.discoverTypes(child, parentIndex, parentFieldViewTag);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const metadata: Metadata = (klass[Symbol.metadata] ??= {});
|
|
77
|
+
|
|
78
|
+
// if any schema/field has filters, mark "context" as having filters.
|
|
79
|
+
if (metadata[-2]) {
|
|
80
|
+
this.hasFilters = true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (parentFieldViewTag !== undefined) {
|
|
84
|
+
this.parentFiltered[`${this.schemas.get(klass)}-${parentIndex}`] = true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
for (const fieldIndex in metadata) {
|
|
88
|
+
const index = fieldIndex as any as number;
|
|
89
|
+
|
|
90
|
+
const fieldType = metadata[index].type;
|
|
91
|
+
const viewTag = metadata[index].tag;
|
|
92
|
+
|
|
93
|
+
if (typeof (fieldType) === "string") {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (Array.isArray(fieldType)) {
|
|
98
|
+
const type = fieldType[0];
|
|
99
|
+
|
|
100
|
+
// skip primitive types
|
|
101
|
+
if (type === "string") {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
this.discoverTypes(type as typeof Schema, index, viewTag);
|
|
106
|
+
|
|
107
|
+
} else if (typeof (fieldType) === "function") {
|
|
108
|
+
this.discoverTypes(fieldType as typeof Schema, viewTag);
|
|
109
|
+
|
|
110
|
+
} else {
|
|
111
|
+
const type = Object.values(fieldType)[0];
|
|
112
|
+
|
|
113
|
+
// skip primitive types
|
|
114
|
+
if (typeof (type) === "string") {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
this.discoverTypes(type as typeof Schema, index, viewTag);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -8,6 +8,7 @@ import { Collection } from "../HelperTypes";
|
|
|
8
8
|
import { encodeArray } from "../../encoder/EncodeOperation";
|
|
9
9
|
import { decodeArray } from "../../decoder/DecodeOperation";
|
|
10
10
|
import type { StateView } from "../../encoder/StateView";
|
|
11
|
+
import { assertInstanceType } from "../../encoding/assert";
|
|
11
12
|
|
|
12
13
|
const DEFAULT_SORT = (a: any, b: any) => {
|
|
13
14
|
const A = a.toString();
|
|
@@ -85,6 +86,8 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
|
|
|
85
86
|
|
|
86
87
|
} else {
|
|
87
88
|
if (setValue[$changes]) {
|
|
89
|
+
assertInstanceType(setValue, obj[$childType] as typeof Schema, obj, key);
|
|
90
|
+
|
|
88
91
|
if (obj.items[key as unknown as number] !== undefined) {
|
|
89
92
|
if (setValue[$changes][$isNew]) {
|
|
90
93
|
this[$changes].indexedOperation(Number(key), OPERATION.MOVE_AND_ADD);
|
|
@@ -99,6 +102,7 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
|
|
|
99
102
|
} else if (setValue[$changes][$isNew]) {
|
|
100
103
|
this[$changes].indexedOperation(Number(key), OPERATION.ADD);
|
|
101
104
|
}
|
|
105
|
+
|
|
102
106
|
} else {
|
|
103
107
|
obj.$changeAt(Number(key), setValue);
|
|
104
108
|
}
|
|
@@ -133,6 +137,7 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
|
|
|
133
137
|
});
|
|
134
138
|
|
|
135
139
|
this[$changes] = new ChangeTree(proxy);
|
|
140
|
+
this[$changes].indexes = {};
|
|
136
141
|
this.push.apply(this, items);
|
|
137
142
|
|
|
138
143
|
return proxy;
|
|
@@ -159,11 +164,13 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
|
|
|
159
164
|
// skip null values
|
|
160
165
|
if (value === undefined || value === null) {
|
|
161
166
|
return;
|
|
167
|
+
|
|
168
|
+
} else if (typeof (value) === "object" && this[$childType]) {
|
|
169
|
+
assertInstanceType(value as any, this[$childType] as typeof Schema, this, i);
|
|
162
170
|
}
|
|
163
171
|
|
|
164
172
|
const changeTree = this[$changes];
|
|
165
173
|
changeTree.indexedOperation(length, OPERATION.ADD, this.items.length);
|
|
166
|
-
// changeTree.indexes[length] = length;
|
|
167
174
|
|
|
168
175
|
this.items.push(value);
|
|
169
176
|
this.tmpItems.push(value);
|
|
@@ -471,6 +478,7 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
|
|
|
471
478
|
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
|
472
479
|
* If thisArg is omitted, undefined is used as the this value.
|
|
473
480
|
*/
|
|
481
|
+
every<S extends V>(predicate: (value: V, index: number, array: V[]) => value is S, thisArg?: any): this is S[];
|
|
474
482
|
every(callbackfn: (value: V, index: number, array: V[]) => unknown, thisArg?: any): boolean {
|
|
475
483
|
return this.items.every(callbackfn, thisArg);
|
|
476
484
|
}
|
|
@@ -690,7 +698,7 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
|
|
|
690
698
|
//
|
|
691
699
|
// ES2023
|
|
692
700
|
//
|
|
693
|
-
with(index: number, value: V): V
|
|
701
|
+
with(index: number, value: V): ArraySchema<V> {
|
|
694
702
|
const copy = this.items.slice();
|
|
695
703
|
copy[index] = value;
|
|
696
704
|
return new ArraySchema(...copy);
|
|
@@ -6,6 +6,8 @@ import { Collection } from "../HelperTypes";
|
|
|
6
6
|
import { decodeKeyValueOperation } from "../../decoder/DecodeOperation";
|
|
7
7
|
import { encodeKeyValueOperation } from "../../encoder/EncodeOperation";
|
|
8
8
|
import type { StateView } from "../../encoder/StateView";
|
|
9
|
+
import type { Schema } from "../../Schema";
|
|
10
|
+
import { assertInstanceType } from "../../encoding/assert";
|
|
9
11
|
|
|
10
12
|
export class MapSchema<V=any, K extends string = string> implements Map<K, V>, Collection<K, V, [K, V]> {
|
|
11
13
|
protected childType: new () => V;
|
|
@@ -39,6 +41,7 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
|
|
|
39
41
|
|
|
40
42
|
constructor (initialValues?: Map<K, V> | Record<K, V>) {
|
|
41
43
|
this[$changes] = new ChangeTree(this);
|
|
44
|
+
this[$changes].indexes = {};
|
|
42
45
|
|
|
43
46
|
if (initialValues) {
|
|
44
47
|
if (
|
|
@@ -71,6 +74,9 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
|
|
|
71
74
|
set(key: K, value: V) {
|
|
72
75
|
if (value === undefined || value === null) {
|
|
73
76
|
throw new Error(`MapSchema#set('${key}', ${value}): trying to set ${value} value on '${key}'.`);
|
|
77
|
+
|
|
78
|
+
} else if (typeof(value) === "object" && this[$childType]) {
|
|
79
|
+
assertInstanceType(value as any, this[$childType] as typeof Schema, this, key);
|
|
74
80
|
}
|
|
75
81
|
|
|
76
82
|
// Force "key" as string
|
package/src/types/symbols.ts
CHANGED
|
@@ -7,6 +7,8 @@ export const $filter = Symbol("$filter");
|
|
|
7
7
|
export const $getByIndex = Symbol("$getByIndex");
|
|
8
8
|
export const $deleteByIndex = Symbol("$deleteByIndex");
|
|
9
9
|
|
|
10
|
+
export const $descriptors = Symbol("$descriptors");
|
|
11
|
+
|
|
10
12
|
/**
|
|
11
13
|
* Used to hold ChangeTree instances whitin the structures
|
|
12
14
|
*/
|