Formatter
in package
Multi-line, indented `.dxn` rendering -- the `pretty: true` option on `Dextrin::encode()`, built on top of {@see Printer}. Every empty collection and every scalar falls through to the single-line printer unchanged (there's nothing multi-line about `[]` or `42`).
The layout (Jan, 2026-10-20): the top-level collection always
breaks, one entry per line, however short it is. A nested collection
is written on one line, its entries single-space separated, when that
line -- its indent and its key included -- fits the width ($width,
80); otherwise it breaks too, and what it holds is laid out again by
the same rule. Columns are counted in code points.
Comments cannot be preserved here, for the same reason no formatter
built on this library's decode-then-reprint approach could: the
lexer discards # comments as trivia before a value ever exists to
carry them forward.
Same optional $registry as Printer, threaded through so a
registered application class instance prints under its schema's
name -- see Printer's own doc.
Table of Contents
Constants
- DEFAULT_INDENT : mixed = 2
- DEFAULT_WIDTH : mixed = 80
Methods
- pretty() : string
- __construct() : mixed
- allowedPairs() : array<int, array{0: mixed, 1: mixed}>
- `$pairs`, having checked every key is one DXN.md §1.6 allows.
- bracketed() : string
- bracketedEntries() : string
- bracketedItemsAndEntries() : string
- extraPairs() : array<int, array{0: mixed, 1: mixed}>
- A struct's extra fields as entries: a name like a field name, any other map key as itself.
- indentStr() : string
- joined() : string
- The rendered entries between `$open` and `$close`: single-space separated on one line, or one per line, indented.
- keywordPairs() : array<int, DXNKeyword, 1: mixed}>
- Struct field names and plain-object property names are always genuinely keyword-shaped (`DXN.md` §1.2's `map_entry` grammar applies to `%Name{...}`'s body too) -- never ambiguous with a string-typed key the way a bare `map`'s own key can be, so they get wrapped as `DXNKeyword` unconditionally, up front, rather than leaving `renderEntry()` to guess from a bare string alone.
- layout() : string
- mapToDxnPairs() : array<int, DXNKeyword|int|string, 1: mixed}>
- A bare PHP array's own key already tells `MapBuilder::toDxnMapKey()` apart a `DXNKeyword` key from a `string` key with the same text (see that class's own doc) -- this converts every pair to that unambiguous form before `renderEntry()` ever sees it, so `renderEntry()` itself never has to guess.
- render() : string
- A nested value on one line when that fits the room its line leaves it, and laid out over lines otherwise. The top level (depth 0) and a value inside a one-line one go straight to `layout()`.
- renderEntry() : string
- Same colon-shorthand-vs-arrow-form rule as {@see Printer}'s own `printEntry()`/`printKeywordEntry()`: only a genuine `DXNKeyword` key gets the shorthand-or-keyword-arrow treatment.
- renderPlainObject() : string
- A genuine application class instance -- every built-in DXN shape is already handled by `render()`'s own dispatch above.
Constants
DEFAULT_INDENT
private
mixed
DEFAULT_INDENT
= 2
DEFAULT_WIDTH
private
mixed
DEFAULT_WIDTH
= 80
Methods
pretty()
public
static pretty(mixed $value[, int $indentSize = self::DEFAULT_INDENT ][, Registry|null $registry = null ][, int $width = self::DEFAULT_WIDTH ]) : string
Parameters
- $value : mixed
- $indentSize : int = self::DEFAULT_INDENT
- $registry : Registry|null = null
- $width : int = self::DEFAULT_WIDTH
Return values
string__construct()
private
__construct() : mixed
allowedPairs()
`$pairs`, having checked every key is one DXN.md §1.6 allows.
private
static allowedPairs(array<int, array{0: mixed, 1: mixed}> $pairs) : array<int, array{0: mixed, 1: mixed}>
Parameters
- $pairs : array<int, array{0: mixed, 1: mixed}>
Return values
array<int, array{0: mixed, 1: mixed}>bracketed()
private
static bracketed(string $open, array<int, mixed> $items, string $close, int $depth, Layout $l) : string
Parameters
- $open : string
- $items : array<int, mixed>
- $close : string
- $depth : int
- $l : Layout
Return values
stringbracketedEntries()
private
static bracketedEntries(string $open, array<int, array{0: mixed, 1: mixed}> $pairs, string $close, int $depth, Layout $l) : string
Parameters
- $open : string
- $pairs : array<int, array{0: mixed, 1: mixed}>
- $close : string
- $depth : int
- $l : Layout
Return values
stringbracketedItemsAndEntries()
private
static bracketedItemsAndEntries(DXNStruct $value, int $depth, Layout $l) : string
Parameters
- $value : DXNStruct
- $depth : int
- $l : Layout
Return values
stringextraPairs()
A struct's extra fields as entries: a name like a field name, any other map key as itself.
private
static extraPairs(DXNStruct $value) : array<int, array{0: mixed, 1: mixed}>
Parameters
- $value : DXNStruct
Return values
array<int, array{0: mixed, 1: mixed}>indentStr()
private
static indentStr(int $depth, Layout $l) : string
Parameters
- $depth : int
- $l : Layout
Return values
stringjoined()
The rendered entries between `$open` and `$close`: single-space separated on one line, or one per line, indented.
private
static joined(string $open, array<int, string> $rendered, string $close, int $depth, Layout $l) : string
Parameters
- $open : string
- $rendered : array<int, string>
- $close : string
- $depth : int
- $l : Layout
Return values
stringkeywordPairs()
Struct field names and plain-object property names are always genuinely keyword-shaped (`DXN.md` §1.2's `map_entry` grammar applies to `%Name{...}`'s body too) -- never ambiguous with a string-typed key the way a bare `map`'s own key can be, so they get wrapped as `DXNKeyword` unconditionally, up front, rather than leaving `renderEntry()` to guess from a bare string alone.
private
static keywordPairs(array<int, array{0: string, 1: mixed}> $pairs) : array<int, DXNKeyword, 1: mixed}>
Parameters
- $pairs : array<int, array{0: string, 1: mixed}>
Return values
array<int, DXNKeyword, 1: mixed}>layout()
private
static layout(mixed $value, int $depth, Layout $l) : string
Parameters
- $value : mixed
- $depth : int
- $l : Layout
Return values
stringmapToDxnPairs()
A bare PHP array's own key already tells `MapBuilder::toDxnMapKey()` apart a `DXNKeyword` key from a `string` key with the same text (see that class's own doc) -- this converts every pair to that unambiguous form before `renderEntry()` ever sees it, so `renderEntry()` itself never has to guess.
private
static mapToDxnPairs(array<int|string, mixed> $map) : array<int, DXNKeyword|int|string, 1: mixed}>
Parameters
- $map : array<int|string, mixed>
Return values
array<int, DXNKeyword|int|string, 1: mixed}>render()
A nested value on one line when that fits the room its line leaves it, and laid out over lines otherwise. The top level (depth 0) and a value inside a one-line one go straight to `layout()`.
private
static render(mixed $value, int $depth, Layout $l) : string
Parameters
- $value : mixed
- $depth : int
- $l : Layout
Return values
stringrenderEntry()
Same colon-shorthand-vs-arrow-form rule as {@see Printer}'s own `printEntry()`/`printKeywordEntry()`: only a genuine `DXNKeyword` key gets the shorthand-or-keyword-arrow treatment.
private
static renderEntry(mixed $key, mixed $value, int $depth, Layout $l) : string
Every other key (ordered-map's own preserved key type, or a
bare map's already-disambiguated MapBuilder::toDxnMapKey()
result) renders through the generic value printer on the
arrow's left side -- correctly quoting a genuinely string-typed
key instead of guessing it was a keyword.
Parameters
- $key : mixed
- $value : mixed
- $depth : int
- $l : Layout
Return values
stringrenderPlainObject()
A genuine application class instance -- every built-in DXN shape is already handled by `render()`'s own dispatch above.
private
static renderPlainObject(object $value, int $depth, Layout $l) : string
Same three-way registry precedence as Printer::printPlainObjectAsStruct()'s own doc, in one pass (no repeated registry lookups, unlike calling that precedence twice from two different helpers would need):
- A struct schema registered for this class renders as that named struct, multi-line if it has any fields.
- Otherwise, a registered tag encoder means this isn't
struct-shaped at all -- defers entirely to
Printer::print()'s own single-line@tag valuehandling, the same precedent already set forDXNCustomTag(never rendered multi-line by this class either). - Otherwise, the PHP-specific "any object is data"
convenience: multi-line if it has any public properties,
single-line (
Printer::print()) if it has none.
Parameters
- $value : object
- $depth : int
- $l : Layout