Accept comments and unquoted keys in a JSON config file
Parse a hand-edited config with a lenient JSON dialect, so comments, trailing commas and unquoted keys load instead of failing on one character.
How-to › Section 15
Reading the formats integrations depend on, building parsers from grammars, validating shapes at boundaries, and transforming nested data.
10 guides in 4 topics. Every guide compares its approaches and shows the output its commands printed.
Each format and when to choose it: JSON, JSONC, JSON5, jsonic (unquoted keys, comments, implicit top level, plugins, jsonic-cli), YAML, TOML, INI, CSV (RFC 4180, headers, custom separators, streaming, strict and lenient modes), XML, Markdown, CSS, JSON Lines, Atom and RSS feeds, protobuf IDL and Zon; error positions, streaming large files, when lenient input is the wrong choice.
Parse a hand-edited config with a lenient JSON dialect, so comments, trailing commas and unquoted keys load instead of failing on one character.
Give a lenient parser to files people edit and a strict one to bodies programs send, keep the loaders apart, and let a test refuse a lenient import at the boundary.
Pull a shared fragment into a config file with @tabnas/multisource, track where each value came from, and refuse cycles and paths that leave the config directory.
Building a parser for your own format: ABNF (RFC 5234) compiled to a rule table with @tabnas/abnf (a state machine as data, not generated parser code), attaching behavior by rule name, extending an existing grammar without forking, inspecting with @tabnas/debug, railroad diagrams, the support libraries (expr, path, directive, hoover, multisource), an LSP and playground for your format, benchmarking with measure, and emitting GBNF for constrained decoding; against peggy, ohm, chevrotain, nearley, ANTLR, tree-sitter, Lark and hand-written recursive descent.
Keep the grammar as plain ABNF, bind behavior to the rule names the compiler assigns, and test that every handler still names a rule and fires after a rename.
Turn on error recovery in chevrotain, ANTLR, tree-sitter or Lark, collect every error in one pass, and test that recovery keeps its place inside nested brackets.
Rewrite a left-recursive rule so peggy accepts it, fold the action from the left to keep subtraction left-associative, and compare with ohm-js and nearley.
Parse a filter language with a tokenizer, a method per grammar rule, and peek and expect helpers, then measure it against the same grammar in peggy and chevrotain.
Runtime validation of inputs, config and SDK responses, and exporting JSON Schema from a validator (for tool definitions and OpenAPI alike): Zod, Joi, Yup, Valibot, ArkType, io-ts, AJV with JSON Schema, Pydantic, go-playground/validator, and gubu (a schema that looks like the data, Required, Optional, Default, Min, Max, One, Exact, Check, Coerce, Email, Url, Uuid, JSON Schema export, TypeScript and Go).
Write the schema as an example of an accepted value, with constructors for types and literals for defaults, so schema and sample read side by side.
Getting, setting, merging, walking, injecting and transforming nested structures, and flattening API responses for analysis: lodash, ramda, immer, jq, JSONPath, JSON Pointer, json-patch, deepmerge, pandas.json_normalize, and struct (getpath, setpath, merge, walk, inject, transform, validate, flatten, ported to 23 languages at parity).
Layer defaults, file, environment and flags with a deep merge so a later source overrides only the keys it sets, and clone first because merge mutates.
Read a deep value by a path held as a string, so a response mapper is a table of paths rather than a chain of optional accesses written out once per field.
Retries, timeouts, pagination and auth are the same problems in every client. Voxgig generates them from your OpenAPI description, in 23 languages, from one model.
Since 2018, Richard Rodger has talked with developer advocates, event organizers, and the people who build developer-facing companies about the specifics of the work.