seroval 0.3.0 → 0.4.0-alpha.1

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/compat.ts ADDED
@@ -0,0 +1,246 @@
1
+ /* eslint-disable guard-for-in */
2
+ /**
3
+ * References
4
+ * - https://kangax.github.io/compat-table/es6/
5
+ * - MDN
6
+ * - ESBuild
7
+ */
8
+
9
+ import assert from './assert';
10
+
11
+ export type Version = [major: number, minor: number, patch: number];
12
+
13
+ function compareVersion(left: Version, right: Version) {
14
+ let diff = left[0] - right[0];
15
+ if (diff === 0) {
16
+ diff = left[1] - right[1];
17
+ }
18
+ if (diff === 0) {
19
+ diff = left[2] - right[2];
20
+ }
21
+ return diff;
22
+ }
23
+
24
+ export interface PlatformVersion {
25
+ es: Version;
26
+ // desktop
27
+ chrome?: Version;
28
+ edge?: Version;
29
+ safari?: Version;
30
+ firefox?: Version;
31
+ opera?: Version;
32
+ // mobile
33
+ ios?: Version;
34
+ samsung?: Version;
35
+ // js runtimes
36
+ deno?: Version;
37
+ node?: Version;
38
+ }
39
+
40
+ export type Platform = keyof PlatformVersion;
41
+
42
+ export const enum Feature {
43
+ AggregateError,
44
+ ArrayPrototypeValues,
45
+ ArrowFunction,
46
+ BigInt,
47
+ Map,
48
+ MethodShorthand,
49
+ ObjectAssign,
50
+ Promise,
51
+ Set,
52
+ SymbolIterator,
53
+ TypedArray,
54
+ }
55
+
56
+ type VersionTable = {
57
+ [key in Feature]: PlatformVersion;
58
+ }
59
+
60
+ const VERSION_TABLE: VersionTable = {
61
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError#browser_compatibility
62
+ [Feature.AggregateError]: {
63
+ es: [2021, 0, 0],
64
+ chrome: [85, 0, 0],
65
+ edge: [85, 0, 0],
66
+ firefox: [79, 0, 0],
67
+ opera: [71, 0, 0],
68
+ safari: [14, 0, 0],
69
+ ios: [14, 0, 0],
70
+ samsung: [14, 0, 0],
71
+ deno: [1, 2, 0],
72
+ node: [15, 0, 0],
73
+ },
74
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values#browser_compatibility
75
+ [Feature.ArrayPrototypeValues]: {
76
+ es: [6, 0, 0],
77
+ chrome: [66, 0, 0],
78
+ edge: [14, 0, 0],
79
+ firefox: [60, 0, 0],
80
+ opera: [53, 0, 0],
81
+ safari: [9, 0, 0],
82
+ ios: [9, 0, 0],
83
+ samsung: [9, 0, 0],
84
+ deno: [1, 0, 0],
85
+ node: [10, 9, 0],
86
+ },
87
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#browser_compatibility
88
+ [Feature.ArrowFunction]: {
89
+ es: [6, 0, 0],
90
+ chrome: [45, 0, 0],
91
+ edge: [12, 0, 0],
92
+ firefox: [24, 0, 0],
93
+ opera: [32, 0, 0],
94
+ safari: [10, 0, 0],
95
+ ios: [10, 0, 0],
96
+ samsung: [5, 0, 0],
97
+ deno: [1, 0, 0],
98
+ node: [4, 0, 0],
99
+ },
100
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#browser_compatibility
101
+ [Feature.BigInt]: {
102
+ es: [2020, 0, 0],
103
+ chrome: [67, 0, 0],
104
+ edge: [79, 0, 0],
105
+ firefox: [68, 0, 0],
106
+ opera: [54, 0, 0],
107
+ safari: [14, 0, 0],
108
+ ios: [14, 0, 0],
109
+ samsung: [9, 0, 0],
110
+ deno: [1, 0, 0],
111
+ node: [10, 4, 0],
112
+ },
113
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#browser_compatibility
114
+ [Feature.Map]: {
115
+ es: [6, 0, 0],
116
+ chrome: [38, 0, 0],
117
+ edge: [12, 0, 0],
118
+ firefox: [13, 0, 0],
119
+ opera: [25, 0, 0],
120
+ safari: [8, 0, 0],
121
+ ios: [8, 0, 0],
122
+ samsung: [3, 0, 0],
123
+ deno: [1, 0, 0],
124
+ node: [0, 12, 0],
125
+ },
126
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions#browser_compatibility
127
+ [Feature.MethodShorthand]: {
128
+ es: [6, 0, 0],
129
+ chrome: [39, 0, 0],
130
+ edge: [12, 0, 0],
131
+ firefox: [34, 0, 0],
132
+ opera: [26, 0, 0],
133
+ safari: [9, 0, 0],
134
+ ios: [9, 0, 0],
135
+ samsung: [4, 0, 0],
136
+ deno: [1, 0, 0],
137
+ node: [4, 0, 0],
138
+ },
139
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#browser_compatibility
140
+ [Feature.ObjectAssign]: {
141
+ es: [6, 0, 0],
142
+ chrome: [45, 0, 0],
143
+ edge: [12, 0, 0],
144
+ firefox: [34, 0, 0],
145
+ opera: [32, 0, 0],
146
+ safari: [9, 0, 0],
147
+ ios: [9, 0, 0],
148
+ samsung: [5, 0, 0],
149
+ deno: [1, 0, 0],
150
+ node: [4, 0, 0],
151
+ },
152
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#browser_compatibility
153
+ [Feature.Promise]: {
154
+ es: [6, 0, 0],
155
+ chrome: [32, 0, 0],
156
+ edge: [12, 0, 0],
157
+ firefox: [29, 0, 0],
158
+ opera: [19, 0, 0],
159
+ safari: [8, 0, 0],
160
+ ios: [8, 0, 0],
161
+ samsung: [2, 0, 0],
162
+ deno: [1, 0, 0],
163
+ node: [0, 12, 0],
164
+ },
165
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#browser_compatibility
166
+ [Feature.Set]: {
167
+ es: [6, 0, 0],
168
+ chrome: [38, 0, 0],
169
+ edge: [12, 0, 0],
170
+ firefox: [13, 0, 0],
171
+ opera: [25, 0, 0],
172
+ safari: [8, 0, 0],
173
+ ios: [8, 0, 0],
174
+ samsung: [3, 0, 0],
175
+ deno: [1, 0, 0],
176
+ node: [0, 12, 0],
177
+ },
178
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator#browser_compatibility
179
+ [Feature.SymbolIterator]: {
180
+ es: [6, 0, 0],
181
+ chrome: [43, 0, 0],
182
+ edge: [12, 0, 0],
183
+ firefox: [36, 0, 0],
184
+ opera: [30, 0, 0],
185
+ safari: [10, 0, 0],
186
+ ios: [10, 0, 0],
187
+ samsung: [4, 0, 0],
188
+ deno: [1, 0, 0],
189
+ node: [0, 12, 0],
190
+ },
191
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#browser_compatibility
192
+ [Feature.TypedArray]: {
193
+ es: [6, 0, 0],
194
+ chrome: [7, 0, 0],
195
+ edge: [12, 0, 0],
196
+ firefox: [4, 0, 0],
197
+ opera: [11, 6, 0],
198
+ safari: [5, 1, 0],
199
+ ios: [4, 2, 0],
200
+ samsung: [1, 0, 0],
201
+ deno: [1, 0, 0],
202
+ node: [0, 10, 0],
203
+ },
204
+ };
205
+
206
+ const TARGET_REGEX = /^(es|chrome|edge|safari|firefox|opera|ios|samsung|deno|node)([0-9]+(\.[0-9]+(\.[0-9]+)?)?)$/i;
207
+
208
+ export type Target = [platform: Platform, version: Version];
209
+
210
+ function parseTarget(target: string): Target {
211
+ const result = TARGET_REGEX.exec(target);
212
+ assert(result, `Invalid target "${target}"`);
213
+ const [, platform, version] = result;
214
+ const [major, minor = '0', patch = '0'] = version.split('.');
215
+ return [platform as Platform, [Number(major), Number(minor), Number(patch)]];
216
+ }
217
+
218
+ function getTargetVersions(targets: string | string[]): Target[] {
219
+ if (Array.isArray(targets)) {
220
+ const versions: Target[] = [];
221
+ for (const target of targets) {
222
+ versions.push(parseTarget(target));
223
+ }
224
+ return versions;
225
+ }
226
+ return [parseTarget(targets)];
227
+ }
228
+
229
+ export function parseTargets(targets: string | string[]): Set<Feature> {
230
+ const parsed = getTargetVersions(targets);
231
+ const flags = new Set<Feature>();
232
+
233
+ for (const key in VERSION_TABLE) {
234
+ const base = VERSION_TABLE[key as unknown as Feature];
235
+ let flag = true;
236
+ for (const [platform, version] of parsed) {
237
+ const baseVersion = base[platform];
238
+ flag = flag && !!baseVersion && (compareVersion(baseVersion, version) <= 0);
239
+ }
240
+ if (flag) {
241
+ flags.add(Number(key) as unknown as Feature);
242
+ }
243
+ }
244
+
245
+ return flags;
246
+ }
package/src/index.ts CHANGED
@@ -1,14 +1,16 @@
1
1
  /* eslint-disable no-await-in-loop */
