tests/blockRefs.test.ts
Rama main · réplica de lectura del repositorio original.
// Block references (shared/blockId.ts + shared/anchors.ts): the marker, the
// block a line belongs to, and the anchor table that `[[Note#^id]]` looks up.
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { blockRange, isBareBlockId, markdownBlock, mintBlockId, parseBlockId, stripBlockId, withBlockId } from "../shared/blockId.ts";
import { markdownAnchors, resolveAnchorIn } from "../shared/anchors.ts";
const NOTE = `---
title: x
---
# Title
First paragraph line one
line two ^para1
- item one ^it1
- item two
wrapped ^it2
- item three
Second paragraph.
^lone
\`\`\`
code ^notanid
\`\`\`
`;
describe("a block id", () => {
it("parses, strips and appends at the line's end", () => {
assert.deepEqual(parseBlockId("some text ^abc-12"), { id: "abc-12", start: 9 });
assert.equal(parseBlockId("a caret ^ in the middle"), null);
assert.equal(stripBlockId("some text ^abc"), "some text");
assert.equal(withBlockId("some text ^old", "new1"), "some text ^new1");
assert.equal(withBlockId("", "x"), "^x");
assert.equal(isBareBlockId(" ^abc "), true);
});
it("mints six lowercase alphanumerics", () => {
assert.match(mintBlockId(), /^[a-z0-9]{6}$/);
assert.equal(mintBlockId(() => 0), "aaaaaa");
});
});
describe("the block a line belongs to", () => {
const lines = NOTE.split("\n");
it("is the paragraph around it, walked up and down", () => {
assert.deepEqual(blockRange(lines, 6), { start: 5, end: 7 });
assert.deepEqual(blockRange(lines, 7), { start: 5, end: 7 });
});
it("is the list item with its wrapped continuation", () => {
assert.deepEqual(blockRange(lines, 9), { start: 8, end: 9 });
assert.deepEqual(blockRange(lines, 10), { start: 9, end: 11 });
});
it("is the block ABOVE a bare id line", () => {
assert.deepEqual(blockRange(lines, 15), { start: 13, end: 15 });
assert.equal(blockRange(lines, 5), null);
});
it("slices the block's markdown with the marker off", () => {
assert.equal(markdownBlock(NOTE, 7), "First paragraph line one\nline two");
assert.equal(markdownBlock(NOTE, 10), "- item two\n wrapped");
assert.equal(markdownBlock(NOTE, 15), "Second paragraph.");
});
});
describe("block ranges, the corners", () => {
it("is a quote's run of > lines, and the id comes off the last quoted line", () => {
const md = "> one\n> two ^q1\n\nafter";
assert.deepEqual(blockRange(md.split("\n"), 2), { start: 0, end: 2 });
assert.equal(markdownBlock(md, 2), "> one\n> two");
});
it("registers ^Abc and ^abc once, the first spelling winning", () => {
const anchors = markdownAnchors("a ^Abc\n\nb ^abc\n").filter((a) => a.kind === "block");
assert.deepEqual(anchors.map((a) => a.id), ["^Abc"]);
});
it("does not read a heading's tail as an id", () => {
assert.equal(markdownAnchors("# Title ^h1\n").some((a) => a.kind === "block"), false);
});
});
describe("block anchors", () => {
it("join the anchor table with the caret kept, titled by the block's text", () => {
const anchors = markdownAnchors(NOTE);
const blocks = anchors.filter((a) => a.kind === "block");
assert.deepEqual(blocks.map((a) => [a.id, a.line]), [["^para1", 7], ["^it1", 9], ["^it2", 11], ["^lone", 15]]);
assert.equal(blocks[0].title, "line two");
assert.equal(blocks[1].title, "item one");
assert.equal(blocks[3].title, "Second paragraph.");
// inside a fence is code, not an address
assert.equal(anchors.some((a) => a.id === "^notanid"), false);
// the heading is still there
assert.equal(anchors[0].id, "title");
});
it("resolves [[Note#^id]] the way findAnchor already resolves headings", () => {
assert.equal(resolveAnchorIn("n.md", NOTE, "^it2")?.line, 11);
assert.equal(resolveAnchorIn("n.md", NOTE, "^nope"), null);
});
});