seroval 1.2.1 → 1.3.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.
Files changed (50) hide show
  1. package/LICENSE +1 -1
  2. package/dist/cjs/development/index.cjs +270 -383
  3. package/dist/cjs/development/index.cjs.map +3 -3
  4. package/dist/cjs/production/index.cjs +6 -6
  5. package/dist/esm/development/index.mjs +270 -383
  6. package/dist/esm/development/index.mjs.map +3 -3
  7. package/dist/esm/production/index.mjs +6 -6
  8. package/dist/types/core/base-primitives.d.ts +1 -2
  9. package/dist/types/core/base-primitives.d.ts.map +1 -1
  10. package/dist/types/core/compat.d.ts +2 -3
  11. package/dist/types/core/compat.d.ts.map +1 -1
  12. package/dist/types/core/constants.d.ts +3 -6
  13. package/dist/types/core/constants.d.ts.map +1 -1
  14. package/dist/types/core/context/deserializer.d.ts +0 -3
  15. package/dist/types/core/context/deserializer.d.ts.map +1 -1
  16. package/dist/types/core/context/parser/async.d.ts +1 -2
  17. package/dist/types/core/context/parser/async.d.ts.map +1 -1
  18. package/dist/types/core/context/parser/stream.d.ts +8 -8
  19. package/dist/types/core/context/parser/stream.d.ts.map +1 -1
  20. package/dist/types/core/context/parser/sync.d.ts +2 -3
  21. package/dist/types/core/context/parser/sync.d.ts.map +1 -1
  22. package/dist/types/core/context/parser.d.ts +3 -3
  23. package/dist/types/core/context/parser.d.ts.map +1 -1
  24. package/dist/types/core/context/serializer.d.ts +1 -5
  25. package/dist/types/core/context/serializer.d.ts.map +1 -1
  26. package/dist/types/core/function-string.d.ts +3 -0
  27. package/dist/types/core/function-string.d.ts.map +1 -0
  28. package/dist/types/core/special-reference.d.ts +4 -5
  29. package/dist/types/core/special-reference.d.ts.map +1 -1
  30. package/dist/types/core/tree/serializer.d.ts +1 -2
  31. package/dist/types/core/tree/serializer.d.ts.map +1 -1
  32. package/dist/types/core/types.d.ts +5 -19
  33. package/dist/types/core/types.d.ts.map +1 -1
  34. package/package.json +8 -8
  35. package/src/core/base-primitives.ts +2 -22
  36. package/src/core/compat.ts +6 -2
  37. package/src/core/constants.ts +2 -5
  38. package/src/core/context/deserializer.ts +2 -35
  39. package/src/core/context/parser/async.ts +54 -83
  40. package/src/core/context/parser/stream.ts +64 -111
  41. package/src/core/context/parser/sync.ts +53 -83
  42. package/src/core/context/parser.ts +9 -24
  43. package/src/core/context/serializer.ts +24 -131
  44. package/src/core/function-string.ts +31 -0
  45. package/src/core/special-reference.ts +96 -8
  46. package/src/core/tree/serializer.ts +0 -7
  47. package/src/core/types.ts +5 -27
  48. package/dist/types/core/abort-signal.d.ts +0 -2
  49. package/dist/types/core/abort-signal.d.ts.map +0 -1
  50. package/src/core/abort-signal.ts +0 -19
@@ -16,8 +16,6 @@ import type { Stream } from '../../stream';
16
16
  import { createStreamFromAsyncIterable } from '../../stream';
17
17
  import { serializeString } from '../../string';
18
18
  import type {
19
- SerovalAbortSignalConstructorNode,
20
- SerovalAbortSignalSyncNode,
21
19
  SerovalNode,
22
20
  SerovalObjectRecordKey,
23
21
  SerovalObjectRecordNode,
@@ -73,7 +71,7 @@ export default abstract class BaseStreamParserContext extends BaseSyncParserCont
73
71
  }
74
72
  }
75
73
 
