From aae64081ad9799961fa8d5fc25ff47d321a288e0 Mon Sep 17 00:00:00 2001 From: rowan Date: Sun, 18 May 2025 03:01:11 -0500 Subject: [PATCH] resolve stuff --- src/case.ts | 1 + src/de/generic.ts | 2 +- src/de/interface.ts | 3 ++- src/decorator.ts | 8 ++++++++ src/json.ts | 17 ++++++++++++++--- src/options.ts | 16 +++++++++++----- src/registry.ts | 16 ++++++++++++++++ src/ser/interface.ts | 12 ++++++------ 8 files changed, 59 insertions(+), 16 deletions(-) create mode 100644 src/registry.ts diff --git a/src/case.ts b/src/case.ts index 1045953..a99dff7 100644 --- a/src/case.ts +++ b/src/case.ts @@ -61,3 +61,4 @@ export function convertCase(value: string, convention: CaseConvention) { return joinMap(upper, '-', words) } } + diff --git a/src/de/generic.ts b/src/de/generic.ts index bd26c87..24ec9ff 100644 --- a/src/de/generic.ts +++ b/src/de/generic.ts @@ -48,7 +48,7 @@ export class GenericVisitor implements Visitor { return result } - visitIterable?(access: IterableAccess): T { + visitIterable(access: IterableAccess): T { const result = new Array(access.sizeHint()) let element diff --git a/src/de/interface.ts b/src/de/interface.ts index 90cd7db..b572ca5 100644 --- a/src/de/interface.ts +++ b/src/de/interface.ts @@ -74,7 +74,8 @@ export interface Deserializer { deserializeSymbol>(visitor: V): T deserializeNull>(visitor: V): T deserializeObject>(visitor: V): T - deserializeIterable?>(visitor: V): T + deserializeClass>(name: string, fields: string[], visitor: V): T + deserializeIterable>(visitor: V): T } export interface Deserialize { diff --git a/src/decorator.ts b/src/decorator.ts index 9a2fdca..dc652c1 100644 --- a/src/decorator.ts +++ b/src/decorator.ts @@ -1,4 +1,5 @@ import { ContainerOptions, PropertyOptions, SerdeOptions } from './options' +import { GlobalRegistry, Registry } from './registry' export const Serde = Symbol('Serde') @@ -42,3 +43,10 @@ export function serde(options: ContainerOptions | PropertyOptions) { export function getMetadata(value: any) { return value[Serde] } + +export function register(registry: Registry = GlobalRegistry) { + return function(target: any) { + registry.add(target) + return target + } +} diff --git a/src/json.ts b/src/json.ts index 0968a84..3159992 100644 --- a/src/json.ts +++ b/src/json.ts @@ -1,4 +1,5 @@ import { DefaultIterableAccessImpl, DefaultMapAccessImpl, Deserialize, Deserializer, IterableAccess, MapAccess, Visitor } from './de' +import { GlobalRegistry, Registry } from './registry' import { IterableSerializer, ObjectSerializer, Serializable, Serializer, serializeWith } from './ser' import { mixin, Nullable } from './utils' @@ -328,10 +329,12 @@ export class JSONSerializer implements Serializer { const unexpected = (expected: string, actual: string, position: number) => new SyntaxError(`Expected ${expected} at position ${position} (got '${actual}')`) export class JSONDeserializer implements Deserializer { + private readonly registry: Registry readonly buffer: StringBuffer - constructor(buffer: StringBuffer) { + constructor(buffer: StringBuffer, registry: Registry = GlobalRegistry) { this.buffer = buffer + this.registry = registry } static fromString(value: string): JSONDeserializer { @@ -353,7 +356,7 @@ export class JSONDeserializer implements Deserializer { case Token.Quote === byte: return this.deserializeString(visitor) case Token.LeftSquare === byte: - return this.deserializeIterable!(visitor) + return this.deserializeIterable(visitor) case Token.LeftCurly === byte: return this.deserializeObject(visitor) default: @@ -386,6 +389,14 @@ export class JSONDeserializer implements Deserializer { } } + + deserializeClass>(name: string, fields: string[], visitor: V): T { + const cls = this.registry.get(name) + // TODO: deserialize name representing class name, use the existing deserializeWith logic + // to deserialize the class here. likely, deserialize name and then return a CommaSeparated + // object + } + deserializeString>(visitor: V): T { const next = this.buffer.take() if (next.next() === Token.Quote) { @@ -449,7 +460,7 @@ export class JSONDeserializer implements Deserializer { throw new Error('Method not implemented.') } - deserializeIterable?>(visitor: V): T { + deserializeIterable>(visitor: V): T { let next = this.buffer.take() if (next.next() === Token.LeftSquare) { diff --git a/src/options.ts b/src/options.ts index 5857752..d99d138 100644 --- a/src/options.ts +++ b/src/options.ts @@ -2,6 +2,7 @@ import { CaseConvention, convertCase } from './case' import { Deserializer } from './de' import { Serializer } from './ser' import { isFunction, isNumber, isString } from './utils' +import { GlobalRegistry, Registry } from './registry' export interface RenameOptions { @@ -17,14 +18,15 @@ export interface RenameAllOptions { export interface ContainerOptions { // deserialization only default?: () => any - rename?: RenameOptions | string - renameAll?: RenameAllOptions | CaseConvention // deserialization only denyUnknownFields?: boolean + expecting?: string + rename?: RenameOptions | string + renameAll?: RenameAllOptions | CaseConvention + registry?: Registry tag?: string content?: string untagged?: boolean - expecting?: string } export interface ConditionalSkipOptions { @@ -59,8 +61,12 @@ export type Stage = typeof Stage[keyof typeof Stage] export class SerdeOptions { private readonly target: any - options: ContainerOptions - properties: Map + readonly options: ContainerOptions + readonly properties: Map + + get registry() { + return this.options.registry || GlobalRegistry + } constructor(target: any, options: ContainerOptions = {}, properties: Map = new Map()) { this.target = target diff --git a/src/registry.ts b/src/registry.ts new file mode 100644 index 0000000..cfa14af --- /dev/null +++ b/src/registry.ts @@ -0,0 +1,16 @@ +import { Constructor } from './utils' + +export class Registry { + registeredClasses: Map = new Map() + + add(ctor: Constructor, key: string = ctor.name) { + this.registeredClasses.set(key, ctor) + } + + get(name: string) { + return this.registeredClasses.get(name) + } +} + +export const GlobalRegistry = new Registry() + diff --git a/src/ser/interface.ts b/src/ser/interface.ts index 229f881..70874fb 100644 --- a/src/ser/interface.ts +++ b/src/ser/interface.ts @@ -11,10 +11,10 @@ export interface IterableSerializer { end(): T } -//export interface ClassSerializer { -// serializeField(name: PropertyKey, value: U): T -// end(): T -//} +export interface ClassSerializer { + serializeField(name: PropertyKey, value: U): T + end(): T +} const TypeSerializerMethods = [ 'serializeString', @@ -26,7 +26,7 @@ const TypeSerializerMethods = [ 'serializeIterable', 'serializeNull', 'serializeObject', - //'serializeInstance', + 'serializeClass', ] as const interface TypeSerializer { @@ -39,7 +39,7 @@ interface TypeSerializer { serializeObject(): ObjectSerializer // serializeMap?(): ObjectSerializer serializeIterable?(): IterableSerializer - //serializeClass?(name: PropertyKey): ClassSerializer + serializeClass(name: PropertyKey): ClassSerializer } const AnySerializerMethods = ['serializeAny']