const yaml = @This();
const Document = @import("../../document.zig");
const AST = @import("../../ast/ast.zig");
const lang = @import("../manifest.zig");
pub const Parser = @import("parser.zig");
pub const Tokenizer = @import("tokenizer.zig");
pub const Printer = @import("printer.zig");
pub const Type = enum {
v1_2_2,
/// YAML 1.1 (2005). Differs from 1.2 almost entirely in *scalar type
/// resolution* (the tag repository at yaml.org/type): `yes/no/on/off/y/n`
/// booleans, leading-zero octal (`0777`) + binary (`0b…`) + sexagesimal
/// (`190:20:30`) ints, `_` digit separators, mandatory-sign float exponents,
/// and `!!timestamp` auto-resolution. Structure/syntax is unchanged.
/// Resolution differences are pinned by the spec fixtures in
/// `testdata/yaml-1.1/` (see `conformance_1_1.zig`) and implemented by
/// `scalarKind1_1` in `parser.zig`. Structure/syntax is shared with 1.2.
v1_1,
};
pub const Language = struct {
pub const Type = yaml.Type;
pub const Parser = yaml.Parser;
pub const Printer = yaml.Printer;
pub const default_type: yaml.Type = .v1_2_2;
pub fn parse(parser: *yaml.Parser, input: []const u8, format: yaml.Type) !Document {
return yaml.Parser.parse(parser.allocator, input, format);
}
pub const print = yaml.Printer.print;
pub const printNode = yaml.Printer.printNode;
/// Parse straight to a core AST with no `Document` around it — what
/// `deserialize.zig` maps onto a Zig type. Optional `Language` decl,
/// required exactly of a language with a `deserializable` dialect row.
pub const parseAbstract = yaml.Parser.parseAbstract;
pub const name = "yaml";
pub const extensions: []const []const u8 = &.{ "yaml", "yml" };
pub const caps: lang.Caps = .{
.read = true,
.edit = true,
.serialize = true,
// Anchors, aliases, `<<` merges and tags: the layer `Materialize`
// collapses when a document leaves YAML for a format without one.
.references = true,
// The core schema has a `null` and none of the extended scalars
// (a `!!timestamp` is a 1.1 tag, not a core kind), so those ride in
// a `$fig` envelope.
.lossless = .{ .null = true },
};
/// What `languages/harness.zig` round-trips and edits: block and flow
/// shapes, a sequence, a nested mapping.
pub const samples: []const []const u8 = &.{
"a: 1\nb:\n - x\n - y\nc:\n d: true\n",
"{a: 1, b: [2, 3]}\n",
};
pub const dialects: []const lang.Dialect(@This()) = &.{.{
.name = "yaml",
.abi_value = 3,
// Third from last: YAML is so permissive (a bare line is a valid plain
// scalar) that almost anything falls through to it, so every stricter
// grammar — and fig and INI, which it would otherwise starve — must
// have had its turn first. Only `.properties` and NestedText accept
// more.
.sniff_rank = 9,
.deserializable = true,
.splice = .literal,
// A bare `key:` seed, not `{}`: see `Syntax.empty_map_literal`'s
// note on why an empty YAML document is the empty string.
.empty_doc_seed = "",
.print_name = "printWith",
.specs = &.{
.{ .name = "1.2", .dialect = .v1_2_2 },
.{ .name = "1.2.2", .dialect = .v1_2_2 },
.{ .name = "1.1", .dialect = .v1_1 },
.{ .name = "1.1.0", .dialect = .v1_1 },
},
.embed = .{
.fence_tag = "yaml",
.fence_aliases = &.{"yml"},
// Bare, not `---yaml`: an untagged frontmatter block is YAML.
.frontmatter = "---",
.script_mime = "application/yaml",
.script_mime_aliases = &.{ "application/x-yaml", "text/yaml" },
.code_class = "language-yaml",
},
}};
/// 1.1 and 1.2.2 differ only in scalar type RESOLUTION, never in the
/// syntax the editor splices, so both dialects answer identically. This
/// is where an editing divergence would land if one ever appeared.
pub fn syntax(t: yaml.Type) lang.Syntax {
_ = t;
return .{
.comments = .hash,
// `<<` merges another mapping's entries in; a key resolved only
// through it is inherited (shadowed on write, refused on delete).
.merge_key = "<<",
.kv_sep = ": ",
// The empty seed rather than `{}` — see `Syntax.empty_map_literal`
// for why the two are not interchangeable here.
.empty_map_literal = "",
// The only editable format whose block mapping has a single-line
// spelling (`k: v`) that reaches the splice paths.
.single_line_block_mapping = true,
};
}
// ── Editing ──────────────────────────────────────────────────────────────
//
// No hooks and no renderers: YAML is the format the generic engine was
// written against. Its reference layer is core — the alias node kind,
// `AST.resolveAlias` and `AST.mergedChild`, the anchor and tag span
// tables on `Document` — so follow-mode replace and inherited-key
// detection are the engine's, the latter switched on by `merge_key`
// above. The value reframe that lets a block collection replace an
// inline one is the engine's too: the parser records every entry's `:`
// (`Document.node_sep_spans`) and the engine rewrites everything after
// the key. `editor_helper.zig` holds this format's editor tests.
};
// Test discovery: importing `yaml.zig` (from root.zig) pulls in every YAML
// submodule's tests, so the module owns its own test surface. The conformance
// suite is build-option-gated and stays in root.zig.
test {
_ = @import("tokenizer.zig");
_ = @import("parser.zig");
_ = @import("printer.zig");
_ = @import("editor_helper.zig");
}