bejamas 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{generate-mdx-CR4bXlml.js → generate-mdx-Csh3BuQB.js} +161 -279
- package/dist/generate-mdx-Csh3BuQB.js.map +1 -0
- package/dist/index.js +188 -8
- package/dist/index.js.map +1 -1
- package/dist/utils-DfvCox_O.js +479 -0
- package/dist/utils-DfvCox_O.js.map +1 -0
- package/package.json +1 -1
- package/dist/generate-mdx-CR4bXlml.js.map +0 -1
- package/dist/get-config-CJUwQ2Xb.js +0 -217
- package/dist/get-config-CJUwQ2Xb.js.map +0 -1
|
@@ -1,282 +1,87 @@
|
|
|
1
|
-
import { getConfig, logger, spinner } from "./
|
|
1
|
+
import { RESERVED_COMPONENTS, createSourceFileFromFrontmatter, detectHasImportTopLevel, discoverExamples, extractComponentTagsFromMDX, extractFrontmatter, extractPropsFromAstroProps, extractPropsFromDeclaredProps, getConfig, logger, normalizeBlockMDX, normalizeUsageMDX, parseJsDocMetadata, resolveOutDir, resolveUiRoot, slugify, spinner, toIdentifier } from "./utils-DfvCox_O.js";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
-
import {
|
|
4
|
-
import path, { dirname, extname, join, posix, relative } from "path";
|
|
3
|
+
import { dirname, extname, join, relative } from "path";
|
|
5
4
|
import { existsSync, mkdirSync } from "fs";
|
|
6
|
-
import { readdir, writeFile } from "fs/promises";
|
|
7
|
-
import { Project, SyntaxKind } from "ts-morph";
|
|
5
|
+
import { readFile, readdir, writeFile } from "fs/promises";
|
|
8
6
|
|
|
9
7
|
//#region rolldown:runtime
|
|
10
8
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
11
9
|
|
|
12
10
|
//#endregion
|
|
13
|
-
//#region src/docs/generate-mdx/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
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");
|
|
11
|
+
//#region src/docs/generate-mdx/mdx-builder.ts
|
|
12
|
+
/**
|
|
13
|
+
* Check if an import path uses the new barrel export pattern (no .astro extension)
|
|
14
|
+
*/
|
|
15
|
+
function isBarrelImport(path$1) {
|
|
16
|
+
return !path$1.endsWith(".astro");
|
|
201
17
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Convert a PascalCase component name to its folder path (kebab-case).
|
|
20
|
+
* Examples:
|
|
21
|
+
* - "Card" → "card"
|
|
22
|
+
* - "CardHeader" → "card"
|
|
23
|
+
* - "InputGroup" → "input-group"
|
|
24
|
+
* - "InputGroupAddon" → "input-group"
|
|
25
|
+
* - "StickySurface" → "sticky-surface"
|
|
26
|
+
* - "RadioGroup" → "radio-group"
|
|
27
|
+
* - "RadioGroupItem" → "radio-group"
|
|
28
|
+
*/
|
|
29
|
+
function componentToFolder(name) {
|
|
30
|
+
const sortedFamilies = [
|
|
31
|
+
"InputGroup",
|
|
32
|
+
"LinkGroup",
|
|
33
|
+
"RadioGroup",
|
|
34
|
+
"ButtonGroup",
|
|
35
|
+
"StickySurface"
|
|
36
|
+
].sort((a, b) => b.length - a.length);
|
|
37
|
+
for (const family of sortedFamilies) if (name === family || name.startsWith(family)) return family.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
38
|
+
const baseMatch = name.match(/^[A-Z][a-z]*/);
|
|
39
|
+
return baseMatch ? baseMatch[0].toLowerCase() : name.toLowerCase();
|
|
206
40
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (!inFence && importLineRegex.test(line)) return true;
|
|
41
|
+
/**
|
|
42
|
+
* Group component names by their folder path
|
|
43
|
+
*/
|
|
44
|
+
function groupComponentsByFolder(components) {
|
|
45
|
+
const groups = /* @__PURE__ */ new Map();
|
|
46
|
+
for (const comp of components) {
|
|
47
|
+
const folder = componentToFolder(comp);
|
|
48
|
+
if (!groups.has(folder)) groups.set(folder, []);
|
|
49
|
+
groups.get(folder).push(comp);
|
|
217
50
|
}
|
|
218
|
-
return
|
|
51
|
+
return groups;
|
|
219
52
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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
|
-
}
|
|
53
|
+
/**
|
|
54
|
+
* Generate import lines for UI components using the barrel import pattern
|
|
55
|
+
*/
|
|
56
|
+
function generateBarrelImports(components, componentsAlias) {
|
|
57
|
+
const groups = groupComponentsByFolder(components);
|
|
58
|
+
const lines = [];
|
|
59
|
+
const sortedFolders = Array.from(groups.keys()).sort();
|
|
60
|
+
for (const folder of sortedFolders) {
|
|
61
|
+
const names = groups.get(folder).sort();
|
|
62
|
+
lines.push(`import { ${names.join(", ")} } from '${componentsAlias}/${folder}';`);
|
|
248
63
|
}
|
|
249
|
-
return
|
|
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;
|
|
64
|
+
return lines;
|
|
265
65
|
}
|
|
266
|
-
|
|
267
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Generate import lines for UI components using the old default import pattern
|
|
68
|
+
*/
|
|
69
|
+
function generateDefaultImports(components, componentsAlias) {
|
|
70
|
+
return components.slice().sort().map((name) => `import ${name} from '${componentsAlias}/${name}.astro';`);
|
|
268
71
|
}
|
|
269
|
-
|
|
270
|
-
//#endregion
|
|
271
|
-
//#region src/docs/generate-mdx/mdx-builder.ts
|
|
272
72
|
function buildMdx(params) {
|
|
273
|
-
const { importName, importPath, title, description, descriptionBodyMDX, usageMDX, hasImport, propsList, propsTable, examples, examplesBlocks, autoImports, lucideIcons, primaryExampleMDX, componentSource, commandName, figmaUrl, componentsAlias } = params;
|
|
73
|
+
const { importName, importPath, title, description, descriptionBodyMDX, usageMDX, hasImport, propsList, propsTable, examples, examplesBlocks, autoImports, lucideIcons, primaryExampleMDX, componentSource, commandName, figmaUrl, componentsAlias, namedExports } = params;
|
|
74
|
+
const useBarrelPattern = isBarrelImport(importPath);
|
|
274
75
|
const sortedLucide = (lucideIcons ?? []).slice().sort();
|
|
275
76
|
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
|
|
77
|
+
const sortedUiAuto = (autoImports ?? []).slice().sort();
|
|
78
|
+
const uiAutoLines = useBarrelPattern ? generateBarrelImports(sortedUiAuto, componentsAlias) : generateDefaultImports(sortedUiAuto, componentsAlias);
|
|
277
79
|
const exampleLines = (examples ?? []).map((ex) => `import ${ex.importName} from '${ex.importPath}';`).sort((a, b) => a.localeCompare(b));
|
|
80
|
+
let mainImportLine = null;
|
|
81
|
+
if (!hasImport) if (useBarrelPattern) mainImportLine = `import { ${[importName, ...namedExports ?? []].sort().join(", ")} } from '${importPath}';`;
|
|
82
|
+
else mainImportLine = `import ${importName} from '${importPath}';`;
|
|
278
83
|
const internalTopImports = [
|
|
279
|
-
|
|
84
|
+
mainImportLine,
|
|
280
85
|
...uiAutoLines,
|
|
281
86
|
...exampleLines
|
|
282
87
|
].filter((v) => v != null).slice().sort((a, b) => String(a).localeCompare(String(b)));
|
|
@@ -296,13 +101,22 @@ function buildMdx(params) {
|
|
|
296
101
|
if (!snippet || !snippet.length) return [];
|
|
297
102
|
const used = extractTags(snippet);
|
|
298
103
|
const usedIcons = sortedLucide.filter((n) => used.has(n));
|
|
299
|
-
const usedUi = (autoImports ?? []).filter((n) => used.has(n))
|
|
104
|
+
const usedUi = (autoImports ?? []).filter((n) => used.has(n));
|
|
300
105
|
const includeMain = !hasImport && used.has(importName);
|
|
106
|
+
const usedNamedExports = useBarrelPattern && namedExports ? namedExports.filter((n) => used.has(n)) : [];
|
|
301
107
|
const external = [];
|
|
302
108
|
if (usedIcons.length) external.push(`import { ${usedIcons.join(", ")} } from '@lucide/astro';`);
|
|
303
109
|
const internal = [];
|
|
304
|
-
if (
|
|
305
|
-
|
|
110
|
+
if (useBarrelPattern) {
|
|
111
|
+
if (includeMain || usedNamedExports.length > 0) {
|
|
112
|
+
const mainExports = [...includeMain ? [importName] : [], ...usedNamedExports].sort();
|
|
113
|
+
internal.push(`import { ${mainExports.join(", ")} } from '${importPath}';`);
|
|
114
|
+
}
|
|
115
|
+
if (usedUi.length > 0) internal.push(...generateBarrelImports(usedUi, componentsAlias));
|
|
116
|
+
} else {
|
|
117
|
+
if (includeMain) internal.push(`import ${importName} from '${importPath}';`);
|
|
118
|
+
internal.push(...usedUi.slice().sort().map((name) => `import ${name} from '${componentsAlias}/${name}.astro';`));
|
|
119
|
+
}
|
|
306
120
|
const externalSorted = external.slice().sort((a, b) => a.localeCompare(b));
|
|
307
121
|
const internalSorted = internal.slice().sort((a, b) => a.localeCompare(b));
|
|
308
122
|
return [
|
|
@@ -498,6 +312,72 @@ ${componentSource}
|
|
|
498
312
|
|
|
499
313
|
//#endregion
|
|
500
314
|
//#region src/docs/generate-mdx/index.ts
|
|
315
|
+
/**
|
|
316
|
+
* Discover components in the components directory.
|
|
317
|
+
* Supports both:
|
|
318
|
+
* - Old pattern: flat .astro files in components/
|
|
319
|
+
* - New pattern: folders with index.ts barrel exports
|
|
320
|
+
*/
|
|
321
|
+
async function discoverComponents(componentsDir) {
|
|
322
|
+
const entries = [];
|
|
323
|
+
const dirEntries = await readdir(componentsDir, { withFileTypes: true });
|
|
324
|
+
for (const entry of dirEntries) if (entry.isDirectory()) {
|
|
325
|
+
const folderPath = join(componentsDir, entry.name);
|
|
326
|
+
const indexPath = join(folderPath, "index.ts");
|
|
327
|
+
if (existsSync(indexPath)) {
|
|
328
|
+
const indexContent = await readFile(indexPath, "utf-8");
|
|
329
|
+
const namedExports = parseBarrelExports(indexContent);
|
|
330
|
+
const mainComponentName = findMainComponent(namedExports, entry.name);
|
|
331
|
+
if (mainComponentName) {
|
|
332
|
+
const mainFilePath = join(folderPath, `${mainComponentName}.astro`);
|
|
333
|
+
if (existsSync(mainFilePath)) {
|
|
334
|
+
const subComponents = namedExports.filter((n) => n !== mainComponentName);
|
|
335
|
+
entries.push({
|
|
336
|
+
name: mainComponentName,
|
|
337
|
+
filePath: mainFilePath,
|
|
338
|
+
folderName: entry.name,
|
|
339
|
+
isFolder: true,
|
|
340
|
+
namedExports: subComponents
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
} else if (entry.isFile() && extname(entry.name).toLowerCase() === ".astro") {
|
|
346
|
+
const componentName = entry.name.replace(/\.astro$/i, "");
|
|
347
|
+
entries.push({
|
|
348
|
+
name: componentName,
|
|
349
|
+
filePath: join(componentsDir, entry.name),
|
|
350
|
+
folderName: "",
|
|
351
|
+
isFolder: false,
|
|
352
|
+
namedExports: []
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
return entries;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Parse a barrel (index.ts) file to extract named exports.
|
|
359
|
+
* Handles patterns like:
|
|
360
|
+
* - export { default as Card } from "./Card.astro";
|
|
361
|
+
* - export { default as CardHeader } from "./CardHeader.astro";
|
|
362
|
+
*/
|
|
363
|
+
function parseBarrelExports(content) {
|
|
364
|
+
const exports = [];
|
|
365
|
+
const exportRegex = /export\s*\{\s*default\s+as\s+(\w+)\s*\}/g;
|
|
366
|
+
let match;
|
|
367
|
+
while ((match = exportRegex.exec(content)) !== null) exports.push(match[1]);
|
|
368
|
+
return exports;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Find the main component from a list of exports.
|
|
372
|
+
* The main component is typically the one that matches the folder name (PascalCase).
|
|
373
|
+
*/
|
|
374
|
+
function findMainComponent(exports, folderName) {
|
|
375
|
+
if (exports.length === 0) return null;
|
|
376
|
+
const expectedName = folderName.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
377
|
+
const exactMatch = exports.find((e) => e === expectedName);
|
|
378
|
+
if (exactMatch) return exactMatch;
|
|
379
|
+
return exports[0];
|
|
380
|
+
}
|
|
501
381
|
async function main() {
|
|
502
382
|
const DEBUG = process.env.BEJAMAS_DEBUG === "1" || process.env.BEJAMAS_DEBUG === "true";
|
|
503
383
|
const cwd = process.env.BEJAMAS_DOCS_CWD && process.env.BEJAMAS_DOCS_CWD.length ? process.env.BEJAMAS_DOCS_CWD : process.cwd();
|
|
@@ -519,17 +399,17 @@ async function main() {
|
|
|
519
399
|
logger.info(`[docs-generator] componentsDir: ${componentsDir}`);
|
|
520
400
|
logger.info(`[docs-generator] outDir: ${outDir}`);
|
|
521
401
|
}
|
|
522
|
-
const
|
|
402
|
+
const components = await discoverComponents(componentsDir);
|
|
523
403
|
if (DEBUG) {
|
|
524
|
-
logger.info(`[docs-generator] components found: ${
|
|
525
|
-
if (
|
|
404
|
+
logger.info(`[docs-generator] components found: ${components.length}`);
|
|
405
|
+
if (components.length) logger.info(`[docs-generator] first few: ${components.slice(0, 5).map((c) => c.name).join(", ")}`);
|
|
526
406
|
}
|
|
527
407
|
let generatedCount = 0;
|
|
528
|
-
const total =
|
|
408
|
+
const total = components.length;
|
|
529
409
|
const spin = spinner(`Generating docs (0/${total})`).start();
|
|
530
|
-
for (const
|
|
531
|
-
const filePath
|
|
532
|
-
const astroFile = await
|
|
410
|
+
for (const component of components) {
|
|
411
|
+
const { name: pascal, filePath, folderName, isFolder, namedExports } = component;
|
|
412
|
+
const astroFile = await readFile(filePath, "utf-8");
|
|
533
413
|
const frontmatterCode = extractFrontmatter(astroFile);
|
|
534
414
|
const sourceFile = createSourceFileFromFrontmatter(frontmatterCode);
|
|
535
415
|
const meta = parseJsDocMetadata(frontmatterCode);
|
|
@@ -543,15 +423,14 @@ async function main() {
|
|
|
543
423
|
required: !p.optional,
|
|
544
424
|
defaultValue: defaultsMap.has(p.name) ? defaultsMap.get(p.name) : null
|
|
545
425
|
}));
|
|
546
|
-
const slug =
|
|
547
|
-
const pascal = f.name.replace(/\.(astro)$/i, "");
|
|
426
|
+
const slug = slugify(pascal);
|
|
548
427
|
const title = meta.title || meta.name || pascal;
|
|
549
428
|
const description = meta.description || "";
|
|
550
429
|
const descriptionBodyMDX = meta.descriptionBodyMDX || "";
|
|
551
430
|
const figmaUrl = meta.figmaUrl || "";
|
|
552
431
|
const propsList = "";
|
|
553
432
|
const importName = pascal;
|
|
554
|
-
const importPath = `${componentsAlias}/${pascal}.astro`;
|
|
433
|
+
const importPath = isFolder ? `${componentsAlias}/${folderName}` : `${componentsAlias}/${pascal}.astro`;
|
|
555
434
|
const { text: usageMDX, hasImport: hasImportUsage } = normalizeUsageMDX(meta.usageMDX || "", pascal);
|
|
556
435
|
const primaryExampleMDX = normalizeBlockMDX(meta.primaryExampleMDX || "").trim();
|
|
557
436
|
const examplesMDX = normalizeBlockMDX(meta.examplesMDX || "").trim();
|
|
@@ -565,13 +444,13 @@ async function main() {
|
|
|
565
444
|
exampleRelPaths = await discoverExamples(filePath, componentsDir);
|
|
566
445
|
examples = (exampleRelPaths || []).map((rel) => {
|
|
567
446
|
const posixRel = rel.split(__require("path").sep).join(__require("path").posix.sep);
|
|
568
|
-
const
|
|
447
|
+
const importPathEx = `${componentsAlias}/${posixRel}`;
|
|
569
448
|
const abs = join(componentsDir, rel);
|
|
570
449
|
const source = __require("fs").readFileSync(abs, "utf-8");
|
|
571
450
|
const base = toIdentifier(__require("path").basename(rel, __require("path").extname(rel)));
|
|
572
451
|
return {
|
|
573
452
|
importName: `${pascal}${base}`,
|
|
574
|
-
importPath:
|
|
453
|
+
importPath: importPathEx,
|
|
575
454
|
title: base,
|
|
576
455
|
source
|
|
577
456
|
};
|
|
@@ -585,6 +464,8 @@ async function main() {
|
|
|
585
464
|
...usedInExamples,
|
|
586
465
|
...usedInPrimary
|
|
587
466
|
]);
|
|
467
|
+
const usedNamedExports = isFolder ? namedExports.filter((n) => autoSet.has(n)) : [];
|
|
468
|
+
if (isFolder) for (const n of namedExports) autoSet.delete(n);
|
|
588
469
|
const autoImports = Array.from(autoSet).filter((name) => !RESERVED_COMPONENTS.has(name)).filter((name) => true);
|
|
589
470
|
const lucideIcons = autoImports.filter((n) => /Icon$/.test(n));
|
|
590
471
|
const uiAutoImports = autoImports.filter((n) => !/Icon$/.test(n));
|
|
@@ -606,7 +487,8 @@ async function main() {
|
|
|
606
487
|
commandName: slug,
|
|
607
488
|
figmaUrl,
|
|
608
489
|
descriptionBodyMDX,
|
|
609
|
-
componentsAlias
|
|
490
|
+
componentsAlias,
|
|
491
|
+
namedExports: isFolder ? usedNamedExports : void 0
|
|
610
492
|
});
|
|
611
493
|
const outFile = join(outDir, `${slug}.mdx`);
|
|
612
494
|
mkdirSync(dirname(outFile), { recursive: true });
|
|
@@ -616,8 +498,8 @@ async function main() {
|
|
|
616
498
|
if (DEBUG) logger.info(`Generated ${outFile}`);
|
|
617
499
|
}
|
|
618
500
|
spin.succeed(`Created ${generatedCount} file${generatedCount === 1 ? "" : "s"}:`);
|
|
619
|
-
|
|
620
|
-
const slug =
|
|
501
|
+
components.map((c) => {
|
|
502
|
+
const slug = slugify(c.name);
|
|
621
503
|
const outFile = join(outDir, `${slug}.mdx`);
|
|
622
504
|
return relative(cwd, outFile);
|
|
623
505
|
}).sort((a, b) => a.localeCompare(b)).forEach((p) => {
|
|
@@ -661,4 +543,4 @@ if (process.env.BEJAMAS_SKIP_AUTO_RUN !== "1" && process.env.BEJAMAS_SKIP_AUTO_R
|
|
|
661
543
|
|
|
662
544
|
//#endregion
|
|
663
545
|
export { runDocsGenerator };
|
|
664
|
-
//# sourceMappingURL=generate-mdx-
|
|
546
|
+
//# sourceMappingURL=generate-mdx-Csh3BuQB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-mdx-Csh3BuQB.js","names":["path","lines: string[]","mainImportLine: string | null","m: RegExpExecArray | null","external: string[]","internal: string[]","exampleSections: string[]","entries: ComponentEntry[]","exports: string[]","match: RegExpExecArray | null","exampleRelPaths: string[]","examples: Array<{\n importName: string;\n importPath: string;\n title: string;\n source: string;\n }>","blocks: Array<{ title: string; body: string[] }>","current: { title: string; body: string[] }"],"sources":["../src/docs/generate-mdx/mdx-builder.ts","../src/docs/generate-mdx/index.ts"],"sourcesContent":["/**\n * Check if an import path uses the new barrel export pattern (no .astro extension)\n */\nfunction isBarrelImport(path: string): boolean {\n return !path.endsWith(\".astro\");\n}\n\n/**\n * Convert a PascalCase component name to its folder path (kebab-case).\n * Examples:\n * - \"Card\" → \"card\"\n * - \"CardHeader\" → \"card\"\n * - \"InputGroup\" → \"input-group\"\n * - \"InputGroupAddon\" → \"input-group\"\n * - \"StickySurface\" → \"sticky-surface\"\n * - \"RadioGroup\" → \"radio-group\"\n * - \"RadioGroupItem\" → \"radio-group\"\n */\nfunction componentToFolder(name: string): string {\n // Known multi-word component families (in PascalCase order)\n // These map to kebab-case folder names\n const multiWordFamilies = [\n \"InputGroup\",\n \"LinkGroup\",\n \"RadioGroup\",\n \"ButtonGroup\",\n \"StickySurface\",\n ];\n\n // Check for multi-word families first (order matters - longer matches first)\n const sortedFamilies = multiWordFamilies.sort((a, b) => b.length - a.length);\n for (const family of sortedFamilies) {\n if (name === family || name.startsWith(family)) {\n // InputGroup → input-group\n return family.replace(/([a-z])([A-Z])/g, \"$1-$2\").toLowerCase();\n }\n }\n\n // For regular names, extract the base component (first PascalCase word)\n // CardHeader → Card → card\n // AvatarFallback → Avatar → avatar\n const baseMatch = name.match(/^[A-Z][a-z]*/);\n return baseMatch ? baseMatch[0].toLowerCase() : name.toLowerCase();\n}\n\n/**\n * Group component names by their folder path\n */\nfunction groupComponentsByFolder(components: string[]): Map<string, string[]> {\n const groups = new Map<string, string[]>();\n for (const comp of components) {\n const folder = componentToFolder(comp);\n if (!groups.has(folder)) {\n groups.set(folder, []);\n }\n groups.get(folder)!.push(comp);\n }\n return groups;\n}\n\n/**\n * Generate import lines for UI components using the barrel import pattern\n */\nfunction generateBarrelImports(\n components: string[],\n componentsAlias: string,\n): string[] {\n const groups = groupComponentsByFolder(components);\n const lines: string[] = [];\n\n // Sort folders alphabetically for consistent output\n const sortedFolders = Array.from(groups.keys()).sort();\n\n for (const folder of sortedFolders) {\n const names = groups.get(folder)!.sort();\n lines.push(\n `import { ${names.join(\", \")} } from '${componentsAlias}/${folder}';`,\n );\n }\n\n return lines;\n}\n\n/**\n * Generate import lines for UI components using the old default import pattern\n */\nfunction generateDefaultImports(\n components: string[],\n componentsAlias: string,\n): string[] {\n return components\n .slice()\n .sort()\n .map((name) => `import ${name} from '${componentsAlias}/${name}.astro';`);\n}\n\nexport function buildMdx(params: {\n importName: string;\n importPath: string;\n title: string;\n description: string;\n descriptionBodyMDX?: string;\n figmaUrl?: string;\n usageMDX: string;\n hasImport: boolean;\n propsList: string;\n propsTable?: Array<{\n name: string;\n type?: string;\n required?: boolean;\n defaultValue?: string | null;\n description?: string | null;\n }>;\n examples: Array<{\n importName: string;\n importPath: string;\n title: string;\n source: string;\n }>;\n examplesBlocks: Array<{ title: string; body: string }>;\n autoImports: string[];\n lucideIcons: string[];\n primaryExampleMDX: string;\n componentSource: string;\n commandName: string;\n componentsAlias: string;\n /**\n * Optional: additional named exports from the main component's barrel.\n * Used when the main component has subcomponents (e.g., Card, CardHeader, CardTitle).\n * If provided, these will be included in the main import statement.\n */\n namedExports?: string[];\n}): string {\n const {\n importName,\n importPath,\n title,\n description,\n descriptionBodyMDX,\n usageMDX,\n hasImport,\n propsList,\n propsTable,\n examples,\n examplesBlocks,\n autoImports,\n lucideIcons,\n primaryExampleMDX,\n componentSource,\n commandName,\n figmaUrl,\n componentsAlias,\n namedExports,\n } = params;\n\n // Detect if we should use the new barrel import pattern\n const useBarrelPattern = isBarrelImport(importPath);\n\n const sortedLucide = (lucideIcons ?? []).slice().sort();\n const lucideTopLine = sortedLucide.length\n ? `import { ${sortedLucide.join(\", \")} } from '@lucide/astro';`\n : null;\n const externalTopImports = [\n `import { Tabs as DocsTabs, TabItem as DocsTabItem } from '@astrojs/starlight/components';`,\n lucideTopLine,\n ]\n .filter((v) => v != null)\n .slice()\n .sort((a, b) => String(a).localeCompare(String(b)));\n\n const sortedUiAuto = (autoImports ?? []).slice().sort();\n\n // Generate UI component imports based on pattern\n const uiAutoLines = useBarrelPattern\n ? generateBarrelImports(sortedUiAuto, componentsAlias)\n : generateDefaultImports(sortedUiAuto, componentsAlias);\n\n const exampleLines = (examples ?? [])\n .map((ex) => `import ${ex.importName} from '${ex.importPath}';`)\n .sort((a, b) => a.localeCompare(b));\n\n // Build main component import\n let mainImportLine: string | null = null;\n if (!hasImport) {\n if (useBarrelPattern) {\n // New pattern: named exports\n const exports = [importName, ...(namedExports ?? [])].sort();\n mainImportLine = `import { ${exports.join(\", \")} } from '${importPath}';`;\n } else {\n // Old pattern: default export\n mainImportLine = `import ${importName} from '${importPath}';`;\n }\n }\n\n const internalTopImports = [mainImportLine, ...uiAutoLines, ...exampleLines]\n .filter((v) => v != null)\n .slice()\n .sort((a, b) => String(a).localeCompare(String(b)));\n\n const importLines = [\n ...externalTopImports,\n externalTopImports.length && internalTopImports.length ? \"\" : null,\n ...internalTopImports,\n ].filter((v) => v !== null && v !== undefined);\n\n // Helper: build per-snippet imports so code fences are minimal and copy-pasteable\n const extractTags = (snippet: string): Set<string> => {\n const found = new Set<string>();\n const tagRegex = /<([A-Z][A-Za-z0-9_]*)\\b/g;\n let m: RegExpExecArray | null;\n while ((m = tagRegex.exec(snippet)) !== null) {\n found.add(m[1]);\n }\n return found;\n };\n\n const buildSnippetImportLines = (snippet: string): string[] => {\n if (!snippet || !snippet.length) return [];\n const used = extractTags(snippet);\n const usedIcons = sortedLucide.filter((n) => used.has(n));\n\n // Find UI components used in snippet\n const usedUi = (autoImports ?? []).filter((n) => used.has(n));\n\n // Check if main component (and its subcomponents) are used\n const includeMain = !hasImport && used.has(importName);\n\n // For new pattern, also check for subcomponents from the main barrel\n const usedNamedExports =\n useBarrelPattern && namedExports\n ? namedExports.filter((n) => used.has(n))\n : [];\n\n const external: string[] = [];\n if (usedIcons.length) {\n external.push(`import { ${usedIcons.join(\", \")} } from '@lucide/astro';`);\n }\n\n const internal: string[] = [];\n\n if (useBarrelPattern) {\n // New pattern: group by folder and use named imports\n\n // Main component and its subcomponents\n if (includeMain || usedNamedExports.length > 0) {\n const mainExports = [\n ...(includeMain ? [importName] : []),\n ...usedNamedExports,\n ].sort();\n internal.push(\n `import { ${mainExports.join(\", \")} } from '${importPath}';`,\n );\n }\n\n // Other UI components grouped by folder\n if (usedUi.length > 0) {\n internal.push(...generateBarrelImports(usedUi, componentsAlias));\n }\n } else {\n // Old pattern: default imports\n if (includeMain) {\n internal.push(`import ${importName} from '${importPath}';`);\n }\n internal.push(\n ...usedUi\n .slice()\n .sort()\n .map(\n (name) => `import ${name} from '${componentsAlias}/${name}.astro';`,\n ),\n );\n }\n\n const externalSorted = external.slice().sort((a, b) => a.localeCompare(b));\n const internalSorted = internal.slice().sort((a, b) => a.localeCompare(b));\n return [\n ...externalSorted,\n externalSorted.length && internalSorted.length ? \"\" : null,\n ...internalSorted,\n ].filter((v) => v !== null && v !== undefined) as string[];\n };\n\n const wrapTextNodes = (snippet: string): string => {\n if (!snippet) return snippet;\n return snippet.replace(/>([^<]+)</g, (match, inner) => {\n const trimmed = inner.trim();\n if (!trimmed.length) return match;\n if (/^\\{[\\s\\S]*\\}$/.test(trimmed)) return match;\n return `>{${JSON.stringify(inner)}}<`;\n });\n };\n\n const toMdxPreview = (snippet: string): string => {\n if (!snippet) return snippet;\n // Convert HTML comments to MDX comment blocks for preview sections\n const withoutComments = snippet.replace(/<!--([\\s\\S]*?)-->/g, \"{/*$1*/}\");\n return wrapTextNodes(withoutComments);\n };\n\n // Split an example body into leading markdown description (paragraphs)\n // and the Astro/HTML snippet that should be rendered in Preview/Source tabs\n const splitDescriptionAndSnippet = (\n body: string,\n ): { descriptionMD: string; snippet: string } => {\n if (!body || !body.trim().length) return { descriptionMD: \"\", snippet: \"\" };\n const lines = body.split(\"\\n\");\n let snippetStartIdx = -1;\n for (let i = 0; i < lines.length; i++) {\n const ln = lines[i];\n // Skip empty lines before first meaningful content\n if (!ln.trim().length) continue;\n // Heuristic: consider this line the start of the snippet if it looks like Astro/HTML/JSX\n // e.g. starts with '<' or '{'\n if (/^\\s*[<{]/.test(ln)) {\n snippetStartIdx = i;\n break;\n }\n // Otherwise it's part of markdown description; keep looking until we hit markup\n }\n if (snippetStartIdx <= 0) {\n // No clear description or snippet starts at the very beginning → treat all as snippet\n return { descriptionMD: \"\", snippet: body.trim() };\n }\n const descriptionMD = lines.slice(0, snippetStartIdx).join(\"\\n\").trim();\n const snippet = lines.slice(snippetStartIdx).join(\"\\n\").trim();\n return { descriptionMD, snippet };\n };\n\n const primaryExampleSection =\n primaryExampleMDX && primaryExampleMDX.length\n ? `<DocsTabs>\n <DocsTabItem label=\"Preview\">\n <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\">\n${toMdxPreview(primaryExampleMDX)}\n </div>\n </DocsTabItem>\n <DocsTabItem label=\"Source\">\n\n\\`\\`\\`astro\n${(() => {\n const lines = buildSnippetImportLines(primaryExampleMDX);\n return lines.length ? `---\\n${lines.join(\"\\n\")}\\n---\\n\\n` : \"\";\n})()}${primaryExampleMDX}\n\\`\\`\\`\n </DocsTabItem>\n</DocsTabs>`\n : null;\n\n const exampleSections: string[] = [];\n if (examplesBlocks && examplesBlocks.length) {\n for (const blk of examplesBlocks) {\n const { descriptionMD, snippet } = splitDescriptionAndSnippet(blk.body);\n const previewBody = toMdxPreview(snippet);\n\n // If there's no snippet, render only header + description\n if (!snippet || !snippet.length) {\n exampleSections.push(\n `### ${blk.title}\n\n${descriptionMD}`.trim(),\n );\n continue;\n }\n\n exampleSections.push(\n `### ${blk.title}\n\n${descriptionMD ? `${descriptionMD}\\n\\n` : \"\"}<DocsTabs>\n <DocsTabItem label=\"Preview\">\n <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\">\n${previewBody}\n </div>\n </DocsTabItem>\n <DocsTabItem label=\"Source\">\n\n\\`\\`\\`astro\n${(() => {\n const lines = buildSnippetImportLines(snippet);\n return lines.length ? `---\\n${lines.join(\"\\n\")}\\n---\\n\\n` : \"\";\n})()}${snippet}\n\\`\\`\\`\n </DocsTabItem>\n</DocsTabs>`,\n );\n }\n }\n if (examples && examples.length) {\n for (const ex of examples) {\n exampleSections.push(\n `### ${ex.title}\n\n<DocsTabs>\n <DocsTabItem label=\"Preview\">\n <div class=\"not-content\">\n <${ex.importName} />\n </div>\n </DocsTabItem>\n <DocsTabItem label=\"Source\">\n\n\\`\\`\\`astro\n${ex.source}\n\\`\\`\\`\n </DocsTabItem>\n</DocsTabs>`,\n );\n }\n }\n\n const formatDefault = (val: unknown): string => {\n if (val == null) return \"\";\n let raw = String(val).trim();\n if (!raw.length) return \"\";\n // Normalize curly quotes to ASCII\n raw = raw\n .replace(/[\\u201C\\u201D\\u201E\\u201F]/g, '\"')\n .replace(/[\\u2018\\u2019]/g, \"'\");\n const isSingleQuoted = /^'[^']*'$/.test(raw);\n const isDoubleQuoted = /^\"[^\"]*\"$/.test(raw);\n const isBacktickSimple = /^`[^`]*`$/.test(raw) && raw.indexOf(\"${\") === -1;\n\n let content = raw;\n if (isSingleQuoted || isDoubleQuoted || isBacktickSimple) {\n const inner = raw.slice(1, -1);\n // Re-quote with standard double quotes\n content = `\"${inner}\"`;\n }\n // Escape table pipes\n content = content.replace(/\\|/g, \"\\\\|\");\n // Choose a backtick fence that doesn't appear in content\n const hasTick = content.includes(\"`\");\n const hasDoubleTick = content.includes(\"``\");\n const fence = !hasTick ? \"`\" : !hasDoubleTick ? \"``\" : \"```\";\n return `${fence}${content}${fence}`;\n };\n\n const installationSection = `## Installation\n<DocsTabs syncKey=\"installation\">\n <DocsTabItem label=\"CLI\">\n\n<DocsTabs syncKey=\"pkg\">\n <DocsTabItem label=\"bun\">\n\n\\`\\`\\`bash\n bunx bejamas add ${commandName}\n\\`\\`\\`\n\n </DocsTabItem>\n <DocsTabItem label=\"npm\">\n\n\\`\\`\\`bash\n npx bejamas add ${commandName}\n\\`\\`\\`\n\n </DocsTabItem>\n <DocsTabItem label=\"pnpm\">\n\n\\`\\`\\`bash\n pnpm dlx bejamas add ${commandName}\n\\`\\`\\`\n\n </DocsTabItem>\n <DocsTabItem label=\"yarn\">\n\n\\`\\`\\`bash\n yarn dlx bejamas add ${commandName}\n\\`\\`\\`\n\n </DocsTabItem>\n</DocsTabs>\n</DocsTabItem>\n<DocsTabItem label=\"Manual\">\n\n\\`\\`\\`astro\n${componentSource}\n\\`\\`\\`\n </DocsTabItem>\n</DocsTabs>`;\n\n const serializeFrontmatter = (\n label: string,\n value?: string,\n ): string | null => {\n if (!value || !value.length) return null;\n return `${label}: ${JSON.stringify(value)}`;\n };\n\n const lines = [\n \"---\",\n serializeFrontmatter(\"title\", title),\n serializeFrontmatter(\"description\", description),\n serializeFrontmatter(\"figmaUrl\", figmaUrl),\n \"---\",\n \"\",\n ...importLines,\n importLines.length ? \"\" : null,\n descriptionBodyMDX && descriptionBodyMDX.length ? descriptionBodyMDX : null,\n descriptionBodyMDX && descriptionBodyMDX.length ? \"\" : null,\n primaryExampleSection,\n primaryExampleSection ? \"\" : null,\n installationSection,\n \"\",\n usageMDX && usageMDX.length ? `## Usage\\n\\n${usageMDX}` : null,\n \"\",\n propsTable && propsTable.length\n ? `## Props\\n\\n| Prop | Type | Default |\\n|---|---|---|\\n${propsTable\n .map(\n (p) =>\n `| <code>${p.name}</code> | \\`${(p.type || \"\").replace(/\\|/g, \"\\\\|\")}\\` | ${formatDefault(p.defaultValue)} |`,\n )\n .join(\"\\n\")}`\n : propsList\n ? `## Props\\n\\n${propsList}`\n : null,\n (propsTable && propsTable.length) || propsList ? \"\" : null,\n exampleSections.length\n ? `## Examples\\n\\n` + exampleSections.join(\"\\n\\n\")\n : null,\n ].filter((v) => v !== null && v !== undefined);\n\n return lines.join(\"\\n\").trim() + \"\\n\";\n}\n","import { mkdirSync, existsSync } from \"fs\";\nimport { readdir, readFile, writeFile } from \"fs/promises\";\nimport { join, extname, dirname, relative, basename } from \"path\";\nimport {\n RESERVED_COMPONENTS,\n slugify,\n extractFrontmatter,\n toIdentifier,\n parseJsDocMetadata,\n extractPropsFromAstroProps,\n extractPropsFromDeclaredProps,\n resolveUiRoot,\n resolveOutDir,\n normalizeUsageMDX,\n normalizeBlockMDX,\n detectHasImportTopLevel,\n discoverExamples,\n extractComponentTagsFromMDX,\n createSourceFileFromFrontmatter,\n} from \"./utils\";\nimport { buildMdx } from \"./mdx-builder\";\nimport { logger } from \"@/src/utils/logger\";\nimport { spinner } from \"@/src/utils/spinner\";\nimport { getConfig } from \"@/src/utils/get-config\";\n\ninterface ComponentEntry {\n /** The main component name (PascalCase), e.g., \"Card\" */\n name: string;\n /** Path to the main .astro file */\n filePath: string;\n /** The folder name (lowercase/kebab-case), e.g., \"card\" */\n folderName: string;\n /** Whether this is a folder-based component with barrel exports */\n isFolder: boolean;\n /** List of subcomponent names exported from the barrel, e.g., [\"CardHeader\", \"CardTitle\"] */\n namedExports: string[];\n}\n\n/**\n * Discover components in the components directory.\n * Supports both:\n * - Old pattern: flat .astro files in components/\n * - New pattern: folders with index.ts barrel exports\n */\nasync function discoverComponents(\n componentsDir: string,\n): Promise<ComponentEntry[]> {\n const entries: ComponentEntry[] = [];\n const dirEntries = await readdir(componentsDir, { withFileTypes: true });\n\n for (const entry of dirEntries) {\n if (entry.isDirectory()) {\n // New pattern: folder with barrel exports\n const folderPath = join(componentsDir, entry.name);\n const indexPath = join(folderPath, \"index.ts\");\n\n if (existsSync(indexPath)) {\n // Parse the barrel file to find exports\n const indexContent = await readFile(indexPath, \"utf-8\");\n const namedExports = parseBarrelExports(indexContent);\n\n // Find the main component (first export or the one matching folder name)\n const mainComponentName = findMainComponent(namedExports, entry.name);\n\n if (mainComponentName) {\n const mainFilePath = join(folderPath, `${mainComponentName}.astro`);\n\n if (existsSync(mainFilePath)) {\n // Filter out the main component from namedExports (it will be imported separately)\n const subComponents = namedExports.filter(\n (n) => n !== mainComponentName,\n );\n\n entries.push({\n name: mainComponentName,\n filePath: mainFilePath,\n folderName: entry.name,\n isFolder: true,\n namedExports: subComponents,\n });\n }\n }\n }\n } else if (entry.isFile() && extname(entry.name).toLowerCase() === \".astro\") {\n // Old pattern: flat .astro file\n const componentName = entry.name.replace(/\\.astro$/i, \"\");\n entries.push({\n name: componentName,\n filePath: join(componentsDir, entry.name),\n folderName: \"\",\n isFolder: false,\n namedExports: [],\n });\n }\n }\n\n return entries;\n}\n\n/**\n * Parse a barrel (index.ts) file to extract named exports.\n * Handles patterns like:\n * - export { default as Card } from \"./Card.astro\";\n * - export { default as CardHeader } from \"./CardHeader.astro\";\n */\nfunction parseBarrelExports(content: string): string[] {\n const exports: string[] = [];\n\n // Match: export { default as ComponentName } from \"...\"\n const exportRegex = /export\\s*\\{\\s*default\\s+as\\s+(\\w+)\\s*\\}/g;\n let match: RegExpExecArray | null;\n\n while ((match = exportRegex.exec(content)) !== null) {\n exports.push(match[1]);\n }\n\n return exports;\n}\n\n/**\n * Find the main component from a list of exports.\n * The main component is typically the one that matches the folder name (PascalCase).\n */\nfunction findMainComponent(\n exports: string[],\n folderName: string,\n): string | null {\n if (exports.length === 0) return null;\n\n // Convert folder name to PascalCase for comparison\n // e.g., \"card\" -> \"Card\", \"input-group\" -> \"InputGroup\"\n const expectedName = folderName\n .split(\"-\")\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(\"\");\n\n // First, try to find exact match\n const exactMatch = exports.find((e) => e === expectedName);\n if (exactMatch) return exactMatch;\n\n // Otherwise, return the first export (usually the main component)\n return exports[0];\n}\n\nasync function main() {\n const DEBUG =\n process.env.BEJAMAS_DEBUG === \"1\" || process.env.BEJAMAS_DEBUG === \"true\";\n const cwd =\n process.env.BEJAMAS_DOCS_CWD && process.env.BEJAMAS_DOCS_CWD.length\n ? (process.env.BEJAMAS_DOCS_CWD as string)\n : process.cwd();\n const config = await getConfig(cwd);\n const componentsAlias = (\n config?.aliases?.ui ||\n config?.aliases?.components ||\n \"@bejamas/ui/components\"\n ).replace(/\\/$/, \"\");\n const componentsDirFromConfig =\n config?.resolvedPaths?.ui || config?.resolvedPaths?.components;\n let uiRoot = resolveUiRoot(cwd);\n let componentsDir = join(uiRoot, \"src\", \"components\");\n if (componentsDirFromConfig) {\n componentsDir = componentsDirFromConfig;\n uiRoot = dirname(dirname(componentsDirFromConfig));\n }\n if (!existsSync(componentsDir)) {\n // Fallback to ui package components if the configured path is missing.\n componentsDir = join(uiRoot, \"src\", \"components\");\n }\n const outDir = resolveOutDir(cwd);\n mkdirSync(outDir, { recursive: true });\n\n if (DEBUG) {\n logger.info(`[docs-generator] cwd: ${cwd}`);\n logger.info(`[docs-generator] uiRoot: ${uiRoot}`);\n logger.info(`[docs-generator] componentsDir: ${componentsDir}`);\n logger.info(`[docs-generator] outDir: ${outDir}`);\n }\n\n // Discover all components (both flat files and folders)\n const components = await discoverComponents(componentsDir);\n\n if (DEBUG) {\n logger.info(`[docs-generator] components found: ${components.length}`);\n if (components.length) {\n logger.info(\n `[docs-generator] first few: ${components\n .slice(0, 5)\n .map((c) => c.name)\n .join(\", \")}`,\n );\n }\n }\n\n let generatedCount = 0;\n const total = components.length;\n const spin = spinner(`Generating docs (0/${total})`).start();\n\n for (const component of components) {\n const { name: pascal, filePath, folderName, isFolder, namedExports } = component;\n\n const astroFile = await readFile(filePath, \"utf-8\");\n const frontmatterCode = extractFrontmatter(astroFile);\n const sourceFile = createSourceFileFromFrontmatter(frontmatterCode);\n const meta = parseJsDocMetadata(frontmatterCode);\n const declaredProps = extractPropsFromDeclaredProps(sourceFile);\n const destructuredProps = extractPropsFromAstroProps(sourceFile);\n\n // Build props table preferring declared types; merge defaults from destructuring\n const defaultsMap = new Map<string, string | null>();\n for (const p of destructuredProps) {\n if (p.name && p.hasDefault) {\n defaultsMap.set(p.name, p.defaultValue || null);\n }\n }\n\n const propsTable = (declaredProps.length ? declaredProps : []).map((p) => ({\n name: p.name,\n type: p.type,\n required: !p.optional,\n defaultValue: defaultsMap.has(p.name) ? defaultsMap.get(p.name)! : null,\n }));\n\n const slug = slugify(pascal);\n const title = meta.title || meta.name || pascal;\n const description = meta.description || \"\";\n const descriptionBodyMDX = (meta as any).descriptionBodyMDX || \"\";\n const figmaUrl = (meta as any).figmaUrl || \"\";\n // Do not display props if there is no declared Props\n const propsList = \"\";\n\n const importName = pascal;\n // Use folder-based barrel import for new pattern, file-based for old pattern\n const importPath = isFolder\n ? `${componentsAlias}/${folderName}`\n : `${componentsAlias}/${pascal}.astro`;\n\n const { text: usageMDX, hasImport: hasImportUsage } = normalizeUsageMDX(\n meta.usageMDX || \"\",\n pascal,\n );\n const primaryExampleMDX = normalizeBlockMDX(\n meta.primaryExampleMDX || \"\",\n ).trim();\n const examplesMDX = normalizeBlockMDX(meta.examplesMDX || \"\").trim();\n const hasImportExamples = detectHasImportTopLevel(examplesMDX, pascal);\n const hasImportPrimary = detectHasImportTopLevel(primaryExampleMDX, pascal);\n const hasImport = hasImportUsage || hasImportExamples || hasImportPrimary;\n\n let exampleRelPaths: string[] = [];\n let examples: Array<{\n importName: string;\n importPath: string;\n title: string;\n source: string;\n }> = [];\n const examplesBlocksRaw = examplesMDX;\n const examplesBlocks = parseExamplesBlocks(examplesBlocksRaw);\n if (examplesBlocks.length === 0) {\n exampleRelPaths = await discoverExamples(filePath, componentsDir);\n examples = (exampleRelPaths || []).map((rel) => {\n const posixRel = rel\n .split(require(\"path\").sep)\n .join(require(\"path\").posix.sep);\n const importPathEx = `${componentsAlias}/${posixRel}`;\n const abs = join(componentsDir, rel);\n const source = require(\"fs\").readFileSync(abs, \"utf-8\");\n const base = toIdentifier(\n require(\"path\").basename(rel, require(\"path\").extname(rel)),\n );\n const importNameEx = `${pascal}${base}`;\n const titleEx = base;\n return { importName: importNameEx, importPath: importPathEx, title: titleEx, source };\n });\n }\n\n const usedInUsage = extractComponentTagsFromMDX(usageMDX).filter(\n (n) => n !== pascal,\n );\n const usedInExamples = extractComponentTagsFromMDX(examplesMDX).filter(\n (n) => n !== pascal,\n );\n const usedInPrimary = extractComponentTagsFromMDX(primaryExampleMDX).filter(\n (n) => n !== pascal,\n );\n const autoSet = new Set<string>([\n ...usedInUsage,\n ...usedInExamples,\n ...usedInPrimary,\n ]);\n\n // For folder-based components, add subcomponents used in examples to namedExports\n const usedNamedExports = isFolder\n ? namedExports.filter((n) => autoSet.has(n))\n : [];\n\n // Remove subcomponents from autoSet (they'll be included via namedExports)\n if (isFolder) {\n for (const n of namedExports) {\n autoSet.delete(n);\n }\n }\n\n const autoImports = Array.from(autoSet)\n .filter((name) => !RESERVED_COMPONENTS.has(name))\n .filter((name) => true);\n\n const lucideIcons = autoImports.filter((n) => /Icon$/.test(n));\n const uiAutoImports = autoImports.filter((n) => !/Icon$/.test(n));\n\n const mdx = buildMdx({\n importName,\n importPath,\n title,\n description,\n usageMDX,\n hasImport,\n propsList,\n propsTable,\n examples,\n examplesBlocks: parseExamplesBlocks(examplesBlocksRaw),\n autoImports: uiAutoImports,\n lucideIcons,\n primaryExampleMDX,\n componentSource: astroFile.trim(),\n commandName: slug,\n figmaUrl,\n descriptionBodyMDX,\n componentsAlias,\n // Pass subcomponents as named exports for folder-based components\n namedExports: isFolder ? usedNamedExports : undefined,\n });\n const outFile = join(outDir, `${slug}.mdx`);\n mkdirSync(dirname(outFile), { recursive: true });\n await writeFile(outFile, mdx, \"utf-8\");\n generatedCount += 1;\n spin.text = `Generating docs (${generatedCount}/${total}) - ${title}`;\n if (DEBUG) logger.info(`Generated ${outFile}`);\n }\n spin.succeed(\n `Created ${generatedCount} file${generatedCount === 1 ? \"\" : \"s\"}:`,\n );\n // log all files with relative paths, sorted alphabetically\n const relPaths = components\n .map((c) => {\n const slug = slugify(c.name);\n const outFile = join(outDir, `${slug}.mdx`);\n return relative(cwd, outFile);\n })\n .sort((a, b) => a.localeCompare(b));\n relPaths.forEach((p) => {\n logger.log(` - ${p}`);\n });\n logger.break();\n}\n\nexport function parseExamplesBlocks(\n examplesMDX: string,\n): Array<{ title: string; body: string }> {\n if (!examplesMDX) return [];\n const lines = examplesMDX.split(\"\\n\");\n const blocks: Array<{ title: string; body: string[] }> = [];\n let current: { title: string; body: string[] } = { title: \"\", body: [] };\n for (const line of lines) {\n const heading = line.match(/^###\\s+(.+)$/);\n if (heading) {\n if (current.title || current.body.length) blocks.push(current);\n current = { title: heading[1].trim(), body: [] };\n continue;\n }\n current.body.push(line);\n }\n if (current.title || current.body.length) blocks.push(current);\n return blocks.map((b, idx) => ({\n title: b.title || `Example ${idx + 1}`,\n body: b.body.join(\"\\n\").trim(),\n }));\n}\n\nexport async function runDocsGenerator(): Promise<void> {\n await main();\n}\n\nif (\n process.env.BEJAMAS_SKIP_AUTO_RUN !== \"1\" &&\n process.env.BEJAMAS_SKIP_AUTO_RUN !== \"true\"\n) {\n runDocsGenerator().catch((err) => {\n logger.error(String(err));\n process.exit(1);\n });\n}\n"],"mappings":";;;;;;;;;;;;;;AAGA,SAAS,eAAe,QAAuB;AAC7C,QAAO,CAACA,OAAK,SAAS,SAAS;;;;;;;;;;;;;AAcjC,SAAS,kBAAkB,MAAsB;CAY/C,MAAM,iBAToB;EACxB;EACA;EACA;EACA;EACA;EACD,CAGwC,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,OAAO;AAC5E,MAAK,MAAM,UAAU,eACnB,KAAI,SAAS,UAAU,KAAK,WAAW,OAAO,CAE5C,QAAO,OAAO,QAAQ,mBAAmB,QAAQ,CAAC,aAAa;CAOnE,MAAM,YAAY,KAAK,MAAM,eAAe;AAC5C,QAAO,YAAY,UAAU,GAAG,aAAa,GAAG,KAAK,aAAa;;;;;AAMpE,SAAS,wBAAwB,YAA6C;CAC5E,MAAM,yBAAS,IAAI,KAAuB;AAC1C,MAAK,MAAM,QAAQ,YAAY;EAC7B,MAAM,SAAS,kBAAkB,KAAK;AACtC,MAAI,CAAC,OAAO,IAAI,OAAO,CACrB,QAAO,IAAI,QAAQ,EAAE,CAAC;AAExB,SAAO,IAAI,OAAO,CAAE,KAAK,KAAK;;AAEhC,QAAO;;;;;AAMT,SAAS,sBACP,YACA,iBACU;CACV,MAAM,SAAS,wBAAwB,WAAW;CAClD,MAAMC,QAAkB,EAAE;CAG1B,MAAM,gBAAgB,MAAM,KAAK,OAAO,MAAM,CAAC,CAAC,MAAM;AAEtD,MAAK,MAAM,UAAU,eAAe;EAClC,MAAM,QAAQ,OAAO,IAAI,OAAO,CAAE,MAAM;AACxC,QAAM,KACJ,YAAY,MAAM,KAAK,KAAK,CAAC,WAAW,gBAAgB,GAAG,OAAO,IACnE;;AAGH,QAAO;;;;;AAMT,SAAS,uBACP,YACA,iBACU;AACV,QAAO,WACJ,OAAO,CACP,MAAM,CACN,KAAK,SAAS,UAAU,KAAK,SAAS,gBAAgB,GAAG,KAAK,UAAU;;AAG7E,SAAgB,SAAS,QAoCd;CACT,MAAM,EACJ,YACA,YACA,OACA,aACA,oBACA,UACA,WACA,WACA,YACA,UACA,gBACA,aACA,aACA,mBACA,iBACA,aACA,UACA,iBACA,iBACE;CAGJ,MAAM,mBAAmB,eAAe,WAAW;CAEnD,MAAM,gBAAgB,eAAe,EAAE,EAAE,OAAO,CAAC,MAAM;CAIvD,MAAM,qBAAqB,CACzB,6FAJoB,aAAa,SAC/B,YAAY,aAAa,KAAK,KAAK,CAAC,4BACpC,KAIH,CACE,QAAQ,MAAM,KAAK,KAAK,CACxB,OAAO,CACP,MAAM,GAAG,MAAM,OAAO,EAAE,CAAC,cAAc,OAAO,EAAE,CAAC,CAAC;CAErD,MAAM,gBAAgB,eAAe,EAAE,EAAE,OAAO,CAAC,MAAM;CAGvD,MAAM,cAAc,mBAChB,sBAAsB,cAAc,gBAAgB,GACpD,uBAAuB,cAAc,gBAAgB;CAEzD,MAAM,gBAAgB,YAAY,EAAE,EACjC,KAAK,OAAO,UAAU,GAAG,WAAW,SAAS,GAAG,WAAW,IAAI,CAC/D,MAAM,GAAG,MAAM,EAAE,cAAc,EAAE,CAAC;CAGrC,IAAIC,iBAAgC;AACpC,KAAI,CAAC,UACH,KAAI,iBAGF,kBAAiB,YADD,CAAC,YAAY,GAAI,gBAAgB,EAAE,CAAE,CAAC,MAAM,CACvB,KAAK,KAAK,CAAC,WAAW,WAAW;KAGtE,kBAAiB,UAAU,WAAW,SAAS,WAAW;CAI9D,MAAM,qBAAqB;EAAC;EAAgB,GAAG;EAAa,GAAG;EAAa,CACzE,QAAQ,MAAM,KAAK,KAAK,CACxB,OAAO,CACP,MAAM,GAAG,MAAM,OAAO,EAAE,CAAC,cAAc,OAAO,EAAE,CAAC,CAAC;CAErD,MAAM,cAAc;EAClB,GAAG;EACH,mBAAmB,UAAU,mBAAmB,SAAS,KAAK;EAC9D,GAAG;EACJ,CAAC,QAAQ,MAAM,MAAM,QAAQ,MAAM,OAAU;CAG9C,MAAM,eAAe,YAAiC;EACpD,MAAM,wBAAQ,IAAI,KAAa;EAC/B,MAAM,WAAW;EACjB,IAAIC;AACJ,UAAQ,IAAI,SAAS,KAAK,QAAQ,MAAM,KACtC,OAAM,IAAI,EAAE,GAAG;AAEjB,SAAO;;CAGT,MAAM,2BAA2B,YAA8B;AAC7D,MAAI,CAAC,WAAW,CAAC,QAAQ,OAAQ,QAAO,EAAE;EAC1C,MAAM,OAAO,YAAY,QAAQ;EACjC,MAAM,YAAY,aAAa,QAAQ,MAAM,KAAK,IAAI,EAAE,CAAC;EAGzD,MAAM,UAAU,eAAe,EAAE,EAAE,QAAQ,MAAM,KAAK,IAAI,EAAE,CAAC;EAG7D,MAAM,cAAc,CAAC,aAAa,KAAK,IAAI,WAAW;EAGtD,MAAM,mBACJ,oBAAoB,eAChB,aAAa,QAAQ,MAAM,KAAK,IAAI,EAAE,CAAC,GACvC,EAAE;EAER,MAAMC,WAAqB,EAAE;AAC7B,MAAI,UAAU,OACZ,UAAS,KAAK,YAAY,UAAU,KAAK,KAAK,CAAC,0BAA0B;EAG3E,MAAMC,WAAqB,EAAE;AAE7B,MAAI,kBAAkB;AAIpB,OAAI,eAAe,iBAAiB,SAAS,GAAG;IAC9C,MAAM,cAAc,CAClB,GAAI,cAAc,CAAC,WAAW,GAAG,EAAE,EACnC,GAAG,iBACJ,CAAC,MAAM;AACR,aAAS,KACP,YAAY,YAAY,KAAK,KAAK,CAAC,WAAW,WAAW,IAC1D;;AAIH,OAAI,OAAO,SAAS,EAClB,UAAS,KAAK,GAAG,sBAAsB,QAAQ,gBAAgB,CAAC;SAE7D;AAEL,OAAI,YACF,UAAS,KAAK,UAAU,WAAW,SAAS,WAAW,IAAI;AAE7D,YAAS,KACP,GAAG,OACA,OAAO,CACP,MAAM,CACN,KACE,SAAS,UAAU,KAAK,SAAS,gBAAgB,GAAG,KAAK,UAC3D,CACJ;;EAGH,MAAM,iBAAiB,SAAS,OAAO,CAAC,MAAM,GAAG,MAAM,EAAE,cAAc,EAAE,CAAC;EAC1E,MAAM,iBAAiB,SAAS,OAAO,CAAC,MAAM,GAAG,MAAM,EAAE,cAAc,EAAE,CAAC;AAC1E,SAAO;GACL,GAAG;GACH,eAAe,UAAU,eAAe,SAAS,KAAK;GACtD,GAAG;GACJ,CAAC,QAAQ,MAAM,MAAM,QAAQ,MAAM,OAAU;;CAGhD,MAAM,iBAAiB,YAA4B;AACjD,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,QAAQ,QAAQ,eAAe,OAAO,UAAU;GACrD,MAAM,UAAU,MAAM,MAAM;AAC5B,OAAI,CAAC,QAAQ,OAAQ,QAAO;AAC5B,OAAI,gBAAgB,KAAK,QAAQ,CAAE,QAAO;AAC1C,UAAO,KAAK,KAAK,UAAU,MAAM,CAAC;IAClC;;CAGJ,MAAM,gBAAgB,YAA4B;AAChD,MAAI,CAAC,QAAS,QAAO;EAErB,MAAM,kBAAkB,QAAQ,QAAQ,sBAAsB,WAAW;AACzE,SAAO,cAAc,gBAAgB;;CAKvC,MAAM,8BACJ,SAC+C;AAC/C,MAAI,CAAC,QAAQ,CAAC,KAAK,MAAM,CAAC,OAAQ,QAAO;GAAE,eAAe;GAAI,SAAS;GAAI;EAC3E,MAAM,QAAQ,KAAK,MAAM,KAAK;EAC9B,IAAI,kBAAkB;AACtB,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;GACrC,MAAM,KAAK,MAAM;AAEjB,OAAI,CAAC,GAAG,MAAM,CAAC,OAAQ;AAGvB,OAAI,WAAW,KAAK,GAAG,EAAE;AACvB,sBAAkB;AAClB;;;AAIJ,MAAI,mBAAmB,EAErB,QAAO;GAAE,eAAe;GAAI,SAAS,KAAK,MAAM;GAAE;EAEpD,MAAM,gBAAgB,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,KAAK,CAAC,MAAM;EACvE,MAAM,UAAU,MAAM,MAAM,gBAAgB,CAAC,KAAK,KAAK,CAAC,MAAM;AAC9D,SAAO;GAAE;GAAe;GAAS;;CAGnC,MAAM,wBACJ,qBAAqB,kBAAkB,SACnC;;;EAGN,aAAa,kBAAkB,CAAC;;;;;;SAMzB;EACP,MAAM,QAAQ,wBAAwB,kBAAkB;AACxD,SAAO,MAAM,SAAS,QAAQ,MAAM,KAAK,KAAK,CAAC,aAAa;KAC1D,GAAG,kBAAkB;;;eAIjB;CAEN,MAAMC,kBAA4B,EAAE;AACpC,KAAI,kBAAkB,eAAe,OACnC,MAAK,MAAM,OAAO,gBAAgB;EAChC,MAAM,EAAE,eAAe,YAAY,2BAA2B,IAAI,KAAK;EACvE,MAAM,cAAc,aAAa,QAAQ;AAGzC,MAAI,CAAC,WAAW,CAAC,QAAQ,QAAQ;AAC/B,mBAAgB,KACd,OAAO,IAAI,MAAM;;EAEzB,gBAAgB,MAAM,CACf;AACD;;AAGF,kBAAgB,KACd,OAAO,IAAI,MAAM;;EAEvB,gBAAgB,GAAG,cAAc,QAAQ,GAAG;;;EAG5C,YAAY;;;;;;SAML;GACP,MAAM,QAAQ,wBAAwB,QAAQ;AAC9C,UAAO,MAAM,SAAS,QAAQ,MAAM,KAAK,KAAK,CAAC,aAAa;MAC1D,GAAG,QAAQ;;;aAIR;;AAGL,KAAI,YAAY,SAAS,OACvB,MAAK,MAAM,MAAM,SACf,iBAAgB,KACd,OAAO,GAAG,MAAM;;;;;SAKf,GAAG,WAAW;;;;;;EAMrB,GAAG,OAAO;;;aAIL;CAIL,MAAM,iBAAiB,QAAyB;AAC9C,MAAI,OAAO,KAAM,QAAO;EACxB,IAAI,MAAM,OAAO,IAAI,CAAC,MAAM;AAC5B,MAAI,CAAC,IAAI,OAAQ,QAAO;AAExB,QAAM,IACH,QAAQ,+BAA+B,KAAI,CAC3C,QAAQ,mBAAmB,IAAI;EAClC,MAAM,iBAAiB,YAAY,KAAK,IAAI;EAC5C,MAAM,iBAAiB,YAAY,KAAK,IAAI;EAC5C,MAAM,mBAAmB,YAAY,KAAK,IAAI,IAAI,IAAI,QAAQ,KAAK,KAAK;EAExE,IAAI,UAAU;AACd,MAAI,kBAAkB,kBAAkB,iBAGtC,WAAU,IAFI,IAAI,MAAM,GAAG,GAAG,CAEV;AAGtB,YAAU,QAAQ,QAAQ,OAAO,MAAM;EAEvC,MAAM,UAAU,QAAQ,SAAS,IAAI;EACrC,MAAM,gBAAgB,QAAQ,SAAS,KAAK;EAC5C,MAAM,QAAQ,CAAC,UAAU,MAAM,CAAC,gBAAgB,OAAO;AACvD,SAAO,GAAG,QAAQ,UAAU;;CAG9B,MAAM,sBAAsB;;;;;;;;oBAQV,YAAY;;;;;;;mBAOb,YAAY;;;;;;;wBAOP,YAAY;;;;;;;wBAOZ,YAAY;;;;;;;;;EASlC,gBAAgB;;;;CAKhB,MAAM,wBACJ,OACA,UACkB;AAClB,MAAI,CAAC,SAAS,CAAC,MAAM,OAAQ,QAAO;AACpC,SAAO,GAAG,MAAM,IAAI,KAAK,UAAU,MAAM;;AAoC3C,QAjCc;EACZ;EACA,qBAAqB,SAAS,MAAM;EACpC,qBAAqB,eAAe,YAAY;EAChD,qBAAqB,YAAY,SAAS;EAC1C;EACA;EACA,GAAG;EACH,YAAY,SAAS,KAAK;EAC1B,sBAAsB,mBAAmB,SAAS,qBAAqB;EACvE,sBAAsB,mBAAmB,SAAS,KAAK;EACvD;EACA,wBAAwB,KAAK;EAC7B;EACA;EACA,YAAY,SAAS,SAAS,eAAe,aAAa;EAC1D;EACA,cAAc,WAAW,SACrB,yDAAyD,WACtD,KACE,MACC,WAAW,EAAE,KAAK,eAAe,EAAE,QAAQ,IAAI,QAAQ,OAAO,MAAM,CAAC,OAAO,cAAc,EAAE,aAAa,CAAC,IAC7G,CACA,KAAK,KAAK,KACb,YACE,eAAe,cACf;EACL,cAAc,WAAW,UAAW,YAAY,KAAK;EACtD,gBAAgB,SACZ,oBAAoB,gBAAgB,KAAK,OAAO,GAChD;EACL,CAAC,QAAQ,MAAM,MAAM,QAAQ,MAAM,OAAU,CAEjC,KAAK,KAAK,CAAC,MAAM,GAAG;;;;;;;;;;;AC3dnC,eAAe,mBACb,eAC2B;CAC3B,MAAMC,UAA4B,EAAE;CACpC,MAAM,aAAa,MAAM,QAAQ,eAAe,EAAE,eAAe,MAAM,CAAC;AAExE,MAAK,MAAM,SAAS,WAClB,KAAI,MAAM,aAAa,EAAE;EAEvB,MAAM,aAAa,KAAK,eAAe,MAAM,KAAK;EAClD,MAAM,YAAY,KAAK,YAAY,WAAW;AAE9C,MAAI,WAAW,UAAU,EAAE;GAEzB,MAAM,eAAe,MAAM,SAAS,WAAW,QAAQ;GACvD,MAAM,eAAe,mBAAmB,aAAa;GAGrD,MAAM,oBAAoB,kBAAkB,cAAc,MAAM,KAAK;AAErE,OAAI,mBAAmB;IACrB,MAAM,eAAe,KAAK,YAAY,GAAG,kBAAkB,QAAQ;AAEnE,QAAI,WAAW,aAAa,EAAE;KAE5B,MAAM,gBAAgB,aAAa,QAChC,MAAM,MAAM,kBACd;AAED,aAAQ,KAAK;MACX,MAAM;MACN,UAAU;MACV,YAAY,MAAM;MAClB,UAAU;MACV,cAAc;MACf,CAAC;;;;YAIC,MAAM,QAAQ,IAAI,QAAQ,MAAM,KAAK,CAAC,aAAa,KAAK,UAAU;EAE3E,MAAM,gBAAgB,MAAM,KAAK,QAAQ,aAAa,GAAG;AACzD,UAAQ,KAAK;GACX,MAAM;GACN,UAAU,KAAK,eAAe,MAAM,KAAK;GACzC,YAAY;GACZ,UAAU;GACV,cAAc,EAAE;GACjB,CAAC;;AAIN,QAAO;;;;;;;;AAST,SAAS,mBAAmB,SAA2B;CACrD,MAAMC,UAAoB,EAAE;CAG5B,MAAM,cAAc;CACpB,IAAIC;AAEJ,SAAQ,QAAQ,YAAY,KAAK,QAAQ,MAAM,KAC7C,SAAQ,KAAK,MAAM,GAAG;AAGxB,QAAO;;;;;;AAOT,SAAS,kBACP,SACA,YACe;AACf,KAAI,QAAQ,WAAW,EAAG,QAAO;CAIjC,MAAM,eAAe,WAClB,MAAM,IAAI,CACV,KAAK,SAAS,KAAK,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,EAAE,CAAC,CAC3D,KAAK,GAAG;CAGX,MAAM,aAAa,QAAQ,MAAM,MAAM,MAAM,aAAa;AAC1D,KAAI,WAAY,QAAO;AAGvB,QAAO,QAAQ;;AAGjB,eAAe,OAAO;CACpB,MAAM,QACJ,QAAQ,IAAI,kBAAkB,OAAO,QAAQ,IAAI,kBAAkB;CACrE,MAAM,MACJ,QAAQ,IAAI,oBAAoB,QAAQ,IAAI,iBAAiB,SACxD,QAAQ,IAAI,mBACb,QAAQ,KAAK;CACnB,MAAM,SAAS,MAAM,UAAU,IAAI;CACnC,MAAM,mBACJ,QAAQ,SAAS,MACjB,QAAQ,SAAS,cACjB,0BACA,QAAQ,OAAO,GAAG;CACpB,MAAM,0BACJ,QAAQ,eAAe,MAAM,QAAQ,eAAe;CACtD,IAAI,SAAS,cAAc,IAAI;CAC/B,IAAI,gBAAgB,KAAK,QAAQ,OAAO,aAAa;AACrD,KAAI,yBAAyB;AAC3B,kBAAgB;AAChB,WAAS,QAAQ,QAAQ,wBAAwB,CAAC;;AAEpD,KAAI,CAAC,WAAW,cAAc,CAE5B,iBAAgB,KAAK,QAAQ,OAAO,aAAa;CAEnD,MAAM,SAAS,cAAc,IAAI;AACjC,WAAU,QAAQ,EAAE,WAAW,MAAM,CAAC;AAEtC,KAAI,OAAO;AACT,SAAO,KAAK,yBAAyB,MAAM;AAC3C,SAAO,KAAK,4BAA4B,SAAS;AACjD,SAAO,KAAK,mCAAmC,gBAAgB;AAC/D,SAAO,KAAK,4BAA4B,SAAS;;CAInD,MAAM,aAAa,MAAM,mBAAmB,cAAc;AAE1D,KAAI,OAAO;AACT,SAAO,KAAK,sCAAsC,WAAW,SAAS;AACtE,MAAI,WAAW,OACb,QAAO,KACL,+BAA+B,WAC5B,MAAM,GAAG,EAAE,CACX,KAAK,MAAM,EAAE,KAAK,CAClB,KAAK,KAAK,GACd;;CAIL,IAAI,iBAAiB;CACrB,MAAM,QAAQ,WAAW;CACzB,MAAM,OAAO,QAAQ,sBAAsB,MAAM,GAAG,CAAC,OAAO;AAE5D,MAAK,MAAM,aAAa,YAAY;EAClC,MAAM,EAAE,MAAM,QAAQ,UAAU,YAAY,UAAU,iBAAiB;EAEvE,MAAM,YAAY,MAAM,SAAS,UAAU,QAAQ;EACnD,MAAM,kBAAkB,mBAAmB,UAAU;EACrD,MAAM,aAAa,gCAAgC,gBAAgB;EACnE,MAAM,OAAO,mBAAmB,gBAAgB;EAChD,MAAM,gBAAgB,8BAA8B,WAAW;EAC/D,MAAM,oBAAoB,2BAA2B,WAAW;EAGhE,MAAM,8BAAc,IAAI,KAA4B;AACpD,OAAK,MAAM,KAAK,kBACd,KAAI,EAAE,QAAQ,EAAE,WACd,aAAY,IAAI,EAAE,MAAM,EAAE,gBAAgB,KAAK;EAInD,MAAM,cAAc,cAAc,SAAS,gBAAgB,EAAE,EAAE,KAAK,OAAO;GACzE,MAAM,EAAE;GACR,MAAM,EAAE;GACR,UAAU,CAAC,EAAE;GACb,cAAc,YAAY,IAAI,EAAE,KAAK,GAAG,YAAY,IAAI,EAAE,KAAK,GAAI;GACpE,EAAE;EAEH,MAAM,OAAO,QAAQ,OAAO;EAC5B,MAAM,QAAQ,KAAK,SAAS,KAAK,QAAQ;EACzC,MAAM,cAAc,KAAK,eAAe;EACxC,MAAM,qBAAsB,KAAa,sBAAsB;EAC/D,MAAM,WAAY,KAAa,YAAY;EAE3C,MAAM,YAAY;EAElB,MAAM,aAAa;EAEnB,MAAM,aAAa,WACf,GAAG,gBAAgB,GAAG,eACtB,GAAG,gBAAgB,GAAG,OAAO;EAEjC,MAAM,EAAE,MAAM,UAAU,WAAW,mBAAmB,kBACpD,KAAK,YAAY,IACjB,OACD;EACD,MAAM,oBAAoB,kBACxB,KAAK,qBAAqB,GAC3B,CAAC,MAAM;EACR,MAAM,cAAc,kBAAkB,KAAK,eAAe,GAAG,CAAC,MAAM;EACpE,MAAM,oBAAoB,wBAAwB,aAAa,OAAO;EACtE,MAAM,mBAAmB,wBAAwB,mBAAmB,OAAO;EAC3E,MAAM,YAAY,kBAAkB,qBAAqB;EAEzD,IAAIC,kBAA4B,EAAE;EAClC,IAAIC,WAKC,EAAE;EACP,MAAM,oBAAoB;AAE1B,MADuB,oBAAoB,kBAAkB,CAC1C,WAAW,GAAG;AAC/B,qBAAkB,MAAM,iBAAiB,UAAU,cAAc;AACjE,eAAY,mBAAmB,EAAE,EAAE,KAAK,QAAQ;IAC9C,MAAM,WAAW,IACd,gBAAc,OAAO,CAAC,IAAI,CAC1B,eAAa,OAAO,CAAC,MAAM,IAAI;IAClC,MAAM,eAAe,GAAG,gBAAgB,GAAG;IAC3C,MAAM,MAAM,KAAK,eAAe,IAAI;IACpC,MAAM,mBAAiB,KAAK,CAAC,aAAa,KAAK,QAAQ;IACvD,MAAM,OAAO,uBACH,OAAO,CAAC,SAAS,eAAa,OAAO,CAAC,QAAQ,IAAI,CAAC,CAC5D;AAGD,WAAO;KAAE,YAFY,GAAG,SAAS;KAEE,YAAY;KAAc,OAD7C;KAC6D;KAAQ;KACrF;;EAGJ,MAAM,cAAc,4BAA4B,SAAS,CAAC,QACvD,MAAM,MAAM,OACd;EACD,MAAM,iBAAiB,4BAA4B,YAAY,CAAC,QAC7D,MAAM,MAAM,OACd;EACD,MAAM,gBAAgB,4BAA4B,kBAAkB,CAAC,QAClE,MAAM,MAAM,OACd;EACD,MAAM,UAAU,IAAI,IAAY;GAC9B,GAAG;GACH,GAAG;GACH,GAAG;GACJ,CAAC;EAGF,MAAM,mBAAmB,WACrB,aAAa,QAAQ,MAAM,QAAQ,IAAI,EAAE,CAAC,GAC1C,EAAE;AAGN,MAAI,SACF,MAAK,MAAM,KAAK,aACd,SAAQ,OAAO,EAAE;EAIrB,MAAM,cAAc,MAAM,KAAK,QAAQ,CACpC,QAAQ,SAAS,CAAC,oBAAoB,IAAI,KAAK,CAAC,CAChD,QAAQ,SAAS,KAAK;EAEzB,MAAM,cAAc,YAAY,QAAQ,MAAM,QAAQ,KAAK,EAAE,CAAC;EAC9D,MAAM,gBAAgB,YAAY,QAAQ,MAAM,CAAC,QAAQ,KAAK,EAAE,CAAC;EAEjE,MAAM,MAAM,SAAS;GACnB;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA,gBAAgB,oBAAoB,kBAAkB;GACtD,aAAa;GACb;GACA;GACA,iBAAiB,UAAU,MAAM;GACjC,aAAa;GACb;GACA;GACA;GAEA,cAAc,WAAW,mBAAmB;GAC7C,CAAC;EACF,MAAM,UAAU,KAAK,QAAQ,GAAG,KAAK,MAAM;AAC3C,YAAU,QAAQ,QAAQ,EAAE,EAAE,WAAW,MAAM,CAAC;AAChD,QAAM,UAAU,SAAS,KAAK,QAAQ;AACtC,oBAAkB;AAClB,OAAK,OAAO,oBAAoB,eAAe,GAAG,MAAM,MAAM;AAC9D,MAAI,MAAO,QAAO,KAAK,aAAa,UAAU;;AAEhD,MAAK,QACH,WAAW,eAAe,OAAO,mBAAmB,IAAI,KAAK,IAAI,GAClE;AASD,CAPiB,WACd,KAAK,MAAM;EACV,MAAM,OAAO,QAAQ,EAAE,KAAK;EAC5B,MAAM,UAAU,KAAK,QAAQ,GAAG,KAAK,MAAM;AAC3C,SAAO,SAAS,KAAK,QAAQ;GAC7B,CACD,MAAM,GAAG,MAAM,EAAE,cAAc,EAAE,CAAC,CAC5B,SAAS,MAAM;AACtB,SAAO,IAAI,OAAO,IAAI;GACtB;AACF,QAAO,OAAO;;AAGhB,SAAgB,oBACd,aACwC;AACxC,KAAI,CAAC,YAAa,QAAO,EAAE;CAC3B,MAAM,QAAQ,YAAY,MAAM,KAAK;CACrC,MAAMC,SAAmD,EAAE;CAC3D,IAAIC,UAA6C;EAAE,OAAO;EAAI,MAAM,EAAE;EAAE;AACxE,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,UAAU,KAAK,MAAM,eAAe;AAC1C,MAAI,SAAS;AACX,OAAI,QAAQ,SAAS,QAAQ,KAAK,OAAQ,QAAO,KAAK,QAAQ;AAC9D,aAAU;IAAE,OAAO,QAAQ,GAAG,MAAM;IAAE,MAAM,EAAE;IAAE;AAChD;;AAEF,UAAQ,KAAK,KAAK,KAAK;;AAEzB,KAAI,QAAQ,SAAS,QAAQ,KAAK,OAAQ,QAAO,KAAK,QAAQ;AAC9D,QAAO,OAAO,KAAK,GAAG,SAAS;EAC7B,OAAO,EAAE,SAAS,WAAW,MAAM;EACnC,MAAM,EAAE,KAAK,KAAK,KAAK,CAAC,MAAM;EAC/B,EAAE;;AAGL,eAAsB,mBAAkC;AACtD,OAAM,MAAM;;AAGd,IACE,QAAQ,IAAI,0BAA0B,OACtC,QAAQ,IAAI,0BAA0B,OAEtC,mBAAkB,CAAC,OAAO,QAAQ;AAChC,QAAO,MAAM,OAAO,IAAI,CAAC;AACzB,SAAQ,KAAK,EAAE;EACf"}
|