bejamas 0.2.6 → 0.2.8

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.
@@ -0,0 +1,973 @@
1
+ import { a as extractComponentTagsFromMDX, b as logger, c as extractPropsFromDeclaredProps, d as parseJsDocMetadata, f as resolveOutDir, g as getConfig, h as toIdentifier, i as discoverExamples, l as normalizeBlockMDX, m as slugify, n as createSourceFileFromFrontmatter, o as extractFrontmatter, p as resolveUiRoot, r as detectHasImportTopLevel, s as extractPropsFromAstroProps, t as RESERVED_COMPONENTS, u as normalizeUsageMDX, y as spinner } from "./utils-gYZJgF4G.js";
2
+ import { createRequire } from "node:module";
3
+ import { dirname, extname, join, relative } from "path";
4
+ import { existsSync, mkdirSync } from "fs";
5
+ import { readFile, readdir, writeFile } from "fs/promises";
6
+
7
+ //#region rolldown:runtime
8
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
9
+
10
+ //#endregion
11
+ //#region src/docs/generate-mdx/examples.ts
12
+ function createImplicitSection() {
13
+ return {
14
+ title: null,
15
+ intro: [],
16
+ items: []
17
+ };
18
+ }
19
+ function normalizeSection(section) {
20
+ return {
21
+ title: section.title,
22
+ introMD: section.intro.join("\n").trim(),
23
+ items: section.items.map((item) => ({
24
+ title: item.title,
25
+ body: item.body.join("\n").trim()
26
+ }))
27
+ };
28
+ }
29
+ function pushItem(section, item) {
30
+ if (!section || !item) return;
31
+ if (!item.title.trim().length && !item.body.join("\n").trim().length) return;
32
+ section.items.push(item);
33
+ }
34
+ function pushSection(sections, section) {
35
+ if (!section) return;
36
+ const normalized = normalizeSection(section);
37
+ if (!normalized.title && !normalized.introMD.length && normalized.items.length === 0) return;
38
+ sections.push(normalized);
39
+ }
40
+ function extractHeading(line, level) {
41
+ const pattern = level === 2 ? /^##(?!#)\s+(.+)$/ : /^###(?!#)\s+(.+)$/;
42
+ const match = line.trim().match(pattern);
43
+ return match ? match[1].trim() : null;
44
+ }
45
+ function splitDescriptionAndSnippetRaw(body) {
46
+ if (!body || !body.trim().length) return {
47
+ descriptionMD: "",
48
+ snippet: ""
49
+ };
50
+ const lines = body.split("\n");
51
+ let snippetStartIdx = -1;
52
+ for (let i = 0; i < lines.length; i += 1) {
53
+ const ln = lines[i];
54
+ if (!ln.trim().length) continue;
55
+ if (/^\s*[<{]/.test(ln)) {
56
+ snippetStartIdx = i;
57
+ break;
58
+ }
59
+ }
60
+ if (snippetStartIdx <= 0) return {
61
+ descriptionMD: "",
62
+ snippet: body.trim()
63
+ };
64
+ return {
65
+ descriptionMD: lines.slice(0, snippetStartIdx).join("\n").trim(),
66
+ snippet: lines.slice(snippetStartIdx).join("\n").trim()
67
+ };
68
+ }
69
+ function splitAstroFrontmatter(sourceCode) {
70
+ const match = sourceCode.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
71
+ if (!match) return {
72
+ frontmatter: "",
73
+ markup: sourceCode.trim()
74
+ };
75
+ return {
76
+ frontmatter: match[1].trim(),
77
+ markup: match[2].trim()
78
+ };
79
+ }
80
+ function stripFrontmatterComments(frontmatter) {
81
+ if (!frontmatter || !frontmatter.length) return "";
82
+ return frontmatter.replace(/\/\*[\s\S]*?\*\//g, "\n").replace(/^[ \t]*\/\/.*$/gm, "").trim();
83
+ }
84
+ function isImportOnlyFrontmatter(frontmatter) {
85
+ const cleaned = stripFrontmatterComments(frontmatter);
86
+ if (!cleaned.length) return true;
87
+ let remaining = cleaned;
88
+ remaining = remaining.replace(/(?:^|\n)\s*import\s+(?:type\s+)?[\s\S]*?\s+from\s+['"][^'"]+['"]\s*;?(?=\n|$)/g, "\n").replace(/(?:^|\n)\s*import\s+['"][^'"]+['"]\s*;?(?=\n|$)/g, "\n").replace(/(?:^|\n)\s*export\s+(?:\*\s+from|\{[\s\S]*?\}\s+from)\s+['"][^'"]+['"]\s*;?(?=\n|$)/g, "\n").trim();
89
+ return remaining.replace(/[;\s]/g, "").length === 0;
90
+ }
91
+ function isAstroFrontmatterPreviewUnsafe(frontmatter) {
92
+ const cleaned = stripFrontmatterComments(frontmatter);
93
+ if (!cleaned.length) return false;
94
+ if (/\b(?:const|let|var|function|class|if|for|while|switch|try|catch|return|throw|await|new)\b|=>|Astro\./.test(cleaned)) return true;
95
+ return !isImportOnlyFrontmatter(cleaned);
96
+ }
97
+ function parseFenceInfo(infoRaw) {
98
+ const parts = (infoRaw || "").trim().split(/\s+/).filter((v) => v.length).map((v) => v.toLowerCase());
99
+ if (!parts.length) return {
100
+ lang: "",
101
+ flags: /* @__PURE__ */ new Set()
102
+ };
103
+ const [lang, ...flags] = parts;
104
+ return {
105
+ lang,
106
+ flags: new Set(flags)
107
+ };
108
+ }
109
+ function extractFirstAstroFence(body) {
110
+ if (!body || !body.trim().length) return null;
111
+ const lines = body.split("\n");
112
+ const outside = [];
113
+ const astroCode = [];
114
+ let inFence = false;
115
+ let currentFenceIsAstro = false;
116
+ let currentFenceSkipPreview = false;
117
+ let currentFenceEnableConsolePanel = false;
118
+ let capturedSkipPreview = false;
119
+ let capturedEnableConsolePanel = false;
120
+ let capturedAstro = false;
121
+ for (const line of lines) {
122
+ const trimmed = line.trim();
123
+ if (trimmed.startsWith("```")) {
124
+ if (!inFence) {
125
+ inFence = true;
126
+ const parsed = parseFenceInfo(trimmed.slice(3).trim());
127
+ currentFenceIsAstro = parsed.lang === "astro";
128
+ currentFenceSkipPreview = parsed.flags.has("nopreview");
129
+ currentFenceEnableConsolePanel = parsed.flags.has("console");
130
+ if (!currentFenceIsAstro || capturedAstro) outside.push(line);
131
+ continue;
132
+ }
133
+ if (currentFenceIsAstro && !capturedAstro) {
134
+ capturedAstro = true;
135
+ capturedSkipPreview = currentFenceSkipPreview;
136
+ capturedEnableConsolePanel = currentFenceEnableConsolePanel;
137
+ } else outside.push(line);
138
+ inFence = false;
139
+ currentFenceIsAstro = false;
140
+ currentFenceSkipPreview = false;
141
+ currentFenceEnableConsolePanel = false;
142
+ continue;
143
+ }
144
+ if (inFence && currentFenceIsAstro && !capturedAstro) {
145
+ astroCode.push(line);
146
+ continue;
147
+ }
148
+ outside.push(line);
149
+ }
150
+ if (!capturedAstro) return null;
151
+ return {
152
+ sourceCode: astroCode.join("\n").trim(),
153
+ descriptionMD: outside.join("\n").trim(),
154
+ skipPreview: capturedSkipPreview,
155
+ enableConsolePanel: capturedEnableConsolePanel
156
+ };
157
+ }
158
+ function parseExamplesSections(examplesMDX) {
159
+ if (!examplesMDX || !examplesMDX.trim().length) return [];
160
+ const sections = [];
161
+ const lines = examplesMDX.split("\n");
162
+ let currentSection = null;
163
+ let currentItem = null;
164
+ let inFence = false;
165
+ for (const line of lines) {
166
+ if (line.trim().startsWith("```")) {
167
+ inFence = !inFence;
168
+ if (!currentSection) currentSection = createImplicitSection();
169
+ if (currentItem) currentItem.body.push(line);
170
+ else currentSection.intro.push(line);
171
+ continue;
172
+ }
173
+ if (!inFence) {
174
+ const h2 = extractHeading(line, 2);
175
+ if (h2) {
176
+ pushItem(currentSection, currentItem);
177
+ currentItem = null;
178
+ pushSection(sections, currentSection);
179
+ currentSection = {
180
+ title: h2,
181
+ intro: [],
182
+ items: []
183
+ };
184
+ continue;
185
+ }
186
+ const h3 = extractHeading(line, 3);
187
+ if (h3) {
188
+ if (!currentSection) currentSection = createImplicitSection();
189
+ pushItem(currentSection, currentItem);
190
+ currentItem = {
191
+ title: h3,
192
+ body: []
193
+ };
194
+ continue;
195
+ }
196
+ }
197
+ if (!currentSection) currentSection = createImplicitSection();
198
+ if (currentItem) currentItem.body.push(line);
199
+ else currentSection.intro.push(line);
200
+ }
201
+ pushItem(currentSection, currentItem);
202
+ pushSection(sections, currentSection);
203
+ return sections;
204
+ }
205
+ function prepareExampleContent(body) {
206
+ if (!body || !body.trim().length) return {
207
+ descriptionMD: "",
208
+ snippet: "",
209
+ sourceCode: "",
210
+ sourceFromFence: false,
211
+ skipPreview: false,
212
+ enableConsolePanel: false
213
+ };
214
+ const fenced = extractFirstAstroFence(body);
215
+ if (fenced) {
216
+ const { frontmatter, markup } = splitAstroFrontmatter(fenced.sourceCode);
217
+ const unsafeFrontmatter = isAstroFrontmatterPreviewUnsafe(frontmatter);
218
+ return {
219
+ descriptionMD: fenced.descriptionMD,
220
+ snippet: markup,
221
+ sourceCode: fenced.sourceCode,
222
+ sourceFromFence: true,
223
+ skipPreview: fenced.skipPreview || unsafeFrontmatter,
224
+ enableConsolePanel: fenced.enableConsolePanel
225
+ };
226
+ }
227
+ const split = splitDescriptionAndSnippetRaw(body);
228
+ return {
229
+ descriptionMD: split.descriptionMD,
230
+ snippet: split.snippet,
231
+ sourceCode: split.snippet,
232
+ sourceFromFence: false,
233
+ skipPreview: false,
234
+ enableConsolePanel: false
235
+ };
236
+ }
237
+ function extractTags(block) {
238
+ if (!block || !block.length) return [];
239
+ const found = /* @__PURE__ */ new Set();
240
+ const tagRegex = /<([A-Z][A-Za-z0-9_]*)\b/g;
241
+ let match;
242
+ while ((match = tagRegex.exec(block)) !== null) found.add(match[1]);
243
+ return Array.from(found);
244
+ }
245
+ function extractComponentTagsFromPreviewMarkdown(block) {
246
+ if (!block || !block.length) return [];
247
+ const found = /* @__PURE__ */ new Set();
248
+ const lines = block.split("\n");
249
+ let inFence = false;
250
+ let fenceOpen = "";
251
+ let currentFenceLang = "";
252
+ const fenceBody = [];
253
+ for (const line of lines) {
254
+ const trimmed = line.trim();
255
+ if (trimmed.startsWith("```")) {
256
+ if (!inFence) {
257
+ inFence = true;
258
+ fenceOpen = line;
259
+ currentFenceLang = parseFenceInfo(trimmed.slice(3).trim()).lang;
260
+ fenceBody.length = 0;
261
+ continue;
262
+ }
263
+ if (currentFenceLang === "astro") {
264
+ const sourceCode = fenceBody.join("\n").trim();
265
+ const prepared = prepareExampleContent(`${fenceOpen}\n${sourceCode}\n${line}`);
266
+ if (!prepared.skipPreview) for (const tag of extractTags(prepared.snippet)) found.add(tag);
267
+ }
268
+ inFence = false;
269
+ fenceOpen = "";
270
+ currentFenceLang = "";
271
+ fenceBody.length = 0;
272
+ continue;
273
+ }
274
+ if (inFence) {
275
+ fenceBody.push(line);
276
+ continue;
277
+ }
278
+ for (const tag of extractTags(line)) found.add(tag);
279
+ }
280
+ return Array.from(found);
281
+ }
282
+ function extractComponentTagsFromExamplesSections(sections) {
283
+ if (!sections?.length) return [];
284
+ const found = /* @__PURE__ */ new Set();
285
+ for (const section of sections) {
286
+ for (const tag of extractComponentTagsFromPreviewMarkdown(section.introMD)) found.add(tag);
287
+ for (const item of section.items) {
288
+ const prepared = prepareExampleContent(item.body);
289
+ if (prepared.skipPreview) continue;
290
+ for (const tag of extractTags(prepared.snippet)) found.add(tag);
291
+ }
292
+ }
293
+ return Array.from(found);
294
+ }
295
+
296
+ //#endregion
297
+ //#region src/docs/generate-mdx/mdx-builder.ts
298
+ /**
299
+ * Check if an import path uses the new barrel export pattern (no .astro extension)
300
+ */
301
+ function isBarrelImport(path$1) {
302
+ return !path$1.endsWith(".astro");
303
+ }
304
+ /**
305
+ * Convert a PascalCase component name to its folder path (kebab-case).
306
+ * Examples:
307
+ * - "Card" → "card"
308
+ * - "CardHeader" → "card"
309
+ * - "InputGroup" → "input-group"
310
+ * - "InputGroupAddon" → "input-group"
311
+ * - "StickySurface" → "sticky-surface"
312
+ * - "RadioGroup" → "radio-group"
313
+ * - "RadioGroupItem" → "radio-group"
314
+ */
315
+ function componentToFolder(name) {
316
+ const sortedFamilies = [
317
+ "InputGroup",
318
+ "LinkGroup",
319
+ "RadioGroup",
320
+ "ButtonGroup",
321
+ "StickySurface"
322
+ ].sort((a, b) => b.length - a.length);
323
+ for (const family of sortedFamilies) if (name === family || name.startsWith(family)) return family.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
324
+ const baseMatch = name.match(/^[A-Z][a-z]*/);
325
+ return baseMatch ? baseMatch[0].toLowerCase() : name.toLowerCase();
326
+ }
327
+ function resolveComponentFolder(name, componentFolderMap) {
328
+ if (!componentFolderMap) return componentToFolder(name);
329
+ const direct = componentFolderMap[name];
330
+ if (direct && direct.length) return direct;
331
+ const prefixMatch = Object.keys(componentFolderMap).filter((key) => name.startsWith(key)).sort((a, b) => b.length - a.length)[0];
332
+ if (prefixMatch) return componentFolderMap[prefixMatch];
333
+ return componentToFolder(name);
334
+ }
335
+ /**
336
+ * Group component names by their folder path
337
+ */
338
+ function groupComponentsByFolder(components, componentFolderMap) {
339
+ const groups = /* @__PURE__ */ new Map();
340
+ for (const comp of components) {
341
+ const folder = resolveComponentFolder(comp, componentFolderMap);
342
+ if (!groups.has(folder)) groups.set(folder, []);
343
+ groups.get(folder).push(comp);
344
+ }
345
+ return groups;
346
+ }
347
+ /**
348
+ * Generate import lines for UI components using the barrel import pattern
349
+ */
350
+ function generateBarrelImports(components, componentsAlias, componentFolderMap) {
351
+ const groups = groupComponentsByFolder(components, componentFolderMap);
352
+ const lines = [];
353
+ const sortedFolders = Array.from(groups.keys()).sort();
354
+ for (const folder of sortedFolders) {
355
+ const names = groups.get(folder).sort();
356
+ lines.push(`import { ${names.join(", ")} } from '${componentsAlias}/${folder}';`);
357
+ }
358
+ return lines;
359
+ }
360
+ /**
361
+ * Generate import lines for UI components using the old default import pattern
362
+ */
363
+ function generateDefaultImports(components, componentsAlias) {
364
+ return components.slice().sort().map((name) => `import ${name} from '${componentsAlias}/${name}.astro';`);
365
+ }
366
+ function buildMdx(params) {
367
+ const { importName, importPath, title, description, descriptionBodyMDX, usageMDX, hasImport, propsList, propsTable, examples, examplesSections, componentFolderMap, autoImports, lucideIcons, primaryExampleMDX, componentSource, commandName, figmaUrl, componentsAlias, namedExports, apiMDX } = params;
368
+ const useBarrelPattern = isBarrelImport(importPath);
369
+ const sortedLucide = (lucideIcons ?? []).slice().sort();
370
+ const externalTopImports = [`import { Tabs as DocsTabs, TabItem as DocsTabItem } from '@astrojs/starlight/components';`, sortedLucide.length ? `import { ${sortedLucide.join(", ")} } from '@lucide/astro';` : null].filter((v) => v != null).slice().sort((a, b) => String(a).localeCompare(String(b)));
371
+ const sortedUiAuto = (autoImports ?? []).slice().sort();
372
+ const uiAutoLines = useBarrelPattern ? generateBarrelImports(sortedUiAuto, componentsAlias, componentFolderMap) : generateDefaultImports(sortedUiAuto, componentsAlias);
373
+ const exampleLines = (examples ?? []).map((ex) => `import ${ex.importName} from '${ex.importPath}';`).sort((a, b) => a.localeCompare(b));
374
+ let mainImportLine = null;
375
+ if (!hasImport) if (useBarrelPattern) mainImportLine = `import { ${[importName, ...namedExports ?? []].sort().join(", ")} } from '${importPath}';`;
376
+ else mainImportLine = `import ${importName} from '${importPath}';`;
377
+ const internalTopImports = [
378
+ mainImportLine,
379
+ ...uiAutoLines,
380
+ ...exampleLines
381
+ ].filter((v) => v != null).slice().sort((a, b) => String(a).localeCompare(String(b)));
382
+ const importLines = [
383
+ ...externalTopImports,
384
+ externalTopImports.length && internalTopImports.length ? "" : null,
385
+ ...internalTopImports
386
+ ].filter((v) => v !== null && v !== void 0);
387
+ const extractTags$1 = (snippet) => {
388
+ const found = /* @__PURE__ */ new Set();
389
+ const tagRegex = /<([A-Z][A-Za-z0-9_]*)\b/g;
390
+ let m;
391
+ while ((m = tagRegex.exec(snippet)) !== null) found.add(m[1]);
392
+ return found;
393
+ };
394
+ const buildSnippetImportLines = (snippet) => {
395
+ if (!snippet || !snippet.length) return [];
396
+ const used = extractTags$1(snippet);
397
+ const usedIcons = sortedLucide.filter((n) => used.has(n));
398
+ const usedUi = (autoImports ?? []).filter((n) => used.has(n));
399
+ const includeMain = !hasImport && used.has(importName);
400
+ const usedNamedExports = useBarrelPattern && namedExports ? namedExports.filter((n) => used.has(n)) : [];
401
+ const external = [];
402
+ if (usedIcons.length) external.push(`import { ${usedIcons.join(", ")} } from '@lucide/astro';`);
403
+ const internal = [];
404
+ if (useBarrelPattern) {
405
+ if (includeMain || usedNamedExports.length > 0) {
406
+ const mainExports = [...includeMain ? [importName] : [], ...usedNamedExports].sort();
407
+ internal.push(`import { ${mainExports.join(", ")} } from '${importPath}';`);
408
+ }
409
+ if (usedUi.length > 0) internal.push(...generateBarrelImports(usedUi, componentsAlias, componentFolderMap));
410
+ } else {
411
+ if (includeMain) internal.push(`import ${importName} from '${importPath}';`);
412
+ internal.push(...usedUi.slice().sort().map((name) => `import ${name} from '${componentsAlias}/${name}.astro';`));
413
+ }
414
+ const externalSorted = external.slice().sort((a, b) => a.localeCompare(b));
415
+ const internalSorted = internal.slice().sort((a, b) => a.localeCompare(b));
416
+ return [
417
+ ...externalSorted,
418
+ externalSorted.length && internalSorted.length ? "" : null,
419
+ ...internalSorted
420
+ ].filter((v) => v !== null && v !== void 0);
421
+ };
422
+ let consolePreviewCounter = 0;
423
+ const wrapTextNodes = (snippet) => {
424
+ if (!snippet) return snippet;
425
+ return snippet.replace(/>([^<]+)</g, (match, inner) => {
426
+ const trimmed = inner.trim();
427
+ if (!trimmed.length) return match;
428
+ if (/^\{[\s\S]*\}$/.test(trimmed)) return match;
429
+ if (/\{[^}]*\}/.test(inner)) return match;
430
+ return `>{${JSON.stringify(inner)}}<`;
431
+ });
432
+ };
433
+ /**
434
+ * Normalize whitespace in preview content.
435
+ * This collapses ALL newlines and multiple spaces into single spaces to prevent
436
+ * MDX parsing issues. In particular, a '>' at the start of a line is interpreted
437
+ * as a block quote marker by MDX, which causes "Unexpected lazy line" errors.
438
+ */
439
+ const normalizeInlineWhitespace = (snippet) => {
440
+ if (!snippet) return snippet;
441
+ return snippet.replace(/\s+/g, " ").trim();
442
+ };
443
+ /**
444
+ * Convert <p> tags that contain component tags to <span> tags.
445
+ * This is necessary because components may render as block elements (like <div>),
446
+ * and HTML doesn't allow block elements inside <p>. The browser would automatically
447
+ * close the <p> before any block element, breaking the layout.
448
+ */
449
+ const convertParagraphsWithComponents = (snippet) => {
450
+ if (!snippet) return snippet;
451
+ return snippet.replace(/<p(\s[^>]*)?>([^]*?)<\/p>/gi, (match, attrs, content) => {
452
+ if (/<[A-Z][A-Za-z0-9]*/.test(content)) return `<span${attrs || ""} style="display:block">${content}</span>`;
453
+ return match;
454
+ });
455
+ };
456
+ const extractInlineScripts = (snippet) => {
457
+ if (!snippet) return {
458
+ markup: snippet,
459
+ scripts: []
460
+ };
461
+ const scripts = [];
462
+ return {
463
+ markup: snippet.replace(/<script\b[^>]*>([\s\S]*?)<\/script>/gi, (_, scriptBody) => {
464
+ scripts.push((scriptBody || "").trim());
465
+ return "";
466
+ }),
467
+ scripts
468
+ };
469
+ };
470
+ const toMdxPreview = (snippet, options = {}) => {
471
+ if (!snippet) return {
472
+ markup: "",
473
+ scripts: []
474
+ };
475
+ const { enableConsolePanel = false } = options;
476
+ const extracted = extractInlineScripts(snippet);
477
+ const withConvertedParagraphs = convertParagraphsWithComponents(extracted.markup.replace(/<!--([\s\S]*?)-->/g, "{/*$1*/}"));
478
+ if (/<p[\s>]/i.test(withConvertedParagraphs)) return {
479
+ markup: normalizeInlineWhitespace(withConvertedParagraphs),
480
+ scripts: enableConsolePanel ? extracted.scripts : []
481
+ };
482
+ return {
483
+ markup: wrapTextNodes(normalizeInlineWhitespace(withConvertedParagraphs)),
484
+ scripts: enableConsolePanel ? extracted.scripts : []
485
+ };
486
+ };
487
+ const buildConsoleRuntimeSource = (rootId, panelId, userScript) => {
488
+ return `(function () {
489
+ var root = document.getElementById(${JSON.stringify(rootId)});
490
+ var panel = document.getElementById(${JSON.stringify(panelId)});
491
+ if (!root || !panel) return;
492
+
493
+ var placeholder = panel.textContent || "Waiting for logs...";
494
+ var hasLogs = false;
495
+
496
+ var toText = function (value) {
497
+ if (typeof value === "string") return value;
498
+ if (value === undefined) return "undefined";
499
+ if (value === null) return "null";
500
+ try {
501
+ return JSON.stringify(value);
502
+ } catch (_error) {
503
+ return String(value);
504
+ }
505
+ };
506
+
507
+ var append = function (level, args) {
508
+ var stamp = new Date().toLocaleTimeString();
509
+ var body = Array.prototype.map.call(args, toText).join(" ");
510
+ var line = "[" + stamp + "] " + String(level).toUpperCase() + ": " + body;
511
+ var current = panel.textContent || "";
512
+ if (!hasLogs && current.trim() === placeholder.trim()) {
513
+ panel.textContent = line;
514
+ } else {
515
+ panel.textContent = current ? current + "\\n" + line : line;
516
+ }
517
+ hasLogs = true;
518
+ panel.scrollTop = panel.scrollHeight;
519
+ };
520
+
521
+ var methods = ["log", "info", "warn", "error"];
522
+ var proxyConsole = Object.create(console);
523
+ for (var i = 0; i < methods.length; i += 1) {
524
+ (function (methodName) {
525
+ var fallback = typeof console.log === "function" ? console.log.bind(console) : function () {};
526
+ var original =
527
+ typeof console[methodName] === "function"
528
+ ? console[methodName].bind(console)
529
+ : fallback;
530
+ proxyConsole[methodName] = function () {
531
+ var args = Array.prototype.slice.call(arguments);
532
+ original.apply(console, args);
533
+ append(methodName, args);
534
+ };
535
+ })(methods[i]);
536
+ }
537
+
538
+ try {
539
+ var run = new Function("console", "root", "panel", ${JSON.stringify(userScript)});
540
+ run(proxyConsole, root, panel);
541
+ } catch (error) {
542
+ var fallbackError = typeof console.error === "function" ? console.error.bind(console) : function () {};
543
+ fallbackError(error);
544
+ append("error", [error]);
545
+ }
546
+ })();`;
547
+ };
548
+ const renderConsoleScripts = (rootId, panelId, scripts) => {
549
+ if (!scripts.length) return "";
550
+ return scripts.filter((script) => script && script.trim().length).map((script) => {
551
+ const runtimeSource = buildConsoleRuntimeSource(rootId, panelId, script);
552
+ return `<script type="module" src="data:text/javascript;charset=utf-8,${encodeURIComponent(runtimeSource)}"><\/script>`;
553
+ }).join("\n");
554
+ };
555
+ const renderPreviewBlock = (snippet, options = {}) => {
556
+ const { enableConsolePanel = false } = options;
557
+ const preparedPreview = toMdxPreview(snippet, options);
558
+ if (!preparedPreview.markup || !preparedPreview.markup.length) return "";
559
+ if (!enableConsolePanel) return `<div class="not-content sl-bejamas-component-preview flex justify-center px-4 md:px-10 py-12 border border-border rounded-t-lg min-h-72 items-center">
560
+ ${preparedPreview.markup}
561
+ </div>`;
562
+ consolePreviewCounter += 1;
563
+ const rootId = `sl-bejamas-console-preview-${consolePreviewCounter}`;
564
+ const panelId = `${rootId}-output`;
565
+ const scriptTags = renderConsoleScripts(rootId, panelId, preparedPreview.scripts);
566
+ return [
567
+ `<div id="${rootId}" class="not-content sl-bejamas-component-preview flex justify-center px-4 md:px-10 py-12 border border-border rounded-t-lg min-h-72 items-center">`,
568
+ preparedPreview.markup,
569
+ "</div>",
570
+ `<div class="not-content sl-bejamas-console-log-shell px-4 md:px-10 py-4 border border-border border-t-0">`,
571
+ `<pre id="${panelId}" data-slot="event-log" class="sl-bejamas-console-log w-full p-3 rounded-md bg-muted text-xs font-mono text-muted-foreground min-h-[80px] max-h-[200px] overflow-y-auto">Waiting for logs...</pre>`,
572
+ scriptTags && scriptTags.length ? scriptTags : null,
573
+ "</div>"
574
+ ].filter((part) => part !== null).join("\n");
575
+ };
576
+ const renderAstroPreviewsInMarkdown = (block) => {
577
+ if (!block || !block.length) return block;
578
+ const lines = block.split("\n");
579
+ const out = [];
580
+ let inFence = false;
581
+ let fenceOpen = "";
582
+ let currentFenceLang = "";
583
+ const fenceBody = [];
584
+ for (const line of lines) {
585
+ const trimmed = line.trim();
586
+ if (trimmed.startsWith("```")) {
587
+ if (!inFence) {
588
+ inFence = true;
589
+ fenceOpen = line;
590
+ const parsed = parseFenceInfo(trimmed.slice(3).trim());
591
+ currentFenceLang = parsed.lang;
592
+ parsed.flags;
593
+ fenceBody.length = 0;
594
+ continue;
595
+ }
596
+ if (currentFenceLang === "astro") {
597
+ const sourceCode = fenceBody.join("\n").trim();
598
+ const prepared = prepareExampleContent(`${fenceOpen}\n${sourceCode}\n${line}`);
599
+ if (prepared.snippet && prepared.snippet.length && !prepared.skipPreview) {
600
+ const previewBlock = renderPreviewBlock(prepared.snippet, { enableConsolePanel: prepared.enableConsolePanel });
601
+ if (previewBlock.length) out.push(previewBlock);
602
+ out.push("");
603
+ }
604
+ }
605
+ out.push(fenceOpen);
606
+ if (fenceBody.length) out.push(...fenceBody);
607
+ out.push(line);
608
+ inFence = false;
609
+ fenceOpen = "";
610
+ currentFenceLang = "";
611
+ fenceBody.length = 0;
612
+ continue;
613
+ }
614
+ if (inFence) {
615
+ fenceBody.push(line);
616
+ continue;
617
+ }
618
+ out.push(line);
619
+ }
620
+ if (inFence) {
621
+ out.push(fenceOpen);
622
+ if (fenceBody.length) out.push(...fenceBody);
623
+ }
624
+ return out.join("\n").trim();
625
+ };
626
+ const renderedDescriptionBodyMDX = renderAstroPreviewsInMarkdown(descriptionBodyMDX || "");
627
+ const renderedUsageMDX = renderAstroPreviewsInMarkdown(usageMDX || "");
628
+ const renderedApiMDX = renderAstroPreviewsInMarkdown(apiMDX || "");
629
+ const primaryExampleSection = primaryExampleMDX && primaryExampleMDX.length ? `${renderPreviewBlock(primaryExampleMDX)}
630
+
631
+ \`\`\`astro
632
+ ${(() => {
633
+ const lines = buildSnippetImportLines(primaryExampleMDX);
634
+ return lines.length ? `---\n${lines.join("\n")}\n---\n\n` : "";
635
+ })()}${primaryExampleMDX}
636
+ \`\`\`` : null;
637
+ const renderExampleItem = (headingLevel, headingTitle, body) => {
638
+ const prepared = prepareExampleContent(body);
639
+ const blocks = [`${headingLevel} ${headingTitle}`];
640
+ if (prepared.descriptionMD && prepared.descriptionMD.length) blocks.push(prepared.descriptionMD);
641
+ if (prepared.snippet && prepared.snippet.length && prepared.sourceCode && prepared.sourceCode.length && !prepared.skipPreview) blocks.push(renderPreviewBlock(prepared.snippet, { enableConsolePanel: prepared.enableConsolePanel }));
642
+ if (prepared.sourceCode && prepared.sourceCode.length) {
643
+ const sourceBlock = prepared.sourceFromFence ? prepared.sourceCode : `${(() => {
644
+ const lines = buildSnippetImportLines(prepared.sourceCode);
645
+ return lines.length ? `---\n${lines.join("\n")}\n---\n\n` : "";
646
+ })()}${prepared.sourceCode}`;
647
+ blocks.push(`\`\`\`astro
648
+ ${sourceBlock}
649
+ \`\`\``);
650
+ }
651
+ return blocks.join("\n\n");
652
+ };
653
+ const renderedExampleSections = [];
654
+ if (examplesSections && examplesSections.length) {
655
+ let implicitExampleCounter = 1;
656
+ for (const section of examplesSections) {
657
+ const sectionParts = [];
658
+ const hasSectionTitle = !!(section.title && section.title.length);
659
+ if (hasSectionTitle) sectionParts.push(`### ${section.title}`);
660
+ if (section.introMD && section.introMD.length) sectionParts.push(section.introMD);
661
+ if (section.items && section.items.length) {
662
+ const itemHeadingLevel = hasSectionTitle ? "####" : "###";
663
+ for (const item of section.items) sectionParts.push(renderExampleItem(itemHeadingLevel, item.title, item.body));
664
+ } else if (!hasSectionTitle && section.introMD && section.introMD.length) {
665
+ const prepared = prepareExampleContent(section.introMD);
666
+ if (prepared.snippet && prepared.snippet.length) {
667
+ sectionParts.length = 0;
668
+ sectionParts.push(renderExampleItem("###", `Example ${implicitExampleCounter}`, section.introMD));
669
+ implicitExampleCounter += 1;
670
+ }
671
+ }
672
+ if (sectionParts.length) renderedExampleSections.push(sectionParts.join("\n\n").trim());
673
+ }
674
+ }
675
+ if (examples && examples.length) for (const ex of examples) renderedExampleSections.push(`### ${ex.title}
676
+
677
+ <div class="not-content">
678
+ <${ex.importName} />
679
+ </div>
680
+
681
+ \`\`\`astro
682
+ ${ex.source}
683
+ \`\`\``);
684
+ const formatDefault = (val) => {
685
+ if (val == null) return "";
686
+ let raw = String(val).trim();
687
+ if (!raw.length) return "";
688
+ raw = raw.replace(/[\u201C\u201D\u201E\u201F]/g, "\"").replace(/[\u2018\u2019]/g, "'");
689
+ const isSingleQuoted = /^'[^']*'$/.test(raw);
690
+ const isDoubleQuoted = /^"[^"]*"$/.test(raw);
691
+ const isBacktickSimple = /^`[^`]*`$/.test(raw) && raw.indexOf("${") === -1;
692
+ let content = raw;
693
+ if (isSingleQuoted || isDoubleQuoted || isBacktickSimple) content = `"${raw.slice(1, -1)}"`;
694
+ content = content.replace(/\|/g, "\\|");
695
+ const hasTick = content.includes("`");
696
+ const hasDoubleTick = content.includes("``");
697
+ const fence = !hasTick ? "`" : !hasDoubleTick ? "``" : "```";
698
+ return `${fence}${content}${fence}`;
699
+ };
700
+ const installationSection = `## Installation
701
+
702
+ <DocsTabs syncKey="pkg">
703
+ <DocsTabItem label="bun">
704
+ \`\`\`bash
705
+ bunx bejamas add ${commandName}
706
+ \`\`\`
707
+ </DocsTabItem>
708
+ <DocsTabItem label="npm">
709
+ \`\`\`bash
710
+ npx bejamas add ${commandName}
711
+ \`\`\`
712
+ </DocsTabItem>
713
+ <DocsTabItem label="pnpm">
714
+ \`\`\`bash
715
+ pnpm dlx bejamas add ${commandName}
716
+ \`\`\`
717
+ </DocsTabItem>
718
+ <DocsTabItem label="yarn">
719
+ \`\`\`bash
720
+ yarn dlx bejamas add ${commandName}
721
+ \`\`\`
722
+ </DocsTabItem>
723
+ </DocsTabs>`;
724
+ const serializeFrontmatter = (label, value) => {
725
+ if (!value || !value.length) return null;
726
+ return `${label}: ${JSON.stringify(value)}`;
727
+ };
728
+ return [
729
+ "---",
730
+ serializeFrontmatter("title", title),
731
+ serializeFrontmatter("description", description),
732
+ serializeFrontmatter("figmaUrl", figmaUrl),
733
+ "---",
734
+ "",
735
+ ...importLines,
736
+ importLines.length ? "" : null,
737
+ renderedDescriptionBodyMDX && renderedDescriptionBodyMDX.length ? renderedDescriptionBodyMDX : null,
738
+ renderedDescriptionBodyMDX && renderedDescriptionBodyMDX.length ? "" : null,
739
+ primaryExampleSection,
740
+ primaryExampleSection ? "" : null,
741
+ installationSection,
742
+ "",
743
+ renderedUsageMDX && renderedUsageMDX.length ? `## Usage\n\n${renderedUsageMDX}` : null,
744
+ "",
745
+ propsTable && propsTable.length ? `## Props\n\n| Prop | Type | Default |\n|---|---|---|\n${propsTable.map((p) => `| <code>${p.name}</code> | \`${(p.type || "").replace(/\|/g, "\\|")}\` | ${formatDefault(p.defaultValue)} |`).join("\n")}` : propsList ? `## Props\n\n${propsList}` : null,
746
+ propsTable && propsTable.length || propsList ? "" : null,
747
+ renderedExampleSections.length ? `## Examples\n\n` + renderedExampleSections.join("\n\n") : null,
748
+ renderedExampleSections.length ? "" : null,
749
+ renderedApiMDX && renderedApiMDX.length ? `## API Reference\n\n${renderedApiMDX}` : null
750
+ ].filter((v) => v !== null && v !== void 0).join("\n").trim() + "\n";
751
+ }
752
+
753
+ //#endregion
754
+ //#region src/docs/generate-mdx/index.ts
755
+ /**
756
+ * Discover components in the components directory.
757
+ * Supports both:
758
+ * - Old pattern: flat .astro files in components/
759
+ * - New pattern: folders with index.ts barrel exports
760
+ */
761
+ async function discoverComponents(componentsDir) {
762
+ const entries = [];
763
+ const dirEntries = await readdir(componentsDir, { withFileTypes: true });
764
+ for (const entry of dirEntries) if (entry.isDirectory()) {
765
+ const folderPath = join(componentsDir, entry.name);
766
+ const indexPath = join(folderPath, "index.ts");
767
+ if (existsSync(indexPath)) {
768
+ const namedExports = parseBarrelExports(await readFile(indexPath, "utf-8"));
769
+ const mainComponentName = findMainComponent(namedExports, entry.name);
770
+ if (mainComponentName) {
771
+ const mainFilePath = join(folderPath, `${mainComponentName}.astro`);
772
+ if (existsSync(mainFilePath)) {
773
+ const subComponents = namedExports.filter((n) => n !== mainComponentName);
774
+ entries.push({
775
+ name: mainComponentName,
776
+ filePath: mainFilePath,
777
+ folderName: entry.name,
778
+ isFolder: true,
779
+ namedExports: subComponents
780
+ });
781
+ }
782
+ }
783
+ }
784
+ } else if (entry.isFile() && extname(entry.name).toLowerCase() === ".astro") {
785
+ const componentName = entry.name.replace(/\.astro$/i, "");
786
+ entries.push({
787
+ name: componentName,
788
+ filePath: join(componentsDir, entry.name),
789
+ folderName: "",
790
+ isFolder: false,
791
+ namedExports: []
792
+ });
793
+ }
794
+ return entries;
795
+ }
796
+ function buildComponentFolderMap(components) {
797
+ const map = {};
798
+ for (const component of components) {
799
+ if (!component.isFolder || !component.folderName) continue;
800
+ map[component.name] = component.folderName;
801
+ for (const sub of component.namedExports) map[sub] = component.folderName;
802
+ }
803
+ return map;
804
+ }
805
+ /**
806
+ * Parse a barrel (index.ts) file to extract named exports.
807
+ * Handles patterns like:
808
+ * - export { default as Card } from "./Card.astro";
809
+ * - export { default as CardHeader } from "./CardHeader.astro";
810
+ */
811
+ function parseBarrelExports(content) {
812
+ const exports = [];
813
+ const exportRegex = /export\s*\{\s*default\s+as\s+(\w+)\s*\}/g;
814
+ let match;
815
+ while ((match = exportRegex.exec(content)) !== null) exports.push(match[1]);
816
+ return exports;
817
+ }
818
+ /**
819
+ * Find the main component from a list of exports.
820
+ * The main component is typically the one that matches the folder name (PascalCase).
821
+ */
822
+ function findMainComponent(exports, folderName) {
823
+ if (exports.length === 0) return null;
824
+ const expectedName = folderName.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
825
+ const exactMatch = exports.find((e) => e === expectedName);
826
+ if (exactMatch) return exactMatch;
827
+ return exports[0];
828
+ }
829
+ async function main() {
830
+ const DEBUG = process.env.BEJAMAS_DEBUG === "1" || process.env.BEJAMAS_DEBUG === "true";
831
+ const cwd = process.env.BEJAMAS_DOCS_CWD && process.env.BEJAMAS_DOCS_CWD.length ? process.env.BEJAMAS_DOCS_CWD : process.cwd();
832
+ const config = await getConfig(cwd);
833
+ const componentsAlias = (config?.aliases?.ui || config?.aliases?.components || "@bejamas/ui/components").replace(/\/$/, "");
834
+ const componentsDirFromConfig = config?.resolvedPaths?.ui || config?.resolvedPaths?.components;
835
+ let uiRoot = resolveUiRoot(cwd);
836
+ let componentsDir = join(uiRoot, "src", "components");
837
+ if (componentsDirFromConfig) {
838
+ componentsDir = componentsDirFromConfig;
839
+ uiRoot = dirname(dirname(componentsDirFromConfig));
840
+ }
841
+ if (!existsSync(componentsDir)) componentsDir = join(uiRoot, "src", "components");
842
+ const outDir = resolveOutDir(cwd);
843
+ mkdirSync(outDir, { recursive: true });
844
+ if (DEBUG) {
845
+ logger.info(`[docs-generator] cwd: ${cwd}`);
846
+ logger.info(`[docs-generator] uiRoot: ${uiRoot}`);
847
+ logger.info(`[docs-generator] componentsDir: ${componentsDir}`);
848
+ logger.info(`[docs-generator] outDir: ${outDir}`);
849
+ }
850
+ const components = await discoverComponents(componentsDir);
851
+ const componentFolderMap = buildComponentFolderMap(components);
852
+ if (DEBUG) {
853
+ logger.info(`[docs-generator] components found: ${components.length}`);
854
+ if (components.length) logger.info(`[docs-generator] first few: ${components.slice(0, 5).map((c) => c.name).join(", ")}`);
855
+ }
856
+ let generatedCount = 0;
857
+ const total = components.length;
858
+ const spin = spinner(`Generating docs (0/${total})`).start();
859
+ for (const component of components) {
860
+ const { name: pascal, filePath, folderName, isFolder, namedExports } = component;
861
+ const astroFile = await readFile(filePath, "utf-8");
862
+ const frontmatterCode = extractFrontmatter(astroFile);
863
+ const sourceFile = createSourceFileFromFrontmatter(frontmatterCode);
864
+ const meta = parseJsDocMetadata(frontmatterCode);
865
+ const declaredProps = extractPropsFromDeclaredProps(sourceFile);
866
+ const destructuredProps = extractPropsFromAstroProps(sourceFile);
867
+ const defaultsMap = /* @__PURE__ */ new Map();
868
+ for (const p of destructuredProps) if (p.name && p.hasDefault) defaultsMap.set(p.name, p.defaultValue || null);
869
+ const propsTable = (declaredProps.length ? declaredProps : []).map((p) => ({
870
+ name: p.name,
871
+ type: p.type,
872
+ required: !p.optional,
873
+ defaultValue: defaultsMap.has(p.name) ? defaultsMap.get(p.name) : null
874
+ }));
875
+ const slug = slugify(pascal);
876
+ const title = meta.title || meta.name || pascal;
877
+ const description = meta.description || "";
878
+ const descriptionBodyMDX = meta.descriptionBodyMDX || "";
879
+ const figmaUrl = meta.figmaUrl || "";
880
+ const propsList = "";
881
+ const importName = pascal;
882
+ const importPath = isFolder ? `${componentsAlias}/${folderName}` : `${componentsAlias}/${pascal}.astro`;
883
+ const { text: usageMDX, hasImport: hasImportUsage } = normalizeUsageMDX(meta.usageMDX || "", pascal);
884
+ const primaryExampleMDX = normalizeBlockMDX(meta.primaryExampleMDX || "").trim();
885
+ const examplesMDX = normalizeBlockMDX(meta.examplesMDX || "").trim();
886
+ const apiMDX = normalizeBlockMDX(meta.apiMDX || "").trim();
887
+ const hasImportExamples = detectHasImportTopLevel(examplesMDX, pascal);
888
+ const hasImportPrimary = detectHasImportTopLevel(primaryExampleMDX, pascal);
889
+ const hasImport = hasImportUsage || hasImportExamples || hasImportPrimary;
890
+ let exampleRelPaths = [];
891
+ let examples = [];
892
+ const parsedExamplesSections = parseExamplesSections(examplesMDX);
893
+ if (parsedExamplesSections.length === 0) {
894
+ exampleRelPaths = await discoverExamples(filePath, componentsDir);
895
+ examples = (exampleRelPaths || []).map((rel) => {
896
+ const importPathEx = `${componentsAlias}/${rel.split(__require("path").sep).join(__require("path").posix.sep)}`;
897
+ const abs = join(componentsDir, rel);
898
+ const source = __require("fs").readFileSync(abs, "utf-8");
899
+ const base = toIdentifier(__require("path").basename(rel, __require("path").extname(rel)));
900
+ return {
901
+ importName: `${pascal}${base}`,
902
+ importPath: importPathEx,
903
+ title: base,
904
+ source
905
+ };
906
+ });
907
+ }
908
+ const usedInUsage = extractComponentTagsFromPreviewMarkdown(usageMDX).filter((n) => n !== pascal);
909
+ const usedInDescription = extractComponentTagsFromPreviewMarkdown(descriptionBodyMDX).filter((n) => n !== pascal);
910
+ const usedInExamples = extractComponentTagsFromExamplesSections(parsedExamplesSections).filter((n) => n !== pascal);
911
+ const usedInPrimary = extractComponentTagsFromMDX(primaryExampleMDX).filter((n) => n !== pascal);
912
+ const usedInApi = extractComponentTagsFromPreviewMarkdown(apiMDX).filter((n) => n !== pascal);
913
+ const autoSet = new Set([
914
+ ...usedInUsage,
915
+ ...usedInDescription,
916
+ ...usedInExamples,
917
+ ...usedInPrimary,
918
+ ...usedInApi
919
+ ]);
920
+ const usedNamedExports = isFolder ? namedExports.filter((n) => autoSet.has(n)) : [];
921
+ if (isFolder) for (const n of namedExports) autoSet.delete(n);
922
+ const autoImports = Array.from(autoSet).filter((name) => !RESERVED_COMPONENTS.has(name)).filter((name) => true);
923
+ const lucideIcons = autoImports.filter((n) => /Icon$/.test(n));
924
+ const uiAutoImports = autoImports.filter((n) => !/Icon$/.test(n));
925
+ const mdx = buildMdx({
926
+ importName,
927
+ importPath,
928
+ title,
929
+ description,
930
+ usageMDX,
931
+ hasImport,
932
+ propsList,
933
+ propsTable,
934
+ examples,
935
+ examplesSections: parsedExamplesSections,
936
+ componentFolderMap,
937
+ autoImports: uiAutoImports,
938
+ lucideIcons,
939
+ primaryExampleMDX,
940
+ componentSource: astroFile.trim(),
941
+ commandName: slug,
942
+ figmaUrl,
943
+ descriptionBodyMDX,
944
+ componentsAlias,
945
+ namedExports: isFolder ? usedNamedExports : void 0,
946
+ apiMDX
947
+ });
948
+ const outFile = join(outDir, `${slug}.mdx`);
949
+ mkdirSync(dirname(outFile), { recursive: true });
950
+ await writeFile(outFile, mdx, "utf-8");
951
+ generatedCount += 1;
952
+ spin.text = `Generating docs (${generatedCount}/${total}) - ${title}`;
953
+ if (DEBUG) logger.info(`Generated ${outFile}`);
954
+ }
955
+ spin.succeed(`Created ${generatedCount} file${generatedCount === 1 ? "" : "s"}:`);
956
+ components.map((c) => {
957
+ return relative(cwd, join(outDir, `${slugify(c.name)}.mdx`));
958
+ }).sort((a, b) => a.localeCompare(b)).forEach((p) => {
959
+ logger.log(` - ${p}`);
960
+ });
961
+ logger.break();
962
+ }
963
+ async function runDocsGenerator() {
964
+ await main();
965
+ }
966
+ if (process.env.BEJAMAS_SKIP_AUTO_RUN !== "1" && process.env.BEJAMAS_SKIP_AUTO_RUN !== "true") runDocsGenerator().catch((err) => {
967
+ logger.error(String(err));
968
+ process.exit(1);
969
+ });
970
+
971
+ //#endregion
972
+ export { runDocsGenerator };
973
+ //# sourceMappingURL=generate-mdx-CoN1YUKw.js.map