4.3 KiB
PureYAML Design
| Field | Value |
|---|---|
| Status | draft |
| Created | 2026-06-05 |
| Last revised | 2026-06-05 |
Purpose
PureYAML exists to provide a dependency-free YAML implementation in Swift that can build on macOS, Linux, and WebAssembly/WASI. The first user is OpenAPIDoctor, which needs YAML parsing and mutation without a C-backed parser blocking browser deployment.
Goals
- Parse a useful YAML subset with no external dependencies.
- Preserve mapping order.
- Emit YAML from the same model.
- Validate YAML structures with path-aware issues.
- Build the library target for
wasm32-unknown-wasip1. - Grow toward Yams-compatible behavior through tests, not source copying.
Non-Goals
- No C source in the public package.
- No external SwiftPM dependency.
- No JavaScript parser or build-time generator.
- No claim of complete YAML 1.2 coverage until the test corpus proves it.
Current Architecture
PureYAML
├── Model
│ ├── Value
│ ├── Mapping
│ └── Pair
├── Parsing
│ ├── Parser
│ ├── Reader
│ ├── Scanner
│ ├── Token
│ ├── TokenCursor
│ ├── TokenEventParser
│ ├── EventComposer
│ ├── Event
│ ├── Mark
│ └── ParseError
├── Emitting
│ └── Dumper
└── Validation
├── Validator
├── Rule
├── Issue
└── Path
PureYAML.parse(_:) and PureYAML.dump(_:) are convenience entry points.
Parsing runs through the scanner, token-event parser, and event composer before
returning PureYAML.Model.Value. The implementation lives in namespaced parser,
dumper, and validator types.
First Milestone
The initial parser supports:
- block mappings
- block sequences
- ordered mappings
- strings
- ints
- doubles
- bools
- nulls
- quoted strings
- comments outside quoted strings
- flow sequences and mappings
- literal and folded block scalars
- anchors and aliases
- YAML directives and document markers for single-document streams
- explicit built-in scalar tags for strings, integers, floats, booleans, and nulls
The parser layer also has an internal event contract. Parsing.Event can
represent stream, document, scalar, sequence, mapping, and alias events, with
marks plus scalar and collection styles. Anchors and tags are carried as event
metadata so the later scanner/composer work can add YAML feature coverage
without changing the event shape.
The parser layer now also has an internal reader/scanner/event contract.
Parsing.Reader advances through Swift String input while tracking UTF-8 byte
indexes, lines, and columns. Parsing.Scanner emits lexical Parsing.Token
values for comments, indentation, block entries, mapping indicators, flow
delimiters, quoted scalar starts, block scalar headers, anchors, aliases, tags,
YAML directives, document markers, and source mark ranges. Parsing.Scanner
also expands tag handles from %TAG directives before emitting tag tokens.
Parsing.TokenEventParser consumes that token stream and emits Parsing.Event
values for block collections, flow collections, aliases, anchors, tags, and
scalars. Parsing.EventComposer consumes those events into
PureYAML.Model.Value, preserving ordered mapping pairs, block scalar text,
alias-resolved values, and explicit built-in scalar tags where the current model
can represent them.
The initial dumper emits block-style YAML from the model.
The initial validator traverses parsed YAML values and reports path-aware issues. The default rule rejects duplicate mapping keys, and callers can build a blank validator plus custom rules for project-specific checks.
Planned Compatibility Work
Compatibility should be added in small, test-backed slices:
- Tag-aware collection handling and merge keys.
- Validation rules beyond duplicate-key behavior.
- Codable-style decoding and encoding.
- Yams corpus comparison tests in a separate compatibility suite.
The private PureYAMLResearch repository may be used to study Yams behavior, but
the public implementation must be written in Swift and must not copy C parser
source.
Attribution Boundary
Yams and its bundled CYaml / libyaml-derived C parser are compatibility
references for PureYAML. They should guide test cases and behavior questions.
They are not source material to copy into this package.