From b07ef5058a13277dbde777184182fc81fbfc771a Mon Sep 17 00:00:00 2001 From: Ajay Ghanwat Date: Mon, 13 Jul 2026 20:48:22 +0530 Subject: [PATCH] fix: generate package examples from usage guides --- scripts/generate-docs.ts | 62 +++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/scripts/generate-docs.ts b/scripts/generate-docs.ts index 5198ae1c..29624589 100644 --- a/scripts/generate-docs.ts +++ b/scripts/generate-docs.ts @@ -171,23 +171,57 @@ function markdown(source: string): { html: string; headings: DocHeading[] } { } function examplesFrom(readme: string, name: string): string { - const examples = [...readme.matchAll(/```([^\n]*)\n([\s\S]*?)```/g)] - .map((match) => ({ language: match[1]!.trim(), code: match[2]!.trim() })) - .filter((example) => example.code) - .filter( - (example, index, all) => all.findIndex((value) => value.code === example.code) === index, - ) - .slice(0, 4); - if (!examples.length) { - examples.push({ - language: "ts", - code: `import * as packageApi from "@wrnexus/${name}";\n\nconsole.log(packageApi);`, - }); + const usage = /^## Usage\s*$([\s\S]*?)(?=^##\s|\s*$)/m.exec(readme)?.[1]; + if (!usage) throw new Error(`@wrnexus/${name} README must contain a Usage section`); + + const examples: { title: string; language: string; code: string }[] = []; + const lines = usage.replace(/\r/g, "").split("\n"); + let title = "Typical usage"; + let prose = ""; + for (let index = 0; index < lines.length; index++) { + const line = lines[index]!; + const heading = /^#{3,4}\s+(.+)$/.exec(line); + if (heading) { + title = heading[1]!.replace(/[`*_]/g, "").trim(); + prose = ""; + continue; + } + const fence = /^```(.*)$/.exec(line); + if (fence) { + const code: string[] = []; + index++; + while (index < lines.length && !/^```/.test(lines[index]!)) { + code.push(lines[index]!); + index++; + } + const value = code.join("\n").trim(); + const language = fence[1]!.trim(); + if (value && language !== "text" && !examples.some((example) => example.code === value)) { + examples.push({ + title: title === "Typical usage" && prose ? prose : title, + language, + code: value, + }); + } + prose = ""; + continue; + } + if (line.trim() && !/^[-*>|]/.test(line.trim())) { + prose = line + .replace(/[`*_]/g, "") + .replace(/\[([^\]]+)\]\([^)]+\)/g, "$1") + .replace(/:\s*$/, "") + .trim(); + } + } + if (examples.length < 2) { + throw new Error(`@wrnexus/${name} README needs at least two Usage code examples`); } return examples + .slice(0, 6) .map( - (example, index) => - `

Example ${index + 1}

${escape(example.code)}
`, + (example) => + `

${inline(example.title)}

${escape(example.code)}
`, ) .join(""); }