seroval 0.1.0 → 0.2.0

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/src/context.ts ADDED
@@ -0,0 +1,200 @@
1
+ import { forEach, join } from './array';
2
+ import getIdentifier from './get-identifier';
3
+ import { AsyncServerValue } from './types';
4
+
5
+ export const EMPTY_SET = 'new Set';
6
+ export const EMPTY_MAP = 'new Map';
7
+ export const EMPTY_ARRAY = '[]';
8
+
9
+ // Array of assignments to be done (used for recursion)
10
+ export type Assignment = [source: string, value: string];
11
+
12
+ // Array of Map.prototype.set calls
13
+ export type MapSet = [source: string, key: string, value: string];
14
+
15
+ // Array of Set.prototype.add calls
16
+ export type SetAdd = [source: string, value: string];
17
+
18
+ export interface SerializationContext {
19
+ stack: Set<unknown>;
20
+ // Set to check if ref id already has an assigned value
21
+ assignedRefs: Set<number>;
22
+ // Variables
23
+ vars: string[];
24
+ // Array of assignments to be done (used for recursion)
25
+ assignments: Assignment[];
26
+ // Array of Map.prototype.set calls
27
+ mapSets: MapSet[];
28
+ // Array of Set.prototype.add calls
29
+ setAdds: SetAdd[];
30
+ // Reference counter
31
+ refCount: Map<unknown, number>;
32
+ // Value-to-ref map
33
+ refs: Map<unknown, number>;
34
+ }
35
+
36
+ export function createSerializationContext(): SerializationContext {
37
+ return {
38
+ refCount: new Map(),
39
+ stack: new Set(),
40
+ refs: new Map(),
41
+ assignedRefs: new Set(),
42
+ vars: [],
43
+ assignments: [],
44
+ mapSets: [],
45
+ setAdds: [],
46
+ };
47
+ }
48
+
49
+ export function resolveAssignments(ctx: SerializationContext) {
50
+ if (ctx.assignments.length) {
51
+ const result: Record<string, string> = {};
52
+
53
+ // Merge all assignments with similar source
54
+ forEach(ctx.assignments, ([source, value]) => {
55
+ if (value in result) {
56
+ result[value] = `${source}=${result[value]}`;
57
+ } else {
58
+ result[value] = `${source}=${value}`;
59
+ }
60
+ });
61
+
62
+ return `${join(Object.values(result), ',')},`;
63
+ }
64
+ return '';
65
+ }
66
+
67
+ export function resolveMapSets(ctx: SerializationContext) {
68
+ if (ctx.mapSets.length) {
69
+ const result: Record<string, string> = {};
70
+
71
+ // Merge all assignments with similar source
72
+ forEach(ctx.mapSets, ([source, key, value]) => {
73
+ if (source in result) {
74
+ result[source] = `${result[source]}.set(${key},${value})`;
75
+ } else {
76
+ result[source] = `${source}.set(${key},${value})`;
77
+ }
78
+ });
79
+
80
+ return `${join(Object.values(result), ',')},`;
81
+ }
82
+ return '';
83
+ }
84
+
85
+ export function resolveSetAdds(ctx: SerializationContext) {
86
+ if (ctx.setAdds.length) {
87
+ const result: Record<string, string> = {};
88
+
89
+ // Merge all assignments with similar source
90
+ forEach(ctx.setAdds, ([source, value]) => {
91
+ if (source in result) {
92
+ result[source] = `${result[source]}.add(${value})`;
93
+ } else {
94
+ result[source] = `${source}.add(${value})`;
95
+ }
96
+ });
97
+
98
+ return `${join(Object.values(result), ',')},`;
99
+ }
100
+ return '';
101
+ }
102
+
103
+ export function resolvePatches(ctx: SerializationContext) {
104
+ return `${resolveAssignments(ctx)}${resolveMapSets(ctx)}${resolveSetAdds(ctx)}`;
105
+ }
106
+
107
+ export function insertRef(ctx: SerializationContext, current: unknown) {
108
+ const count = ctx.refCount.get(current) || 0;
109
+ ctx.refCount.set(current, count + 1);
110
+ return count === 0;
111
+ }
112
+
113
+ export function constructorCheck<T extends NonNullable<AsyncServerValue>>(
114
+ value: NonNullable<AsyncServerValue>,
115
+ constructor: unknown,
116
+ ): value is T {
117
+ return value.constructor === constructor;
118
+ }
119
+
120
+ export function createRef(
121
+ ctx: SerializationContext,
122
+ value: unknown,
123
+ ) {
124
+ const current = ctx.refs.get(value);
125
+ if (current != null) {
126
+ return current;
127
+ }
128
+ const id = ctx.refs.size;
129
+ ctx.refs.set(value, id);
130
+ return id;
131
+ }
132
+
133
+ export function getRefParam(ctx: SerializationContext, index: number) {
134
+ if (ctx.vars[index]) {
135
+ return ctx.vars[index];
136
+ }
137
+ const result = getIdentifier(index);
138
+ ctx.vars[index] = result;
139
+ return result;
140
+ }
141
+
142
+ export function assignRef(
143
+ ctx: SerializationContext,
144
+ index: number,
145
+ value: string,
146
+ ) {
147
+ return `${getRefParam(ctx, index)}=${value}`;
148
+ }
149
+
150
+ export function createAssignment(
151
+ ctx: SerializationContext,
152
+ source: string,
153
+ value: string,
154
+ ) {
155
+ ctx.assignments.push([source, value]);
156
+ }
157
+
158
+ export function createSetAdd(
159
+ ctx: SerializationContext,
160
+ ref: number,
161
+ value: string,
162
+ ) {
163
+ ctx.setAdds.push([getRefParam(ctx, ref), value]);
164
+ }
165
+
166
+ export function createMapSet(
167
+ ctx: SerializationContext,
168
+ ref: number,
169
+ key: string,
170
+ value: string,
171
+ ) {
172
+ ctx.mapSets.push([getRefParam(ctx, ref), key, value]);
173
+ }
174
+
175
+ export function createArrayAssign(
176
+ ctx: SerializationContext,
177
+ ref: number,
178
+ index: number,
179
+ value: string,
180
+ ) {
181
+ createAssignment(ctx, `${getRefParam(ctx, ref)}[${index}]`, value);
182
+ }
183
+
184
+ export function createObjectIdentifierAssign(
185
+ ctx: SerializationContext,
186
+ ref: number,
187
+ key: string,
188
+ value: string,
189
+ ) {
190
+ createAssignment(ctx, `${getRefParam(ctx, ref)}.${key}`, value);
191
+ }
192
+
193
+ export function createObjectComputedAssign(
194
+ ctx: SerializationContext,
195
+ ref: number,
196
+ key: string,
197
+ value: string,
198
+ ) {
199
+ createAssignment(ctx, `${getRefParam(ctx, ref)}[${key}]`, value);
200
+ }
@@ -1,3 +1,4 @@
1
+ // Written by https://github.com/DylanPiercey and is distributed under the MIT license.
1
2
  const REF_START_CHARS = 'hjkmoquxzABCDEFGHIJKLNPQRTUVWXYZ$_'; // Avoids chars that could evaluate to a reserved word.
2
3
  const REF_START_CHARS_LEN = REF_START_CHARS.length;
3
4
  const REF_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$_';