Kiira
ChevronDown
Github

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:

``ts
console.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=walkthrough
const user = getUser()
``
Some explanatory prose between the snippets
``ts group=walkthrough
console.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 --fix writes explicit group= tags onto those fences so the relationship is recorded in the Markdown:
<!-- after `kiira check --fix` -->
``ts group=example-1
const user = getUser()
``
``ts group=example-1
console.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:

``ts
const greeting = "hello"
``
Some prose
``ts
console.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:

``ts
const backend = new RedisBackend()
``
``ts group=none
const 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.

Info

Tip

Turning on defaultGroup: "file" makes Kiira stop suggesting group= fixes for that file — there's nothing left to group.