Skip to content

Commit

Permalink
Add cross-reference streaming serializer
Browse files Browse the repository at this point in the history
  • Loading branch information
lxsmnsyc committed Sep 8, 2023
1 parent 85f51dd commit dab182b
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 26 deletions.
72 changes: 54 additions & 18 deletions packages/seroval/src/core/cross/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import { Feature } from '../compat';
import {
CROSS_IIFE_ARGUMENTS,
CROSS_IIFE_PARAMS,
GLOBAL_CONTEXT_KEY,
GLOBAL_CONTEXT_PARAM,
ROOT_REFERENCE,
} from '../keys';
import type { SerovalNode } from '../types';
import parseAsync from './async';
import type {
CrossParserContextOptions, CrossSerializerContext,
CrossParserContextOptions,
CrossSerializerContext,
} from './context';
import {
createCrossParserContext,
createCrossSerializerContext,
createStreamingCrossParserContext,
} from './context';
import serializeTree, { getRefExpr, resolvePatches } from './serialize';
import crossSerializeTree, { getRefExpr, resolvePatches } from './serialize';
import crossParseStream from './stream';
import parseSync from './sync';

function finalize(
Expand All @@ -26,35 +29,35 @@ function finalize(
if (ctx.features & Feature.ArrowFunction) {
if (patches) {
if (id == null) {
const params = '(' + CROSS_IIFE_PARAMS + ',' + ROOT_REFERENCE + ')';
const params = '(' + GLOBAL_CONTEXT_PARAM + ',' + ROOT_REFERENCE + ')';
const body = ROOT_REFERENCE + '=' + result + ',' + patches + ROOT_REFERENCE;
return '(' + params + '=>(' + body + '))';
}
return '((' + CROSS_IIFE_PARAMS + ')=>(' + result + ',' + patches + getRefExpr(id) + '))' + CROSS_IIFE_ARGUMENTS;
return '((' + GLOBAL_CONTEXT_PARAM + ')=>(' + result + ',' + patches + getRefExpr(id) + '))(' + GLOBAL_CONTEXT_KEY + ')';
}
return '((' + CROSS_IIFE_PARAMS + ')=>' + result + ')' + CROSS_IIFE_ARGUMENTS;
return '((' + GLOBAL_CONTEXT_PARAM + ')=>' + result + ')(' + GLOBAL_CONTEXT_KEY + ')';
}
if (patches) {
if (id == null) {
const params = '(' + CROSS_IIFE_PARAMS + ',' + ROOT_REFERENCE + ')';
const params = '(' + GLOBAL_CONTEXT_PARAM + ',' + ROOT_REFERENCE + ')';
const body = ROOT_REFERENCE + '=' + result + ',' + patches + ROOT_REFERENCE;
return '(function' + params + '{return ' + body + '})';
return '(function' + params + '{return ' + body + '})(' + GLOBAL_CONTEXT_KEY + ')';
}
return '(function(' + CROSS_IIFE_PARAMS + '){return ' + result + ',' + patches + getRefExpr(id) + '})' + CROSS_IIFE_ARGUMENTS;
return '(function(' + GLOBAL_CONTEXT_PARAM + '){return ' + result + ',' + patches + getRefExpr(id) + '})(' + GLOBAL_CONTEXT_KEY + ')';
}
return '(function(' + CROSS_IIFE_PARAMS + '){return ' + result + '})' + CROSS_IIFE_ARGUMENTS;
return '(function(' + GLOBAL_CONTEXT_PARAM + '){return ' + result + '})(' + GLOBAL_CONTEXT_KEY + ')';
}

export function crossSerialize<T>(
source: T,
options?: Partial<CrossParserContextOptions>,
options?: CrossParserContextOptions,
): string {
const ctx = createCrossParserContext(options);
const tree = parseSync(ctx, source);
const serial = createCrossSerializerContext({
features: ctx.features,
});
const result = serializeTree(serial, tree);
const result = crossSerializeTree(serial, tree);
return finalize(
serial,
tree.i,
Expand All @@ -64,14 +67,14 @@ export function crossSerialize<T>(

export async function crossSerializeAsync<T>(
source: T,
options?: Partial<CrossParserContextOptions>,
options?: CrossParserContextOptions,
): Promise<string> {
const ctx = createCrossParserContext(options);
const tree = await parseAsync(ctx, source);
const serial = createCrossSerializerContext({
features: ctx.features,
});
const result = serializeTree(serial, tree);
const result = crossSerializeTree(serial, tree);
return finalize(
serial,
tree.i,
Expand All @@ -86,7 +89,7 @@ export interface SerovalCrossJSON {

export function toCrossJSON<T>(
source: T,
options?: Partial<CrossParserContextOptions>,
options?: CrossParserContextOptions,
): SerovalCrossJSON {
const ctx = createCrossParserContext(options);
return {
Expand All @@ -97,7 +100,7 @@ export function toCrossJSON<T>(

export async function toCrossJSONAsync<T>(
source: T,
options?: Partial<CrossParserContextOptions>,
options?: CrossParserContextOptions,
): Promise<SerovalCrossJSON> {
const ctx = createCrossParserContext(options);
return {
Expand All @@ -110,7 +113,7 @@ export function compileCrossJSON(source: SerovalCrossJSON): string {
const serial = createCrossSerializerContext({
features: source.f,
});
const result = serializeTree(serial, source.t);
const result = crossSerializeTree(serial, source.t);
return finalize(
serial,
source.t.i,
Expand All @@ -124,3 +127,36 @@ export function compileCrossJSON(source: SerovalCrossJSON): string {
// });
// return deserializeTree(serial, source.t) as T;
// }

export interface CrossSerializeStreamOptions extends CrossParserContextOptions {
onSerialize: (data: string) => void;
}

export function crossSerializeStream<T>(
source: T,
options: CrossSerializeStreamOptions,
): () => void {
const ctx = createStreamingCrossParserContext({
refs: options.refs,
disabledFeatures: options.disabledFeatures,
onParse(node) {
const serial = createCrossSerializerContext({
features: ctx.features,
});

options.onSerialize(
finalize(
serial,
node.i,
crossSerializeTree(serial, node),
),
);
},
});

ctx.onParse(crossParseStream(ctx, source));

return () => {
ctx.alive = false;
};
}
7 changes: 4 additions & 3 deletions packages/seroval/src/core/cross/serialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
import type { Assignment } from '../assignments';
import { resolveAssignments, resolveFlags } from '../assignments';
import {
GLOBAL_CONTEXT_PARAM,
GLOBAL_CONTEXT_PROMISE_CONSTRUCTOR,
GLOBAL_CONTEXT_REFERENCES,
GLOBAL_CONTEXT_REJECTERS,
Expand All @@ -55,7 +56,7 @@ import {
} from '../keys';

export function getRefExpr(id: number): string {
return GLOBAL_CONTEXT_REFERENCES + '[' + id + ']';
return GLOBAL_CONTEXT_PARAM + '.' + GLOBAL_CONTEXT_REFERENCES + '[' + id + ']';
}

function pushObjectFlag(
Expand Down Expand Up @@ -718,13 +719,13 @@ function serializeFulfilled(
node: SerovalFulfilledNode,
): string {
const callee = node.s ? GLOBAL_CONTEXT_RESOLVERS : GLOBAL_CONTEXT_REJECTERS;
return callee + '[' + node.i + '](' + crossSerializeTree(ctx, node.f) + ')';
return GLOBAL_CONTEXT_PARAM + '.' + GLOBAL_CONTEXT_REFERENCES + '[' + node.i + '].' + callee + '(' + crossSerializeTree(ctx, node.f) + ')';
}

function serializeResolver(
node: SerovalResolverNode,
): string {
return assignIndexedValue(node.i, GLOBAL_CONTEXT_PROMISE_CONSTRUCTOR + '()');
return assignIndexedValue(node.i, GLOBAL_CONTEXT_PARAM + '.' + GLOBAL_CONTEXT_PROMISE_CONSTRUCTOR + '()');
}

export default function crossSerializeTree(
Expand Down
8 changes: 3 additions & 5 deletions packages/seroval/src/core/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@ export const GLOBAL_CONTEXT_REJECTERS = 'f';

export const GLOBAL_CONTEXT_PROMISE_CONSTRUCTOR = 'p';

export const ROOT_REFERENCE = 'o';
export const ROOT_REFERENCE = 't';

export const GLOBAL_CONTEXT_PARAM = 'o';

export const GLOBAL_CONTEXT_PROPERTIES = [
GLOBAL_CONTEXT_REFERENCES,
GLOBAL_CONTEXT_PROMISE_CONSTRUCTOR,
GLOBAL_CONTEXT_RESOLVERS,
GLOBAL_CONTEXT_REJECTERS,
];

export const CROSS_IIFE_PARAMS = GLOBAL_CONTEXT_PROPERTIES.join(',');

export const CROSS_IIFE_ARGUMENTS = `(${GLOBAL_CONTEXT_PROPERTIES.map((item) => `${GLOBAL_CONTEXT_KEY}.${item}`).join(',')})`;

0 comments on commit dab182b

Please sign in to comment.