@farming-labs/svelte 0.1.57 → 0.1.59
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/dist/markdown.d.ts +4 -1
- package/dist/markdown.js +159 -3
- package/dist/server.js +8 -2
- package/package.json +2 -2
package/dist/markdown.d.ts
CHANGED
|
@@ -9,14 +9,17 @@
|
|
|
9
9
|
* - Tables, lists, inline formatting, headings with anchor IDs
|
|
10
10
|
*/
|
|
11
11
|
import { type DocsTheme } from "@farming-labs/docs";
|
|
12
|
+
import { type SerializedOpenDocsProvider } from "@farming-labs/docs/server";
|
|
12
13
|
interface RenderMarkdownOptions {
|
|
13
14
|
theme?: DocsTheme;
|
|
15
|
+
icons?: Record<string, string>;
|
|
16
|
+
openDocsProviders?: SerializedOpenDocsProvider[];
|
|
14
17
|
}
|
|
15
18
|
/**
|
|
16
19
|
* Render a markdown string to HTML with full syntax highlighting,
|
|
17
20
|
* callouts, tables, tabs, and copy-to-clipboard support.
|
|
18
21
|
*
|
|
19
|
-
* Designed for server-side use in SvelteKit
|
|
22
|
+
* Designed for server-side use in SvelteKit page loaders.
|
|
20
23
|
*/
|
|
21
24
|
export declare function renderMarkdown(content: string, options?: RenderMarkdownOptions): Promise<string>;
|
|
22
25
|
export {};
|
package/dist/markdown.js
CHANGED
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* - Tables, lists, inline formatting, headings with anchor IDs
|
|
10
10
|
*/
|
|
11
11
|
import { resolveDocsAgentMdxContent } from "@farming-labs/docs";
|
|
12
|
+
import { parsePromptStringArray, resolvePromptProviderChoices, sanitizePromptText, } from "@farming-labs/docs/server";
|
|
12
13
|
import { createHighlighter } from "shiki";
|
|
13
|
-
let highlighterPromise;
|
|
14
|
+
let highlighterPromise = null;
|
|
14
15
|
function getHighlighter() {
|
|
15
16
|
if (!highlighterPromise) {
|
|
16
17
|
highlighterPromise = createHighlighter({
|
|
@@ -51,6 +52,21 @@ const hoverLinkDefaults = {
|
|
|
51
52
|
side: "bottom",
|
|
52
53
|
sideOffset: 12,
|
|
53
54
|
};
|
|
55
|
+
const promptDefaults = {
|
|
56
|
+
actions: ["copy"],
|
|
57
|
+
copyLabel: "Copy prompt",
|
|
58
|
+
copiedLabel: "Copied",
|
|
59
|
+
openLabel: "Open in",
|
|
60
|
+
copyIcon: "copy",
|
|
61
|
+
copiedIcon: "check",
|
|
62
|
+
openIcon: "arrowUpRight",
|
|
63
|
+
};
|
|
64
|
+
const promptActionIcons = {
|
|
65
|
+
copy: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2" /><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" /></svg>',
|
|
66
|
+
check: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12" /></svg>',
|
|
67
|
+
arrowUpRight: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" /><polyline points="15 3 21 3 21 9" /><line x1="10" y1="14" x2="21" y2="3" /></svg>',
|
|
68
|
+
chevronDown: '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9" /></svg>',
|
|
69
|
+
};
|
|
54
70
|
function escapeHtml(value) {
|
|
55
71
|
return value
|
|
56
72
|
.replace(/&/g, "&")
|
|
@@ -117,6 +133,21 @@ function resolveHoverLinkOptions(theme) {
|
|
|
117
133
|
}
|
|
118
134
|
return base;
|
|
119
135
|
}
|
|
136
|
+
function resolvePromptOptions(theme) {
|
|
137
|
+
const configured = theme?.ui?.components?.Prompt;
|
|
138
|
+
const base = { ...promptDefaults };
|
|
139
|
+
if (typeof configured === "function") {
|
|
140
|
+
const resolved = configured(base);
|
|
141
|
+
if (resolved && typeof resolved === "object") {
|
|
142
|
+
return { ...base, ...resolved };
|
|
143
|
+
}
|
|
144
|
+
return base;
|
|
145
|
+
}
|
|
146
|
+
if (configured && typeof configured === "object") {
|
|
147
|
+
return { ...base, ...configured };
|
|
148
|
+
}
|
|
149
|
+
return base;
|
|
150
|
+
}
|
|
120
151
|
function renderHoverLink(attrSource, children, theme) {
|
|
121
152
|
const attrs = parseJsxAttributes(attrSource);
|
|
122
153
|
const defaults = resolveHoverLinkOptions(theme);
|
|
@@ -164,6 +195,120 @@ function renderHoverLink(attrSource, children, theme) {
|
|
|
164
195
|
`</span>` +
|
|
165
196
|
`</span>`);
|
|
166
197
|
}
|
|
198
|
+
function resolvePromptIconName(value) {
|
|
199
|
+
if (value === false)
|
|
200
|
+
return false;
|
|
201
|
+
if (typeof value !== "string")
|
|
202
|
+
return undefined;
|
|
203
|
+
const trimmed = value.trim();
|
|
204
|
+
if (!trimmed)
|
|
205
|
+
return undefined;
|
|
206
|
+
if (trimmed === "false")
|
|
207
|
+
return false;
|
|
208
|
+
return trimmed;
|
|
209
|
+
}
|
|
210
|
+
function renderPromptIconHtml(name, iconRegistry) {
|
|
211
|
+
if (!name)
|
|
212
|
+
return "";
|
|
213
|
+
const registryMatch = iconRegistry?.[name];
|
|
214
|
+
if (registryMatch)
|
|
215
|
+
return registryMatch;
|
|
216
|
+
return promptActionIcons[name] ?? "";
|
|
217
|
+
}
|
|
218
|
+
function renderPrompt(attrSource, children, options) {
|
|
219
|
+
const attrs = parseJsxAttributes(attrSource);
|
|
220
|
+
const defaults = resolvePromptOptions(options.theme);
|
|
221
|
+
const title = toStringValue(attrs.title) ?? toStringValue(defaults.title);
|
|
222
|
+
const description = toStringValue(attrs.description) ?? toStringValue(defaults.description);
|
|
223
|
+
const iconName = toStringValue(attrs.icon) ?? toStringValue(defaults.icon);
|
|
224
|
+
const showTitle = attrs.showTitle !== undefined
|
|
225
|
+
? toBoolean(attrs.showTitle, true)
|
|
226
|
+
: toBoolean(defaults.showTitle, true);
|
|
227
|
+
const showDescription = attrs.showDescription !== undefined
|
|
228
|
+
? toBoolean(attrs.showDescription, true)
|
|
229
|
+
: toBoolean(defaults.showDescription, true);
|
|
230
|
+
const showPrompt = attrs.showPrompt !== undefined
|
|
231
|
+
? toBoolean(attrs.showPrompt, false)
|
|
232
|
+
: toBoolean(defaults.showPrompt, false);
|
|
233
|
+
const actions = parsePromptStringArray(attrs.actions ?? defaults.actions) ?? ["copy"];
|
|
234
|
+
const providers = resolvePromptProviderChoices(options.openDocsProviders, parsePromptStringArray(attrs.providers ?? defaults.providers)) ?? [];
|
|
235
|
+
const copyLabel = toStringValue(attrs.copyLabel) ?? toStringValue(defaults.copyLabel) ?? promptDefaults.copyLabel;
|
|
236
|
+
const copiedLabel = toStringValue(attrs.copiedLabel) ??
|
|
237
|
+
toStringValue(defaults.copiedLabel) ??
|
|
238
|
+
promptDefaults.copiedLabel;
|
|
239
|
+
const openLabel = toStringValue(attrs.openLabel) ?? toStringValue(defaults.openLabel) ?? promptDefaults.openLabel;
|
|
240
|
+
const copyIcon = resolvePromptIconName(attrs.copyIcon ?? defaults.copyIcon);
|
|
241
|
+
const copiedIcon = resolvePromptIconName(attrs.copiedIcon ?? defaults.copiedIcon);
|
|
242
|
+
const openIcon = resolvePromptIconName(attrs.openIcon ?? defaults.openIcon);
|
|
243
|
+
const promptText = sanitizePromptText(dedentCode(children.trim()));
|
|
244
|
+
if (!promptText)
|
|
245
|
+
return "";
|
|
246
|
+
const cardIconHtml = iconName && options.icons?.[iconName] ? options.icons[iconName] : "";
|
|
247
|
+
const copyIconHtml = renderPromptIconHtml(copyIcon, options.icons);
|
|
248
|
+
const copiedIconHtml = renderPromptIconHtml(copiedIcon, options.icons);
|
|
249
|
+
const openIconHtml = renderPromptIconHtml(openIcon, options.icons);
|
|
250
|
+
const showCopy = actions.includes("copy");
|
|
251
|
+
const showOpen = actions.includes("open") && providers.length > 0;
|
|
252
|
+
const escapedPrompt = escapeHtml(promptText);
|
|
253
|
+
const singleProvider = showOpen && providers.length === 1 ? providers[0] : null;
|
|
254
|
+
let actionsHtml = "";
|
|
255
|
+
if (showCopy || showOpen) {
|
|
256
|
+
actionsHtml += '<div class="fd-prompt-actions">';
|
|
257
|
+
if (showCopy) {
|
|
258
|
+
actionsHtml +=
|
|
259
|
+
`<button type="button" class="fd-prompt-action-btn" data-prompt-copy>` +
|
|
260
|
+
`<span class="fd-prompt-action-icon">${copyIconHtml}</span>` +
|
|
261
|
+
`<span data-prompt-copy-label="${escapeHtml(copiedLabel)}" data-prompt-default-label="${escapeHtml(copyLabel)}">${escapeHtml(copyLabel)}</span>` +
|
|
262
|
+
`<span class="fd-prompt-action-icon fd-prompt-action-icon-copied" hidden>${copiedIconHtml}</span>` +
|
|
263
|
+
`</button>`;
|
|
264
|
+
}
|
|
265
|
+
if (singleProvider) {
|
|
266
|
+
actionsHtml +=
|
|
267
|
+
`<button type="button" class="fd-prompt-action-btn" data-prompt-open-direct data-url-template="${escapeHtml(singleProvider.urlTemplate)}">` +
|
|
268
|
+
`<span class="fd-prompt-action-icon">${openIconHtml}</span>` +
|
|
269
|
+
`<span>${escapeHtml(openLabel)} ${escapeHtml(singleProvider.name)}</span>` +
|
|
270
|
+
`</button>`;
|
|
271
|
+
}
|
|
272
|
+
else if (showOpen) {
|
|
273
|
+
actionsHtml +=
|
|
274
|
+
`<div class="fd-prompt-dropdown" data-prompt-dropdown>` +
|
|
275
|
+
`<button type="button" class="fd-prompt-action-btn" aria-expanded="false" data-prompt-trigger>` +
|
|
276
|
+
`<span class="fd-prompt-action-icon">${openIconHtml}</span>` +
|
|
277
|
+
`<span>${escapeHtml(openLabel)}</span>` +
|
|
278
|
+
`<span class="fd-prompt-action-chevron">${promptActionIcons.chevronDown}</span>` +
|
|
279
|
+
`</button>` +
|
|
280
|
+
`<div class="fd-prompt-menu" role="menu" hidden data-prompt-menu>`;
|
|
281
|
+
for (const provider of providers) {
|
|
282
|
+
actionsHtml +=
|
|
283
|
+
`<button type="button" role="menuitem" class="fd-prompt-menu-item" data-prompt-open-provider data-url-template="${escapeHtml(provider.urlTemplate)}">` +
|
|
284
|
+
(provider.iconHtml
|
|
285
|
+
? `<span class="fd-prompt-menu-icon">${provider.iconHtml}</span>`
|
|
286
|
+
: "") +
|
|
287
|
+
`<span class="fd-prompt-menu-label">${escapeHtml(openLabel)} ${escapeHtml(provider.name)}</span>` +
|
|
288
|
+
`</button>`;
|
|
289
|
+
}
|
|
290
|
+
actionsHtml += `</div></div>`;
|
|
291
|
+
}
|
|
292
|
+
actionsHtml += `</div>`;
|
|
293
|
+
}
|
|
294
|
+
return (`<div class="fd-prompt" data-prompt-card>` +
|
|
295
|
+
(cardIconHtml || (showTitle && title) || (showDescription && description)
|
|
296
|
+
? `<div class="fd-prompt-header">` +
|
|
297
|
+
(cardIconHtml ? `<span class="fd-prompt-icon">${cardIconHtml}</span>` : "") +
|
|
298
|
+
`<div class="fd-prompt-copy">` +
|
|
299
|
+
(showTitle && title ? `<p class="fd-prompt-title">${escapeHtml(title)}</p>` : "") +
|
|
300
|
+
(showDescription && description
|
|
301
|
+
? `<p class="fd-prompt-description">${escapeHtml(description)}</p>`
|
|
302
|
+
: "") +
|
|
303
|
+
`</div></div>`
|
|
304
|
+
: "") +
|
|
305
|
+
`<div data-prompt-text hidden aria-hidden="true">${escapedPrompt}</div>` +
|
|
306
|
+
(showPrompt
|
|
307
|
+
? `<div class="fd-prompt-body"><pre class="fd-prompt-code">${escapedPrompt}</pre></div>`
|
|
308
|
+
: "") +
|
|
309
|
+
actionsHtml +
|
|
310
|
+
`</div>`);
|
|
311
|
+
}
|
|
167
312
|
const calloutIcons = {
|
|
168
313
|
note: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>',
|
|
169
314
|
warning: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',
|
|
@@ -237,7 +382,7 @@ function dedentCode(raw) {
|
|
|
237
382
|
* Render a markdown string to HTML with full syntax highlighting,
|
|
238
383
|
* callouts, tables, tabs, and copy-to-clipboard support.
|
|
239
384
|
*
|
|
240
|
-
* Designed for server-side use in SvelteKit
|
|
385
|
+
* Designed for server-side use in SvelteKit page loaders.
|
|
241
386
|
*/
|
|
242
387
|
export async function renderMarkdown(content, options = {}) {
|
|
243
388
|
if (!content)
|
|
@@ -294,6 +439,12 @@ export async function renderMarkdown(content, options = {}) {
|
|
|
294
439
|
hoverLinkBlocks.push(renderHoverLink(attrSource, children, options.theme));
|
|
295
440
|
return placeholder;
|
|
296
441
|
});
|
|
442
|
+
const promptBlocks = [];
|
|
443
|
+
result = result.replace(/<Prompt(?:\s+([^>]*?))?>([\s\S]*?)<\/Prompt>/g, (_, attrSource, children) => {
|
|
444
|
+
const placeholder = `%%PROMPT_${promptBlocks.length}%%`;
|
|
445
|
+
promptBlocks.push(renderPrompt(attrSource ?? "", children, options));
|
|
446
|
+
return placeholder;
|
|
447
|
+
});
|
|
297
448
|
// Inline code
|
|
298
449
|
result = result.replace(/`([^`]+)`/g, "<code>$1</code>");
|
|
299
450
|
// Headings (h4 → h1 order to avoid prefix collisions)
|
|
@@ -334,6 +485,8 @@ export async function renderMarkdown(content, options = {}) {
|
|
|
334
485
|
result = result.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>");
|
|
335
486
|
result = result.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>");
|
|
336
487
|
result = result.replace(/\*(.+?)\*/g, "<em>$1</em>");
|
|
488
|
+
// Images — before links so  is not captured as a link
|
|
489
|
+
result = result.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, (_, alt, src) => `<img src="${src}" alt="${alt.replace(/"/g, """)}" class="fd-docs-content-img" loading="lazy" decoding="async" />`);
|
|
337
490
|
// Links
|
|
338
491
|
result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
|
|
339
492
|
// Horizontal rules
|
|
@@ -384,7 +537,7 @@ export async function renderMarkdown(content, options = {}) {
|
|
|
384
537
|
return "";
|
|
385
538
|
if (/^<(h[1-6]|pre|ul|ol|blockquote|hr|table|div)/.test(block))
|
|
386
539
|
return block;
|
|
387
|
-
if (/^%%(CODEBLOCK|CALLOUT|TABS)_\d+%%$/.test(block))
|
|
540
|
+
if (/^%%(CODEBLOCK|CALLOUT|TABS|PROMPT|HOVERLINK)_\d+%%$/.test(block))
|
|
388
541
|
return block;
|
|
389
542
|
return `<p>${block}</p>`;
|
|
390
543
|
})
|
|
@@ -402,5 +555,8 @@ export async function renderMarkdown(content, options = {}) {
|
|
|
402
555
|
for (let i = 0; i < hoverLinkBlocks.length; i++) {
|
|
403
556
|
result = result.replace(`%%HOVERLINK_${i}%%`, hoverLinkBlocks[i]);
|
|
404
557
|
}
|
|
558
|
+
for (let i = 0; i < promptBlocks.length; i++) {
|
|
559
|
+
result = result.replace(`%%PROMPT_${i}%%`, promptBlocks[i]);
|
|
560
|
+
}
|
|
405
561
|
return result;
|
|
406
562
|
}
|
package/dist/server.js
CHANGED
|
@@ -31,7 +31,7 @@ import fs from "node:fs";
|
|
|
31
31
|
import path from "node:path";
|
|
32
32
|
import matter from "gray-matter";
|
|
33
33
|
import { applySidebarFolderIndexBehavior, buildDocsAgentDiscoverySpec, findDocsMarkdownPage, isDocsAgentDiscoveryRequest, isDocsSkillRequest, normalizeDocsRelated, performDocsSearch, renderDocsMarkdownDocument, renderDocsSkillDocument, stripGeneratedAgentProvenance, resolveDocsAgentMdxContent, resolvePageSidebarFolderIndexBehavior, resolveSearchRequestConfig, resolveDocsI18n, resolveDocsLlmsTxtFormat, resolveDocsLocale, resolveDocsMarkdownRequest, resolveDocsPath, resolvePageReadingTime, resolveReadingTimeOptions, resolveDocsSkillFormat, } from "@farming-labs/docs";
|
|
34
|
-
import { createDocsMcpHttpHandler, resolveDocsMcpConfig } from "@farming-labs/docs/server";
|
|
34
|
+
import { createDocsMcpHttpHandler, resolveDocsMcpConfig, serializeDocsIconRegistry, serializeOpenDocsProviders, } from "@farming-labs/docs/server";
|
|
35
35
|
import { loadDocsNavTree, loadDocsContent, flattenNavTree } from "./content.js";
|
|
36
36
|
import { renderMarkdown } from "./markdown.js";
|
|
37
37
|
export { createSvelteApiReference } from "./api-reference.js";
|
|
@@ -489,7 +489,13 @@ export function createDocsServer(config = {}) {
|
|
|
489
489
|
enabledByDefault: readingTimeOptions.enabled,
|
|
490
490
|
wordsPerMinute: readingTimeOptions.wordsPerMinute,
|
|
491
491
|
});
|
|
492
|
-
const html = await renderMarkdown(humanRawContent, {
|
|
492
|
+
const html = await renderMarkdown(humanRawContent, {
|
|
493
|
+
theme: config.theme,
|
|
494
|
+
icons: serializeDocsIconRegistry(config.icons),
|
|
495
|
+
openDocsProviders: serializeOpenDocsProviders(config.pageActions?.openDocs && typeof config.pageActions.openDocs === "object"
|
|
496
|
+
? config.pageActions.openDocs.providers
|
|
497
|
+
: undefined),
|
|
498
|
+
});
|
|
493
499
|
const currentUrl = isIndex ? `/${entry}` : `/${entry}/${slug}`;
|
|
494
500
|
const currentIndex = flatPages.findIndex((p) => p.url === currentUrl);
|
|
495
501
|
const previousPage = currentIndex > 0 ? flatPages[currentIndex - 1] : null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@farming-labs/svelte",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.59",
|
|
4
4
|
"description": "SvelteKit adapter for @farming-labs/docs — content loading and navigation utilities",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"docs",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@types/node": "^22.10.0",
|
|
58
58
|
"typescript": "^5.9.3",
|
|
59
|
-
"@farming-labs/docs": "0.1.
|
|
59
|
+
"@farming-labs/docs": "0.1.59"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
62
|
"@farming-labs/docs": "*"
|