import type { FieldProcessor } from '@ephox/boulder'; import { Obj } from '@ephox/katamari'; import * as AlloyParts from '../../parts/AlloyParts'; import type { PartTypeAdt } from '../../parts/PartType'; import * as Tagger from '../../registry/Tagger'; import * as SpecSchema from '../../spec/SpecSchema'; import type { AlloySpec, SketchSpec } from '../component/SpecTypes'; import type { CompositeSketchDetail, CompositeSketchSpec, SingleSketchDetail, SingleSketchSpec } from './Sketcher'; export type SingleSketchFactory = (detail: D, specWithUid: S) => SketchSpec; export type CompositeSketchFactory = (detail: D, components: AlloySpec[], spec: S, externals: any) => SketchSpec; const single = (owner: string, schema: FieldProcessor[], factory: SingleSketchFactory, spec: S): SketchSpec => { const specWithUid = supplyUid(spec); const detail = SpecSchema.asRawOrDie(owner, schema, specWithUid, [ ], [ ]); return factory(detail, specWithUid); }; const composite = (owner: string, schema: FieldProcessor[], partTypes: PartTypeAdt[], factory: CompositeSketchFactory, spec: S): SketchSpec => { const specWithUid = supplyUid(spec); // Identify any information required for external parts const partSchemas = AlloyParts.schemas(partTypes); // Generate partUids for all parts (external and otherwise) const partUidsSchema = AlloyParts.defaultUidsSchema(partTypes); const detail = SpecSchema.asRawOrDie(owner, schema, specWithUid, partSchemas, [ partUidsSchema ]); // Create (internals, externals) substitutions const subs = AlloyParts.substitutes(owner, detail, partTypes); // Work out the components by substituting internals const components = AlloyParts.components(owner, detail, subs.internals()); return factory(detail, components, specWithUid, subs.externals()); }; const hasUid = (spec: S): spec is S & { uid: string } => Obj.has(spec as any, 'uid'); const supplyUid = (spec: S): S & { uid: string } => { return hasUid(spec) ? spec : { ...spec, uid: Tagger.generate('uid') }; }; export { supplyUid, single, composite };