2
2
  import { isPrimitive } from './checks';
3
- import serializePrimitive from './serialize-primitive';
3
+ import { Feature } from './compat';
4
4
  import {
5
5
  createRef,
6
6
  createSerializationContext,
7
7
  generateTreeAsync,
8
8
  generateTreeSync,
9
9
  getRefParam,
10
+ Options,
10
11
  resolvePatches,
11
12
  SerializationContext,
13
+ serializePrimitive,
12
14
  serializeTree,
13
15
  } from './tree';
14
16
  import {
@@ -30,24 +32,35 @@ export {
30
32
  ErrorValue,
31
33
  };
32
34
 
33
- function finalize<T extends ServerValue | AsyncServerValue>(
35
+ function finalize<T extends NonPrimitiveServerValue<ServerValue | AsyncServerValue>>(
34
36
  ctx: SerializationContext,
35
- source: NonPrimitiveServerValue<T>,
37
+ source: T,
36
38
  result: string,
37
39
  ) {
38
40
  // Shared references detected
39
41
  if (ctx.vars.length) {
40
- // Get (or create) a ref from the source
41
- const index = getRefParam(ctx, createRef(ctx, source));
42
42
  const patches = resolvePatches(ctx);
43
- const params = ctx.vars.length > 1
44
- ? `(${ctx.vars.join(',')})`
43
+ let body = result;
44
+ if (patches) {
45
+ // Get (or create) a ref from the source
46
+ const index = getRefParam(ctx, createRef(ctx, source));
47
+ if (result.startsWith(`${index}=`)) {
48
+ body = `${result},${patches}${index}`;
49
+ } else {
50
+ body = `${index}=${result},${patches}${index}`;
51
+ }
52
+ }
53
+ let params = ctx.vars.length > 1
54
+ ? ctx.vars.join(',')
45
55
  : ctx.vars[0];
46
56
  // Source is probably already assigned
47
- if (result.startsWith(`${index}=`)) {
48
- return `(${params}=>(${result},${patches}${index}))()`;
57
+ if (ctx.features.has(Feature.ArrowFunction)) {
58
+ params = ctx.vars.length > 1 || ctx.vars.length === 0
59
+ ? `(${params})`
60
+ : params;
61
+ return `(${params}=>(${body}))()`;
49
62
  }
50
- return `(${params}=>(${index}=${result},${patches}${index}))()`;
63
+ return `(function(${params}){return ${body}})()`;
51
64
  }
52
65
  if (source.constructor === Object) {
53
66
  return `(${result})`;
@@ -55,21 +68,27 @@ function finalize<T extends ServerValue | AsyncServerValue>(
55
68
  return result;
56
69
  }
57
70
 
58
- export function serialize(source: ServerValue) {
71
+ export function serialize<T extends ServerValue>(
72
+ source: T,
73
+ options?: Partial<Options>,
74
+ ) {
75
+ const ctx = createSerializationContext(options);
59
76
  if (isPrimitive(source)) {
60
- return serializePrimitive(source);
77
+ return serializePrimitive(ctx, source);
61
78
  }
62
- const ctx = createSerializationContext();
63
79
  const tree = generateTreeSync(ctx, source);
64
80
  const result = serializeTree(ctx, tree);
65
81
  return finalize(ctx, source, result);
66
82
  }
67
83
 
68
- export async function serializeAsync(source: AsyncServerValue) {
84
+ export async function serializeAsync<T extends AsyncServerValue>(
85
+ source: T,
86
+ options?: Partial<Options>,
87
+ ) {
88
+ const ctx = createSerializationContext(options);
69
89
  if (isPrimitive(source)) {
70
- return serializePrimitive(source);
90
+ return serializePrimitive(ctx, source);
71
91
  }
72
- const ctx = createSerializationContext();
73
92
  const tree = await generateTreeAsync(ctx, source);
74
93
  const result = serializeTree(ctx, tree);
75
94
  return finalize(ctx, source, result);