SchemaController
The Schema is the central hub for all data invariants, and metaData associated with the data-model itself. Outside of the types defined in the JSON payload, it doesn’t manage or keep any state. It simply serves as an orchestrator for other modules to interface w/ the schema.
Despite that role, SchemaController lives in schema/, not controllers/ — a naming quirk worth calling out, since it plays the same per-flow orchestrator role as DataController, ValidationController, and friends.
Key Files
Section titled “Key Files”core/player/src/schema/schema.ts—SchemaControllerclass and theparse()function that expands an authored schemacore/player/src/schema/types.ts—FormatDefinition,FormatOptions,FormatType
Construction
Section titled “Construction”constructor(schema?: SchemaType.Schema)SchemaController is constructed once per player.start(flow) call from userFlow.schema, before the DataController or ValidationController (both of which depend on it). See Start to Render for exactly where it’s wired up. Player calls this.hooks.schema.call(schema) right after construction so plugins can register data types and formatters via addDataTypes/addFormatters.
Expanding the Schema
Section titled “Expanding the Schema”The authored schema block is a graph of named nodes (ROOT plus any referenced types). The module-level parse() function walks that graph breadth-first and flattens it into a Map<string, DataType> keyed by dotted path (arrays get a trailing [] segment, records get {}) — this becomes schema.schema, the controller’s read-only lookup table. It throws if it detects a cycle, since a self-referencing schema would recurse forever.
Binding Lookups
Section titled “Binding Lookups”getType(binding)— normalizes aBindingInstance(numeric array indices become[], matching howparse()recorded them) and looks up the flattened map, then runs the result through theresolveTypeForBindinghook.getApparentType(binding)— callsgetType, then merges in the base type definition registered viaaddDataTypes(if the schema type references one viatype), concatenatingvalidationarrays from both. This is the “effective” type authors think of when they addvalidation,format, ordefault.getValidationsForBinding(binding)— readsgetApparentType(binding)?.validation, filling in defaults (severity: "error",trigger: "change") for any validation reference that omits them. This is the method that makesSchemaControllerimplement theValidationProviderinterface that ValidationController consumes as one of its two validation sources (schema-level, alongside cross-field/view validations).getFormatter(binding)— resolves the apparent type’sformatreference against the formatters registered viaaddFormatters, returning{ format, deformat }functions (orundefinedif none is registered). DataController calls this from itsformat/deformathook taps.
Hooks / Extension Points
Section titled “Hooks / Extension Points”| Hook | Type | Gives you | Use it when… |
|---|---|---|---|
resolveTypeForBinding | SyncWaterfallHook<[SchemaType.DataTypes | undefined, BindingInstance]> | The schema type looked up for a binding (possibly undefined), plus the binding itself | You want to override or synthesize a type for bindings that aren’t explicitly in the authored schema |
Relationship to Other Subsystems
Section titled “Relationship to Other Subsystems”- Schema (content reference) and Schema (authoring guide) cover what you author in the
schemablock; this page covers what runs it at runtime - Data Formatting and Deformatting — the guide for the formatter references
getFormatterresolves - ValidationController — consumes
SchemaControlleras aValidationProviderfor schema-level validations - DataController — uses
SchemaController’s formatters for itsformat/deformathooks and itsdefaultvalues forresolveDefaultValue