import { type FieldProcessor, FieldSchema, StructureSchema } from '@ephox/boulder'; import { Obj } from '@ephox/katamari'; import * as FunctionAnnotator from '../../debugging/FunctionAnnotator'; import * as AlloyParts from '../../parts/AlloyParts'; import type { PartTypeAdt } from '../../parts/PartType'; import type { BaseSketchDetail, BaseSketchSpec } from '../../spec/SpecSchema'; import type { AlloyComponent } from '../component/ComponentApi'; import type { AlloySpec, SketchSpec } from '../component/SpecTypes'; import * as GuiTypes from './GuiTypes'; import * as UiSketcher from './UiSketcher'; export interface SingleSketchSpec extends BaseSketchSpec { } export interface SingleSketchDetail extends BaseSketchDetail { } type SketcherApisFunc = (apis: A, comp: AlloyComponent, ...rest: any[]) => R; type FunctionRecord = { [K in keyof A]: Function }; type SketcherApisFuncRecord> = { [K in keyof A]: A[K] }; export interface SingleSketch { readonly name: string; readonly configFields: FieldProcessor[]; readonly sketch: (spec: S) => SketchSpec; } export interface SingleSketcherSpec, E extends FunctionRecord = {}> { name: string; factory: UiSketcher.SingleSketchFactory; configFields: FieldProcessor[]; apis?: Record>; extraApis?: E; } export interface SingleSketcherRawDetail, E extends FunctionRecord = {}> { name: string; factory: UiSketcher.SingleSketchFactory; configFields: FieldProcessor[]; apis: Record>; extraApis: E; } export interface CompositeSketchSpec extends BaseSketchSpec { } export interface CompositeSketchDetail extends BaseSketchDetail { parts: Record; partUids: Record; } export interface CompositeSketch { readonly name: string; readonly configFields: FieldProcessor[]; readonly partFields: PartTypeAdt[]; readonly sketch: (spec: S) => SketchSpec; readonly parts: AlloyParts.GeneratedParts; } export interface CompositeSketcherSpec, E extends FunctionRecord = {}> { name: string; factory: UiSketcher.CompositeSketchFactory; configFields: FieldProcessor[]; partFields: PartTypeAdt[]; apis?: Record>; extraApis?: E; } export interface CompositeSketcherRawDetail, E extends FunctionRecord = {}> { name: string; factory: UiSketcher.CompositeSketchFactory; configFields: FieldProcessor[]; partFields: PartTypeAdt[]; apis: Record>; extraApis: E; } export const isSketchSpec = (spec: AlloySpec): spec is SketchSpec => { return (spec as SketchSpec).uid !== undefined; }; const singleSchema = StructureSchema.objOfOnly([ FieldSchema.required('name'), FieldSchema.required('factory'), FieldSchema.required('configFields'), FieldSchema.defaulted('apis', { }), FieldSchema.defaulted('extraApis', { }) ]); const compositeSchema = StructureSchema.objOfOnly([ FieldSchema.required('name'), FieldSchema.required('factory'), FieldSchema.required('configFields'), FieldSchema.required('partFields'), FieldSchema.defaulted('apis', { }), FieldSchema.defaulted('extraApis', { }) ]); const single = < S extends SingleSketchSpec, D extends SingleSketchDetail, A extends FunctionRecord, E extends FunctionRecord = {} >(rawConfig: SingleSketcherSpec): SingleSketch & A & E => { const config: SingleSketcherRawDetail = StructureSchema.asRawOrDie('Sketcher for ' + rawConfig.name, singleSchema, rawConfig); const sketch = (spec: S) => UiSketcher.single(config.name, config.configFields, config.factory, spec); const apis = Obj.map(config.apis, GuiTypes.makeApi) as any as SketcherApisFuncRecord; const extraApis = Obj.map(config.extraApis, (f, k) => FunctionAnnotator.markAsExtraApi(f, k)) as E; return { name: config.name, configFields: config.configFields, sketch, ...apis, ...extraApis }; }; const composite = < S extends CompositeSketchSpec, D extends CompositeSketchDetail, A extends FunctionRecord, E extends FunctionRecord = {} >(rawConfig: CompositeSketcherSpec): CompositeSketch & A & E => { const config: CompositeSketcherRawDetail = StructureSchema.asRawOrDie('Sketcher for ' + rawConfig.name, compositeSchema, rawConfig); const sketch = (spec: S) => UiSketcher.composite(config.name, config.configFields, config.partFields, config.factory, spec); // These are constructors that will store their configuration. const parts: AlloyParts.GeneratedParts = AlloyParts.generate(config.name, config.partFields); const apis = Obj.map(config.apis, GuiTypes.makeApi) as any as SketcherApisFuncRecord; const extraApis = Obj.map(config.extraApis, (f, k) => FunctionAnnotator.markAsExtraApi(f, k)) as E; return { name: config.name, partFields: config.partFields, configFields: config.configFields, sketch, parts, ...apis, ...extraApis }; }; export { single, composite };