A pure Crystal YAML 1.2 parser with comment preservation for round-trip parsing.
JustYAML is designed to preserve comments during parsing, enabling true round-trip editing of YAML files. Edit configuration files programmatically without losing valuable documentation.
input = <<-YAML
# Server configuration
server:
host: localhost # Development only
port: 8080
YAML
ast = JustYAML.parse(input)
output = JustYAML.dump(ast)
# Comments are preserved in the outputJustYAML has zero dependencies. It's pure Crystal.
- Just install: No C extensions to compile, no libyaml required
- Debuggable: Step through the code with a debugger to understand exactly how your YAML is being parsed
- Simple types: Returns plain Crystal objects you can iterate over and inspect
Implements the YAML 1.2 specification with strict parsing and detailed error messages.
- Full support for anchors, aliases, and merge keys
- Block and flow collection styles
- All scalar styles: plain, single-quoted, double-quoted, literal, and folded
-
Add the dependency to your
shard.yml:dependencies: just_yaml: github: luislavena/just_yaml.cr
-
Run
shards install
require "just_yaml"
# Parse YAML to native Crystal types
result = JustYAML.load(<<-YAML)
name: JustYAML
version: 1.0
features:
- comment preservation
- strict parsing
- round-trip support
YAML
# Cast to access hash keys
data = result.as(Hash(String, JustYAML::Any))
puts data["name"] # => "JustYAML"
puts data["version"] # => 1.0require "just_yaml"
input = <<-YAML
# Application settings
app:
name: MyApp # Display name
debug: false # Enable for development
# Database configuration
database:
host: localhost
port: 5432
YAML
# Parse to AST (preserves comments)
ast = JustYAML.parse(input)
# Serialize back to YAML (comments preserved)
output = JustYAML.dump(ast)
puts outputrequire "just_yaml"
result = JustYAML.load(<<-YAML)
defaults: &defaults
adapter: postgres
host: localhost
development:
<<: *defaults
database: dev_db
production:
<<: *defaults
database: prod_db
YAML
data = result.as(Hash(String, JustYAML::Any))
dev = data["development"].as(Hash(String, JustYAML::Any))
prod = data["production"].as(Hash(String, JustYAML::Any))
puts dev["adapter"] # => "postgres"
puts prod["database"] # => "prod_db"JustYAML provides detailed error messages with precise source locations.
require "just_yaml"
begin
JustYAML.load("key: [unclosed")
rescue ex : JustYAML::ParseError
puts ex.message # => "Expected SequenceEnd, got StreamEnd at line 1, column 15"
endmodule JustYAML
# Parse YAML string to AST (preserves comments)
def self.parse(input : String) : AST::StreamNode
# Parse and resolve to Crystal types (loses comments)
def self.load(input : String) : Any
# Serialize AST back to YAML string
def self.dump(node : AST::StreamNode, indent : Int32 = 2) : String
end# The Any type alias represents resolved YAML values
# Use .as() to cast to the expected type for access
alias JustYAML::Any = Nil | Bool | Int64 | Float64 | String |
Array(Any) | Hash(String, Any)JustYAML::Error # Base exception class
JustYAML::LexerError # Tokenization errors
JustYAML::ParseError # AST construction errors
JustYAML::ResolveError # Type resolution errorsAll exceptions include the source location (line and column) where the error occurred.
crystal specJustYAML is verified against the official yaml-test-suite. The tests are included as a git submodule.
-
Initialize the submodule:
git submodule update --init -
Run the full test suite:
crystal spec
- Fork it (https://github.com/luislavena/just_yaml.cr/fork)
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a new Pull Request
This Crystal implementation was produced using Claude Code with the Opus model. The project is inspired by justhtml, a Python HTML5 parser, and its Crystal port just_html.cr.
MIT License. See LICENSE for details.
- Luis Lavena - creator and maintainer