Skip to content

Commit 098445c

Browse files
committed
fix(docs): preserve explicit search heading links
1 parent 6519ba4 commit 098445c

4 files changed

Lines changed: 32 additions & 25 deletions

File tree

‎apps/docs/AGENTS.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Read [EDITORIAL_GUIDE.md](EDITORIAL_GUIDE.md) before editing documentation. It d
1414
- Edit generated API and CLI prose at its owner, then use the generation commands in the editorial guide. Do not hand-edit generated specifications, reference pages, or marked generated regions.
1515
- Preserve page URLs, operation IDs, method/path pairs, command options, authentication, and schema behavior. Validate copyable request bodies against the canonical input contracts.
1616
- Check inbound heading anchors from the entire docs site and application before renaming them. Use native explicit tab triggers for provider bookmarks, with `aria-controls` matching panel IDs; preserve the reciprocal `aria-labelledby` relationship and avoid duplicate element IDs.
17+
- Search citations must use the page's explicit heading IDs and omit the alias syntax from result titles.
1718

1819
## Layout and components
1920

‎apps/docs/INTEGRATIONS_AUDIT.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ PR review checked the capability boundaries again against each operation. Correc
4848

4949
## Validation
5050

51+
Search citation extraction now honors explicit heading IDs without including alias syntax in result titles. Retained parser regressions fail before the fix and when either ID preservation or label cleanup is removed; ordinary heading links remain unchanged.
52+
5153
Completed local validation:
5254

5355
- All three independent before/after reviews reached a qualified pass after their findings were corrected and reread.

‎apps/sim/lib/chunkers/docs-chunker.test.ts‎

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { describe, expect, it, vi } from 'vitest'
66

77
vi.mock('@/lib/knowledge/embeddings', () => knowledgeEmbeddingsMock)
88

9-
import { mkdtemp, writeFile } from 'fs/promises'
9+
import { mkdtemp, rm, writeFile } from 'fs/promises'
1010
import { tmpdir } from 'os'
1111
import { join } from 'path'
1212
import { ChunkLimitExceededError } from '@/lib/chunkers/chunk-budget'
@@ -129,28 +129,6 @@ describe('DocsChunker output budget', () => {
129129
*/
130130
describe('DocsChunker page title', () => {
131131
const NAV_LINK = '[Next](/docs/tables/workflow-columns)'
132-
const PARAGRAPH =
133-
'Tables store rows your workflows read and write. Columns are typed, and every write is validated against the schema before it lands, so a bad row never reaches a downstream block. '
134-
const _BODY = `# Tables
135-
136-
${PARAGRAPH.repeat(3)}
137-
138-
## Querying rows
139-
140-
Use the Table block to query, insert, or update rows from a workflow. ${PARAGRAPH.repeat(3)}
141-
142-
## ${NAV_LINK}
143-
144-
${NAV_LINK}
145-
`
146-
147-
async function _chunkPage(content: string) {
148-
const dir = await mkdtemp(join(tmpdir(), 'docs-chunker-'))
149-
const file = join(dir, 'tables.mdx')
150-
await writeFile(file, content)
151-
return new DocsChunker({ chunkSize: 100, chunkOverlap: 0 }).chunkMdxFile(file, dir)
152-
}
153-
154132
it('never resolves a link-only heading as the title', () => {
155133
expect(
156134
resolveDocumentTitle({}, [{ level: 2, text: NAV_LINK, anchor: 'next', position: 0 }])
@@ -163,3 +141,27 @@ ${NAV_LINK}
163141
).toBe('Tables')
164142
})
165143
})
144+
145+
describe('DocsChunker section links', () => {
146+
it.each([
147+
['Use the block [#usage-instructions]', 'Use the block', 'usage-instructions'],
148+
['Renamed section [#Stable.ID-v2]', 'Renamed section', 'Stable.ID-v2'],
149+
['Ordinary heading', 'Ordinary heading', 'ordinary-heading'],
150+
])('links %s to its rendered section', async (heading, label, anchor) => {
151+
const dir = await mkdtemp(join(tmpdir(), 'docs-section-links-'))
152+
try {
153+
const file = join(dir, 'guide.mdx')
154+
await writeFile(
155+
file,
156+
`## ${heading}\n\nSearch results should take readers to the matching section of a page. Stable section identifiers preserve those links when headings change, and the result title should contain only the visible heading.`
157+
)
158+
const chunks = await new DocsChunker({ chunkOverlap: 0 }).chunkMdxFile(file, dir)
159+
160+
expect(chunks).toHaveLength(1)
161+
expect(chunks[0]?.headerLink).toBe(`https://docs.sim.ai/guide#${anchor}`)
162+
expect(chunks[0]?.headerText).toBe(label)
163+
} finally {
164+
await rm(dir, { recursive: true, force: true })
165+
}
166+
})
167+
})

‎apps/sim/lib/chunkers/docs-chunker.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,10 +218,12 @@ export class DocsChunker {
218218

219219
while ((match = headerRegex.exec(content)) !== null) {
220220
const level = match[1].length
221-
const text = match[2].trim()
221+
const rawText = match[2].trim()
222+
const aliasMatch = /\s*\[#(.+?)]\s*$/.exec(rawText)
223+
const text = aliasMatch ? rawText.slice(0, aliasMatch.index).trimEnd() : rawText
222224
// A heading that is only a link (`## [Next](…)`) is navigation, not a section.
223225
if (LINK_ONLY_LINE.test(text)) continue
224-
const anchor = this.generateAnchor(text)
226+
const anchor = aliasMatch?.[1] ?? this.generateAnchor(text)
225227

226228
headers.push({
227229
text,

0 commit comments

Comments
 (0)