bejamas 0.0.0-canary.0cf9645

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 ADDED
@@ -0,0 +1,43 @@
1
+ # bejamas
2
+
3
+ A CLI for adding components to your project.
4
+
5
+ ## Usage
6
+
7
+ Use the `init` command to initialize dependencies for a new project.
8
+
9
+ The `init` command installs dependencies, adds the `cn` util, and configures CSS variables for the project.
10
+
11
+ ```bash
12
+ npx bejamas init
13
+ ```
14
+
15
+ ## add
16
+
17
+ Use the `add` command to add components to your project.
18
+
19
+ The `add` command adds a component to your project and installs all required dependencies.
20
+
21
+ ```bash
22
+ npx bejamas add [component]
23
+ ```
24
+
25
+ ### Example
26
+
27
+ ```bash
28
+ npx shadcn add button
29
+ ```
30
+
31
+ You can also run the command without any arguments to view a list of all available components:
32
+
33
+ ```bash
34
+ npx shadcn add
35
+ ```
36
+
37
+ ## Documentation
38
+
39
+ Visit https://ui.bejamas.com/docs/cli to view the documentation.
40
+
41
+ ## License
42
+
43
+ Licensed under the [MIT license](https://github.com/bejamas/ui/blob/main/LICENSE.md).
@@ -0,0 +1,654 @@
1
+ import { logger, spinner } from "./spinner-9iMQF079.js";
2
+ import { createRequire } from "node:module";
3
+ import { createRequire as createRequire$1 } from "module";
4
+ import path, { dirname, extname, join, posix, relative } from "path";
5
+ import { existsSync, mkdirSync } from "fs";
6
+ import { readdir, writeFile } from "fs/promises";
7
+ import { Project, SyntaxKind } from "ts-morph";
8
+
9
+ //#region rolldown:runtime
10
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
11
+
12
+ //#endregion
13
+ //#region src/docs/generate-mdx/utils.ts
14
+ const RESERVED_COMPONENTS = new Set([
15
+ "Fragment",
16
+ "CodePackageManagers",
17
+ "DocsTabs",
18
+ "DocsTabItem",
19
+ "DocsCodePackageManagers",
20
+ "Tabs",
21
+ "TabItem"
22
+ ]);
23
+ function slugify(input) {
24
+ return input.replace(/\.(astro|md|mdx|tsx|ts|jsx|js)$/i, "").replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/\s+/g, "-").replace(/_+/g, "-").toLowerCase();
25
+ }
26
+ function extractFrontmatter(source) {
27
+ const match = source.match(/^---\n([\s\S]*?)\n---/);
28
+ return match && match[1] || "";
29
+ }
30
+ function toIdentifier(name) {
31
+ const base = name.replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9]+/g, " ").trim().replace(/\b\w/g, (c) => c.toUpperCase()).replace(/\s+/g, "");
32
+ return /^[A-Za-z_]/.test(base) ? base : `Ex${base}`;
33
+ }
34
+ function parseJsDocMetadata(frontmatterCode) {
35
+ const jsDocMatch = frontmatterCode.match(/\/\*\*([\s\S]*?)\*\//);
36
+ if (!jsDocMatch) return {};
37
+ const lines = jsDocMatch[1].split("\n").map((l) => l.replace(/^\s*\*\s?/, ""));
38
+ const meta = {};
39
+ let inUsage = false;
40
+ let inExamples = false;
41
+ let inPrimaryExample = false;
42
+ let captureDescriptionBody = false;
43
+ const usageLines = [];
44
+ const examplesLines = [];
45
+ const primaryExampleLines = [];
46
+ const descriptionBodyLines = [];
47
+ for (const rawLine of lines) {
48
+ const line = rawLine;
49
+ if (inUsage) if (line.trim().startsWith("@")) inUsage = false;
50
+ else {
51
+ usageLines.push(line);
52
+ continue;
53
+ }
54
+ if (inPrimaryExample) if (line.trim().startsWith("@")) inPrimaryExample = false;
55
+ else {
56
+ primaryExampleLines.push(line);
57
+ continue;
58
+ }
59
+ if (inExamples) if (line.trim().startsWith("@")) inExamples = false;
60
+ else {
61
+ examplesLines.push(line);
62
+ continue;
63
+ }
64
+ if (captureDescriptionBody) if (line.trim().startsWith("@")) captureDescriptionBody = false;
65
+ else {
66
+ descriptionBodyLines.push(line);
67
+ continue;
68
+ }
69
+ if (line.trim().startsWith("@component")) meta.name = line.replace("@component", "").trim();
70
+ else if (line.trim().startsWith("@title")) meta.title = line.replace("@title", "").trim();
71
+ else if (line.trim().startsWith("@description")) {
72
+ meta.description = line.replace("@description", "").trim();
73
+ captureDescriptionBody = true;
74
+ continue;
75
+ } else if (line.trim().startsWith("@figmaUrl")) meta.figmaUrl = line.replace("@figmaUrl", "").trim();
76
+ else if (line.trim().startsWith("@figma")) meta.figmaUrl = line.replace("@figma", "").trim();
77
+ else if (line.trim().startsWith("@usage")) {
78
+ inUsage = true;
79
+ continue;
80
+ } else if (line.trim().startsWith("@examples")) {
81
+ inExamples = true;
82
+ continue;
83
+ } else if (line.trim().startsWith("@preview")) {
84
+ inPrimaryExample = true;
85
+ continue;
86
+ } else if (line.trim().startsWith("@example")) {
87
+ inPrimaryExample = true;
88
+ continue;
89
+ }
90
+ }
91
+ if (usageLines.length) meta.usageMDX = usageLines.join("\n").trim();
92
+ if (examplesLines.length) meta.examplesMDX = examplesLines.join("\n").trim();
93
+ if (primaryExampleLines.length) meta.primaryExampleMDX = primaryExampleLines.join("\n").trim();
94
+ if (descriptionBodyLines.length) meta.descriptionBodyMDX = descriptionBodyLines.join("\n").trim();
95
+ return meta;
96
+ }
97
+ function extractPropsFromAstroProps(sourceFile) {
98
+ function unwrapAstroProps(node) {
99
+ let current = node;
100
+ for (let i = 0; i < 10; i += 1) {
101
+ const kind = current.getKind();
102
+ if (kind === SyntaxKind.PropertyAccessExpression) {
103
+ const expr = current.getExpression();
104
+ if (expr && expr.getText() === "Astro" && current.getName() === "props") return current;
105
+ return null;
106
+ }
107
+ if (kind === SyntaxKind.AsExpression || kind === SyntaxKind.TypeAssertion || kind === SyntaxKind.SatisfiesExpression || kind === SyntaxKind.NonNullExpression || kind === SyntaxKind.ParenthesizedExpression) {
108
+ const next = current.getExpression && current.getExpression();
109
+ if (!next) return null;
110
+ current = next;
111
+ continue;
112
+ }
113
+ return null;
114
+ }
115
+ return null;
116
+ }
117
+ const target = sourceFile.getDescendantsOfKind(SyntaxKind.VariableDeclaration).find((decl) => {
118
+ const init = decl.getInitializer();
119
+ if (!init) return false;
120
+ return !!unwrapAstroProps(init);
121
+ });
122
+ if (!target) return [];
123
+ const nameNode = target.getNameNode();
124
+ if (!nameNode || nameNode.getKind() !== SyntaxKind.ObjectBindingPattern) return [];
125
+ return nameNode.asKindOrThrow(SyntaxKind.ObjectBindingPattern).getElements().map((el) => {
126
+ if (!!el.getDotDotDotToken()) return {
127
+ isRest: true,
128
+ hasDefault: false,
129
+ alias: el.getName()
130
+ };
131
+ const propertyNameNode = el.getPropertyNameNode();
132
+ const name = el.getName();
133
+ const propName = propertyNameNode ? propertyNameNode.getText() : name;
134
+ const initializer = el.getInitializer();
135
+ let defaultValue;
136
+ if (initializer) defaultValue = initializer.getText();
137
+ return {
138
+ name: propName,
139
+ hasDefault: initializer != null,
140
+ defaultValue
141
+ };
142
+ });
143
+ }
144
+ function extractPropsFromDeclaredProps(sourceFile) {
145
+ function normalizeTypeText(text) {
146
+ if (!text) return "";
147
+ return text.replace(/\s+/g, " ").replace(/;\s*$/, "").trim();
148
+ }
149
+ const iface = sourceFile.getInterface("Props");
150
+ if (iface) return iface.getProperties().map((prop) => {
151
+ const name = prop.getName();
152
+ const typeNode = prop.getTypeNode();
153
+ const rawType = typeNode ? typeNode.getText() : prop.getType().getText();
154
+ const typeText = normalizeTypeText(rawType);
155
+ const optional = prop.hasQuestionToken();
156
+ return {
157
+ name,
158
+ type: typeText,
159
+ optional
160
+ };
161
+ });
162
+ const typeAlias = sourceFile.getTypeAlias("Props");
163
+ if (typeAlias) {
164
+ const typeNode = typeAlias.getTypeNode();
165
+ if (typeNode && typeNode.getKind() === SyntaxKind.TypeLiteral) return typeNode.asKindOrThrow(SyntaxKind.TypeLiteral).getProperties().map((prop) => {
166
+ const name = prop.getName();
167
+ const tn = prop.getTypeNode();
168
+ const rawType = tn ? tn.getText() : prop.getType().getText();
169
+ const typeText = normalizeTypeText(rawType);
170
+ const optional = prop.hasQuestionToken();
171
+ return {
172
+ name,
173
+ type: typeText,
174
+ optional
175
+ };
176
+ });
177
+ }
178
+ return [];
179
+ }
180
+ function resolveUiRoot(cwd) {
181
+ const require$1 = createRequire$1(import.meta.url);
182
+ const envRoot = process.env.BEJAMAS_UI_ROOT;
183
+ if (envRoot && existsSync(path.join(envRoot, "package.json"))) return envRoot;
184
+ try {
185
+ const pkgPath = require$1.resolve("@bejamas/ui/package.json", { paths: [cwd] });
186
+ return path.dirname(pkgPath);
187
+ } catch {}
188
+ let current = cwd;
189
+ for (let i = 0; i < 6; i += 1) {
190
+ const candidate = path.join(current, "packages", "ui", "package.json");
191
+ if (existsSync(candidate)) return path.dirname(candidate);
192
+ const parent = path.dirname(current);
193
+ if (parent === current) break;
194
+ current = parent;
195
+ }
196
+ try {
197
+ const anyEntry = require$1.resolve("@bejamas/ui/*", { paths: [cwd] });
198
+ return path.resolve(anyEntry, "..", "..");
199
+ } catch {}
200
+ throw new Error("Unable to locate @bejamas/ui in the workspace");
201
+ }
202
+ function resolveOutDir(cwd) {
203
+ const envOut = process.env.BEJAMAS_DOCS_OUT_DIR;
204
+ if (envOut && envOut.length) return path.isAbsolute(envOut) ? envOut : path.resolve(cwd, envOut);
205
+ return path.resolve(cwd, "../../apps/web/src/content/docs/components");
206
+ }
207
+ function detectHasImportTopLevel(block, pascalName) {
208
+ if (!block) return false;
209
+ let inFence = false;
210
+ const importLineRegex = /* @__PURE__ */ new RegExp(`^\\s*import\\s+.*\\bfrom\\s+['"][^'"]+\\b${pascalName}\\.astro['"]`);
211
+ for (const line of block.split("\n")) {
212
+ if (line.trim().startsWith("```")) {
213
+ inFence = !inFence;
214
+ continue;
215
+ }
216
+ if (!inFence && importLineRegex.test(line)) return true;
217
+ }
218
+ return false;
219
+ }
220
+ function normalizeBlockMDX(block) {
221
+ if (!block) return "";
222
+ return block.replace(/from\s+['"]@\/ui\/components\//g, "from '@bejamas/ui/components/");
223
+ }
224
+ function normalizeUsageMDX(usageMDX, pascalName) {
225
+ const normalized = normalizeBlockMDX(usageMDX);
226
+ const hasImport = detectHasImportTopLevel(normalized, pascalName);
227
+ return {
228
+ text: normalized.trim(),
229
+ hasImport
230
+ };
231
+ }
232
+ function extractComponentTagsFromMDX(block) {
233
+ if (!block) return [];
234
+ let inFence = false;
235
+ const found = /* @__PURE__ */ new Set();
236
+ const tagRegex = /<([A-Z][A-Za-z0-9_]*)\b/g;
237
+ for (const line of block.split("\n")) {
238
+ if (line.trim().startsWith("```")) {
239
+ inFence = !inFence;
240
+ continue;
241
+ }
242
+ if (inFence) continue;
243
+ let match;
244
+ while ((match = tagRegex.exec(line)) !== null) {
245
+ const name = match[1];
246
+ found.add(name);
247
+ }
248
+ }
249
+ return Array.from(found);
250
+ }
251
+ async function discoverExamples(componentFilePath, componentsDir) {
252
+ const fileBase = path.basename(componentFilePath, path.extname(componentFilePath));
253
+ const kebabBase = slugify(fileBase);
254
+ const candidates = [join(dirname(componentFilePath), `${fileBase}.examples`), join(dirname(componentFilePath), `${kebabBase}.examples`)];
255
+ const found = [];
256
+ for (const dir of candidates) try {
257
+ const items = await readdir(dir, { withFileTypes: true });
258
+ for (const it of items) if (it.isFile() && extname(it.name).toLowerCase() === ".astro") {
259
+ const abs = join(dir, it.name);
260
+ const relFromComponents = path.relative(componentsDir, abs).split(path.sep).join(posix.sep);
261
+ found.push(relFromComponents);
262
+ }
263
+ } catch {}
264
+ return found;
265
+ }
266
+ function createSourceFileFromFrontmatter(frontmatterCode) {
267
+ return new Project({ useInMemoryFileSystem: true }).createSourceFile("Component.ts", frontmatterCode, { overwrite: true });
268
+ }
269
+
270
+ //#endregion
271
+ //#region src/docs/generate-mdx/mdx-builder.ts
272
+ function buildMdx(params) {
273
+ const { importName, importPath, title, description, descriptionBodyMDX, usageMDX, hasImport, propsList, propsTable, examples, examplesBlocks, autoImports, lucideIcons, primaryExampleMDX, componentSource, commandName, figmaUrl } = params;
274
+ const sortedLucide = (lucideIcons ?? []).slice().sort();
275
+ 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)));
276
+ const uiAutoLines = (autoImports ?? []).slice().sort().map((name) => `import ${name} from '@bejamas/ui/components/${name}.astro';`);
277
+ const exampleLines = (examples ?? []).map((ex) => `import ${ex.importName} from '${ex.importPath}';`).sort((a, b) => a.localeCompare(b));
278
+ const internalTopImports = [
279
+ !hasImport ? `import ${importName} from '${importPath}';` : null,
280
+ ...uiAutoLines,
281
+ ...exampleLines
282
+ ].filter((v) => v != null).slice().sort((a, b) => String(a).localeCompare(String(b)));
283
+ const importLines = [
284
+ ...externalTopImports,
285
+ externalTopImports.length && internalTopImports.length ? "" : null,
286
+ ...internalTopImports
287
+ ].filter((v) => v !== null && v !== void 0);
288
+ const extractTags = (snippet) => {
289
+ const found = /* @__PURE__ */ new Set();
290
+ const tagRegex = /<([A-Z][A-Za-z0-9_]*)\b/g;
291
+ let m;
292
+ while ((m = tagRegex.exec(snippet)) !== null) found.add(m[1]);
293
+ return found;
294
+ };
295
+ const buildSnippetImportLines = (snippet) => {
296
+ if (!snippet || !snippet.length) return [];
297
+ const used = extractTags(snippet);
298
+ const usedIcons = sortedLucide.filter((n) => used.has(n));
299
+ const usedUi = (autoImports ?? []).filter((n) => used.has(n)).slice().sort();
300
+ const includeMain = !hasImport && used.has(importName);
301
+ const external = [];
302
+ if (usedIcons.length) external.push(`import { ${usedIcons.join(", ")} } from '@lucide/astro';`);
303
+ const internal = [];
304
+ if (includeMain) internal.push(`import ${importName} from '${importPath}';`);
305
+ internal.push(...usedUi.map((name) => `import ${name} from '@bejamas/ui/components/${name}.astro';`));
306
+ const externalSorted = external.slice().sort((a, b) => a.localeCompare(b));
307
+ const internalSorted = internal.slice().sort((a, b) => a.localeCompare(b));
308
+ return [
309
+ ...externalSorted,
310
+ externalSorted.length && internalSorted.length ? "" : null,
311
+ ...internalSorted
312
+ ].filter((v) => v !== null && v !== void 0);
313
+ };
314
+ const wrapTextNodes = (snippet) => {
315
+ if (!snippet) return snippet;
316
+ return snippet.replace(/>([^<]+)</g, (match, inner) => {
317
+ const trimmed = inner.trim();
318
+ if (!trimmed.length) return match;
319
+ if (/^\{[\s\S]*\}$/.test(trimmed)) return match;
320
+ return `>{${JSON.stringify(inner)}}<`;
321
+ });
322
+ };
323
+ const toMdxPreview = (snippet) => {
324
+ if (!snippet) return snippet;
325
+ const withoutComments = snippet.replace(/<!--([\s\S]*?)-->/g, "{/*$1*/}");
326
+ return wrapTextNodes(withoutComments);
327
+ };
328
+ const splitDescriptionAndSnippet = (body) => {
329
+ if (!body || !body.trim().length) return {
330
+ descriptionMD: "",
331
+ snippet: ""
332
+ };
333
+ const lines = body.split("\n");
334
+ let snippetStartIdx = -1;
335
+ for (let i = 0; i < lines.length; i++) {
336
+ const ln = lines[i];
337
+ if (!ln.trim().length) continue;
338
+ if (/^\s*[<{]/.test(ln)) {
339
+ snippetStartIdx = i;
340
+ break;
341
+ }
342
+ }
343
+ if (snippetStartIdx <= 0) return {
344
+ descriptionMD: "",
345
+ snippet: body.trim()
346
+ };
347
+ const descriptionMD = lines.slice(0, snippetStartIdx).join("\n").trim();
348
+ const snippet = lines.slice(snippetStartIdx).join("\n").trim();
349
+ return {
350
+ descriptionMD,
351
+ snippet
352
+ };
353
+ };
354
+ const primaryExampleSection = primaryExampleMDX && primaryExampleMDX.length ? `<DocsTabs>
355
+ <DocsTabItem label="Preview">
356
+ <div class="not-content sl-bejamas-component-preview flex justify-center px-10 py-12 border border-border rounded-md min-h-[450px] items-center [&_input]:max-w-xs">
357
+ ${toMdxPreview(primaryExampleMDX)}
358
+ </div>
359
+ </DocsTabItem>
360
+ <DocsTabItem label="Source">
361
+
362
+ \`\`\`astro
363
+ ${(() => {
364
+ const lines = buildSnippetImportLines(primaryExampleMDX);
365
+ return lines.length ? `---\n${lines.join("\n")}\n---\n\n` : "";
366
+ })()}${primaryExampleMDX}
367
+ \`\`\`
368
+ </DocsTabItem>
369
+ </DocsTabs>` : null;
370
+ const exampleSections = [];
371
+ if (examplesBlocks && examplesBlocks.length) for (const blk of examplesBlocks) {
372
+ const { descriptionMD, snippet } = splitDescriptionAndSnippet(blk.body);
373
+ const previewBody = toMdxPreview(snippet);
374
+ if (!snippet || !snippet.length) {
375
+ exampleSections.push(`### ${blk.title}
376
+
377
+ ${descriptionMD}`.trim());
378
+ continue;
379
+ }
380
+ exampleSections.push(`### ${blk.title}
381
+
382
+ ${descriptionMD ? `${descriptionMD}\n\n` : ""}<DocsTabs>
383
+ <DocsTabItem label="Preview">
384
+ <div class="not-content sl-bejamas-component-preview flex justify-center px-10 py-12 border border-border rounded-md min-h-[450px] items-center [&_input]:max-w-xs">
385
+ ${previewBody}
386
+ </div>
387
+ </DocsTabItem>
388
+ <DocsTabItem label="Source">
389
+
390
+ \`\`\`astro
391
+ ${(() => {
392
+ const lines = buildSnippetImportLines(snippet);
393
+ return lines.length ? `---\n${lines.join("\n")}\n---\n\n` : "";
394
+ })()}${snippet}
395
+ \`\`\`
396
+ </DocsTabItem>
397
+ </DocsTabs>`);
398
+ }
399
+ if (examples && examples.length) for (const ex of examples) exampleSections.push(`### ${ex.title}
400
+
401
+ <DocsTabs>
402
+ <DocsTabItem label="Preview">
403
+ <div class="not-content">
404
+ <${ex.importName} />
405
+ </div>
406
+ </DocsTabItem>
407
+ <DocsTabItem label="Source">
408
+
409
+ \`\`\`astro
410
+ ${ex.source}
411
+ \`\`\`
412
+ </DocsTabItem>
413
+ </DocsTabs>`);
414
+ const formatDefault = (val) => {
415
+ if (val == null) return "";
416
+ let raw = String(val).trim();
417
+ if (!raw.length) return "";
418
+ raw = raw.replace(/[\u201C\u201D\u201E\u201F]/g, "\"").replace(/[\u2018\u2019]/g, "'");
419
+ const isSingleQuoted = /^'[^']*'$/.test(raw);
420
+ const isDoubleQuoted = /^"[^"]*"$/.test(raw);
421
+ const isBacktickSimple = /^`[^`]*`$/.test(raw) && raw.indexOf("${") === -1;
422
+ let content = raw;
423
+ if (isSingleQuoted || isDoubleQuoted || isBacktickSimple) content = `"${raw.slice(1, -1)}"`;
424
+ content = content.replace(/\|/g, "\\|");
425
+ const hasTick = content.includes("`");
426
+ const hasDoubleTick = content.includes("``");
427
+ const fence = !hasTick ? "`" : !hasDoubleTick ? "``" : "```";
428
+ return `${fence}${content}${fence}`;
429
+ };
430
+ const installationSection = `## Installation
431
+ <DocsTabs syncKey="installation">
432
+ <DocsTabItem label="CLI">
433
+
434
+ <DocsTabs syncKey="pkg">
435
+ <DocsTabItem label="bun">
436
+
437
+ \`\`\`bash
438
+ bunx bejamas add ${commandName}
439
+ \`\`\`
440
+
441
+ </DocsTabItem>
442
+ <DocsTabItem label="npm">
443
+
444
+ \`\`\`bash
445
+ npx bejamas add ${commandName}
446
+ \`\`\`
447
+
448
+ </DocsTabItem>
449
+ <DocsTabItem label="pnpm">
450
+
451
+ \`\`\`bash
452
+ pnpm dlx bejamas add ${commandName}
453
+ \`\`\`
454
+
455
+ </DocsTabItem>
456
+ <DocsTabItem label="yarn">
457
+
458
+ \`\`\`bash
459
+ yarn dlx bejamas add ${commandName}
460
+ \`\`\`
461
+
462
+ </DocsTabItem>
463
+ </DocsTabs>
464
+ </DocsTabItem>
465
+ <DocsTabItem label="Manual">
466
+
467
+ \`\`\`astro
468
+ ${componentSource}
469
+ \`\`\`
470
+ </DocsTabItem>
471
+ </DocsTabs>`;
472
+ const serializeFrontmatter = (label, value) => {
473
+ if (!value || !value.length) return null;
474
+ return `${label}: ${JSON.stringify(value)}`;
475
+ };
476
+ return [
477
+ "---",
478
+ serializeFrontmatter("title", title),
479
+ serializeFrontmatter("description", description),
480
+ serializeFrontmatter("figmaUrl", figmaUrl),
481
+ "---",
482
+ "",
483
+ ...importLines,
484
+ importLines.length ? "" : null,
485
+ descriptionBodyMDX && descriptionBodyMDX.length ? descriptionBodyMDX : null,
486
+ descriptionBodyMDX && descriptionBodyMDX.length ? "" : null,
487
+ primaryExampleSection,
488
+ primaryExampleSection ? "" : null,
489
+ installationSection,
490
+ "",
491
+ usageMDX && usageMDX.length ? `## Usage\n\n${usageMDX}` : null,
492
+ "",
493
+ 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,
494
+ propsTable && propsTable.length || propsList ? "" : null,
495
+ exampleSections.length ? `## Examples\n\n` + exampleSections.join("\n\n") : null
496
+ ].filter((v) => v !== null && v !== void 0).join("\n").trim() + "\n";
497
+ }
498
+
499
+ //#endregion
500
+ //#region src/docs/generate-mdx/index.ts
501
+ async function main() {
502
+ const DEBUG = process.env.BEJAMAS_DEBUG === "1" || process.env.BEJAMAS_DEBUG === "true";
503
+ const cwd = process.env.BEJAMAS_DOCS_CWD && process.env.BEJAMAS_DOCS_CWD.length ? process.env.BEJAMAS_DOCS_CWD : process.cwd();
504
+ const uiRoot = resolveUiRoot(cwd);
505
+ const componentsDir = join(uiRoot, "src", "components");
506
+ const outDir = resolveOutDir(cwd);
507
+ mkdirSync(outDir, { recursive: true });
508
+ if (DEBUG) {
509
+ logger.info(`[docs-generator] cwd: ${cwd}`);
510
+ logger.info(`[docs-generator] uiRoot: ${uiRoot}`);
511
+ logger.info(`[docs-generator] componentsDir: ${componentsDir}`);
512
+ logger.info(`[docs-generator] outDir: ${outDir}`);
513
+ }
514
+ const files = (await readdir(componentsDir, { withFileTypes: true })).filter((e) => e.isFile() && extname(e.name).toLowerCase() === ".astro");
515
+ if (DEBUG) {
516
+ logger.info(`[docs-generator] components found: ${files.length}`);
517
+ if (files.length) logger.info(`[docs-generator] first few: ${files.slice(0, 5).map((f) => f.name).join(", ")}`);
518
+ }
519
+ let generatedCount = 0;
520
+ const total = files.length;
521
+ const spin = spinner(`Generating docs (0/${total})`).start();
522
+ for (const f of files) {
523
+ const filePath = join(componentsDir, f.name);
524
+ const astroFile = await (await import("fs/promises")).readFile(filePath, "utf-8");
525
+ const frontmatterCode = extractFrontmatter(astroFile);
526
+ const sourceFile = createSourceFileFromFrontmatter(frontmatterCode);
527
+ const meta = parseJsDocMetadata(frontmatterCode);
528
+ const declaredProps = extractPropsFromDeclaredProps(sourceFile);
529
+ const destructuredProps = extractPropsFromAstroProps(sourceFile);
530
+ const defaultsMap = /* @__PURE__ */ new Map();
531
+ for (const p of destructuredProps) if (p.name && p.hasDefault) defaultsMap.set(p.name, p.defaultValue || null);
532
+ const propsTable = (declaredProps.length ? declaredProps : []).map((p) => ({
533
+ name: p.name,
534
+ type: p.type,
535
+ required: !p.optional,
536
+ defaultValue: defaultsMap.has(p.name) ? defaultsMap.get(p.name) : null
537
+ }));
538
+ const slug = `${slugify(f.name)}`;
539
+ const pascal = f.name.replace(/\.(astro)$/i, "");
540
+ const title = meta.title || meta.name || pascal;
541
+ const description = meta.description || "";
542
+ const descriptionBodyMDX = meta.descriptionBodyMDX || "";
543
+ const figmaUrl = meta.figmaUrl || "";
544
+ const propsList = "";
545
+ const importName = pascal;
546
+ const importPath = `@bejamas/ui/components/${pascal}.astro`;
547
+ const { text: usageMDX, hasImport: hasImportUsage } = normalizeUsageMDX(meta.usageMDX || "", pascal);
548
+ const primaryExampleMDX = normalizeBlockMDX(meta.primaryExampleMDX || "").trim();
549
+ const examplesMDX = normalizeBlockMDX(meta.examplesMDX || "").trim();
550
+ const hasImportExamples = detectHasImportTopLevel(examplesMDX, pascal);
551
+ const hasImportPrimary = detectHasImportTopLevel(primaryExampleMDX, pascal);
552
+ const hasImport = hasImportUsage || hasImportExamples || hasImportPrimary;
553
+ let exampleRelPaths = [];
554
+ let examples = [];
555
+ const examplesBlocksRaw = examplesMDX;
556
+ if (parseExamplesBlocks(examplesBlocksRaw).length === 0) {
557
+ exampleRelPaths = await discoverExamples(filePath, componentsDir);
558
+ examples = (exampleRelPaths || []).map((rel) => {
559
+ const importPath$1 = `@bejamas/ui/components/${rel.split(__require("path").sep).join(__require("path").posix.sep)}`;
560
+ const abs = join(componentsDir, rel);
561
+ const source = __require("fs").readFileSync(abs, "utf-8");
562
+ const base = toIdentifier(__require("path").basename(rel, __require("path").extname(rel)));
563
+ return {
564
+ importName: `${pascal}${base}`,
565
+ importPath: importPath$1,
566
+ title: base,
567
+ source
568
+ };
569
+ });
570
+ }
571
+ const usedInUsage = extractComponentTagsFromMDX(usageMDX).filter((n) => n !== pascal);
572
+ const usedInExamples = extractComponentTagsFromMDX(examplesMDX).filter((n) => n !== pascal);
573
+ const usedInPrimary = extractComponentTagsFromMDX(primaryExampleMDX).filter((n) => n !== pascal);
574
+ const autoSet = new Set([
575
+ ...usedInUsage,
576
+ ...usedInExamples,
577
+ ...usedInPrimary
578
+ ]);
579
+ const autoImports = Array.from(autoSet).filter((name) => !RESERVED_COMPONENTS.has(name)).filter((name) => true);
580
+ const lucideIcons = autoImports.filter((n) => /Icon$/.test(n));
581
+ const uiAutoImports = autoImports.filter((n) => !/Icon$/.test(n));
582
+ const mdx = buildMdx({
583
+ importName,
584
+ importPath,
585
+ title,
586
+ description,
587
+ usageMDX,
588
+ hasImport,
589
+ propsList,
590
+ propsTable,
591
+ examples,
592
+ examplesBlocks: parseExamplesBlocks(examplesBlocksRaw),
593
+ autoImports: uiAutoImports,
594
+ lucideIcons,
595
+ primaryExampleMDX,
596
+ componentSource: astroFile.trim(),
597
+ commandName: slug,
598
+ figmaUrl,
599
+ descriptionBodyMDX
600
+ });
601
+ const outFile = join(outDir, `${slug}.mdx`);
602
+ mkdirSync(dirname(outFile), { recursive: true });
603
+ await writeFile(outFile, mdx, "utf-8");
604
+ generatedCount += 1;
605
+ spin.text = `Generating docs (${generatedCount}/${total}) - ${title}`;
606
+ if (DEBUG) logger.info(`Generated ${outFile}`);
607
+ }
608
+ spin.succeed(`Created ${generatedCount} file${generatedCount === 1 ? "" : "s"}:`);
609
+ files.map((f) => {
610
+ const slug = `${slugify(f.name)}`;
611
+ const outFile = join(outDir, `${slug}.mdx`);
612
+ return relative(cwd, outFile);
613
+ }).sort((a, b) => a.localeCompare(b)).forEach((p) => {
614
+ logger.log(` - ${p}`);
615
+ });
616
+ logger.break();
617
+ }
618
+ function parseExamplesBlocks(examplesMDX) {
619
+ if (!examplesMDX) return [];
620
+ const lines = examplesMDX.split("\n");
621
+ const blocks = [];
622
+ let current = {
623
+ title: "",
624
+ body: []
625
+ };
626
+ for (const line of lines) {
627
+ const heading = line.match(/^###\s+(.+)$/);
628
+ if (heading) {
629
+ if (current.title || current.body.length) blocks.push(current);
630
+ current = {
631
+ title: heading[1].trim(),
632
+ body: []
633
+ };
634
+ continue;
635
+ }
636
+ current.body.push(line);
637
+ }
638
+ if (current.title || current.body.length) blocks.push(current);
639
+ return blocks.map((b, idx) => ({
640
+ title: b.title || `Example ${idx + 1}`,
641
+ body: b.body.join("\n").trim()
642
+ }));
643
+ }
644
+ async function runDocsGenerator() {
645
+ await main();
646
+ }
647
+ if (process.env.BEJAMAS_SKIP_AUTO_RUN !== "1" && process.env.BEJAMAS_SKIP_AUTO_RUN !== "true") runDocsGenerator().catch((err) => {
648
+ logger.error(String(err));
649
+ process.exit(1);
650
+ });
651
+
652
+ //#endregion
653
+ export { runDocsGenerator };
654
+ //# sourceMappingURL=generate-mdx-Bq9erbjr.js.map