English

Developer tools · Syntax converters

YAML features lost in a JSON conversion: comments, anchors and tags

· How it works

yaml json data-formats

YAML comments and anchors fading while resolved data continues into JSON
Original ToolAcre vector illustration

YAML has comments, anchors, aliases, merge keys, tags and multi-document streams; JSON has none of them. This post explains what a converter does with each and why converting back never restores the original file.

The file came back longer and without a single comment — a YAML config converted to JSON and back, and everything that did not survive

A YAML file can return from JSON longer even after every comment disappears. Anchors that shared one mapping are resolved into repeated object data, so the serializer writes each copy independently. The values may still agree, yet the authoring structure and explanation have gone.

That is why a YAML-to-JSON-to-YAML round trip should be judged as data conversion, not source preservation. ToolAcre reads a restricted value graph and writes a new document. It never retains a concrete syntax tree containing comments, anchor names, quote choices or block-scalar presentation.

Comments — why JSON has no place for them and every # line is gone after conversion

Comments are discarded by the YAML parser because JSON has no comment node. A line beginning with `#` can explain why a timeout exists or who owns a service; once removed, no algorithm can infer the wording or placement. Converting back creates valid YAML without that operational context.

Preserve the original file in version control and review diffs before replacing it. If the goal is only to inspect resolved values, JSON is useful. If the goal is to reformat while retaining commentary, this generic value converter is the wrong representation.

Anchors and aliases — &default and *default expanded into repeated copies, and how the file grows as a result

Anchors and aliases are accepted within safety limits, then resolved. `base: &b {x: 1}` and `copy: *b` become two object paths containing `x: 1`. Output YAML uses `noRefs`, so shared object identity does not create new anchors. The compact relationship is gone even when the repeated values survive.

Recursive aliases are refused because JSON cannot express cycles. Alias expansion is capped by alias count, nesting and an expanded-node measurement; a short document that would stringify into more than one million values is stopped. This guards the tab without claiming arbitrary YAML support.

Merge keys — the <<: convention from YAML 1.1, how parsers that support it flatten the merged mapping, and what happens in ones that do not

The outline assumes YAML 1.1 merge keys are flattened. ToolAcre loads only js-yaml’s JSON or Core schema, neither of which enables the merge type. Under these schemas, a `<<` key is ordinary data rather than an instruction to merge mappings. Presenting a flattened merge as shipped behaviour would therefore be false.

If your source depends on merge-key semantics, resolve it in the application that owns that convention or rewrite the values explicitly before conversion. An alias used as the value of ordinary `<<` may still resolve to an object, but the key remains `<<`; that is not equivalent to merging its members into the parent.

Merge keys are not enabled by the two restricted schemas this converter ships

Standard explicit tags recognized by the restricted schema can choose basic types, such as `!!str` or `!!int`. Custom and richer tags—including binary, timestamp, set, ordered map, JavaScript function and Python object constructors—are rejected. They are not stringified and are never executed.

A YAML stream separated by `---` is accepted. One document becomes one value; several become an array with a warning naming the document count. A trailing separator can create an empty final document according to the selected schema. No target here has a stream model, so the array is a declared convention.

Unsafe tags are refused; multi-document streams become arrays

Use `defaults: &d` with retries and timeout, a comment explaining the timeout, then `service:` with `inherited: *d`. JSON contains both defaults and a repeated inherited object; the comment and anchor name are absent. Converting that JSON back emits two mappings rather than an anchor relationship.

Add `---` followed by another document and the JSON root becomes an array of documents. Add `!!binary` and conversion stops with a restricted-schema hint. These three changes distinguish resolved supported data, structural convention and outright unsupported construction.

What this does not cover — key order and quoting style, which usually survive but are not guaranteed by either format

Ordinary object insertion order often remains visible, but it is not source-style preservation, and selecting sort keys deliberately changes it. Quotes, flow versus block style, scalar spelling and comments do not survive. Duplicate mapping keys keep the last value with a warning rather than preserving both invalid entries.

The writer protects ambiguous strings by quoting values a YAML 1.1 consumer might misread, but that safety choice can differ from the author’s original style. Data equality is the defensible test for ordinary JSON-shaped values; textual equality is not.

Key order may remain, while comments, anchors, tag spelling and style are not preserved

YAML-to-JSON is lossy whenever meaning lived outside the JSON-shaped value: comments, aliases, unsupported tags, stream boundaries as such, and style. ToolAcre makes several losses visible and refuses dangerous or cyclic constructs rather than pretending to preserve them.

Convert a representative file before adopting the workflow. Inspect warnings, diff resolved values and keep the authored YAML. The panel is an excellent lens on what a parser sees, but it is not a comment-preserving editor or a full YAML object-model transformer.

For a migration review, separate value changes from source-only changes. A JSON deep comparison can establish whether ordinary values survived, while a text diff reveals comments, anchors and style that necessarily changed. Neither check replaces the other. Calling the value comparison lossless would ignore source information; calling every textual change a data failure would ignore valid re-serialization.