diff --git a/.github/workflows/search.yml b/.github/workflows/search.yml index b3d60d06629..b4631ceca5d 100644 --- a/.github/workflows/search.yml +++ b/.github/workflows/search.yml @@ -9,7 +9,12 @@ on: - 'supabase/migrations/**' - 'apps/docs/**' - 'spec/**' - workflow_dispatch: {} + workflow_dispatch: + inputs: + refresh: + description: 'Refresh all pages' + required: false + type: boolean schedule: - cron: '0 0 * * *' @@ -46,6 +51,12 @@ jobs: - name: Run migrations run: npx supabase db push + - name: Update embeddings + working-directory: ./apps/docs + if: ${{ !inputs.refresh }} + run: npm run embeddings + - name: Refresh embeddings working-directory: ./apps/docs - run: npm run embeddings + if: ${{ inputs.refresh }} + run: npm run embeddings:refresh diff --git a/apps/docs/scripts/search/sources/markdown.ts b/apps/docs/scripts/search/sources/markdown.ts index 851839a772b..91beb6cc01a 100644 --- a/apps/docs/scripts/search/sources/markdown.ts +++ b/apps/docs/scripts/search/sources/markdown.ts @@ -96,6 +96,23 @@ export function splitTreeBy(tree: Root, predicate: (node: Content) => boolean) { }, []) } +/** + * Parses a markdown heading which can optionally + * contain a custom anchor in the format: + * + * ```markdown + * ### My Heading [#my-custom-anchor] + * ``` + */ +export function parseHeading(heading: string): { heading: string; customAnchor?: string } { + const match = heading.match(/(.*) *\[#(.*)\]/) + if (match) { + const [, heading, customAnchor] = match + return { heading, customAnchor } + } + return { heading } +} + /** * Processes MDX content for search indexing. * It extracts metadata, strips it of all JSX, @@ -140,12 +157,20 @@ export function processMdxForSearch(content: string): ProcessedMdx { const sections = sectionTrees.map((tree) => { const [firstNode] = tree.children + const content = toMarkdown(tree) - const heading = firstNode.type === 'heading' ? toString(firstNode) : undefined - const slug = heading ? slugger.slug(heading) : undefined + const rawHeading: string = firstNode.type === 'heading' ? toString(firstNode) : undefined + + if (!rawHeading) { + return { content } + } + + const { heading, customAnchor } = parseHeading(rawHeading) + + const slug = slugger.slug(customAnchor ?? heading) return { - content: toMarkdown(tree), + content, heading, slug, }