ardo 2.8.0 → 3.0.0

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.
@@ -364,7 +364,7 @@ declare function CodeBlock({ code: codeProp, language, title, lineNumbers, highl
364
364
  interface CodeGroupProps {
365
365
  /** CodeBlock components to display as tabs */
366
366
  children: React.ReactNode;
367
- /** Comma-separated tab labels (set by remarkContainersMdx from code block meta) */
367
+ /** Comma-separated tab labels */
368
368
  labels?: string;
369
369
  }
370
370
  /**
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-NBRHGTR2.js";
5
5
  import {
6
6
  generateApiDocs
7
- } from "./chunk-CYZLI4AU.js";
7
+ } from "./chunk-PGHUPTGL.js";
8
8
 
9
9
  // src/vite/plugin.ts
10
10
  import { reactRouter } from "@react-router/dev/vite";
@@ -12,7 +12,6 @@ import mdx from "@mdx-js/rollup";
12
12
  import remarkFrontmatter from "remark-frontmatter";
13
13
  import remarkMdxFrontmatter from "remark-mdx-frontmatter";
14
14
  import remarkGfm from "remark-gfm";
15
- import remarkDirective from "remark-directive";
16
15
  import rehypeShiki from "@shikijs/rehype";
17
16
 
18
17
  // src/markdown/shiki.ts
@@ -50,17 +49,29 @@ async function createShikiHighlighter(config) {
50
49
  const highlighter = await createHighlighter({
51
50
  themes,
52
51
  langs: [
52
+ // Web fundamentals
53
53
  "javascript",
54
54
  "typescript",
55
55
  "jsx",
56
56
  "tsx",
57
- "json",
58
57
  "html",
59
58
  "css",
59
+ "scss",
60
+ // Data & config formats
61
+ "json",
62
+ "jsonc",
63
+ "yaml",
64
+ "toml",
65
+ "xml",
66
+ "graphql",
67
+ // Markdown & docs
60
68
  "markdown",
69
+ "mdx",
70
+ // Shell & DevOps
61
71
  "bash",
62
72
  "shell",
63
- "yaml",
73
+ "dockerfile",
74
+ // General purpose
64
75
  "python",
65
76
  "rust",
66
77
  "go",
@@ -260,172 +271,6 @@ function ardoLineTransformer(options = {}) {
260
271
  };
261
272
  }
262
273
 
263
- // src/markdown/containers.ts
264
- import { visit as visit2 } from "unist-util-visit";
265
- var containerTypes = [
266
- "tip",
267
- "warning",
268
- "danger",
269
- "info",
270
- "note",
271
- "details",
272
- "code-group"
273
- ];
274
- var defaultTitles = {
275
- tip: "TIP",
276
- warning: "WARNING",
277
- danger: "DANGER",
278
- info: "INFO",
279
- note: "NOTE",
280
- details: "Details",
281
- "code-group": ""
282
- };
283
- function remarkContainers() {
284
- return function(tree) {
285
- visit2(tree, "containerDirective", (node) => {
286
- const type = node.name;
287
- if (!containerTypes.includes(type)) {
288
- return;
289
- }
290
- const data = node.data || (node.data = {});
291
- const titleNode = node.children[0];
292
- let customTitle;
293
- if (titleNode && titleNode.type === "paragraph" && titleNode.children[0]?.type === "text" && titleNode.data?.directiveLabel) {
294
- customTitle = titleNode.children[0].value;
295
- node.children.shift();
296
- }
297
- const title = customTitle || defaultTitles[type];
298
- if (type === "code-group") {
299
- data.hName = "div";
300
- data.hProperties = {
301
- className: ["ardo-code-group"]
302
- };
303
- const tabs = [];
304
- for (const child of node.children) {
305
- if (child.type === "code") {
306
- const codeNode = child;
307
- const meta = codeNode.meta || "";
308
- const labelMatch = meta.match(/\[([^\]]+)\]/);
309
- const label = labelMatch ? labelMatch[1] : codeNode.lang || "Code";
310
- tabs.push({ label, content: child });
311
- }
312
- }
313
- const tabsHtml = tabs.map(
314
- (tab, i) => `<button class="ardo-code-group-tab${i === 0 ? " active" : ""}" data-index="${i}">${escapeHtml2(tab.label)}</button>`
315
- ).join("");
316
- node.children = [
317
- {
318
- type: "html",
319
- value: `<div class="ardo-code-group-tabs">${tabsHtml}</div>`
320
- },
321
- {
322
- type: "html",
323
- value: '<div class="ardo-code-group-panels">'
324
- },
325
- ...tabs.map(
326
- (tab, i) => ({
327
- type: "html",
328
- value: `<div class="ardo-code-group-panel${i === 0 ? " active" : ""}" data-index="${i}">`
329
- })
330
- ),
331
- ...node.children.flatMap((child, _i) => [
332
- child,
333
- {
334
- type: "html",
335
- value: "</div>"
336
- }
337
- ]),
338
- {
339
- type: "html",
340
- value: "</div>"
341
- }
342
- ];
343
- return;
344
- }
345
- if (type === "details") {
346
- data.hName = "details";
347
- data.hProperties = {
348
- className: ["ardo-details"]
349
- };
350
- node.children.unshift({
351
- type: "html",
352
- value: `<summary class="ardo-details-summary">${escapeHtml2(title)}</summary>`
353
- });
354
- return;
355
- }
356
- data.hName = "div";
357
- data.hProperties = {
358
- className: ["ardo-container", `ardo-container-${type}`]
359
- };
360
- node.children.unshift({
361
- type: "html",
362
- value: `<p class="ardo-container-title">${escapeHtml2(title)}</p>`
363
- });
364
- });
365
- };
366
- }
367
- function escapeHtml2(text) {
368
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
369
- }
370
- var containerToComponent = {
371
- tip: "Tip",
372
- warning: "Warning",
373
- danger: "Danger",
374
- info: "Info",
375
- note: "Note"
376
- };
377
- function remarkContainersMdx() {
378
- return function(tree) {
379
- visit2(tree, "containerDirective", (node, index, parent) => {
380
- if (!parent || typeof index !== "number") return;
381
- if (node.name === "code-group") {
382
- const labels = node.children.filter((child) => child.type === "code").map((child) => {
383
- const meta = child.meta || "";
384
- const match = meta.match(/\[([^\]]+)\]/);
385
- return match ? match[1] : child.lang || "Code";
386
- });
387
- const jsxNode2 = {
388
- type: "mdxJsxFlowElement",
389
- name: "CodeGroup",
390
- attributes: [
391
- {
392
- type: "mdxJsxAttribute",
393
- name: "labels",
394
- value: labels.join(",")
395
- }
396
- ],
397
- children: node.children
398
- };
399
- parent.children[index] = jsxNode2;
400
- return;
401
- }
402
- const componentName = containerToComponent[node.name];
403
- if (!componentName) return;
404
- const titleNode = node.children[0];
405
- let customTitle;
406
- if (titleNode && titleNode.type === "paragraph" && titleNode.children[0]?.type === "text" && titleNode.data?.directiveLabel) {
407
- customTitle = titleNode.children[0].value;
408
- node.children.shift();
409
- }
410
- const attributes = [];
411
- if (customTitle) {
412
- attributes.push({
413
- type: "mdxJsxAttribute",
414
- name: "title",
415
- value: customTitle
416
- });
417
- }
418
- const jsxNode = {
419
- type: "mdxJsxFlowElement",
420
- name: componentName,
421
- attributes,
422
- children: node.children
423
- };
424
- parent.children[index] = jsxNode;
425
- });
426
- };
427
- }
428
-
429
274
  // src/vite/plugin.ts
430
275
  import fs2 from "fs/promises";
431
276
  import fsSync2 from "fs";
@@ -582,6 +427,89 @@ function outdent(text) {
582
427
  if (indent === 0 || indent === Infinity) return trimmed;
583
428
  return lines.map((line) => line.slice(indent)).join("\n");
584
429
  }
430
+ function findSelfClosingCodeBlocks(source) {
431
+ const results = [];
432
+ const tag = "<CodeBlock";
433
+ let searchFrom = 0;
434
+ while (true) {
435
+ const start = source.indexOf(tag, searchFrom);
436
+ if (start === -1) break;
437
+ const afterTag = start + tag.length;
438
+ if (afterTag >= source.length || !/\s/.test(source[afterTag])) {
439
+ searchFrom = afterTag;
440
+ continue;
441
+ }
442
+ let i = afterTag;
443
+ let depth = 0;
444
+ let inSingle = false;
445
+ let inDouble = false;
446
+ let inTemplate = false;
447
+ let found = false;
448
+ while (i < source.length) {
449
+ const ch = source[i];
450
+ if ((inSingle || inDouble || inTemplate) && ch === "\\") {
451
+ i += 2;
452
+ continue;
453
+ }
454
+ if (inSingle) {
455
+ if (ch === "'") inSingle = false;
456
+ i++;
457
+ continue;
458
+ }
459
+ if (inDouble) {
460
+ if (ch === '"') inDouble = false;
461
+ i++;
462
+ continue;
463
+ }
464
+ if (inTemplate) {
465
+ if (ch === "`") inTemplate = false;
466
+ i++;
467
+ continue;
468
+ }
469
+ if (ch === "'") {
470
+ inSingle = true;
471
+ i++;
472
+ continue;
473
+ }
474
+ if (ch === '"') {
475
+ inDouble = true;
476
+ i++;
477
+ continue;
478
+ }
479
+ if (ch === "`") {
480
+ inTemplate = true;
481
+ i++;
482
+ continue;
483
+ }
484
+ if (ch === "{") {
485
+ depth++;
486
+ i++;
487
+ continue;
488
+ }
489
+ if (ch === "}") {
490
+ depth--;
491
+ i++;
492
+ continue;
493
+ }
494
+ if (depth === 0 && ch === "/" && i + 1 < source.length && source[i + 1] === ">") {
495
+ const fullMatch = source.substring(start, i + 2);
496
+ const propsStr = source.substring(afterTag, i).trim();
497
+ results.push({ fullMatch, propsStr, index: start });
498
+ found = true;
499
+ searchFrom = i + 2;
500
+ break;
501
+ }
502
+ if (depth === 0 && ch === ">") {
503
+ searchFrom = i + 1;
504
+ found = true;
505
+ break;
506
+ }
507
+ i++;
508
+ }
509
+ if (!found) break;
510
+ }
511
+ return results;
512
+ }
585
513
  function ardoCodeBlockPlugin(markdownConfig) {
586
514
  return {
587
515
  name: "ardo:codeblock-highlight",
@@ -592,14 +520,12 @@ function ardoCodeBlockPlugin(markdownConfig) {
592
520
  if (id.includes("node_modules")) return;
593
521
  let result = code;
594
522
  let offset = 0;
595
- const propRegex = /<CodeBlock\s+([^>]*?)\/>/g;
596
- let match;
597
- while ((match = propRegex.exec(code)) !== null) {
598
- const fullMatch = match[0];
599
- const propsStr = match[1];
600
- const codeMatch = propsStr.match(/\bcode="((?:[^"\\]|\\.)*)"/s) || propsStr.match(/\bcode=\{"((?:[^"\\]|\\.)*)"\}/s);
523
+ const propMatches = findSelfClosingCodeBlocks(code);
524
+ for (const match of propMatches) {
525
+ const { fullMatch, propsStr } = match;
526
+ const codeMatch = propsStr.match(/\bcode="((?:[^"\\]|\\.)*)"/s) || propsStr.match(/\bcode=\{\s*"((?:[^"\\]|\\.)*)"\s*\}/s) || propsStr.match(/\bcode=\{\s*'((?:[^'\\]|\\.)*)'\s*\}/s);
601
527
  if (!codeMatch) continue;
602
- const langMatch = propsStr.match(/\blanguage="([^"]*)"/) || propsStr.match(/\blanguage=\{"([^"]*)"\}/);
528
+ const langMatch = propsStr.match(/\blanguage="([^"]*)"/) || propsStr.match(/\blanguage=\{"([^"]*)"\}/) || propsStr.match(/\blanguage=\{'([^']*)'\}/);
603
529
  if (!langMatch) continue;
604
530
  if (propsStr.includes("__html")) continue;
605
531
  const codeContent = codeMatch[1].replace(/\\n/g, "\n").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
@@ -618,11 +544,12 @@ function ardoCodeBlockPlugin(markdownConfig) {
618
544
  }
619
545
  const childrenRegex = /<CodeBlock\s+([^>]*?)>([\s\S]*?)<\/CodeBlock>/g;
620
546
  offset = result.length - code.length;
621
- while ((match = childrenRegex.exec(code)) !== null) {
622
- const fullMatch = match[0];
623
- const propsStr = match[1];
624
- let rawChildren = match[2];
625
- const langMatch = propsStr.match(/\blanguage="([^"]*)"/) || propsStr.match(/\blanguage=\{"([^"]*)"\}/);
547
+ let regexMatch;
548
+ while ((regexMatch = childrenRegex.exec(code)) !== null) {
549
+ const fullMatch = regexMatch[0];
550
+ const propsStr = regexMatch[1];
551
+ let rawChildren = regexMatch[2];
552
+ const langMatch = propsStr.match(/\blanguage="([^"]*)"/) || propsStr.match(/\blanguage=\{"([^"]*)"\}/) || propsStr.match(/\blanguage=\{'([^']*)'\}/);
626
553
  if (!langMatch) continue;
627
554
  if (propsStr.includes("__html")) continue;
628
555
  const templateMatch = rawChildren.match(/^\s*\{`([\s\S]*)`\}\s*$/);
@@ -638,7 +565,7 @@ function ardoCodeBlockPlugin(markdownConfig) {
638
565
  const escapedHtml = JSON.stringify(html);
639
566
  const escapedCode = JSON.stringify(codeContent);
640
567
  const newTag = `<CodeBlock __html={${escapedHtml}} code={${escapedCode}} ${propsStr} />`;
641
- result = result.slice(0, match.index + offset) + newTag + result.slice(match.index + offset + fullMatch.length);
568
+ result = result.slice(0, regexMatch.index + offset) + newTag + result.slice(regexMatch.index + offset + fullMatch.length);
642
569
  offset += newTag.length - fullMatch.length;
643
570
  } catch {
644
571
  }
@@ -928,8 +855,6 @@ export const meta = () => [${metaEntries.join(", ")}];
928
855
  remarkFrontmatter,
929
856
  [remarkMdxFrontmatter, { name: "frontmatter" }],
930
857
  remarkGfm,
931
- remarkDirective,
932
- remarkContainersMdx,
933
858
  remarkCodeMeta
934
859
  ],
935
860
  rehypePlugins: [[rehypeShiki, shikiOptions]],
@@ -1084,20 +1009,19 @@ import { unified } from "unified";
1084
1009
  import remarkParse from "remark-parse";
1085
1010
  import remarkGfm2 from "remark-gfm";
1086
1011
  import remarkFrontmatter2 from "remark-frontmatter";
1087
- import remarkDirective2 from "remark-directive";
1088
1012
  import remarkRehype from "remark-rehype";
1089
1013
  import rehypeStringify from "rehype-stringify";
1090
1014
  import matter2 from "gray-matter";
1091
1015
 
1092
1016
  // src/markdown/toc.ts
1093
- import { visit as visit3 } from "unist-util-visit";
1017
+ import { visit as visit2 } from "unist-util-visit";
1094
1018
  function remarkExtractToc(options) {
1095
1019
  const { tocExtraction, levels } = options;
1096
1020
  const [minLevel, maxLevel] = levels;
1097
1021
  return function(tree) {
1098
1022
  const headings = [];
1099
1023
  let headingIndex = 0;
1100
- visit3(tree, "heading", (node) => {
1024
+ visit2(tree, "heading", (node) => {
1101
1025
  if (node.depth < minLevel || node.depth > maxLevel) {
1102
1026
  return;
1103
1027
  }
@@ -1163,7 +1087,7 @@ function buildTocTree(headings, _minLevel) {
1163
1087
  }
1164
1088
 
1165
1089
  // src/markdown/links.ts
1166
- import { visit as visit4 } from "unist-util-visit";
1090
+ import { visit as visit3 } from "unist-util-visit";
1167
1091
  function rehypeLinks(options) {
1168
1092
  const { basePath } = options;
1169
1093
  const normalizedBase = basePath === "/" ? "" : basePath.replace(/\/$/, "");
@@ -1171,7 +1095,7 @@ function rehypeLinks(options) {
1171
1095
  if (!normalizedBase) {
1172
1096
  return;
1173
1097
  }
1174
- visit4(tree, "element", (node) => {
1098
+ visit3(tree, "element", (node) => {
1175
1099
  if (node.tagName === "a") {
1176
1100
  const href = node.properties?.href;
1177
1101
  if (typeof href === "string") {
@@ -1191,7 +1115,7 @@ async function transformMarkdown(content, config, options = {}) {
1191
1115
  const { basePath = "/", highlighter: providedHighlighter } = options;
1192
1116
  const tocExtraction = { toc: [] };
1193
1117
  const highlighter = providedHighlighter ?? await createShikiHighlighter(config);
1194
- const processor = unified().use(remarkParse).use(remarkFrontmatter2, ["yaml"]).use(remarkGfm2).use(remarkDirective2).use(remarkContainers).use(remarkExtractToc, { tocExtraction, levels: config.toc?.level ?? [2, 3] }).use(remarkRehype, { allowDangerousHtml: true }).use(rehypeShikiFromHighlighter, { highlighter, config }).use(rehypeLinks, { basePath }).use(rehypeStringify, { allowDangerousHtml: true });
1118
+ const processor = unified().use(remarkParse).use(remarkFrontmatter2, ["yaml"]).use(remarkGfm2).use(remarkExtractToc, { tocExtraction, levels: config.toc?.level ?? [2, 3] }).use(remarkRehype, { allowDangerousHtml: true }).use(rehypeShikiFromHighlighter, { highlighter, config }).use(rehypeLinks, { basePath }).use(rehypeStringify, { allowDangerousHtml: true });
1195
1119
  if (config.remarkPlugins) {
1196
1120
  for (const plugin of config.remarkPlugins) {
1197
1121
  processor.use(plugin);
@@ -1403,4 +1327,4 @@ export {
1403
1327
  getPageDataForRoute,
1404
1328
  generateSidebar2 as generateSidebar
1405
1329
  };
1406
- //# sourceMappingURL=chunk-YUGJQYEK.js.map
1330
+ //# sourceMappingURL=chunk-DEHRVW7C.js.map