sourcey 3.3.5 → 3.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +3 -3
  2. package/dist/cli.js +0 -1
  3. package/dist/client/index.js +0 -1
  4. package/dist/components/App.js +0 -1
  5. package/dist/components/layout/Head.js +0 -1
  6. package/dist/components/layout/Header.js +0 -1
  7. package/dist/components/layout/Page.js +0 -1
  8. package/dist/components/layout/Sidebar.js +0 -1
  9. package/dist/components/layout/TableOfContents.js +0 -1
  10. package/dist/components/openapi/CodeSamples.js +0 -1
  11. package/dist/components/openapi/Definition.js +0 -1
  12. package/dist/components/openapi/EndpointBar.js +0 -1
  13. package/dist/components/openapi/Introduction.js +0 -1
  14. package/dist/components/openapi/Operation.js +0 -1
  15. package/dist/components/openapi/Parameters.js +0 -1
  16. package/dist/components/openapi/RequestBody.js +0 -1
  17. package/dist/components/openapi/Responses.js +0 -1
  18. package/dist/components/openapi/Security.js +0 -1
  19. package/dist/components/openapi/Tags.js +0 -1
  20. package/dist/components/schema/ExampleView.js +0 -1
  21. package/dist/components/schema/SchemaDatatype.js +0 -1
  22. package/dist/components/schema/SchemaView.js +0 -1
  23. package/dist/components/ui/Badge.js +0 -1
  24. package/dist/components/ui/CopyButton.js +0 -1
  25. package/dist/components/ui/Logo.js +0 -1
  26. package/dist/components/ui/Markdown.js +0 -1
  27. package/dist/components/ui/SectionLabel.js +0 -1
  28. package/dist/components/ui/SocialIcon.js +0 -1
  29. package/dist/config.d.ts +11 -0
  30. package/dist/config.d.ts.map +1 -1
  31. package/dist/config.js +1 -1
  32. package/dist/core/converter.js +0 -1
  33. package/dist/core/doxygen-loader.d.ts.map +1 -1
  34. package/dist/core/doxygen-loader.js +158 -4
  35. package/dist/core/loader.js +0 -1
  36. package/dist/core/markdown-loader.js +0 -1
  37. package/dist/core/navigation.js +0 -1
  38. package/dist/core/normalizer.js +0 -1
  39. package/dist/core/parser.js +0 -1
  40. package/dist/core/search-indexer.js +0 -1
  41. package/dist/core/types.js +0 -1
  42. package/dist/dev-server.d.ts.map +1 -1
  43. package/dist/dev-server.js +217 -31
  44. package/dist/index.js +0 -1
  45. package/dist/init.js +0 -1
  46. package/dist/renderer/context.js +0 -1
  47. package/dist/renderer/html-builder.js +0 -1
  48. package/dist/renderer/static-renderer.js +0 -1
  49. package/dist/utils/code-samples.js +0 -1
  50. package/dist/utils/copy-svg.js +0 -1
  51. package/dist/utils/example-generator.js +0 -1
  52. package/dist/utils/highlighter.js +0 -1
  53. package/dist/utils/html-id.js +0 -1
  54. package/dist/utils/http.js +0 -1
  55. package/dist/utils/icons.js +0 -1
  56. package/dist/utils/lang-icons.js +0 -1
  57. package/dist/utils/markdown.js +0 -1
  58. package/dist/vite-plugin.js +0 -1
  59. package/package.json +4 -4
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  Sourcey is an open source documentation platform. Point it at an OpenAPI spec, add markdown guides, get a complete docs site. Static HTML you own; no dashboard, no monthly bill, no API calls to render your own documentation. Deploy anywhere.
6
6
 
7
7
  [![npm](https://img.shields.io/npm/v/sourcey)](https://www.npmjs.com/package/sourcey)
8
- [![build](https://img.shields.io/github/actions/workflow/status/sourcey/sourcey/ci.yml?branch=master)](https://github.com/sourcey/sourcey/actions)
8
+ [![build](https://img.shields.io/github/actions/workflow/status/nilstate/sourcey/ci.yml?branch=master)](https://github.com/nilstate/sourcey/actions)
9
9
  [![node](https://img.shields.io/node/v/sourcey)](https://nodejs.org)
10
10
 
11
11
  ```bash
@@ -14,7 +14,7 @@ npx sourcey init
14
14
 
15
15
  ![Sourcey](assets/screenshot.jpg)
16
16
 
17
- **[Live demo](https://cheesestore.github.io/)** · [Documentation](https://sourcey.com/docs) · [GitHub](https://github.com/sourcey/sourcey)
17
+ **[Live demo](https://cheesestore.github.io/)** · [Documentation](https://sourcey.com/docs) · [GitHub](https://github.com/nilstate/sourcey)
18
18
 
19
19
  ## Features
20
20
 
@@ -159,7 +159,7 @@ sourcey validate api.yaml Validate a spec file
159
159
  ## Development
160
160
 
161
161
  ```bash
162
- git clone https://github.com/sourcey/sourcey.git
162
+ git clone https://github.com/nilstate/sourcey.git
163
163
  cd sourcey && npm install
164
164
  npm run build && npm test
165
165
 
package/dist/cli.js CHANGED
@@ -162,4 +162,3 @@ const main = defineCommand({
162
162
  },
163
163
  });
164
164
  runMain(main);
165
- //# sourceMappingURL=cli.js.map
@@ -5,4 +5,3 @@ import "./scroll-tracker.js";
5
5
  import "./tabs.js";
6
6
  import "./theme-toggle.js";
7
7
  import "./search.js";
8
- //# sourceMappingURL=index.js.map
@@ -10,4 +10,3 @@ export function App({ spec, options, navigation, currentPage, site }) {
10
10
  const content = options.embeddable ? (_jsx(Page, {})) : (_jsxs("html", { lang: "en", children: [_jsx(Head, {}), _jsxs("body", { id: "sourcey", children: [_jsx(Page, {}), _jsx("script", { src: `${options.assetBase}sourcey.js`, defer: true })] })] }));
11
11
  return (_jsx(SiteContext.Provider, { value: site, children: _jsx(SpecContext.Provider, { value: spec, children: _jsx(OptionsContext.Provider, { value: options, children: _jsx(NavigationContext.Provider, { value: navigation, children: _jsx(PageContext.Provider, { value: currentPage, children: content }) }) }) }) }));
12
12
  }
13
- //# sourceMappingURL=App.js.map
@@ -53,4 +53,3 @@ export function Head() {
53
53
  `;
54
54
  return (_jsxs("head", { children: [_jsx("meta", { charset: "utf-8" }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }), _jsx("title", { children: pageTitle }), _jsx("meta", { name: "description", content: pageDescription }), _jsx("meta", { name: "sourcey-search", content: `${options.assetBase}search-index.json` }), _jsx("style", { dangerouslySetInnerHTML: { __html: themeCSS } }), _jsx("style", { dangerouslySetInnerHTML: { __html: langIconCSS() } }), site.customCSS && _jsx("style", { dangerouslySetInnerHTML: { __html: site.customCSS } }), _jsx("script", { dangerouslySetInnerHTML: { __html: `(function(){var t=localStorage.getItem('sourcey-theme');if(t==='dark')document.documentElement.classList.add('dark')})()` } }), googleFontsUrl && (_jsxs(_Fragment, { children: [_jsx("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }), _jsx("link", { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "anonymous" }), _jsx("link", { rel: "stylesheet", href: googleFontsUrl })] })), _jsx("link", { rel: "stylesheet", href: `${options.assetBase}sourcey.css` }), site.favicon && _jsx("link", { rel: "icon", href: site.favicon })] }));
55
55
  }
56
- //# sourceMappingURL=Head.js.map
@@ -46,4 +46,3 @@ export function Header() {
46
46
  : "text-[rgb(var(--color-gray-600))] dark:text-[rgb(var(--color-gray-400))] hover:text-[rgb(var(--color-gray-800))] dark:hover:text-[rgb(var(--color-gray-300))]"}`, children: [tab.label, isActive ? (_jsx("div", { class: "absolute bottom-0 h-[1.5px] w-full left-0 bg-[rgb(var(--color-primary))] dark:bg-[rgb(var(--color-primary-light))]" })) : (_jsx("div", { class: "absolute bottom-0 h-[1.5px] w-full left-0 group-hover:bg-[rgb(var(--color-gray-200))] dark:group-hover:bg-[rgb(var(--color-gray-700))]" }))] }, tab.slug));
47
47
  }) }) }))] })] }));
