Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a9ba44c
fix(llm): preserve valid Setext heading anchors
KayleeWilliams Aug 23, 2026
9227528
fix(llm): retain CRLF Setext headings
KayleeWilliams Aug 23, 2026
fb73028
fix(llm): strip quoted inline HTML tags
KayleeWilliams Aug 23, 2026
3c576fd
fix(llm): align HTML block heading detection
KayleeWilliams Aug 23, 2026
508f480
fix(llm): preserve inline heading text
KayleeWilliams Aug 23, 2026
64d2da5
fix(llm): classify quoted standalone tags
KayleeWilliams Aug 23, 2026
c5b7257
fix(llm): allow quoted tag delimiters
KayleeWilliams Aug 23, 2026
4a26db4
fix(llm): parse heading HTML constructs safely
KayleeWilliams Aug 23, 2026
308956c
fix(llm): align MDX heading constructs
KayleeWilliams Aug 24, 2026
a653e8e
fix(llm): recognize MDX heading fragments
KayleeWilliams Aug 24, 2026
45b70f5
fix(llm): refine MDX heading markers
KayleeWilliams Aug 24, 2026
021c95a
fix(llm): parse MDX heading attributes
KayleeWilliams Aug 24, 2026
9ccff47
fix(llm): parse MDX expression literals
KayleeWilliams Aug 24, 2026
2d76d8e
fix(llm): parse regex after statement blocks
KayleeWilliams Aug 24, 2026
0a2c6fa
fix(llm): track nested MDX expressions
KayleeWilliams Aug 24, 2026
45c745e
fix(llm): accept MDX identifier characters
KayleeWilliams Aug 24, 2026
4944ec8
fix(llm): classify JavaScript block slashes
KayleeWilliams Aug 24, 2026
2ee111f
fix(llm): track JavaScript block contexts
KayleeWilliams Aug 24, 2026
2153594
fix(llm): stack JavaScript statement contexts
KayleeWilliams Aug 24, 2026
17ed2f3
fix(llm): classify postfix update operators
KayleeWilliams Aug 24, 2026
093f3e6
fix(llm): stack nested case contexts
KayleeWilliams Aug 24, 2026
4bb8d0f
fix(llm): parse Unicode identifiers and spreads
KayleeWilliams Aug 24, 2026
58986cf
fix(llm): classify class heritage operands
KayleeWilliams Aug 24, 2026
d2a6bdf
refactor(llm): clarify update operator state
KayleeWilliams Aug 24, 2026
b9d34d8
fix(llm): recognize class static blocks
KayleeWilliams Aug 24, 2026
cb08d5e
fix(llm): distinguish class member names
KayleeWilliams Aug 24, 2026
cf5b07e
fix(llm): parse escaped class identifiers
KayleeWilliams Aug 24, 2026
bdf6510
fix(llm): preserve lazy identifier scanning
KayleeWilliams Aug 24, 2026
4fb0caf
fix(llm): recognize binding-less catch blocks
KayleeWilliams Aug 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/setext-heading-scanner.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"leadtype": patch
---

Keep table-of-contents and search anchors aligned with rendered Setext and ATX headings containing inline HTML or MDX markup, including indentation and line-ending edge cases.
1 change: 1 addition & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/leadtype/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@
"mdast-util-mdx": "3.0.0",
"mdast-util-mdx-jsx": "3.2.0",
"mdast-util-mdxjs-esm": "2.0.1",
"micromark-util-html-tag-name": "2.0.1",
"react": "^19.0.0",
"rollup": "^4.40.0",
"rollup-plugin-dts": "^6.2.1",
Expand Down
63 changes: 62 additions & 1 deletion packages/leadtype/src/internal/docs-heading.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import { htmlBlockNames } from "micromark-util-html-tag-name";
import { describe, expect, it } from "vitest";
import { createDocsHeadingSlugger, slugifyDocsHeading } from "./docs-heading";
import {
createDocsHeadingSlugger,
docsHtmlBlockTagNames,
scanDocsMarkdown,
slugifyDocsHeading,
} from "./docs-heading";

describe("docs HTML block tags", () => {
it("matches the tag list used by the Markdown parser", () => {
expect(docsHtmlBlockTagNames).toEqual(htmlBlockNames);
});
});

describe("createDocsHeadingSlugger", () => {
it("suffixes duplicate slugs the way extractDocsTableOfContents does", () => {
Expand Down Expand Up @@ -46,3 +58,52 @@ describe("createDocsHeadingSlugger", () => {
expect(slugger.slug("Foo")).toBe("foo-2");
});
});

describe("scanDocsMarkdown", () => {
it("recognizes binding-less catch statement bodies", () => {
const [heading] = scanDocsMarkdown(
`## <Badge onClick={() => { try {} catch { function helper() {} /don't/.test(value); } }} /> Install`
);

expect(heading).toEqual({ kind: "heading", level: 2, title: "Install" });
});

it("rejects malformed escaped class binding starts", () => {
const invalidBindingStarts = [
[
"\\x61",
"<Badge value= class \\x61 static function helper /don't/.test value ; /> Install",
],
[
"\\u{}",
"<Badge value= class \\u static function helper /don't/.test value ; /> Install",
],
// This also guards the range check before String.fromCodePoint, which
// would throw for an out-of-range escape instead of rejecting it.
[
"\\u{110000}",
"<Badge value= class \\u 110000 static function helper /don't/.test value ; /> Install",
],
[
"\\u0030",
"<Badge value= class \\u0030 static function helper /don't/.test value ; /> Install",
],
[
"\\uD800",
"<Badge value= class \\uD800 static function helper /don't/.test value ; /> Install",
],
];

for (const [bindingStart, expectedTitle] of invalidBindingStarts) {
const [heading] = scanDocsMarkdown(
`## <Badge value={class ${bindingStart} { static { function helper() {} /don't/.test(value); } }} /> Install`
);

expect(heading).toEqual({
kind: "heading",
level: 2,
title: expectedTitle,
});
}
});
});
Loading
Loading