sourcey 3.3.5 → 3.3.7
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.
- package/README.md +3 -3
- package/dist/cli.js +0 -1
- package/dist/client/index.js +0 -1
- package/dist/components/App.js +0 -1
- package/dist/components/layout/Head.js +0 -1
- package/dist/components/layout/Header.js +0 -1
- package/dist/components/layout/Page.js +0 -1
- package/dist/components/layout/Sidebar.js +0 -1
- package/dist/components/layout/TableOfContents.js +0 -1
- package/dist/components/openapi/CodeSamples.js +0 -1
- package/dist/components/openapi/Definition.js +0 -1
- package/dist/components/openapi/EndpointBar.js +0 -1
- package/dist/components/openapi/Introduction.js +0 -1
- package/dist/components/openapi/Operation.js +0 -1
- package/dist/components/openapi/Parameters.js +0 -1
- package/dist/components/openapi/RequestBody.js +0 -1
- package/dist/components/openapi/Responses.js +0 -1
- package/dist/components/openapi/Security.js +0 -1
- package/dist/components/openapi/Tags.js +0 -1
- package/dist/components/schema/ExampleView.js +0 -1
- package/dist/components/schema/SchemaDatatype.js +0 -1
- package/dist/components/schema/SchemaView.js +0 -1
- package/dist/components/ui/Badge.js +0 -1
- package/dist/components/ui/CopyButton.js +0 -1
- package/dist/components/ui/Logo.js +0 -1
- package/dist/components/ui/Markdown.js +0 -1
- package/dist/components/ui/SectionLabel.js +0 -1
- package/dist/components/ui/SocialIcon.js +0 -1
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -1
- package/dist/core/converter.js +0 -1
- package/dist/core/doxygen-loader.d.ts.map +1 -1
- package/dist/core/doxygen-loader.js +158 -4
- package/dist/core/loader.js +0 -1
- package/dist/core/markdown-loader.js +0 -1
- package/dist/core/navigation.js +0 -1
- package/dist/core/normalizer.js +0 -1
- package/dist/core/parser.js +0 -1
- package/dist/core/search-indexer.js +0 -1
- package/dist/core/types.js +0 -1
- package/dist/dev-server.d.ts.map +1 -1
- package/dist/dev-server.js +217 -31
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -11
- package/dist/init.js +0 -1
- package/dist/renderer/context.js +0 -1
- package/dist/renderer/html-builder.js +0 -1
- package/dist/renderer/static-renderer.js +0 -1
- package/dist/utils/code-samples.js +0 -1
- package/dist/utils/copy-svg.js +0 -1
- package/dist/utils/example-generator.js +0 -1
- package/dist/utils/highlighter.js +0 -1
- package/dist/utils/html-id.js +0 -1
- package/dist/utils/http.js +0 -1
- package/dist/utils/icons.js +0 -1
- package/dist/utils/lang-icons.js +0 -1
- package/dist/utils/markdown.js +0 -1
- package/dist/vite-plugin.js +0 -1
- 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
|
[](https://www.npmjs.com/package/sourcey)
|
|
8
|
-
[](https://github.com/nilstate/sourcey/actions)
|
|
9
9
|
[](https://nodejs.org)
|
|
10
10
|
|
|
11
11
|
```bash
|
|
@@ -14,7 +14,7 @@ npx sourcey init
|
|
|
14
14
|
|
|
15
15
|

|
|
16
16
|
|
|
17
|
-
**[Live demo](https://cheesestore.github.io/)** · [Documentation](https://sourcey.com/docs) · [GitHub](https://github.com/
|
|
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/
|
|
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
package/dist/client/index.js
CHANGED
package/dist/components/App.js
CHANGED
|
@@ -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
|
|
@@ -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
|
|
@@ -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
|
|
@@ -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
|
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;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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,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;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
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
|
package/dist/core/converter.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doxygen-loader.d.ts","sourceRoot":"","sources":["../../src/core/doxygen-loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
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
|
-
|
|
219
|
+
function escHtml(s) {
|
|
220
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
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
|
+
}
|
package/dist/core/loader.js
CHANGED
package/dist/core/navigation.js
CHANGED
package/dist/core/normalizer.js
CHANGED
package/dist/core/parser.js
CHANGED
package/dist/core/types.js
CHANGED
package/dist/dev-server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../src/dev-server.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/dev-server.js
CHANGED
|
@@ -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
|
|
62
|
-
//
|
|
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
|
|
65
|
-
const { siteTabs,
|
|
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
|
-
|
|
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"
|
|
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:
|
|
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
|
-
//
|
|
285
|
+
// Incremental rebuild when content files change
|
|
114
286
|
vite.watcher.on("change", async (file) => {
|
|
115
|
-
|
|
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
|
|
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
|
|
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.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAe,MAAM,aAAa,CAAC;AAc/D,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAY3E;AAMD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,MAAM,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CACtC;AAED,wBAAsB,aAAa,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CA0G5F;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAe,MAAM,aAAa,CAAC;AAc/D,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAY3E;AAMD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,MAAM,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CACtC;AAED,wBAAsB,aAAa,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CA0G5F;AAgKD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,YAAY,EACV,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
|
-
import { resolve, extname } from "node:path";
|
|
2
|
+
import { resolve, extname, posix } from "node:path";
|
|
3
3
|
import { loadSpec } from "./core/loader.js";
|
|
4
4
|
import { convertToOpenApi3 } from "./core/converter.js";
|
|
5
5
|
import { parseSpec } from "./core/parser.js";
|
|
@@ -99,7 +99,7 @@ export async function buildSiteDocs(options = {}) {
|
|
|
99
99
|
// Resolve internal links in markdown pages.
|
|
100
100
|
// Builds a map from every plausible href to the correct output path,
|
|
101
101
|
// then rewrites matching href attributes in each page's HTML.
|
|
102
|
-
resolveInternalLinks(sitePages);
|
|
102
|
+
resolveInternalLinks(sitePages, config);
|
|
103
103
|
// Build search index
|
|
104
104
|
const markdownPagesByTab = new Map();
|
|
105
105
|
for (const tab of tabs) {
|
|
@@ -192,7 +192,7 @@ async function resolveAssetUrl(pathOrUrl) {
|
|
|
192
192
|
* rewrites matching href values so they resolve on static file servers
|
|
193
193
|
* that don't support extensionless URLs.
|
|
194
194
|
*/
|
|
195
|
-
function resolveInternalLinks(pages) {
|
|
195
|
+
function resolveInternalLinks(pages, config) {
|
|
196
196
|
// Build a map from every plausible clean path to the output path.
|
|
197
197
|
// e.g. "components" -> "components.html", "config/ref-theme-tokens" -> "config/ref-theme-tokens.html"
|
|
198
198
|
const pathMap = new Map();
|
|
@@ -201,6 +201,10 @@ function resolveInternalLinks(pages) {
|
|
|
201
201
|
const clean = out.replace(/\.html$/, ""); // "components" or "config/ref-theme-tokens"
|
|
202
202
|
pathMap.set(clean, out);
|
|
203
203
|
}
|
|
204
|
+
// Repo source link base: e.g. "https://github.com/user/repo/tree/main"
|
|
205
|
+
const repoBase = config.repo?.replace(/\/$/, "");
|
|
206
|
+
const branch = config.editBranch;
|
|
207
|
+
const sourceBase = repoBase && branch ? `${repoBase}/tree/${branch}` : undefined;
|
|
204
208
|
for (const page of pages) {
|
|
205
209
|
if (page.currentPage.kind !== "markdown" || !page.currentPage.markdown)
|
|
206
210
|
continue;
|
|
@@ -218,8 +222,8 @@ function resolveInternalLinks(pages) {
|
|
|
218
222
|
// Split off hash fragment
|
|
219
223
|
const [path, hash] = href.split("#", 2);
|
|
220
224
|
const hashSuffix = hash ? `#${hash}` : "";
|
|
221
|
-
// Normalize: strip leading slash, trailing slash
|
|
222
|
-
const clean = path.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
225
|
+
// Normalize: strip leading slash, trailing slash, and .md extension
|
|
226
|
+
const clean = path.replace(/^\/+/, "").replace(/\/+$/, "").replace(/\.md$/, "");
|
|
223
227
|
// Skip if already has .html extension
|
|
224
228
|
if (clean.endsWith(".html"))
|
|
225
229
|
return _match;
|
|
@@ -235,13 +239,26 @@ function resolveInternalLinks(pages) {
|
|
|
235
239
|
break;
|
|
236
240
|
candidate = candidate.substring(slash + 1);
|
|
237
241
|
}
|
|
238
|
-
if (
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
242
|
+
if (target) {
|
|
243
|
+
// Build relative path from this page to the target
|
|
244
|
+
const relativePath = toRoot + target;
|
|
245
|
+
return `href="${relativePath}${hashSuffix}"`;
|
|
246
|
+
}
|
|
247
|
+
// If the link contains ../ and we have a repo URL configured,
|
|
248
|
+
// resolve it relative to the markdown source file. Links to docs
|
|
249
|
+
// pages are already handled above (pathMap lookup catches them after
|
|
250
|
+
// .md stripping and prefix stripping). What remains are links to
|
|
251
|
+
// repo source code outside the docs directory.
|
|
252
|
+
if (sourceBase && href.includes("../") && md.sourcePath) {
|
|
253
|
+
const sourceDir = posix.dirname(md.sourcePath);
|
|
254
|
+
const resolved = posix.normalize(posix.join(sourceDir, path));
|
|
255
|
+
// Only rewrite if the path stays inside the repo root
|
|
256
|
+
if (!resolved.startsWith("..")) {
|
|
257
|
+
return `href="${sourceBase}/${resolved}${hashSuffix}"`;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return _match;
|
|
243
261
|
});
|
|
244
262
|
}
|
|
245
263
|
}
|
|
246
264
|
export { defineConfig } from "./config.js";
|
|
247
|
-
//# sourceMappingURL=index.js.map
|
package/dist/init.js
CHANGED
package/dist/renderer/context.js
CHANGED
|
@@ -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
|
package/dist/utils/copy-svg.js
CHANGED
|
@@ -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
|
package/dist/utils/html-id.js
CHANGED
package/dist/utils/http.js
CHANGED
package/dist/utils/icons.js
CHANGED
package/dist/utils/lang-icons.js
CHANGED
package/dist/utils/markdown.js
CHANGED
package/dist/vite-plugin.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sourcey",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.7",
|
|
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/
|
|
72
|
+
"url": "git+https://github.com/nilstate/sourcey.git"
|
|
73
73
|
},
|
|
74
74
|
"bugs": {
|
|
75
|
-
"url": "https://github.com/
|
|
75
|
+
"url": "https://github.com/nilstate/sourcey/issues"
|
|
76
76
|
},
|
|
77
|
-
"homepage": "https://github.com/
|
|
77
|
+
"homepage": "https://github.com/nilstate/sourcey#readme"
|
|
78
78
|
}
|