bejamas 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{generate-mdx-CR4bXlml.js → generate-mdx-5r1bKyim.js} +3 -263
- package/dist/generate-mdx-5r1bKyim.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,272 +1,12 @@
|
|
|
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
5
|
import { readdir, writeFile } from "fs/promises";
|
|
7
|
-
import { Project, SyntaxKind } from "ts-morph";
|
|
8
6
|
|
|
9
7
|
//#region rolldown:runtime
|
|
10
8
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
11
9
|
|
|
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
10
|
//#endregion
|
|
271
11
|
//#region src/docs/generate-mdx/mdx-builder.ts
|
|
272
12
|
function buildMdx(params) {
|
|
@@ -661,4 +401,4 @@ if (process.env.BEJAMAS_SKIP_AUTO_RUN !== "1" && process.env.BEJAMAS_SKIP_AUTO_R
|
|
|
661
401
|
|
|
662
402
|
//#endregion
|
|
663
403
|
export { runDocsGenerator };
|
|
664
|
-
//# sourceMappingURL=generate-mdx-
|
|
404
|
+
//# sourceMappingURL=generate-mdx-5r1bKyim.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-mdx-5r1bKyim.js","names":["m: RegExpExecArray | null","external: string[]","internal: string[]","exampleSections: string[]","exampleRelPaths: string[]","examples: Array<{\n importName: string;\n importPath: string;\n title: string;\n source: string;\n }>","importPath","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":["export 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}): 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 } = params;\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 const sortedUiAuto = (autoImports ?? []).slice().sort();\n const uiAutoLines = sortedUiAuto.map(\n (name) => `import ${name} from '${componentsAlias}/${name}.astro';`,\n );\n const exampleLines = (examples ?? [])\n .map((ex) => `import ${ex.importName} from '${ex.importPath}';`)\n .sort((a, b) => a.localeCompare(b));\n const internalTopImports = [\n !hasImport ? `import ${importName} from '${importPath}';` : null,\n ...uiAutoLines,\n ...exampleLines,\n ]\n .filter((v) => v != null)\n .slice()\n .sort((a, b) => String(a).localeCompare(String(b)));\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 const usedUi = (autoImports ?? [])\n .filter((n) => used.has(n))\n .slice()\n .sort();\n const includeMain = !hasImport && used.has(importName);\n\n const external: string[] = [];\n if (usedIcons.length) {\n external.push(`import { ${usedIcons.join(\", \")} } from '@lucide/astro';`);\n }\n const internal: string[] = [];\n if (includeMain)\n internal.push(`import ${importName} from '${importPath}';`);\n internal.push(\n ...usedUi.map((name) => `import ${name} from '${componentsAlias}/${name}.astro';`),\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, writeFile } from \"fs/promises\";\nimport { join, extname, dirname, relative } 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\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 const entriesDir = await readdir(componentsDir, { withFileTypes: true });\n const files = entriesDir.filter(\n (e) => e.isFile() && extname(e.name).toLowerCase() === \".astro\",\n );\n if (DEBUG) {\n logger.info(`[docs-generator] components found: ${files.length}`);\n if (files.length)\n logger.info(\n `[docs-generator] first few: ${files\n .slice(0, 5)\n .map((f) => f.name)\n .join(\", \")}`,\n );\n }\n\n let generatedCount = 0;\n const total = files.length;\n const spin = spinner(`Generating docs (0/${total})`).start();\n for (const f of files) {\n const filePath = join(componentsDir, f.name);\n const astroFile = await (\n await import(\"fs/promises\")\n ).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(f.name)}`;\n const pascal = f.name.replace(/\\.(astro)$/i, \"\");\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 const importPath = `${componentsAlias}/${pascal}.astro`;\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 importPath = `${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 importName = `${pascal}${base}`;\n const title = base;\n return { importName, importPath, title, 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 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 });\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 = files\n .map((f) => {\n const slug = `${slugify(f.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":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { BASE_COLORS, getConfig, getProjectInfo, highlighter, logger, spinner } from "./
|
|
2
|
+
import { BASE_COLORS, extractFrontmatter, getConfig, getProjectInfo, highlighter, logger, parseJsDocMetadata, resolveUiRoot, spinner } from "./utils-DfvCox_O.js";
|
|
3
3
|
import { Command } from "commander";
|
|
4
4
|
import { createRequire } from "module";
|
|
5
5
|
import path from "path";
|
|
@@ -8,12 +8,12 @@ import os from "os";
|
|
|
8
8
|
import dotenv from "dotenv";
|
|
9
9
|
import { detect } from "@antfu/ni";
|
|
10
10
|
import { z } from "zod";
|
|
11
|
+
import { bold, cyan, dim, green, magenta, red, white, yellow } from "kleur/colors";
|
|
11
12
|
import { execa } from "execa";
|
|
12
13
|
import prompts from "prompts";
|
|
13
14
|
import fg from "fast-glob";
|
|
14
|
-
import path$1, {
|
|
15
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
16
|
-
import { fileURLToPath } from "node:url";
|
|
15
|
+
import path$1, { extname as extname$1, isAbsolute, join as join$1, relative as relative$1, resolve } from "node:path";
|
|
16
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
17
17
|
import fs from "node:fs/promises";
|
|
18
18
|
|
|
19
19
|
//#region src/utils/errors.ts
|
|
@@ -375,9 +375,10 @@ async function runInit(options) {
|
|
|
375
375
|
}
|
|
376
376
|
|
|
377
377
|
//#endregion
|
|
378
|
-
//#region src/
|
|
379
|
-
|
|
380
|
-
|
|
378
|
+
//#region src/utils/tsconfig-utils.ts
|
|
379
|
+
/**
|
|
380
|
+
* Read and parse tsconfig.json from the project root
|
|
381
|
+
*/
|
|
381
382
|
function readTsConfig(projectRoot) {
|
|
382
383
|
try {
|
|
383
384
|
const tsconfigPath = resolve(projectRoot, "tsconfig.json");
|
|
@@ -388,6 +389,9 @@ function readTsConfig(projectRoot) {
|
|
|
388
389
|
return null;
|
|
389
390
|
}
|
|
390
391
|
}
|
|
392
|
+
/**
|
|
393
|
+
* Resolve an alias path (like @/components) using tsconfig.json paths
|
|
394
|
+
*/
|
|
391
395
|
function resolveAliasPathUsingTsConfig(inputPath, projectRoot) {
|
|
392
396
|
const cfg = readTsConfig(projectRoot);
|
|
393
397
|
if (!cfg || !cfg.compilerOptions) return null;
|
|
@@ -406,6 +410,9 @@ function resolveAliasPathUsingTsConfig(inputPath, projectRoot) {
|
|
|
406
410
|
}
|
|
407
411
|
return null;
|
|
408
412
|
}
|
|
413
|
+
|
|
414
|
+
//#endregion
|
|
415
|
+
//#region src/commands/docs.ts
|
|
409
416
|
async function generateDocs({ cwd, outDir, verbose }) {
|
|
410
417
|
const DEBUG = process.env.BEJAMAS_DEBUG === "1" || process.env.BEJAMAS_DEBUG === "true" || verbose;
|
|
411
418
|
try {
|
|
@@ -520,7 +527,7 @@ async function generateDocs({ cwd, outDir, verbose }) {
|
|
|
520
527
|
if (process.env.BEJAMAS_DOCS_CWD) logger.info(`Docs CWD: ${process.env.BEJAMAS_DOCS_CWD}`);
|
|
521
528
|
if (process.env.BEJAMAS_DOCS_OUT_DIR) logger.info(`Docs out: ${process.env.BEJAMAS_DOCS_OUT_DIR}`);
|
|
522
529
|
}
|
|
523
|
-
const mod = await import("./generate-mdx-
|
|
530
|
+
const mod = await import("./generate-mdx-5r1bKyim.js");
|
|
524
531
|
if (typeof mod.runDocsGenerator === "function") await mod.runDocsGenerator();
|
|
525
532
|
else throw new Error("Failed to load docs generator. Export 'runDocsGenerator' not found.");
|
|
526
533
|
} catch (err) {
|
|
@@ -536,6 +543,178 @@ const docs = new Command().name("docs:build").alias("docs").description("generat
|
|
|
536
543
|
});
|
|
537
544
|
});
|
|
538
545
|
|
|
546
|
+
//#endregion
|
|
547
|
+
//#region src/commands/docs-check.ts
|
|
548
|
+
const REQUIRED_FIELDS = [
|
|
549
|
+
"name",
|
|
550
|
+
"title",
|
|
551
|
+
"description"
|
|
552
|
+
];
|
|
553
|
+
const RECOMMENDED_FIELDS = [
|
|
554
|
+
"primaryExampleMDX",
|
|
555
|
+
"usageMDX",
|
|
556
|
+
"figmaUrl"
|
|
557
|
+
];
|
|
558
|
+
const FIELD_LABELS = {
|
|
559
|
+
name: "@component",
|
|
560
|
+
title: "@title",
|
|
561
|
+
description: "@description",
|
|
562
|
+
primaryExampleMDX: "@preview",
|
|
563
|
+
usageMDX: "@usage",
|
|
564
|
+
figmaUrl: "@figmaUrl"
|
|
565
|
+
};
|
|
566
|
+
function checkComponentDocs(filePath, fileName) {
|
|
567
|
+
const content = readFileSync(filePath, "utf-8");
|
|
568
|
+
const frontmatter = extractFrontmatter(content);
|
|
569
|
+
const meta = parseJsDocMetadata(frontmatter);
|
|
570
|
+
const componentName = fileName.replace(/\.astro$/i, "");
|
|
571
|
+
const missingRequired = [];
|
|
572
|
+
const missingRecommended = [];
|
|
573
|
+
for (const field of REQUIRED_FIELDS) {
|
|
574
|
+
const value = meta[field];
|
|
575
|
+
if (!value || typeof value === "string" && !value.trim()) missingRequired.push(FIELD_LABELS[field] || field);
|
|
576
|
+
}
|
|
577
|
+
for (const field of RECOMMENDED_FIELDS) {
|
|
578
|
+
const value = meta[field];
|
|
579
|
+
if (!value || typeof value === "string" && !value.trim()) missingRecommended.push(FIELD_LABELS[field] || field);
|
|
580
|
+
}
|
|
581
|
+
let status;
|
|
582
|
+
if (missingRequired.length > 0) status = "missing";
|
|
583
|
+
else if (missingRecommended.length > 0) status = "incomplete";
|
|
584
|
+
else status = "complete";
|
|
585
|
+
return {
|
|
586
|
+
name: componentName,
|
|
587
|
+
file: fileName,
|
|
588
|
+
status,
|
|
589
|
+
missingRequired,
|
|
590
|
+
missingRecommended
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
async function checkDocs({ cwd, json }) {
|
|
594
|
+
try {
|
|
595
|
+
const shellCwd = process.cwd();
|
|
596
|
+
let projectRoot = shellCwd;
|
|
597
|
+
let probe = shellCwd;
|
|
598
|
+
for (let i = 0; i < 6 && probe; i += 1) {
|
|
599
|
+
const candidate = resolve(probe, "components.json");
|
|
600
|
+
if (existsSync(candidate)) {
|
|
601
|
+
projectRoot = probe;
|
|
602
|
+
try {
|
|
603
|
+
const raw = readFileSync(candidate, "utf-8");
|
|
604
|
+
const config = JSON.parse(raw);
|
|
605
|
+
if (!cwd && !process.env.BEJAMAS_UI_ROOT && config?.aliases?.ui) {
|
|
606
|
+
const mapped = String(config.aliases.ui);
|
|
607
|
+
let uiAbs = null;
|
|
608
|
+
if (mapped.startsWith("./") || mapped.startsWith("../") || isAbsolute(mapped)) uiAbs = resolve(projectRoot, mapped);
|
|
609
|
+
else uiAbs = resolveAliasPathUsingTsConfig(mapped, projectRoot);
|
|
610
|
+
if (!uiAbs && mapped.startsWith("@/")) uiAbs = resolve(projectRoot, "src", mapped.slice(2));
|
|
611
|
+
if (uiAbs) process.env.BEJAMAS_UI_ROOT = uiAbs;
|
|
612
|
+
}
|
|
613
|
+
if (!cwd && !process.env.BEJAMAS_UI_ROOT && config?.tailwind?.css) {
|
|
614
|
+
const cssRaw = String(config.tailwind.css);
|
|
615
|
+
let cssAbs = null;
|
|
616
|
+
if (cssRaw.startsWith("./") || cssRaw.startsWith("../") || isAbsolute(cssRaw)) cssAbs = resolve(projectRoot, cssRaw);
|
|
617
|
+
else cssAbs = resolveAliasPathUsingTsConfig(cssRaw, projectRoot);
|
|
618
|
+
if (!cssAbs && cssRaw.startsWith("@/")) cssAbs = resolve(projectRoot, "src", cssRaw.slice(2));
|
|
619
|
+
if (cssAbs) {
|
|
620
|
+
const uiRootFromCss = resolve(cssAbs, "..", "..", "..");
|
|
621
|
+
process.env.BEJAMAS_UI_ROOT = uiRootFromCss;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
} catch {}
|
|
625
|
+
break;
|
|
626
|
+
}
|
|
627
|
+
const parent = resolve(probe, "..");
|
|
628
|
+
probe = parent === probe ? null : parent;
|
|
629
|
+
}
|
|
630
|
+
if (cwd && cwd.length) process.env.BEJAMAS_UI_ROOT = resolve(cwd);
|
|
631
|
+
let uiRoot;
|
|
632
|
+
try {
|
|
633
|
+
uiRoot = resolveUiRoot(shellCwd);
|
|
634
|
+
} catch {
|
|
635
|
+
logger.error("Unable to locate @bejamas/ui. Use --cwd to specify the UI package path.");
|
|
636
|
+
process.exit(1);
|
|
637
|
+
}
|
|
638
|
+
const componentsDir = join$1(uiRoot, "src", "components");
|
|
639
|
+
if (!existsSync(componentsDir)) {
|
|
640
|
+
logger.error(`Components directory not found: ${componentsDir}\n\nExpected structure: <uiRoot>/src/components/*.astro\nUse --cwd to specify a different UI package root.`);
|
|
641
|
+
process.exit(1);
|
|
642
|
+
}
|
|
643
|
+
const files = readdirSync(componentsDir, { withFileTypes: true }).filter((e) => e.isFile() && extname$1(e.name).toLowerCase() === ".astro").map((e) => e.name).sort();
|
|
644
|
+
if (files.length === 0) {
|
|
645
|
+
logger.warn("No .astro component files found.");
|
|
646
|
+
process.exit(0);
|
|
647
|
+
}
|
|
648
|
+
const results = [];
|
|
649
|
+
for (const file of files) {
|
|
650
|
+
const filePath = join$1(componentsDir, file);
|
|
651
|
+
const status = checkComponentDocs(filePath, file);
|
|
652
|
+
results.push(status);
|
|
653
|
+
}
|
|
654
|
+
const complete = results.filter((r) => r.status === "complete");
|
|
655
|
+
const incomplete = results.filter((r) => r.status === "incomplete");
|
|
656
|
+
const missing = results.filter((r) => r.status === "missing");
|
|
657
|
+
const checkResult = {
|
|
658
|
+
total: results.length,
|
|
659
|
+
complete,
|
|
660
|
+
incomplete,
|
|
661
|
+
missing
|
|
662
|
+
};
|
|
663
|
+
if (json) {
|
|
664
|
+
console.log(JSON.stringify(checkResult, null, 2));
|
|
665
|
+
if (missing.length > 0) process.exit(1);
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
const termWidth = Math.min(80, process.stdout.columns || 80);
|
|
669
|
+
const headerLine = "━".repeat(termWidth);
|
|
670
|
+
logger.break();
|
|
671
|
+
console.log(dim("┌" + "─".repeat(termWidth - 2) + "┐"));
|
|
672
|
+
console.log(dim("│") + bold(cyan(" docs:check")) + dim(" — Component Documentation Status") + " ".repeat(Math.max(0, termWidth - 47)) + dim("│"));
|
|
673
|
+
console.log(dim("└" + "─".repeat(termWidth - 2) + "┘"));
|
|
674
|
+
logger.break();
|
|
675
|
+
const formatTag = (tag) => magenta(tag);
|
|
676
|
+
const formatComponentName = (name) => bold(white(name));
|
|
677
|
+
if (complete.length > 0) {
|
|
678
|
+
console.log(green(`✓ Complete (${complete.length} component${complete.length === 1 ? "" : "s"}):`));
|
|
679
|
+
const names = complete.map((c) => formatComponentName(c.name)).join(dim(", "));
|
|
680
|
+
console.log(` ${names}`);
|
|
681
|
+
logger.break();
|
|
682
|
+
}
|
|
683
|
+
if (incomplete.length > 0) {
|
|
684
|
+
console.log(yellow(`⚠ Incomplete (${incomplete.length} component${incomplete.length === 1 ? "" : "s"}):`));
|
|
685
|
+
for (const comp of incomplete) {
|
|
686
|
+
const missingFields = comp.missingRecommended.map(formatTag).join(dim(", "));
|
|
687
|
+
console.log(` ${formatComponentName(comp.name)} ${dim("-")} ${dim("missing:")} ${missingFields}`);
|
|
688
|
+
}
|
|
689
|
+
logger.break();
|
|
690
|
+
}
|
|
691
|
+
if (missing.length > 0) {
|
|
692
|
+
console.log(red(`✗ Missing Docs (${missing.length} component${missing.length === 1 ? "" : "s"}):`));
|
|
693
|
+
for (const comp of missing) {
|
|
694
|
+
const missingFields = comp.missingRequired.map(formatTag).join(dim(", "));
|
|
695
|
+
console.log(` ${formatComponentName(comp.name)} ${dim("-")} ${dim("missing:")} ${missingFields}`);
|
|
696
|
+
}
|
|
697
|
+
logger.break();
|
|
698
|
+
}
|
|
699
|
+
console.log(dim(headerLine));
|
|
700
|
+
const completeText = green(`${complete.length}/${results.length} complete`);
|
|
701
|
+
const incompleteText = incomplete.length > 0 ? yellow(`${incomplete.length} incomplete`) : dim(`${incomplete.length} incomplete`);
|
|
702
|
+
const missingText = missing.length > 0 ? red(`${missing.length} missing docs`) : dim(`${missing.length} missing docs`);
|
|
703
|
+
console.log(`${bold("Summary:")} ${completeText} ${dim("|")} ${incompleteText} ${dim("|")} ${missingText}`);
|
|
704
|
+
logger.break();
|
|
705
|
+
if (missing.length > 0) process.exit(1);
|
|
706
|
+
} catch (err) {
|
|
707
|
+
logger.error(err?.message || String(err));
|
|
708
|
+
process.exit(1);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
const docsCheck = new Command().name("docs:check").description("check documentation status for all components").option("-c, --cwd <cwd>", "path to UI working directory").option("--json", "output results as JSON").action(async (opts) => {
|
|
712
|
+
await checkDocs({
|
|
713
|
+
cwd: opts.cwd,
|
|
714
|
+
json: Boolean(opts.json)
|
|
715
|
+
});
|
|
716
|
+
});
|
|
717
|
+
|
|
539
718
|
//#endregion
|
|
540
719
|
//#region src/utils/astro-imports.ts
|
|
541
720
|
function updateImportAliases(moduleSpecifier, config, isRemote = false) {
|
|
@@ -708,6 +887,7 @@ const program = new Command().name("bejamas").description("bejamas/ui cli").conf
|
|
|
708
887
|
program.addCommand(init);
|
|
709
888
|
program.addCommand(add);
|
|
710
889
|
program.addCommand(docs);
|
|
890
|
+
program.addCommand(docsCheck);
|
|
711
891
|
program.parse(process.argv);
|
|
712
892
|
var src_default = program;
|
|
713
893
|
|