48
48
  }
49
- //# sourceMappingURL=Header.js.map
@@ -90,4 +90,3 @@ export function Page() {
90
90
  : DefaultLayout;
91
91
  return (_jsxs("div", { id: "page", class: "relative antialiased text-[rgb(var(--color-gray-500))] dark:text-[rgb(var(--color-gray-400))]", children: [_jsx(Header, {}), _jsx("span", { class: "fixed inset-0 bg-[rgb(var(--color-background-light))] dark:bg-[rgb(var(--color-background-dark))] -z-10 pointer-events-none" }), _jsx(Layout, {}), _jsx("div", { id: "search-dialog", role: "dialog", "aria-label": "Search", children: _jsxs("div", { class: "search-dialog-inner", children: [_jsxs("div", { class: "search-input-row", children: [_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", class: "search-input-icon", children: _jsx("path", { "fill-rule": "evenodd", d: "M9 3.5a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11ZM2 9a7 7 0 1 1 12.452 4.391l3.328 3.329a.75.75 0 1 1-1.06 1.06l-3.329-3.328A7 7 0 0 1 2 9Z", "clip-rule": "evenodd" }) }), _jsx("input", { id: "search-input", type: "text", placeholder: "Search docs...", autocomplete: "off", spellcheck: false })] }), _jsx("div", { id: "search-results" }), _jsxs("div", { class: "search-footer", children: [_jsxs("span", { class: "search-footer-hint", children: [_jsx("kbd", { children: "\u2191\u2193" }), " navigate"] }), _jsxs("span", { class: "search-footer-hint", children: [_jsx("kbd", { children: "\u21B5" }), " select"] }), _jsxs("span", { class: "search-footer-hint", children: [_jsx("kbd", { children: "esc" }), " close"] })] })] }) })] }));
92
92
  }
93
- //# sourceMappingURL=Page.js.map
@@ -54,4 +54,3 @@ export function Sidebar() {
54
54
  return (_jsx("li", { children: _jsxs("a", { href: link.href, target: "_blank", rel: "noopener noreferrer", class: "flex items-center gap-2.5 text-[rgb(var(--color-gray-600))] hover:text-[rgb(var(--color-gray-900))] dark:text-[rgb(var(--color-gray-400))] dark:hover:text-[rgb(var(--color-gray-200))]", children: [link.type !== "link" && _jsx(SocialIcon, { type: link.type }), _jsx("span", { children: label })] }) }, link.href));
55
55
  }), primaryAction && (_jsx("li", { children: _jsxs("a", { href: primaryAction.href, target: "_blank", class: "group relative flex items-center justify-center px-4 py-2 text-sm font-medium", children: [_jsx("span", { class: "absolute inset-0 bg-[rgb(var(--color-primary-dark))] rounded-lg group-hover:opacity-90" }), _jsx("span", { class: "z-10 text-white", children: primaryAction.label })] }) }))] }) }))] })] }));
56
56
  }
57
- //# sourceMappingURL=Sidebar.js.map
@@ -23,4 +23,3 @@ export function TableOfContents({ headings }) {
23
23
  return null;
24
24
  return (_jsx("aside", { id: "toc", class: "hidden xl:flex self-start sticky xl:flex-col max-w-[28rem] z-[21]", style: "height: calc(100vh - var(--header-height) - 2.5rem); top: calc(var(--header-height) + 2.5rem)", children: _jsx("div", { class: "z-10 hidden xl:flex box-border max-h-full pl-10 w-[19rem]", children: _jsxs("div", { class: "text-[rgb(var(--color-gray-600))] text-sm leading-6 w-[16.5rem] overflow-y-auto space-y-2 pb-4 -mt-10 pt-10", children: [_jsx("h5", { class: "font-semibold text-[rgb(var(--color-gray-900))] dark:text-[rgb(var(--color-gray-200))]", children: "On this page" }), _jsx("nav", { children: _jsx(TocList, { headings: headings }) })] }) }) }));
25
25
  }
26
- //# sourceMappingURL=TableOfContents.js.map
@@ -17,4 +17,3 @@ export function CodeSamplesExamples({ operation, serverUrl, codeSampleLangs }) {
17
17
  return (_jsx("div", { class: `code-lang-panel${i === 0 ? " active" : ""}`, "data-lang-panel": String(i), children: _jsx("div", { class: "relative w-full px-4 py-3.5 text-sm leading-6 bg-[rgb(var(--color-code-block-light))] dark:bg-[rgb(var(--color-code-block-dark))] overflow-x-auto", style: "font-variant-ligatures: none", children: _jsx("div", { class: "font-mono whitespace-pre text-xs leading-[1.35rem] code-block", dangerouslySetInnerHTML: { __html: html } }) }) }, i));
18
18
  })] }));
19
19
  }
20
- //# sourceMappingURL=CodeSamples.js.map
@@ -9,4 +9,3 @@ export function Definition({ name, schema }) {
9
9
  const id = `definition-${htmlId(name)}`;
10
10
  return (_jsxs("div", { id: id, class: "py-8 border-t border-[rgb(var(--color-gray-100))] dark:border-[rgb(var(--color-gray-800))]", "data-traverse-target": id, children: [_jsx("a", { id: `/definitions/${name}` }), _jsx("header", { class: "mb-4", children: _jsxs("div", { class: "flex items-baseline gap-2", children: [_jsx("h2", { class: "text-xl font-bold text-[rgb(var(--color-gray-900))] dark:text-[rgb(var(--color-gray-200))]", children: name }), _jsx("span", { class: "text-sm text-[rgb(var(--color-gray-500))] font-normal", children: schema.type ?? "object" })] }) }), _jsxs("div", { class: "flex flex-col xl:flex-row gap-8", children: [_jsx("div", { class: "flex-1 min-w-0", children: _jsx(SchemaView, { schema: schema }) }), _jsx("aside", { class: "hidden xl:block w-[28rem] shrink-0 sticky self-start", style: "top: calc(var(--header-height) + 2.5rem)", children: _jsx(ExampleView, { schema: schema, title: "Example" }) })] }), _jsx("div", { class: "xl:hidden mt-6", children: _jsx(ExampleView, { schema: schema, title: "Example" }) })] }));
11
11
  }
12
- //# sourceMappingURL=Definition.js.map
@@ -17,4 +17,3 @@ export function EndpointBar({ method, path, serverUrl }) {
17
17
  const segments = path.split("/").filter(Boolean);
18
18
  return (_jsxs("div", { class: "flex items-center gap-2 rounded-[var(--radius)] border border-[rgb(var(--color-gray-200)/0.7)] dark:border-[rgb(var(--color-border-dark-subtle)/0.1)] px-3 py-2.5 mb-6 overflow-hidden", children: [_jsx("div", { class: `rounded-lg font-bold px-1.5 py-0.5 text-sm leading-5 shrink-0 ${colorClass}`, children: method.toUpperCase() }), _jsxs("div", { class: "flex items-center overflow-x-auto flex-1 no-scrollbar gap-0.5 font-mono", children: [_jsx("span", { class: "text-sm text-[rgb(var(--color-gray-500))] dark:text-[rgb(var(--color-gray-500))] shrink-0", children: serverUrl }), segments.map((seg, i) => (_jsxs("span", { class: "flex items-center shrink-0", children: [_jsx("span", { class: "text-sm text-[rgb(var(--color-gray-400))]", children: "/" }), _jsx("span", { class: "text-sm font-medium text-[rgb(var(--color-gray-800))] dark:text-[rgb(var(--color-gray-50))]", children: seg })] }, i)))] })] }));
19
19
  }
