import { ClassType, CompilerContext, CustomError } from '@deepkit/core'; import { AnnotationDefinition, EmbeddedOptions, FindType, ReflectionKind, Type, TypeArray, TypeClass, TypeIndexSignature, TypeObjectLiteral, TypeParameter, TypeProperty, TypePropertySignature, TypeUnion } from './reflection/type.js'; import { ReflectionProperty } from './reflection/reflection.js'; import { ValidationErrorItem } from './validator.js'; /** * Make sure to change the id when a custom naming strategy is implemented, since caches are based on it. */ export declare class NamingStrategy { id: string; constructor(id?: string); getPropertyName(type: TypeProperty | TypePropertySignature, forSerializer: string): string | undefined; } export declare const underscoreNamingStrategy: { getPropertyName(type: TypeProperty | TypePropertySignature, forSerializer: string): string | undefined; id: string; }; /** * Options that can be passed to the serialization/deserialization functions * and change the behavior in runtime (not embedded in JIT). */ export interface SerializationOptions { /** * Which groups to include. If a property is not assigned to * a given group, it will be excluded. * Use an empty array to include only non-grouped properties. */ groups?: string[]; /** * Which groups to exclude. If a property is assigned to at least * one given group, it will be excluded. Basically the opposite of * `groups`, but you can combine both. * Use an empty array to exclude only non-grouped properties. */ groupsExclude?: string[]; /** * Allows more loosely data for certain types. e.g. * * - '1', '0', 'true', 'false' will be converted to true|false for boolean type. * - '1' will be converted to number for number type. * - 1 will be converted to string for string type. * * This will activate all registered type guards with negative specifically. * * This is enabled by default. */ loosely?: boolean; } export type SerializeFunction = (data: T, state?: SerializationOptions) => R; export declare function getPartialType(type: TypeClass | TypeObjectLiteral): any; /** * Creates a (cached) Partial of the given type and returns a (cached) serializer function for the given registry (serialize or deserialize). */ export declare function getPartialSerializeFunction(type: TypeClass | TypeObjectLiteral, registry: TemplateRegistry, namingStrategy?: NamingStrategy): SerializeFunction; /** * Returns a (cached) serializer function for the given registry (serialize or deserialize). */ export declare function getSerializeFunction(type: Type, registry: TemplateRegistry, namingStrategy?: NamingStrategy, path?: string, jitStack?: JitStack): SerializeFunction; export declare function createSerializeFunction(type: Type, registry: TemplateRegistry, namingStrategy?: NamingStrategy, path?: string | RuntimeCode | (string | RuntimeCode)[], jitStack?: JitStack): SerializeFunction; export type Guard = (data: any, state?: { errors?: ValidationErrorItem[]; }) => data is T; export declare function createTypeGuardFunction(type: Type, stateIn?: Partial, serializerToUse?: Serializer, withLoose?: boolean): undefined | Guard; export declare class SerializationError extends CustomError { originalMessage: string; code: string; path: string; constructor(originalMessage: string, code?: string, path?: string); } export declare class RuntimeCode { code: string; constructor(code: string); } export declare function collapsePath(path: (string | RuntimeCode)[], prefix?: string): string; export declare function getPropertyNameString(propertyName?: string | RuntimeCode): string; /** * internal: The jit stack cache is used in both serializer and guards, so its cache key needs to be aware of it */ export declare class JitStack { protected stacks: { registry?: TemplateRegistry; map: Map; }[]; protected id: number; getStack(registry?: TemplateRegistry): Map; has(registry: TemplateRegistry, type: Type): boolean; get(registry: TemplateRegistry, type: Type): { fn: Function | undefined; id: number; } | undefined; prepare(registry: TemplateRegistry, type: Type): { id: number; prepare: (fn: Function) => { fn: Function | undefined; }; }; getOrCreate(registry: TemplateRegistry | undefined, type: Type, create: () => Function): { fn: Function | undefined; id: number; }; } export declare class ContainerAccessor { container: string | ContainerAccessor; property: string; constructor(container: string | ContainerAccessor, property: string); toString(): string; } export declare class TemplateState { originalSetter: string | ContainerAccessor; originalAccessor: string | ContainerAccessor; compilerContext: CompilerContext; registry: TemplateRegistry; namingStrategy: NamingStrategy; jitStack: JitStack; path: (string | RuntimeCode)[]; /** * Before and after template content is rendered before/after all other templates. * When a template is put into its own function, before/after templates are run outside of this function. */ template: string; ended: boolean; setter: string | ContainerAccessor; accessor: string | ContainerAccessor; /** * Strict means only use type guards of specificality of 1 (used for is()/validation()). * For deserialization loose is used. */ validation?: 'strict' | 'loose'; /** * When this is set all specificalities are used (used in union type guards to detect which member to pick). */ allSpecificalities?: TypeGuardRegistry; propertyName?: string | RuntimeCode; setterDisabled: boolean; parentTypes: Type[]; target: 'serialize' | 'deserialize'; protected handledAnnotations: AnnotationDefinition[]; constructor(originalSetter: string | ContainerAccessor, originalAccessor: string | ContainerAccessor, compilerContext: CompilerContext, registry: TemplateRegistry, namingStrategy?: NamingStrategy, jitStack?: JitStack, path?: (string | RuntimeCode)[]); isValidation(): boolean; withValidation(validation: this['validation']): this; includeAllSpecificalities(guardRegistry: TypeGuardRegistry): this; replaceTemplate(template: string): void; /** * Forks as state, with an empty propertyName. */ fork(setter?: string | ContainerAccessor, accessor?: string | ContainerAccessor, path?: (string | RuntimeCode)[]): TemplateState; fullFork(): TemplateState; forRegistry(registry: TemplateRegistry): this; forPropertyName(name?: string | number | symbol | RuntimeCode): this; disableSetter(): this; enableSetter(): this; /** * Can be used to track which annotation was already handled. Necessary to use with `isAnnotationHandled` to avoid infinite recursive loops * when a serializer template issues sub calls depending on annotation data. */ annotationHandled(annotation: AnnotationDefinition): void; isAnnotationHandled(annotation: AnnotationDefinition): boolean; get isSerialization(): boolean; get isDeserialization(): boolean; extendPath(path: string | RuntimeCode | number | symbol): this; assignValidationError(code: string, message: string): string; throwCode(type: Type | string, error?: string, accessor?: string | ContainerAccessor): string; /** * Adds template code for setting the `this.setter` variable. The expression evaluated in `code` is assigned to `this.setter`. * `this.accessor` will point now to `this.setter`. */ addSetter(code: string | { toString(): string; }): void; addSetterAndReportErrorIfInvalid(errorCode: string, message: string, code: string): void; /** * Adds a converter function that is executed on the current `this.accessor` value. * * @example * ```typescript * serializer.deserializeRegistry.registerClass(Date, (type, state) => { * // make sure to check `v` as it is any! * state.convert((v: any) => { * if ('number' !== typeof v) throw new SerializationError('Expected number'); * return new Date(v); * }); * }); * * serializer.serializeRegistry.registerClass(Date, (type, state) => { * // in serialization `v` is always the specific type * state.convert((v: Date) => v.getTime()); * }); * ``` */ convert(callback: (value: any) => any): void; /** * Allows to add a custom code that is executed on the current `this.accessor` value. * * @example * ```typescript * serializer.deserializeRegistry.addDecorator( * isCustomTypeClass, * (type, state) => { * state.touch((value) => { * if ('onLoad' in value) value.onLoad(); * }); * } * ); * ``` */ touch(callback: (value: any) => void): void; /** * Stop executing next templates. */ stop(): void; setVariable(name: string, value?: any): string; setContext(values: { [name: string]: any; }): void; addCode(code: string): void; /** * Adds template code for setting the `this.setter` variable manually, so use `${state.setter} = value`. * `this.accessor` will point now to `this.setter`. */ addCodeForSetter(code: string): void; hasSetterCode(): boolean; } export type Template = (type: T, state: TemplateState) => void; export type TemplateHook = (type: Type, state: TemplateState) => void; /** * Just sets the state.setter to state.accessor without any modification. */ export declare function noopTemplate(type: Type, state: TemplateState): void; interface TemplateDecorator { predicate: (type: Type) => boolean; template: Template; } export declare class TemplateRegistry { serializer: Serializer; protected static ids: number; id: number; protected templates: { [kind in ReflectionKind]?: Template[]; }; protected decorator: TemplateDecorator[]; preHooks: TemplateHook[]; postHooks: TemplateHook[]; classTemplates: Map, Template[]>; constructor(serializer?: Serializer); clear(): void; get(type: Type): Template[]; getDecorator(type: Type): Template[]; /** * Registers a template for all binary classes: ArrayBuffer, Uint8Array, Int8Array, etc. */ registerBinary(template: Template): void; /** * Registers a template for a given class type. * * As soon as a single template has registered for the given classType the template registry * only returns templates for this particular classType and omits all general purpose ReflectionKind.class templates for this particular classType. */ registerClass(classType: ClassType, template: Template): void; prependClass(classType: ClassType, template: Template): void; appendClass(classType: ClassType, template: Template): void; protected getClassTemplates(classType: ClassType): Template[]; addPreHook(callback: TemplateHook): void; addPostHook(callback: TemplateHook): void; /** * Removes all registered templates. */ unregister(kind: ReflectionKind): void; /** * Registers a new template and replaces all existing (added via register,prepend,append). */ register(kind: T, template: Template>): void; /** * Registers additional templates that handle type decorators/annotations. The templates can safely assume that the given type in `state.accessor` * is already type-checked to be `T`. * * Decorator templates run last (after normal templates and postHook). * * This split between register and registerForDecorator is made to have a distinction between native type templates and additional user-made templates. * This allows to fetch only decorator templates and decide upon the result whether additional code is necessary or not. (this would not be possible * if everything is added to the `register` call that does always the basic checks). */ addDecorator(predicate: (type: Type) => boolean, template: Template): void; /** * Removes all registered decorators for a certain type. */ removeDecorator(type: Type): void; prepend(kind: T, template: Template>): void; append(kind: T, template: Template>): void; } /** * To avoid circular builds, class/object literal code is extract to its own function. * if this returns true, code is put into state to call an already existing function. */ export declare function callExtractedFunctionIfAvailable(state: TemplateState, type: Type): boolean; export declare function extractStateToFunctionAndCallIt(state: TemplateState, type: Type): { setFunction: (fn: Function) => { fn: Function | undefined; }; id: number; state: TemplateState; }; export declare function buildFunction(state: TemplateState, type: Type): Function; export declare function executeTemplates(state: TemplateState, type: Type, withLoose?: boolean, withCache?: boolean): string; export declare function createConverterJSForMember(property: ReflectionProperty | TypeProperty | TypePropertySignature | TypeIndexSignature, state: TemplateState, undefinedSetterCode?: string, nullSetterCode?: string): string; export declare function inAccessor(accessor: ContainerAccessor | string): string; export declare function deserializeEmbedded(type: TypeClass | TypeObjectLiteral, state: TemplateState, container?: string): string; export declare function getIndexCheck(context: CompilerContext, i: string, type: Type): string; /** * Sort, so the order is literal, number, string, symbol. literal comes first as its the most specific type. * We need to do that for numbers since all keys are string|symbol in runtime, and we need to check if a string is numeric first before falling back to string. */ export declare function sortSignatures(signatures: TypeIndexSignature[]): void; export declare function getStaticDefaultCodeForProperty(member: TypeProperty | TypePropertySignature, setter: string | ContainerAccessor, state: TemplateState): string; export declare function getEmbeddedProperty(type: TypeClass | TypeObjectLiteral): TypeProperty | TypePropertySignature | undefined; export declare function serializeObjectLiteral(type: TypeObjectLiteral | TypeClass, state: TemplateState): void; export declare function typeGuardEmbedded(type: TypeClass | TypeObjectLiteral, state: TemplateState, embedded: EmbeddedOptions): void; export declare function typeGuardObjectLiteral(type: TypeObjectLiteral | TypeClass, state: TemplateState): void; export declare function serializeArray(type: TypeArray, state: TemplateState): void; export declare function typeGuardArray(elementType: Type, state: TemplateState): void; export declare function getSetTypeToArray(type: TypeClass): TypeArray; export declare function getMapTypeToArray(type: TypeClass): TypeArray; export declare function getNTypeToArray(type: TypeClass, n: number): TypeArray; export declare function executeTypeArgumentAsArray(type: TypeClass, typeIndex: number, state: TemplateState): void; export declare function forwardSetToArray(type: TypeClass, state: TemplateState): void; export declare function forwardMapToArray(type: TypeClass, state: TemplateState): void; export declare function serializePropertyOrParameter(type: TypePropertySignature | TypeProperty | TypeParameter, state: TemplateState): void; export declare function validatePropertyOrParameter(type: TypePropertySignature | TypeProperty | TypeParameter, state: TemplateState): void; export declare function handleUnion(type: TypeUnion, state: TemplateState): void; export declare function getNameExpression(name: string | number | symbol | undefined, state: TemplateState): string; export declare class TypeGuardRegistry { serializer: Serializer; registry: { [specificality: number]: TemplateRegistry; }; protected sorted?: [specificality: number, registry: TemplateRegistry][]; /** * Lowest specificality first */ getSortedTemplateRegistries(): [specificality: number, registry: TemplateRegistry][]; constructor(serializer: Serializer); clear(): void; /** * * @see register() for specificality explanation. */ getRegistry(specificality: number): TemplateRegistry; /** * Registers a new template and replaces all existing (added via register,prepend,append). * * Specificality defines when the given template guard is executed. * * - 1 means its used for JS types - exact types. For example for type string `'string' ==== typeof v` is used. Same for number, bigint, and boolean. * Guards of this specificality are used for the `is()` function. * * - >1 means it acts as a fallback. For example in a union `number | Date`, when a string is given, the Date can allow `string` type as well, so it gets converted to a Date. * * - >0 && <1 means its acts as a priority guard. For example in a `string | Date`, a string of date-format is converted to a Date instead of a string. This is necessary * to support regular JSON. * * - <0, anything below 0 means it can optionally be used for loosely types. This is handy when data comes from a string-only encoding like URL query strings. * In this specificality a numeric string is converted to a number or bigint, a 1|0|true|false string converted to boolean . */ register(specificality: number, kind: T, template: Template>): void; /** * @see register */ registerClass(specificality: number, classType: ClassType, template: Template): void; /** * @see register */ registerBinary(specificality: number, template: Template): void; } /** * Default serializer that can convert JS data structures to the target type. * It coerces types, converts object literals to class instances, and has type guards for JS types. * * JSONSerializer has the same but for JSON data structures. */ export declare class Serializer { name: string; serializeRegistry: TemplateRegistry; deserializeRegistry: TemplateRegistry; typeGuards: TypeGuardRegistry; validators: TemplateRegistry; constructor(name?: string); setExplicitUndefined(type: Type, state: TemplateState): boolean; protected registerValidators(): void; clear(): void; protected registerSerializers(): void; protected registerTypeGuards(): void; } export declare const serializableKinds: ReflectionKind[]; export declare class EmptySerializer extends Serializer { constructor(name?: string); protected registerValidators(): void; protected registerSerializers(): void; } export declare const serializer: Serializer; export {}; export declare type __ΩSerializationOptions = any[]; export declare type __ΩSerializeFunction = any[]; export declare type __ΩGuard = any[]; export declare type __ΩTemplate = any[]; export declare type __ΩTemplateHook = any[];