UNPKG

@colyseus/schema

Version:

Binary state serializer with delta encoding for games

121 lines (102 loc) 6.33 kB
import type { Definition, DefinitionType, PrimitiveType, RawPrimitiveType } from "../annotations"; import type { Schema } from "../Schema"; import type { ArraySchema } from "./custom/ArraySchema"; import type { CollectionSchema } from "./custom/CollectionSchema"; import type { MapSchema } from "./custom/MapSchema"; import type { SetSchema } from "./custom/SetSchema"; export type Constructor<T = {}> = new (...args: any[]) => T; export interface Collection<K = any, V = any, IT = V> { [Symbol.iterator](): IterableIterator<IT>; forEach(callback: Function): void; entries(): IterableIterator<[K, V]>; } export type InferValueType<T extends DefinitionType> = T extends "string" ? string : T extends "number" ? number : T extends "int8" ? number : T extends "uint8" ? number : T extends "int16" ? number : T extends "uint16" ? number : T extends "int32" ? number : T extends "uint32" ? number : T extends "int64" ? number : T extends "uint64" ? number : T extends "float32" ? number : T extends "float64" ? number : T extends "boolean" ? boolean // Handle { type: ... } patterns : T extends { type: infer ChildType extends PrimitiveType } ? InferValueType<ChildType> : T extends { type: infer ChildType extends Constructor } ? InstanceType<ChildType> : T extends { type: Array<infer ChildType> } ? (ChildType extends Record<string | number, string | number> ? ChildType[keyof ChildType][] : ChildType[]) // TS ENUM : T extends { type: { map: infer ChildType } } ? (ChildType extends Record<string | number, string | number> ? MapSchema<ChildType[keyof ChildType]> : MapSchema<ChildType>) // TS ENUM : T extends { type: { set: infer ChildType } } ? (ChildType extends Record<string | number, string | number> ? SetSchema<ChildType[keyof ChildType]> : SetSchema<ChildType>) // TS ENUM : T extends { type: { collection: infer ChildType } } ? (ChildType extends Record<string | number, string | number> ? CollectionSchema<ChildType[keyof ChildType]> : CollectionSchema<ChildType>) // TS ENUM : T extends { type: infer ChildType } ? (ChildType extends Record<string | number, string | number> ? ChildType[keyof ChildType] : ChildType) // TS ENUM // Handle direct array patterns : T extends Array<infer ChildType extends Constructor> ? InstanceType<ChildType>[] : T extends Array<infer ChildType> ? (ChildType extends Record<string | number, string | number> ? ChildType[keyof ChildType][] : ChildType[]) // TS ENUM // Handle collection object patterns : T extends { array: infer ChildType extends Constructor } ? InstanceType<ChildType>[] : T extends { array: infer ChildType } ? (ChildType extends Record<string | number, string | number> ? ChildType[keyof ChildType][] : ChildType[]) // TS ENUM : T extends { map: infer ChildType extends Constructor } ? MapSchema<InstanceType<ChildType>> : T extends { map: infer ChildType } ? (ChildType extends Record<string | number, string | number> ? MapSchema<ChildType[keyof ChildType]> : MapSchema<ChildType>) // TS ENUM : T extends { set: infer ChildType extends Constructor } ? SetSchema<InstanceType<ChildType>> : T extends { set: infer ChildType } ? (ChildType extends Record<string | number, string | number> ? SetSchema<ChildType[keyof ChildType]> : SetSchema<ChildType>) // TS ENUM : T extends { collection: infer ChildType extends Constructor } ? CollectionSchema<InstanceType<ChildType>> : T extends { collection: infer ChildType } ? (ChildType extends Record<string | number, string | number> ? CollectionSchema<ChildType[keyof ChildType]> : CollectionSchema<ChildType>) // TS ENUM // Handle direct types : T extends Constructor ? InstanceType<T> : T extends Record<string | number, string | number> ? T[keyof T] // TS ENUM : T extends PrimitiveType ? T : never; export type InferSchemaInstanceType<T extends Definition> = { [K in keyof T]: T[K] extends (...args: any[]) => any ? (T[K] extends new (...args: any[]) => any ? InferValueType<T[K]> : T[K]) : InferValueType<T[K]> } & Schema; export type NonFunctionProps<T> = Omit<T, { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]>; export type NonFunctionPropNames<T> = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T]; export type NonFunctionNonPrimitivePropNames<T> = { [K in keyof T]: T[K] extends Function ? never : T[K] extends number | string | boolean ? never : K }[keyof T]; // Helper to recursively convert Schema instances to their JSON representation type ToJSONValue<U> = U extends Schema ? ToJSON<U> : U; export type ToJSON<T> = NonFunctionProps<{ [K in keyof T]: T[K] extends MapSchema<infer U> ? Record<string, ToJSONValue<U>> : T[K] extends Map<string, infer U> ? Record<string, ToJSONValue<U>> : T[K] extends ArraySchema<infer U> ? ToJSONValue<U>[] : T[K] extends SetSchema<infer U> ? ToJSONValue<U>[] : T[K] extends CollectionSchema<infer U> ? ToJSONValue<U>[] : T[K] extends Schema ? ToJSON<T[K]> : T[K] }>; // Helper type to check if T is exactly 'never' (meaning no InitProps was provided) export type IsNever<T> = [T] extends [never] ? true : false; /** * Type helper for .assign() method - allows assigning values in a flexible way * - Primitives can be assigned directly * - Schema instances can be assigned from plain objects or Schema instances * - Collections can be assigned from their JSON representations */ export type AssignableProps<T> = { [K in NonFunctionPropNames<T>]?: T[K] extends MapSchema<infer U> ? MapSchema<U> | Record<string, U extends Schema ? (U | AssignableProps<U>) : U> : T[K] extends ArraySchema<infer U> ? ArraySchema<U> | (U extends Schema ? (U | AssignableProps<U>)[] : U[]) : T[K] extends SetSchema<infer U> ? SetSchema<U> | Set<U> | (U extends Schema ? (U | AssignableProps<U>)[] : U[]) : T[K] extends CollectionSchema<infer U> ? CollectionSchema<U> | (U extends Schema ? (U | AssignableProps<U>)[] : U[]) : T[K] extends Schema ? T[K] | AssignableProps<T[K]> : T[K] };