@stoplight/yaml-ast-parser review
@stoplight/yaml-ast-parser 0.0.50 is a CommonJS fork of js-yaml that returns a position-bearing syntax tree instead of an ordinary JavaScript object. Maps contain mapping nodes, sequences contain item nodes, scalars retain raw text, and recovered parse errors are attached to the document. It also recognizes RAML `!include` references without loading their files. The current npm version was published in March 2024, yet it has no matching Git tag or release note; the only GitHub release is 0.0.45. Use it for existing Stoplight or RAML tooling that needs this exact AST, not as a fresh general-purpose YAML choice.
@stoplight/yaml-ast-parser 0.0.50 installed in 1.4 seconds with 0 dependencies and 0 audit findings in our sandbox, but its browser bundle failed and its release has no matching Git tag or notes. Keep it for tooling already coupled to this recoverable RAML-aware AST; new YAML editors should start with `yaml`.
We installed it
| Install | ✓ · 1.4s | 1 package on disk · 1 MB |
| Import | ✓ | ESM import works · require() works · CommonJS package |
| Browser | n/a | could not be bundled for the browser (Node-only code, most likely) |
| Types | ✓ | TypeScript types bundled |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does @stoplight/yaml-ast-parser install cleanly?
Yes. In a fresh container with an empty cache, npm install @stoplight/yaml-ast-parser finished in 1 seconds, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.
Can @stoplight/yaml-ast-parser run in a browser?
Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.
Does @stoplight/yaml-ast-parser work with both ESM and CommonJS?
Yes. Both import '@stoplight/yaml-ast-parser' and require('@stoplight/yaml-ast-parser') worked in Node 22 in our run. The package is published as CommonJS.
Does @stoplight/yaml-ast-parser include TypeScript types?
Yes, type declarations ship inside the package, so no @types install is needed.
@stoplight/yaml-ast-parser or yaml: which should you use?
yaml: Use it for a maintained YAML 1.2 parser with document, CST, schema, comment, and stringification APIs. @stoplight/yaml-ast-parser 0.0.50 installed in 1.4 seconds with 0 dependencies and 0 audit findings in our sandbox, but its browser bundle failed and its release has no matching Git tag or notes.
When should you not use @stoplight/yaml-ast-parser?
You only need a JavaScript value from YAML. yaml and js-yaml have current documentation and avoid this package's custom tree traversal.
Use it if
- An existing Stoplight, Spectral, or RAML workflow expects the package's numeric `Kind` enum and `YAMLNode` interfaces.
- An editor or linter needs UTF-16 source offsets, comments, and recoverable diagnostics rather than a plain parsed value.
- RAML `!include` tokens must appear as AST nodes so another layer can resolve them under its own path policy.
- Code must inspect duplicate keys or malformed input while still receiving a partial syntax tree.
- You only need a JavaScript value from YAML. `yaml` and `js-yaml` have current documentation and avoid this package's custom tree traversal.
- A browser bundle is required. Our esbuild browser build failed, so version 0.0.50 did not produce a browser artifact in the measured setup.
- You need a documented round-trip editor that preserves formatting while applying node edits. The README covers AST inspection and ranges, not a patch or document-editing API.
- A mature compatibility contract matters. The version remains 0.0.50, node interfaces expose deprecated `any` fields, and the current npm release has no matching repository tag or release notes.
- You expect `!include` to read files safely. The parser only records an include-reference node; your application must resolve paths, enforce a root, detect cycles, and read content.
Setup reality
We installed @stoplight/yaml-ast-parser 0.0.50 in a fresh Node 22 Bookworm sandbox. npm took 1.4 seconds and left 1 package using 1 MB on disk. The package is 956 KB unpacked with 0 direct and 0 peer dependencies. npm audit reported 0 known vulnerabilities. It bundles TypeScript declarations.
The artifact is CommonJS with no exports map. Both require() and ESM import worked in our Node 22 checks. No credential, native compiler, or configuration file is needed. A browser bundle could not be built by esbuild in the measured environment, so do not assume the parser belongs in a client-side editor without testing your exact bundler and target.
load() returns a YAMLNode, not a plain object. Branch on Kind before reading mappings, items, or scalar values. The parser often recovers and places diagnostics in errors; receiving a root node does not establish that input is valid. Positions are offsets into the original JavaScript string, measured in UTF-16 code units. Convert carefully before patching a UTF-8 file buffer.
Comments are collected separately rather than attached to the mapping or item they describe. loadAll() reports each YAML document through a callback. RAML includes remain unresolved syntax. Version 0.0.50 ships generated tests and declarations built with an older toolchain, and the public README documents only the main node shapes. Budget time to read the declarations and tests before depending on loader options, dump behavior, or scalar inference in production.
Patterns
Load YAML and reject recovered errors parse-syntax-tree
import * as YAML from '@stoplight/yaml-ast-parser';
const source = 'name: demo\nenabled: true\n';
const root = YAML.load(source);
if (root.errors.length > 0) {
throw new Error(root.errors.map(error => error.reason).join('; '));
}Version 0.0.50 can return a tree after syntax recovery. An empty `errors` array is the check for a clean parse.
Check the node kind before reading a map narrow-node-kind
if (root.kind !== YAML.Kind.MAP) {
throw new TypeError('expected a YAML map');
}
const mappings = (root as YAML.YamlMap).mappings;Map, mapping-pair, sequence, scalar, anchor-reference, and include-reference nodes have different fields. Deprecated convenience fields are broadly typed.
Locate a named mapping entry find-map-value
const pair = (root as YAML.YamlMap).mappings.find(
mapping => mapping.key.value === 'name',
);
if (pair?.value.kind === YAML.Kind.SCALAR) {
console.log((pair.value as YAML.YAMLScalar).value);
}A map stores `YAMLMapping` pairs. The mapping value is another node and still needs a kind check.
Traverse the six AST node kinds walk-all-nodes
function* walk(node: YAML.YAMLNode): Generator<YAML.YAMLNode> {
yield node;
if (node.kind === YAML.Kind.MAP) {
for (const pair of (node as YAML.YamlMap).mappings) yield* walk(pair);
} else if (node.kind === YAML.Kind.MAPPING) {
yield* walk((node as YAML.YAMLMapping).key);
yield* walk((node as YAML.YAMLMapping).value);
} else if (node.kind === YAML.Kind.SEQ) {
for (const item of (node as YAML.YAMLSequence).items) yield* walk(item);
}
}The public tree has no general `children()` method. Mapping pairs are nodes and must be visited if their ranges or errors matter.
Recover the exact text covered by a node slice-original-source
const original = source.slice(node.startPosition, node.endPosition);Positions count UTF-16 code units in the JavaScript string. They are not UTF-8 byte offsets for a Buffer.
Turn parser marks into editor positions report-diagnostics
const diagnostics = root.errors.map(error => ({
message: error.reason,
severity: error.isWarning ? 'warning' : 'error',
line: error.mark?.line ?? 0,
column: error.mark?.column ?? 0,
}));Mark line and column values are zero-based. Add 1 only at a UI boundary that displays one-based positions.
Collect every document in a YAML stream parse-document-stream
const documents: YAML.YAMLNode[] = [];
YAML.loadAll(source, document => documents.push(document));
for (const document of documents) {
console.log(document.errors);
}`loadAll()` uses a callback and returns void. Each document has its own root and error list.
Read document-level comment ranges inspect-comments
const document = YAML.safeLoad('name: demo # public label\n');
for (const comment of document.comments ?? []) {
console.log(source.slice(comment.startPosition, comment.endPosition));
}Comments are collected separately. The parser does not assign a comment to a particular key or sequence item.
Infer a scalar before converting it classify-scalar
const scalar = pair.value as YAML.YAMLScalar;
const scalarType = YAML.determineScalarType(scalar);
if (scalarType === YAML.ScalarType.int) {
const value = YAML.parseYamlBigInteger(scalar.value);
}Scalar text and inferred type are separate. Big integers may return a number or bigint depending on the value.
Keep duplicate-key diagnostics enabled detect-duplicate-keys
const document = YAML.load('name: first\nname: second\n');
const reasons = document.errors.map(error => error.reason);Loader options can ignore duplicate keys, but downstream meaning stays ambiguous. Configuration and API descriptions should normally reject them.
Collect unresolved RAML include nodes find-raml-includes
const document = YAML.load('schema: !include schema.json\n');
const includes = [...walk(document)].filter(
node => node.kind === YAML.Kind.INCLUDE_REF,
);An `INCLUDE_REF` records source syntax only. Resolve it beneath an allowed root and detect recursive includes in application code.
Read an anchor reference and its resolved node inspect-anchor-reference
for (const node of walk(root)) {
if (node.kind === YAML.Kind.ANCHOR_REF) {
const ref = node as YAML.YAMLAnchorReference;
console.log(ref.referencesAnchor, ref.value);
}
}Anchor references carry the anchor name and a node value. Preserve node ranges if diagnostics must point back to the alias token.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| yaml | npm | Use it for a maintained YAML 1.2 parser with document, CST, schema, comment, and stringification APIs. |
| js-yaml | npm | Use it when the task is conventional YAML parsing and dumping rather than source-aware AST diagnostics. |
| yaml-ast-parser | npm | Use the original unscoped package only when an old dependency requires that exact package name; it is older than the Stoplight fork. |
| @stoplight/spectral-core | npm | Use Spectral's core when the actual goal is linting structured documents with rules and diagnostics, not maintaining a parser directly. |
More utils guides
lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

