Skip to content

Functions Reference

This page is the canonical reference for every CCL function the test suite exercises. Each heading is the stable anchor for the corresponding function:* tag (e.g. function:parse#parse).

For the full recursive algorithm, see Parsing Algorithm. For patterns and examples, see Implementing CCL and Library Features.

The canonical CCL data model is the in-memory shape that build_model produces and that every other function operates on — typed accessors project from it, canonical_format renders it back to text, and build_hierarchy is a JSON-friendly view of it.

The Model type is a recursive map:

type Model = Map<string, Model>

There are no scalar leaves. A string value like "localhost" is not stored as a value — it becomes a key in the inner map pointing to the empty model ({}). This is what makes the model recursive in a single type rather than a sum of “object” and “string” cases.

host = localhost

{"host": {"localhost": {}}}

Duplicate keys at the same level merge. Their inner maps are combined recursively, which is how bare lists, repeated keys, and compose all work uniformly:

item = first
item = second

{"item": {"first": {}, "second": {}}}

The model is order-agnostic. Key ordering within any map is unspecified. Anything that needs ordered access — most notably get_list — picks an order at the typed-access layer, governed by the array_order_* behavior. This is why two inputs that are semantically equal in the model produce identical canonical_format output even when their source text looked different.

Reference implementation. The OCaml reference exposes this model as fix : Parser.key_val list -> t where type t = Fix of t KeyMap.t. See ccl-test-data issue #142 for the ongoing work to formally add build_model to the test suite.

Tag: function:parse

parse(text: string) → Entry[]

Converts CCL text into a flat list of key-value entries. Splits each line on its delimiter, trims keys, preserves in-value whitespace, folds continuation lines into the preceding value using the baseline-N rule.

Under the toplevel_indent_strip behavior, top-level parsing uses N = 0 and strips leading whitespace on top-level keys. Under toplevel_indent_preserve, the baseline is determined dynamically from the first content line.

See Continuation Lines for the baseline-N algorithm and Behavior Reference — Continuation Baseline for the top-level choice.

host = localhost
port = 8080

[{key: "host", value: "localhost"}, {key: "port", value: "8080"}]


Tag: function:parse_indented

parse_indented(text: string) → Entry[]

Nested-value parsing. Determines baseline N from the indentation of the first content line, then parses with that baseline. Used internally by build_hierarchy to re-parse nested values.

parse_indented and parse differ only in how they pick N. See parse vs parse_indented for the worked example.


Tag: function:build_model

build_model(entries: Entry[]) → Model

Converts flat parsed entries into the canonical CCL data model. See that section for the Model type, the no-scalar-leaves rule, duplicate-key merging, and order-agnosticism.

server =
host = localhost
port = 8080

{"server": {"host": {"localhost": {}}, "port": {"8080": {}}}}


Tag: function:build_hierarchy

build_hierarchy(entries: Entry[]) → object

A JSON-friendly view of build_model. Projects the recursive Model type into a conventional nested-object shape:

  • Single leaf node — a key whose inner model has exactly one key pointing to {} → string value
  • Multiple leaf nodes — a key whose inner model has multiple keys all pointing to {} → array of strings
  • Nested nodes — a key whose inner model has non-empty values → nested object (recursed)
server =
host = localhost
port = 8080

{"server": {"host": "localhost", "port": "8080"}}

item = first
item = second
item = third

{"item": ["first", "second", "third"]}

The flat string output for bare-list entries is the correct projection of leaf nodes from build_model — not a behavior choice, but a consequence of the projection rule. See Bare List Hierarchy and Parsing Algorithm — Build Hierarchy.


Tag: function:load

load(text: string) → object

Convenience combining parse + build_hierarchy in one call. Equivalent to build_hierarchy(parse(text)).

All typed accessors project from build_model output, navigating the Model value by a key path passed as variadic string segments (e.g. get_string(ccl, "database", "host")).

Accessor behavior under ambiguous values is governed by:

Error conditions (uniform across typed accessors):

  • Missing path segment — fail with a path-aware error (implementations should include the full path and available siblings to aid debugging).
  • Intermediate segment is a scalar, not an object — fail; the path cannot descend through a non-object value.
  • Type conversion failure — e.g. get_int on "hello". Fail with both the expected type and the raw value.
  • Empty path — implementation-defined; tests don’t require a specific behavior.

Tag: function:get_string

get_string(ccl: CCL, ...path: string) → string

Returns the raw string value at the given path. No coercion.


Tag: function:get_int

get_int(ccl: CCL, ...path: string) → int

Parses the string at the given path as an integer. Errors if the value is not a valid integer.


Tag: function:get_bool

get_bool(ccl: CCL, ...path: string) → bool

Coerces the string at the given path to a boolean. The accepted set of truthy/falsy tokens depends on the Boolean Parsing behavior.


Tag: function:get_float

get_float(ccl: CCL, ...path: string) → float

Parses the string at the given path as a floating-point number.


Tag: function:get_list

get_list(ccl: CCL, ...path: string) → string[]

Returns an array of string values at the given path. Bare-list entries (empty-key children) are the canonical source; get_list has well-defined array semantics regardless of how build_hierarchy represents bare lists (see Bare List Hierarchy).

Single-value coercion depends on List Coercion.

Tag: function:filter

filter(entries: Entry[], predicate) → Entry[]

Filters entries. The test suite validates filter used to strip comment entries — keys beginning with / (see Comments).


Tag: function:compose

compose(left: Entry[], right: Entry[]) → Entry[]

Concatenates two entry lists so duplicate keys between them merge at object level when passed through build_hierarchy. compose is expected to be associative; the test suite validates this via the compose_associative algebraic property (and the identity_left/identity_right identity properties).


Tag: function:expand_dotted

expand_dotted(entries: Entry[]) → Entry[]

Transforms entries with dotted keys (e.g. database.host = localhost) into nested structures. Opt-in: CCL treats dotted keys as literal strings by default. See Dotted Keys Explained and the experimental_dotted_keys feature.

Tag: function:print

print(ccl: CCL) → string

Renders a CCL value back to text in a structure-preserving form. Distinct from canonical_format, which imposes a normalized ordering.

See Library Features — Formatting for the print vs canonical_format comparison.


Tag: function:canonical_format

canonical_format(ccl: CCL) → string

Renders a CCL value in a canonical form: stable key ordering, consistent indentation (per indent_spaces vs indent_tabs), no redundant whitespace. Two inputs that are semantically equal produce identical canonical output.


Tag: function:round_trip

round_trip(text: string) → string

canonical_format(load(text)). Validates the round-trip property: round-tripping a canonical input must be a fixed point.