@farming-labs/svelte 0.1.124 → 0.1.126

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.
Files changed (2) hide show
  1. package/dist/markdown.js +81 -5
  2. package/package.json +2 -2
package/dist/markdown.js CHANGED
@@ -348,20 +348,60 @@ function highlightCode(hl, code, lang) {
348
348
  }
349
349
  }
350
350
  function parseMeta(meta) {
351
- const lang = (meta.split(/\s/)[0] || "text").toLowerCase();
352
- const titleMatch = meta.match(/title=["']([^"']+)["']/);
351
+ const trimmed = meta.trim();
352
+ const lang = (trimmed.split(/\s/)[0] || "text").toLowerCase();
353
+ const titleMatch = trimmed.match(/\b(?:title|filename|file|name|label)=["']([^"']+)["']/);
353
354
  return { lang, title: titleMatch ? titleMatch[1] : null };
354
355
  }
356
+ const ignoredCodeGroupBareTitleTokens = new Set([
357
+ "copy",
358
+ "no-copy",
359
+ "nocopy",
360
+ "line-numbers",
361
+ "linenumbers",
362
+ "runnable",
363
+ "show-line-numbers",
364
+ "showlinenumbers",
365
+ "wrap",
366
+ ]);
367
+ function parseCodeGroupMeta(meta) {
368
+ const parsed = parseMeta(meta);
369
+ if (parsed.title)
370
+ return parsed;
371
+ const trimmed = meta.trim();
372
+ const language = trimmed.split(/\s+/, 1)[0] ?? "";
373
+ const bareTitle = trimmed
374
+ .slice(language.length)
375
+ .trim()
376
+ .replace(/\{[^}]*\}/g, " ")
377
+ .split(/\s+/)
378
+ .find((part) => part && !part.includes("=") && !ignoredCodeGroupBareTitleTokens.has(part.toLowerCase()));
379
+ return {
380
+ ...parsed,
381
+ title: bareTitle ? bareTitle.replace(/^["']|["']$/g, "") : null,
382
+ };
383
+ }
384
+ function createCodeGroupTabValue(label, used) {
385
+ const slug = slugify(label) || `code-${used.size + 1}`;
386
+ let value = slug;
387
+ let suffix = 2;
388
+ while (used.has(value)) {
389
+ value = `${slug}-${suffix}`;
390
+ suffix += 1;
391
+ }
392
+ used.add(value);
393
+ return value;
394
+ }
355
395
  function wrapCodeWithCopy(html, rawCode, title, language) {
356
396
  const escapedRaw = rawCode
357
397
  .replace(/&/g, "&")
358
398
  .replace(/"/g, """)
359
399
  .replace(/</g, "&lt;")
360
400
  .replace(/>/g, "&gt;");
361
- const dataLang = language ? ` data-language="${String(language).replace(/"/g, "&quot;")}"` : "";
401
+ const dataLang = language ? ` data-language="${escapeHtml(String(language))}"` : "";
362
402
  const copyBtn = `<button class="fd-copy-btn" data-code="${escapedRaw}" title="Copy code"><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 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg></button>`;
363
403
  if (title) {
364
- return `<div class="fd-codeblock fd-codeblock--titled"${dataLang}><div class="fd-codeblock-title"><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="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/></svg><span class="fd-codeblock-title-text">${title}</span>${copyBtn}</div><div class="fd-codeblock-content">${html}</div></div>`;
404
+ return `<div class="fd-codeblock fd-codeblock--titled"${dataLang}><div class="fd-codeblock-title"><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="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/></svg><span class="fd-codeblock-title-text">${escapeHtml(title)}</span>${copyBtn}</div><div class="fd-codeblock-content">${html}</div></div>`;
365
405
  }
366
406
  return `<div class="fd-codeblock"${dataLang}>${copyBtn}<div class="fd-codeblock-content">${html}</div></div>`;
367
407
  }
@@ -389,8 +429,44 @@ export async function renderMarkdown(content, options = {}) {
389
429
  return "";
390
430
  const hl = await getHighlighter();
391
431
  let result = resolveDocsAgentMdxContent(content, "human");
392
- // ── Tabs blocks: <Tabs items={[...]}> ... </Tabs> ──
432
+ // ── Mintlify-style code groups: <CodeGroup> fenced code blocks </CodeGroup> ──
393
433
  const tabsBlocks = [];
434
+ result = result.replace(/<CodeGroup(?:\s+([^>]*?))?>([\s\S]*?)<\/CodeGroup>/g, (_, attrSource, body) => {
435
+ const attrs = parseJsxAttributes(attrSource ?? "");
436
+ const dropdown = toBoolean(attrs.dropdown, false);
437
+ const usedValues = new Set();
438
+ const panels = [];
439
+ const codeRegex = /```([^\n]*)\n([\s\S]*?)```/g;
440
+ let codeMatch;
441
+ while ((codeMatch = codeRegex.exec(body)) !== null) {
442
+ const { lang, title } = parseCodeGroupMeta(codeMatch[1]);
443
+ const label = title || lang || `Code ${panels.length + 1}`;
444
+ const value = createCodeGroupTabValue(label, usedValues);
445
+ const dedented = dedentCode(codeMatch[2]);
446
+ const { html, raw } = highlightCode(hl, dedented, lang);
447
+ panels.push({
448
+ label,
449
+ value,
450
+ html: wrapCodeWithCopy(html, raw, null, lang),
451
+ });
452
+ }
453
+ if (panels.length === 0)
454
+ return body;
455
+ let tabsHtml = `<div class="fd-tabs" data-tabs data-code-group${dropdown ? ' data-dropdown="true"' : ""}>`;
456
+ tabsHtml += `<div class="fd-tabs-list" role="tablist">`;
457
+ for (let i = 0; i < panels.length; i++) {
458
+ tabsHtml += `<button role="tab" class="fd-tab-trigger${i === 0 ? " fd-tab-active" : ""}" data-tab-value="${escapeHtml(panels[i].value)}" aria-selected="${i === 0}">${escapeHtml(panels[i].label)}</button>`;
459
+ }
460
+ tabsHtml += `</div>`;
461
+ for (let i = 0; i < panels.length; i++) {
462
+ tabsHtml += `<div class="fd-tab-panel${i === 0 ? " fd-tab-panel-active" : ""}" data-tab-panel="${escapeHtml(panels[i].value)}" role="tabpanel">${panels[i].html}</div>`;
463
+ }
464
+ tabsHtml += `</div>`;
465
+ const placeholder = `%%TABS_${tabsBlocks.length}%%`;
466
+ tabsBlocks.push(tabsHtml);
467
+ return placeholder;
468
+ });
469
+ // ── Tabs blocks: <Tabs items={[...]}> ... </Tabs> ──
394
470
  result = result.replace(/<Tabs\s+items=\{?\[([^\]]+)\]\}?>([\s\S]*?)<\/Tabs>/g, (_, itemsStr, body) => {
395
471
  const items = itemsStr.split(",").map((s) => s.trim().replace(/^["']|["']$/g, ""));
396
472
  const panels = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/svelte",
3
- "version": "0.1.124",
3
+ "version": "0.1.126",
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.124"
59
+ "@farming-labs/docs": "0.1.126"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "@farming-labs/docs": "*"