feat(core): adopt remark/unified as the internal Markdown parser (ADR 0002)

Add unified + remark-parse as dependencies of @kitchen-md/core and wire a
private internal processor (packages/core/src/markdown.ts) that parses
CommonMark into mdast. remark stays an implementation detail and is not
re-exported from the package entry, so consumers take no transitive remark
dependency (ADR 0003).

The OFM wikilink plugin and the public parse/AST surface are deferred to the
core-parser spec: canonical remark-wiki-link@2.0.1 targets an old micromark
generation incompatible with remark-parse@11, and OFM plus annotation
handling is that spec's scope.

This also exercises the flake's bun2nix vendoring against a real dependency
closure (58 vendored packages); nix build still compiles a working binary
offline in the sandbox.
This commit is contained in:
2026-07-25 21:11:01 -04:00
parent 09b9d432c2
commit 3a7b4f2456
5 changed files with 296 additions and 0 deletions

View File

@@ -8,5 +8,12 @@
},
"scripts": {
"test": "bun test"
},
"dependencies": {
"remark-parse": "^11.0.0",
"unified": "^11.0.5"
},
"devDependencies": {
"@types/mdast": "^4.0.4"
}
}

View File

@@ -0,0 +1,10 @@
// core's internal CommonMark parser, built on remark/unified.
import type { Root } from "mdast";
import remarkParse from "remark-parse";
import { unified } from "unified";
const processor = unified().use(remarkParse);
export function parseMarkdown(source: string): Root {
return processor.parse(source);
}

View File

@@ -0,0 +1,20 @@
import { describe, expect, test } from "bun:test";
import { parseMarkdown } from "./markdown.ts";
describe("internal markdown parser", () => {
test("parses CommonMark into an mdast root", () => {
const tree = parseMarkdown("# Title\n\nA paragraph.\n");
expect(tree.type).toBe("root");
expect(tree.children[0]?.type).toBe("heading");
expect(tree.children[1]?.type).toBe("paragraph");
});
test("represents a fenced code block as a code node with its value verbatim", () => {
const tree = parseMarkdown("```\n@ladle{}\n```\n");
const first = tree.children[0];
expect(first?.type).toBe("code");
expect(first).toMatchObject({ value: "@ladle{}" });
});
});