Value maps: technical reference
This page describes the current implementation contract for developers and maintainers. The authoring guide covers UI workflows. The model/resolver is generic; the List element is currently the only element integration. Template-specific APIs retain their List naming and are opt-in imports.
Persisted schema
Maps are stored in the optional ILayoutRoot.valueMaps array. A map is identified by its name within that layout, without a separate global identifier.
type TValueMapOutputType = 'text' | 'number' | 'boolean' | 'asset' | 'textTemplate' | 'htmlTemplate'
type TValueMapTextEditor = 'plain' | 'icon' | 'libraryIcon' | 'color'
type TValueMapOutputValue = string | number | boolean
interface ValueMapShape {
name: string
outputs: {
key: string
type: TValueMapOutputType
editor?: TValueMapTextEditor // Text outputs only
}[]
rows: {
match: 'equals' | 'range'
value?: string // Equals comparison text
from?: number // Range lower bound
to?: number // Range upper bound
fromExclusive?: boolean
toExclusive?: boolean
values: Record<string, TValueMapOutputValue>
}[]
fallback?: { values: Record<string, TValueMapOutputValue> }
}
This is an explanatory shape; import the actual IValueMap, IValueMapOutput, IValueMapRow and IValueMapValues types from @insynergie/neuroomnet-server-mediacontrol/common/control.
Validation responsibilities
The common ValueMaps schema rule validates structure and relationships between definitions and row values. Map names/output keys must be non-empty and unique in their scope. Keys __proto__, prototype and constructor are rejected. Values must be own properties of a plain or null-prototype record, declared in outputs, and have the exact required scalar type. Number values and bounds must be finite. Text editor hints apply only to Text outputs. Null/array/object outputs and the earlier fixed-output draft format are invalid.
Sparse records are valid. The schema does not synthesize missing keys, coerce types or merge fallback values. Empty or shadowed matching conditions are handled by advisory diagnostics rather than silently reordered. valueMapDiagnostics exposes the shared rule analysis used by the editor.
Template syntax validation is separate: getValueMapTemplateErrors(layout) parses every stored Text/HTML template value in each rule/fallback and returns field-addressed errors. Ordinary Text values are not parsed as templates. Server save and import/editor boundaries apply the appropriate checks. Parse-valid source can still fail during rendering, for example on an unknown helper.
Raw resolver API
Import from @insynergie/neuroomnet-server-mediacontrol/common/control/valueMapResolve. This module has no Handlebars dependency. Callers supply a map object rather than a map-name dictionary.
| Function | Result |
|---|---|
matchesValueMapRow(row, input) | Whether the condition matches the input. |
resolveValueMap(map, input) | The first matched row or fallback; otherwise undefined. |
resolveValueMapOutput(map, input, key) | { row, output, value } for a declared own output in the selected result; otherwise undefined. |
getValueMapOutput(map, input, key) | The raw string/number/boolean value or undefined. |
An undefined map returns no result. Unsafe/undeclared keys and absent own values return undefined. An absent value in a matching rule does not cause another rule/fallback lookup. No function executes source, emits HTML, adds metadata or writes variables.
import type { IValueMap } from '@insynergie/neuroomnet-server-mediacontrol/common/control'
import { getValueMapOutput } from '@insynergie/neuroomnet-server-mediacontrol/common/control/valueMapResolve'
const map: IValueMap = {
name: 'Availability',
outputs: [{ key: 'available', type: 'boolean' }],
rows: [{ match: 'equals', value: 'offline', values: { available: false } }],
}
const available = getValueMapOutput(map, 'offline', 'available')
// available === false; do not replace it using a truthiness fallback.
Matching uses string-form Equals and finite numeric Range conversion as described in matching rules. A future consumer should reuse these functions rather than implementing a second interpretation.
Template rendering API
Import explicitly from @insynergie/neuroomnet-server-mediacontrol/common/control/listTemplate. The general control barrel does not load the renderer. It uses an isolated Handlebars instance so helper registration does not alter unrelated Handlebars users.
interface RenderOptionsShape {
assetUrl?(reference: string): string | undefined
poolIconUrl?(key: string): string | undefined
valueMaps?: Record<string, IValueMap>
}
interface RenderResultShape {
html: string
rowClasses: string[]
diagnostics: {
code: 'syntax' | 'render' | 'missing-reference' | 'type' | 'cycle' | 'depth' | 'row'
message: string
map?: string
key?: string
line?: number
column?: number
}[]
}
The actual exported interfaces are IListItemRenderOptions, IRenderedListItem and IRenderDiagnostic. renderListItemResult(template, item, options?) returns the structured result. renderListItem(...) is a string facade returning only HTML; use the structured result when row metadata or diagnostics matter.
getTemplateSyntaxError(source) checks syntax without executing source. getListItemTemplateError(source) supports the item editor's check by rendering against an empty context and can also reveal unknown helpers. getValueMapTemplateErrors(layout) checks stored fragment syntax with field locations.
Rendering guarantees
mapreturns raw typed values/source and contributes no metadata.renderMapaccepts only Text/HTML template definitions, preserving caller context/root and supplying local input/outputs.- HTML source retains authored markup; ordinary data is escaped. Text results stay strings and normal outer insertion escapes once. Triple braces deliberately bypass that escaping.
- Each nested call has an isolated frame. Child data is restored on return. Asset/library resolvers and loop data are retained.
- Active
(map object, selected row object, output key)tuples detect cycles. At most 32 active fragment frames are allowed; subsequent nesting fails locally. Sequential reuse is valid. - A fragment execution failure yields empty fragment content and discards its partial classes, with a diagnostic. Surrounding successful content/classes survive. It does not retry fallback.
- Text-mode results never contribute row classes, including nested HTML declarations. HTML metadata combines only from successful frames.
- Outer template execution failure returns empty HTML and classes. Rendering does not mutate authored maps or write runtime variables.
Source/mode compilation uses a bounded cache of 100 entries. Each render creates its own metadata/diagnostic frame; cached compilation does not share item state. Consumers should treat helper output according to its type rather than attempting automatic string recursion.
Reference and rename APIs
Import from @insynergie/neuroomnet-server-mediacontrol/common/control/templateReferences. The parser loads Handlebars explicitly. Current default providers discover List item templates and all stored map template outputs, including fallback.
| Contract/API | Purpose |
|---|---|
IValueMapConsumerLocation | kind: 'element' | 'map', index, optional name, property and optional numeric row/'fallback'. |
IValueMapConsumer | Location plus optional template source/contextMap or a structured {name, key} reference. |
TValueMapConsumerProvider | Function from a layout to consumer records. |
collectValueMapReferences(layout, providers?) | Parsed references with consumer, mapName/outputKey where known, status and optional line. |
filterValueMapReferences(references, mapName, key?) | Known targets plus unresolved potential matches; never guesses a target. |
valueMapUsages(layout, map, key?) | Consumer descriptions used in deletion feedback. |
renameValueMap(layout, map, name) | Mutates the map name and provable current references; returns warnings. |
renameValueMapOutput(layout, map, index, key) | Mutates definition/stored values/provable references; returns warnings. |
Reference status is literal, dynamic or invalid. Literal identifies parsed constant names/keys; it does not guarantee that the referenced definition still exists. Repeated equivalent references within one consumer are deduplicated. Dynamic/unparseable references remain potential uses in filters.
To extend discovery, pass [...valueMapConsumerProviders, additionalProvider] to the collector; the exported default provider array is readonly. A provider can describe a future structured reference without changing the collector or usage-table model. This prepares reference discovery; it does not add a binding schema, rendering logic or safe rename handling for a new element. A future integration must implement and test those responsibilities deliberately.
Literal rename uses parsed source locations, not global string replacement. It follows map/renderMap calls and, for the owning map, @outputs paths and literal lookup keys. Dynamic references, malformed source and ambiguous duplicate names/keys are left for review rather than retargeted to an arbitrary map.
Asset lifecycle APIs
Import from @insynergie/neuroomnet-server-mediacontrol/common/control/layoutAssets.
| API | Behaviour |
|---|---|
documentLayouts(document) | Finds direct json, template.json and page-panel embedded control-template layouts, including JSON-string representation. |
transformDocumentLayouts(document, transform) | Transforms all those layouts on a structured clone, preserving string/object representation and unrelated fields. |
collectDocumentAssetIds(document) | Sorted unique non-empty structured image/draggable IDs and typed Asset values in every rule/fallback. |
clearDocumentAssetReferences(document) | Clones, clears those structured references and removes the private top-level usage index for export. |
Stored template source, ordinary Text outputs and runtime item data are deliberately excluded from usage tracking. Server save/startup backfill derives _assetIds from saved structured references. That index is private persistence data, not an author-supplied protocol/export field. Asset deletion checks saved usage and rejects in-use IDs. Releasing a reference requires saving its removal.
Export keeps schema definitions and source but empties typed Asset IDs, image lists and draggable file IDs throughout all contained layouts. False, zero and empty text survive. Import validates before modifying the working copy; media assignment is destination-specific.
Extension boundaries
The retained preparation consists of typed generic maps, the dependency-free resolver, shared validation/diagnostics, asset traversal and the provider-based reference model. There is no unused universal property-binding model, global map catalogue, override layer, write-target abstraction or binding UI for other elements.
A future element can resolve a Number/Boolean/Text/Asset output directly without adopting HTML templates or list classes. It must define its input/reference schema, acceptable output types, unset behaviour, change reactivity and element-specific application of the result. It must also integrate reference/rename/delete feedback and export/asset handling where applicable. row and listItem-* remain List presentation details rather than requirements of the generic map model.