Skip to content

Match and Union ​

Example ​

Input Markdown ​

md
## 3. EVENTS

### [00:00-01:00] - Introduction

**NARRATION:**
Lesson overview and expected outcomes.

**VISUAL:**
Timeline showing all lesson segments.

Schema ​

ts
import { md } from '@markschema/mdshape'

const intentSchema = md.discriminatedUnion('type', [
  md.object({ type: md.literal('NARRATION'), text: md.string().min(10) }),
  md.object({ type: md.literal('VISUAL'), text: md.string().min(10) }),
])

const schema = md.document({
  intents: md
    .section('3. EVENTS')
    .subsections(3)
    .each(
      md.object({
        intents: md.match
          .labels(['NARRATION', 'VISUAL'])
          .entries({ nameKey: 'type', contentKey: 'text' })
          .each(intentSchema),
      }),
    ),
})

Result ​

Success ​

json
{
  "success": true,
  "data": {
    "intents": [
      {
        "intents": [
          {
            "type": "NARRATION",
            "text": "Lesson overview and expected outcomes."
          },
          {
            "type": "VISUAL",
            "text": "Timeline showing all lesson segments."
          }
        ]
      }
    ]
  }
}

Error ​

json
{
  "success": false,
  "error": {
    "issues": [
      {
        "code": "missing_section",
        "message": "Missing section \"3. EVENTS\"",
        "path": [
          "intents"
        ],
        "line": 1,
        "position": {
          "start": {
            "line": 1,
            "column": 1
          }
        }
      }
    ]
  }
}

Right vs Wrong ​

  • Right: use md.literal(...) in every discriminated variant.
  • Wrong: use md.string() for the discriminator and lose deterministic variant routing.

Common error: mixing labels([...]).values(...) (simple values) with entries(...).each(...) (typed objects).