Documentation / Développement / Guides pratiques / Add value-sets, dimensions, types and conversions

Add value-sets, dimensions, types and conversions

Before a node can declare a coded, quantity or object port, the terminology, dimension or datatype it points at has to exist. This recipe walks the four vocabulary contribution points that back those ports — value-sets, dimensions, types and conversions — using one consistent example: an estimated GFR result.

Everything below lives under contributes: in your plugin.yaml. For the full field list and semantics of every section see the plugin manifest reference; for the shape of the type: blocks see the TypeRef reference. If you don't have a plugin skeleton yet, scaffold one first.

Before you start

The host applies contributions in a fixed order: value-sets → dimensions → types → conversions → nodes → adapters → agents → eventSources → eventBindings. So a value-set or dimension is always registered before the type that uses it, and a type before the node or conversion that references it. Author each section in the same order and forward references resolve on their own.

A malformed contribution — or one referencing an unknown value-set, dimension or type — is logged and skipped; the rest of the plugin still loads. A port whose type can't be resolved makes its node get skipped too, so keep the identifiers below in sync.

Add a value-set

A value-set is the terminology behind a coded type. Enumerate its concepts, or mark it external: true when a terminology server resolves the codes at runtime.

contributes:
  valueSets:
    - id: renal-stage
      system: urn:acme:renal-stage
      doc: KDIGO chronic-kidney-disease stage.
      concepts:
        - { code: G1, display: "G1 — normal or high (≥ 90)" }
        - { code: G2, display: "G2 — mildly decreased" }
        - { code: G3, display: "G3 — moderately decreased" }
        - { code: G3a, display: "G3a", parent: G3 }   # optional hierarchy
  • id is the identifier a { kind: coded, valueSet: <id> } type points at.
  • system is the code-system URI.
  • doc is required; concepts[].parent is optional and only records hierarchy.
  • Set external: true and leave concepts: [] for a server-resolved terminology (SNOMED CT, LOINC, …). An enumerated value-set codegens to a literal union of its codes; an external one falls back to string.

For the ops side — pointing an instance at a terminology server — see Configure terminology.

Add a dimension

A dimension gives quantity types their UCUM unit checking: a canonical unit plus the factor from each accepted unit to it.

contributes:
  dimensions:
    - name: filtration-rate
      label: Glomerular filtration rate
      canonical: "mL/min/{1.73_m2}"
      units:
        - { symbol: "mL/min/{1.73_m2}", toCanonical: 1 }
  • name is the identifier a { kind: quantity, dimension: <name> } type points at.
  • canonical is the reference unit; every units[].toCanonical is the multiplier that converts that unit's values into the canonical one (the canonical unit itself is 1).
  • List every unit you want accepted on ports of this dimension.

Add a type

A type is an explicit descriptor: each field carries a TypeRef, a required flag and an optional doc. layer is datatype (reusable building blocks) or resource (clinical resources). This is where the value-set and dimension above get consumed.

contributes:
  types:
    - name: EgfrResult
      doc: Estimated GFR (value + equation + stage).
      layer: resource
      fields:
        value:    { type: { kind: quantity, dimension: filtration-rate }, required: true }
        equation: { type: { kind: primitive, name: String }, required: true }
        stage:    { type: { kind: coded, valueSet: renal-stage }, required: true }
  • name is what an { kind: object, name: <name> } port references.
  • doc is required on the type; fields.<field>.doc is optional.
  • A type owned by a dependsOn plugin is referenced by name and resolved across the dependency closure — codegen imports it from the owning package, you don't redeclare it.

See the TypeRef reference for every kind (primitive, coded, quantity, object, ref, list, any), and the type system for why datatypes and resources are layered this way.

Add a conversion

A registered conversion powers the transform.convert node (and the editor's auto-insert when two wired ports need bridging). from/to are type names — a registered type or a primitive — and expr is a JEXL expression evaluated over value, the input.

contributes:
  conversions:
    - from: EgfrResult
      to: Decimal
      label: eGFR → number
      expr: value.value.value

Here the input is an EgfrResult, so value.value is its quantity field and value.value.value is the numeric measure. Register one conversion per from/to pair you want the platform to offer.

Verify

  1. Validate the manifest — this catches an unresolved value-set/dimension/type reference before you ship:

    meridian-plugin validate
    
  2. Regenerate the typed client so EgfrResult, the renal-stage code union and the rest surface in TypeScript — see Generate types:

    meridian-plugin generate
    
  3. Build and bundle with meridian-plugin build (esbuild), then publish to the registry when ready.

Next steps

  • Reference the new types from typed ports in Implement a node behavior.
  • Localize the labels and docs you added in Translate a plugin.
  • Map these types onto FHIR resources: FHIR mapping (apps/ehr-lab/docs/resources/reference/fhir-mapping.md).
  • Background on how the registries fit together: type system registries and the plugins concept.
75 documents7 sectionssource : /docs · généré au build