feat(course-format): markdown extraction, discovery, loading, repository
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7a68800f6f
commit
c78c7ec8d8
7 files changed
+558
-2
No files matched your search
@@ -0,0 +1,89 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { extractHints, extractSection, slugify } from "../src/markdown";
|
||||
|
||||
describe("slugify", () => {
|
||||
test("follows GitHub's algorithm", () => {
|
||||
expect(slugify("Exercise 3.1 — `move`")).toBe("exercise-31--move");
|
||||
expect(slugify("Why this module")).toBe("why-this-module");
|
||||
expect(slugify("Rules as functions `State → State`")).toBe("rules-as-functions-state--state");
|
||||
expect(slugify("**Bold** and [a link](http://x.y)")).toBe("bold-and-a-link");
|
||||
});
|
||||
});
|
||||
|
||||
const sample = `# Top
|
||||
|
||||
intro
|
||||
|
||||
## First
|
||||
|
||||
one
|
||||
|
||||
### Middle
|
||||
|
||||
middle body
|
||||
|
||||
\`\`\`sh
|
||||
# not a heading
|
||||
\`\`\`
|
||||
|
||||
#### Deeper
|
||||
|
||||
deep body
|
||||
|
||||
### Sibling
|
||||
|
||||
sibling body
|
||||
|
||||
## Last
|
||||
|
||||
end
|
||||
`;
|
||||
|
||||
describe("extractSection", () => {
|
||||
test("returns only the middle section, including deeper headings", () => {
|
||||
const s = extractSection(sample, "middle");
|
||||
expect(s).not.toBeNull();
|
||||
expect(s!.startsWith("### Middle")).toBe(true);
|
||||
expect(s).toContain("# not a heading");
|
||||
expect(s).toContain("deep body");
|
||||
expect(s).not.toContain("sibling body");
|
||||
expect(s).not.toContain("one");
|
||||
});
|
||||
test("returns null for an unknown anchor", () => {
|
||||
expect(extractSection(sample, "nope")).toBeNull();
|
||||
});
|
||||
test("a section runs to the end of file when nothing follows", () => {
|
||||
expect(extractSection(sample, "last")).toBe("## Last\n\nend");
|
||||
});
|
||||
});
|
||||
|
||||
describe("extractHints", () => {
|
||||
const md = `## Hints
|
||||
|
||||
<details><summary>Exercise 3.1 (move) — nudge</summary>
|
||||
|
||||
Think about direction.
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>Exercise 3.1 (move) — stronger hint</summary>
|
||||
|
||||
Add the delta.
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>Exercise 3.2 (inBounds) — nudge</summary>
|
||||
|
||||
Other.
|
||||
|
||||
</details>
|
||||
`;
|
||||
test("returns matching blocks in order with trimmed labels", () => {
|
||||
const h = extractHints(md, "Exercise 3.1 (move)");
|
||||
expect(h.map((x) => x.label)).toEqual(["nudge", "stronger hint"]);
|
||||
expect(h[0]!.body).toBe("Think about direction.");
|
||||
});
|
||||
test("returns [] when nothing matches", () => {
|
||||
expect(extractHints(md, "Exercise 9.9")).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user