Minimal YAML to JSON Converter
A Node script that parses a small, common subset of YAML (key-value pairs, nested maps, and simple lists) and prints the equivalent JSON document.
Project
node-yaml-to-json
Entry point: yaml2json.mjs
Install
node --versionRun
node yaml2json.mjs sample.yamlTest
node --test yaml2json.test.mjsExpected output
Prints the JSON representation of the YAML file with nested maps and lists preserved.Dependencies
- node >=20
What it does
Parses a deliberately small subset of YAML using indentation, which is enough for simple configuration files and shows how indentation-sensitive parsing works.
import { readFileSync } from 'node:fs';
function parseYaml(text) {
const lines = text.split(/\r?\n/).filter((l) => l.trim() && !l.trim().startsWith('#'));
const root = {};
const stack = [{ indent: -1, value: root }];
for (const line of lines) {
const indent = line.match(/^ */)[0].length;
const content = line.trim();
while (stack.length > 1 && indent <= stack[stack.length - 1].indent) stack.pop();
const parent = stack[stack.length - 1].value;
if (content.startsWith('- ')) {
if (!Array.isArray(parent)) throw new Error('list without a key: ' + content);
parent.push(coerce(content.slice(2)));
continue;
}
const [key, ...rest] = content.split(':');
const value = rest.join(':').trim();
if (value === '') {
const child = {};
parent[key.trim()] = child;
stack.push({ indent, value: child });
} else parent[key.trim()] = coerce(value);
}
return root;
}
function coerce(value) {
if (value === 'true' || value === 'false') return value === 'true';
if (/^-?\d+$/.test(value)) return Number(value);
return value.replace(/^["']|["']$/g, '');
}
console.log(JSON.stringify(parseYaml(readFileSync(process.argv[2] ?? 'sample.yaml', 'utf8')), null, 2));
It handles scalars, nested maps, and dash lists, and explicitly does not attempt anchors, multi-line scalars, or flow syntax.
Run and verify
printf 'name: demo\nport: 3000\ntags:\n - a\n - b\n' > sample.yaml
node yaml2json.mjs sample.yaml
Create the small YAML sample then convert it; nesting is driven entirely by indentation.
Expected Output
For the sample the program should print JSON with the number, string, and list preserved. The output is:
{
"name": "demo",
"port": 3000,
"tags": [
"a",
"b"
]
}
Numeric scalars become numbers, booleans become booleans, and nested keys are placed inside their parent map rather than flattened.
Limitations
It supports a small subset only; anchors, block scalars, flow collections, and quoted keys are out of scope and need a full parser.