Go library for KDL 2.0.0.
  • Go 99.1%
  • Nix 0.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
shimeoki 1cacbe5c26
refactor!: remove ParseError and improve errors
instead of doing that at the parse level, i moved
some logic to the scanner. maybe not very good
and should be done in one place instead, but okay
for now.

two biggest changes for QoL:

1. errors specify both the start and the end
2. some errors include a hint

with the first point they are now less confusing,
because it was showing the start of the token.

with the second point it's probably going to be
more clear that a document is expected to be a v2,
because hint tells to "use a hash".

that is a breaking change, because i removed
ParseError (not confident it is even needed right
now). may be, once again, reconsidered later, but
only when i am going to be sure that is a good
design
2026-09-18 23:47:56 +03:00
testdata test: finish official tests 2026-08-29 15:42:49 +03:00
.gitignore chore: gitignore with covers 2026-08-29 15:42:48 +03:00
arshal_test.go refactor!: remove NewNumber 2026-09-18 17:03:24 +03:00
compress.go docs: remove blank line before Compress 2026-09-07 12:58:39 +03:00
debug.go refactor: debug.go 2026-08-29 15:42:49 +03:00
example_test.go fix: nil access in example for Nodes() append 2026-09-18 17:03:24 +03:00
flake.lock chore: update flake 2026-08-29 15:42:49 +03:00
flake.nix chore: justfile 2026-09-18 17:03:24 +03:00
format.go fix: resets 2026-09-02 21:53:55 +03:00
go.mod feat!: bump go to 1.27 2026-08-31 16:40:32 +03:00
is.go refactor: separate is.go file 2026-09-02 21:53:55 +03:00
justfile chore: no cgo in justfile 2026-09-18 17:03:24 +03:00
kdly_test.go refactor: new (un)marshaling 2026-09-07 12:58:40 +03:00
LICENSE initial public commit 2026-06-08 17:17:59 +03:00
marshal.go refactor!: remove NewNumber 2026-09-18 17:03:24 +03:00
node.go refactor!: remove Type 2026-09-18 17:03:24 +03:00
node_test.go test: node.go 2026-09-18 17:03:24 +03:00
number.go refactor!: remove ParseError and improve errors 2026-09-18 23:47:56 +03:00
parse.go refactor!: remove ParseError and improve errors 2026-09-18 23:47:56 +03:00
parse_test.go refactor: move lexer to the root package 2026-08-29 15:42:49 +03:00
read.go refactor!: remove ParseError and improve errors 2026-09-18 23:47:56 +03:00
README.md refactor!: remove Type 2026-09-18 17:03:24 +03:00
reflect.go fix: check name in type indexing 2026-09-18 17:03:24 +03:00
scan.go refactor!: remove ParseError and improve errors 2026-09-18 23:47:56 +03:00
scan_test.go refactor: move lexer to the root package 2026-08-29 15:42:49 +03:00
string.go refactor!: remove ParseError and improve errors 2026-09-18 23:47:56 +03:00
string_test.go feat: stringer 2026-08-29 15:42:49 +03:00
token.go refactor: move lexer to the root package 2026-08-29 15:42:49 +03:00
treefmt.nix docs: readme with license and credits 2026-08-29 15:42:49 +03:00
unmarshal.go refactor!: remove Type 2026-09-18 17:03:24 +03:00
value.go refactor!: remove Type 2026-09-18 17:03:24 +03:00
write.go fix: resets 2026-09-02 21:53:55 +03:00

kdly

Go Reference

kdly is a Go library for KDL 2.0.0. It does not support KDL v1 in any way. If you need an implementation for 1.0.0, please see other implementations.

Features

  • Strict KDL v2 compliance with no v1 support and without any extensions.
  • Open and simple design focused on fully exported parse tree structures.
  • Format- and comment-preserving scanner/parser.
  • Formatting (WIP)
  • Compressing (WIP)
  • (Un)marshaling (WIP)

The library requires at least Go 1.27 and has no module dependencies.

Credits

While no code was taken directly, first revisions of this library were heavily inspired from kdl-go by sblinch on GitHub. Also, many architectural decisions are influenced by the standard library (GitHub), as well as some implementation details.

License

Files in the testdata folder are taken from the official KDL test suite. They are distributed under CC BY-SA 4.0 license.

Source code in this project is distributed under BSD-3-Clause license.

Issues

The project is still in 'alpha'. API is not stable and there are not enough tests to guarantee that all features work correctly. However, most design decisions are unlikely to change.

There are some issues, limitations and other known things about the project that don't work as expected.

  • Some multi-line comment sequences are not recognized properly. For example, /*/*/.

  • Single- and multi-line comments are recognized as separate tokens with their own contents. However, slashdashes are recognized as a simple /- sequence. The parser allows any combinations of tokens in slashdashed elements, but these tokens should be well-formed. This means, that if a slashdashed element has, for example, an invalid string, then the parse won't succeed.

  • Formatting is not properly tested, so use it with caution on real documents.

  • (Un)marshaling is not properly tested and is in the state of a rewrite.

Compatibility

While the library is not stable yet (no major version or it is zero), breaking changes can be done without prior notice. Please be careful when using and updating the library at this stage.

However, the project is already able to give some non-formal compatibility guarantees even in this state:

  • The behavior listed in the issues should not be depended upon: it's either non-final or is a bug. That is also the case for undocumented (un)marshaling behavior.

  • Parse tree types (Document, Node and other types used in them) are not expected to be changed any time soon. However, some functions or methods related to them (to be precise, NewDocument(), Document.Bind() and Version()) may be changed.

  • Logic for converting Number or String types to other types is guaranteed only in terms of KDL specification. For example, conversion of a Number to a Go primitive right now is done via strconv, and can be more forgiving than the permitted KDL syntax. The underlying implementation can be changed to remove this behavior.

Documentation

While KDL looks very similar to JSON, it is a node-based language like XML. Therefore, in KDL, two nodes on a single level with the same name are allowed, and their order matters.

As said in encoding/xml, these types of data collections cannot be represented easily in Go. Structs are single key-value pairs, and while order of the fields is impotant, most of the time it is unused.

Because of that, the library provides a first-class support for it's own data types like Document and Node, which are able to represent any valid KDL document byte-by-byte. These types are fully public and used almost everywhere.

(Un)marshaling is also supported, but uses it's own set of rules and the aforementioned Document type. If you need more manual control, then please use the types directly instead.

Quickstart

A single KDL document is mapped to a single Document struct. A KDL document is a whole file or data stream until EOF. To either parse or format a single document, use the Parser and Formatter types:

// error and file handling removed for brevity

f, err := os.Open("input.kdl")
doc, err := kdly.NewParser(f).Parse()

// do anything you want to 'doc'
doc.Nodes = append(kdly.Version(), doc.Nodes...)

f, err = os.Open("output.kdl")
err = kdly.NewFormatter(f).Format(doc)

If you need to work with freeform Go values, then use (un)marshaling via NewDocument() and Document.Bind():

type Config struct {
  Version int `kdly:"version"`
}

cfg := Config{Version: 1}
doc, err := kdly.NewDocument(cfg)
f, err := os.Open("config.kdl")
err = kdly.NewFormatter(f).Format(doc) // version 1

cfg = Config{}
f, err = os.Open("config.kdl")
doc, err = kdly.NewParser(f).Parse()
err = doc.Bind(&cfg) // cfg.Version = 1