API overview¶
The package is one public surface: a File that holds immutable revisions,
Snapshot, Document and Node views into a revision, typed reads, and one
Transaction shape for edits. Every method's signature and doc comment is on
pkg.go.dev; this page
is the map, and says what each piece is for and how the pieces relate.
Parsing¶
Options selects the language (Version, zero to let each document
negotiate its own from its directives), the schema profiles per document
(Profiles, nil for each document's default), and the resource limits.
Every limit left at zero takes the value DefaultLimits returns, which is
sized for configuration files; an explicit limit always wins.
Parse is strict. Bytes that are not YAML under the selected language return
an error and no File: ErrSyntax, ErrUnsupportedVersion for a %YAML
directive naming a version the engine does not implement, ErrVersionConflict
when a directive disagrees with Options.Version, ErrEncoding for bytes
that are not valid in their encoding, or ErrSyntaxLimit. A
document that is YAML but not meaningful under its schema parses; see
Validation.
Every other directive is accepted. Document.Directives reports what a
document declared, %YAML, %TAG and reserved names alike, each with its
parameters and location, so a reader that allows none can refuse them itself:
directives, err := doc.Directives()
if err != nil {
return err
}
if len(directives) > 0 {
first := directives[0]
return fmt.Errorf("line %d: %%%s directives are not allowed", first.Location.Start.Line, first.Name)
}
Revisions and views¶
A File publishes immutable revisions. f.Snapshot() is the current one, and
a Snapshot keeps describing that revision however many edits land afterwards,
so a reader never sees a half-applied change and a handle never goes stale on
its own.
| View | Reached by | What it is |
|---|---|---|
Snapshot |
File.Snapshot, Transaction.Snapshot |
One revision: its Bytes, its Documents, its stream Comments, and Validate |
Document |
Snapshot.Document(i), Snapshot.Documents |
One document: Root, Index, Version, the Directives it declared, document-level Comments, and the dotted-path helpers |
Node |
Document.Root, Node.Get, Entries, Items |
One syntax occurrence: a scalar, mapping, sequence or alias |
Entry |
Node.Entries |
A mapping's key and value nodes, with the entry's Comments |
Mapping, Sequence |
Node.Mapping, Node.Sequence, Node.Value |
A collection view, with typed Lookup and Items |
A working snapshot taken inside Edit expires when the callback returns; a
committed snapshot lives as long as you hold it.
Addressing¶
Node.Get(steps ...Step) walks from a node. A Step is one of:
| Step | Addresses |
|---|---|
StringStep("key") |
The entry whose key is the string key, exactly as spelt: a key containing a dot is one step |
IndexStep(i) |
The ith item of a sequence |
KeyStep(key) |
The entry whose key equals a typed Key: IntKey(8080) matches 8080, 0x1f90 and 0o17620 alike |
Document.Get("a.b.c") is sugar for Root().Get(StringStep("a"),
StringStep("b"), StringStep("c")); PathSteps does the split on its own.
Paths and steps has the rules.
Reading¶
Every read is typed and returns an error rather than a zero value when the node is not what was asked for.
| Method | Returns | Fails with |
|---|---|---|
String, Bool, Int64, Uint64, Float64, Float32, Time, Binary |
The value, if the node resolves to that type under the document's schema | ErrKind for another type, ErrRange or ErrPrecision when the value does not fit |
BigInt, Rat, Number |
The exact value, for integers beyond int64 and decimals beyond float64 |
ErrKind |
Value |
The native Go value: scalars as above, nil for null, Mapping or Sequence for collections |
ErrSemantic when the subtree is invalid |
Project(expandAliases) |
A recursive native projection, map[string]any and []any all the way down, with an Origin (location, key location, path, alias hops) for every value |
The projection limits, alias errors unless expansion is requested, a << key |
Raw, LiteralText, Syntax |
The source bytes, the decoded text, and the kind, style, tag, anchor and location | Nothing beyond an expired view |
Entries, Items, Comments, ItemComments |
Literal structure and comment ownership, valid even where semantics are not | ErrKind on the wrong kind |
CommentOwner, ItemCommentOwner |
The owner a comment command names as its destination; Snapshot, Document and Entry have CommentOwner too |
ErrKind on the wrong kind |
AliasTarget |
The anchored node an alias refers to | ErrKind on a non-alias |
EvaluateMerge(limits) |
The mapping with << merge keys applied, under a profile that supports them, each inherited entry carrying the MergeHop that supplied it |
Merge errors; zero limits |
Which spellings are which type depends on the document's version: yes is a
boolean under 1.1 and a string under 1.2, 0777 is octal under 1.1 and
decimal under 1.2. Document.Version says which rules apply.
Reading a document works every one of these against one file,
provenance and merge keys included.
Editing¶
The callback is the transaction. Commands stage changes against a private working revision; when the callback returns nil the engine re-parses the result, checks it against an independent statement of every staged edit, and publishes it. Any error, from a command or from the callback, discards the lot. A command's error poisons the transaction even if the callback ignores it.
| Command | Does |
|---|---|
Set(container, key, value) |
Writes a mapping entry, creating it at the end when absent |
ReplaceEntry(container, key, value) |
Writes an existing entry; absent is ErrNotFound |
Insert(container, step, value) |
Adds a new mapping entry (absent key) or a sequence item before IndexStep(i); an existing key is ErrExists |
Replace(target, value) |
Replaces a selected node, whatever its kind; the way to change a sequence item |
Remove(container, step), RemoveIfPresent |
Removes an entry or item, with or without tolerating absence |
CreateDocument(value), CreateDocumentWithProfile |
Gives an empty stream its first document; a stream with one is ErrDocumentExists |
ChangeComments(changes) |
Moves or copies comments to an entry or item, a block collection's tail, a document marker, the gap between documents, or the stream's header or footer; see Move or copy a comment |
ReplaceWithComments(target, value, changes) |
Replaces a node and moves or copies comments in one command, including into the new value with InReplacement |
Every command produces a new working revision and expires every Node from
the previous one, so take tx.Snapshot() again before the next command. A
handle from another revision is ErrStale; a helper such as Document.Set
called inside a callback is ErrActiveTransaction.
Writes accept strings, booleans, all integer and float widths, *big.Int,
time.Time, []byte, nil, maps, slices and arrays, and MappingInput for
an ordered mapping. Normalize turns one into the Graph the engine writes,
and Node.Detach gives back a Graph you can write elsewhere.
Dotted-path helpers¶
Document.Set(path, value) and Document.Remove(path) each run one Edit
containing one command, with Set creating missing mapping ancestors (and
a one-item sequence for a missing [0]); a path's [n] is the nth item
of a sequence, replaced in place, appended at the sequence's length and
ErrNotFound beyond, or the integer key n of a mapping.
They are convenience for a single change and offer no atomicity across
calls. Document.Get(path) needs no transaction.
Validation¶
Snapshot.Validate composes the revision's semantics under its profiles and
returns a ValidationReport: the diagnostics with locations and related
locations, and the checks that could not run because a node they depend on
had already failed. It errors when any diagnostic is a genuine failure.
Validate a document shows it in use.
Profiles¶
A Profile is a Base schema, Core, JSON, Strings, Failsafe or the
YAML 1.1 Standard11, with Extensions for the standard timestamp and binary
types, implicit timestamp recognition and merge-key support. NewProfile
refuses combinations outside the nineteen the design froze;
DefaultProfile(version) is what a document gets without an override.
Resolvers¶
Custom application tags such as !secret vault/database can be resolved on
request through a ResolverRegistry attached to a ResolverSet. Parsing,
reading, validating and emitting never invoke a resolver; a caller asks for a
specific tagged node and receives a Resolved envelope carrying the handler's
payload. The registry API is documented on pkg.go.dev, and a consumer that does
not register anything is not affected by it.
Limits¶
Every operation is bounded: source bytes, nodes, depth, comments, work per
transaction. The types behind Options.Limits are aliased here
(SyntaxLimits, ComposeLimits, EditLimits and so on) so a caller can set
them without importing internal packages. The zero value means the default,
and the defaults are measured against real configuration files. The ones a
caller is likeliest to meet:
| Limit | Default | Refuses |
|---|---|---|
| Nodes, in every layer | 100,000 | a mapping of more than about 50,000 entries |
Syntax.Bytes |
64 MiB | a larger source |
Syntax.Depth |
256 | deeper nesting |
Edit.Commands |
1,000 | a longer batch in one transaction |
Edit.RevisionBytes |
256 MiB | a batch whose working revisions hold more |
DefaultLimits returns every field.