Skip to content

Commit

Permalink
Add support for FormData
Browse files Browse the repository at this point in the history
  • Loading branch information
lxsmnsyc committed Apr 9, 2023
1 parent b936a66 commit a466500
Show file tree
Hide file tree
Showing 9 changed files with 289 additions and 74 deletions.
20 changes: 14 additions & 6 deletions packages/seroval/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,33 @@ interface IndexAssignment {
v: string;
}

interface MapAssignment {
t: 'map';
interface SetAssignment {
t: 'set';
s: string;
k: string;
v: string;
}

interface SetAssignment {
t: 'set';
interface AddAssignment {
t: 'add';
s: string;
k: undefined;
v: string;
}

interface AppendAssignment {
t: 'append';
s: string;
k: string;
v: string;
}

// Array of assignments to be done (used for recursion)
export type Assignment =
| IndexAssignment
| MapAssignment
| SetAssignment;
| AddAssignment
| SetAssignment
| AppendAssignment;

export interface ParserContext {
refs: Map<unknown, number>;
Expand Down
29 changes: 28 additions & 1 deletion packages/seroval/src/tree/async.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
SerovalAggregateErrorNode,
SerovalArrayNode,
SerovalErrorNode,
SerovalFormDataNode,
SerovalHeadersNode,
SerovalIterableNode,
SerovalMapNode,
Expand Down Expand Up @@ -357,7 +358,7 @@ async function generateHeadersNode(
id: number,
current: Headers,
): Promise<SerovalHeadersNode> {
assert(ctx.features & Feature.WebAPI, 'Unsupported type "File"');
assert(ctx.features & Feature.WebAPI, 'Unsupported type "Headers"');
const items: [string, string][] = [];
current.forEach((value, key) => {
items.push([key, value]);
Expand All @@ -376,6 +377,30 @@ async function generateHeadersNode(
};
}

async function generateFormDataNode(
ctx: ParserContext,
id: number,
current: FormData,
): Promise<SerovalFormDataNode> {
assert(ctx.features & Feature.WebAPI, 'Unsupported type "FormData"');
const items: Record<string, FormDataEntryValue> = {};
current.forEach((value, key) => {
items[key] = value;
});
return {
t: SerovalNodeType.FormData,
i: id,
s: undefined,
l: undefined,
c: undefined,
m: undefined,
d: await generateProperties(ctx, items),
a: undefined,
f: undefined,
b: undefined,
};
}

async function parse<T>(
ctx: ParserContext,
current: T,
Expand Down Expand Up @@ -492,6 +517,8 @@ async function parse<T>(
return createFileNode(ctx, id, current as unknown as File);
case Headers:
return generateHeadersNode(ctx, id, current as unknown as Headers);
case FormData:
return generateFormDataNode(ctx, id, current as unknown as FormData);
default:
break;
}
Expand Down
101 changes: 54 additions & 47 deletions packages/seroval/src/tree/deserialize.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/* eslint-disable prefer-spread */
/* eslint-disable @typescript-eslint/no-use-before-define */
import {
SerializationContext,
} from '../context';
import { deserializeString } from '../string';
import { AsyncServerValue } from '../types';
import { getReference } from './reference';
import { getErrorConstructor, getTypedArrayConstructor } from './shared';
import { SYMBOL_REF } from './symbols';
Expand All @@ -17,6 +17,7 @@ import {
SerovalDateNode,
SerovalErrorNode,
SerovalFileNode,
SerovalFormDataNode,
SerovalHeadersNode,
SerovalIterableNode,
SerovalMapNode,
Expand All @@ -39,22 +40,23 @@ function assignIndexedValue<T>(
index: number,
value: T,
) {
ctx.valueMap.set(index, value);
if (ctx.markedRefs.has(index)) {
ctx.valueMap.set(index, value);
}
return value;
}

type SerovalNodeListNode =
| SerovalArrayNode
| SerovalIterableNode
| SerovalHeadersNode;

function deserializeNodeList(
function deserializeArray(
ctx: SerializationContext,
node: SerovalNodeListNode,
result: unknown[],
node: SerovalArrayNode,
) {
const result: unknown[] = assignIndexedValue(
ctx,
node.i,
new Array<unknown>(node.l),
);
let item: SerovalNode;
for (let i = 0, len = node.a.length; i < len; i++) {
for (let i = 0, len = node.l; i < len; i++) {
item = node.a[i];
if (item) {
result[i] = deserializeTree(ctx, item);
Expand All @@ -63,21 +65,6 @@ function deserializeNodeList(
return result;
}

function deserializeArray(
ctx: SerializationContext,
node: SerovalArrayNode,
) {
const result: AsyncServerValue[] = assignIndexedValue(
ctx,
node.i,
new Array<AsyncServerValue>(node.l),
);
ctx.stack.push(node.i);
deserializeNodeList(ctx, node, result);
ctx.stack.pop();
return result;
}

function deserializeProperties(
ctx: SerializationContext,
node: SerovalObjectRecordNode,
Expand All @@ -99,22 +86,18 @@ function deserializeNullConstructor(
const result = assignIndexedValue(
ctx,
node.i,
Object.create(null) as Record<string, AsyncServerValue>,
Object.create(null) as Record<string, unknown>,
);
ctx.stack.push(node.i);
deserializeProperties(ctx, node.d, result);
ctx.stack.pop();
return result;
}

function deserializeObject(
ctx: SerializationContext,
node: SerovalObjectNode,
) {
const result = assignIndexedValue(ctx, node.i, {} as Record<string, AsyncServerValue>);
ctx.stack.push(node.i);
const result = assignIndexedValue(ctx, node.i, {} as Record<string, unknown>);
deserializeProperties(ctx, node.d, result);
ctx.stack.pop();
return result;
}

Expand All @@ -123,11 +106,9 @@ function deserializeSet(
node: SerovalSetNode,
) {
const result = assignIndexedValue(ctx, node.i, new Set<unknown>());
ctx.stack.push(node.i);
for (let i = 0, len = node.a.length; i < len; i++) {
for (let i = 0, len = node.l; i < len; i++) {
result.add(deserializeTree(ctx, node.a[i]));
}
ctx.stack.pop();
return result;
}

Expand All @@ -140,18 +121,16 @@ function deserializeMap(
node.i,
new Map<unknown, unknown>(),
);
ctx.stack.push(node.i);
for (let i = 0; i < node.d.s; i++) {
for (let i = 0, len = node.d.s; i < len; i++) {
result.set(
deserializeTree(ctx, node.d.k[i]),
deserializeTree(ctx, node.d.v[i]),
);
}
ctx.stack.pop();
return result;
}

type AssignableValue = AggregateError | Error | Iterable<AsyncServerValue>
type AssignableValue = AggregateError | Error | Iterable<unknown>
type AssignableNode = SerovalAggregateErrorNode | SerovalErrorNode | SerovalIterableNode;

function deserializeDictionary<T extends AssignableValue>(
Expand All @@ -160,9 +139,7 @@ function deserializeDictionary<T extends AssignableValue>(
result: T,
) {
if (node.d) {
ctx.stack.push(node.i);
const fields = deserializeProperties(ctx, node.d, {});
ctx.stack.pop();
Object.assign(result, fields);
}
return result;
Expand Down Expand Up @@ -247,9 +224,15 @@ function deserializeIterable(
ctx: SerializationContext,
node: SerovalIterableNode,
) {
const values: AsyncServerValue[] = [];
deserializeNodeList(ctx, node, values);
const result = assignIndexedValue(ctx, node.i, {
const values: unknown[] = [];
let item: SerovalNode;
for (let i = 0, len = node.l; i < len; i++) {
item = node.a[i];
if (item) {
values[i] = deserializeTree(ctx, item);
}
}
const result: Iterable<unknown> = assignIndexedValue(ctx, node.i, {
[Symbol.iterator]: () => values.values(),
});
return deserializeDictionary(ctx, node, result);
Expand Down Expand Up @@ -332,9 +315,31 @@ function deserializeHeaders(
ctx: SerializationContext,
node: SerovalHeadersNode,
) {
const values: [string, string][] = [];
deserializeNodeList(ctx, node, values);
return assignIndexedValue(ctx, node.i, new Headers(values));
const result = assignIndexedValue(ctx, node.i, new Headers());
let item: SerovalNode;
let entry: [string, string];
for (let i = 0, len = node.l; i < len; i++) {
item = node.a[i];
if (item) {
entry = deserializeTree(ctx, item) as [string, string];
result.append.apply(result, entry);
}
}
return result;
}

function deserializeFormData(
ctx: SerializationContext,
node: SerovalFormDataNode,
) {
const result = assignIndexedValue(ctx, node.i, new FormData());
for (let i = 0, len = node.d.s; i < len; i++) {
result.set(
deserializeString(node.d.k[i]),
deserializeTree(ctx, node.d.v[i]) as FormDataEntryValue,
);
}
return result;
}

export default function deserializeTree(
Expand Down Expand Up @@ -406,6 +411,8 @@ export default function deserializeTree(
return deserializeFile(ctx, node);
case SerovalNodeType.Headers:
return deserializeHeaders(ctx, node);
case SerovalNodeType.FormData:
return deserializeFormData(ctx, node);
default:
throw new Error('Unsupported type');
}
Expand Down
Loading

0 comments on commit a466500

Please sign in to comment.