sourcey 3.5.10 → 3.6.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 +24 -97
- package/dist/adapters/index.d.ts +12 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +130 -0
- package/dist/adapters/mkdocs.d.ts +5 -0
- package/dist/adapters/mkdocs.d.ts.map +1 -0
- package/dist/adapters/mkdocs.js +367 -0
- package/dist/adapters/shared.d.ts +12 -0
- package/dist/adapters/shared.d.ts.map +1 -0
- package/dist/adapters/shared.js +134 -0
- package/dist/adapters/types.d.ts +74 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +1 -0
- package/dist/cli.js +28 -34
- package/dist/client/search.js +213 -82
- package/dist/client/tabs.js +23 -0
- package/dist/components/layout/Head.js +17 -4
- package/dist/components/layout/TableOfContents.d.ts.map +1 -1
- package/dist/components/layout/TableOfContents.js +4 -2
- package/dist/components/openapi/Introduction.d.ts.map +1 -1
- package/dist/components/openapi/Introduction.js +16 -1
- package/dist/components/openapi/Security.d.ts.map +1 -1
- package/dist/components/openapi/Security.js +18 -2
- package/dist/config.d.ts +101 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +95 -143
- package/dist/core/api-rendering.d.ts +47 -0
- package/dist/core/api-rendering.d.ts.map +1 -0
- package/dist/core/api-rendering.js +76 -0
- package/dist/core/doxygen-loader.d.ts.map +1 -1
- package/dist/core/doxygen-loader.js +36 -17
- package/dist/core/godoc-loader.d.ts.map +1 -1
- package/dist/core/godoc-loader.js +17 -6
- package/dist/core/markdown-loader.d.ts +14 -0
- package/dist/core/markdown-loader.d.ts.map +1 -1
- package/dist/core/markdown-loader.js +70 -26
- package/dist/core/mcp-normalizer.d.ts.map +1 -1
- package/dist/core/mcp-normalizer.js +48 -34
- package/dist/core/navigation.d.ts.map +1 -1
- package/dist/core/navigation.js +8 -7
- package/dist/core/parser.d.ts.map +1 -1
- package/dist/core/parser.js +75 -4
- package/dist/core/rustdoc-introspector.d.ts +29 -0
- package/dist/core/rustdoc-introspector.d.ts.map +1 -0
- package/dist/core/rustdoc-introspector.js +236 -0
- package/dist/core/rustdoc-loader.d.ts +25 -0
- package/dist/core/rustdoc-loader.d.ts.map +1 -0
- package/dist/core/rustdoc-loader.js +469 -0
- package/dist/core/rustdoc-render.d.ts +76 -0
- package/dist/core/rustdoc-render.d.ts.map +1 -0
- package/dist/core/rustdoc-render.js +785 -0
- package/dist/core/rustdoc-types.d.ts +314 -0
- package/dist/core/rustdoc-types.d.ts.map +1 -0
- package/dist/core/rustdoc-types.js +18 -0
- package/dist/core/search-indexer.d.ts +10 -0
- package/dist/core/search-indexer.d.ts.map +1 -1
- package/dist/core/search-indexer.js +6 -1
- package/dist/core/sourcey-rustdoc/Cargo.lock +705 -0
- package/dist/core/sourcey-rustdoc/Cargo.toml +38 -0
- package/dist/core/sourcey-rustdoc/README.md +59 -0
- package/dist/core/sourcey-rustdoc/src/diagnostics.rs +42 -0
- package/dist/core/sourcey-rustdoc/src/doctest.rs +268 -0
- package/dist/core/sourcey-rustdoc/src/extract.rs +492 -0
- package/dist/core/sourcey-rustdoc/src/lib.rs +58 -0
- package/dist/core/sourcey-rustdoc/src/links.rs +126 -0
- package/dist/core/sourcey-rustdoc/src/main.rs +256 -0
- package/dist/core/sourcey-rustdoc/src/signature.rs +415 -0
- package/dist/core/sourcey-rustdoc/src/spec.rs +390 -0
- package/dist/core/sourcey-rustdoc/tests/format_version.rs +45 -0
- package/dist/dev-server.d.ts.map +1 -1
- package/dist/dev-server.js +109 -33
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -14
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +21 -16
- package/dist/renderer/changelog-feed.d.ts.map +1 -1
- package/dist/renderer/changelog-feed.js +27 -19
- package/dist/renderer/html-builder.d.ts.map +1 -1
- package/dist/renderer/html-builder.js +4 -3
- package/dist/renderer/llms.js +57 -2
- package/dist/site-assembly.d.ts +5 -0
- package/dist/site-assembly.d.ts.map +1 -1
- package/dist/site-assembly.js +161 -25
- package/dist/themes/default/sourcey.css +300 -0
- package/dist/utils/code-samples.d.ts +1 -0
- package/dist/utils/code-samples.d.ts.map +1 -1
- package/dist/utils/code-samples.js +30 -22
- package/dist/utils/html.d.ts +10 -0
- package/dist/utils/html.d.ts.map +1 -0
- package/dist/utils/html.js +152 -0
- package/dist/utils/http.d.ts +0 -2
- package/dist/utils/http.d.ts.map +1 -1
- package/dist/utils/http.js +19 -34
- package/dist/utils/markdown.d.ts.map +1 -1
- package/dist/utils/markdown.js +115 -39
- package/dist/vite-plugin.d.ts +2 -0
- package/dist/vite-plugin.d.ts.map +1 -1
- package/dist/vite-plugin.js +71 -1
- package/package.json +11 -5
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared API-documentation rendering primitives.
|
|
3
|
+
*
|
|
4
|
+
* Introduced by the rustdoc adapter and designed to be reusable by the godoc
|
|
5
|
+
* and doxygen adapters in a follow-on retrofit. Class names mirror rustdoc's
|
|
6
|
+
* DOM so deep-links from a rustdoc URL line up with sourcey output.
|
|
7
|
+
*/
|
|
8
|
+
import { escapeAttr as sharedEscapeAttr, escapeHtml as sharedEscapeHtml } from "../utils/html.js";
|
|
9
|
+
export function apiStabilityCallout(input) {
|
|
10
|
+
switch (input.kind) {
|
|
11
|
+
case "unstable": {
|
|
12
|
+
const issue = input.issueId
|
|
13
|
+
? ` (<a href="${escapeAttr((input.issueBaseUrl ?? "https://github.com/rust-lang/rust/issues/") +
|
|
14
|
+
String(input.issueId))}">#${input.issueId}</a>)`
|
|
15
|
+
: "";
|
|
16
|
+
const feature = input.featureName ? ` <code>${escapeHtml(input.featureName)}</code>` : "";
|
|
17
|
+
return `<div class="stab unstable api-stab api-stab-unstable">🔬 This is a nightly-only experimental API.${feature}${issue}</div>`;
|
|
18
|
+
}
|
|
19
|
+
case "deprecated": {
|
|
20
|
+
const since = input.since ? ` since ${escapeHtml(input.since)}` : "";
|
|
21
|
+
const reason = input.reason ? `: ${escapeHtml(input.reason)}` : "";
|
|
22
|
+
return `<div class="stab deprecated api-stab api-stab-deprecated">👎 Deprecated${since}${reason}</div>`;
|
|
23
|
+
}
|
|
24
|
+
case "portability": {
|
|
25
|
+
const feature = input.featureName
|
|
26
|
+
? ` crate feature <code>${escapeHtml(input.featureName)}</code>`
|
|
27
|
+
: "";
|
|
28
|
+
return `<div class="stab portability api-stab api-stab-portability">Available on${feature} only.</div>`;
|
|
29
|
+
}
|
|
30
|
+
case "non_exhaustive":
|
|
31
|
+
return `<div class="stab api-stab api-stab-non-exhaustive">This is marked <code>#[non_exhaustive]</code>; new variants or fields may be added in future versions.</div>`;
|
|
32
|
+
case "must_use": {
|
|
33
|
+
const reason = input.reason ? `: ${escapeHtml(input.reason)}` : "";
|
|
34
|
+
return `<div class="stab api-stab api-stab-must-use"><code>#[must_use]</code>${reason}</div>`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function apiItemInfoRow(input) {
|
|
39
|
+
const parts = [];
|
|
40
|
+
if (input.since) {
|
|
41
|
+
parts.push(`<span class="since api-since">${escapeHtml(input.since)}</span>`);
|
|
42
|
+
}
|
|
43
|
+
if (input.sourceHref) {
|
|
44
|
+
parts.push(`<a class="srclink api-srclink" href="${escapeAttr(input.sourceHref)}">${escapeHtml(input.sourceLabel ?? "Source")}</a>`);
|
|
45
|
+
}
|
|
46
|
+
if (parts.length === 0)
|
|
47
|
+
return "";
|
|
48
|
+
return `<div class="rightside api-rightside">${parts.join(" · ")}</div>`;
|
|
49
|
+
}
|
|
50
|
+
export function apiSymbolLink(input) {
|
|
51
|
+
const title = input.title ? ` title="${escapeAttr(input.title)}"` : "";
|
|
52
|
+
return `<a class="${escapeAttr(input.kind)} api-symbol-link"${title} href="${escapeAttr(input.href)}">${escapeHtml(input.text)}</a>`;
|
|
53
|
+
}
|
|
54
|
+
export function apiImplToggle(input) {
|
|
55
|
+
return apiToggle({
|
|
56
|
+
...input,
|
|
57
|
+
cssClass: "api-toggle api-impl-toggle",
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function apiToggle(input) {
|
|
61
|
+
const openAttr = input.open === false ? "" : " open";
|
|
62
|
+
return `<details class="${escapeAttr(input.cssClass)}"${openAttr}><summary class="api-toggle-summary">${input.summary}</summary><div class="api-toggle-body">${input.body}</div></details>`;
|
|
63
|
+
}
|
|
64
|
+
export function apiSectionAnchor(input) {
|
|
65
|
+
const cls = input.className ? ` ${input.className}` : "";
|
|
66
|
+
return (`<h${input.level} id="${escapeAttr(input.id)}" class="section-header api-section-header${cls}">` +
|
|
67
|
+
`${escapeHtml(input.text)}` +
|
|
68
|
+
` <a class="anchor api-anchor" href="#${escapeAttr(input.id)}">§</a>` +
|
|
69
|
+
`</h${input.level}>`);
|
|
70
|
+
}
|
|
71
|
+
export function escapeHtml(value) {
|
|
72
|
+
return sharedEscapeHtml(value);
|
|
73
|
+
}
|
|
74
|
+
export function escapeAttr(value) {
|
|
75
|
+
return sharedEscapeAttr(value);
|
|
76
|
+
}
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AAO7E,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,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMzF;AAED,wBAAgB,kCAAkC,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAoB9E;AAED,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOxE;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOhE;AAED,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAoBrE;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,aAAa,CAAC,CA4GxB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { generate } from "moxygen";
|
|
2
|
-
import { renderMarkdown, extractHeadings, extractFirstParagraph, stripMarkdownLinks } from "../utils/markdown.js";
|
|
2
|
+
import { renderMarkdown, extractHeadings, extractFirstParagraph, stripMarkdownLinks, } from "../utils/markdown.js";
|
|
3
3
|
export function normalizeDoxygenDescription(description, markdown) {
|
|
4
4
|
if (!description)
|
|
5
5
|
return "";
|
|
@@ -35,9 +35,7 @@ export function rewriteGeneratedDoxygenHref(href) {
|
|
|
35
35
|
const [path, hash] = href.split("#", 2);
|
|
36
36
|
if (!path.startsWith("api_") || !path.endsWith(".md"))
|
|
37
37
|
return href;
|
|
38
|
-
const slug = path
|
|
39
|
-
.slice("api_".length, -".md".length)
|
|
40
|
-
.replace(/--/g, "-");
|
|
38
|
+
const slug = path.slice("api_".length, -".md".length).replace(/--/g, "-");
|
|
41
39
|
return `${slug}.html${hash ? `#${hash}` : ""}`;
|
|
42
40
|
}
|
|
43
41
|
export function rewriteGeneratedDoxygenHtmlLinks(html) {
|
|
@@ -56,11 +54,19 @@ export function rewriteGeneratedDoxygenHtmlLinks(html) {
|
|
|
56
54
|
});
|
|
57
55
|
}
|
|
58
56
|
export async function loadDoxygenTab(config, tabSlug, tabLabel) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
57
|
+
let generated;
|
|
58
|
+
try {
|
|
59
|
+
generated = await generate({
|
|
60
|
+
directory: config.xml,
|
|
61
|
+
language: config.language,
|
|
62
|
+
sourceUrl: config.sourceUrl,
|
|
63
|
+
quiet: true,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
68
|
+
throw new Error(`Failed to load Doxygen XML from ${config.xml}: ${message}`);
|
|
69
|
+
}
|
|
64
70
|
const pages = new Map();
|
|
65
71
|
const groupMap = new Map();
|
|
66
72
|
for (const page of generated) {
|
|
@@ -79,6 +85,7 @@ export async function loadDoxygenTab(config, tabSlug, tabLabel) {
|
|
|
79
85
|
headings,
|
|
80
86
|
sourcePath: `api/${page.slug}.md`,
|
|
81
87
|
editPath: page.kind === "group" ? `api/${page.slug}.md` : null,
|
|
88
|
+
searchEntries: page.searchEntries,
|
|
82
89
|
});
|
|
83
90
|
// Group by the last segment of namespace (e.g. "icy::http" -> "http")
|
|
84
91
|
const groupKey = page.module ?? lastSegment(page.namespace) ?? "API";
|
|
@@ -198,7 +205,9 @@ function buildRichIndex(groupMap, pages) {
|
|
|
198
205
|
cards.push(`<a href="${href}" class="card-item">` +
|
|
199
206
|
`<div class="card-item-inner">` +
|
|
200
207
|
`<h3 class="card-item-title">${escHtml(page.title)}</h3>` +
|
|
201
|
-
(desc
|
|
208
|
+
(desc
|
|
209
|
+
? `<div class="card-item-content"><p>${escHtml(desc)}</p>${meta}</div>`
|
|
210
|
+
: `<div class="card-item-content">${meta}</div>`) +
|
|
202
211
|
`</div></a>`);
|
|
203
212
|
}
|
|
204
213
|
// Also include groups without a group page (orphan namespaces)
|
|
@@ -278,15 +287,25 @@ function lastSegment(name) {
|
|
|
278
287
|
return parts[parts.length - 1] || name;
|
|
279
288
|
}
|
|
280
289
|
function escHtml(s) {
|
|
281
|
-
return s
|
|
290
|
+
return s
|
|
291
|
+
.replace(/&/g, "&")
|
|
292
|
+
.replace(/</g, "<")
|
|
293
|
+
.replace(/>/g, ">")
|
|
294
|
+
.replace(/"/g, """);
|
|
282
295
|
}
|
|
283
296
|
function kindLabel(kind) {
|
|
284
297
|
switch (kind) {
|
|
285
|
-
case "class":
|
|
286
|
-
|
|
287
|
-
case "
|
|
288
|
-
|
|
289
|
-
case "
|
|
290
|
-
|
|
298
|
+
case "class":
|
|
299
|
+
return "Classes";
|
|
300
|
+
case "struct":
|
|
301
|
+
return "Structs";
|
|
302
|
+
case "enum":
|
|
303
|
+
return "Enums";
|
|
304
|
+
case "union":
|
|
305
|
+
return "Unions";
|
|
306
|
+
case "typedef":
|
|
307
|
+
return "Type Aliases";
|
|
308
|
+
default:
|
|
309
|
+
return kind.charAt(0).toUpperCase() + kind.slice(1) + "s";
|
|
291
310
|
}
|
|
292
311
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"godoc-loader.d.ts","sourceRoot":"","sources":["../../src/core/godoc-loader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"godoc-loader.d.ts","sourceRoot":"","sources":["../../src/core/godoc-loader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAaxD,OAAO,KAAK,EAAE,YAAY,EAAmB,MAAM,sBAAsB,CAAC;AAC1E,OAAO,KAAK,EAAE,OAAO,EAA6B,MAAM,iBAAiB,CAAC;AAE1E,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,qBAAqB,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,WAAW,GAAE,sBAA2B,GACvC,OAAO,CAAC,iBAAiB,CAAC,CAG5B"}
|
|
@@ -2,7 +2,7 @@ import { readFile } from "node:fs/promises";
|
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
3
|
import { GODOC_SCHEMA_VERSION } from "./godoc-types.js";
|
|
4
4
|
import { runIntrospector, GodocIntrospectorError } from "./godoc-introspector.js";
|
|
5
|
-
import { renderCodeBlock, renderMarkdown
|
|
5
|
+
import { renderCodeBlock, renderMarkdown } from "../utils/markdown.js";
|
|
6
6
|
/**
|
|
7
7
|
* Resolve a configured godoc tab into pre-rendered Sourcey pages plus a
|
|
8
8
|
* navigation tab. Honours `mode: "live" | "snapshot" | "auto"`:
|
|
@@ -32,7 +32,18 @@ async function loadSpec(config) {
|
|
|
32
32
|
return runIntrospector({ config });
|
|
33
33
|
}
|
|
34
34
|
if (config.snapshot) {
|
|
35
|
-
|
|
35
|
+
const spec = await loadSnapshot(config.snapshot, config.module);
|
|
36
|
+
return {
|
|
37
|
+
...spec,
|
|
38
|
+
diagnostics: [
|
|
39
|
+
{
|
|
40
|
+
severity: "info",
|
|
41
|
+
code: "GODOC_AUTO_FELL_BACK_TO_SNAPSHOT",
|
|
42
|
+
message: "godoc auto mode did not find Go on PATH and used the configured snapshot.",
|
|
43
|
+
},
|
|
44
|
+
...spec.diagnostics,
|
|
45
|
+
],
|
|
46
|
+
};
|
|
36
47
|
}
|
|
37
48
|
throw new GodocIntrospectorError("GO_NOT_FOUND", "godoc mode is 'auto' and Go is not on PATH. Install Go or set " +
|
|
38
49
|
"mode: 'snapshot' with a committed godoc.json.");
|
|
@@ -455,7 +466,9 @@ function sourceURL(position, sourceLinks) {
|
|
|
455
466
|
if (!position || !sourceLinks.repo || !sourceLinks.editBranch)
|
|
456
467
|
return undefined;
|
|
457
468
|
const repoBase = sourceLinks.repo.replace(/\/$/, "");
|
|
458
|
-
const basePath = sourceLinks.editBasePath
|
|
469
|
+
const basePath = sourceLinks.editBasePath
|
|
470
|
+
? `${sourceLinks.editBasePath.replace(/^\/|\/$/g, "")}/`
|
|
471
|
+
: "";
|
|
459
472
|
return `${repoBase}/blob/${sourceLinks.editBranch}/${basePath}${position.file}#L${position.line}`;
|
|
460
473
|
}
|
|
461
474
|
function renderExample(ex) {
|
|
@@ -472,9 +485,7 @@ function renderExample(ex) {
|
|
|
472
485
|
return parts.join("\n");
|
|
473
486
|
}
|
|
474
487
|
function humaniseSuffix(suffix) {
|
|
475
|
-
return suffix
|
|
476
|
-
.replace(/_/g, " ")
|
|
477
|
-
.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
488
|
+
return suffix.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
478
489
|
}
|
|
479
490
|
function renderDoc(input) {
|
|
480
491
|
return renderMarkdown(input).trim();
|
|
@@ -20,12 +20,19 @@ export interface MarkdownPage {
|
|
|
20
20
|
editBasePath?: string | null;
|
|
21
21
|
/** Optional page-local entries that should be indexed in addition to headings. */
|
|
22
22
|
searchEntries?: PageSearchEntry[];
|
|
23
|
+
/** Optional source root used to rewrite source-format-relative assets. */
|
|
24
|
+
sourceRoot?: string;
|
|
23
25
|
}
|
|
24
26
|
export interface PageSearchEntry {
|
|
25
27
|
title: string;
|
|
26
28
|
content: string;
|
|
27
29
|
anchor?: string;
|
|
28
30
|
category: string;
|
|
31
|
+
symbolKind?: string;
|
|
32
|
+
owner?: string;
|
|
33
|
+
ownerKind?: string;
|
|
34
|
+
namespace?: string;
|
|
35
|
+
qualifiedName?: string;
|
|
29
36
|
}
|
|
30
37
|
export interface ChangelogPage {
|
|
31
38
|
kind: "changelog";
|
|
@@ -45,7 +52,14 @@ export type { PageHeading } from "../utils/markdown.js";
|
|
|
45
52
|
export interface LoadDocsPageOptions {
|
|
46
53
|
changelog?: boolean;
|
|
47
54
|
repoUrl?: string;
|
|
55
|
+
sourceRoot?: string;
|
|
56
|
+
preprocess?: MarkdownPreprocessor[];
|
|
48
57
|
}
|
|
58
|
+
export interface MarkdownPreprocessContext {
|
|
59
|
+
filePath: string;
|
|
60
|
+
sourceRoot?: string;
|
|
61
|
+
}
|
|
62
|
+
export type MarkdownPreprocessor = (body: string, context: MarkdownPreprocessContext) => string;
|
|
49
63
|
/**
|
|
50
64
|
* Load a single markdown file and return a MarkdownPage.
|
|
51
65
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown-loader.d.ts","sourceRoot":"","sources":["../../src/core/markdown-loader.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"markdown-loader.d.ts","sourceRoot":"","sources":["../../src/core/markdown-loader.ts"],"names":[],"mappings":"AAOA,OAAO,EAOL,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAMtD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAC;IACjB,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,sEAAsE;IACtE,UAAU,EAAE,MAAM,CAAC;IACnB,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,8FAA8F;IAC9F,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,kFAAkF;IAClF,aAAa,CAAC,EAAE,eAAe,EAAE,CAAC;IAClC,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,mBAAmB,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,aAAa,CAAC;AAEpD,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAUxD,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,oBAAoB,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,yBAAyB,KAAK,MAAM,CAAC;AAonChG;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAK5F;AAED,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,QAAQ,CAAC,CAgCnB;AA+DD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOrD"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
1
|
+
import { readFile as readFileAsync } from "node:fs/promises";
|
|
2
2
|
import { basename, extname, relative } from "node:path";
|
|
3
3
|
import { load as parseYaml } from "js-yaml";
|
|
4
4
|
import { normalizeChangelog } from "./changelog-normalizer.js";
|
|
5
5
|
import { htmlId } from "../utils/html-id.js";
|
|
6
|
+
import { escapeAttr, safeUrl } from "../utils/html.js";
|
|
6
7
|
import { renderIcon } from "../utils/icons.js";
|
|
7
|
-
import { renderCodeBlock, renderMarkdown, renderMarkdownInline, extractHeadings, } from "../utils/markdown.js";
|
|
8
|
+
import { renderCodeBlock, renderMarkdown, renderMarkdownInline, extractHeadings, extractFirstParagraph, stripMarkdownLinks, } from "../utils/markdown.js";
|
|
8
9
|
// ---------------------------------------------------------------------------
|
|
9
10
|
// Frontmatter parsing
|
|
10
11
|
// ---------------------------------------------------------------------------
|
|
@@ -453,8 +454,9 @@ ${body}
|
|
|
453
454
|
const cols = node.attrs.cols || "2";
|
|
454
455
|
const cardHtml = cards
|
|
455
456
|
.map((card) => {
|
|
456
|
-
const
|
|
457
|
-
const
|
|
457
|
+
const safeHref = card.attrs.href ? safeUrl(card.attrs.href) : null;
|
|
458
|
+
const tag = safeHref ? "a" : "div";
|
|
459
|
+
const href = safeHref ? ` href="${escapeHtmlAttr(safeHref)}"` : "";
|
|
458
460
|
const iconHtml = renderIcon(card.attrs.icon || "");
|
|
459
461
|
const title = renderMarkdownInline(card.attrs.title || "").trim();
|
|
460
462
|
const body = renderComponentChildrenToHtml(card.children);
|
|
@@ -502,7 +504,10 @@ ${body}
|
|
|
502
504
|
return null;
|
|
503
505
|
return `\n\n${buildTabbedHtml(codeBlocks, nextId("cg"), "directive-code-group")}\n`;
|
|
504
506
|
}
|
|
505
|
-
if (node.name === "Note" ||
|
|
507
|
+
if (node.name === "Note" ||
|
|
508
|
+
node.name === "Warning" ||
|
|
509
|
+
node.name === "Tip" ||
|
|
510
|
+
node.name === "Info") {
|
|
506
511
|
const type = node.name.toLowerCase();
|
|
507
512
|
const label = renderMarkdownInline(node.attrs.title?.trim() || node.name.charAt(0).toUpperCase() + node.name.slice(1)).trim();
|
|
508
513
|
const body = renderComponentChildrenToHtml(node.children);
|
|
@@ -562,10 +567,7 @@ function escapeRegExp(value) {
|
|
|
562
567
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
563
568
|
}
|
|
564
569
|
function escapeHtmlAttr(value) {
|
|
565
|
-
return value
|
|
566
|
-
.replace(/&/g, "&")
|
|
567
|
-
.replace(/"/g, """)
|
|
568
|
-
.replace(/</g, "<");
|
|
570
|
+
return escapeAttr(value);
|
|
569
571
|
}
|
|
570
572
|
function stripDirectiveIndent(line) {
|
|
571
573
|
return line.replace(/^ {0,3}/, "");
|
|
@@ -585,9 +587,7 @@ function closesFence(line, fence) {
|
|
|
585
587
|
}
|
|
586
588
|
/** Build tabbed UI HTML (shared by :::tabs and :::code-group). */
|
|
587
589
|
function buildTabbedHtml(tabs, id, extraClass) {
|
|
588
|
-
const cls = extraClass
|
|
589
|
-
? `directive-tabs ${extraClass} not-prose`
|
|
590
|
-
: "directive-tabs not-prose";
|
|
590
|
+
const cls = extraClass ? `directive-tabs ${extraClass} not-prose` : "directive-tabs not-prose";
|
|
591
591
|
const buttons = tabs
|
|
592
592
|
.map((t, i) => `<button class="directive-tab${i === 0 ? " active" : ""}" data-tab-group="${id}" data-tab-index="${i}">${t.title}</button>`)
|
|
593
593
|
.join("\n");
|
|
@@ -652,7 +652,10 @@ function splitChildren(content, marker) {
|
|
|
652
652
|
}
|
|
653
653
|
children.push({
|
|
654
654
|
attrs: parseAttrs(start[1] ?? ""),
|
|
655
|
-
body: lines
|
|
655
|
+
body: lines
|
|
656
|
+
.slice(i + 1, j)
|
|
657
|
+
.join("\n")
|
|
658
|
+
.trim(),
|
|
656
659
|
});
|
|
657
660
|
i = j + 1;
|
|
658
661
|
}
|
|
@@ -696,7 +699,9 @@ const SUPPORTED_DIRECTIVES = new Set([
|
|
|
696
699
|
"accordion",
|
|
697
700
|
]);
|
|
698
701
|
function matchDirectiveStart(line) {
|
|
699
|
-
const match = stripDirectiveIndent(line)
|
|
702
|
+
const match = stripDirectiveIndent(line)
|
|
703
|
+
.trimEnd()
|
|
704
|
+
.match(/^:::(\w[\w-]*)(.*)$/);
|
|
700
705
|
if (!match || !SUPPORTED_DIRECTIVES.has(match[1]))
|
|
701
706
|
return null;
|
|
702
707
|
return {
|
|
@@ -821,8 +826,9 @@ ${body}
|
|
|
821
826
|
if (type === "card-group") {
|
|
822
827
|
const cols = parseAttrs(meta.match(/^\{([^}]*)\}$/)?.[1] ?? "").cols || "2";
|
|
823
828
|
const cards = splitChildren(content, "card").map((child) => {
|
|
824
|
-
const
|
|
825
|
-
const
|
|
829
|
+
const safeHref = child.attrs.href ? safeUrl(child.attrs.href) : null;
|
|
830
|
+
const tag = safeHref ? "a" : "div";
|
|
831
|
+
const href = safeHref ? ` href="${escapeHtmlAttr(safeHref)}"` : "";
|
|
826
832
|
const iconHtml = renderIcon(child.attrs.icon || "");
|
|
827
833
|
const title = renderMarkdownInline(child.attrs.title || "").trim();
|
|
828
834
|
const body = renderDirectiveMarkdown(child.body);
|
|
@@ -927,12 +933,12 @@ function preprocessDirectives(body) {
|
|
|
927
933
|
* Load a single markdown file and return a MarkdownPage.
|
|
928
934
|
*/
|
|
929
935
|
export async function loadMarkdownPage(filePath, slug) {
|
|
930
|
-
const raw = await
|
|
936
|
+
const raw = await readFileAsync(filePath, "utf-8");
|
|
931
937
|
const { meta, body } = parseFrontmatter(raw);
|
|
932
938
|
return loadMarkdownPageFromBody(filePath, slug, body, meta);
|
|
933
939
|
}
|
|
934
940
|
export async function loadDocsPage(filePath, slug, options = {}) {
|
|
935
|
-
const raw = await
|
|
941
|
+
const raw = await readFileAsync(filePath, "utf-8");
|
|
936
942
|
const { meta, body } = parseFrontmatter(raw);
|
|
937
943
|
if (shouldTreatAsChangelog(filePath, meta, options)) {
|
|
938
944
|
const sourcePath = relative(process.cwd(), filePath);
|
|
@@ -941,9 +947,7 @@ export async function loadDocsPage(filePath, slug, options = {}) {
|
|
|
941
947
|
description: typeof meta.description === "string" ? meta.description : undefined,
|
|
942
948
|
repoUrl: options.repoUrl,
|
|
943
949
|
});
|
|
944
|
-
const description = typeof meta.description === "string"
|
|
945
|
-
? meta.description
|
|
946
|
-
: changelog.description ?? "";
|
|
950
|
+
const description = typeof meta.description === "string" ? meta.description : (changelog.description ?? "");
|
|
947
951
|
return {
|
|
948
952
|
kind: "changelog",
|
|
949
953
|
title: changelog.title,
|
|
@@ -960,7 +964,7 @@ export async function loadDocsPage(filePath, slug, options = {}) {
|
|
|
960
964
|
rawBody: body,
|
|
961
965
|
};
|
|
962
966
|
}
|
|
963
|
-
return loadMarkdownPageFromBody(filePath, slug, body, meta);
|
|
967
|
+
return loadMarkdownPageFromBody(filePath, slug, body, meta, options);
|
|
964
968
|
}
|
|
965
969
|
function shouldTreatAsChangelog(filePath, meta, options) {
|
|
966
970
|
if (options.changelog === false)
|
|
@@ -969,14 +973,15 @@ function shouldTreatAsChangelog(filePath, meta, options) {
|
|
|
969
973
|
return true;
|
|
970
974
|
return basename(filePath).toLowerCase() === "changelog.md";
|
|
971
975
|
}
|
|
972
|
-
function loadMarkdownPageFromBody(filePath, slug, body, meta) {
|
|
976
|
+
function loadMarkdownPageFromBody(filePath, slug, body, meta, options = {}) {
|
|
973
977
|
resetDirectiveCounter();
|
|
974
|
-
const
|
|
978
|
+
const sourcePreprocessed = preprocessSourceMarkdown(body, filePath, options);
|
|
979
|
+
const componentPreprocessed = preprocessComponents(sourcePreprocessed);
|
|
975
980
|
const preprocessed = preprocessDirectives(componentPreprocessed);
|
|
976
981
|
const headings = extractHeadings(componentPreprocessed);
|
|
977
982
|
const html = renderMarkdown(preprocessed);
|
|
978
983
|
const title = meta.title ?? extractFirstHeading(componentPreprocessed) ?? slug;
|
|
979
|
-
const description = meta.description
|
|
984
|
+
const description = normalizeMarkdownDescription(meta.description, componentPreprocessed);
|
|
980
985
|
// Strip leading h1 from rendered HTML when it duplicates the page title
|
|
981
986
|
const cleanHtml = html.replace(/^\s*<h1[^>]*>(.*?)<\/h1>\s*/i, (_m, inner) => inner.replace(/<[^>]+>/g, "").trim() === title ? "" : _m);
|
|
982
987
|
const sourcePath = relative(process.cwd(), filePath);
|
|
@@ -989,8 +994,15 @@ function loadMarkdownPageFromBody(filePath, slug, body, meta) {
|
|
|
989
994
|
headings,
|
|
990
995
|
sourcePath,
|
|
991
996
|
editPath: sourcePath,
|
|
997
|
+
sourceRoot: options.sourceRoot ? relative(process.cwd(), options.sourceRoot) : undefined,
|
|
992
998
|
};
|
|
993
999
|
}
|
|
1000
|
+
function normalizeMarkdownDescription(description, markdown) {
|
|
1001
|
+
if (typeof description === "string" && description.trim()) {
|
|
1002
|
+
return description;
|
|
1003
|
+
}
|
|
1004
|
+
return stripMarkdownLinks(extractFirstParagraph(markdown)).replace(/\s+/g, " ").trim();
|
|
1005
|
+
}
|
|
994
1006
|
/**
|
|
995
1007
|
* Extract the first # heading from markdown as a fallback title.
|
|
996
1008
|
*/
|
|
@@ -1008,5 +1020,37 @@ function extractFirstHeading(md) {
|
|
|
1008
1020
|
export function slugFromPath(filePath) {
|
|
1009
1021
|
const ext = extname(filePath);
|
|
1010
1022
|
const stripped = ext ? filePath.slice(0, -ext.length) : filePath;
|
|
1011
|
-
return stripped
|
|
1023
|
+
return stripped
|
|
1024
|
+
.split("/")
|
|
1025
|
+
.map((s) => slugSegmentFromPath(s))
|
|
1026
|
+
.join("/");
|
|
1027
|
+
}
|
|
1028
|
+
function slugSegmentFromPath(segment) {
|
|
1029
|
+
const normalized = segment
|
|
1030
|
+
.replace(/^operator=$/, "operator-assign")
|
|
1031
|
+
.replace(/^~(.+)$/, "destructor-$1")
|
|
1032
|
+
.replace(/<=>/g, "-spaceship")
|
|
1033
|
+
.replace(/<=/g, "-le")
|
|
1034
|
+
.replace(/>=/g, "-ge")
|
|
1035
|
+
.replace(/==/g, "-eq")
|
|
1036
|
+
.replace(/!=/g, "-ne")
|
|
1037
|
+
.replace(/\[\]/g, "-array")
|
|
1038
|
+
.replace(/\+=/g, "-plus-eq")
|
|
1039
|
+
.replace(/\/=/g, "-slash-eq")
|
|
1040
|
+
.replace(/\//g, "-slash")
|
|
1041
|
+
.replace(/=/g, "-eq")
|
|
1042
|
+
.replace(/\+/g, "-plus")
|
|
1043
|
+
.replace(/</g, "-lt")
|
|
1044
|
+
.replace(/>/g, "-gt");
|
|
1045
|
+
return htmlId(normalized);
|
|
1046
|
+
}
|
|
1047
|
+
function preprocessSourceMarkdown(body, filePath, options) {
|
|
1048
|
+
let current = body;
|
|
1049
|
+
for (const preprocess of options.preprocess ?? []) {
|
|
1050
|
+
current = preprocess(current, {
|
|
1051
|
+
filePath,
|
|
1052
|
+
sourceRoot: options.sourceRoot,
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
return current;
|
|
1012
1056
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-normalizer.d.ts","sourceRoot":"","sources":["../../src/core/mcp-normalizer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"mcp-normalizer.d.ts","sourceRoot":"","sources":["../../src/core/mcp-normalizer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,OAAO,EAMR,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EACV,cAAc,EASf,MAAM,YAAY,CAAC;AAKpB,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAwD9D"}
|
|
@@ -9,12 +9,14 @@ import { generateExample } from "../utils/example-generator.js";
|
|
|
9
9
|
// ── Public API ────────────────────────────────────────────────────────
|
|
10
10
|
export function normalizeMcpSpec(spec) {
|
|
11
11
|
const connectionInfo = {
|
|
12
|
-
transport: spec.transport
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
transport: spec.transport
|
|
13
|
+
? {
|
|
14
|
+
type: spec.transport.type,
|
|
15
|
+
command: spec.transport.command,
|
|
16
|
+
args: spec.transport.args,
|
|
17
|
+
url: spec.transport.url,
|
|
18
|
+
}
|
|
19
|
+
: undefined,
|
|
18
20
|
serverName: spec.server.name,
|
|
19
21
|
mcpVersion: spec.mcpVersion,
|
|
20
22
|
capabilities: spec.capabilities,
|
|
@@ -58,13 +60,14 @@ function toolToOperation(tool, connection) {
|
|
|
58
60
|
const group = tool["x-sourcey-group"];
|
|
59
61
|
const inputSchema = convertSchema(tool.inputSchema);
|
|
60
62
|
const outputSchema = tool.outputSchema ? convertSchema(tool.outputSchema) : undefined;
|
|
61
|
-
|
|
62
|
-
const parameters = flattenInputSchema(tool.inputSchema);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
const emitsRequestBody = hasNestedProperties(tool.inputSchema);
|
|
64
|
+
const parameters = emitsRequestBody ? [] : flattenInputSchema(tool.inputSchema);
|
|
65
|
+
const requestBody = emitsRequestBody
|
|
66
|
+
? {
|
|
67
|
+
required: true,
|
|
68
|
+
content: { "application/json": { schema: inputSchema } },
|
|
69
|
+
}
|
|
70
|
+
: undefined;
|
|
68
71
|
return {
|
|
69
72
|
operationId: tool.name,
|
|
70
73
|
summary: tool.title ?? tool.name,
|
|
@@ -80,12 +83,14 @@ function toolToOperation(tool, connection) {
|
|
|
80
83
|
codeSamples: generateToolSamples(tool, inputSchema),
|
|
81
84
|
mcpExtras: {
|
|
82
85
|
type: "tool",
|
|
83
|
-
annotations: tool.annotations
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
annotations: tool.annotations
|
|
87
|
+
? {
|
|
88
|
+
readOnlyHint: tool.annotations.readOnlyHint,
|
|
89
|
+
destructiveHint: tool.annotations.destructiveHint,
|
|
90
|
+
idempotentHint: tool.annotations.idempotentHint,
|
|
91
|
+
openWorldHint: tool.annotations.openWorldHint,
|
|
92
|
+
}
|
|
93
|
+
: undefined,
|
|
89
94
|
outputSchema,
|
|
90
95
|
connection,
|
|
91
96
|
},
|
|
@@ -136,7 +141,7 @@ function resourceTemplateToOperation(template, connection) {
|
|
|
136
141
|
// ── Prompt → Operation ────────────────────────────────────────────────
|
|
137
142
|
function promptToOperation(prompt, connection) {
|
|
138
143
|
const group = prompt["x-sourcey-group"];
|
|
139
|
-
const parameters = (prompt.arguments ?? []).map(arg => ({
|
|
144
|
+
const parameters = (prompt.arguments ?? []).map((arg) => ({
|
|
140
145
|
name: arg.name,
|
|
141
146
|
in: "argument",
|
|
142
147
|
description: arg.description,
|
|
@@ -189,18 +194,20 @@ function convertSchema(schema, name) {
|
|
|
189
194
|
}
|
|
190
195
|
}
|
|
191
196
|
if (schema.additionalProperties !== undefined) {
|
|
192
|
-
result.additionalProperties =
|
|
193
|
-
|
|
194
|
-
|
|
197
|
+
result.additionalProperties =
|
|
198
|
+
typeof schema.additionalProperties === "boolean"
|
|
199
|
+
? schema.additionalProperties
|
|
200
|
+
: convertSchema(schema.additionalProperties);
|
|
195
201
|
}
|
|
196
202
|
if (schema.required)
|
|
197
203
|
result.required = schema.required;
|
|
198
204
|
// Array — handle JsonSchema.items being JsonSchema | JsonSchema[]
|
|
199
205
|
if (schema.items) {
|
|
200
206
|
if (Array.isArray(schema.items)) {
|
|
201
|
-
result.items =
|
|
202
|
-
|
|
203
|
-
|
|
207
|
+
result.items =
|
|
208
|
+
schema.items.length === 1
|
|
209
|
+
? convertSchema(schema.items[0])
|
|
210
|
+
: { oneOf: schema.items.map((s) => convertSchema(s)) };
|
|
204
211
|
}
|
|
205
212
|
else {
|
|
206
213
|
result.items = convertSchema(schema.items);
|
|
@@ -265,7 +272,10 @@ function hasNestedProperties(schema) {
|
|
|
265
272
|
return Object.values(schema.properties).some((prop) => {
|
|
266
273
|
if (prop.type === "object" && prop.properties)
|
|
267
274
|
return true;
|
|
268
|
-
if (prop.type === "array" &&
|
|
275
|
+
if (prop.type === "array" &&
|
|
276
|
+
prop.items &&
|
|
277
|
+
!Array.isArray(prop.items) &&
|
|
278
|
+
prop.items.type === "object")
|
|
269
279
|
return true;
|
|
270
280
|
if (prop.allOf || prop.anyOf || prop.oneOf)
|
|
271
281
|
return true;
|
|
@@ -276,7 +286,7 @@ function extractUriTemplateParams(uriTemplate) {
|
|
|
276
286
|
const matches = uriTemplate.match(/\{([^}]+)\}/g);
|
|
277
287
|
if (!matches)
|
|
278
288
|
return [];
|
|
279
|
-
return matches.map(m => ({
|
|
289
|
+
return matches.map((m) => ({
|
|
280
290
|
name: m.slice(1, -1),
|
|
281
291
|
in: "path",
|
|
282
292
|
required: true,
|
|
@@ -289,11 +299,12 @@ function slugify(name) {
|
|
|
289
299
|
}
|
|
290
300
|
// ── Code sample generation ────────────────────────────────────────────
|
|
291
301
|
function generateToolSamples(tool, inputSchema) {
|
|
292
|
-
const example = inputSchema.properties
|
|
293
|
-
? generateExample(inputSchema)
|
|
294
|
-
: {};
|
|
302
|
+
const example = inputSchema.properties ? generateExample(inputSchema) : {};
|
|
295
303
|
const exampleJson = JSON.stringify(example, null, 2);
|
|
296
|
-
const indented = exampleJson
|
|
304
|
+
const indented = exampleJson
|
|
305
|
+
.split("\n")
|
|
306
|
+
.map((line, i) => (i === 0 ? line : " " + line))
|
|
307
|
+
.join("\n");
|
|
297
308
|
return [
|
|
298
309
|
{
|
|
299
310
|
lang: "json",
|
|
@@ -345,10 +356,13 @@ function generateResourceSamples(resource) {
|
|
|
345
356
|
];
|
|
346
357
|
}
|
|
347
358
|
function generatePromptSamples(prompt) {
|
|
348
|
-
const args =
|
|
359
|
+
const args = prompt.arguments ?? [];
|
|
349
360
|
const exampleArgs = Object.fromEntries(args.map((a) => [a.name, `<${a.name}>`]));
|
|
350
361
|
const argsJson = JSON.stringify(exampleArgs, null, 2);
|
|
351
|
-
const indented = argsJson
|
|
362
|
+
const indented = argsJson
|
|
363
|
+
.split("\n")
|
|
364
|
+
.map((line, i) => (i === 0 ? line : " " + line))
|
|
365
|
+
.join("\n");
|
|
352
366
|
const tsArgs = args.map((a) => ` ${a.name}: "<${a.name}>",`).join("\n");
|
|
353
367
|
const pyArgs = args.map((a) => ` "${a.name}": "<${a.name}>",`).join("\n");
|
|
354
368
|
return [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/core/navigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAgB/D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAMD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,MAAM,EACf,UAAU,GAAE,UAAkB,GAC7B,OAAO,CAiDT;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,WAAW,EAChB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,EAClC,UAAU,GAAE,UAAkB,GAC7B,OAAO,
|
|
1
|
+
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/core/navigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAgB/D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAMD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,MAAM,EACf,UAAU,GAAE,UAAkB,GAC7B,OAAO,CAiDT;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,WAAW,EAChB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,EAClC,UAAU,GAAE,UAAkB,GAC7B,OAAO,CA8BT;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,cAAc,CASnE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,cAAc,EACnB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,cAAc,CAEhB"}
|