76
- private onParse(node: SerovalNode): void {
74
+ onParse(node: SerovalNode): void {
77
75
  if (this.initial) {
78
76
  this.buffer.push(node);
79
77
  } else {
@@ -81,7 +79,7 @@ export default abstract class BaseStreamParserContext extends BaseSyncParserCont
81
79
  }
82
80
  }
83
81
 
84
- private onError(error: unknown): void {
82
+ onError(error: unknown): void {
85
83
  if (this.onErrorCallback) {
86
84
  this.onErrorCallback(error);
87
85
  } else {
@@ -95,11 +93,11 @@ export default abstract class BaseStreamParserContext extends BaseSyncParserCont
95
93
  }
96
94
  }
97
95
 
98
- private pushPendingState(): void {
96
+ pushPendingState(): void {
99
97
  this.pending++;
100
98
  }
101
99
 
102
- private popPendingState(): void {
100
+ popPendingState(): void {
103
101
  if (--this.pending <= 0) {
104
102
  this.onDone();
105
103
  }
@@ -113,7 +111,7 @@ export default abstract class BaseStreamParserContext extends BaseSyncParserCont
113
111
  const valueNodes: SerovalNode[] = [];
114
112
  for (let i = 0, len = entries.length; i < len; i++) {
115
113
  keyNodes.push(serializeString(entries[i][0]));
116
- valueNodes.push(this.parse(entries[i][1]));
114
+ valueNodes.push(this.parseTop(entries[i][1]));
117
115
  }
118
116
  // Check special properties, symbols in this case
119
117
  let symbol = Symbol.iterator;
@@ -122,7 +120,7 @@ export default abstract class BaseStreamParserContext extends BaseSyncParserCont
122
120
  valueNodes.push(
123
121
  createIteratorFactoryInstanceNode(
124
122
  this.parseIteratorFactory(),
125
- this.parse(
123
+ this.parseTop(
126
124
  iteratorToSequence(properties as unknown as Iterable<unknown>),
127
125
  ),
128
126
  ),
@@ -134,7 +132,7 @@ export default abstract class BaseStreamParserContext extends BaseSyncParserCont
134
132
  valueNodes.push(
135
133
  createAsyncIteratorFactoryInstanceNode(
136
134
  this.parseAsyncIteratorFactory(),
137
- this.parse(
135
+ this.parseTop(
138
136
  createStreamFromAsyncIterable(
139
137
  properties as unknown as AsyncIterable<unknown>,
140
138
  ),
@@ -159,66 +157,68 @@ export default abstract class BaseStreamParserContext extends BaseSyncParserCont
159
157
  };
160
158
  }
161
159
 
160
+ protected handlePromiseSuccess(id: number, data: unknown): void {
161
+ const parsed = this.parseWithError(data);
162
+ if (parsed) {
163
+ this.onParse(
164
+ createSerovalNode(
165
+ SerovalNodeType.PromiseSuccess,
166
+ id,
167
+ NIL,
168
+ NIL,
169
+ NIL,
170
+ NIL,
171
+ NIL,
172
+ NIL,
173
+ [this.parseSpecialReference(SpecialReference.PromiseSuccess), parsed],
174
+ NIL,
175
+ NIL,
176
+ NIL,
177
+ ),
178
+ );
179
+ }
180
+ this.popPendingState();
181
+ }
182
+
183
+ protected handlePromiseFailure(id: number, data: unknown): void {
184
+ if (this.alive) {
185
+ const parsed = this.parseWithError(data);
186
+ if (parsed) {
187
+ this.onParse(
188
+ createSerovalNode(
189
+ SerovalNodeType.PromiseFailure,
190
+ id,
191
+ NIL,
192
+ NIL,
193
+ NIL,
194
+ NIL,
195
+ NIL,
196
+ NIL,
197
+ [
198
+ this.parseSpecialReference(SpecialReference.PromiseFailure),
199
+ parsed,
200
+ ],
201
+ NIL,
202
+ NIL,
203
+ NIL,
204
+ ),
205
+ );
206
+ }
207
+ }
208
+ this.popPendingState();
209
+ }
210
+
162
211
  protected parsePromise(
163
212
  id: number,
164
213
  current: Promise<unknown>,
165
214
  ): SerovalPromiseConstructorNode {
215
+ const resolver = this.createIndex({});
166
216
  current.then(
167
- data => {
168
- const parsed = this.parseWithError(data);
169
- if (parsed) {
170
- this.onParse(
171
- createSerovalNode(
172
- SerovalNodeType.PromiseResolve,
173
- id,
174
- NIL,
175
- NIL,
176
- NIL,
177
- NIL,
178
- NIL,
179
- NIL,
180
- [
181
- this.parseSpecialReference(SpecialReference.PromiseResolve),
182
- parsed,
183
- ],
184
- NIL,
185
- NIL,
186
- NIL,
187
- ),
188
- );
189
- }
190
- this.popPendingState();
191
- },
192
- data => {
193
- if (this.alive) {
194
- const parsed = this.parseWithError(data);
195
- if (parsed) {
196
- this.onParse(
197
- createSerovalNode(
198
- SerovalNodeType.PromiseReject,
199
- id,
200
- NIL,
201
- NIL,
202
- NIL,
203
- NIL,
204
- NIL,
205
- NIL,
206
- [
207
- this.parseSpecialReference(SpecialReference.PromiseReject),
208
- parsed,
209
- ],
210
- NIL,
211
- NIL,
212
- NIL,
213
- ),
214
- );
215
- }
216
- }
217
- this.popPendingState();
218
- },
217
+ this.handlePromiseSuccess.bind(this, resolver),
218
+ this.handlePromiseFailure.bind(this, resolver),
219
219
  );
220
220
  this.pushPendingState();
221
- return this.createPromiseConstructorNode(id);
221
+ return this.createPromiseConstructorNode(id, resolver);
222
222
  }
223
223
 
224
224
  protected parsePlugin(
@@ -281,56 +281,9 @@ export default abstract class BaseStreamParserContext extends BaseSyncParserCont
281
281
  return result;
282
282
  }
283
283
 
284
- protected handleAbortSignal(id: number, current: AbortSignal): void {
285
- if (this.alive) {
286
- const parsed = this.parseWithError(current.reason);
287
- if (parsed) {
288
- this.onParse(
289
- createSerovalNode(
290
- SerovalNodeType.AbortSignalAbort,
291
- id,
292
- NIL,
293
- NIL,
294
- NIL,
295
- NIL,
296
- NIL,
297
- NIL,
298
- [
299
- this.parseSpecialReference(SpecialReference.AbortSignalAbort),
300
- parsed,
301
- ],
302
- NIL,
303
- NIL,
304
- NIL,
305
- ),
306
- );
307
- }
308
- }
309
- this.popPendingState();
310
- }
311
-
312
- protected parseAbortSignal(
313
- id: number,
314
- current: AbortSignal,
315
- ): SerovalAbortSignalConstructorNode | SerovalAbortSignalSyncNode {
316
- if (current.aborted) {
317
- return this.parseAbortSignalSync(id, current);
318
- }
319
-
320
- this.pushPendingState();
321
-
322
- current.addEventListener(
323
- 'abort',
324
- this.handleAbortSignal.bind(this, id, current),
325
- { once: true },
326
- );
327
-
328
- return this.createAbortSignalConstructorNode(id);
329
- }
330
-
331
- private parseWithError<T>(current: T): SerovalNode | undefined {
284
+ parseWithError<T>(current: T): SerovalNode | undefined {
332
285
  try {
333
- return this.parse(current);
286
+ return this.parseTop(current);
334
287
  } catch (err) {
335
288
  this.onError(err);
336
289
  return NIL;
@@ -19,7 +19,7 @@ import {
19
19
  createTypedArrayNode,
20
20
  } from '../../base-primitives';
21
21
  import { Feature } from '../../compat';
22
- import { NIL, SerovalNodeType } from '../../constants';
22
+ import { NIL } from '../../constants';
23
23
  import { SerovalParserError, SerovalUnsupportedTypeError } from '../../errors';
24
24
  import {
25
25
  FALSE_NODE,
@@ -27,15 +27,12 @@ import {
27
27
  TRUE_NODE,
28
28
  UNDEFINED_NODE,
29
29
  } from '../../literals';
30
- import { createSerovalNode } from '../../node';
31
30
  import { OpaqueReference } from '../../opaque-reference';
32
31
  import { SpecialReference } from '../../special-reference';
33
32
  import type { Stream } from '../../stream';
34
33
  import { createStream, isStream } from '../../stream';
35
34
  import { serializeString } from '../../string';
36
35
  import type {
37
- SerovalAbortSignalConstructorNode,
38
- SerovalAbortSignalSyncNode,
39
36
  SerovalAggregateErrorNode,
40
37
  SerovalArrayNode,
41
38
  SerovalBigIntTypedArrayNode,
@@ -71,7 +68,7 @@ export default abstract class BaseSyncParserContext extends BaseParserContext {
71
68
  const nodes = [];
72
69
  for (let i = 0, len = current.length; i < len; i++) {
73
70
  if (i in current) {
74
- nodes[i] = this.parse(current[i]);
71
+ nodes[i] = this.parseTop(current[i]);
75
72
  }
76
73
  }
77
74
  return nodes;
@@ -89,7 +86,7 @@ export default abstract class BaseSyncParserContext extends BaseParserContext {
89
86
  const valueNodes: SerovalNode[] = [];
90
87
  for (let i = 0, len = entries.length; i < len; i++) {
91
88
  keyNodes.push(serializeString(entries[i][0]));
92
- valueNodes.push(this.parse(entries[i][1]));
89
+ valueNodes.push(this.parseTop(entries[i][1]));
93
90
  }
94
91
  // Check special properties, symbols in this case
95
92
  let symbol = Symbol.iterator;
@@ -98,7 +95,7 @@ export default abstract class BaseSyncParserContext extends BaseParserContext {
98
95
  valueNodes.push(
99
96
  createIteratorFactoryInstanceNode(
100
97
  this.parseIteratorFactory(),
101
- this.parse(
98
+ this.parseTop(
102
99
  iteratorToSequence(properties as unknown as Iterable<unknown>),
103
100
  ),
104
101
  ),
@@ -110,7 +107,7 @@ export default abstract class BaseSyncParserContext extends BaseParserContext {
110
107
  valueNodes.push(
111
108
  createAsyncIteratorFactoryInstanceNode(
112
109
  this.parseAsyncIteratorFactory(),
113
- this.parse(createStream()),
110
+ this.parseTop(createStream()),
114
111
  ),
115
112
  );
116
113
  }
@@ -145,25 +142,29 @@ export default abstract class BaseSyncParserContext extends BaseParserContext {
145
142
  }
146
143
 
147
144
  protected parseBoxed(id: number, current: object): SerovalBoxedNode {
148
- return createBoxedNode(id, this.parse(current.valueOf()));
145
+ return createBoxedNode(id, this.parseTop(current.valueOf()));
149
146
  }
150
147
 
151
148
  protected parseTypedArray(
152
149
  id: number,
153
150
  current: TypedArrayValue,
154
151
  ): SerovalTypedArrayNode {
155
- return createTypedArrayNode(id, current, this.parse(current.buffer));
152
+ return createTypedArrayNode(id, current, this.parseTop(current.buffer));
156
153
  }
157
154
 
158
155
  protected parseBigIntTypedArray(
159
156
  id: number,
160
157
  current: BigIntTypedArrayValue,
161
158
  ): SerovalBigIntTypedArrayNode {
162
- return createBigIntTypedArrayNode(id, current, this.parse(current.buffer));
159
+ return createBigIntTypedArrayNode(
160
+ id,
161
+ current,
162
+ this.parseTop(current.buffer),
163
+ );
163
164
  }
164
165
 
165
166
  protected parseDataView(id: number, current: DataView): SerovalDataViewNode {
166
- return createDataViewNode(id, current, this.parse(current.buffer));
167
+ return createDataViewNode(id, current, this.parseTop(current.buffer));
167
168
  }
168
169
 
169
170
  protected parseError(id: number, current: Error): SerovalErrorNode {
@@ -194,8 +195,8 @@ export default abstract class BaseSyncParserContext extends BaseParserContext {
194
195
  const keyNodes: SerovalNode[] = [];
195
196
  const valueNodes: SerovalNode[] = [];
196
197
  for (const [key, value] of current.entries()) {
197
- keyNodes.push(this.parse(key));
198
- valueNodes.push(this.parse(value));
198
+ keyNodes.push(this.parseTop(key));
199
+ valueNodes.push(this.parseTop(value));
199
200
  }
200
201
  return this.createMapNode(id, keyNodes, valueNodes, current.size);
201
202
  }
@@ -203,7 +204,7 @@ export default abstract class BaseSyncParserContext extends BaseParserContext {
203
204
  protected parseSet(id: number, current: Set<unknown>): SerovalSetNode {
204
205
  const items: SerovalNode[] = [];
205
206
  for (const item of current.keys()) {
206
- items.push(this.parse(item));
207
+ items.push(this.parseTop(item));
207
208
  }
208
209
  return createSetNode(id, current.size, items);
209
210
  }
@@ -242,37 +243,7 @@ export default abstract class BaseSyncParserContext extends BaseParserContext {
242
243
  id: number,
243
244
  _current: Promise<unknown>,
244
245
  ): SerovalPromiseConstructorNode {
245
- return this.createPromiseConstructorNode(id);
246
- }
247
-
248
- protected parseAbortSignalSync(
249
- id: number,
250
- current: AbortSignal,
251
- ): SerovalAbortSignalSyncNode {
252
- return createSerovalNode(
253
- SerovalNodeType.AbortSignalSync,
254
- id,
255
- NIL,
256
- NIL,
257
- NIL,
258
- NIL,
259
- NIL,
260
- NIL,
261
- NIL,
262
- this.parse(current.reason),
263
- NIL,
264
- NIL,
265
- );
266
- }
267
-
268
- protected parseAbortSignal(
269
- id: number,
270
- current: AbortSignal,
271
- ): SerovalAbortSignalConstructorNode | SerovalAbortSignalSyncNode {
272
- if (current.aborted) {
273
- return this.parseAbortSignalSync(id, current);
274
- }
275
- return this.createAbortSignalConstructorNode(id);
246
+ return this.createPromiseConstructorNode(id, this.createIndex({}));
276
247
  }
277
248
 
278
249
  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: ehh
@@ -285,7 +256,7 @@ export default abstract class BaseSyncParserContext extends BaseParserContext {
285
256
  }
286
257
  const currentClass = current.constructor;
287
258
  if (currentClass === OpaqueReference) {
288
- return this.parse(
259
+ return this.parseTop(
289
260
  (current as OpaqueReference<unknown, unknown>).replacement,
290
261
  );
291
262
  }
@@ -349,13 +320,6 @@ export default abstract class BaseSyncParserContext extends BaseParserContext {
349
320
  return this.parsePromise(id, current as unknown as Promise<unknown>);
350
321
  }
351
322
  const currentFeatures = this.features;
352
- if (
353
- currentFeatures & Feature.AbortSignal &&
354
- typeof AbortSignal !== 'undefined' &&
355
- currentClass === AbortSignal
356
- ) {
357
- return this.parseAbortSignal(id, current as unknown as AbortSignal);
358
- }
359
323
  // BigInt Typed Arrays
360
324
  if (currentFeatures & Feature.BigIntTypedArray) {
361
325
  switch (currentClass) {
@@ -401,38 +365,44 @@ export default abstract class BaseSyncParserContext extends BaseParserContext {
401
365
  throw new SerovalUnsupportedTypeError(current);
402
366
  }
403
367
 
404
- parse<T>(current: T): SerovalNode {
405
- try {
406
- switch (typeof current) {
407
- case 'boolean':
408
- return current ? TRUE_NODE : FALSE_NODE;
409
- case 'undefined':
410
- return UNDEFINED_NODE;
411
- case 'string':
412
- return createStringNode(current as string);
413
- case 'number':
414
- return createNumberNode(current as number);
415
- case 'bigint':
416
- return createBigIntNode(current as bigint);
417
- case 'object': {
418
- if (current) {
419
- const ref = this.getReference(current);
420
- return ref.type === ParserNodeType.Fresh
421
- ? this.parseObject(ref.value, current as object)
422
- : ref.value;
423
- }
424
- return NULL_NODE;
368
+ parseTop<T>(current: T): SerovalNode {
369
+ switch (typeof current) {
370
+ case 'boolean':
371
+ return current ? TRUE_NODE : FALSE_NODE;
372
+ case 'undefined':
373
+ return UNDEFINED_NODE;
374
+ case 'string':
375
+ return createStringNode(current as string);
376
+ case 'number':
377
+ return createNumberNode(current as number);
378
+ case 'bigint':
379
+ return createBigIntNode(current as bigint);
380
+ case 'object': {
381
+ if (current) {
382
+ const ref = this.getReference(current);
383
+ return ref.type === ParserNodeType.Fresh
384
+ ? this.parseObject(ref.value, current as object)
385
+ : ref.value;
425
386
  }
426
- case 'symbol':
427
- return this.parseWellKnownSymbol(current);
428
- case 'function': {
429
- return this.parseFunction(current);
430
- }
431
- default:
432
- throw new SerovalUnsupportedTypeError(current);
387
+ return NULL_NODE;
388
+ }
389
+ case 'symbol':
390
+ return this.parseWellKnownSymbol(current);
391
+ case 'function': {
392
+ return this.parseFunction(current);
433
393
  }
394
+ default:
395
+ throw new SerovalUnsupportedTypeError(current);
396
+ }
397
+ }
398
+
399
+ parse<T>(current: T): SerovalNode {
400
+ try {
401
+ return this.parseTop(current);
434
402
  } catch (error) {
435
- throw new SerovalParserError(error);
403
+ throw error instanceof SerovalParserError
404
+ ? error
405
+ : new SerovalParserError(error);
436
406
  }
437
407
  }
438
408
  }
@@ -17,7 +17,6 @@ import {
17
17
  SpecialReference,
18
18
  } from '../special-reference';
19
19
  import type {
20
- SerovalAbortSignalConstructorNode,
21
20
  SerovalAsyncIteratorFactoryNode,
22
21
  SerovalIndexedValueNode,
23
22
  SerovalIteratorFactoryNode,
@@ -87,6 +86,12 @@ export abstract class BaseParserContext implements PluginAccessOptions {
87
86
  return this.marked.has(id);
88
87
  }
89
88
 
89
+ protected createIndex<T>(current: T): number {
90
+ const id = this.refs.size;
91
+ this.refs.set(current, id);
92
+ return id;
93
+ }
94
+
90
95
  protected getIndexedValue<T>(current: T): FreshNode | IndexedNode {
91
96
  const registeredId = this.refs.get(current);
92
97
  if (registeredId != null) {
@@ -96,11 +101,9 @@ export abstract class BaseParserContext implements PluginAccessOptions {
96
101
  value: createIndexedValueNode(registeredId),
97
102
  };
98
103
  }
99
- const id = this.refs.size;
100
- this.refs.set(current, id);
101
104
  return {
102
105
  type: ParserNodeType.Fresh,
103
- value: id,
106
+ value: this.createIndex(current),
104
107
  };
105
108
  }
106
109
 
@@ -247,11 +250,12 @@ export abstract class BaseParserContext implements PluginAccessOptions {
247
250
 
248
251
  protected createPromiseConstructorNode(
249
252
  id: number,
253
+ resolver: number,
250
254
  ): SerovalPromiseConstructorNode {
251
255
  return createSerovalNode(
252
256
  SerovalNodeType.PromiseConstructor,
253
257
  id,
254
- NIL,
258
+ resolver,
255
259
  NIL,
256
260
  NIL,
257
261
  NIL,
@@ -263,23 +267,4 @@ export abstract class BaseParserContext implements PluginAccessOptions {
263
267
  NIL,
264
268
  );
265
269
  }
266
-
267
- protected createAbortSignalConstructorNode(
268
- id: number,
269
- ): SerovalAbortSignalConstructorNode {
270
- return createSerovalNode(
271
- SerovalNodeType.AbortSignalConstructor,
272
- id,
273
- NIL,
274
- NIL,
275
- NIL,
276
- NIL,
277
- NIL,
278
- NIL,
279
- NIL,
280
- this.parseSpecialReference(SpecialReference.AbortSignalConstructor),
281
- NIL,
282
- NIL,
283
- );
284
- }
285
270
  }