sourcey 3.4.11 → 3.5.1
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 +13 -12
- package/dist/cli.js +46 -4
- package/dist/components/changelog/ChangelogPage.d.ts +5 -0
- package/dist/components/changelog/ChangelogPage.d.ts.map +1 -0
- package/dist/components/changelog/ChangelogPage.js +8 -0
- package/dist/components/changelog/EntryList.d.ts +5 -0
- package/dist/components/changelog/EntryList.d.ts.map +1 -0
- package/dist/components/changelog/EntryList.js +6 -0
- package/dist/components/changelog/TypeBadge.d.ts +6 -0
- package/dist/components/changelog/TypeBadge.d.ts.map +1 -0
- package/dist/components/changelog/TypeBadge.js +14 -0
- package/dist/components/changelog/VersionCard.d.ts +6 -0
- package/dist/components/changelog/VersionCard.d.ts.map +1 -0
- package/dist/components/changelog/VersionCard.js +25 -0
- package/dist/components/layout/Head.d.ts.map +1 -1
- package/dist/components/layout/Head.js +15 -3
- package/dist/components/layout/Page.d.ts.map +1 -1
- package/dist/components/layout/Page.js +12 -6
- package/dist/components/openapi/Introduction.d.ts.map +1 -1
- package/dist/components/openapi/Introduction.js +1 -1
- package/dist/components/openapi/MediaTypeDetails.d.ts +11 -0
- package/dist/components/openapi/MediaTypeDetails.d.ts.map +1 -0
- package/dist/components/openapi/MediaTypeDetails.js +54 -0
- package/dist/components/openapi/Parameters.d.ts.map +1 -1
- package/dist/components/openapi/Parameters.js +6 -1
- package/dist/components/openapi/RequestBody.d.ts.map +1 -1
- package/dist/components/openapi/RequestBody.js +5 -1
- package/dist/components/openapi/Responses.d.ts.map +1 -1
- package/dist/components/openapi/Responses.js +1 -1
- package/dist/components/openapi/Security.d.ts.map +1 -1
- package/dist/components/openapi/Security.js +3 -2
- package/dist/components/openapi/Tags.d.ts.map +1 -1
- package/dist/components/openapi/Tags.js +8 -1
- package/dist/config.d.ts +50 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +50 -4
- package/dist/core/changelog-normalizer.d.ts +8 -0
- package/dist/core/changelog-normalizer.d.ts.map +1 -0
- package/dist/core/changelog-normalizer.js +531 -0
- package/dist/core/doxygen-loader.d.ts.map +1 -1
- package/dist/core/doxygen-loader.js +2 -0
- package/dist/core/loader.js +2 -0
- package/dist/core/markdown-loader.d.ts +21 -0
- package/dist/core/markdown-loader.d.ts.map +1 -1
- package/dist/core/markdown-loader.js +43 -25
- package/dist/core/mcp-normalizer.d.ts.map +1 -1
- package/dist/core/navigation.d.ts +4 -3
- package/dist/core/navigation.d.ts.map +1 -1
- package/dist/core/navigation.js +20 -6
- package/dist/core/normalizer.d.ts.map +1 -1
- package/dist/core/normalizer.js +102 -4
- package/dist/core/parser.d.ts +2 -2
- package/dist/core/parser.d.ts.map +1 -1
- package/dist/core/parser.js +23 -16
- package/dist/core/search-indexer.d.ts +3 -2
- package/dist/core/search-indexer.d.ts.map +1 -1
- package/dist/core/search-indexer.js +50 -17
- package/dist/core/tag-utils.d.ts +5 -0
- package/dist/core/tag-utils.d.ts.map +1 -0
- package/dist/core/tag-utils.js +22 -0
- package/dist/core/types.d.ts +82 -4
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +1 -1
- package/dist/dev-server.d.ts +2 -0
- package/dist/dev-server.d.ts.map +1 -1
- package/dist/dev-server.js +83 -212
- package/dist/index.d.ts +6 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +115 -247
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +7 -3
- package/dist/og/fonts/Inter-Bold.ttf +0 -0
- package/dist/og/fonts/Inter-Regular.ttf +0 -0
- package/dist/og/generate-og-image.d.ts +10 -0
- package/dist/og/generate-og-image.d.ts.map +1 -0
- package/dist/og/generate-og-image.js +198 -0
- package/dist/renderer/changelog-feed.d.ts +18 -0
- package/dist/renderer/changelog-feed.d.ts.map +1 -0
- package/dist/renderer/changelog-feed.js +91 -0
- package/dist/renderer/context.d.ts +27 -7
- package/dist/renderer/context.d.ts.map +1 -1
- package/dist/renderer/html-builder.d.ts +10 -1
- package/dist/renderer/html-builder.d.ts.map +1 -1
- package/dist/renderer/html-builder.js +58 -5
- package/dist/renderer/llms.d.ts.map +1 -1
- package/dist/renderer/llms.js +133 -24
- package/dist/site-assembly.d.ts +25 -0
- package/dist/site-assembly.d.ts.map +1 -0
- package/dist/site-assembly.js +467 -0
- package/dist/site-url.d.ts +12 -0
- package/dist/site-url.d.ts.map +1 -0
- package/dist/site-url.js +67 -0
- package/dist/themes/default/sourcey.css +236 -0
- package/dist/utils/code-samples.d.ts.map +1 -1
- package/dist/utils/code-samples.js +53 -12
- package/dist/utils/markdown.d.ts +6 -0
- package/dist/utils/markdown.d.ts.map +1 -1
- package/dist/utils/markdown.js +11 -2
- package/dist/vite-plugin.d.ts +2 -0
- package/dist/vite-plugin.d.ts.map +1 -1
- package/dist/vite-plugin.js +6 -2
- package/package.json +6 -3
package/dist/dev-server.js
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { createServer as createViteServer } from "vite";
|
|
2
2
|
import { resolve, dirname, extname, basename, relative } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { access } from "node:fs/promises";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { loadConfig, resolveConfigFromRaw, tabPath } from "./config.js";
|
|
5
|
+
import { loadConfig, pageOutputPath, resolveConfigFromRaw, tabPath } from "./config.js";
|
|
6
6
|
import { loadSpec } from "./core/loader.js";
|
|
7
7
|
import { convertToOpenApi3 } from "./core/converter.js";
|
|
8
8
|
import { parseSpec } from "./core/parser.js";
|
|
9
9
|
import { normalizeSpec } from "./core/normalizer.js";
|
|
10
10
|
import { normalizeMcpSpec } from "./core/mcp-normalizer.js";
|
|
11
|
-
import { buildNavFromSpec,
|
|
12
|
-
import {
|
|
11
|
+
import { buildNavFromSpec, buildSiteNavigation, withActivePage } from "./core/navigation.js";
|
|
12
|
+
import { loadDocsPage, slugFromPath } from "./core/markdown-loader.js";
|
|
13
13
|
import { loadDoxygenTab } from "./core/doxygen-loader.js";
|
|
14
14
|
import { buildSearchIndex } from "./core/search-indexer.js";
|
|
15
|
+
import { createRenderOptions } from "./renderer/html-builder.js";
|
|
16
|
+
import { assembleSite, buildSiteConfig, collectDocsPagesByTab, enforceChangelogDiagnostics, formatChangelogDiagnostic, rebuildMarkdownTabNavigation, resolveInternalLinks, } from "./site-assembly.js";
|
|
17
|
+
import { stripBaseUrl } from "./site-url.js";
|
|
15
18
|
import { sourceyPlugin } from "./vite-plugin.js";
|
|
16
19
|
import tailwindcss from "@tailwindcss/vite";
|
|
17
20
|
import preact from "@preact/preset-vite";
|
|
@@ -29,14 +32,15 @@ function log(msg) {
|
|
|
29
32
|
const t = new Date().toLocaleTimeString([], { hour12: false, hour: "2-digit", minute: "2-digit", second: "2-digit" });
|
|
30
33
|
console.log(` \x1b[2m${t}\x1b[0m ${msg}`);
|
|
31
34
|
}
|
|
32
|
-
function shortPath(
|
|
33
|
-
return relative(process.cwd(),
|
|
35
|
+
function shortPath(path) {
|
|
36
|
+
return relative(process.cwd(), path) || basename(path);
|
|
34
37
|
}
|
|
35
38
|
export async function startDevServer(options) {
|
|
36
39
|
const { port } = options;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
let config = await loadConfig(options.config);
|
|
41
|
+
const configPath = options.config?.endsWith(".ts")
|
|
42
|
+
? resolve(options.config)
|
|
43
|
+
: resolve(options.config ?? process.cwd(), "sourcey.config.ts");
|
|
40
44
|
const watchPaths = [configPath];
|
|
41
45
|
for (const tab of config.tabs) {
|
|
42
46
|
if (tab.openapi)
|
|
@@ -47,8 +51,8 @@ export async function startDevServer(options) {
|
|
|
47
51
|
watchPaths.push(tab.doxygen.xml);
|
|
48
52
|
if (tab.groups) {
|
|
49
53
|
for (const group of tab.groups) {
|
|
50
|
-
for (const
|
|
51
|
-
watchPaths.push(
|
|
54
|
+
for (const page of group.pages) {
|
|
55
|
+
watchPaths.push(page.file);
|
|
52
56
|
}
|
|
53
57
|
}
|
|
54
58
|
}
|
|
@@ -68,8 +72,8 @@ export async function startDevServer(options) {
|
|
|
68
72
|
}
|
|
69
73
|
if (tab.groups) {
|
|
70
74
|
for (const group of tab.groups) {
|
|
71
|
-
for (const
|
|
72
|
-
map.set(resolve(
|
|
75
|
+
for (const page of group.pages) {
|
|
76
|
+
map.set(resolve(page.file), { kind: "markdown", tabSlug: tab.slug, pagePath: page.file, pageSlug: page.slug });
|
|
73
77
|
}
|
|
74
78
|
}
|
|
75
79
|
}
|
|
@@ -77,23 +81,30 @@ export async function startDevServer(options) {
|
|
|
77
81
|
return map;
|
|
78
82
|
}
|
|
79
83
|
let fileToContent = buildFileToContent(config);
|
|
80
|
-
// Resolve source paths for Vite dev serving.
|
|
81
|
-
// Prefer src/ (local dev) but fall back to dist/ (npm install).
|
|
82
84
|
const projectRoot = resolve(__dirname, "..");
|
|
83
85
|
const hasSrc = await exists(resolve(projectRoot, "src/client/index.ts"));
|
|
84
86
|
const tailwindCssPath = resolve(projectRoot, hasSrc ? "src/themes/default/main.css" : "dist/themes/default/main.css");
|
|
85
87
|
const sourceyCssPath = resolve(projectRoot, hasSrc ? "src/themes/default/sourcey.css" : "dist/themes/default/sourcey.css");
|
|
86
88
|
const clientEntry = resolve(projectRoot, hasSrc ? "src/client/index.ts" : "dist/client/index.js");
|
|
87
89
|
const ssrRendererPath = resolve(projectRoot, hasSrc ? "src/renderer/static-renderer.ts" : "dist/renderer/static-renderer.js");
|
|
88
|
-
let vite;
|
|
89
90
|
let cache = null;
|
|
90
91
|
let cachePromise = null;
|
|
92
|
+
function reportChangelogDiagnostics(diagnostics) {
|
|
93
|
+
for (const diagnostic of diagnostics) {
|
|
94
|
+
const writer = diagnostic.severity === "error" ? console.error : console.warn;
|
|
95
|
+
writer(` ${formatChangelogDiagnostic(diagnostic)}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
91
98
|
function fullRebuild() {
|
|
92
99
|
if (!cachePromise) {
|
|
93
100
|
const start = performance.now();
|
|
94
101
|
log("building site data...");
|
|
95
102
|
cachePromise = (async () => {
|
|
96
|
-
const data = await
|
|
103
|
+
const data = await assembleSite(config);
|
|
104
|
+
if (data.changelogDiagnostics.length) {
|
|
105
|
+
reportChangelogDiagnostics(data.changelogDiagnostics);
|
|
106
|
+
}
|
|
107
|
+
enforceChangelogDiagnostics(data.changelogDiagnostics, options.strictChangelog ?? false);
|
|
97
108
|
const siteConfig = await buildSiteConfig(config);
|
|
98
109
|
const result = { data, siteConfig };
|
|
99
110
|
cache = result;
|
|
@@ -113,12 +124,7 @@ export async function startDevServer(options) {
|
|
|
113
124
|
return Promise.resolve(cache);
|
|
114
125
|
return fullRebuild();
|
|
115
126
|
}
|
|
116
|
-
// Incremental patch: reload only the piece that changed, then reassemble
|
|
117
|
-
// siteTabs + pageMap from the patched data. Falls back to full rebuild if
|
|
118
|
-
// the cache isn't warm yet.
|
|
119
127
|
async function incrementalUpdate(content) {
|
|
120
|
-
// Capture current cache; if a full rebuild replaces it while we await,
|
|
121
|
-
// we abandon this patch (the rebuild already produced fresh data).
|
|
122
128
|
const snapshot = cache;
|
|
123
129
|
if (!snapshot) {
|
|
124
130
|
await fullRebuild();
|
|
@@ -129,37 +135,48 @@ export async function startDevServer(options) {
|
|
|
129
135
|
if (content.kind === "markdown") {
|
|
130
136
|
const slug = slugFromPath(content.pageSlug);
|
|
131
137
|
log(`reloading ${shortPath(content.pagePath)}`);
|
|
132
|
-
const page = await
|
|
138
|
+
const page = await loadDocsPage(content.pagePath, slug, {
|
|
139
|
+
changelog: config.changelog.enabled,
|
|
140
|
+
repoUrl: config.repo,
|
|
141
|
+
});
|
|
133
142
|
if (cache !== snapshot)
|
|
134
143
|
return;
|
|
135
|
-
const pageKey =
|
|
144
|
+
const pageKey = pageOutputPath(content.tabSlug, slug, config.prettyUrls);
|
|
136
145
|
const existing = data.pageMap.get(pageKey);
|
|
146
|
+
if (page.kind === "changelog" || existing?.currentPage.kind === "changelog") {
|
|
147
|
+
cache = null;
|
|
148
|
+
cachePromise = null;
|
|
149
|
+
await fullRebuild();
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
137
152
|
if (existing) {
|
|
138
153
|
existing.currentPage = { kind: "markdown", markdown: page };
|
|
139
154
|
}
|
|
140
|
-
|
|
155
|
+
rebuildMarkdownTabNavigation(data.pageMap, data.siteTabs, config.tabs, content.tabSlug, config.prettyUrls);
|
|
141
156
|
}
|
|
142
157
|
else if (content.kind === "doxygen") {
|
|
143
|
-
const tab = config.tabs.find((
|
|
158
|
+
const tab = config.tabs.find((candidate) => candidate.slug === content.tabSlug);
|
|
144
159
|
if (!tab?.doxygen)
|
|
145
160
|
return;
|
|
146
161
|
log(`rebuilding doxygen tab "${tab.label}"`);
|
|
147
162
|
const { pages, navTab } = await loadDoxygenTab(tab.doxygen, tab.slug, tab.label);
|
|
148
163
|
if (cache !== snapshot)
|
|
149
164
|
return;
|
|
150
|
-
for (const [key,
|
|
151
|
-
if (
|
|
165
|
+
for (const [key, page] of data.pageMap) {
|
|
166
|
+
if (page.tabSlug === content.tabSlug)
|
|
152
167
|
data.pageMap.delete(key);
|
|
153
168
|
}
|
|
154
169
|
for (const [slug, page] of pages) {
|
|
155
|
-
|
|
170
|
+
const outputPath = pageOutputPath(tab.slug, slug, config.prettyUrls);
|
|
171
|
+
data.pageMap.set(outputPath, {
|
|
172
|
+
outputPath,
|
|
156
173
|
spec: data.primarySpec,
|
|
157
174
|
currentPage: { kind: "markdown", markdown: page },
|
|
158
175
|
tabSlug: tab.slug,
|
|
159
176
|
pageSlug: slug,
|
|
160
177
|
});
|
|
161
178
|
}
|
|
162
|
-
const idx = data.siteTabs.findIndex((
|
|
179
|
+
const idx = data.siteTabs.findIndex((candidate) => candidate.slug === content.tabSlug);
|
|
163
180
|
if (idx !== -1)
|
|
164
181
|
data.siteTabs[idx] = navTab;
|
|
165
182
|
else
|
|
@@ -180,11 +197,11 @@ export async function startDevServer(options) {
|
|
|
180
197
|
existing.currentPage = { kind: "spec", spec };
|
|
181
198
|
existing.spec = spec;
|
|
182
199
|
}
|
|
183
|
-
const tab = config.tabs.find((
|
|
200
|
+
const tab = config.tabs.find((candidate) => candidate.slug === content.tabSlug);
|
|
184
201
|
if (tab) {
|
|
185
|
-
const navTab = buildNavFromSpec(spec, tab.slug);
|
|
202
|
+
const navTab = buildNavFromSpec(spec, tab.slug, config.prettyUrls);
|
|
186
203
|
navTab.label = tab.label;
|
|
187
|
-
const idx = data.siteTabs.findIndex((
|
|
204
|
+
const idx = data.siteTabs.findIndex((candidate) => candidate.slug === content.tabSlug);
|
|
188
205
|
if (idx !== -1)
|
|
189
206
|
data.siteTabs[idx] = navTab;
|
|
190
207
|
}
|
|
@@ -203,54 +220,31 @@ export async function startDevServer(options) {
|
|
|
203
220
|
existing.currentPage = { kind: "spec", spec };
|
|
204
221
|
existing.spec = spec;
|
|
205
222
|
}
|
|
206
|
-
const tab = config.tabs.find((
|
|
223
|
+
const tab = config.tabs.find((candidate) => candidate.slug === content.tabSlug);
|
|
207
224
|
if (tab) {
|
|
208
|
-
const navTab = buildNavFromSpec(spec, tab.slug);
|
|
225
|
+
const navTab = buildNavFromSpec(spec, tab.slug, config.prettyUrls);
|
|
209
226
|
navTab.label = tab.label;
|
|
210
|
-
const idx = data.siteTabs.findIndex((
|
|
227
|
+
const idx = data.siteTabs.findIndex((candidate) => candidate.slug === content.tabSlug);
|
|
211
228
|
if (idx !== -1)
|
|
212
229
|
data.siteTabs[idx] = navTab;
|
|
213
230
|
}
|
|
214
231
|
}
|
|
232
|
+
resolveInternalLinks(Array.from(data.pageMap.values()), config);
|
|
215
233
|
const ms = Math.round(performance.now() - start);
|
|
216
234
|
log(`updated \x1b[2m(${ms}ms)\x1b[0m`);
|
|
217
235
|
}
|
|
218
|
-
// Rebuild navigation for a single markdown tab from cached page data
|
|
219
|
-
function rebuildTabNav(data, tabs, tabSlug) {
|
|
220
|
-
const tab = tabs.find((t) => t.slug === tabSlug);
|
|
221
|
-
if (!tab?.groups)
|
|
222
|
-
return;
|
|
223
|
-
const pagesByPath = new Map();
|
|
224
|
-
for (const group of tab.groups) {
|
|
225
|
-
for (const rp of group.pages) {
|
|
226
|
-
const slug = slugFromPath(rp.slug);
|
|
227
|
-
const pageKey = tabPath(tab.slug, `${slug}.html`);
|
|
228
|
-
const entry = data.pageMap.get(pageKey);
|
|
229
|
-
if (entry?.currentPage.kind === "markdown") {
|
|
230
|
-
pagesByPath.set(rp.slug, entry.currentPage.markdown);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
const navTab = buildNavFromPages(tab, pagesByPath);
|
|
235
|
-
const idx = data.siteTabs.findIndex((t) => t.slug === tabSlug);
|
|
236
|
-
if (idx !== -1)
|
|
237
|
-
data.siteTabs[idx] = navTab;
|
|
238
|
-
}
|
|
239
|
-
// Reload config through Vite SSR (bypasses Node's module cache)
|
|
240
236
|
async function reloadConfig() {
|
|
241
237
|
const configMod = await vite.ssrLoadModule(configPath);
|
|
242
|
-
return resolveConfigFromRaw(configMod.default,
|
|
238
|
+
return resolveConfigFromRaw(configMod.default, dirname(configPath));
|
|
243
239
|
}
|
|
244
240
|
async function render(url) {
|
|
245
|
-
// Load renderer through Vite's SSR graph so invalidateAll() picks up
|
|
246
|
-
// component changes. Site data uses static imports (file reads only).
|
|
247
241
|
const { renderPage } = await vite.ssrLoadModule(ssrRendererPath);
|
|
248
242
|
const { data, siteConfig: site } = await getCached();
|
|
249
|
-
const
|
|
250
|
-
const
|
|
251
|
-
let pagePath =
|
|
243
|
+
const navigation = buildSiteNavigation(data.siteTabs);
|
|
244
|
+
const requestPath = stripBaseUrl(new URL(url, "http://sourcey.local").pathname, config.baseUrl);
|
|
245
|
+
let pagePath = requestPath.replace(/^\//, "").replace(/\/$/, "");
|
|
252
246
|
if (!pagePath || pagePath === "index.html") {
|
|
253
|
-
const firstKey = pageMap.keys().next().value;
|
|
247
|
+
const firstKey = data.pageMap.keys().next().value;
|
|
254
248
|
if (!firstKey)
|
|
255
249
|
return null;
|
|
256
250
|
pagePath = firstKey;
|
|
@@ -258,35 +252,30 @@ export async function startDevServer(options) {
|
|
|
258
252
|
if (!pagePath.endsWith(".html")) {
|
|
259
253
|
pagePath += "/index.html";
|
|
260
254
|
}
|
|
261
|
-
|
|
255
|
+
let pageData = data.pageMap.get(pagePath);
|
|
256
|
+
if (!pageData && pagePath.endsWith(".html") && !pagePath.endsWith("/index.html")) {
|
|
257
|
+
// Fallback for stale `.html` links when prettyUrls is enabled.
|
|
258
|
+
const pretty = pagePath.replace(/\.html$/, "/index.html");
|
|
259
|
+
pageData = data.pageMap.get(pretty);
|
|
260
|
+
}
|
|
262
261
|
if (!pageData)
|
|
263
262
|
return null;
|
|
264
263
|
const activeNav = withActivePage(navigation, pageData.tabSlug, pageData.pageSlug);
|
|
265
|
-
const renderOptions =
|
|
264
|
+
const renderOptions = createRenderOptions(pageData, site, {
|
|
265
|
+
embeddable: false,
|
|
266
|
+
assetBase: config.baseUrl || "/",
|
|
267
|
+
});
|
|
266
268
|
let html = renderPage(pageData.spec, renderOptions, activeNav, pageData.currentPage, site);
|
|
267
|
-
// Rewrite asset paths for Vite HMR
|
|
268
|
-
// Preact outputs <link ... href="/sourcey.css"/> (no space before />)
|
|
269
269
|
html = html.replace(/<link rel="stylesheet" href="[^"]*sourcey\.css"\s*\/?>/, `<link rel="stylesheet" href="/@fs${tailwindCssPath}" />\n<link rel="stylesheet" href="/@fs${sourceyCssPath}?direct" />`);
|
|
270
270
|
html = html.replace(/<script src="[^"]*sourcey\.js"[^>]*><\/script>/, `<script type="module" src="/@fs${clientEntry}"></script>`);
|
|
271
271
|
html = html.replace(/<script src="[^"]*sourcey\.js"\s*\/?>/, `<script type="module" src="/@fs${clientEntry}"></script>`);
|
|
272
272
|
return html;
|
|
273
273
|
}
|
|
274
274
|
async function buildSearchIndexForDev() {
|
|
275
|
-
const { data
|
|
276
|
-
const navigation = buildSiteNavigation(siteTabs);
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
if (tab.groups || tab.doxygen) {
|
|
280
|
-
const tabPages = [];
|
|
281
|
-
for (const [, entry] of pageMap) {
|
|
282
|
-
if (entry.tabSlug === tab.slug && entry.currentPage.kind === "markdown") {
|
|
283
|
-
tabPages.push(entry.currentPage.markdown);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
markdownPagesByTab.set(tab.slug, tabPages);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
return buildSearchIndex(specsBySlug, markdownPagesByTab, navigation, "/", config.search.featured);
|
|
275
|
+
const { data } = await getCached();
|
|
276
|
+
const navigation = buildSiteNavigation(data.siteTabs);
|
|
277
|
+
const docsPagesByTab = collectDocsPagesByTab(data.pageMap, config.tabs);
|
|
278
|
+
return buildSearchIndex(data.specsBySlug, docsPagesByTab, navigation, config.baseUrl || "/", config.search.featured);
|
|
290
279
|
}
|
|
291
280
|
const viteConfig = {
|
|
292
281
|
root: process.cwd(),
|
|
@@ -303,6 +292,7 @@ export async function startDevServer(options) {
|
|
|
303
292
|
tailwindcss(),
|
|
304
293
|
sourceyPlugin({
|
|
305
294
|
watchPaths,
|
|
295
|
+
baseUrl: () => config.baseUrl,
|
|
306
296
|
render,
|
|
307
297
|
searchIndex: buildSearchIndexForDev,
|
|
308
298
|
}),
|
|
@@ -313,16 +303,13 @@ export async function startDevServer(options) {
|
|
|
313
303
|
exclude: ["sourcey"],
|
|
314
304
|
},
|
|
315
305
|
};
|
|
316
|
-
vite = await createViteServer(viteConfig);
|
|
317
|
-
// Incremental rebuild when content files change
|
|
306
|
+
const vite = await createViteServer(viteConfig);
|
|
318
307
|
vite.watcher.on("change", async (file) => {
|
|
319
|
-
// Check direct match first (markdown pages, spec files, config)
|
|
320
308
|
let content = fileToContent.get(file);
|
|
321
|
-
// For .xml files inside a doxygen directory, map to the parent tab
|
|
322
309
|
if (!content && extname(file) === ".xml") {
|
|
323
|
-
for (const [,
|
|
324
|
-
if (
|
|
325
|
-
content =
|
|
310
|
+
for (const [, candidate] of fileToContent) {
|
|
311
|
+
if (candidate.kind === "doxygen" && file.startsWith(resolve(candidate.xmlDir))) {
|
|
312
|
+
content = candidate;
|
|
326
313
|
break;
|
|
327
314
|
}
|
|
328
315
|
}
|
|
@@ -341,133 +328,17 @@ export async function startDevServer(options) {
|
|
|
341
328
|
fullRebuild().catch((err) => {
|
|
342
329
|
console.error(" Site data rebuild failed:", err.message);
|
|
343
330
|
});
|
|
331
|
+
return;
|
|
344
332
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
});
|
|
349
|
-
}
|
|
333
|
+
incrementalUpdate(content).catch((err) => {
|
|
334
|
+
console.error(" Incremental update failed:", err.message);
|
|
335
|
+
});
|
|
350
336
|
});
|
|
351
337
|
await vite.listen();
|
|
352
|
-
console.log(`\n Sourcey dev server running at http://localhost:${port}`);
|
|
338
|
+
console.log(`\n Sourcey dev server running at http://localhost:${port}${config.baseUrl || "/"}`);
|
|
353
339
|
console.log(` Watching: ${watchPaths.length} content file${watchPaths.length === 1 ? "" : "s"} + components + CSS (HMR)`);
|
|
354
340
|
console.log(` Press Ctrl+C to stop\n`);
|
|
355
|
-
// Build in background — server is listening, first request waits for this
|
|
356
341
|
fullRebuild().catch((err) => {
|
|
357
342
|
console.error(" Initial site data build failed:", err.message);
|
|
358
343
|
});
|
|
359
344
|
}
|
|
360
|
-
async function loadSiteData(tabs) {
|
|
361
|
-
const specsBySlug = new Map();
|
|
362
|
-
const siteTabs = [];
|
|
363
|
-
const pageMap = new Map();
|
|
364
|
-
for (const tab of tabs) {
|
|
365
|
-
if (tab.openapi) {
|
|
366
|
-
const loaded = await loadSpec(tab.openapi);
|
|
367
|
-
const parsed = await parseSpec(loaded);
|
|
368
|
-
const openapi3 = await convertToOpenApi3(parsed);
|
|
369
|
-
const spec = normalizeSpec(openapi3);
|
|
370
|
-
specsBySlug.set(tab.slug, spec);
|
|
371
|
-
}
|
|
372
|
-
else if (tab.mcp) {
|
|
373
|
-
const { parse } = await import("mcp-parser");
|
|
374
|
-
const mcpSpec = await parse(tab.mcp);
|
|
375
|
-
const spec = normalizeMcpSpec(mcpSpec);
|
|
376
|
-
specsBySlug.set(tab.slug, spec);
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
const primarySpec = specsBySlug.values().next().value ?? {
|
|
380
|
-
info: { title: "", version: "", description: "" },
|
|
381
|
-
servers: [], tags: [], operations: [], schemas: {}, securitySchemes: {}, webhooks: [],
|
|
382
|
-
};
|
|
383
|
-
for (const tab of tabs) {
|
|
384
|
-
if (tab.openapi || tab.mcp) {
|
|
385
|
-
const spec = specsBySlug.get(tab.slug);
|
|
386
|
-
const navTab = buildNavFromSpec(spec, tab.slug);
|
|
387
|
-
navTab.label = tab.label;
|
|
388
|
-
siteTabs.push(navTab);
|
|
389
|
-
pageMap.set(tabPath(tab.slug, "index.html"), {
|
|
390
|
-
spec,
|
|
391
|
-
currentPage: { kind: "spec", spec },
|
|
392
|
-
tabSlug: tab.slug,
|
|
393
|
-
pageSlug: "introduction",
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
else if (tab.doxygen) {
|
|
397
|
-
const { pages, navTab } = await loadDoxygenTab(tab.doxygen, tab.slug, tab.label);
|
|
398
|
-
for (const [slug, page] of pages) {
|
|
399
|
-
pageMap.set(tabPath(tab.slug, `${slug}.html`), {
|
|
400
|
-
spec: primarySpec,
|
|
401
|
-
currentPage: { kind: "markdown", markdown: page },
|
|
402
|
-
tabSlug: tab.slug,
|
|
403
|
-
pageSlug: slug,
|
|
404
|
-
});
|
|
405
|
-
}
|
|
406
|
-
siteTabs.push(navTab);
|
|
407
|
-
}
|
|
408
|
-
else if (tab.groups) {
|
|
409
|
-
const pagesByPath = new Map();
|
|
410
|
-
for (const group of tab.groups) {
|
|
411
|
-
for (const rp of group.pages) {
|
|
412
|
-
const slug = slugFromPath(rp.slug);
|
|
413
|
-
const page = await loadMarkdownPage(rp.file, slug);
|
|
414
|
-
pagesByPath.set(rp.slug, page);
|
|
415
|
-
pageMap.set(tabPath(tab.slug, `${slug}.html`), {
|
|
416
|
-
spec: primarySpec,
|
|
417
|
-
currentPage: { kind: "markdown", markdown: page },
|
|
418
|
-
tabSlug: tab.slug,
|
|
419
|
-
pageSlug: slug,
|
|
420
|
-
});
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
const navTab = buildNavFromPages(tab, pagesByPath);
|
|
424
|
-
siteTabs.push(navTab);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
return { siteTabs, primarySpec, pageMap, specsBySlug };
|
|
428
|
-
}
|
|
429
|
-
async function buildSiteConfig(config) {
|
|
430
|
-
const logo = config.logo
|
|
431
|
-
? {
|
|
432
|
-
light: await resolveAssetUrl(config.logo.light ?? ""),
|
|
433
|
-
dark: config.logo.dark ? await resolveAssetUrl(config.logo.dark) : undefined,
|
|
434
|
-
href: config.logo.href,
|
|
435
|
-
}
|
|
436
|
-
: undefined;
|
|
437
|
-
const customCSS = await loadCustomCSS(config.theme.css);
|
|
438
|
-
return {
|
|
439
|
-
name: config.name,
|
|
440
|
-
theme: config.theme,
|
|
441
|
-
logo: logo?.light ? logo : undefined,
|
|
442
|
-
favicon: config.favicon ? await resolveAssetUrl(config.favicon) : undefined,
|
|
443
|
-
repo: config.repo,
|
|
444
|
-
editBranch: config.editBranch,
|
|
445
|
-
editBasePath: config.editBasePath,
|
|
446
|
-
codeSamples: config.codeSamples,
|
|
447
|
-
navbar: config.navbar,
|
|
448
|
-
footer: config.footer,
|
|
449
|
-
customCSS: customCSS || undefined,
|
|
450
|
-
};
|
|
451
|
-
}
|
|
452
|
-
async function loadCustomCSS(paths) {
|
|
453
|
-
const parts = [];
|
|
454
|
-
for (const p of paths) {
|
|
455
|
-
parts.push(await readFile(p, "utf-8"));
|
|
456
|
-
}
|
|
457
|
-
return parts.join("\n");
|
|
458
|
-
}
|
|
459
|
-
const MIME_TYPES = {
|
|
460
|
-
".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg",
|
|
461
|
-
".gif": "image/gif", ".svg": "image/svg+xml", ".webp": "image/webp",
|
|
462
|
-
".ico": "image/x-icon",
|
|
463
|
-
};
|
|
464
|
-
async function resolveAssetUrl(pathOrUrl) {
|
|
465
|
-
if (!pathOrUrl || pathOrUrl.startsWith("http://") || pathOrUrl.startsWith("https://") || pathOrUrl.startsWith("data:")) {
|
|
466
|
-
return pathOrUrl;
|
|
467
|
-
}
|
|
468
|
-
const abs = resolve(pathOrUrl);
|
|
469
|
-
const ext = extname(abs).toLowerCase();
|
|
470
|
-
const mime = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
471
|
-
const data = await readFile(abs);
|
|
472
|
-
return `data:${mime};base64,${data.toString("base64")}`;
|
|
473
|
-
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { NormalizedSpec } from "./core/types.js";
|
|
1
|
+
import type { ChangelogDiagnostic, NormalizedSpec } from "./core/types.js";
|
|
3
2
|
import type { ResolvedConfig } from "./config.js";
|
|
4
3
|
export interface BuildOptions {
|
|
5
4
|
specSource: string;
|
|
6
5
|
outputDir?: string;
|
|
7
6
|
embeddable?: boolean;
|
|
8
7
|
skipWrite?: boolean;
|
|
8
|
+
strictChangelog?: boolean;
|
|
9
9
|
}
|
|
10
10
|
export interface BuildResult {
|
|
11
11
|
spec: NormalizedSpec;
|
|
12
12
|
outputDir: string;
|
|
13
13
|
pageCount: number;
|
|
14
|
+
changelogDiagnostics: ChangelogDiagnostic[];
|
|
14
15
|
}
|
|
15
16
|
/**
|
|
16
17
|
* Build API documentation from a single OpenAPI/Swagger spec.
|
|
@@ -23,22 +24,17 @@ export interface SiteBuildOptions {
|
|
|
23
24
|
config?: ResolvedConfig;
|
|
24
25
|
skipWrite?: boolean;
|
|
25
26
|
embeddable?: boolean;
|
|
27
|
+
strictChangelog?: boolean;
|
|
26
28
|
}
|
|
27
29
|
export interface SiteBuildResult {
|
|
28
30
|
outputDir: string;
|
|
29
31
|
pageCount: number;
|
|
32
|
+
changelogDiagnostics: ChangelogDiagnostic[];
|
|
30
33
|
/** @internal specs by tab slug, for buildDocs compat */
|
|
31
34
|
_specs?: Map<string, NormalizedSpec>;
|
|
32
35
|
}
|
|
33
36
|
export declare function buildSiteDocs(options?: SiteBuildOptions): Promise<SiteBuildResult>;
|
|
34
|
-
/**
|
|
35
|
-
* Rewrite internal links in markdown page HTML to correct relative .html paths.
|
|
36
|
-
*
|
|
37
|
-
* Authors write links like [Page](/slug) or [Page](/tab/slug). This pass
|
|
38
|
-
* rewrites matching href values so they resolve on static file servers
|
|
39
|
-
* that don't support extensionless URLs.
|
|
40
|
-
*/
|
|
41
|
-
export declare function resolveInternalLinks(pages: SitePage[], config: ResolvedConfig): void;
|
|
42
37
|
export { defineConfig } from "./config.js";
|
|
38
|
+
export { resolveInternalLinks } from "./site-assembly.js";
|
|
43
39
|
export type { NormalizedSpec, NormalizedOperation, NormalizedTag, NormalizedSchema, NormalizedParameter, NormalizedRequestBody, NormalizedResponse, } from "./core/types.js";
|
|
44
40
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAA8B,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACvG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAkBlD,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;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,mBAAmB,EAAE,CAAC;CAC7C;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAkB3E;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;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,mBAAmB,EAAE,CAAC;IAC5C,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,CAwF5F;AAyED,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAG1D,YAAY,EACV,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC"}
|