sourcey 3.3.10 → 3.4.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 +19 -3
- package/dist/client/scroll-tracker.js +8 -1
- package/dist/client/search.js +26 -7
- package/dist/components/layout/Head.d.ts.map +1 -1
- package/dist/components/layout/Head.js +1 -1
- package/dist/components/layout/Header.d.ts.map +1 -1
- package/dist/components/layout/Header.js +2 -2
- package/dist/components/layout/Page.d.ts.map +1 -1
- package/dist/components/layout/Page.js +6 -5
- package/dist/components/layout/Sidebar.d.ts.map +1 -1
- package/dist/components/layout/Sidebar.js +11 -2
- package/dist/components/layout/TableOfContents.d.ts.map +1 -1
- package/dist/components/layout/TableOfContents.js +3 -2
- package/dist/components/mcp/AnnotationBadges.d.ts +15 -0
- package/dist/components/mcp/AnnotationBadges.d.ts.map +1 -0
- package/dist/components/mcp/AnnotationBadges.js +10 -0
- package/dist/components/mcp/McpConnection.d.ts +10 -0
- package/dist/components/mcp/McpConnection.d.ts.map +1 -0
- package/dist/components/mcp/McpConnection.js +32 -0
- package/dist/components/mcp/McpEndpointBar.d.ts +8 -0
- package/dist/components/mcp/McpEndpointBar.d.ts.map +1 -0
- package/dist/components/mcp/McpEndpointBar.js +16 -0
- package/dist/components/mcp/McpReturns.d.ts +18 -0
- package/dist/components/mcp/McpReturns.d.ts.map +1 -0
- package/dist/components/mcp/McpReturns.js +33 -0
- package/dist/components/openapi/Operation.d.ts.map +1 -1
- package/dist/components/openapi/Operation.js +5 -1
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +12 -3
- package/dist/core/markdown-loader.d.ts.map +1 -1
- package/dist/core/markdown-loader.js +7 -2
- package/dist/core/mcp-normalizer.d.ts +11 -0
- package/dist/core/mcp-normalizer.d.ts.map +1 -0
- package/dist/core/mcp-normalizer.js +382 -0
- package/dist/core/search-indexer.d.ts +3 -1
- package/dist/core/search-indexer.d.ts.map +1 -1
- package/dist/core/search-indexer.js +7 -3
- package/dist/core/types.d.ts +26 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/dev-server.d.ts.map +1 -1
- package/dist/dev-server.js +47 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -10
- package/dist/renderer/html-builder.d.ts +2 -0
- package/dist/renderer/html-builder.d.ts.map +1 -1
- package/dist/renderer/html-builder.js +15 -0
- package/dist/renderer/llms.d.ts +6 -0
- package/dist/renderer/llms.d.ts.map +1 -0
- package/dist/renderer/llms.js +247 -0
- package/dist/themes/default/main.css +3 -0
- package/dist/themes/default/sourcey.css +101 -23
- package/dist/utils/icons.d.ts +4 -0
- package/dist/utils/icons.d.ts.map +1 -1
- package/dist/utils/icons.js +6 -0
- package/dist/utils/markdown.d.ts.map +1 -1
- package/dist/utils/markdown.js +97 -1
- package/package.json +6 -2
package/dist/dev-server.js
CHANGED
|
@@ -7,6 +7,7 @@ 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
|
+
import { normalizeMcpSpec } from "./core/mcp-normalizer.js";
|
|
10
11
|
import { buildNavFromSpec, buildNavFromPages, buildSiteNavigation, withActivePage } from "./core/navigation.js";
|
|
11
12
|
import { loadMarkdownPage, slugFromPath } from "./core/markdown-loader.js";
|
|
12
13
|
import { loadDoxygenTab } from "./core/doxygen-loader.js";
|
|
@@ -40,6 +41,8 @@ export async function startDevServer(options) {
|
|
|
40
41
|
for (const tab of config.tabs) {
|
|
41
42
|
if (tab.openapi)
|
|
42
43
|
watchPaths.push(tab.openapi);
|
|
44
|
+
if (tab.mcp)
|
|
45
|
+
watchPaths.push(tab.mcp);
|
|
43
46
|
if (tab.doxygen)
|
|
44
47
|
watchPaths.push(tab.doxygen.xml);
|
|
45
48
|
if (tab.groups) {
|
|
@@ -57,6 +60,9 @@ export async function startDevServer(options) {
|
|
|
57
60
|
if (tab.openapi) {
|
|
58
61
|
map.set(resolve(tab.openapi), { kind: "openapi", tabSlug: tab.slug, specPath: tab.openapi });
|
|
59
62
|
}
|
|
63
|
+
if (tab.mcp) {
|
|
64
|
+
map.set(resolve(tab.mcp), { kind: "mcp", tabSlug: tab.slug, specPath: tab.mcp });
|
|
65
|
+
}
|
|
60
66
|
if (tab.doxygen) {
|
|
61
67
|
map.set(resolve(tab.doxygen.xml), { kind: "doxygen", tabSlug: tab.slug, xmlDir: tab.doxygen.xml });
|
|
62
68
|
}
|
|
@@ -183,6 +189,29 @@ export async function startDevServer(options) {
|
|
|
183
189
|
data.siteTabs[idx] = navTab;
|
|
184
190
|
}
|
|
185
191
|
}
|
|
192
|
+
else if (content.kind === "mcp") {
|
|
193
|
+
log(`reparsing mcp spec ${shortPath(content.specPath)}`);
|
|
194
|
+
const { parse } = await import("mcp-parser");
|
|
195
|
+
const mcpSpec = await parse(content.specPath);
|
|
196
|
+
const spec = normalizeMcpSpec(mcpSpec);
|
|
197
|
+
if (cache !== snapshot)
|
|
198
|
+
return;
|
|
199
|
+
data.specsBySlug.set(content.tabSlug, spec);
|
|
200
|
+
const pageKey = tabPath(content.tabSlug, "index.html");
|
|
201
|
+
const existing = data.pageMap.get(pageKey);
|
|
202
|
+
if (existing) {
|
|
203
|
+
existing.currentPage = { kind: "spec", spec };
|
|
204
|
+
existing.spec = spec;
|
|
205
|
+
}
|
|
206
|
+
const tab = config.tabs.find((t) => t.slug === content.tabSlug);
|
|
207
|
+
if (tab) {
|
|
208
|
+
const navTab = buildNavFromSpec(spec, tab.slug);
|
|
209
|
+
navTab.label = tab.label;
|
|
210
|
+
const idx = data.siteTabs.findIndex((t) => t.slug === content.tabSlug);
|
|
211
|
+
if (idx !== -1)
|
|
212
|
+
data.siteTabs[idx] = navTab;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
186
215
|
const ms = Math.round(performance.now() - start);
|
|
187
216
|
log(`updated \x1b[2m(${ms}ms)\x1b[0m`);
|
|
188
217
|
}
|
|
@@ -257,7 +286,7 @@ export async function startDevServer(options) {
|
|
|
257
286
|
markdownPagesByTab.set(tab.slug, tabPages);
|
|
258
287
|
}
|
|
259
288
|
}
|
|
260
|
-
return buildSearchIndex(specsBySlug, markdownPagesByTab, navigation);
|
|
289
|
+
return buildSearchIndex(specsBySlug, markdownPagesByTab, navigation, "/", config.search.featured);
|
|
261
290
|
}
|
|
262
291
|
const viteConfig = {
|
|
263
292
|
root: process.cwd(),
|
|
@@ -265,6 +294,9 @@ export async function startDevServer(options) {
|
|
|
265
294
|
port,
|
|
266
295
|
strictPort: true,
|
|
267
296
|
hmr: true,
|
|
297
|
+
fs: {
|
|
298
|
+
allow: [process.cwd(), projectRoot],
|
|
299
|
+
},
|
|
268
300
|
},
|
|
269
301
|
plugins: [
|
|
270
302
|
preact(),
|
|
@@ -330,20 +362,26 @@ async function loadSiteData(tabs) {
|
|
|
330
362
|
const siteTabs = [];
|
|
331
363
|
const pageMap = new Map();
|
|
332
364
|
for (const tab of tabs) {
|
|
333
|
-
if (
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
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
|
+
}
|
|
340
378
|
}
|
|
341
379
|
const primarySpec = specsBySlug.values().next().value ?? {
|
|
342
380
|
info: { title: "", version: "", description: "" },
|
|
343
381
|
servers: [], tags: [], operations: [], schemas: {}, securitySchemes: {}, webhooks: [],
|
|
344
382
|
};
|
|
345
383
|
for (const tab of tabs) {
|
|
346
|
-
if (tab.openapi) {
|
|
384
|
+
if (tab.openapi || tab.mcp) {
|
|
347
385
|
const spec = specsBySlug.get(tab.slug);
|
|
348
386
|
const navTab = buildNavFromSpec(spec, tab.slug);
|
|
349
387
|
navTab.label = tab.label;
|
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":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAe,MAAM,aAAa,CAAC;AAe/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,CAoH5F;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
|
@@ -4,6 +4,7 @@ import { loadSpec } from "./core/loader.js";
|
|
|
4
4
|
import { convertToOpenApi3 } from "./core/converter.js";
|
|
5
5
|
import { parseSpec } from "./core/parser.js";
|
|
6
6
|
import { normalizeSpec } from "./core/normalizer.js";
|
|
7
|
+
import { normalizeMcpSpec } from "./core/mcp-normalizer.js";
|
|
7
8
|
import { buildSite as buildSiteHtml } from "./renderer/html-builder.js";
|
|
8
9
|
import { tabPath } from "./config.js";
|
|
9
10
|
import { loadConfig, configFromSpec } from "./config.js";
|
|
@@ -11,6 +12,7 @@ import { loadMarkdownPage, slugFromPath } from "./core/markdown-loader.js";
|
|
|
11
12
|
import { loadDoxygenTab } from "./core/doxygen-loader.js";
|
|
12
13
|
import { buildNavFromSpec, buildNavFromPages, buildSiteNavigation } from "./core/navigation.js";
|
|
13
14
|
import { buildSearchIndex } from "./core/search-indexer.js";
|
|
15
|
+
import { generateLlmsTxt, generateLlmsFullTxt } from "./renderer/llms.js";
|
|
14
16
|
/**
|
|
15
17
|
* Build API documentation from a single OpenAPI/Swagger spec.
|
|
16
18
|
* Wraps the spec in a single-tab site and renders through the modern layout.
|
|
@@ -33,15 +35,21 @@ export async function buildSiteDocs(options = {}) {
|
|
|
33
35
|
const sitePages = [];
|
|
34
36
|
const siteTabs = [];
|
|
35
37
|
const specsBySlug = new Map();
|
|
36
|
-
// Load all specs
|
|
38
|
+
// Load all specs (OpenAPI and MCP)
|
|
37
39
|
for (const tab of tabs) {
|
|
38
|
-
if (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
if (tab.openapi) {
|
|
41
|
+
const loaded = await loadSpec(tab.openapi);
|
|
42
|
+
const parsed = await parseSpec(loaded);
|
|
43
|
+
const openapi3 = await convertToOpenApi3(parsed);
|
|
44
|
+
const spec = normalizeSpec(openapi3);
|
|
45
|
+
specsBySlug.set(tab.slug, spec);
|
|
46
|
+
}
|
|
47
|
+
else if (tab.mcp) {
|
|
48
|
+
const { parse } = await import("mcp-parser");
|
|
49
|
+
const mcpSpec = await parse(tab.mcp);
|
|
50
|
+
const spec = normalizeMcpSpec(mcpSpec);
|
|
51
|
+
specsBySlug.set(tab.slug, spec);
|
|
52
|
+
}
|
|
45
53
|
}
|
|
46
54
|
// Primary spec for SpecContext on markdown pages
|
|
47
55
|
const primarySpec = specsBySlug.values().next().value ?? createMinimalSpec();
|
|
@@ -49,7 +57,7 @@ export async function buildSiteDocs(options = {}) {
|
|
|
49
57
|
const site = await buildSiteConfig(config);
|
|
50
58
|
// Process all tabs
|
|
51
59
|
for (const tab of tabs) {
|
|
52
|
-
if (tab.openapi) {
|
|
60
|
+
if (tab.openapi || tab.mcp) {
|
|
53
61
|
const spec = specsBySlug.get(tab.slug);
|
|
54
62
|
const navTab = buildNavFromSpec(spec, tab.slug);
|
|
55
63
|
navTab.label = tab.label;
|
|
@@ -110,10 +118,14 @@ export async function buildSiteDocs(options = {}) {
|
|
|
110
118
|
markdownPagesByTab.set(tab.slug, tabPages);
|
|
111
119
|
}
|
|
112
120
|
}
|
|
113
|
-
const searchIndex = buildSearchIndex(specsBySlug, markdownPagesByTab, navigation);
|
|
121
|
+
const searchIndex = buildSearchIndex(specsBySlug, markdownPagesByTab, navigation, "/", config.search.featured);
|
|
122
|
+
const llmsTxt = generateLlmsTxt(sitePages, navigation, site);
|
|
123
|
+
const llmsFullTxt = generateLlmsFullTxt(sitePages, navigation, site);
|
|
114
124
|
if (!options.skipWrite) {
|
|
115
125
|
await buildSiteHtml(sitePages, navigation, outputDir, site, {
|
|
116
126
|
searchIndex,
|
|
127
|
+
llmsTxt,
|
|
128
|
+
llmsFullTxt,
|
|
117
129
|
embeddable: options.embeddable,
|
|
118
130
|
});
|
|
119
131
|
}
|
|
@@ -18,5 +18,7 @@ export interface SitePage {
|
|
|
18
18
|
export declare function buildSite(pages: SitePage[], navigation: SiteNavigation, outputDir: string, site: SiteConfig, options?: {
|
|
19
19
|
embeddable?: boolean;
|
|
20
20
|
searchIndex?: string;
|
|
21
|
+
llmsTxt?: string;
|
|
22
|
+
llmsFullTxt?: string;
|
|
21
23
|
}): Promise<BuildOutput>;
|
|
22
24
|
//# sourceMappingURL=html-builder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-builder.d.ts","sourceRoot":"","sources":["../../src/renderer/html-builder.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAiB,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AA0B5D,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,KAAK,EAAE,QAAQ,EAAE,EACjB,UAAU,EAAE,cAAc,EAC1B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,UAAU,EAChB,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"html-builder.d.ts","sourceRoot":"","sources":["../../src/renderer/html-builder.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAiB,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AA0B5D,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,KAAK,EAAE,QAAQ,EAAE,EACjB,UAAU,EAAE,cAAc,EAC1B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,UAAU,EAChB,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/F,OAAO,CAAC,WAAW,CAAC,CAsDtB"}
|
|
@@ -60,6 +60,21 @@ export async function buildSite(pages, navigation, outputDir, site, options) {
|
|
|
60
60
|
if (options?.searchIndex) {
|
|
61
61
|
await writeFile(resolve(resolvedDir, "search-index.json"), options.searchIndex, "utf-8");
|
|
62
62
|
}
|
|
63
|
+
if (options?.llmsTxt) {
|
|
64
|
+
await writeFile(resolve(resolvedDir, "llms.txt"), options.llmsTxt, "utf-8");
|
|
65
|
+
}
|
|
66
|
+
if (options?.llmsFullTxt) {
|
|
67
|
+
await writeFile(resolve(resolvedDir, "llms-full.txt"), options.llmsFullTxt, "utf-8");
|
|
68
|
+
}
|
|
69
|
+
const urls = pages.map(p => ` <url><loc>${p.outputPath}</loc></url>`);
|
|
70
|
+
const sitemap = [
|
|
71
|
+
`<?xml version="1.0" encoding="UTF-8"?>`,
|
|
72
|
+
`<!-- Generated by Sourcey https://sourcey.com -->`,
|
|
73
|
+
`<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">`,
|
|
74
|
+
...urls,
|
|
75
|
+
`</urlset>`,
|
|
76
|
+
].join("\n");
|
|
77
|
+
await writeFile(resolve(resolvedDir, "sitemap.xml"), sitemap, "utf-8");
|
|
63
78
|
return { htmlPath: resolve(resolvedDir, "index.html"), outputDir: resolvedDir };
|
|
64
79
|
}
|
|
65
80
|
/**
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SiteNavigation } from "../core/navigation.js";
|
|
2
|
+
import type { SiteConfig } from "./context.js";
|
|
3
|
+
import type { SitePage } from "./html-builder.js";
|
|
4
|
+
export declare function generateLlmsTxt(pages: SitePage[], navigation: SiteNavigation, site: SiteConfig): string;
|
|
5
|
+
export declare function generateLlmsFullTxt(pages: SitePage[], navigation: SiteNavigation, site: SiteConfig): string;
|
|
6
|
+
//# sourceMappingURL=llms.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llms.d.ts","sourceRoot":"","sources":["../../src/renderer/llms.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,QAAQ,EAAE,EACjB,UAAU,EAAE,cAAc,EAC1B,IAAI,EAAE,UAAU,GACf,MAAM,CA4CR;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,QAAQ,EAAE,EACjB,UAAU,EAAE,cAAc,EAC1B,IAAI,EAAE,UAAU,GACf,MAAM,CA8BR"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { htmlId } from "../utils/html-id.js";
|
|
2
|
+
export function generateLlmsTxt(pages, navigation, site) {
|
|
3
|
+
const lines = [];
|
|
4
|
+
const title = resolveSiteTitle(pages, site);
|
|
5
|
+
const summary = resolveSiteSummary(pages, site);
|
|
6
|
+
lines.push(`# ${title}`);
|
|
7
|
+
lines.push("");
|
|
8
|
+
if (summary) {
|
|
9
|
+
lines.push(`> ${firstLine(summary)}`);
|
|
10
|
+
lines.push("");
|
|
11
|
+
}
|
|
12
|
+
for (const tab of navigation.tabs) {
|
|
13
|
+
const tabPages = pages.filter((page) => page.tabSlug === tab.slug);
|
|
14
|
+
if (!tabPages.length)
|
|
15
|
+
continue;
|
|
16
|
+
lines.push(`## ${tab.label}`);
|
|
17
|
+
lines.push("");
|
|
18
|
+
for (const page of tabPages) {
|
|
19
|
+
if (page.currentPage.kind === "markdown" && page.currentPage.markdown) {
|
|
20
|
+
const doc = page.currentPage.markdown;
|
|
21
|
+
const desc = doc.description || excerpt(stripHtml(doc.html));
|
|
22
|
+
lines.push(`- [${doc.title}](${page.outputPath})${desc ? `: ${desc}` : ""}`);
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const spec = page.currentPage.spec ?? page.spec;
|
|
26
|
+
const overview = spec.info.description ? firstLine(spec.info.description) : `${spec.operations.length} documented operations`;
|
|
27
|
+
lines.push(`- [${spec.info.title}](${page.outputPath})${overview ? `: ${overview}` : ""}`);
|
|
28
|
+
for (const op of spec.operations) {
|
|
29
|
+
if (op.hidden)
|
|
30
|
+
continue;
|
|
31
|
+
const opLabel = op.summary ?? operationDisplayName(op);
|
|
32
|
+
const opSummary = [operationKind(op), firstLine(op.description)].filter(Boolean).join(" — ");
|
|
33
|
+
lines.push(`- [${opLabel}](${page.outputPath}#${operationAnchor(op)})${opSummary ? `: ${opSummary}` : ""}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
lines.push("");
|
|
37
|
+
}
|
|
38
|
+
return lines.join("\n");
|
|
39
|
+
}
|
|
40
|
+
export function generateLlmsFullTxt(pages, navigation, site) {
|
|
41
|
+
const lines = [];
|
|
42
|
+
const title = resolveSiteTitle(pages, site);
|
|
43
|
+
const summary = resolveSiteSummary(pages, site);
|
|
44
|
+
lines.push(`# ${title}`);
|
|
45
|
+
lines.push("");
|
|
46
|
+
if (summary) {
|
|
47
|
+
lines.push(summary);
|
|
48
|
+
lines.push("");
|
|
49
|
+
}
|
|
50
|
+
for (const tab of navigation.tabs) {
|
|
51
|
+
const tabPages = pages.filter((page) => page.tabSlug === tab.slug);
|
|
52
|
+
if (!tabPages.length)
|
|
53
|
+
continue;
|
|
54
|
+
lines.push(`## ${tab.label}`);
|
|
55
|
+
lines.push("");
|
|
56
|
+
for (const page of tabPages) {
|
|
57
|
+
if (page.currentPage.kind === "markdown" && page.currentPage.markdown) {
|
|
58
|
+
appendMarkdownPage(lines, page);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
appendSpecPage(lines, page);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return lines.join("\n");
|
|
66
|
+
}
|
|
67
|
+
function appendMarkdownPage(lines, page) {
|
|
68
|
+
const doc = page.currentPage.markdown;
|
|
69
|
+
lines.push(`### ${doc.title}`);
|
|
70
|
+
lines.push("");
|
|
71
|
+
lines.push(`Path: \`${page.outputPath}\``);
|
|
72
|
+
lines.push("");
|
|
73
|
+
if (doc.description) {
|
|
74
|
+
lines.push(doc.description);
|
|
75
|
+
lines.push("");
|
|
76
|
+
}
|
|
77
|
+
const body = stripHtml(doc.html);
|
|
78
|
+
if (body) {
|
|
79
|
+
lines.push(body);
|
|
80
|
+
lines.push("");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function appendSpecPage(lines, page) {
|
|
84
|
+
const spec = page.currentPage.spec ?? page.spec;
|
|
85
|
+
lines.push(`### ${spec.info.title}`);
|
|
86
|
+
lines.push("");
|
|
87
|
+
lines.push(`Path: \`${page.outputPath}\``);
|
|
88
|
+
if (spec.info.version) {
|
|
89
|
+
lines.push(`Version: ${spec.info.version}`);
|
|
90
|
+
}
|
|
91
|
+
lines.push("");
|
|
92
|
+
if (spec.info.description) {
|
|
93
|
+
lines.push(spec.info.description);
|
|
94
|
+
lines.push("");
|
|
95
|
+
}
|
|
96
|
+
if (spec.operations.length) {
|
|
97
|
+
lines.push("#### Operations");
|
|
98
|
+
lines.push("");
|
|
99
|
+
for (const op of spec.operations) {
|
|
100
|
+
if (op.hidden)
|
|
101
|
+
continue;
|
|
102
|
+
appendOperation(lines, op);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const schemas = Object.entries(spec.schemas);
|
|
106
|
+
if (schemas.length) {
|
|
107
|
+
lines.push("#### Models");
|
|
108
|
+
lines.push("");
|
|
109
|
+
for (const [name, schema] of schemas) {
|
|
110
|
+
const desc = schema.description ? `: ${schema.description}` : "";
|
|
111
|
+
lines.push(`- ${name}${desc}`);
|
|
112
|
+
}
|
|
113
|
+
lines.push("");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function appendOperation(lines, op) {
|
|
117
|
+
lines.push(`##### ${operationDisplayName(op)}`);
|
|
118
|
+
lines.push("");
|
|
119
|
+
if (op.summary && op.summary !== operationDisplayName(op)) {
|
|
120
|
+
lines.push(`Summary: ${op.summary}`);
|
|
121
|
+
lines.push("");
|
|
122
|
+
}
|
|
123
|
+
if (op.description) {
|
|
124
|
+
lines.push(op.description);
|
|
125
|
+
lines.push("");
|
|
126
|
+
}
|
|
127
|
+
if (op.parameters.length) {
|
|
128
|
+
lines.push("Parameters:");
|
|
129
|
+
for (const param of op.parameters) {
|
|
130
|
+
const req = param.required ? "required" : "optional";
|
|
131
|
+
const type = param.schema ? formatSchemaType(param.schema) : "unknown";
|
|
132
|
+
const desc = param.description ? ` — ${firstLine(param.description)}` : "";
|
|
133
|
+
lines.push(`- \`${param.name}\` (${param.in}, ${type}, ${req})${desc}`);
|
|
134
|
+
}
|
|
135
|
+
lines.push("");
|
|
136
|
+
}
|
|
137
|
+
if (op.requestBody) {
|
|
138
|
+
const mediaTypes = Object.keys(op.requestBody.content);
|
|
139
|
+
if (mediaTypes.length) {
|
|
140
|
+
lines.push(`Request body: ${mediaTypes.join(", ")}`);
|
|
141
|
+
lines.push("");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (op.mcpExtras?.outputSchema) {
|
|
145
|
+
lines.push("Returns:");
|
|
146
|
+
lines.push("```json");
|
|
147
|
+
lines.push(JSON.stringify(op.mcpExtras.outputSchema, null, 2));
|
|
148
|
+
lines.push("```");
|
|
149
|
+
lines.push("");
|
|
150
|
+
}
|
|
151
|
+
else if (op.responses.length) {
|
|
152
|
+
lines.push("Responses:");
|
|
153
|
+
for (const response of op.responses) {
|
|
154
|
+
lines.push(`- ${formatResponse(response)}`);
|
|
155
|
+
}
|
|
156
|
+
lines.push("");
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function resolveSiteTitle(pages, site) {
|
|
160
|
+
if (site.name && site.name !== "API Reference")
|
|
161
|
+
return site.name;
|
|
162
|
+
const specPages = pages.filter((page) => page.currentPage.kind === "spec");
|
|
163
|
+
if (specPages.length === 1) {
|
|
164
|
+
const spec = specPages[0].currentPage.spec ?? specPages[0].spec;
|
|
165
|
+
if (spec.info.title)
|
|
166
|
+
return spec.info.title;
|
|
167
|
+
}
|
|
168
|
+
const firstMarkdown = pages.find((page) => page.currentPage.kind === "markdown" && page.currentPage.markdown);
|
|
169
|
+
if (firstMarkdown?.currentPage.markdown?.title)
|
|
170
|
+
return firstMarkdown.currentPage.markdown.title;
|
|
171
|
+
return site.name || "Documentation";
|
|
172
|
+
}
|
|
173
|
+
function resolveSiteSummary(pages, site) {
|
|
174
|
+
const firstMarkdown = pages.find((page) => page.currentPage.kind === "markdown" && page.currentPage.markdown?.description);
|
|
175
|
+
if (firstMarkdown?.currentPage.markdown?.description)
|
|
176
|
+
return firstMarkdown.currentPage.markdown.description;
|
|
177
|
+
const firstSpec = pages.find((page) => page.currentPage.kind === "spec");
|
|
178
|
+
const spec = firstSpec ? (firstSpec.currentPage.spec ?? firstSpec.spec) : undefined;
|
|
179
|
+
if (spec?.info.description)
|
|
180
|
+
return spec.info.description;
|
|
181
|
+
return site.name ? `${site.name} documentation generated by Sourcey.` : undefined;
|
|
182
|
+
}
|
|
183
|
+
function operationDisplayName(op) {
|
|
184
|
+
if (op.mcpExtras?.type === "tool")
|
|
185
|
+
return `TOOL ${op.path}`;
|
|
186
|
+
if (op.mcpExtras?.type === "resource")
|
|
187
|
+
return `RESOURCE ${op.path}`;
|
|
188
|
+
if (op.mcpExtras?.type === "prompt")
|
|
189
|
+
return `PROMPT ${op.path}`;
|
|
190
|
+
return `${op.method.toUpperCase()} ${op.path}`;
|
|
191
|
+
}
|
|
192
|
+
function operationKind(op) {
|
|
193
|
+
if (op.mcpExtras?.type === "tool")
|
|
194
|
+
return "tool";
|
|
195
|
+
if (op.mcpExtras?.type === "resource")
|
|
196
|
+
return "resource";
|
|
197
|
+
if (op.mcpExtras?.type === "prompt")
|
|
198
|
+
return "prompt";
|
|
199
|
+
return `${op.method.toUpperCase()} ${op.path}`;
|
|
200
|
+
}
|
|
201
|
+
function operationAnchor(op) {
|
|
202
|
+
return `operation-${htmlId(op.path)}-${htmlId(op.method)}`;
|
|
203
|
+
}
|
|
204
|
+
function formatResponse(response) {
|
|
205
|
+
const desc = response.description ? firstLine(response.description) : "";
|
|
206
|
+
return desc ? `${response.statusCode}: ${desc}` : response.statusCode;
|
|
207
|
+
}
|
|
208
|
+
function formatSchemaType(schema) {
|
|
209
|
+
if (Array.isArray(schema.type))
|
|
210
|
+
return schema.type.join(" | ");
|
|
211
|
+
if (schema.type)
|
|
212
|
+
return schema.type;
|
|
213
|
+
if (schema.oneOf?.length)
|
|
214
|
+
return schema.oneOf.map(formatSchemaType).join(" | ");
|
|
215
|
+
if (schema.anyOf?.length)
|
|
216
|
+
return schema.anyOf.map(formatSchemaType).join(" | ");
|
|
217
|
+
if (schema.allOf?.length)
|
|
218
|
+
return "object";
|
|
219
|
+
if (schema.properties)
|
|
220
|
+
return "object";
|
|
221
|
+
return "unknown";
|
|
222
|
+
}
|
|
223
|
+
function stripHtml(html) {
|
|
224
|
+
return decodeEntities(html)
|
|
225
|
+
.replace(/<pre[\s\S]*?<\/pre>/gi, (match) => match.replace(/<[^>]+>/g, " "))
|
|
226
|
+
.replace(/<code[\s\S]*?<\/code>/gi, (match) => match.replace(/<[^>]+>/g, " "))
|
|
227
|
+
.replace(/<[^>]+>/g, " ")
|
|
228
|
+
.replace(/\s+/g, " ")
|
|
229
|
+
.trim();
|
|
230
|
+
}
|
|
231
|
+
function decodeEntities(text) {
|
|
232
|
+
return text
|
|
233
|
+
.replace(/ /g, " ")
|
|
234
|
+
.replace(/&/g, "&")
|
|
235
|
+
.replace(/</g, "<")
|
|
236
|
+
.replace(/>/g, ">")
|
|
237
|
+
.replace(/"/g, "\"")
|
|
238
|
+
.replace(/'/g, "'");
|
|
239
|
+
}
|
|
240
|
+
function excerpt(text, max = 140) {
|
|
241
|
+
if (text.length <= max)
|
|
242
|
+
return text;
|
|
243
|
+
return `${text.slice(0, max - 1).trimEnd()}…`;
|
|
244
|
+
}
|
|
245
|
+
function firstLine(text) {
|
|
246
|
+
return text?.split("\n").map((line) => line.trim()).find(Boolean) ?? "";
|
|
247
|
+
}
|
|
@@ -65,6 +65,9 @@
|
|
|
65
65
|
--method-put: #d97706;
|
|
66
66
|
--method-delete: #dc2626;
|
|
67
67
|
--method-patch: #9333ea;
|
|
68
|
+
--method-tool: #9333ea;
|
|
69
|
+
--method-resource: #16a34a;
|
|
70
|
+
--method-prompt: #2563eb;
|
|
68
71
|
|
|
69
72
|
/* Typography */
|
|
70
73
|
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
|