Skip to content

Commit 9ab1da3

Browse files
authored
Merge pull request #69 from lxsmnsyc/feat-sequence
feat: `Sequence`
2 parents daedcfc + 1813185 commit 9ab1da3

File tree

15 files changed

+275
-107
lines changed

15 files changed

+275
-107
lines changed

.changeset/sour-frogs-rush.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"seroval": minor
3+
---
4+
5+
feat: sequence node

packages/seroval/src/core/base-primitives.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import type {
2929
SerovalPluginNode,
3030
SerovalReferenceNode,
3131
SerovalRegExpNode,
32+
SerovalSequenceNode,
3233
SerovalSetNode,
3334
SerovalStreamConstructorNode,
3435
SerovalStreamNextNode,
@@ -394,7 +395,7 @@ export function createSetNode(
394395

395396
export function createIteratorFactoryInstanceNode(
396397
factory: SerovalNodeWithID,
397-
items: SerovalNode,
398+
items: SerovalNodeWithID,
398399
): SerovalIteratorFactoryInstanceNode {
399400
return createSerovalNode(
400401
SerovalNodeType.IteratorFactoryInstance,
@@ -414,7 +415,7 @@ export function createIteratorFactoryInstanceNode(
414415

415416
export function createAsyncIteratorFactoryInstanceNode(
416417
factory: SerovalNodeWithID,
417-
items: SerovalNode,
418+
items: SerovalNodeWithID,
418419
): SerovalAsyncIteratorFactoryInstanceNode {
419420
return createSerovalNode(
420421
SerovalNodeType.AsyncIteratorFactoryInstance,
@@ -512,3 +513,25 @@ export function createStreamReturnNode(
512513
NIL,
513514
);
514515
}
516+
517+
export function createSequenceNode(
518+
id: number,
519+
sequence: SerovalNode[],
520+
throwAt: number,
521+
doneAt: number,
522+
): SerovalSequenceNode {
523+
return createSerovalNode(
524+
SerovalNodeType.Sequence,
525+
id,
526+
throwAt,
527+
NIL,
528+
NIL,
529+
NIL,
530+
NIL,
531+
sequence,
532+
NIL,
533+
NIL,
534+
NIL,
535+
doneAt,
536+
);
537+
}

packages/seroval/src/core/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export const enum SerovalNodeType {
6161
StreamNext = 32,
6262
StreamThrow = 33,
6363
StreamReturn = 34,
64+
Sequence = 35,
6465
}
6566

6667
export const enum SerovalObjectFlags {

packages/seroval/src/core/constructors.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Sequence } from './sequence';
12
import type { Stream } from './stream';
23

34
type SpecialPromise = Promise<unknown> & { s?: 1 | 2; v?: unknown };
@@ -130,12 +131,6 @@ export const STREAM_CONSTRUCTOR = () => {
130131
export const SERIALIZED_STREAM_CONSTRUCTOR =
131132
/* @__PURE__ */ STREAM_CONSTRUCTOR.toString();
132133

133-
export interface Sequence {
134-
v: unknown[];
135-
t: number;
136-
d: number;
137-
}
138-
139134
export const ITERATOR_CONSTRUCTOR =
140135
(symbol: symbol) => (sequence: Sequence) => () => {
141136
let index = 0;

packages/seroval/src/core/context/async-parser.ts

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
createNumberNode,
1313
createPluginNode,
1414
createRegExpNode,
15+
createSequenceNode,
1516
createSetNode,
1617
createStreamConstructorNode,
1718
createStreamNextNode,
@@ -27,6 +28,11 @@ import { FALSE_NODE, NULL_NODE, TRUE_NODE, UNDEFINED_NODE } from '../literals';
2728
import { createSerovalNode } from '../node';
2829
import { OpaqueReference } from '../opaque-reference';
2930
import type { SerovalMode } from '../plugin';
31+
import {
32+
createSequenceFromIterable,
33+
isSequence,
34+
type Sequence,
35+
} from '../sequence';
3036
import { SpecialReference } from '../special-reference';
3137
import type { Stream } from '../stream';
3238
import { createStreamFromAsyncIterable, isStream } from '../stream';
@@ -46,18 +52,19 @@ import type {
4652
SerovalErrorNode,
4753
SerovalMapNode,
4854
SerovalNode,
55+
SerovalNodeWithID,
4956
SerovalNullConstructorNode,
5057
SerovalObjectNode,
5158
SerovalObjectRecordKey,
5259
SerovalObjectRecordNode,
5360
SerovalPluginNode,
5461
SerovalPromiseNode,
62+
SerovalSequenceNode,
5563
SerovalSetNode,
5664
SerovalStreamConstructorNode,
5765
SerovalTypedArrayNode,
5866
} from '../types';
5967
import { getErrorOptions } from '../utils/error';
60-
import { iteratorToSequence } from '../utils/iterator-to-sequence';
6168
import promiseToResult from '../utils/promise-to-result';
6269
import type {
6370
BigIntTypedArrayValue,
@@ -155,11 +162,13 @@ async function parseProperties(
155162
valueNodes.push(
156163
createIteratorFactoryInstanceNode(
157164
parseIteratorFactory(ctx.base),
158-
await parseAsync(
165+
(await parseAsync(
159166
ctx,
160167
depth,
161-
iteratorToSequence(properties as unknown as Iterable<unknown>),
162-
),
168+
createSequenceFromIterable(
169+
properties as unknown as Iterable<unknown>,
170+
),
171+
)) as SerovalNodeWithID,
163172
),
164173
);
165174
}
@@ -168,13 +177,13 @@ async function parseProperties(
168177
valueNodes.push(
169178
createAsyncIteratorFactoryInstanceNode(
170179
parseAsyncIteratorFactory(ctx.base),
171-
await parseAsync(
180+
(await parseAsync(
172181
ctx,
173182
depth,
174183
createStreamFromAsyncIterable(
175184
properties as unknown as AsyncIterable<unknown>,
176185
),
177-
),
186+
)) as SerovalNodeWithID,
178187
),
179188
);
180189
}
@@ -435,6 +444,19 @@ async function parseStream(
435444
);
436445
}
437446

447+
async function parseSequence(
448+
ctx: AsyncParserContext,
449+
depth: number,
450+
id: number,
451+
current: Sequence,
452+
): Promise<SerovalSequenceNode> {
453+
const nodes: SerovalNode[] = [];
454+
for (let i = 0, len = current.v.length; i < len; i++) {
455+
nodes[i] = await parseAsync(ctx, depth, current.v[i]);
456+
}
457+
return createSequenceNode(id, nodes, current.t, current.d);
458+
}
459+
438460
export async function parseObjectAsync(
439461
ctx: AsyncParserContext,
440462
depth: number,
@@ -447,6 +469,9 @@ export async function parseObjectAsync(
447469
if (isStream(current)) {
448470
return parseStream(ctx, depth, id, current);
449471
}
472+
if (isSequence(current)) {
473+
return parseSequence(ctx, depth, id, current);
474+
}
450475
const currentClass = current.constructor;
451476
if (currentClass === OpaqueReference) {
452477
return parseAsync(

packages/seroval/src/core/context/deserializer.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
import type { PluginAccessOptions } from '../plugin';
2424
import { SerovalMode } from '../plugin';
2525
import { getReference } from '../reference';
26+
import { createSequence, type Sequence, sequenceToIterator } from '../sequence';
2627
import type { Stream } from '../stream';
2728
import { createStream, isStream, streamToAsyncIterable } from '../stream';
2829
import { deserializeString } from '../string';
@@ -57,15 +58,14 @@ import type {
5758
SerovalPromiseResolveNode,
5859
SerovalReferenceNode,
5960
SerovalRegExpNode,
61+
SerovalSequenceNode,
6062
SerovalSetNode,
6163
SerovalStreamConstructorNode,
6264
SerovalStreamNextNode,
6365
SerovalStreamReturnNode,
6466
SerovalStreamThrowNode,
6567
SerovalTypedArrayNode,
6668
} from '../types';
67-
import type { Sequence } from '../utils/iterator-to-sequence';
68-
import { sequenceToIterator } from '../utils/iterator-to-sequence';
6969
import type {
7070
BigIntTypedArrayValue,
7171
TypedArrayValue,
@@ -713,6 +713,22 @@ function deserializeAsyncIteratorFactory(
713713
return NIL;
714714
}
715715

716+
function deserializeSequence(
717+
ctx: DeserializerContext,
718+
depth: number,
719+
node: SerovalSequenceNode,
720+
): Sequence {
721+
const result = assignIndexedValue(
722+
ctx,
723+
node.i,
724+
createSequence([], node.s, node.l),
725+
);
726+
for (let i = 0, len = node.a.length; i < len; i++) {
727+
result.v[i] = deserialize(ctx, depth, node.a[i]);
728+
}
729+
return result;
730+
}
731+
716732
function deserialize(
717733
ctx: DeserializerContext,
718734
depth: number,
@@ -793,6 +809,8 @@ function deserialize(
793809
case SerovalNodeType.AsyncIteratorFactory:
794810
return deserializeAsyncIteratorFactory(ctx, depth, node);
795811
// case SerovalNodeType.SpecialReference:
812+
case SerovalNodeType.Sequence:
813+
return deserializeSequence(ctx, depth, node);
796814
default:
797815
throw new SerovalUnsupportedNodeError(node);
798816
}

packages/seroval/src/core/context/serializer.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import type {
5050
SerovalPromiseResolveNode,
5151
SerovalReferenceNode,
5252
SerovalRegExpNode,
53+
SerovalSequenceNode,
5354
SerovalSetNode,
5455
SerovalStreamConstructorNode,
5556
SerovalStreamNextNode,
@@ -484,6 +485,15 @@ function createObjectAssign(
484485
createAssignment(ctx.base, getRefParam(ctx, ref) + '.' + key, value);
485486
}
486487

488+
function createSequenceAssign(
489+
ctx: SerializerContext,
490+
ref: number,
491+
index: number | string,
492+
value: string,
493+
): void {
494+
createAssignment(ctx.base, getRefParam(ctx, ref) + '.v[' + index + ']', value);
495+
}
496+
487497
/**
488498
* Checks if the value is in the stack. Stack here is a reference
489499
* structure to know if a object is to be accessed in a TDZ.
@@ -1239,6 +1249,48 @@ function serializeStreamReturn(
12391249
return getRefParam(ctx, node.i) + '.return(' + serialize(ctx, node.f) + ')';
12401250
}
12411251

1252+
function serializeSequenceItem(
1253+
ctx: SerializerContext,
1254+
id: number,
1255+
index: number,
1256+
item: SerovalNode,
1257+
): string {
1258+
const base = ctx.base;
1259+
if (isIndexedValueInStack(base, item)) {
1260+
markSerializerRef(base, id);
1261+
createSequenceAssign(
1262+
ctx,
1263+
id,
1264+
index,
1265+
getRefParam(ctx, (item as SerovalIndexedValueNode).i),
1266+
);
1267+
return '';
1268+
}
1269+
return serialize(ctx, item);
1270+
}
1271+
1272+
function serializeSequence(
1273+
ctx: SerializerContext,
1274+
node: SerovalSequenceNode,
1275+
): string {
1276+
const items = node.a;
1277+
const size = items.length;
1278+
const id = node.i;
1279+
if (size > 0) {
1280+
ctx.base.stack.push(id);
1281+
let result = serializeSequenceItem(ctx, id, 0, items[0]);
1282+
for (let i = 1, item = result; i < size; i++) {
1283+
item = serializeSequenceItem(ctx, id, i, items[i]);
1284+
result += (item && result && ',') + item;
1285+
}
1286+
ctx.base.stack.pop();
1287+
if (result) {
1288+
return '{__SEROVAL_SEQUENCE__:!0,v:[' + result + '],t:' + node.s + ',d:' + node.l + '}';
1289+
}
1290+
}
1291+
return '{__SEROVAL_SEQUENCE__:!0,v:[],t:-1,d:0}';
1292+
}
1293+
12421294
function serializeAssignable(
12431295
ctx: SerializerContext,
12441296
node: SerovalNode,
@@ -1283,6 +1335,8 @@ function serializeAssignable(
12831335
return serializePlugin(ctx, node);
12841336
case SerovalNodeType.SpecialReference:
12851337
return SPECIAL_REF_STRING[node.s];
1338+
case SerovalNodeType.Sequence:
1339+
return serializeSequence(ctx, node);
12861340
default:
12871341
throw new SerovalUnsupportedNodeError(node);
12881342
}

0 commit comments

Comments
 (0)