YAML + Zod
YAML + Zod ↗ makes a neat pair for configurations or DSLs.
Error reporting with line and column
Section titled “Error reporting with line and column”When Zod validation fails, it gives back the path to the offending value (e.g. ["resources", 0, "type"]). The yaml ↗ package can parse YAML into an AST that retains source positions. Combining the two, you can point the user to the exact line and column in their YAML file:
import { LineCounter, Node, ParsedNode, parseDocument, Scalar, YAMLMap, YAMLSeq, parse as parseYaml,} from "yaml";import { ZodError } from "zod";
type Path = (string | number)[];
function traverseAst( ast: ParsedNode | null | Scalar<ParsedNode | null>, path: Path): null | Node { if (path.length === 0 || ast === null) return ast; const [current, ...rest] = path; if (ast instanceof YAMLMap) { return traverseAst(ast.get(current, true) ?? null, rest); } if (ast instanceof YAMLSeq) { return traverseAst(ast.get(current, true) ?? null, rest); } throw new Error(`Unexpected node type: ${ast.constructor}`);}
function getLineCol(file: string, path: Path) { const lineCounter = new LineCounter(); const ast = parseDocument(file, { keepSourceTokens: true, lineCounter, }); const srcToken = traverseAst(ast.contents, path)?.srcToken; if (srcToken) return lineCounter.linePos(srcToken.offset);}
function constructError( message: string, path: Path, file?: string) { const pos = file ? getLineCol(file, path) : undefined; return new Error( `${message} ${pos ? `at ${pos.line}:${pos.col} ` : ""}(${path.join("/")})` );}Then in the parse function, catch ZodError and map it to a user-friendly message:
import { mySchema } from "./schema.js";
function parse(file: string) { const rawData = parseYaml(file); try { return mySchema.parse(rawData); } catch (e) { if (e instanceof ZodError) { const path = e.errors[0].path; throw constructError(e.errors[0].message, path, file); } throw e; }}This gives errors like: Wrong value "ec2" at 3:12 (resources/0/type) instead of a generic Zod message.
IDE autocomplete via JSON Schema
Section titled “IDE autocomplete via JSON Schema”Zod schemas can be converted to JSON Schema with zod-to-json-schema ↗. Once you have a JSON Schema, the YAML extension for VS Code ↗ provides autocomplete and validation in the editor.
You can also use an inlined schema ↗ comment at the top of the YAML file:
# yaml-language-server: $schema=https://example.com/schema.jsonSo the workflow is:
- Define your schema with Zod (single source of truth)
- Use it at runtime for validation with precise error locations
- Convert to JSON Schema for IDE support
Real-world example
Section titled “Real-world example”diagrams-as-code ↗ uses this approach. YAML serves as the DSL for describing infrastructure diagrams, Zod validates the structure, and errors point to exact positions in the source file.