Skip to content

Commit 30c3256

Browse files
jaysin586claude
andcommitted
fix(vite): discover example mirrors from route folder when index array is absent
`exampleMirrorsPlugin` required a curated `const examples = [...]` array in the examples landing page and threw `Could not find const examples array` when the page built its list dynamically (e.g. a `$derived` sitemap walk). Make the index optional: parse the curated array when present, otherwise discover examples straight from the `examplesDir` route folder and derive the index from each page's SEO copy and primary section tag (instead of a generic label). Backward compatible — a curated array still drives ordering and tags. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 0ec41c5 commit 30c3256

1 file changed

Lines changed: 39 additions & 5 deletions

File tree

src/lib/vite/example-mirrors.ts

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@
1212
* Each per-example mirror includes fenced Svelte source copied from
1313
* `src/lib/examples/<slug>/demos/*.svelte`, so coding agents can fetch
1414
* runnable examples without scraping the interactive UI.
15+
*
16+
* The examples landing page may expose a curated `const examples = [{ slug,
17+
* title, tag, description }]` array to control index ordering and tags. When
18+
* it doesn't — a missing landing page, or one that builds its list
19+
* dynamically — the plugin discovers examples from the `examplesDir` route
20+
* folder and derives the index from each page's SEO copy and primary section
21+
* tag.
1522
*/
1623
import { existsSync } from 'node:fs'
1724
import { mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises'
@@ -165,8 +172,18 @@ async function parseExamplePages({
165172
)
166173
}
167174

175+
/**
176+
* Parse the optional curated `const examples = [{ slug, title, tag,
177+
* description }]` index from the examples landing page. Returns `[]` when the
178+
* page declares no such array — many sites build their index dynamically
179+
* (`$derived`, a sitemap walk, etc.), in which case the plugin discovers
180+
* examples straight from the route folder instead. A curated array, when
181+
* present, drives ordering and the advertised tags.
182+
*/
168183
function parseExampleIndex(source: string): ExampleIndexItem[] {
169-
const arraySource = extractConstArray(source, 'examples')
184+
const arraySource = findConstArray(source, 'examples')
185+
if (arraySource === null) return []
186+
170187
const objects = splitTopLevelObjects(arraySource)
171188

172189
return objects.map((objectSource) => ({
@@ -377,13 +394,16 @@ function renderExampleIndexMarkdown({
377394
pages: ExamplePageMirror[]
378395
opts: ResolvedOptions
379396
}): string {
397+
// When no curated index array is present, build the list from the
398+
// folder-discovered pages, advertising each example's primary section
399+
// tag (falling back to a generic label only when a page has no sections).
380400
const indexItems =
381401
items.length > 0
382402
? items
383403
: pages.map((page) => ({
384404
slug: page.slug,
385405
title: page.title,
386-
tag: 'EXAMPLE',
406+
tag: page.sections[0]?.tag ?? 'EXAMPLE',
387407
description: page.description
388408
}))
389409
const pageDescriptions = new Map(pages.map((page) => [page.slug, page.description]))
@@ -428,15 +448,29 @@ function codeFence(source: string, language: string): string {
428448
return `${fence}${language}\n${source.trimEnd()}\n${fence}`
429449
}
430450

431-
function extractConstArray(source: string, constName: string): string {
451+
/**
452+
* Locate a `const <name> = [ … ]` array literal and return its inner source,
453+
* or `null` when the file declares no such array (e.g. the index page builds
454+
* its list dynamically). Callers that require the array use
455+
* {@link extractConstArray}; callers that can fall back to folder discovery
456+
* use this nullable form directly.
457+
*/
458+
function findConstArray(source: string, constName: string): string | null {
432459
const pattern = new RegExp(`const\\s+${constName}\\b[^=]*=\\s*\\[`)
433460
const match = pattern.exec(source)
434-
if (!match)
435-
throw new Error(`[docs-kit:example-mirrors] Could not find const ${constName} array`)
461+
if (!match) return null
436462

437463
return readBalanced(source, match.index + match[0].length - 1, '[', ']')
438464
}
439465

466+
function extractConstArray(source: string, constName: string): string {
467+
const arraySource = findConstArray(source, constName)
468+
if (arraySource === null)
469+
throw new Error(`[docs-kit:example-mirrors] Could not find const ${constName} array`)
470+
471+
return arraySource
472+
}
473+
440474
function splitTopLevelObjects(source: string): string[] {
441475
const objects: string[] = []
442476
let index = 0

0 commit comments

Comments
 (0)