@gesslar/lpml
v1.0.0
Published
Decode LPML (LPC Markup Language) to JSON and encode JSON to LPML.
Maintainers
Readme
@gesslar/lpml
Decode LPML (LPC Markup Language) to JSON and encode JSON back to LPML.
LPML is the human-friendly config format used by the Ox mudlib: JSON5-ish with
LPC-flavoured extensions. This package is a faithful JavaScript port of Ox's
lpml_decode() / lpml_encode() simul_efuns (/adm/simul_efun/lpml.lpc), so
files written by either side read identically on the other.
Install
npm install @gesslar/lpmlLibrary
import {decode, decodeFile, encode} from "@gesslar/lpml"
decode(`{
name: "cave bat",
weapon name: "fangs", // spacey keys
long: "A leathery cave bat"
"clings to the ceiling.", // adjacent strings join with a space
level: [1, 3,], // trailing commas
mask: 0xFF,
}`)
// => { name: "cave bat", "weapon name": "fangs",
// long: "A leathery cave bat clings to the ceiling.",
// level: [1, 3], mask: 255 }
encode({name: "cave bat", level: [1, 3]})
// => '{ level: [1, 3], name: "cave bat" }\n'decode(text, options?)
| Option | Default | Description |
| ---------- | ------------------------- | ------------------------------------------------------------------ |
| basePath | — | Directory for relative "#./file.lpml" includes. |
| root | — | Mudlib root. Include paths become mudlib paths ("#/adm/etc/x.lpml" reads <root>/adm/etc/x.lpml); without it they are native paths. |
| includes | true | Set false to leave "#path" strings untouched. |
| readFile | fs.readFileSync | Custom include reader (path) => string \| null. |
| maxInt | Number.MAX_SAFE_INTEGER | Value of MAX_INT. |
| maxFloat | Number.MAX_VALUE | Value of MAX_FLOAT. |
Throws LpmlSyntaxError (with line and column) on malformed input.
decodeFile(file, options?)
Reads and decodes a file. Relative includes resolve against the file's
directory. With root, the file must live under it and includes are treated
as mudlib paths.
encode(value, options?)
| Option | Default | Description |
| ---------- | ------- | ------------------------------------------------------ |
| width | 79 | Maximum line length. encode(value, 60) also works. |
| sortKeys | true | Sort keys like the LPC encoder; false keeps order. |
Output uses bare keys where safe, trailing commas, expands containers only when
they overflow, and wraps long strings with adjacent-literal concatenation so
the decoded value is unchanged. Throws TypeError on circular references and
unrepresentable values (functions, symbols).
CLI
lpml decode monster.lpml # LPML -> JSON (indent 2)
lpml decode -i 0 < monster.lpml # compact, from stdin
lpml decode -r /mud/ox/lib file.lpml # resolve "#/abs" includes in the mudlib
lpml encode data.json -w 100 # JSON -> LPML
lpml encode --no-sort < data.json # keep key orderDifferences from the LPC implementation
Most of these follow from JSON's data model; the last two make up for there being no driver to lean on.
true/falsedecode to booleans (LPC:1/0) and encode back astrue/false.null,undefined,InfinityandNaNdecode tonull.- JavaScript has one number type, so
70.0decodes to70and re-encodes as an int. LPC code reading the result gets an int where it had a float. MAX_INTdefaults toNumber.MAX_SAFE_INTEGER, since FluffOS's 64-bitMAX_INTis not exactly representable as a Number.encodeacceptsBigIntand writes it exactly, so you can emit 64-bit LPC ints.decodealways returns Numbers, so a BigInt beyondNumber.MAX_SAFE_INTEGERdoes not survive a JS round trip.- Sparse array holes encode as
null, asJSON.stringifydoes. - A number literal that overflows (
1e999) decodes tonull, likeInfinity. - With
root, includes can't read outside the root (the driver enforces this in the MUD); such an include is left as its string, like a missing file. - Circular includes fail after 64 levels instead of recursing without limit.
License
@gesslar/lpml is released under the 0BSD.
