@colyseus/schema 3.0.0-alpha.4 → 3.0.0-alpha.40
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/bin/schema-debug +94 -0
- package/build/cjs/index.js +1521 -809
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +1519 -808
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +1528 -816
- package/lib/Metadata.d.ts +21 -9
- package/lib/Metadata.js +169 -32
- package/lib/Metadata.js.map +1 -1
- package/lib/Reflection.d.ts +19 -4
- package/lib/Reflection.js +66 -32
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.d.ts +4 -4
- package/lib/Schema.js +44 -50
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.d.ts +31 -34
- package/lib/annotations.js +110 -160
- package/lib/annotations.js.map +1 -1
- package/lib/bench_encode.d.ts +1 -0
- package/lib/bench_encode.js +130 -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 +85 -3
- package/lib/codegen/parser.js.map +1 -1
- package/lib/codegen/types.js +6 -3
- package/lib/codegen/types.js.map +1 -1
- package/lib/debug.d.ts +1 -0
- package/lib/debug.js +51 -0
- package/lib/debug.js.map +1 -0
- package/lib/decoder/DecodeOperation.d.ts +0 -1
- package/lib/decoder/DecodeOperation.js +30 -12
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/decoder/Decoder.d.ts +6 -7
- package/lib/decoder/Decoder.js +9 -9
- 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 +27 -21
- package/lib/encoder/ChangeTree.js +246 -186
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/EncodeOperation.d.ts +3 -6
- package/lib/encoder/EncodeOperation.js +47 -61
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.d.ts +9 -8
- package/lib/encoder/Encoder.js +165 -88
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.d.ts +22 -0
- package/lib/encoder/Root.js +81 -0
- package/lib/encoder/Root.js.map +1 -0
- package/lib/encoder/StateView.d.ts +7 -7
- package/lib/encoder/StateView.js +70 -74
- 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 +20 -21
- package/lib/encoding/decode.js.map +1 -1
- package/lib/encoding/encode.d.ts +2 -2
- package/lib/encoding/encode.js +52 -48
- 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 +19 -13
- package/lib/index.js.map +1 -1
- package/lib/types/HelperTypes.d.ts +34 -2
- package/lib/types/HelperTypes.js.map +1 -1
- package/lib/types/TypeContext.d.ts +23 -0
- package/lib/types/TypeContext.js +111 -0
- package/lib/types/TypeContext.js.map +1 -0
- package/lib/types/custom/ArraySchema.d.ts +2 -2
- package/lib/types/custom/ArraySchema.js +33 -22
- 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.d.ts +3 -1
- package/lib/types/custom/MapSchema.js +12 -4
- 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 +8 -5
- package/lib/types/symbols.js +9 -6
- 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 +9 -7
- package/lib/utils.js.map +1 -1
- package/package.json +7 -6
- package/src/Metadata.ts +190 -42
- package/src/Reflection.ts +77 -39
- package/src/Schema.ts +59 -64
- package/src/annotations.ts +155 -203
- package/src/bench_encode.ts +108 -0
- package/src/codegen/parser.ts +107 -0
- package/src/codegen/types.ts +1 -0
- package/src/debug.ts +55 -0
- package/src/decoder/DecodeOperation.ts +40 -12
- package/src/decoder/Decoder.ts +14 -12
- package/src/decoder/ReferenceTracker.ts +3 -2
- package/src/decoder/strategy/StateCallbacks.ts +153 -82
- package/src/encoder/ChangeTree.ts +286 -202
- package/src/encoder/EncodeOperation.ts +77 -77
- package/src/encoder/Encoder.ts +201 -96
- package/src/encoder/Root.ts +93 -0
- package/src/encoder/StateView.ts +76 -88
- package/src/encoding/assert.ts +4 -3
- package/src/encoding/encode.ts +37 -31
- package/src/encoding/spec.ts +1 -0
- package/src/index.ts +8 -14
- package/src/types/HelperTypes.ts +54 -2
- package/src/types/TypeContext.ts +133 -0
- package/src/types/custom/ArraySchema.ts +49 -19
- package/src/types/custom/CollectionSchema.ts +1 -0
- package/src/types/custom/MapSchema.ts +18 -5
- package/src/types/custom/SetSchema.ts +1 -0
- package/src/types/symbols.ts +10 -7
- package/src/utils.ts +7 -3
package/src/encoder/StateView.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { ChangeTree, Ref } from "./ChangeTree";
|
|
2
|
-
import { $changes } from "../types/symbols";
|
|
1
|
+
import { ChangeSet, ChangeTree, IndexedOperations, Ref } from "./ChangeTree";
|
|
2
|
+
import { $changes, $fieldIndexesByViewTag, $viewFieldIndexes } from "../types/symbols";
|
|
3
3
|
import { DEFAULT_VIEW_TAG } from "../annotations";
|
|
4
4
|
import { OPERATION } from "../encoding/spec";
|
|
5
5
|
import { Metadata } from "../Metadata";
|
|
6
|
-
import type { Schema } from "../Schema";
|
|
7
6
|
|
|
8
|
-
export function createView(
|
|
7
|
+
export function createView() {
|
|
8
|
+
return new StateView();
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export class StateView {
|
|
@@ -25,37 +25,35 @@ export class StateView {
|
|
|
25
25
|
* Manual "ADD" operations for changes per ChangeTree, specific to this view.
|
|
26
26
|
* (This is used to force encoding a property, even if it was not changed)
|
|
27
27
|
*/
|
|
28
|
-
changes
|
|
28
|
+
changes: { [refId: number]: IndexedOperations } = {};
|
|
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
|
|
53
51
|
// be set (only the parent's changes are set)
|
|
54
52
|
//
|
|
55
|
-
let changes = this.changes.
|
|
53
|
+
let changes = this.changes[changeTree.refId];
|
|
56
54
|
if (changes === undefined) {
|
|
57
|
-
changes =
|
|
58
|
-
this.changes.
|
|
55
|
+
changes = {};
|
|
56
|
+
this.changes[changeTree.refId] = changes;
|
|
59
57
|
}
|
|
60
58
|
|
|
61
59
|
// set tag
|
|
@@ -72,99 +70,89 @@ 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
|
-
metadata?.[
|
|
74
|
+
metadata?.[$fieldIndexesByViewTag]?.[tag]?.forEach((index) => {
|
|
79
75
|
if (changeTree.getChange(index) !== OPERATION.DELETE) {
|
|
80
|
-
changes
|
|
76
|
+
changes[index] = OPERATION.ADD;
|
|
81
77
|
}
|
|
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
|
-
for (
|
|
86
|
+
for (let i = 0, len = changeSet.operations.length; i < len; i++) {
|
|
87
|
+
const index = changeSet.operations[i];
|
|
88
|
+
if (index === undefined) { continue; } // skip "undefined" indexes
|
|
89
|
+
|
|
90
|
+
const op = changeTree.indexedOperations[index];
|
|
91
|
+
const tagAtIndex = metadata?.[index].tag;
|
|
102
92
|
if (
|
|
103
|
-
(
|
|
104
|
-
|
|
93
|
+
(
|
|
94
|
+
isInvisible || // if "invisible", include all
|
|
95
|
+
tagAtIndex === undefined || // "all change" with no tag
|
|
96
|
+
tagAtIndex === tag // tagged property
|
|
97
|
+
) &&
|
|
98
|
+
op !== OPERATION.DELETE
|
|
105
99
|
) {
|
|
106
|
-
changes
|
|
100
|
+
changes[index] = op;
|
|
107
101
|
}
|
|
108
102
|
}
|
|
109
103
|
}
|
|
110
104
|
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
this.
|
|
118
|
-
}
|
|
105
|
+
// Add children of this ChangeTree to this view
|
|
106
|
+
changeTree.forEachChild((change, index) => {
|
|
107
|
+
// Do not ADD children that don't have the same tag
|
|
108
|
+
if (metadata && metadata[index].tag !== tag) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
this.add(change.ref, tag, false);
|
|
112
|
+
});
|
|
119
113
|
|
|
120
114
|
return this;
|
|
121
115
|
}
|
|
122
116
|
|
|
123
|
-
protected addParent(changeTree: ChangeTree, tag: number) {
|
|
124
|
-
|
|
125
|
-
|
|
117
|
+
protected addParent(changeTree: ChangeTree, parentIndex: number, tag: number) {
|
|
118
|
+
// view must have all "changeTree" parent tree
|
|
119
|
+
this.items.add(changeTree);
|
|
126
120
|
|
|
127
|
-
|
|
128
|
-
const
|
|
121
|
+
// add parent's parent
|
|
122
|
+
const parentChangeTree = changeTree.parent?.[$changes];
|
|
123
|
+
if (parentChangeTree && (parentChangeTree.isFiltered || parentChangeTree.isPartiallyFiltered)) {
|
|
124
|
+
this.addParent(parentChangeTree, changeTree.parentIndex, tag);
|
|
125
|
+
}
|
|
129
126
|
|
|
130
|
-
|
|
131
|
-
|
|
127
|
+
// parent is already available, no need to add it!
|
|
128
|
+
if (!this.invisible.has(changeTree)) {
|
|
132
129
|
return;
|
|
133
130
|
}
|
|
134
131
|
|
|
135
|
-
this.addParent(parentChangeTree, tag);
|
|
136
|
-
|
|
137
132
|
// add parent's tag properties
|
|
138
|
-
if (
|
|
133
|
+
if (changeTree.getChange(parentIndex) !== OPERATION.DELETE) {
|
|
139
134
|
|
|
140
|
-
let
|
|
141
|
-
if (
|
|
142
|
-
|
|
143
|
-
this.changes.
|
|
135
|
+
let changes = this.changes[changeTree.refId];
|
|
136
|
+
if (changes === undefined) {
|
|
137
|
+
changes = {};
|
|
138
|
+
this.changes[changeTree.refId] = changes;
|
|
144
139
|
}
|
|
145
140
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
// parentChange: (
|
|
150
|
-
// parentChangeTree.getChange(parentIndex) &&
|
|
151
|
-
// OPERATION[parentChangeTree.getChange(parentIndex)]
|
|
152
|
-
// ),
|
|
153
|
-
// })
|
|
141
|
+
if (!this.tags) {
|
|
142
|
+
this.tags = new WeakMap<ChangeTree, Set<number>>();
|
|
143
|
+
}
|
|
154
144
|
|
|
155
|
-
if (!this.tags) { this.tags = new WeakMap<ChangeTree, Set<number>>(); }
|
|
156
145
|
let tags: Set<number>;
|
|
157
|
-
if (!this.tags.has(
|
|
146
|
+
if (!this.tags.has(changeTree)) {
|
|
158
147
|
tags = new Set<number>();
|
|
159
|
-
this.tags.set(
|
|
148
|
+
this.tags.set(changeTree, tags);
|
|
160
149
|
} else {
|
|
161
|
-
tags = this.tags.get(
|
|
150
|
+
tags = this.tags.get(changeTree);
|
|
162
151
|
}
|
|
163
152
|
tags.add(tag);
|
|
164
153
|
|
|
165
|
-
|
|
154
|
+
changes[parentIndex] = OPERATION.ADD;
|
|
166
155
|
}
|
|
167
|
-
|
|
168
156
|
}
|
|
169
157
|
|
|
170
158
|
remove(obj: Ref, tag: number = DEFAULT_VIEW_TAG) {
|
|
@@ -179,10 +167,10 @@ export class StateView {
|
|
|
179
167
|
const ref = changeTree.ref;
|
|
180
168
|
const metadata: Metadata = ref.constructor[Symbol.metadata];
|
|
181
169
|
|
|
182
|
-
let changes = this.changes.
|
|
170
|
+
let changes = this.changes[changeTree.refId];
|
|
183
171
|
if (changes === undefined) {
|
|
184
|
-
changes =
|
|
185
|
-
this.changes.
|
|
172
|
+
changes = {};
|
|
173
|
+
this.changes[changeTree.refId] = changes;
|
|
186
174
|
}
|
|
187
175
|
|
|
188
176
|
if (tag === DEFAULT_VIEW_TAG) {
|
|
@@ -190,25 +178,25 @@ export class StateView {
|
|
|
190
178
|
const parent = changeTree.parent;
|
|
191
179
|
if (!Metadata.isValidInstance(parent)) {
|
|
192
180
|
const parentChangeTree = parent[$changes];
|
|
193
|
-
let changes = this.changes.
|
|
181
|
+
let changes = this.changes[parentChangeTree.refId];
|
|
194
182
|
if (changes === undefined) {
|
|
195
|
-
changes =
|
|
196
|
-
this.changes.
|
|
183
|
+
changes = {};
|
|
184
|
+
this.changes[parentChangeTree.refId] = changes;
|
|
197
185
|
}
|
|
198
186
|
// DELETE / DELETE BY REF ID
|
|
199
|
-
changes
|
|
187
|
+
changes[changeTree.parentIndex] = OPERATION.DELETE;
|
|
200
188
|
|
|
201
189
|
} else {
|
|
202
190
|
// delete all "tagged" properties.
|
|
203
|
-
metadata[
|
|
204
|
-
changes
|
|
191
|
+
metadata[$viewFieldIndexes].forEach((index) =>
|
|
192
|
+
changes[index] = OPERATION.DELETE);
|
|
205
193
|
}
|
|
206
194
|
|
|
207
195
|
|
|
208
196
|
} else {
|
|
209
197
|
// delete only tagged properties
|
|
210
|
-
metadata[
|
|
211
|
-
changes
|
|
198
|
+
metadata[$fieldIndexesByViewTag][tag].forEach((index) =>
|
|
199
|
+
changes[index] = OPERATION.DELETE);
|
|
212
200
|
}
|
|
213
201
|
|
|
214
202
|
// remove 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/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: (str: string, _?: any) => number = (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);
|
|
@@ -64,21 +68,24 @@ export function utf8Write(view, str, it) {
|
|
|
64
68
|
view[it.offset++] = c;
|
|
65
69
|
}
|
|
66
70
|
else if (c < 0x800) {
|
|
67
|
-
view[it.offset
|
|
68
|
-
view[it.offset
|
|
71
|
+
view[it.offset] = 0xc0 | (c >> 6);
|
|
72
|
+
view[it.offset + 1] = 0x80 | (c & 0x3f);
|
|
73
|
+
it.offset += 2;
|
|
69
74
|
}
|
|
70
75
|
else if (c < 0xd800 || c >= 0xe000) {
|
|
71
|
-
view[it.offset
|
|
72
|
-
view[it.offset
|
|
73
|
-
view[it.offset
|
|
76
|
+
view[it.offset] = 0xe0 | (c >> 12);
|
|
77
|
+
view[it.offset+1] = 0x80 | (c >> 6 & 0x3f);
|
|
78
|
+
view[it.offset+2] = 0x80 | (c & 0x3f);
|
|
79
|
+
it.offset += 3;
|
|
74
80
|
}
|
|
75
81
|
else {
|
|
76
82
|
i++;
|
|
77
83
|
c = 0x10000 + (((c & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff));
|
|
78
|
-
view[it.offset
|
|
79
|
-
view[it.offset
|
|
80
|
-
view[it.offset
|
|
81
|
-
view[it.offset
|
|
84
|
+
view[it.offset] = 0xf0 | (c >> 18);
|
|
85
|
+
view[it.offset+1] = 0x80 | (c >> 12 & 0x3f);
|
|
86
|
+
view[it.offset+2] = 0x80 | (c >> 6 & 0x3f);
|
|
87
|
+
view[it.offset+3] = 0x80 | (c & 0x3f);
|
|
88
|
+
it.offset += 4;
|
|
82
89
|
}
|
|
83
90
|
}
|
|
84
91
|
}
|
|
@@ -166,8 +173,7 @@ export function string(bytes: BufferLike, value: string, it: Iterator) {
|
|
|
166
173
|
// encode `null` strings as empty.
|
|
167
174
|
if (!value) { value = ""; }
|
|
168
175
|
|
|
169
|
-
|
|
170
|
-
let length = Buffer.byteLength(value, "utf8");
|
|
176
|
+
let length = utf8Length(value, "utf8");
|
|
171
177
|
let size = 0;
|
|
172
178
|
|
|
173
179
|
// 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, schema, type SchemaWithExtends, } 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";
|
package/src/types/HelperTypes.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import type { Definition, DefinitionType, PrimitiveType, RawPrimitiveType } from "../annotations";
|
|
2
|
+
import type { Schema } from "../Schema";
|
|
3
|
+
import type { ArraySchema } from "./custom/ArraySchema";
|
|
4
|
+
import type { CollectionSchema } from "./custom/CollectionSchema";
|
|
5
|
+
import type { MapSchema } from "./custom/MapSchema";
|
|
6
|
+
import type { SetSchema } from "./custom/SetSchema";
|
|
7
|
+
|
|
8
|
+
export type Constructor<T = {}> = new (...args: any[]) => T;
|
|
3
9
|
|
|
4
10
|
export interface Collection<K = any, V = any, IT = V> {
|
|
5
11
|
[Symbol.iterator](): IterableIterator<IT>;
|
|
@@ -7,6 +13,52 @@ export interface Collection<K = any, V = any, IT = V> {
|
|
|
7
13
|
entries(): IterableIterator<[K, V]>;
|
|
8
14
|
}
|
|
9
15
|
|
|
16
|
+
export type InferValueType<T extends DefinitionType> =
|
|
17
|
+
T extends "string" ? string
|
|
18
|
+
: T extends "number" ? number
|
|
19
|
+
: T extends "int8" ? number
|
|
20
|
+
: T extends "uint8" ? number
|
|
21
|
+
: T extends "int16" ? number
|
|
22
|
+
: T extends "uint16" ? number
|
|
23
|
+
: T extends "int32" ? number
|
|
24
|
+
: T extends "uint32" ? number
|
|
25
|
+
: T extends "int64" ? number
|
|
26
|
+
: T extends "uint64" ? number
|
|
27
|
+
: T extends "float32" ? number
|
|
28
|
+
: T extends "float64" ? number
|
|
29
|
+
: T extends "boolean" ? boolean
|
|
30
|
+
|
|
31
|
+
: T extends { type: infer ChildType extends Constructor } ? InstanceType<ChildType>
|
|
32
|
+
: T extends { type: infer ChildType extends PrimitiveType } ? ChildType
|
|
33
|
+
|
|
34
|
+
: T extends Array<infer ChildType extends Constructor> ? InstanceType<ChildType>[]
|
|
35
|
+
: T extends Array<infer ChildType extends RawPrimitiveType> ? ChildType[]
|
|
36
|
+
|
|
37
|
+
: T extends { array: infer ChildType extends Constructor } ? InstanceType<ChildType>[]
|
|
38
|
+
: T extends { array: infer ChildType extends PrimitiveType } ? ChildType[]
|
|
39
|
+
|
|
40
|
+
: T extends { map: infer ChildType extends Constructor } ? MapSchema<InstanceType<ChildType>>
|
|
41
|
+
: T extends { map: infer ChildType extends PrimitiveType } ? MapSchema<ChildType>
|
|
42
|
+
|
|
43
|
+
: T extends { set: infer ChildType extends Constructor } ? SetSchema<InstanceType<ChildType>>
|
|
44
|
+
: T extends { set: infer ChildType extends PrimitiveType } ? SetSchema<ChildType>
|
|
45
|
+
|
|
46
|
+
: T extends { collection: infer ChildType extends Constructor } ? CollectionSchema<InstanceType<ChildType>>
|
|
47
|
+
: T extends { collection: infer ChildType extends PrimitiveType } ? CollectionSchema<ChildType>
|
|
48
|
+
|
|
49
|
+
: T extends Constructor ? InstanceType<T>
|
|
50
|
+
: T extends PrimitiveType ? T
|
|
51
|
+
|
|
52
|
+
: never;
|
|
53
|
+
|
|
54
|
+
export type InferSchemaInstanceType<T extends Definition> = {
|
|
55
|
+
[K in keyof T]: InferValueType<T[K]>
|
|
56
|
+
} & Schema;
|
|
57
|
+
|
|
58
|
+
export type DefinedSchemaType<T extends Definition, P extends typeof Schema> = {
|
|
59
|
+
new (): InferSchemaInstanceType<T> & InstanceType<P>;
|
|
60
|
+
} & typeof Schema;
|
|
61
|
+
|
|
10
62
|
export type NonFunctionProps<T> = Omit<T, {
|
|
11
63
|
[K in keyof T]: T[K] extends Function ? K : never;
|
|
12
64
|
}[keyof T]>;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Metadata } from "../Metadata";
|
|
2
|
+
import { Schema } from "../Schema";
|
|
3
|
+
import { $viewFieldIndexes } from "./symbols";
|
|
4
|
+
|
|
5
|
+
export class TypeContext {
|
|
6
|
+
types: { [id: number]: typeof Schema; } = {};
|
|
7
|
+
schemas = new Map<typeof Schema, number>();
|
|
8
|
+
|
|
9
|
+
hasFilters: boolean = false;
|
|
10
|
+
parentFiltered: {[typeIdAndParentIndex: string]: boolean} = {};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* For inheritance support
|
|
14
|
+
* Keeps track of which classes extends which. (parent -> children)
|
|
15
|
+
*/
|
|
16
|
+
static inheritedTypes = new Map<typeof Schema, Set<typeof Schema>>();
|
|
17
|
+
|
|
18
|
+
static register(target: typeof Schema) {
|
|
19
|
+
const parent = Object.getPrototypeOf(target);
|
|
20
|
+
if (parent !== Schema) {
|
|
21
|
+
let inherits = TypeContext.inheritedTypes.get(parent);
|
|
22
|
+
if (!inherits) {
|
|
23
|
+
inherits = new Set<typeof Schema>();
|
|
24
|
+
TypeContext.inheritedTypes.set(parent, inherits);
|
|
25
|
+
}
|
|
26
|
+
inherits.add(target);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
constructor(rootClass?: typeof Schema) {
|
|
31
|
+
if (rootClass) {
|
|
32
|
+
this.discoverTypes(rootClass);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
has(schema: typeof Schema) {
|
|
37
|
+
return this.schemas.has(schema);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get(typeid: number) {
|
|
41
|
+
return this.types[typeid];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
add(schema: typeof Schema, typeid: number = this.schemas.size) {
|
|
45
|
+
// skip if already registered
|
|
46
|
+
if (this.schemas.has(schema)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
this.types[typeid] = schema;
|
|
51
|
+
|
|
52
|
+
//
|
|
53
|
+
// Workaround to allow using an empty Schema (with no `@type()` fields)
|
|
54
|
+
//
|
|
55
|
+
if (schema[Symbol.metadata] === undefined) {
|
|
56
|
+
Metadata.initialize(schema);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this.schemas.set(schema, typeid);
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
getTypeId(klass: typeof Schema) {
|
|
64
|
+
return this.schemas.get(klass);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private discoverTypes(klass: typeof Schema, parentIndex?: number, parentFieldViewTag?: number) {
|
|
68
|
+
if (!this.add(klass)) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// add classes inherited from this base class
|
|
73
|
+
TypeContext.inheritedTypes.get(klass)?.forEach((child) => {
|
|
74
|
+
this.discoverTypes(child, parentIndex, parentFieldViewTag);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// add parent classes
|
|
78
|
+
let parent: any = klass;
|
|
79
|
+
while (
|
|
80
|
+
(parent = Object.getPrototypeOf(parent)) &&
|
|
81
|
+
parent !== Schema && // stop at root (Schema)
|
|
82
|
+
parent !== Function.prototype // stop at root (non-Schema)
|
|
83
|
+
) {
|
|
84
|
+
this.discoverTypes(parent);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const metadata: Metadata = (klass[Symbol.metadata] ??= {});
|
|
88
|
+
|
|
89
|
+
// if any schema/field has filters, mark "context" as having filters.
|
|
90
|
+
if (metadata[$viewFieldIndexes]) {
|
|
91
|
+
this.hasFilters = true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (parentFieldViewTag !== undefined) {
|
|
95
|
+
this.parentFiltered[`${this.schemas.get(klass)}-${parentIndex}`] = true;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
for (const fieldIndex in metadata) {
|
|
99
|
+
const index = fieldIndex as any as number;
|
|
100
|
+
|
|
101
|
+
const fieldType = metadata[index].type;
|
|
102
|
+
const viewTag = metadata[index].tag;
|
|
103
|
+
|
|
104
|
+
if (typeof (fieldType) === "string") {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (Array.isArray(fieldType)) {
|
|
109
|
+
const type = fieldType[0];
|
|
110
|
+
|
|
111
|
+
// skip primitive types
|
|
112
|
+
if (type === "string") {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this.discoverTypes(type as typeof Schema, index, viewTag);
|
|
117
|
+
|
|
118
|
+
} else if (typeof (fieldType) === "function") {
|
|
119
|
+
this.discoverTypes(fieldType as typeof Schema, viewTag);
|
|
120
|
+
|
|
121
|
+
} else {
|
|
122
|
+
const type = Object.values(fieldType)[0];
|
|
123
|
+
|
|
124
|
+
// skip primitive types
|
|
125
|
+
if (typeof (type) === "string") {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
this.discoverTypes(type as typeof Schema, index, viewTag);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|