20
- //# sourceMappingURL=EndpointBar.js.map
@@ -11,4 +11,3 @@ export function Introduction() {
11
11
  const { info, servers } = spec;
12
12
  return (_jsxs("div", { id: "introduction", "data-traverse-target": "introduction", class: "mb-8", children: [info.description && (_jsx(Markdown, { content: info.description, class: "max-w-none" })), info.termsOfService && (_jsx("p", { class: "mt-4 text-sm text-[rgb(var(--color-gray-500))]", children: _jsx("a", { href: info.termsOfService, class: "text-[rgb(var(--color-primary))] dark:text-[rgb(var(--color-primary-light))]", children: "Terms of Service" }) })), info.contact?.email && (_jsxs("p", { class: "mt-2 text-sm text-[rgb(var(--color-gray-500))]", children: ["Contact: ", _jsx("a", { href: `mailto:${info.contact.email}`, class: "text-[rgb(var(--color-primary))] dark:text-[rgb(var(--color-primary-light))]", children: info.contact.email })] })), servers.length > 0 && (_jsxs("div", { class: "mt-6 rounded-[var(--radius)] border border-[rgb(var(--color-gray-200)/0.7)] dark:border-[rgb(var(--color-border-dark-subtle)/0.1)] overflow-x-auto", children: [_jsxs("div", { class: "px-4 py-2.5 text-xs font-semibold text-[rgb(var(--color-gray-600))] dark:text-[rgb(var(--color-gray-300))] border-b border-[rgb(var(--color-gray-200)/0.7)] dark:border-[rgb(var(--color-border-dark-subtle)/0.1)]", children: ["Base URL", servers.length > 1 ? "s" : ""] }), servers.map((s, i) => (_jsxs("div", { class: `flex items-baseline gap-3 px-4 py-2 ${i > 0 ? "border-t border-[rgb(var(--color-gray-100))] dark:border-[rgb(var(--color-gray-800))]" : ""}`, children: [_jsx("code", { class: "font-mono text-sm text-[rgb(var(--color-gray-800))] dark:text-[rgb(var(--color-gray-200))]", children: s.url }), s.description && (_jsx("span", { class: "text-xs text-[rgb(var(--color-gray-500))]", children: s.description }))] }, i)))] }))] }));
13
13
  }
14
- //# sourceMappingURL=Introduction.js.map
@@ -28,4 +28,3 @@ function bodyMediaType(body) {
28
28
  const types = Object.keys(body.content);
29
29
  return types.length ? types[0] : undefined;
30
30
  }
31
- //# sourceMappingURL=Operation.js.map
@@ -7,4 +7,3 @@ export function Parameters({ parameters }) {
7
7
  return null;
8
8
  return (_jsx("div", { class: "params-list", children: parameters.map((param) => (_jsxs("div", { class: "param-item", children: [_jsxs("div", { class: "param-header", children: [_jsx("code", { class: "param-name", children: param.name }), param.schema && (_jsx("span", { class: "param-type", children: _jsx(SchemaDatatype, { schema: param.schema }) })), param.required && _jsx(RequiredBadge, {}), param.deprecated && _jsx(DeprecatedBadge, {}), _jsx("span", { class: "param-in", children: param.in })] }), param.description && (_jsx("div", { class: "param-description", children: _jsx(Markdown, { content: param.description }) }))] }, `${param.in}-${param.name}`))) }));
9
9
  }
10
- //# sourceMappingURL=Parameters.js.map
@@ -23,4 +23,3 @@ export function RequestBodyExample({ body }) {
23
23
  return null;
24
24
  return _jsx(ExampleView, { schema: content.schema, title: "Request Body" });
25
25
  }
26
- //# sourceMappingURL=RequestBody.js.map
@@ -68,4 +68,3 @@ function getResponseSchema(r) {
68
68
  const firstMedia = Object.values(r.content)[0];
69
69
  return firstMedia?.schema ?? null;
70
70
  }
71
- //# sourceMappingURL=Responses.js.map
@@ -30,4 +30,3 @@ export function SecurityDefinitions() {
30
30
  .map(([s, desc]) => `${s} — ${desc}`)
31
31
  .join(", ")] }))] }, flowType))) })), scheme.type === "openIdConnect" && scheme.openIdConnectUrl && (_jsxs("p", { class: "mt-1", children: ["OpenID Connect:", " ", _jsx("a", { href: scheme.openIdConnectUrl, class: "text-[rgb(var(--color-primary))] dark:text-[rgb(var(--color-primary-light))]", children: scheme.openIdConnectUrl })] }))] })] }, name))) })] }));
32
32
  }
33
- //# sourceMappingURL=Security.js.map
@@ -7,4 +7,3 @@ export function Tags({ tags, serverUrl }) {
7
7
  .filter((t) => !t.hidden)
8
8
  .map((tag) => (_jsxs("div", { class: "mt-12", children: [_jsxs("div", { id: `tag-${htmlId(tag.name)}`, "data-traverse-target": `tag-${htmlId(tag.name)}`, class: "mb-6", children: [_jsx("h1", { class: "text-xl font-bold text-[rgb(var(--color-gray-900))] dark:text-[rgb(var(--color-gray-200))] mb-2", children: tag.name }), tag.description && (_jsx(Markdown, { content: tag.description, class: "text-sm max-w-none" }))] }), tag.operations.map((op) => (_jsx(Operation, { operation: op, serverUrl: serverUrl }, `${op.method}-${op.path}`)))] }, tag.name))) }));
9
9
  }
10
- //# sourceMappingURL=Tags.js.map
@@ -13,4 +13,3 @@ export function ExampleView({ schema, title }) {
13
13
  const html = highlightCode(json, "json");
14
14
  return (_jsxs("div", { class: "code-group not-prose", children: [title && (_jsxs("div", { class: "relative flex items-center justify-between gap-2 px-3", children: [_jsx("div", { class: "flex min-w-0 items-center gap-1.5 font-medium text-xs leading-6 my-1 mb-1.5", children: _jsx("span", { class: "truncate text-[rgb(var(--color-stone-950))] dark:text-[rgb(var(--color-stone-50))]", children: title }) }), _jsx("div", { class: "flex shrink-0 items-center justify-end gap-1.5", children: _jsx(CopyButton, {}) })] })), _jsxs("div", { class: "relative w-full px-4 py-3.5 text-sm leading-6 bg-[rgb(var(--color-code-block-light))] dark:bg-[rgb(var(--color-code-block-dark))] overflow-x-auto", style: "font-variant-ligatures: none", children: [!title && (_jsx("div", { class: "absolute top-3 right-4 z-10", children: _jsx(CopyButton, {}) })), _jsx("div", { class: "font-mono whitespace-pre text-xs leading-[1.35rem]", dangerouslySetInnerHTML: { __html: html } })] })] }));
15
15
  }
16
- //# sourceMappingURL=ExampleView.js.map
@@ -37,4 +37,3 @@ function formatBaseType(schema) {
37
37
  const type = Array.isArray(schema.type) ? schema.type.join(" | ") : schema.type;
38
38
  return type ?? "any";
39
39
  }
40
- //# sourceMappingURL=SchemaDatatype.js.map
@@ -41,4 +41,3 @@ function PropertyRow({ name, schema, required, depth, maxDepth, }) {
41
41
  (schema.items.properties || schema.items.allOf || schema.items.oneOf || schema.items.anyOf));
42
42
  return (_jsxs("div", { class: "param-item", children: [_jsxs("div", { class: "param-header", children: [_jsx("code", { class: "param-name", children: name }), _jsx("span", { class: "param-type", children: _jsx(SchemaDatatype, { schema: schema }) }), required && _jsx(RequiredBadge, {}), schema.readOnly && _jsx(ReadOnlyBadge, {}), schema.writeOnly && _jsx(Badge, { children: "write only" }), schema.deprecated && _jsx(DeprecatedBadge, {})] }), schema.description && (_jsx("div", { class: "param-description", children: _jsx(Markdown, { content: schema.description }) })), hasInner && (_jsxs("details", { class: "schema-expandable", children: [_jsxs("summary", { class: "schema-expandable-toggle", children: [_jsx("svg", { class: "schema-expandable-icon", viewBox: "0 0 256 512", width: "8", height: "8", children: _jsx("path", { fill: "currentColor", d: "M249.3 235.8c10.2 12.6 9.5 31.1-2.2 42.8l-128 128c-9.2 9.2-22.9 11.9-34.9 6.9S64.5 396.9 64.5 384l0-256c0-12.9 7.8-24.6 19.8-29.6s25.7-2.2 34.9 6.9l128 128 2.2 2.4z" }) }), "Show child attributes"] }), _jsx("div", { class: "schema-expandable-content", children: _jsx(SchemaView, { schema: schema.type === "array" && schema.items ? schema.items : schema, depth: depth + 1, maxDepth: maxDepth }) })] }))] }));
43
43
  }
