import { Interface, ToInterface, Cast, FieldCtor, ToConstructor, HasTail, Head, Tail } from "./Types"; import { Doc, Field, ObjectField } from "./Doc"; import { URLField } from "./URLField"; type All = { 1: makeInterface<[Head], U> & All, U>, 0: makeInterface<[Head], U> }[HasTail extends true ? 1 : 0]; type AllToInterface = { 1: ToInterface> & AllToInterface>, 0: ToInterface> }[HasTail extends true ? 1 : 0]; export const emptySchema = createSchema({}); export const Document = makeInterface(emptySchema); export type Document = makeInterface<[typeof emptySchema]>; const DocSymbol = Symbol("Doc"); export type makeInterface = Partial> & U; // export function makeInterface(schemas: T): (doc: U) => All; // export function makeInterface(schema: T): (doc: U) => makeInterface; export function makeInterface(...schemas: T): (doc: U) => makeInterface { let schema: Interface = {}; for (const s of schemas) { for (const key in s) { schema[key] = s[key]; } } const proto = new Proxy({}, { get(target: any, prop) { if (prop === DocSymbol) { return target[prop]; } const field = target[DocSymbol][prop]; if (prop in schema) { return Cast(field, (schema as any)[prop]); } return field; }, set(target: any, prop, value) { if (prop === DocSymbol) { target[prop] = value; } target[DocSymbol][prop] = value; return true; } }); return function (doc: any) { const obj = Object.create(proto); obj.__doc = doc; return obj; }; } export type makeStrictInterface = Partial>; export function makeStrictInterface(schema: T): (doc: Doc) => makeStrictInterface { const proto = {}; for (const key in schema) { const type = schema[key]; Object.defineProperty(proto, key, { get() { return Cast(this.__doc[key], type as any); }, set(value) { value = Cast(value, type as any); if (value !== undefined) { this.__doc[key] = value; return; } throw new TypeError("Expected type " + type); } }); } return function (doc: any) { const obj = Object.create(proto); obj.__doc = doc; return obj; }; } export function createSchema(schema: T): T & { prototype: ToConstructor } { schema.prototype = Doc; return schema as any; }