Skip to content

Commit

Permalink
Fix error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
lxsmnsyc committed Jan 11, 2024
1 parent 199b7f7 commit fa46922
Show file tree
Hide file tree
Showing 13 changed files with 432 additions and 317 deletions.
132 changes: 66 additions & 66 deletions docs/compatibility.md

Large diffs are not rendered by default.

7 changes: 0 additions & 7 deletions packages/seroval/src/core/UnsupportedTypeError.ts

This file was deleted.

5 changes: 0 additions & 5 deletions packages/seroval/src/core/base-primitives.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import assert from './utils/assert';
import type { WellKnownSymbols } from './constants';
import { INV_SYMBOL_REF, SerovalNodeType } from './constants';
import {
Expand Down Expand Up @@ -195,10 +194,6 @@ export function createWKSymbolNode(
id: number,
current: WellKnownSymbols,
): SerovalWKSymbolNode {
assert(
current in INV_SYMBOL_REF,
new Error('Only well-known symbols are supported.'),
);
return {
t: SerovalNodeType.WKSymbol,
i: id,
Expand Down
162 changes: 86 additions & 76 deletions packages/seroval/src/core/context/deserializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ import { createDeferred } from '../utils/deferred';
import assert from '../utils/assert';
import type { Stream } from '../stream';
import { createStream, streamToAsyncIterable } from '../stream';
import {
SerovalMissingInstanceError,
SerovalMissingPluginError,
SerovalDeserializationError,
SerovalUnsupportedNodeError,
} from '../errors';

function applyObjectFlag(obj: unknown, flag: SerovalObjectFlags): unknown {
switch (flag) {
Expand Down Expand Up @@ -276,7 +282,7 @@ export default abstract class BaseDeserializerContext
}
}
}
throw new Error('Missing plugin for tag "' + node.c + '".');
throw new SerovalMissingPluginError(node.c);
}

private deserializePromiseConstructor(
Expand All @@ -287,14 +293,14 @@ export default abstract class BaseDeserializerContext

private deserializePromiseResolve(node: SerovalPromiseResolveNode): unknown {
const deferred = this.refs.get(node.i) as Deferred | undefined;
assert(deferred, new Error('Missing Promise instance.'));
assert(deferred, new SerovalMissingInstanceError('Promise'));
deferred.resolve(this.deserialize(node.a[1]));
return undefined;
}

private deserializePromiseReject(node: SerovalPromiseRejectNode): unknown {
const deferred = this.refs.get(node.i) as Deferred | undefined;
assert(deferred, new Error('Missing Promise instance.'));
assert(deferred, new SerovalMissingInstanceError('Promise'));
deferred.reject(this.deserialize(node.a[1]));
return undefined;
}
Expand Down Expand Up @@ -330,21 +336,21 @@ export default abstract class BaseDeserializerContext

private deserializeStreamNext(node: SerovalStreamNextNode): unknown {
const deferred = this.refs.get(node.i) as Stream<unknown> | undefined;
assert(deferred, new Error('Missing Stream instance.'));
assert(deferred, new SerovalMissingInstanceError('Stream'));
deferred.next(this.deserialize(node.f));
return undefined;
}

private deserializeStreamThrow(node: SerovalStreamThrowNode): unknown {
const deferred = this.refs.get(node.i) as Stream<unknown> | undefined;
assert(deferred, new Error('Missing Stream instance.'));
assert(deferred, new SerovalMissingInstanceError('Stream'));
deferred.throw(this.deserialize(node.f));
return undefined;
}

private deserializeStreamReturn(node: SerovalStreamReturnNode): unknown {
const deferred = this.refs.get(node.i) as Stream<unknown> | undefined;
assert(deferred, new Error('Missing Stream instance.'));
assert(deferred, new SerovalMissingInstanceError('Stream'));
deferred.return(this.deserialize(node.f));
return undefined;
}
Expand All @@ -364,76 +370,80 @@ export default abstract class BaseDeserializerContext
}

deserialize(node: SerovalNode): unknown {
switch (node.t) {
case SerovalNodeType.Constant:
return CONSTANT_VAL[node.s];
case SerovalNodeType.Number:
return node.s;
case SerovalNodeType.String:
return deserializeString(node.s);
case SerovalNodeType.BigInt:
return BigInt(node.s);
case SerovalNodeType.IndexedValue:
return this.refs.get(node.i);
case SerovalNodeType.Reference:
return this.deserializeReference(node);
case SerovalNodeType.Array:
return this.deserializeArray(node);
case SerovalNodeType.Object:
case SerovalNodeType.NullConstructor:
return this.deserializeObject(node);
case SerovalNodeType.Date:
return this.deserializeDate(node);
case SerovalNodeType.RegExp:
return this.deserializeRegExp(node);
case SerovalNodeType.Set:
return this.deserializeSet(node);
case SerovalNodeType.Map:
return this.deserializeMap(node);
case SerovalNodeType.ArrayBuffer:
return this.deserializeArrayBuffer(node);
case SerovalNodeType.BigIntTypedArray:
case SerovalNodeType.TypedArray:
return this.deserializeTypedArray(node);
case SerovalNodeType.DataView:
return this.deserializeDataView(node);
case SerovalNodeType.AggregateError:
return this.deserializeAggregateError(node);
case SerovalNodeType.Error:
return this.deserializeError(node);
case SerovalNodeType.Promise:
return this.deserializePromise(node);
case SerovalNodeType.WKSymbol:
return SYMBOL_REF[node.s];
case SerovalNodeType.Boxed:
return this.deserializeBoxed(node);
case SerovalNodeType.Plugin:
return this.deserializePlugin(node);
case SerovalNodeType.PromiseConstructor:
return this.deserializePromiseConstructor(node);
case SerovalNodeType.PromiseResolve:
return this.deserializePromiseResolve(node);
case SerovalNodeType.PromiseReject:
return this.deserializePromiseReject(node);
case SerovalNodeType.IteratorFactoryInstance:
return this.deserializeIteratorFactoryInstance(node);
case SerovalNodeType.AsyncIteratorFactoryInstance:
return this.deserializeAsyncIteratorFactoryInstance(node);
case SerovalNodeType.StreamConstructor:
return this.deserializeStreamConstructor(node);
case SerovalNodeType.StreamNext:
return this.deserializeStreamNext(node);
case SerovalNodeType.StreamThrow:
return this.deserializeStreamThrow(node);
case SerovalNodeType.StreamReturn:
return this.deserializeStreamReturn(node);
case SerovalNodeType.IteratorFactory:
return this.deserializeIteratorFactory(node);
case SerovalNodeType.AsyncIteratorFactory:
return this.deserializeAsyncIteratorFactory(node);
// case SerovalNodeType.SpecialReference:
default:
throw new Error('invariant');
try {
switch (node.t) {
case SerovalNodeType.Constant:
return CONSTANT_VAL[node.s];
case SerovalNodeType.Number:
return node.s;
case SerovalNodeType.String:
return deserializeString(node.s);
case SerovalNodeType.BigInt:
return BigInt(node.s);
case SerovalNodeType.IndexedValue:
return this.refs.get(node.i);
case SerovalNodeType.Reference:
return this.deserializeReference(node);
case SerovalNodeType.Array:
return this.deserializeArray(node);
case SerovalNodeType.Object:
case SerovalNodeType.NullConstructor:
return this.deserializeObject(node);
case SerovalNodeType.Date:
return this.deserializeDate(node);
case SerovalNodeType.RegExp:
return this.deserializeRegExp(node);
case SerovalNodeType.Set:
return this.deserializeSet(node);
case SerovalNodeType.Map:
return this.deserializeMap(node);
case SerovalNodeType.ArrayBuffer:
return this.deserializeArrayBuffer(node);
case SerovalNodeType.BigIntTypedArray:
case SerovalNodeType.TypedArray:
return this.deserializeTypedArray(node);
case SerovalNodeType.DataView:
return this.deserializeDataView(node);
case SerovalNodeType.AggregateError:
return this.deserializeAggregateError(node);
case SerovalNodeType.Error:
return this.deserializeError(node);
case SerovalNodeType.Promise:
return this.deserializePromise(node);
case SerovalNodeType.WKSymbol:
return SYMBOL_REF[node.s];
case SerovalNodeType.Boxed:
return this.deserializeBoxed(node);
case SerovalNodeType.Plugin:
return this.deserializePlugin(node);
case SerovalNodeType.PromiseConstructor:
return this.deserializePromiseConstructor(node);
case SerovalNodeType.PromiseResolve:
return this.deserializePromiseResolve(node);
case SerovalNodeType.PromiseReject:
return this.deserializePromiseReject(node);
case SerovalNodeType.IteratorFactoryInstance:
return this.deserializeIteratorFactoryInstance(node);
case SerovalNodeType.AsyncIteratorFactoryInstance:
return this.deserializeAsyncIteratorFactoryInstance(node);
case SerovalNodeType.StreamConstructor:
return this.deserializeStreamConstructor(node);
case SerovalNodeType.StreamNext:
return this.deserializeStreamNext(node);
case SerovalNodeType.StreamThrow:
return this.deserializeStreamThrow(node);
case SerovalNodeType.StreamReturn:
return this.deserializeStreamReturn(node);
case SerovalNodeType.IteratorFactory:
return this.deserializeIteratorFactory(node);
case SerovalNodeType.AsyncIteratorFactory:
return this.deserializeAsyncIteratorFactory(node);
// case SerovalNodeType.SpecialReference:
default:
throw new SerovalUnsupportedNodeError(node);
}
} catch (error) {
throw new SerovalDeserializationError(error);
}
}
}
13 changes: 3 additions & 10 deletions packages/seroval/src/core/context/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import type {
SerovalWKSymbolNode,
} from '../types';
import { getObjectFlag } from '../utils/get-object-flag';
import { SerovalUnsupportedTypeError } from '../errors';

export interface BaseParserContextOptions extends PluginAccessOptions {
disabledFeatures?: number;
Expand Down Expand Up @@ -118,12 +119,7 @@ export abstract class BaseParserContext implements PluginAccessOptions {
protected getStrictReference<T>(
current: T,
): SerovalIndexedValueNode | SerovalReferenceNode {
assert(
hasReferenceID(current),
new Error(
'Cannot serialize ' + typeof current + ' without reference ID.',
),
);
assert(hasReferenceID(current), new SerovalUnsupportedTypeError(current));
const result = this.getIndexedValue(current);
if (result.type === NodeType.Indexed) {
return result.value;
Expand All @@ -144,10 +140,7 @@ export abstract class BaseParserContext implements PluginAccessOptions {
if (ref.type !== NodeType.Fresh) {
return ref.value;
}
assert(
current in INV_SYMBOL_REF,
new Error('Cannot serialized unsupported symbol.'),
);
assert(current in INV_SYMBOL_REF, new SerovalUnsupportedTypeError(current));
return createWKSymbolNode(ref.value, current as WellKnownSymbols);
}

Expand Down
56 changes: 30 additions & 26 deletions packages/seroval/src/core/context/parser/async.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import UnsupportedTypeError from '../../UnsupportedTypeError';
import {
createPluginNode,
createDateNode,
Expand Down Expand Up @@ -61,6 +60,7 @@ import type {
BigIntTypedArrayValue,
TypedArrayValue,
} from '../../utils/typed-array';
import { SerovalParserError, SerovalUnsupportedTypeError } from '../../errors';

type ObjectLikeNode =
| SerovalObjectNode
Expand Down Expand Up @@ -429,36 +429,40 @@ export default abstract class BaseAsyncParserContext extends BaseParserContext {
if (Symbol.iterator in current || Symbol.asyncIterator in current) {
return this.parsePlainObject(id, current, !!currentClass);
}
throw new UnsupportedTypeError(current);
throw new SerovalUnsupportedTypeError(current);
}

async parse<T>(current: T): Promise<SerovalNode> {
switch (typeof current) {
case 'boolean':
return current ? TRUE_NODE : FALSE_NODE;
case 'undefined':
return UNDEFINED_NODE;
case 'string':
return createStringNode(current as string);
case 'number':
return createNumberNode(current as number);
case 'bigint':
return createBigIntNode(current as bigint);
case 'object': {
if (current) {
const ref = this.getReference(current);
return ref.type === 0
? await this.parseObject(ref.value, current as object)
: ref.value;
try {
switch (typeof current) {
case 'boolean':
return current ? TRUE_NODE : FALSE_NODE;
case 'undefined':
return UNDEFINED_NODE;
case 'string':
return createStringNode(current as string);
case 'number':
return createNumberNode(current as number);
case 'bigint':
return createBigIntNode(current as bigint);
case 'object': {
if (current) {
const ref = this.getReference(current);
return ref.type === 0
? await this.parseObject(ref.value, current as object)
: ref.value;
}
return NULL_NODE;
}
return NULL_NODE;
case 'symbol':
return this.parseWellKnownSymbol(current);
case 'function':
return this.parseFunction(current as (...args: unknown[]) => unknown);
default:
throw new SerovalUnsupportedTypeError(current);
}
case 'symbol':
return this.parseWellKnownSymbol(current);
case 'function':
return this.parseFunction(current as (...args: unknown[]) => unknown);
default:
throw new UnsupportedTypeError(current);
} catch (error) {
throw new SerovalParserError(error);
}
}
}
Loading

0 comments on commit fa46922

Please sign in to comment.