1
0
Fork
You've already forked kdl
0
A parser and stringifier for the KDL Document Language
  • JavaScript 99.7%
  • Shell 0.3%
Bram Gotink c769afc7aa
{refactor} replace switch with or-chain
This yields an extra 1% speed boost! No but seriously,
it was weird to have that one function that used a
switch where all others used an or-chain.
2026年06月03日 23:26:53 +02:00
.config {chore} switch to @dot-config/husky 2025年01月10日 21:07:12 +01:00
.github/workflows {chore} switch pipeline to mdbook 5 2026年04月08日 22:49:06 +02:00
.vscode {feature} initial commit 2022年06月26日 14:39:24 +02:00
.yarn/releases {chore} bump deps, remove kdljs dependency 2025年02月06日 22:12:31 +01:00
.zed {chore} configure zed to use prettier 2024年04月05日 21:40:47 +02:00
documentation {chore} bump mdbook to v5 2026年04月08日 22:35:19 +02:00
scripts {feat} iterate over codepoints via index for perf gains 2026年06月03日 23:24:25 +02:00
src {refactor} replace switch with or-chain 2026年06月03日 23:26:53 +02:00
test {fix} smol issue in number stringifier 2026年03月26日 20:59:01 +01:00
.editorconfig {feature} update to KDL 2.0.0-draft.4 2024年02月17日 12:00:55 +01:00
.gitignore {feature} initial commit 2022年06月26日 14:39:24 +02:00
.gitmodules {feature} add kdl-test tests 2026年03月26日 20:15:18 +01:00
.yarnrc.yml {chore} bump deps, remove kdljs dependency 2025年02月06日 22:12:31 +01:00
LICENSE.md {feature} initial commit 2022年06月26日 14:39:24 +02:00
package.json {chore} version v0.4.0 2025年11月30日 01:02:59 +01:00
README.md {doc} update v1-compat text in README 2025年01月27日 01:04:04 +01:00
tsconfig.json {chore} revamp tsconfigs 2025年02月15日 21:50:50 +01:00
yarn.lock {feature} make firstMatchingDeserializer usable with ctx.run 2025年06月21日 20:45:10 +02:00

@bgotink/kdl

This package contains a parser and stringifier for the KDL Document Language, a node-based, human-friendly configuration and serialization format.

The parser in this package focuses on parsing documents in a way that allows for format-preserving modifications. This is most useful when working with KDL files maintained by humans.

Install

yarn add @bgotink/kdl
# or
npm install @bgotink/kdl
# or
pnpm add @bgotink/kdl
# or ...

Usage

The examples below assume a Node.js environment. The @bgotink/kdl package works in any javascript runtime, including browsers, as long as it supports relatively modern browser standards. If you're trying to run these samples in a non-Node.js runtime, replace the import for assert with something equivalent in your runtime.

import {parse, format} from "@bgotink/kdl";
import assert from "node:assert/strict";
const doc = parse(String.raw`
	node "value" #"other value"# 2.0 4 #false \
			#null -0 {
		child; "child too"
	}
`);
doc.nodes[0].children.nodes[0].entries.push(
	parse(
		String.raw`/-lorem="ipsum" \
			dolor=#true`,
		{as: "entry"},
	),
);
assert.equal(
	format(doc),
	String.raw`
	node "value" #"other value"# 2.0 4 #false \
			#null -0 {
		child /-lorem="ipsum" \
			dolor=#true; "child too"
	}
`,
);

JSON-in-KDL (JiK)

This package exports function from @bgotink/kdl/json to parse and stringify KDL documents as JSON-in-KDL (JiK) 4.0.0. For information on the format, see the JiK 4.0.0 specification.

import {parse} from "@bgotink/kdl/json";
import assert from "node:assert/strict";
assert.deepEqual(
	parse(
		String.raw`
			- {
				prop #false
				otherProp {
					- 0
					- 2
					- 4
				}
			}
		`,
	),
	{
		prop: false,
		otherProp: [0, 2, 4],
	},
);

There are four functions:

  • parse and stringify turn text into the encoded JSON value and back. These functions are useful for encoding/decoding entire JiK files.
  • toJson and fromJson turn KDL nodes into the encoded JSON value and back. These functions give more fine-grained control over the output, and can be used for e.g. encoding/decoding a JiK node embedded in a KDL document.

(De)Serialization

The package contains utilities for (de)serialization in @bgotink/kdl/dessert.

import {parse} from "@bgotink/kdl/dessert";
import assert from "node:assert/strict";
assert.deepEqual(
	parse(
		String.raw`
			name "my-package"
			dependency "@bgotink/kdl" range="^0.2.0"
			dependency "prettier" range="^3" dev=#true
		`,
		(ctx) => {
			const dependencies = {};
			const devDependencies = {};
			const name = ctx.child.single.required("name", (ctx) =>
				ctx.argument.required("string"),
			);
			for (const dependency of ctx.children("dependency", (ctx) => ({
				name: ctx.argument.required("string"),
				range: ctx.property("range", "string") ?? "*",
				dev: ctx.property("dev", "boolean") ?? false,
			}))) {
				(dependency.dev ? devDependencies : dependencies)[dependency.name] =
					dependency.range;
			}
			return {name, dependencies, devDependencies};
		},
	),
	{
		name: "my-package",
		dependencies: {
			"@bgotink/kdl": "^0.2.0",
		},
		devDependencies: {
			prettier: "^3",
		},
	},
);

KDL v1

The package exports two functions from @bgotink/kdl/v1-compat to support documents written in KDL v1:

  • parse parses a KDL v1 document and transforms all linked formatting information to turn it into a valid KDL v2 document. If the resulting document is passed to format(), the resulting string will be the same document but in KDL v2 syntax. It will include all comments and formatting applied by the original document's author.
  • parseCompat parses a document that's either KDL v2 or KDL v1 and returns a valid KDL v2 document. This is a helper function that combines the regular parse function with the v1-compat parse function into a single function that supports both formats.

Quirks

This package turns KDL documents into JavaScript objects and vice versa. It is therefore limited by the JavaScript language.

Properties

Multiple properties with the same name are allowed. All duplicated will be preserved, meaning those documents will correctly round-trip. When using node.getProperty()/node.getProperties()/node.getPropertyEntry(), the last property with that name's value will be returned, effectively shadowing any earlier duplicates. Using node.getPropertyEntries()/node.entries does expose the shadowed duplicates, leaving it up to the caller to handle these. Passing the node through clearFormat() removes these shadowed duplicates.

Numbers

JavaScript stores all numbers as 64-bit IEEE 754 floating point numbers. This limits what integer values can be used safely. These limits are lower than you might expect if you're used to working in environments that have a separate 64-bit integer data type.

The original representation of parsed numbers is retained, unless clearFormat is called on the value or any entry/node/document containing the value.

License

This package is licensed under the MIT license, which can be found in LICENSE.md.

The test suite at test/upstream is part of the KDL specification and is available under the Creative Commons Attribution-ShareAlike 4.0 International License.