44
- //# sourceMappingURL=SchemaView.js.map
@@ -11,4 +11,3 @@ export function DeprecatedBadge() {
11
11
  export function ReadOnlyBadge() {
12
12
  return (_jsx("span", { class: "whitespace-nowrap rounded-md bg-[rgb(var(--color-gray-100)/0.5)] px-2 py-0.5 text-xs font-medium text-[rgb(var(--color-gray-600))] dark:bg-[rgb(var(--color-surface-dark-tint)/0.05)] dark:text-[rgb(var(--color-gray-200))]", children: "read only" }));
13
13
  }
14
- //# sourceMappingURL=Badge.js.map
@@ -7,4 +7,3 @@ import { COPY_ICON_PATH_1, COPY_ICON_PATH_2 } from "../../utils/copy-svg.js";
7
7
  export function CopyButton() {
8
8
  return (_jsxs("div", { class: "relative z-10 select-none", children: [_jsx("button", { "aria-label": "Copy code", class: "copy-btn peer group/copy flex size-[26px] items-center justify-center rounded-md backdrop-blur", type: "button", "data-copy-source": "code", children: _jsxs("svg", { class: "size-4 text-[rgb(var(--color-stone-400))] group-hover/copy:text-[rgb(var(--color-stone-500))] dark:text-[rgb(255_255_255/0.4)] dark:group-hover/copy:text-[rgb(255_255_255/0.6)]", fill: "none", height: "18", viewBox: "0 0 18 18", width: "18", xmlns: "http://www.w3.org/2000/svg", children: [_jsx("title", { children: "Copy" }), _jsx("path", { d: COPY_ICON_PATH_1, stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: COPY_ICON_PATH_2, stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }) }), _jsx("div", { "aria-hidden": "true", class: "copy-tooltip absolute top-[2.75rem] left-1/2 -translate-x-1/2 -translate-y-1/2 whitespace-nowrap rounded-lg bg-[rgb(var(--color-primary-dark))] px-1.5 py-0.5 text-white text-xs opacity-0 peer-hover:opacity-100 transition-opacity pointer-events-none", children: "Copy" })] }));
9
9
  }
10
- //# sourceMappingURL=CopyButton.js.map
@@ -6,4 +6,3 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "preact/jsx-ru
6
6
  export function Logo({ href, logo, name, height = "h-7" }) {
7
7
  return (_jsx("a", { href: href, class: "select-none inline-block", children: logo?.light ? (_jsxs(_Fragment, { children: [_jsx("img", { src: logo.light, alt: name || "Home", class: `w-auto ${height} object-contain block dark:hidden` }), _jsx("img", { src: logo.dark ?? logo.light, alt: name || "Home", class: `w-auto ${height} object-contain hidden dark:block` })] })) : (_jsx("span", { class: "text-sm font-semibold text-[rgb(var(--color-gray-900))] dark:text-[rgb(var(--color-gray-200))]", children: name || "Docs" })) }));
8
8
  }
9
- //# sourceMappingURL=Logo.js.map
@@ -10,4 +10,3 @@ export function Markdown({ content, inline, class: className }) {
10
10
  const cls = className ? `prose prose-gray dark:prose-invert ${className}` : "prose prose-gray dark:prose-invert";
11
11
  return (_jsx("div", { class: cls, dangerouslySetInnerHTML: { __html: html } }));
12
12
  }
13
- //# sourceMappingURL=Markdown.js.map
@@ -6,4 +6,3 @@ import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
6
6
  export function SectionLabel({ children, meta }) {
7
7
  return (_jsxs("div", { class: "flex items-baseline border-b pb-2.5 border-[rgb(var(--color-gray-100))] dark:border-[rgb(var(--color-gray-800))] w-full mb-4", children: [_jsx("h4", { class: "flex-1 mb-0 text-sm font-semibold text-[rgb(var(--color-gray-900))] dark:text-[rgb(var(--color-gray-200))]", children: children }), meta && (_jsx("div", { class: "flex items-center gap-2 text-xs font-medium font-mono text-[rgb(var(--color-gray-500))]", children: meta }))] }));
8
8
  }
9
- //# sourceMappingURL=SectionLabel.js.map
@@ -65,4 +65,3 @@ export function SocialIcon({ type }) {
65
65
  return null;
66
66
  return (_jsx("svg", { viewBox: icon.viewBox, fill: "currentColor", class: "w-5 h-5", dangerouslySetInnerHTML: { __html: icon.path } }));
67
67
  }
68
- //# sourceMappingURL=SocialIcon.js.map
package/dist/config.d.ts CHANGED
@@ -53,6 +53,7 @@ export interface SourceyConfig {
53
53
  links?: NavbarLink[];
54
54
  };
55
55
  }
56
+ export type DoxygenIndexStyle = "auto" | "rich" | "structured" | "flat" | "none";
56
57
  export interface DoxygenConfig {
57
58
  /** Path to Doxygen XML output directory */
58
59
  xml: string;
@@ -60,6 +61,15 @@ export interface DoxygenConfig {
60
61
  language?: string;
61
62
  /** Use Doxygen groups for navigation grouping */
62
63
  groups?: boolean;
64
+ /**
65
+ * Index page style for the API reference landing page.
66
+ * - "auto": pick the best format based on available data (default)
67
+ * - "rich": card grid with module descriptions (requires groups with descriptions)
68
+ * - "structured": grouped list of types by module/namespace
69
+ * - "flat": alphabetical list categorized by kind (classes, structs, etc.)
70
+ * - "none" or false: no index page, land on the first API page
71
+ */
72
+ index?: DoxygenIndexStyle | false;
63
73
  }
64
74
  export interface TabConfig {
65
75
  tab: string;
@@ -128,6 +138,7 @@ export interface ResolvedDoxygenConfig {
128
138
  xml: string;
129
139
  language: string;
130
140
  groups: boolean;
141
+ index: DoxygenIndexStyle;
131
142
  }
132
143
  export interface ResolvedTab {
133
144
  label: string;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;AAE9D,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,KAAK,CAAC,EAAE;QACN,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,GAAG;QACd,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sHAAsH;IACtH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iJAAiJ;IACjJ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE;QACV,IAAI,EAAE,SAAS,EAAE,CAAC;KACnB,CAAC;IACF,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;QACrB,OAAO,CAAC,EAAE;YAAE,IAAI,EAAE,QAAQ,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC;KAC3D,CAAC;IACF,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;KACtB,CAAC;CACH;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,GAAG,MAAM,GAAG,MAAM,CAAC;AAEjF,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,iBAAiB,GAAG,KAAK,CAAC;CACnC;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAEhJ,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CAEjE;AAMD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzD,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1D,GAAG,EAAE,MAAM,EAAE,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,aAAa,CAAC;IACrB,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,MAAM,EAAE;QAAE,KAAK,EAAE,UAAU,EAAE,CAAC;QAAC,OAAO,CAAC,EAAE;YAAE,IAAI,EAAE,QAAQ,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IAC3F,MAAM,EAAE;QAAE,KAAK,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC;CACjC;AAED,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,iBAAiB,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB,OAAO,CAAC,EAAE,qBAAqB,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAuBD,wBAAsB,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAwBtE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CAgB/D;AAMD,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAuBzG;AAsKD,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,wEAAwE;AACxE,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO5C"}
package/dist/config.js CHANGED
@@ -159,6 +159,7 @@ async function resolveTabs(tabs, configDir) {
159
159
  xml: absXml,
160
160
  language: tab.doxygen.language ?? "cpp",
161
161
  groups: tab.doxygen.groups ?? false,
162
+ index: tab.doxygen.index === false ? "none" : (tab.doxygen.index ?? "auto"),
162
163
  },
163
164
  });
164
165
  }
@@ -261,4 +262,3 @@ async function assertExists(filePath, label) {
261
262
  throw new Error(`${label} not found: ${filePath}`);
262
263
  }
263
264
  }
264
- //# sourceMappingURL=config.js.map
@@ -26,4 +26,3 @@ export async function convertToOpenApi3(parsed) {
26
26
  source: parsed.source,
27
27
  };
28
28
  }
29
- //# sourceMappingURL=converter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"doxygen-loader.d.ts","sourceRoot":"","sources":["../../src/core/doxygen-loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAE1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,EAA6B,MAAM,iBAAiB,CAAC;AAM1E,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACjC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,aAAa,CAAC,CAwExB"}
1
+ {"version":3,"file":"doxygen-loader.d.ts","sourceRoot":"","sources":["../../src/core/doxygen-loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAqB,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAE7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,EAA6B,MAAM,iBAAiB,CAAC;AAM1E,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACjC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,aAAa,CAAC,CA4FxB"}
@@ -31,16 +31,13 @@ export async function loadDoxygenTab(config, tabSlug, tabLabel) {
31
31
  // Build navigation: namespace index pages first, then classes alphabetically
32
32
  const groups = [];
33
33
  for (const [key, items] of groupMap) {
34
- // Use the group overview page's title as the sidebar label if available
35
34
  const groupPage = items.find((i) => i.kind === "group");
36
35
  const label = groupPage?.title ?? key;
37
36
  const sorted = items.sort((a, b) => {
38
- // Group overview page always first
39
37
  if (a.kind === "group" && b.kind !== "group")
40
38
  return -1;
41
39
  if (a.kind !== "group" && b.kind === "group")
42
40
  return 1;
43
- // Then namespace index pages
44
41
  if (a.kind === "namespace" && b.kind !== "namespace")
45
42
  return -1;
46
43
  if (a.kind !== "namespace" && b.kind === "namespace")
@@ -56,6 +53,25 @@ export async function loadDoxygenTab(config, tabSlug, tabLabel) {
56
53
  })),
57
54
  });
58
55
  }
56
+ // Generate index page
57
+ const indexStyle = resolveIndexStyle(config.index, groupMap, pages);
58
+ if (indexStyle !== "none") {
59
+ const indexSlug = "index";
60
+ const indexHtml = buildIndexHtml(indexStyle, tabSlug, tabLabel, groupMap, pages);
61
+ const indexHeadings = indexStyle === "rich" ? [] : extractHeadings(indexHtml);
62
+ pages.set(indexSlug, {
63
+ title: tabLabel,
64
+ description: "",
65
+ slug: indexSlug,
66
+ html: indexHtml,
67
+ headings: indexHeadings,
68
+ sourcePath: config.xml,
69
+ });
70
+ groups.unshift({
71
+ label: tabLabel,
72
+ items: [{ label: "Overview", href: `${tabSlug}/${indexSlug}.html`, id: indexSlug }],
73
+ });
74
+ }
59
75
  const firstItem = groups[0]?.items[0];
60
76
  return {
61
77
  pages,
@@ -68,10 +84,148 @@ export async function loadDoxygenTab(config, tabSlug, tabLabel) {
68
84
  },
69
85
  };
70
86
  }
