Grouping snippets
How Kiira groups code fences — by default each fence is an isolated module, but fences sharing a group= id are type-checked together in document order so later snippets can use earlier declarations.
The default: isolated fences
By default, each fence is checked as its own isolated module. That means a fence cannot see declarations from a fence above it. This snippet fails on its own because user is never defined:
``tsconsole.log(user.name)``Grouping with group=
When you give two or more fences the same group= id, Kiira type-checks them together, in document order — concatenating them into a single virtual module. A later fence can use a const (or any declaration) from an earlier fence in the same group:
``ts group=walkthroughconst user = getUser()``Some explanatory prose between the snippets``ts group=walkthroughconsole.log(user.name) // ✅ `user` is in scope from the first fence``This is exactly how step-by-step tutorials read: each fence builds on the last. Grouping lets you split a single coherent example across several fences with prose in between, while still type-checking it as one program.
Auto-detected continuations
Kiira auto-detects when an ungrouped fence is really a continuation of an earlier one (for example, it references a symbol declared above). When detected:
- During a normal
kiira check, Kiira treats them as a continuation so you get meaningful results instead of spurious "cannot find name" errors. - Running
kiira check --fixwrites explicitgroup=tags onto those fences so the relationship is recorded in the Markdown:
<!-- after `kiira check --fix` -->``ts group=example-1const user = getUser()````ts group=example-1console.log(user.name)``Adding the tags yourself is always fine, and it makes intent explicit for readers and other tooling.
File-level grouping for literate docs
If your docs are literate — one fence sets up imports and values, and later fences build on them throughout the page — tagging every fence with group= doesn't scale. Set defaultGroup: "file" in your config and Kiira groups every checkable fence in a file into one implicit group, in document order, as if you'd stamped the same group= on each:
import { defineConfig } from "kiira-core"export default defineConfig({ include: ["docs/**/*.{md,mdx}"], defaultGroup: "file", // "none" (default) | "file"})Now this page type-checks with no annotations — the second fence resolves greeting from the first:
``tsconst greeting = "hello"``Some prose``tsconsole.log(greeting.toUpperCase()) // ✅ resolved from the fence above``You can scope it per directory with per-glob overrides — for example, file-group your guides but keep an isolated reference section:
defaultGroup: "file",overrides: [{ include: ["docs/reference/**"], defaultGroup: "none" }],Detaching a fence with group=none
File grouping concatenates every fence, so two fences that each redeclare the same name (e.g. showing two alternatives that both do const backend = …) would now collide with TS2451 Cannot redeclare. Detach one with group=none to restore its isolation:
``tsconst backend = new RedisBackend()````ts group=noneconst backend = new MemoryBackend() // ✅ checked on its own, no redeclare``group=none (and an explicit group=<id>) always wins over defaultGroup. Fences marked ignore or validate=none are left out of the group entirely, exactly as without file grouping.