import {CanonicalItemClass} from '../../CanonicalReceiver' import {BaseSerializer} from './BaseSerializer' import {Awaitable, ErrorWithContext, JSONState, Rehydratable} from '../../../util' import {Container, Inject, Injectable} from '../../../di' import {Canon} from '../../../service/Canon' /** State encoded by this class. */ export interface SimpleCanonicalItemSerialState extends JSONState { rehydrate?: JSONState canonicalIdentifier: string } /** * A serializer implementation that serializes class instances derived from the Canon loading system. * These instances must be CanonicalItemClass instances and take no constructor parameters. * If the instance is Rehydratable, then the state will be (re-)stored. */ @Injectable() export class SimpleCanonicalItemSerializer extends BaseSerializer { @Inject() protected readonly canon!: Canon @Inject() protected readonly container!: Container protected decodeSerial(serial: SimpleCanonicalItemSerialState): Awaitable { const canon = this.canon.getFromFullyQualified(serial.canonicalIdentifier) if ( !canon ) { throw new ErrorWithContext('Unable to decode serialized payload: the canonical identifier was not found', { serial, }) } if ( canon instanceof CanonicalItemClass ) { if ( serial.rehydrate && typeof (canon as any).rehydrate === 'function' ) { (canon as unknown as Rehydratable).rehydrate(serial.rehydrate) } return canon as TActual } else if ( canon?.prototype instanceof CanonicalItemClass ) { const inst = this.container.make(canon) if ( serial.rehydrate && typeof (inst as any).rehydrate === 'function' ) { (inst as unknown as Rehydratable).rehydrate(serial.rehydrate) } return inst as TActual } throw new ErrorWithContext('Attempted to instantiate serialized item into non-Canonical class', { canon, serial, }) } protected async encodeActual(actual: TActual): Promise { const ctor = actual.constructor as typeof CanonicalItemClass const canonicalIdentifier = ctor.getFullyQualifiedCanonicalResolver() if ( !canonicalIdentifier ) { throw new ErrorWithContext('Unable to determine Canonical resolver for serialization.', [ actual, ]) } const state: SimpleCanonicalItemSerialState = { canonicalIdentifier, } if ( typeof (actual as any).dehydrate === 'function' ) { state.rehydrate = await (actual as unknown as Rehydratable).dehydrate() } return state } protected getName(): string { return '@extollo/lib:SimpleCanonicalItemSerializer' } matchActual(some: TActual): boolean { return ( some instanceof CanonicalItemClass && some.constructor.length === 0 ) } }