87
+ /**
88
+ * Resolve "auto" to a concrete style based on the data we have.
89
+ */
90
+ function resolveIndexStyle(configured, groupMap, pages) {
91
+ if (configured !== "auto")
92
+ return configured;
93
+ // Tiny projects — no index needed
94
+ if (pages.size < 5)
95
+ return "none";
96
+ // Check if we have groups with descriptions
97
+ const groupsWithDesc = [...groupMap.values()]
98
+ .map((items) => items.find((i) => i.kind === "group"))
99
+ .filter((g) => !!g)
100
+ .filter((g) => pages.get(g.slug)?.description);
101
+ if (groupsWithDesc.length >= 2)
102
+ return "rich";
103
+ // Check if we have meaningful grouping (multiple groups/namespaces)
104
+ if (groupMap.size >= 2)
105
+ return "structured";
106
+ return "flat";
107
+ }
108
+ /**
109
+ * Build index page HTML using sourcey's existing component markup.
110
+ */
111
+ function buildIndexHtml(style, tabSlug, _tabLabel, groupMap, pages) {
112
+ if (style === "rich")
113
+ return buildRichIndex(tabSlug, groupMap, pages);
114
+ if (style === "structured")
115
+ return buildStructuredIndex(tabSlug, groupMap, pages);
116
+ return buildFlatIndex(tabSlug, groupMap);
117
+ }
118
+ /**
119
+ * Rich: card grid with module name, description, and type count.
120
+ * Uses sourcey's card-group/card-item CSS.
121
+ */
122
+ function buildRichIndex(tabSlug, groupMap, pages) {
123
+ const cards = [];
124
+ for (const [, items] of groupMap) {
125
+ const groupEntry = items.find((i) => i.kind === "group");
126
+ if (!groupEntry)
127
+ continue;
128
+ const page = pages.get(groupEntry.slug);
129
+ if (!page)
130
+ continue;
131
+ const typeCount = items.filter((i) => i.kind !== "group" && i.kind !== "namespace").length;
132
+ const href = `${tabSlug}/${groupEntry.slug}.html`;
133
+ const desc = page.description || "";
134
+ const meta = typeCount > 0
135
+ ? `<p style="margin:0.5rem 0 0;font-size:0.8rem;opacity:0.5">${typeCount} type${typeCount !== 1 ? "s" : ""}</p>`
136
+ : "";
137
+ cards.push(`<a href="${href}" class="card-item">` +
138
+ `<div class="card-item-inner">` +
139
+ `<h3 class="card-item-title">${escHtml(page.title)}</h3>` +
140
+ (desc ? `<div class="card-item-content"><p>${escHtml(desc)}</p>${meta}</div>` : `<div class="card-item-content">${meta}</div>`) +
141
+ `</div></a>`);
142
+ }
143
+ // Also include groups without a group page (orphan namespaces)
144
+ for (const [key, items] of groupMap) {
145
+ const hasGroup = items.some((i) => i.kind === "group");
146
+ if (hasGroup)
147
+ continue;
148
+ const typeCount = items.filter((i) => i.kind !== "namespace").length;
149
+ if (typeCount === 0)
150
+ continue;
151
+ const firstItem = items[0];
152
+ const href = `${tabSlug}/${firstItem.slug}.html`;
153
+ cards.push(`<a href="${href}" class="card-item">` +
154
+ `<div class="card-item-inner">` +
155
+ `<h3 class="card-item-title">${escHtml(key)}</h3>` +
156
+ `<div class="card-item-content"><p style="margin:0;font-size:0.8rem;opacity:0.5">${typeCount} type${typeCount !== 1 ? "s" : ""}</p></div>` +
157
+ `</div></a>`);
158
+ }
159
+ if (cards.length === 0)
160
+ return "";
161
+ const cols = cards.length <= 2 ? "2" : "3";
162
+ return `<div class="card-group not-prose" data-cols="${cols}">\n${cards.join("\n")}\n</div>`;
163
+ }
164
+ /**
165
+ * Structured: grouped list of types by module/namespace.
166
+ * Rendered as markdown headings with link lists.
167
+ */
168
+ function buildStructuredIndex(tabSlug, groupMap, pages) {
169
+ const sections = [];
170
+ for (const [key, items] of groupMap) {
171
+ const groupEntry = items.find((i) => i.kind === "group");
172
+ const title = groupEntry ? (pages.get(groupEntry.slug)?.title ?? key) : key;
173
+ const types = items.filter((i) => i.kind !== "group" && i.kind !== "namespace");
174
+ if (types.length === 0 && !groupEntry)
175
+ continue;
176
+ const links = [];
177
+ if (groupEntry) {
178
+ links.push(`- [Overview](${tabSlug}/${groupEntry.slug}.html)`);
179
+ }
180
+ for (const t of types) {
181
+ links.push(`- [${t.title}](${tabSlug}/${t.slug}.html)`);
182
+ }
183
+ sections.push(`### ${title}\n\n${links.join("\n")}`);
184
+ }
185
+ return renderMarkdown(sections.join("\n\n"));
186
+ }
187
+ /**
188
+ * Flat: alphabetical list categorized by kind.
189
+ */
190
+ function buildFlatIndex(tabSlug, groupMap) {
191
+ const byKind = new Map();
192
+ for (const [, items] of groupMap) {
193
+ for (const item of items) {
194
+ if (item.kind === "group" || item.kind === "namespace")
195
+ continue;
196
+ const label = kindLabel(item.kind);
197
+ if (!byKind.has(label))
198
+ byKind.set(label, []);
199
+ byKind.get(label).push(item);
200
+ }
201
+ }
202
+ const sections = [];
203
+ for (const [label, items] of byKind) {
204
+ const sorted = items.sort((a, b) => a.title.localeCompare(b.title));
205
+ const links = sorted.map((i) => `- [${i.title}](${tabSlug}/${i.slug}.html)`).join("\n");
206
+ sections.push(`### ${label}\n\n${links}`);
207
+ }
208
+ return renderMarkdown(sections.join("\n\n"));
209
+ }
210
+ // ---------------------------------------------------------------------------
211
+ // Utilities
212
+ // ---------------------------------------------------------------------------
71
213
  function lastSegment(name) {
72
214
  if (!name)
73
215
  return undefined;
74
216
  const parts = name.split("::");
75
217
  return parts[parts.length - 1] || name;
76
218
  }
77
- //# sourceMappingURL=doxygen-loader.js.map
219
+ function escHtml(s) {
220
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
221
+ }
222
+ function kindLabel(kind) {
223
+ switch (kind) {
224
+ case "class": return "Classes";
225
+ case "struct": return "Structs";
226
+ case "enum": return "Enums";
227
+ case "union": return "Unions";
228
+ case "typedef": return "Type Aliases";
229
+ default: return kind.charAt(0).toUpperCase() + kind.slice(1) + "s";
230
+ }
231
+ }
@@ -89,4 +89,3 @@ function detectVersion(raw) {
89
89
  function isUrl(source) {
90
90
  return source.startsWith("http://") || source.startsWith("https://");
91
91
  }
92
- //# sourceMappingURL=loader.js.map
@@ -257,4 +257,3 @@ function extractFirstHeading(md) {
257
257
  export function slugFromPath(filePath) {
258
258
  return htmlId(basename(filePath, extname(filePath)));
259
259
  }
260
- //# sourceMappingURL=markdown-loader.js.map
@@ -105,4 +105,3 @@ export function buildSiteNavigation(tabs) {
105
105
  export function withActivePage(nav, tabSlug, pageSlug) {
106
106
  return { ...nav, activeTabSlug: tabSlug, activePageSlug: pageSlug };
107
107
  }
108
- //# sourceMappingURL=navigation.js.map
@@ -469,4 +469,3 @@ function str(value, fallback) {
469
469
  function optStr(value) {
470
470
  return typeof value === "string" ? value : undefined;
471
471
  }
472
- //# sourceMappingURL=normalizer.js.map
@@ -31,4 +31,3 @@ export async function parseSpec(loaded) {
31
31
  throw new Error(`Failed to parse OpenAPI spec: ${message}`);
32
32
  }
33
33
  }
34
- //# sourceMappingURL=parser.js.map
@@ -70,4 +70,3 @@ export function buildSearchIndex(specs, pages, navigation, assetBase = "/") {
70
70
  function stripHtml(html) {
71
71
  return html.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
72
72
  }
73
- //# sourceMappingURL=search-indexer.js.map
@@ -4,4 +4,3 @@
4
4
  * before rendering, so components never need to know the source format.
5
5
  */
6
6
  export {};
7
- //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../src/dev-server.ts"],"names":[],"mappings":"AA4BA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0H7E"}
1
+ {"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../src/dev-server.ts"],"names":[],"mappings":"AAqCA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoW7E"}
@@ -1,5 +1,5 @@
1
1
  import { createServer as createViteServer } from "vite";
2
- import { resolve, dirname, extname } from "node:path";
2
+ import { resolve, dirname, extname, basename, relative } from "node:path";
3
3
  import { readFile, access } from "node:fs/promises";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { loadConfig, resolveConfigFromRaw, tabPath } from "./config.js";
@@ -24,6 +24,13 @@ async function exists(path) {
24
24
  return false;
25
25
  }
26
26
  }
27
+ function log(msg) {
28
+ const t = new Date().toLocaleTimeString([], { hour12: false, hour: "2-digit", minute: "2-digit", second: "2-digit" });
29
+ console.log(` \x1b[2m${t}\x1b[0m ${msg}`);
30
+ }
31
+ function shortPath(p) {
32
+ return relative(process.cwd(), p) || basename(p);
33
+ }
27
34
  export async function startDevServer(options) {
28
35
  const { port } = options;
29
36
  const configPath = resolve(process.cwd(), "sourcey.config.ts");
@@ -43,6 +50,27 @@ export async function startDevServer(options) {
43
50
  }
44
51
  }
45
52
  }
53
+ function buildFileToContent(cfg) {
54
+ const map = new Map();
55
+ map.set(configPath, { kind: "config" });
56
+ for (const tab of cfg.tabs) {
57
+ if (tab.openapi) {
58
+ map.set(resolve(tab.openapi), { kind: "openapi", tabSlug: tab.slug, specPath: tab.openapi });
59
+ }
60
+ if (tab.doxygen) {
61
+ map.set(resolve(tab.doxygen.xml), { kind: "doxygen", tabSlug: tab.slug, xmlDir: tab.doxygen.xml });
62
+ }
63
+ if (tab.groups) {
64
+ for (const group of tab.groups) {
65
+ for (const pagePath of group.pages) {
66
+ map.set(resolve(pagePath), { kind: "markdown", tabSlug: tab.slug, pagePath });
67
+ }
68
+ }
69
+ }
70
+ }
71
+ return map;
72
+ }
73
+ let fileToContent = buildFileToContent(config);
46
74
  // Resolve source paths for Vite dev serving.
47
75
  // Prefer src/ (local dev) but fall back to dist/ (npm install).
48
76
  const projectRoot = resolve(__dirname, "..");
@@ -52,19 +80,145 @@ export async function startDevServer(options) {
52
80
  const clientEntry = resolve(projectRoot, hasSrc ? "src/client/index.ts" : "dist/client/index.js");
53
81
  const ssrRendererPath = resolve(projectRoot, hasSrc ? "src/renderer/static-renderer.ts" : "dist/renderer/static-renderer.js");
54
82
  let vite;
83
+ let cache = null;
84
+ let cachePromise = null;
85
+ function fullRebuild() {
86
+ if (!cachePromise) {
87
+ const start = performance.now();
88
+ log("building site data...");
89
+ cachePromise = (async () => {
90
+ const data = await loadSiteData(config.tabs);
91
+ const siteConfig = await buildSiteConfig(config);
92
+ const result = { data, siteConfig };
93
+ cache = result;
94
+ cachePromise = null;
95
+ const ms = Math.round(performance.now() - start);
96
+ log(`ready \x1b[2m(${data.pageMap.size} pages in ${ms}ms)\x1b[0m`);
97
+ return result;
98
+ })().catch((err) => {
99
+ cachePromise = null;
100
+ throw err;
101
+ });
102
+ }
103
+ return cachePromise;
104
+ }
105
+ function getCached() {
106
+ if (cache)
107
+ return Promise.resolve(cache);
108
+ return fullRebuild();
109
+ }
110
+ // Incremental patch: reload only the piece that changed, then reassemble
111
+ // siteTabs + pageMap from the patched data. Falls back to full rebuild if
112
+ // the cache isn't warm yet.
113
+ async function incrementalUpdate(content) {
114
+ // Capture current cache; if a full rebuild replaces it while we await,
115
+ // we abandon this patch (the rebuild already produced fresh data).
116
+ const snapshot = cache;
117
+ if (!snapshot) {
118
+ await fullRebuild();
119
+ return;
120
+ }
121
+ const { data } = snapshot;
122
+ const start = performance.now();
123
+ if (content.kind === "markdown") {
124
+ const slug = slugFromPath(content.pagePath);
125
+ log(`reloading ${shortPath(content.pagePath)}`);
126
+ const page = await loadMarkdownPage(content.pagePath, slug);
127
+ if (cache !== snapshot)
128
+ return;
129
+ const pageKey = tabPath(content.tabSlug, `${slug}.html`);
130
+ const existing = data.pageMap.get(pageKey);
131
+ if (existing) {
132
+ existing.currentPage = { kind: "markdown", markdown: page };
133
+ }
134
+ rebuildTabNav(data, config.tabs, content.tabSlug);
135
+ }
136
+ else if (content.kind === "doxygen") {
137
+ const tab = config.tabs.find((t) => t.slug === content.tabSlug);
138
+ if (!tab?.doxygen)
139
+ return;
140
+ log(`rebuilding doxygen tab "${tab.label}"`);
141
+ const { pages, navTab } = await loadDoxygenTab(tab.doxygen, tab.slug, tab.label);
142
+ if (cache !== snapshot)
143
+ return;
144
+ for (const [key, entry] of data.pageMap) {
145
+ if (entry.tabSlug === content.tabSlug)
146
+ data.pageMap.delete(key);
147
+ }
148
+ for (const [slug, page] of pages) {
149
+ data.pageMap.set(tabPath(tab.slug, `${slug}.html`), {
150
+ spec: data.primarySpec,
151
+ currentPage: { kind: "markdown", markdown: page },
152
+ tabSlug: tab.slug,
153
+ pageSlug: slug,
154
+ });
155
+ }
156
+ const idx = data.siteTabs.findIndex((t) => t.slug === content.tabSlug);
157
+ if (idx !== -1)
158
+ data.siteTabs[idx] = navTab;
159
+ else
160
+ data.siteTabs.push(navTab);
161
+ }
162
+ else if (content.kind === "openapi") {
163
+ log(`reparsing spec ${shortPath(content.specPath)}`);
164
+ const loaded = await loadSpec(content.specPath);
165
+ const parsed = await parseSpec(loaded);
166
+ const openapi3 = await convertToOpenApi3(parsed);
167
+ const spec = normalizeSpec(openapi3);
168
+ if (cache !== snapshot)
169
+ return;
170
+ data.specsBySlug.set(content.tabSlug, spec);
171
+ const pageKey = tabPath(content.tabSlug, "index.html");
172
+ const existing = data.pageMap.get(pageKey);
173
+ if (existing) {
174
+ existing.currentPage = { kind: "spec", spec };
175
+ existing.spec = spec;
176
+ }
177
+ const tab = config.tabs.find((t) => t.slug === content.tabSlug);
178
+ if (tab) {
179
+ const navTab = buildNavFromSpec(spec, tab.slug);
180
+ navTab.label = tab.label;
181
+ const idx = data.siteTabs.findIndex((t) => t.slug === content.tabSlug);
182
+ if (idx !== -1)
183
+ data.siteTabs[idx] = navTab;
184
+ }
185
+ }
186
+ const ms = Math.round(performance.now() - start);
187
+ log(`updated \x1b[2m(${ms}ms)\x1b[0m`);
188
+ }
189
+ // Rebuild navigation for a single markdown tab from cached page data
190
+ function rebuildTabNav(data, tabs, tabSlug) {
191
+ const tab = tabs.find((t) => t.slug === tabSlug);
192
+ if (!tab?.groups)
193
+ return;
194
+ const pagesByPath = new Map();
195
+ for (const group of tab.groups) {
196
+ for (const pagePath of group.pages) {
197
+ const slug = slugFromPath(pagePath);
198
+ const pageKey = tabPath(tab.slug, `${slug}.html`);
199
+ const entry = data.pageMap.get(pageKey);
200
+ if (entry?.currentPage.kind === "markdown") {
201
+ pagesByPath.set(pagePath, entry.currentPage.markdown);
202
+ }
203
+ }
204
+ }
205
+ const navTab = buildNavFromPages(tab, pagesByPath);
206
+ const idx = data.siteTabs.findIndex((t) => t.slug === tabSlug);
207
+ if (idx !== -1)
208
+ data.siteTabs[idx] = navTab;
209
+ }
55
210
  // Reload config through Vite SSR (bypasses Node's module cache)
56
211
  async function reloadConfig() {
57
212
  const configMod = await vite.ssrLoadModule(configPath);
58
213
  return resolveConfigFromRaw(configMod.default, process.cwd());
59
214
  }
60
215
  async function render(url) {
61
- // Load render-path modules through Vite's SSR graph so invalidateAll() works.
62
- // Static imports would survive invalidation and serve stale output.
216
+ // Load renderer through Vite's SSR graph so invalidateAll() picks up
217
+ // component changes. Site data uses static imports (file reads only).
63
218
  const { renderPage } = await vite.ssrLoadModule(ssrRendererPath);
64
- const mdLoader = await vite.ssrLoadModule(resolve(projectRoot, hasSrc ? "src/core/markdown-loader.ts" : "dist/core/markdown-loader.js"));
65
- const { siteTabs, primarySpec, pageMap } = await loadSiteData(config.tabs, mdLoader.loadMarkdownPage);
219
+ const { data, siteConfig: site } = await getCached();
220
+ const { siteTabs, pageMap } = data;
66
221
  const navigation = buildSiteNavigation(siteTabs);
67
- const site = await buildSiteConfig(config);
68
222
  let pagePath = url.replace(/^\//, "").replace(/\/$/, "");
69
223
  if (!pagePath || pagePath === "index.html") {
70
224
  const firstKey = pageMap.keys().next().value;
@@ -82,11 +236,29 @@ export async function startDevServer(options) {
82
236
  const renderOptions = { embeddable: false, assetBase: "/" };
83
237
  let html = renderPage(pageData.spec, renderOptions, activeNav, pageData.currentPage, site);
84
238
  // Rewrite asset paths for Vite HMR
85
- html = html.replace(/<link rel="stylesheet" href="[^"]*sourcey\.css"[^>]*\/>/, `<link rel="stylesheet" href="/@fs${tailwindCssPath}" />\n<link rel="stylesheet" href="/@fs${sourceyCssPath}?direct" />`);
239
+ // Preact outputs <link ... href="/sourcey.css"/> (no space before />)
240
+ html = html.replace(/<link rel="stylesheet" href="[^"]*sourcey\.css"\s*\/?>/, `<link rel="stylesheet" href="/@fs${tailwindCssPath}" />\n<link rel="stylesheet" href="/@fs${sourceyCssPath}?direct" />`);
86
241
  html = html.replace(/<script src="[^"]*sourcey\.js"[^>]*><\/script>/, `<script type="module" src="/@fs${clientEntry}"></script>`);
87
- html = html.replace(/<script src="[^"]*sourcey\.js"[^>]*\/>/, `<script type="module" src="/@fs${clientEntry}"></script>`);
242
+ html = html.replace(/<script src="[^"]*sourcey\.js"\s*\/?>/, `<script type="module" src="/@fs${clientEntry}"></script>`);
88
243
  return html;
89
244
  }
245
+ async function buildSearchIndexForDev() {
246
+ const { data: { siteTabs, pageMap, specsBySlug } } = await getCached();
247
+ const navigation = buildSiteNavigation(siteTabs);
248
+ const markdownPagesByTab = new Map();
249
+ for (const tab of config.tabs) {
250
+ if (tab.groups || tab.doxygen) {
251
+ const tabPages = [];
252
+ for (const [, entry] of pageMap) {
253
+ if (entry.tabSlug === tab.slug && entry.currentPage.kind === "markdown") {
254
+ tabPages.push(entry.currentPage.markdown);
255
+ }
256
+ }
257
+ markdownPagesByTab.set(tab.slug, tabPages);
258
+ }
259
+ }
260
+ return buildSearchIndex(specsBySlug, markdownPagesByTab, navigation);
261
+ }
90
262
  const viteConfig = {
91
263
  root: process.cwd(),
92
264
  server: {
@@ -100,7 +272,7 @@ export async function startDevServer(options) {
100
272
  sourceyPlugin({
101
273
  watchPaths,
102
274
  render,
103
- searchIndex: () => buildSearchIndexForDev(config),
275
+ searchIndex: buildSearchIndexForDev,
104
276
  }),
105
277
  ],
106
278
  clearScreen: false,
@@ -110,18 +282,50 @@ export async function startDevServer(options) {
110
282
  },
111
283
  };
112
284
  vite = await createViteServer(viteConfig);
113
- // Reload config when sourcey.config.ts changes
285
+ // Incremental rebuild when content files change
114
286
  vite.watcher.on("change", async (file) => {
115
- if (file === configPath) {
287
+ // Check direct match first (markdown pages, spec files, config)
288
+ let content = fileToContent.get(file);
289
+ // For .xml files inside a doxygen directory, map to the parent tab
290
+ if (!content && extname(file) === ".xml") {
291
+ for (const [, c] of fileToContent) {
292
+ if (c.kind === "doxygen" && file.startsWith(resolve(c.xmlDir))) {
293
+ content = c;
294
+ break;
295
+ }
296
+ }
297
+ }
298
+ if (!content)
299
+ return;
300
+ if (content.kind === "config") {
301
+ log("config changed, reloading...");
116
302
  config = await reloadConfig();
303
+ fileToContent = buildFileToContent(config);
304
+ for (const path of fileToContent.keys()) {
305
+ vite.watcher.add(path);
306
+ }
307
+ cache = null;
308
+ cachePromise = null;
309
+ fullRebuild().catch((err) => {
310
+ console.error(" Site data rebuild failed:", err.message);
311
+ });
312
+ }
313
+ else {
314
+ incrementalUpdate(content).catch((err) => {
315
+ console.error(" Incremental update failed:", err.message);
316
+ });
117
317
  }
118
318
  });
119
319
  await vite.listen();
120
320
  console.log(`\n Sourcey dev server running at http://localhost:${port}`);
121
321
  console.log(` Watching: ${watchPaths.length} content file${watchPaths.length === 1 ? "" : "s"} + components + CSS (HMR)`);
122
322
  console.log(` Press Ctrl+C to stop\n`);
323
+ // Build in background — server is listening, first request waits for this
324
+ fullRebuild().catch((err) => {
325
+ console.error(" Initial site data build failed:", err.message);
326
+ });
123
327
  }
124
- async function loadSiteData(tabs, loadMarkdownPageFn = loadMarkdownPage) {
328
+ async function loadSiteData(tabs) {
125
329
  const specsBySlug = new Map();
126
330
  const siteTabs = [];
127
331
  const pageMap = new Map();
@@ -168,7 +372,7 @@ async function loadSiteData(tabs, loadMarkdownPageFn = loadMarkdownPage) {
168
372
  for (const group of tab.groups) {
169
373
  for (const pagePath of group.pages) {
170
374
  const slug = slugFromPath(pagePath);
171
- const page = await loadMarkdownPageFn(pagePath, slug);
375
+ const page = await loadMarkdownPage(pagePath, slug);
172
376
  pagesByPath.set(pagePath, page);
173
377
  pageMap.set(tabPath(tab.slug, `${slug}.html`), {
174
378
  spec: primarySpec,
@@ -214,23 +418,6 @@ async function loadCustomCSS(paths) {
214
418
  }
215
419
  return parts.join("\n");
216
420
  }
217
- async function buildSearchIndexForDev(config) {
218
- const { siteTabs, pageMap, specsBySlug } = await loadSiteData(config.tabs);
219
- const navigation = buildSiteNavigation(siteTabs);
220
- const markdownPagesByTab = new Map();
221
- for (const tab of config.tabs) {
222
- if (tab.groups || tab.doxygen) {
223
- const tabPages = [];
224
- for (const [, entry] of pageMap) {
225
- if (entry.tabSlug === tab.slug && entry.currentPage.kind === "markdown") {
226
- tabPages.push(entry.currentPage.markdown);
227
- }
228
- }
229
- markdownPagesByTab.set(tab.slug, tabPages);
230
- }
231
- }
232
- return buildSearchIndex(specsBySlug, markdownPagesByTab, navigation);
233
- }
234
421
  const MIME_TYPES = {
235
422
  ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg",
236
423
  ".gif": "image/gif", ".svg": "image/svg+xml", ".webp": "image/webp",
@@ -245,4 +432,3 @@ async function resolveAssetUrl(pathOrUrl) {
245
432
  const data = await readFile(abs);
246
433
  return `data:${mime};base64,${data.toString("base64")}`;
247
434
  }
248
- //# sourceMappingURL=dev-server.js.map
package/dist/index.js CHANGED
@@ -244,4 +244,3 @@ function resolveInternalLinks(pages) {
244
244
  }
245
245
  }
246
246
  export { defineConfig } from "./config.js";
247
- //# sourceMappingURL=index.js.map
package/dist/init.js CHANGED
@@ -267,4 +267,3 @@ import { myFunction } from "my-package";
267
267
  consola.log("");
268
268
  },
269
269
  });
270
- //# sourceMappingURL=init.js.map
@@ -19,4 +19,3 @@ export const NavigationContext = createContext(null);
19
19
  */
20
20
  export const PageContext = createContext(null);
21
21
  export const SiteContext = createContext(null);
22
- //# sourceMappingURL=context.js.map
@@ -96,4 +96,3 @@ async function buildAssets(outputDir) {
96
96
  const builtCSS = await readFile(resolve(outputDir, "sourcey.css"), "utf-8").catch(() => "");
97
97
  await writeFile(resolve(outputDir, "sourcey.css"), builtCSS + "\n" + componentCSS, "utf-8");
98
98
  }
99
- //# sourceMappingURL=html-builder.js.map
@@ -14,4 +14,3 @@ export function renderPage(spec, options, navigation, currentPage, site) {
14
14
  }
15
15
  return `<!DOCTYPE html>\n${html}`;
16
16
  }
17
- //# sourceMappingURL=static-renderer.js.map
@@ -223,4 +223,3 @@ function indent(str, spaces) {
223
223
  const pad = " ".repeat(spaces);
224
224
  return str.replace(/\n/g, "\n" + pad);
225
225
  }
226
- //# sourceMappingURL=code-samples.js.map
@@ -6,4 +6,3 @@ export const COPY_ICON_PATH_1 = "M14.25 5.25H7.25C6.14543 5.25 5.25 6.14543 5.25
6
6
  export const COPY_ICON_PATH_2 = "M2.80103 11.998L1.77203 5.07397C1.61003 3.98097 2.36403 2.96397 3.45603 2.80197L10.38 1.77297C11.313 1.63397 12.19 2.16297 12.528 3.00097";
7
7
  /** Raw HTML string for server-rendered contexts (markdown code blocks). */
8
8
  export const COPY_ICON_SVG = `<svg fill="none" height="18" viewBox="0 0 18 18" width="18" xmlns="http://www.w3.org/2000/svg"><title>Copy</title><path d="${COPY_ICON_PATH_1}" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="${COPY_ICON_PATH_2}" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
9
- //# sourceMappingURL=copy-svg.js.map
@@ -120,4 +120,3 @@ function mergeAllOfExamples(schemas, seen) {
120
120
  }
121
121
  return Object.keys(merged).length > 0 ? merged : undefined;
122
122
  }
123
- //# sourceMappingURL=example-generator.js.map
@@ -59,4 +59,3 @@ export function highlightCode(code, lang) {
59
59
  defaultColor: false,
60
60
  });
61
61
  }
62
- //# sourceMappingURL=highlighter.js.map
@@ -8,4 +8,3 @@ export function htmlId(value) {
8
8
  .replace(/[^a-z0-9]+/g, "-")
9
9
  .replace(/^-+|-+$/g, "");
10
10
  }
11
- //# sourceMappingURL=html-id.js.map
@@ -94,4 +94,3 @@ export function methodColor(method) {
94
94
  return "bg-gray-500";
95
95
  }
96
96
  }
97
- //# sourceMappingURL=http.js.map
@@ -56,4 +56,3 @@ export function renderIcon(name) {
56
56
  return "";
57
57
  return `<svg class="card-icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">${path}</svg>`;
58
58
  }
59
- //# sourceMappingURL=icons.js.map
@@ -84,4 +84,3 @@ export function langIconCSS() {
84
84
  }
85
85
  return rules.join("\n");
86
86
  }
87
- //# sourceMappingURL=lang-icons.js.map
@@ -77,4 +77,3 @@ export function renderMarkdownInline(input) {
77
77
  return "";
78
78
  return marked.parseInline(input, { async: false });
79
79
  }
80
- //# sourceMappingURL=markdown.js.map
@@ -95,4 +95,3 @@ export function sourceyPlugin(options) {
95
95
  },
96
96
  };
97
97
  }
98
- //# sourceMappingURL=vite-plugin.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sourcey",
3
- "version": "3.3.5",
3
+ "version": "3.3.6",
4
4
  "description": "Open source documentation platform. API references, guides, static output.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -69,10 +69,10 @@
69
69
  "license": "AGPL-3.0-only",
70
70
  "repository": {
71
71
  "type": "git",
72
- "url": "git+https://github.com/sourcey/sourcey.git"
72
+ "url": "git+https://github.com/nilstate/sourcey.git"
73
73
  },
74
74
  "bugs": {
75
- "url": "https://github.com/sourcey/sourcey/issues"
75
+ "url": "https://github.com/nilstate/sourcey/issues"
76
76
  },
77
- "homepage": "https://github.com/sourcey/sourcey#readme"
77
+ "homepage": "https://github.com/nilstate/sourcey#readme"
78
78
  }