bejamas 0.4.1 → 0.5.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/README.md +8 -1
- package/dist/{generate-mdx-Ce7A9Uxe.js → generate-mdx-Bd_qGcMg.js} +82 -40
- package/dist/generate-mdx-Bd_qGcMg.js.map +1 -0
- package/dist/index.js +598 -249
- package/dist/index.js.map +1 -1
- package/dist/{utils-CyYWo_qS.js → utils-BEqgES6q.js} +1389 -1043
- package/dist/utils-BEqgES6q.js.map +1 -0
- package/package.json +16 -16
- package/src/tailwind.css +535 -3
- package/dist/generate-mdx-Ce7A9Uxe.js.map +0 -1
- package/dist/utils-CyYWo_qS.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as PRESET_MENU_COLORS, A as SEMANTIC_ICON_NAMES, B as getFontValue, C as BEJAMAS_COMPONENTS_SCHEMA_URL, D as ICON_LIBRARIES, E as resolveRegistryUrl, F as RTL_LANGUAGE_VALUES, G as normalizeDesignSystemConfig, H as getRadiusValue, I as designSystemConfigSchema, J as PRESET_CHART_COLORS, K as DEFAULT_PRESET_CONFIG, L as getDocumentDirection, M as getSemanticIconNameFromLucidePath, N as renderSemanticIconSvgWithAttributeString, O as buildRegistryTheme, P as DEFAULT_DESIGN_SYSTEM_CONFIG, Q as PRESET_MENU_ACCENTS, R as getDocumentLanguage, S as highlighter, T as buildUiUrl, U as getStyleDefaultRadius, V as getHeadingFontValue, W as getStyleId, X as PRESET_FONT_HEADINGS, Y as PRESET_FONTS, Z as PRESET_ICON_LIBRARIES, _ as findCommonRoot, at as encodePreset, b as getProjectInfo, d as parseJsDocMetadata, et as PRESET_RADII, g as spinner, it as decodePreset, j as getSemanticIconNameFromLucideExport, k as ICON_LIBRARY_COLLECTIONS, nt as PRESET_THEMES, o as extractFrontmatter, ot as isPresetCode, p as resolveUiRoot, q as PRESET_BASE_COLORS, rt as V1_CHART_COLOR_MAP, st as fonts, tt as PRESET_STYLES, v as getConfig, w as BASE_COLORS, x as logger, y as getWorkspaceConfig, z as getFontPackageName } from "./utils-BEqgES6q.js";
|
|
3
3
|
import { Command } from "commander";
|
|
4
4
|
import { createRequire } from "module";
|
|
5
5
|
import path, { extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
@@ -18,6 +18,8 @@ import { execa } from "execa";
|
|
|
18
18
|
import prompts from "prompts";
|
|
19
19
|
import * as tar from "tar";
|
|
20
20
|
import os$1 from "node:os";
|
|
21
|
+
import { stripVTControlCharacters } from "node:util";
|
|
22
|
+
import { StringDecoder } from "node:string_decoder";
|
|
21
23
|
|
|
22
24
|
//#region src/registry/context.ts
|
|
23
25
|
let context = { headers: {} };
|
|
@@ -25,17 +27,12 @@ function clearRegistryContext() {
|
|
|
25
27
|
context.headers = {};
|
|
26
28
|
}
|
|
27
29
|
|
|
28
|
-
//#endregion
|
|
29
|
-
//#region src/utils/errors.ts
|
|
30
|
-
const MISSING_DIR_OR_EMPTY_PROJECT = "1";
|
|
31
|
-
const MISSING_CONFIG = "3";
|
|
32
|
-
|
|
33
30
|
//#endregion
|
|
34
31
|
//#region src/preflights/preflight-init.ts
|
|
35
32
|
async function preFlightInit(options) {
|
|
36
33
|
const errors = {};
|
|
37
34
|
if (!fs.existsSync(options.cwd) || !fs.existsSync(path$1.resolve(options.cwd, "package.json"))) {
|
|
38
|
-
errors[
|
|
35
|
+
errors["1"] = true;
|
|
39
36
|
return {
|
|
40
37
|
errors,
|
|
41
38
|
projectInfo: null
|
|
@@ -62,8 +59,8 @@ const ASTRO_CONFIG_CANDIDATES = [
|
|
|
62
59
|
const ASTRO_LAYOUT_CANDIDATES = ["src/layouts/Layout.astro", "apps/web/src/layouts/Layout.astro"];
|
|
63
60
|
const STARLIGHT_HEAD_RELATIVE_PATH = "apps/docs/src/components/Head.astro";
|
|
64
61
|
const ASTRO_FONT_PROVIDERS = ["fontsource", "google"];
|
|
65
|
-
const ASTRO_FONTSOURCE_FONT_NAMES = new Set(["geist", "geist-mono"]);
|
|
66
|
-
const MANAGED_BODY_FONT_CLASSES = new Set(["font-mono", "font-serif"]);
|
|
62
|
+
const ASTRO_FONTSOURCE_FONT_NAMES = /* @__PURE__ */ new Set(["geist", "geist-mono"]);
|
|
63
|
+
const MANAGED_BODY_FONT_CLASSES = /* @__PURE__ */ new Set(["font-mono", "font-serif"]);
|
|
67
64
|
function compactSource$1(source) {
|
|
68
65
|
return source.replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
|
|
69
66
|
}
|
|
@@ -71,23 +68,25 @@ function escapeRegExp$2(value) {
|
|
|
71
68
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
72
69
|
}
|
|
73
70
|
function upsertImport(source, moduleName, importedName, fallbackNames = []) {
|
|
74
|
-
const importPattern =
|
|
71
|
+
const importPattern = new RegExp(`import\\s*\\{([^}]+)\\}\\s*from\\s*["']${escapeRegExp$2(moduleName)}["'];?`);
|
|
75
72
|
if (importPattern.test(source)) return source.replace(importPattern, (_match, importsSource) => {
|
|
76
73
|
const imports = importsSource.split(",").map((value) => value.trim()).filter(Boolean);
|
|
77
74
|
if (!imports.includes(importedName)) imports.push(importedName);
|
|
78
75
|
for (const name of fallbackNames) if (!imports.includes(name)) imports.unshift(name);
|
|
79
76
|
return `import { ${Array.from(new Set(imports)).join(", ")} } from "${moduleName}";`;
|
|
80
77
|
});
|
|
81
|
-
const importLine = `import { ${Array.from(new Set([...fallbackNames, importedName])).join(", ")} } from "${moduleName}";`;
|
|
78
|
+
const importLine = `import { ${Array.from(/* @__PURE__ */ new Set([...fallbackNames, importedName])).join(", ")} } from "${moduleName}";`;
|
|
82
79
|
const frontmatterEnd = source.indexOf("---", 3);
|
|
83
80
|
if (source.startsWith("---") && frontmatterEnd !== -1) return `${source.slice(0, frontmatterEnd).trimEnd()}\n${importLine}\n${source.slice(frontmatterEnd)}`;
|
|
84
81
|
return `${importLine}\n${source}`;
|
|
85
82
|
}
|
|
86
83
|
function buildAstroConfigFontBlock(fontsToSerialize) {
|
|
87
|
-
|
|
84
|
+
const body = fontsToSerialize.length === 0 ? "" : `\n${fontsToSerialize.map((font) => ` {\n provider: fontProviders.${font.provider}(),\n name: ${JSON.stringify(font.name)},\n cssVariable: ${JSON.stringify(font.cssVariable)},\n subsets: ${JSON.stringify(font.subsets)},\n },`).join("\n")}\n`;
|
|
85
|
+
return `${ASTRO_CONFIG_BLOCK_START}\n/** @type {NonNullable<import("astro").AstroUserConfig["fonts"]>} */\nconst ${ASTRO_FONT_CONSTANT} = [${body}];\n${ASTRO_CONFIG_BLOCK_END}`;
|
|
88
86
|
}
|
|
89
87
|
function buildAstroLayoutFontBlock(fontsToSerialize) {
|
|
90
|
-
|
|
88
|
+
const body = fontsToSerialize.map((font) => `<Font cssVariable="${font.cssVariable}" />`).join("\n");
|
|
89
|
+
return `${ASTRO_LAYOUT_BLOCK_START}\n${body}\n${ASTRO_LAYOUT_BLOCK_END}`;
|
|
91
90
|
}
|
|
92
91
|
function bodyFontClassFromCssVariable(cssVariable) {
|
|
93
92
|
if (cssVariable === "--font-mono" || cssVariable === "--font-serif") return fontClassFromCssVariable(cssVariable);
|
|
@@ -102,14 +101,14 @@ function upsertManagedBodyFontClass(source, cssVariable) {
|
|
|
102
101
|
const classMatch = attrs.match(classPattern);
|
|
103
102
|
const quote = classMatch?.[1] ?? "\"";
|
|
104
103
|
const existingClasses = (classMatch?.[2] ?? "").split(/\s+/).filter(Boolean).filter((className) => !MANAGED_BODY_FONT_CLASSES.has(className));
|
|
105
|
-
const nextClasses = bodyClass ? Array.from(new Set([...existingClasses, bodyClass])) : existingClasses;
|
|
104
|
+
const nextClasses = bodyClass ? Array.from(/* @__PURE__ */ new Set([...existingClasses, bodyClass])) : existingClasses;
|
|
106
105
|
let nextAttrs = attrs.replace(classPattern, "");
|
|
107
106
|
if (nextClasses.length > 0) nextAttrs = `${nextAttrs} class=${quote}${nextClasses.join(" ")}${quote}`;
|
|
108
107
|
return `<body${nextAttrs}${selfClosing}>`;
|
|
109
108
|
});
|
|
110
109
|
}
|
|
111
110
|
function parseManagedAstroFonts(source) {
|
|
112
|
-
const markerPattern =
|
|
111
|
+
const markerPattern = new RegExp(`${escapeRegExp$2(ASTRO_CONFIG_BLOCK_START)}[\\s\\S]*?const\\s+${ASTRO_FONT_CONSTANT}\\s*=\\s*\\[([\\s\\S]*?)\\];[\\s\\S]*?${escapeRegExp$2(ASTRO_CONFIG_BLOCK_END)}`);
|
|
113
112
|
const match = source.match(markerPattern);
|
|
114
113
|
if (!match) return [];
|
|
115
114
|
return (match[1].match(/\{[\s\S]*?\}/g) ?? []).map((entry) => {
|
|
@@ -325,7 +324,7 @@ const CREATE_BLOCK_START = "/* bejamas:create:start */";
|
|
|
325
324
|
const CREATE_BLOCK_END = "/* bejamas:create:end */";
|
|
326
325
|
const SHADCN_TAILWIND_IMPORT = "@import \"shadcn/tailwind.css\";";
|
|
327
326
|
const BEJAMAS_TAILWIND_IMPORT = "@import \"bejamas/tailwind.css\";";
|
|
328
|
-
const MANAGED_TAILWIND_IMPORTS = new Set([SHADCN_TAILWIND_IMPORT, BEJAMAS_TAILWIND_IMPORT]);
|
|
327
|
+
const MANAGED_TAILWIND_IMPORTS = /* @__PURE__ */ new Set([SHADCN_TAILWIND_IMPORT, BEJAMAS_TAILWIND_IMPORT]);
|
|
329
328
|
const MANAGED_ICON_PACKAGES = new Set(ICON_LIBRARIES.map((library) => library.packageName));
|
|
330
329
|
const FALLBACK_ICON_PACKAGE_VERSION = "latest";
|
|
331
330
|
const TEMPLATE_APP_UI_IMPORT = "import { appUi } from \"@/i18n/ui\";";
|
|
@@ -740,7 +739,7 @@ function transformManagedTailwindImportCss(source) {
|
|
|
740
739
|
}
|
|
741
740
|
async function patchComponentsJson(filepath, config) {
|
|
742
741
|
const current = await fs.readJson(filepath);
|
|
743
|
-
const { rsc: _rsc, tsx: _tsx
|
|
742
|
+
const { rsc: _rsc, tsx: _tsx, ...normalizedCurrent } = current;
|
|
744
743
|
const next = {
|
|
745
744
|
...normalizedCurrent,
|
|
746
745
|
$schema: BEJAMAS_COMPONENTS_SCHEMA_URL,
|
|
@@ -865,8 +864,8 @@ async function patchLayoutFile(filepath, config) {
|
|
|
865
864
|
const current = await fs.readFile(filepath, "utf8");
|
|
866
865
|
if (current.includes("from \"@/i18n/ui\"")) return;
|
|
867
866
|
if (config.rtl) {
|
|
868
|
-
const next
|
|
869
|
-
if (next
|
|
867
|
+
const next = transformTemplateLayoutToI18n(current);
|
|
868
|
+
if (next !== current) await fs.writeFile(filepath, next, "utf8");
|
|
870
869
|
return;
|
|
871
870
|
}
|
|
872
871
|
const nextLanguage = getDocumentLanguage(config);
|
|
@@ -1012,7 +1011,8 @@ function rewriteAstroIcons(content, iconLibrary) {
|
|
|
1012
1011
|
function renderSemanticIconUsage(original, library, attributeString = "") {
|
|
1013
1012
|
const semanticName = attributeString.match(/\sname=(["'])([^"']+)\1/)?.[2];
|
|
1014
1013
|
if (!semanticName || !SEMANTIC_ICON_NAMES.includes(semanticName)) return original;
|
|
1015
|
-
|
|
1014
|
+
const normalizedAttributeString = attributeString.replace(/\sname=(["'])[^"']+\1/g, "").replace(/\slibrary=(["'])[^"']+\1/g, "").replace(/\sdata-icon-library=(["'])[^"']+\1/g, "").trim();
|
|
1015
|
+
return renderSemanticIconSvgWithAttributeString(library, semanticName, normalizedAttributeString);
|
|
1016
1016
|
}
|
|
1017
1017
|
|
|
1018
1018
|
//#endregion
|
|
@@ -1064,6 +1064,15 @@ function rewriteAstroMenus(content, menuColor) {
|
|
|
1064
1064
|
//#endregion
|
|
1065
1065
|
//#region src/utils/astro-imports.ts
|
|
1066
1066
|
function updateImportAliases(moduleSpecifier, config, isRemote = false) {
|
|
1067
|
+
const scope = config.aliases.components.split("/")[0];
|
|
1068
|
+
for (const [segment, alias] of [
|
|
1069
|
+
["lib/utils", config.aliases.utils],
|
|
1070
|
+
["lib", config.aliases.lib],
|
|
1071
|
+
["hooks", config.aliases.hooks]
|
|
1072
|
+
]) {
|
|
1073
|
+
if (!alias) continue;
|
|
1074
|
+
for (const prefix of [`@/${segment}`, `${scope}/${segment}`]) if (moduleSpecifier === prefix || moduleSpecifier.startsWith(`${prefix}/`)) return alias + moduleSpecifier.slice(prefix.length);
|
|
1075
|
+
}
|
|
1067
1076
|
if (!moduleSpecifier.startsWith("@/") && !isRemote) return moduleSpecifier;
|
|
1068
1077
|
let specifier = moduleSpecifier;
|
|
1069
1078
|
if (isRemote && specifier.startsWith("@/")) specifier = specifier.replace(/^@\//, `@/registry/${config.style || "bejamas-juno"}/`);
|
|
@@ -1088,6 +1097,7 @@ function rewriteAstroImports(content, config) {
|
|
|
1088
1097
|
if (finalSpec === specifier) return full;
|
|
1089
1098
|
return full.replace(specifier, finalSpec);
|
|
1090
1099
|
});
|
|
1100
|
+
updated = updated.replace(/(?:export\s+(?:type\s+)?(?:\{[^}]*\}|\*)\s+from\s*|import\s*\(\s*)["']([^"']+)["']/g, (full, specifier) => full.replace(specifier, updateImportAliases(specifier, config)));
|
|
1091
1101
|
updated = updated.replace(/import\s+["']([^"']+)["']/g, (full, specifier) => {
|
|
1092
1102
|
const next = updateImportAliases(specifier, config, false);
|
|
1093
1103
|
if (next === specifier) return full;
|
|
@@ -1096,25 +1106,45 @@ function rewriteAstroImports(content, config) {
|
|
|
1096
1106
|
updated = rewriteAstroMenus(updated, config.menuColor);
|
|
1097
1107
|
return rewriteAstroIcons(updated, config.iconLibrary);
|
|
1098
1108
|
}
|
|
1099
|
-
|
|
1100
|
-
|
|
1109
|
+
function getConfiguredSourceRoots(config) {
|
|
1110
|
+
return Array.from(new Set([
|
|
1111
|
+
config.resolvedPaths.components,
|
|
1112
|
+
config.resolvedPaths.ui,
|
|
1113
|
+
config.resolvedPaths.lib,
|
|
1114
|
+
config.resolvedPaths.hooks
|
|
1115
|
+
].filter((root) => Boolean(root))));
|
|
1116
|
+
}
|
|
1117
|
+
function isPathWithin(filePath, root) {
|
|
1118
|
+
const relative = path.relative(root, filePath);
|
|
1119
|
+
return relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
1120
|
+
}
|
|
1121
|
+
async function fixAstroImports(cwd, isVerbose, targetConfig, scope = { kind: "configured-roots" }) {
|
|
1122
|
+
const config = targetConfig ?? await getConfig(cwd);
|
|
1101
1123
|
if (!config) return;
|
|
1102
|
-
const
|
|
1103
|
-
for (const
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
for (const
|
|
1111
|
-
const
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1124
|
+
const files = /* @__PURE__ */ new Set();
|
|
1125
|
+
if (scope.kind === "files") for (const filePath of scope.paths) {
|
|
1126
|
+
const absolutePath = path.resolve(cwd, filePath);
|
|
1127
|
+
if (!/\.(?:astro|ts|js)$/.test(absolutePath)) continue;
|
|
1128
|
+
if ((await fs$1.stat(absolutePath).catch(() => null))?.isFile()) files.add(absolutePath);
|
|
1129
|
+
}
|
|
1130
|
+
else {
|
|
1131
|
+
const excluded = new Set((scope.exclude ?? []).map((filePath) => path.resolve(cwd, filePath)));
|
|
1132
|
+
for (const root of getConfiguredSourceRoots(config)) {
|
|
1133
|
+
const matches = await fg("**/*.{astro,ts,js}", {
|
|
1134
|
+
cwd: root,
|
|
1135
|
+
absolute: true,
|
|
1136
|
+
dot: false
|
|
1137
|
+
});
|
|
1138
|
+
for (const filePath of matches) if (!excluded.has(path.resolve(filePath))) files.add(filePath);
|
|
1116
1139
|
}
|
|
1117
1140
|
}
|
|
1141
|
+
for (const filePath of files) {
|
|
1142
|
+
const original = await fs$1.readFile(filePath, "utf8");
|
|
1143
|
+
const rewritten = rewriteAstroImports(original, config);
|
|
1144
|
+
if (rewritten === original) continue;
|
|
1145
|
+
await fs$1.writeFile(filePath, rewritten, "utf8");
|
|
1146
|
+
if (isVerbose) logger.info(`[bejamas-ui] fixed imports in ${path.relative(cwd, filePath)}`);
|
|
1147
|
+
}
|
|
1118
1148
|
}
|
|
1119
1149
|
|
|
1120
1150
|
//#endregion
|
|
@@ -1235,7 +1265,7 @@ const TEMPLATE_DIRNAME = {
|
|
|
1235
1265
|
"astro-monorepo": "monorepo-astro",
|
|
1236
1266
|
"astro-with-component-docs-monorepo": "monorepo-astro-with-docs"
|
|
1237
1267
|
};
|
|
1238
|
-
const TEMPLATE_EXCLUDED_BASENAMES = new Set(["node_modules", ".astro"]);
|
|
1268
|
+
const TEMPLATE_EXCLUDED_BASENAMES = /* @__PURE__ */ new Set(["node_modules", ".astro"]);
|
|
1239
1269
|
const DEFAULT_TEMPLATE_REPOSITORY = "bejamas/ui";
|
|
1240
1270
|
const DEFAULT_TEMPLATE_REF = "main";
|
|
1241
1271
|
function resolveLocalTemplatesDir(env = process.env) {
|
|
@@ -1498,12 +1528,32 @@ async function getInstalledUiComponents(cwd) {
|
|
|
1498
1528
|
|
|
1499
1529
|
//#endregion
|
|
1500
1530
|
//#region src/utils/reorganize-components.ts
|
|
1531
|
+
const BEJAMAS_REGISTRY_NAMESPACE = "@bejamas/";
|
|
1532
|
+
/**
|
|
1533
|
+
* Resolve the Bejamas item name behind a user-provided specifier. Returns null
|
|
1534
|
+
* for URLs and third-party namespaces, which shadcn resolves on its own.
|
|
1535
|
+
*/
|
|
1536
|
+
function resolveBejamasRegistryItemName(specifier) {
|
|
1537
|
+
const name = specifier.startsWith("@bejamas/") ? specifier.slice(9) : specifier;
|
|
1538
|
+
return /^[a-z0-9][a-z0-9-]*$/.test(name) ? name : null;
|
|
1539
|
+
}
|
|
1540
|
+
function isRegistryItemUrl(specifier) {
|
|
1541
|
+
return /^https?:\/\//.test(specifier);
|
|
1542
|
+
}
|
|
1501
1543
|
async function fetchRegistryItem(componentName, registryUrl, style = "bejamas-juno") {
|
|
1502
|
-
|
|
1544
|
+
if (isRegistryItemUrl(componentName)) try {
|
|
1545
|
+
const response = await fetch(componentName);
|
|
1546
|
+
return response.ok ? await response.json() : null;
|
|
1547
|
+
} catch {
|
|
1548
|
+
return null;
|
|
1549
|
+
}
|
|
1550
|
+
const itemName = resolveBejamasRegistryItemName(componentName);
|
|
1551
|
+
if (!itemName) return null;
|
|
1552
|
+
const url = `${registryUrl}/styles/${style}/${itemName}.json`;
|
|
1503
1553
|
try {
|
|
1504
|
-
const response = await fetch(url
|
|
1554
|
+
const response = await fetch(url);
|
|
1505
1555
|
if (!response.ok) {
|
|
1506
|
-
const fallbackUrl = `${registryUrl}/${
|
|
1556
|
+
const fallbackUrl = `${registryUrl}/${itemName}.json`;
|
|
1507
1557
|
const fallbackResponse = await fetch(fallbackUrl);
|
|
1508
1558
|
if (!fallbackResponse.ok) return null;
|
|
1509
1559
|
return await fallbackResponse.json();
|
|
@@ -1516,7 +1566,7 @@ async function fetchRegistryItem(componentName, registryUrl, style = "bejamas-ju
|
|
|
1516
1566
|
function getSubfolderFromPaths(files) {
|
|
1517
1567
|
if (!files || files.length === 0) return null;
|
|
1518
1568
|
const uiFiles = files.filter((file) => file.type === "registry:ui");
|
|
1519
|
-
if (uiFiles.length
|
|
1569
|
+
if (uiFiles.length === 0) return null;
|
|
1520
1570
|
const subfolders = /* @__PURE__ */ new Set();
|
|
1521
1571
|
for (const file of uiFiles) {
|
|
1522
1572
|
const parts = file.path.split("/");
|
|
@@ -1525,8 +1575,8 @@ function getSubfolderFromPaths(files) {
|
|
|
1525
1575
|
}
|
|
1526
1576
|
if (subfolders.size === 1) return Array.from(subfolders)[0];
|
|
1527
1577
|
if (uiFiles.length > 0) {
|
|
1528
|
-
const dirname
|
|
1529
|
-
const folderName = path.basename(dirname
|
|
1578
|
+
const dirname = path.dirname(uiFiles[0].path);
|
|
1579
|
+
const folderName = path.basename(dirname);
|
|
1530
1580
|
if (folderName && folderName !== "ui") return folderName;
|
|
1531
1581
|
}
|
|
1532
1582
|
return null;
|
|
@@ -1556,7 +1606,7 @@ function resolveShadcnUiRelativePath(filePath, uiDir) {
|
|
|
1556
1606
|
function shouldReorganizeRegistryUiFiles(files, uiDir) {
|
|
1557
1607
|
if (!uiDir) return false;
|
|
1558
1608
|
if (!getSubfolderFromPaths(files)) return false;
|
|
1559
|
-
return files.filter((file) => file.type === "registry:ui").some((file) => {
|
|
1609
|
+
return (files ?? []).filter((file) => file.type === "registry:ui").some((file) => {
|
|
1560
1610
|
return !resolveShadcnUiRelativePath(file.path, uiDir).includes("/");
|
|
1561
1611
|
});
|
|
1562
1612
|
}
|
|
@@ -1577,6 +1627,7 @@ async function reorganizeRegistryUiFiles(files, uiDir, verbose, overwriteExistin
|
|
|
1577
1627
|
const targetDir = path.join(uiDir, subfolder);
|
|
1578
1628
|
for (const file of uiFiles) {
|
|
1579
1629
|
const filename = path.basename(file.path);
|
|
1630
|
+
if (filename === "index.ts") continue;
|
|
1580
1631
|
const flatPath = path.join(uiDir, filename);
|
|
1581
1632
|
const targetPath = path.join(targetDir, filename);
|
|
1582
1633
|
if (!await pathExists(flatPath)) continue;
|
|
@@ -1605,39 +1656,82 @@ async function reorganizeRegistryUiFiles(files, uiDir, verbose, overwriteExistin
|
|
|
1605
1656
|
result.movedFiles.push(`${subfolder}/${filename}`);
|
|
1606
1657
|
if (verbose) logger.info(`[bejamas-ui] Moved ${filename} -> ${subfolder}/${filename}`);
|
|
1607
1658
|
}
|
|
1659
|
+
if (await pathExists(targetDir)) await repairComponentBarrel(targetDir, files, overwriteExisting);
|
|
1608
1660
|
return result;
|
|
1609
1661
|
}
|
|
1662
|
+
async function repairComponentBarrel(targetDir, files, overwriteExisting = false) {
|
|
1663
|
+
const localFiles = (await fs$1.readdir(targetDir)).filter((name) => name.endsWith(".astro")).sort();
|
|
1664
|
+
if (!localFiles.length) return;
|
|
1665
|
+
const indexPath = path.join(targetDir, "index.ts");
|
|
1666
|
+
const existing = await fs$1.readFile(indexPath, "utf8").catch(() => "");
|
|
1667
|
+
const registryBarrel = files.find((file) => path.basename(file.path) === "index.ts")?.content ?? "";
|
|
1668
|
+
const cleaned = (overwriteExisting || !existing ? registryBarrel : existing).replace(/export\s*\{[^}]*\}\s*from\s*["'](\.\/[^"']+\.astro)["'];?/g, (statement, specifier) => localFiles.includes(specifier.slice(2)) ? statement : "").trim();
|
|
1669
|
+
const next = [cleaned, ...localFiles.filter((file) => {
|
|
1670
|
+
const name = path.basename(file, ".astro");
|
|
1671
|
+
return !new RegExp(`default\\s+as\\s+${name}\\b`).test(cleaned);
|
|
1672
|
+
}).map((file) => `export { default as ${path.basename(file, ".astro")} } from "./${file}";`)].filter(Boolean).join("\n") + "\n";
|
|
1673
|
+
if (next !== existing) await fs$1.writeFile(indexPath, next);
|
|
1674
|
+
}
|
|
1675
|
+
/** Resolve dependencies as well as the requested item before repairing output. */
|
|
1676
|
+
async function fetchRegistryTree(components, registryUrl, style = "bejamas-juno") {
|
|
1677
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1678
|
+
const items = [];
|
|
1679
|
+
async function visit(name) {
|
|
1680
|
+
if (seen.has(name)) return;
|
|
1681
|
+
seen.add(name);
|
|
1682
|
+
if (!isRegistryItemUrl(name) && !resolveBejamasRegistryItemName(name)) return;
|
|
1683
|
+
const item = await fetchRegistryItem(name, registryUrl, style);
|
|
1684
|
+
if (!item) throw new Error(`Unable to load registry item ${name} for installation validation.`);
|
|
1685
|
+
for (const dependency of item.registryDependencies ?? []) await visit(dependency);
|
|
1686
|
+
items.push(item);
|
|
1687
|
+
}
|
|
1688
|
+
for (const name of components) await visit(name);
|
|
1689
|
+
return items;
|
|
1690
|
+
}
|
|
1610
1691
|
async function reorganizeComponents(components, uiDir, registryUrl, verbose, style = "bejamas-juno", overwriteExisting = false) {
|
|
1692
|
+
return reorganizeRegistryItems(uiDir && components.length ? await fetchRegistryTree(components, registryUrl, style) : [], uiDir, verbose, overwriteExisting);
|
|
1693
|
+
}
|
|
1694
|
+
/** Reuse the registry tree already resolved for this installation. */
|
|
1695
|
+
async function reorganizeRegistryItems(items, uiDir, verbose, overwriteExisting = false) {
|
|
1611
1696
|
const result = {
|
|
1612
1697
|
totalMoved: 0,
|
|
1613
1698
|
movedFiles: [],
|
|
1614
1699
|
skippedFiles: []
|
|
1615
1700
|
};
|
|
1616
|
-
if (!
|
|
1617
|
-
for (const
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
if (verbose) logger.info(`[bejamas-ui] Could not fetch registry for ${componentName}, skipping reorganization`);
|
|
1621
|
-
continue;
|
|
1622
|
-
}
|
|
1623
|
-
if (!shouldReorganizeRegistryUiFiles(registryItem.files, uiDir)) continue;
|
|
1624
|
-
const componentResult = await reorganizeRegistryUiFiles(registryItem.files, uiDir, verbose, overwriteExisting);
|
|
1701
|
+
if (!items.some((item) => shouldReorganizeRegistryUiFiles(item.files, uiDir))) return result;
|
|
1702
|
+
for (const item of items) {
|
|
1703
|
+
if (!shouldReorganizeRegistryUiFiles(item.files, uiDir)) continue;
|
|
1704
|
+
const componentResult = await reorganizeRegistryUiFiles(item.files, uiDir, verbose, overwriteExisting);
|
|
1625
1705
|
result.totalMoved += componentResult.totalMoved;
|
|
1626
1706
|
result.movedFiles.push(...componentResult.movedFiles);
|
|
1627
1707
|
result.skippedFiles.push(...componentResult.skippedFiles);
|
|
1628
|
-
if (componentResult.totalMoved > 0 && verbose) {
|
|
1629
|
-
const subfolder = getSubfolderFromPaths(registryItem.files);
|
|
1630
|
-
logger.info(`[bejamas-ui] Reorganized ${componentName} into ${subfolder}/`);
|
|
1631
|
-
}
|
|
1632
|
-
} catch (err) {
|
|
1633
|
-
if (verbose) logger.warn(`[bejamas-ui] Failed to reorganize ${componentName}: ${err}`);
|
|
1634
1708
|
}
|
|
1709
|
+
const flatIndex = path.join(uiDir, "index.ts");
|
|
1710
|
+
const flatContent = await fs$1.readFile(flatIndex, "utf8").catch(() => null);
|
|
1711
|
+
if (flatContent && items.some((item) => item.files?.some((file) => file.type === "registry:ui" && path.basename(file.path) === "index.ts" && file.content.trim() === flatContent.trim()))) await fs$1.unlink(flatIndex);
|
|
1635
1712
|
return result;
|
|
1636
1713
|
}
|
|
1714
|
+
/** Update legacy template exports once the installed UI uses nested barrels. */
|
|
1715
|
+
async function repairUiPackageExports(uiDir, packageRoot) {
|
|
1716
|
+
const entries = await fs$1.readdir(uiDir, { withFileTypes: true }).catch(() => []);
|
|
1717
|
+
if (!entries.some((entry) => entry.isDirectory()) || entries.some((entry) => entry.name.endsWith(".astro"))) return;
|
|
1718
|
+
const packagePath = path.join(packageRoot, "package.json");
|
|
1719
|
+
const manifest = JSON.parse(await fs$1.readFile(packagePath, "utf8"));
|
|
1720
|
+
if (!manifest.exports || typeof manifest.exports !== "object") return;
|
|
1721
|
+
const relativeUi = path.relative(packageRoot, uiDir).split(path.sep).join("/");
|
|
1722
|
+
if (relativeUi.startsWith("../")) return;
|
|
1723
|
+
const prefix = `./${relativeUi}`;
|
|
1724
|
+
let changed = false;
|
|
1725
|
+
for (const [specifier, target] of Object.entries(manifest.exports)) if (target === `${prefix}/*.astro` || target === `${prefix}/*.ts`) {
|
|
1726
|
+
manifest.exports[specifier] = `${prefix}/*/index.ts`;
|
|
1727
|
+
changed = true;
|
|
1728
|
+
}
|
|
1729
|
+
if (changed) await fs$1.writeFile(packagePath, JSON.stringify(manifest, null, 2) + "\n");
|
|
1730
|
+
}
|
|
1637
1731
|
|
|
1638
1732
|
//#endregion
|
|
1639
1733
|
//#region src/utils/shadcn-cli.ts
|
|
1640
|
-
const PINNED_SHADCN_VERSION = "4.
|
|
1734
|
+
const PINNED_SHADCN_VERSION = "4.21.0";
|
|
1641
1735
|
const PINNED_SHADCN_PACKAGE = `shadcn@${PINNED_SHADCN_VERSION}`;
|
|
1642
1736
|
const PINNED_SHADCN_EXEC_PREFIX = path.join(os$1.tmpdir(), "bejamas-shadcn", PINNED_SHADCN_VERSION);
|
|
1643
1737
|
async function ensurePinnedShadcnExecPrefix() {
|
|
@@ -1772,32 +1866,32 @@ function ensureShadcnReinstallFlag(forwardedOptions, shouldReinstall) {
|
|
|
1772
1866
|
function extractOptionsForShadcnInit(rawArgv, cmd) {
|
|
1773
1867
|
if (typeof cmd.getOptionValueSource === "function") {
|
|
1774
1868
|
const opts = cmd.optsWithGlobals();
|
|
1775
|
-
const forwarded
|
|
1869
|
+
const forwarded = [];
|
|
1776
1870
|
const getSource = (key) => cmd.getOptionValueSource(key);
|
|
1777
1871
|
const addBoolean = (key, flag, negateFlag) => {
|
|
1778
1872
|
if (getSource(key) !== "cli") return;
|
|
1779
1873
|
const value = opts[key];
|
|
1780
1874
|
if (typeof value !== "boolean") return;
|
|
1781
|
-
if (value) forwarded
|
|
1782
|
-
else if (negateFlag) forwarded
|
|
1875
|
+
if (value) forwarded.push(flag);
|
|
1876
|
+
else if (negateFlag) forwarded.push(negateFlag);
|
|
1783
1877
|
};
|
|
1784
1878
|
addBoolean("yes", "--yes");
|
|
1785
1879
|
addBoolean("force", "--force");
|
|
1786
1880
|
addBoolean("silent", "--silent");
|
|
1787
1881
|
addBoolean("reinstall", "--reinstall", "--no-reinstall");
|
|
1788
|
-
const initIndex
|
|
1789
|
-
if (initIndex
|
|
1790
|
-
const rest
|
|
1791
|
-
const doubleDashIndex = rest
|
|
1792
|
-
if (doubleDashIndex !== -1) forwarded
|
|
1882
|
+
const initIndex = rawArgv.findIndex((arg) => arg === "init");
|
|
1883
|
+
if (initIndex !== -1) {
|
|
1884
|
+
const rest = rawArgv.slice(initIndex + 1);
|
|
1885
|
+
const doubleDashIndex = rest.indexOf("--");
|
|
1886
|
+
if (doubleDashIndex !== -1) forwarded.push(...rest.slice(doubleDashIndex));
|
|
1793
1887
|
}
|
|
1794
|
-
return forwarded
|
|
1888
|
+
return forwarded;
|
|
1795
1889
|
}
|
|
1796
1890
|
const initIndex = rawArgv.findIndex((arg) => arg === "init");
|
|
1797
1891
|
if (initIndex === -1) return [];
|
|
1798
1892
|
const rest = rawArgv.slice(initIndex + 1);
|
|
1799
1893
|
const forwarded = [];
|
|
1800
|
-
const filteredFlags = new Set([
|
|
1894
|
+
const filteredFlags = /* @__PURE__ */ new Set([
|
|
1801
1895
|
"-v",
|
|
1802
1896
|
"--verbose",
|
|
1803
1897
|
"-t",
|
|
@@ -1848,7 +1942,7 @@ async function runInit(options) {
|
|
|
1848
1942
|
const designConfig = resolveDesignSystemConfig(options);
|
|
1849
1943
|
let newProjectTemplate;
|
|
1850
1944
|
if (!options.skipPreflight) {
|
|
1851
|
-
if ((await preFlightInit(options)).errors[
|
|
1945
|
+
if ((await preFlightInit(options)).errors["1"]) {
|
|
1852
1946
|
const { projectPath, template } = await createProject(options);
|
|
1853
1947
|
if (!projectPath) process.exit(1);
|
|
1854
1948
|
options.cwd = projectPath;
|
|
@@ -1962,13 +2056,14 @@ function resolveAliasPathUsingTsConfig(inputPath, projectRoot) {
|
|
|
1962
2056
|
const paths = cfg.compilerOptions.paths || {};
|
|
1963
2057
|
for (const [key, values] of Object.entries(paths)) {
|
|
1964
2058
|
const pattern = key.replace(/\*/g, "(.*)");
|
|
1965
|
-
const re =
|
|
2059
|
+
const re = new RegExp(`^${pattern}$`);
|
|
1966
2060
|
const match = inputPath.match(re);
|
|
1967
2061
|
if (!match) continue;
|
|
1968
2062
|
const wildcard = match[1] || "";
|
|
1969
2063
|
const first = Array.isArray(values) ? values[0] : values;
|
|
1970
2064
|
if (!first) continue;
|
|
1971
|
-
|
|
2065
|
+
const target = String(first).replace(/\*/g, wildcard);
|
|
2066
|
+
return resolve(projectRoot, baseUrl, target);
|
|
1972
2067
|
}
|
|
1973
2068
|
return null;
|
|
1974
2069
|
}
|
|
@@ -1979,6 +2074,8 @@ async function generateDocs({ cwd, outDir, verbose }) {
|
|
|
1979
2074
|
const DEBUG = process.env.BEJAMAS_DEBUG === "1" || process.env.BEJAMAS_DEBUG === "true" || verbose;
|
|
1980
2075
|
try {
|
|
1981
2076
|
const shellCwd = process.cwd();
|
|
2077
|
+
if (cwd && cwd.length) process.env.BEJAMAS_UI_ROOT = resolve(shellCwd, cwd);
|
|
2078
|
+
if (outDir && outDir.length) process.env.BEJAMAS_DOCS_OUT_DIR = outDir;
|
|
1982
2079
|
let projectRoot = shellCwd;
|
|
1983
2080
|
let probe = shellCwd;
|
|
1984
2081
|
for (let i = 0; i < 6 && probe; i += 1) {
|
|
@@ -2030,27 +2127,30 @@ async function generateDocs({ cwd, outDir, verbose }) {
|
|
|
2030
2127
|
}
|
|
2031
2128
|
if (!process.env.BEJAMAS_DOCS_CWD) process.env.BEJAMAS_DOCS_CWD = shellCwd;
|
|
2032
2129
|
if (!process.env.BEJAMAS_UI_ROOT) {
|
|
2130
|
+
const defaultGuess = (() => {
|
|
2131
|
+
let current = shellCwd;
|
|
2132
|
+
for (let i = 0; i < 6; i += 1) {
|
|
2133
|
+
const cand = resolve(current, "packages/ui/package.json");
|
|
2134
|
+
if (existsSync(cand)) {
|
|
2135
|
+
const abs = resolve(current, "packages/ui");
|
|
2136
|
+
return relative(shellCwd, abs) || abs;
|
|
2137
|
+
}
|
|
2138
|
+
const parent = resolve(current, "..");
|
|
2139
|
+
if (parent === current) break;
|
|
2140
|
+
current = parent;
|
|
2141
|
+
}
|
|
2142
|
+
const nm = resolve(shellCwd, "node_modules/@bejamas/ui/package.json");
|
|
2143
|
+
if (existsSync(nm)) {
|
|
2144
|
+
const abs = resolve(shellCwd, "node_modules/@bejamas/ui");
|
|
2145
|
+
return relative(shellCwd, abs) || abs;
|
|
2146
|
+
}
|
|
2147
|
+
return "packages/ui";
|
|
2148
|
+
})();
|
|
2033
2149
|
const { uiRoot } = await prompts({
|
|
2034
2150
|
type: "text",
|
|
2035
2151
|
name: "uiRoot",
|
|
2036
2152
|
message: "Path to @bejamas/ui package root:",
|
|
2037
|
-
initial:
|
|
2038
|
-
let current = shellCwd;
|
|
2039
|
-
for (let i = 0; i < 6; i += 1) {
|
|
2040
|
-
if (existsSync(resolve(current, "packages/ui/package.json"))) {
|
|
2041
|
-
const abs = resolve(current, "packages/ui");
|
|
2042
|
-
return relative(shellCwd, abs) || abs;
|
|
2043
|
-
}
|
|
2044
|
-
const parent = resolve(current, "..");
|
|
2045
|
-
if (parent === current) break;
|
|
2046
|
-
current = parent;
|
|
2047
|
-
}
|
|
2048
|
-
if (existsSync(resolve(shellCwd, "node_modules/@bejamas/ui/package.json"))) {
|
|
2049
|
-
const abs = resolve(shellCwd, "node_modules/@bejamas/ui");
|
|
2050
|
-
return relative(shellCwd, abs) || abs;
|
|
2051
|
-
}
|
|
2052
|
-
return "packages/ui";
|
|
2053
|
-
})(),
|
|
2153
|
+
initial: defaultGuess,
|
|
2054
2154
|
validate: (val) => {
|
|
2055
2155
|
const p = resolve(shellCwd, val);
|
|
2056
2156
|
return existsSync(resolve(p, "package.json")) ? true : `No package.json found in ${p}`;
|
|
@@ -2062,8 +2162,6 @@ async function generateDocs({ cwd, outDir, verbose }) {
|
|
|
2062
2162
|
}
|
|
2063
2163
|
process.env.BEJAMAS_UI_ROOT = resolve(shellCwd, uiRoot);
|
|
2064
2164
|
}
|
|
2065
|
-
if (cwd && cwd.length) process.env.BEJAMAS_UI_ROOT = resolve(cwd);
|
|
2066
|
-
if (outDir && outDir.length) process.env.BEJAMAS_DOCS_OUT_DIR = outDir;
|
|
2067
2165
|
if (!process.env.BEJAMAS_DOCS_OUT_DIR) {
|
|
2068
2166
|
const { out } = await prompts({
|
|
2069
2167
|
type: "text",
|
|
@@ -2086,7 +2184,7 @@ async function generateDocs({ cwd, outDir, verbose }) {
|
|
|
2086
2184
|
if (process.env.BEJAMAS_DOCS_CWD) logger.info(`Docs CWD: ${process.env.BEJAMAS_DOCS_CWD}`);
|
|
2087
2185
|
if (process.env.BEJAMAS_DOCS_OUT_DIR) logger.info(`Docs out: ${process.env.BEJAMAS_DOCS_OUT_DIR}`);
|
|
2088
2186
|
}
|
|
2089
|
-
const mod = await import("./generate-mdx-
|
|
2187
|
+
const mod = await import("./generate-mdx-Bd_qGcMg.js");
|
|
2090
2188
|
if (typeof mod.runDocsGenerator === "function") await mod.runDocsGenerator();
|
|
2091
2189
|
else throw new Error("Failed to load docs generator. Export 'runDocsGenerator' not found.");
|
|
2092
2190
|
} catch (err) {
|
|
@@ -2123,7 +2221,9 @@ const FIELD_LABELS = {
|
|
|
2123
2221
|
figmaUrl: "@figmaUrl"
|
|
2124
2222
|
};
|
|
2125
2223
|
function checkComponentDocs(filePath, fileName) {
|
|
2126
|
-
const
|
|
2224
|
+
const content = readFileSync(filePath, "utf-8");
|
|
2225
|
+
const frontmatter = extractFrontmatter(content);
|
|
2226
|
+
const meta = parseJsDocMetadata(frontmatter);
|
|
2127
2227
|
const componentName = fileName.replace(/\.astro$/i, "");
|
|
2128
2228
|
const missingRequired = [];
|
|
2129
2229
|
const missingRecommended = [];
|
|
@@ -2271,33 +2371,286 @@ const docsCheck = new Command().name("docs:check").description("check documentat
|
|
|
2271
2371
|
});
|
|
2272
2372
|
});
|
|
2273
2373
|
|
|
2374
|
+
//#endregion
|
|
2375
|
+
//#region ../registry/src/lib/headless-dependencies.ts
|
|
2376
|
+
/** Headless behaviors imported by emitted frontmatter, client scripts or helpers. */
|
|
2377
|
+
function getHeadlessDependencies(files) {
|
|
2378
|
+
const dependencies = /* @__PURE__ */ new Set();
|
|
2379
|
+
for (const file of files) {
|
|
2380
|
+
const source = (file.content ?? "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
2381
|
+
for (const match of source.matchAll(/(?:\bfrom\s*|\bimport\s*\(?\s*)["'](@data-slot\/[^/"']+)(?:\/[^"']*)?["']/g)) dependencies.add(match[1]);
|
|
2382
|
+
}
|
|
2383
|
+
return [...dependencies].sort();
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
//#endregion
|
|
2387
|
+
//#region src/utils/registry-dependencies.ts
|
|
2388
|
+
function missingRegistryDependencies(manifest, items) {
|
|
2389
|
+
const declared = {
|
|
2390
|
+
...manifest.devDependencies,
|
|
2391
|
+
...manifest.dependencies
|
|
2392
|
+
};
|
|
2393
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
2394
|
+
for (const item of items) for (const specifier of item.dependencies ?? []) {
|
|
2395
|
+
const name = specifier.match(/^(@[^/]+\/[^@/]+|[^@/]+)/)?.[1];
|
|
2396
|
+
if (name && !declared[name]) candidates.set(name, specifier);
|
|
2397
|
+
}
|
|
2398
|
+
for (const item of items) for (const name of getHeadlessDependencies(item.files ?? [])) if (!declared[name] && !candidates.has(name)) candidates.set(name, name);
|
|
2399
|
+
return [...candidates.values()].sort();
|
|
2400
|
+
}
|
|
2401
|
+
async function ensureRegistryDependencies(cwd, items) {
|
|
2402
|
+
const missing = missingRegistryDependencies(JSON.parse(await fs$1.readFile(path.join(cwd, "package.json"), "utf8")), items);
|
|
2403
|
+
if (!missing.length) return;
|
|
2404
|
+
const manager = await getPackageManager(cwd);
|
|
2405
|
+
await execa(manager, [manager === "npm" ? "install" : "add", ...missing], {
|
|
2406
|
+
cwd,
|
|
2407
|
+
stdio: "inherit"
|
|
2408
|
+
});
|
|
2409
|
+
}
|
|
2410
|
+
|
|
2411
|
+
//#endregion
|
|
2412
|
+
//#region src/utils/registry-install.ts
|
|
2413
|
+
/**
|
|
2414
|
+
* shadcn reports written files relative to the directory it ran in, except in
|
|
2415
|
+
* a workspace where paths are relative to the monorepo root. Resolve each
|
|
2416
|
+
* reported path against the candidate bases and keep the ones that exist; the
|
|
2417
|
+
* first base with a match wins, so list the one shadcn reports against first.
|
|
2418
|
+
*/
|
|
2419
|
+
function resolveReportedFiles(files, bases, exists = existsSync) {
|
|
2420
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
2421
|
+
for (const file of files) {
|
|
2422
|
+
const match = (path.isAbsolute(file) ? [file] : bases.map((base) => path.resolve(base, file))).find((candidate) => exists(candidate));
|
|
2423
|
+
if (match) resolved.add(match);
|
|
2424
|
+
}
|
|
2425
|
+
return Array.from(resolved);
|
|
2426
|
+
}
|
|
2427
|
+
/**
|
|
2428
|
+
* Bases for `resolveReportedFiles`. In a workspace, shadcn reports paths
|
|
2429
|
+
* relative to the monorepo root, so it comes before the app directory.
|
|
2430
|
+
*/
|
|
2431
|
+
function getReportedFileBases(cwd, config, uiConfig) {
|
|
2432
|
+
const workspaceRoot = config && uiConfig && uiConfig.resolvedPaths.cwd !== config.resolvedPaths.cwd ? findCommonRoot(config.resolvedPaths.cwd, uiConfig.resolvedPaths.cwd) : null;
|
|
2433
|
+
return workspaceRoot ? [workspaceRoot, cwd] : [cwd];
|
|
2434
|
+
}
|
|
2435
|
+
/** Installed files (relative to cwd or absolute) not covered by config aliases. */
|
|
2436
|
+
function filesOutsideConfigRoots(cwd, files, config) {
|
|
2437
|
+
const roots = getConfiguredSourceRoots(config);
|
|
2438
|
+
return files.filter((file) => !roots.some((root) => isPathWithin(path.resolve(cwd, file), root)));
|
|
2439
|
+
}
|
|
2440
|
+
function buildSubfolderMap(registryItems) {
|
|
2441
|
+
const filenameToSubfolders = /* @__PURE__ */ new Map();
|
|
2442
|
+
for (const registryItem of registryItems) {
|
|
2443
|
+
const subfolder = getSubfolderFromPaths(registryItem.files);
|
|
2444
|
+
if (!subfolder) continue;
|
|
2445
|
+
for (const file of registryItem.files ?? []) if (file.type === "registry:ui") {
|
|
2446
|
+
const filename = path.basename(file.path);
|
|
2447
|
+
const subfolders = filenameToSubfolders.get(filename) || [];
|
|
2448
|
+
subfolders.push(subfolder);
|
|
2449
|
+
filenameToSubfolders.set(filename, subfolders);
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2452
|
+
const uniqueMap = /* @__PURE__ */ new Map();
|
|
2453
|
+
const sharedFilenames = /* @__PURE__ */ new Set();
|
|
2454
|
+
filenameToSubfolders.forEach((subfolders, filename) => {
|
|
2455
|
+
if (subfolders.length === 1) uniqueMap.set(filename, `${subfolders[0]}/${filename}`);
|
|
2456
|
+
else sharedFilenames.add(filename);
|
|
2457
|
+
});
|
|
2458
|
+
return {
|
|
2459
|
+
uniqueMap,
|
|
2460
|
+
sharedFilenames
|
|
2461
|
+
};
|
|
2462
|
+
}
|
|
2463
|
+
/**
|
|
2464
|
+
* Repairs the output of several shadcn runs in one command. Work the next run
|
|
2465
|
+
* depends on happens per item in `install`; project-wide passes (import scan,
|
|
2466
|
+
* package exports, dependency installs) run once in `finish`, which the command
|
|
2467
|
+
* also calls before exiting on a failure so completed items stay usable.
|
|
2468
|
+
*/
|
|
2469
|
+
var RegistryInstallBatch = class {
|
|
2470
|
+
constructor(context) {
|
|
2471
|
+
this.context = context;
|
|
2472
|
+
this.items = [];
|
|
2473
|
+
this.written = /* @__PURE__ */ new Set();
|
|
2474
|
+
this.kept = /* @__PURE__ */ new Set();
|
|
2475
|
+
this.bases = getReportedFileBases(context.cwd, context.config, context.uiConfig);
|
|
2476
|
+
}
|
|
2477
|
+
async install({ items, writtenFiles, skippedFiles }) {
|
|
2478
|
+
const { cwd, uiDir, verbose, overwrite } = this.context;
|
|
2479
|
+
const reorganization = await reorganizeRegistryItems(items, uiDir, verbose, overwrite);
|
|
2480
|
+
this.items.push(...items);
|
|
2481
|
+
for (const file of resolveReportedFiles(writtenFiles, this.bases)) this.written.add(file);
|
|
2482
|
+
for (const file of resolveReportedFiles(skippedFiles, this.bases)) this.kept.add(file);
|
|
2483
|
+
for (const file of reorganization.skippedFiles) this.kept.add(path.resolve(uiDir, file));
|
|
2484
|
+
await syncManagedTailwindCss(cwd);
|
|
2485
|
+
const requestedItem = items.at(-1);
|
|
2486
|
+
if (requestedItem?.type === "registry:font") {
|
|
2487
|
+
const nextFont = toManagedAstroFont(requestedItem.name);
|
|
2488
|
+
if (nextFont) {
|
|
2489
|
+
const currentFonts = await readManagedAstroFontsFromProject(cwd);
|
|
2490
|
+
const nextFonts = mergeManagedAstroFonts(currentFonts, nextFont);
|
|
2491
|
+
await syncAstroFontsInProject(cwd, nextFonts, nextFont.cssVariable);
|
|
2492
|
+
await syncAstroManagedFontCss(cwd, nextFont.cssVariable);
|
|
2493
|
+
await cleanupAstroFontPackages(cwd);
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
return reorganization;
|
|
2497
|
+
}
|
|
2498
|
+
async finish() {
|
|
2499
|
+
if (!this.items.length) return;
|
|
2500
|
+
const { cwd, config, uiConfig, uiDir, verbose } = this.context;
|
|
2501
|
+
const items = this.items.splice(0);
|
|
2502
|
+
const written = Array.from(this.written);
|
|
2503
|
+
const kept = Array.from(this.kept).filter((file) => !this.written.has(file));
|
|
2504
|
+
this.written.clear();
|
|
2505
|
+
this.kept.clear();
|
|
2506
|
+
await fixAstroImports(cwd, verbose, uiConfig, {
|
|
2507
|
+
kind: "configured-roots",
|
|
2508
|
+
exclude: kept
|
|
2509
|
+
});
|
|
2510
|
+
if (config) {
|
|
2511
|
+
const appFiles = uiConfig ? filesOutsideConfigRoots(cwd, written, uiConfig) : written;
|
|
2512
|
+
if (appFiles.length) await fixAstroImports(cwd, verbose, config, {
|
|
2513
|
+
kind: "files",
|
|
2514
|
+
paths: appFiles
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2517
|
+
if (uiConfig) {
|
|
2518
|
+
await repairUiPackageExports(uiDir, uiConfig.resolvedPaths.cwd);
|
|
2519
|
+
if (!config || config.resolvedPaths.cwd === uiConfig.resolvedPaths.cwd) await ensureRegistryDependencies(uiConfig.resolvedPaths.cwd, items);
|
|
2520
|
+
else {
|
|
2521
|
+
await ensureRegistryDependencies(uiConfig.resolvedPaths.cwd, items.filter((item) => item.type !== "registry:block"));
|
|
2522
|
+
const blockItems = items.filter((item) => item.type === "registry:block");
|
|
2523
|
+
if (blockItems.length) await ensureRegistryDependencies(config.resolvedPaths.cwd, blockItems);
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
};
|
|
2528
|
+
|
|
2529
|
+
//#endregion
|
|
2530
|
+
//#region src/utils/shadcn-prompts.ts
|
|
2531
|
+
const QUESTION_PATTERN = /(?:^|\s)\?\s+([^\r\n]+?)\s+›/g;
|
|
2532
|
+
const CONFIRM_PATTERN = /(?:^|\s)\?\s+([^\r\n]+?)\s+›\s*\((?:y\/N|Y\/n)\)/g;
|
|
2533
|
+
const SUMMARY_PATTERN = /(?:Created|Updated|Skipped)\s+\d+\s+file|No files updated/i;
|
|
2534
|
+
/**
|
|
2535
|
+
* Decline every confirm question (overwrites, setup offers), then close stdin
|
|
2536
|
+
* when shadcn finishes its file phase. Any other question is reported through
|
|
2537
|
+
* `onUnsupportedPrompt` instead of being left to hang.
|
|
2538
|
+
*/
|
|
2539
|
+
function respondToShadcnPrompts(subprocess, { onUnsupportedPrompt, unsupportedPromptDelayMs = 250 } = {}) {
|
|
2540
|
+
let unsupportedTimer;
|
|
2541
|
+
let waitingOn;
|
|
2542
|
+
let reported = false;
|
|
2543
|
+
function clearUnsupportedTimer() {
|
|
2544
|
+
if (unsupportedTimer) clearTimeout(unsupportedTimer);
|
|
2545
|
+
unsupportedTimer = void 0;
|
|
2546
|
+
waitingOn = void 0;
|
|
2547
|
+
}
|
|
2548
|
+
function inspect(line, answered) {
|
|
2549
|
+
const text = stripVTControlCharacters(line);
|
|
2550
|
+
const stdin = subprocess.stdin;
|
|
2551
|
+
const canAnswer = stdin && !stdin.destroyed && !stdin.writableEnded;
|
|
2552
|
+
if (canAnswer) for (const match of text.matchAll(CONFIRM_PATTERN)) {
|
|
2553
|
+
const message = match[1];
|
|
2554
|
+
if (answered.has(message)) continue;
|
|
2555
|
+
answered.add(message);
|
|
2556
|
+
stdin.write("n\n");
|
|
2557
|
+
if (message === waitingOn) clearUnsupportedTimer();
|
|
2558
|
+
}
|
|
2559
|
+
const message = Array.from(text.matchAll(QUESTION_PATTERN), (match) => match[1]).filter((message) => !answered.has(message)).at(-1);
|
|
2560
|
+
if (message && message !== waitingOn && onUnsupportedPrompt && !reported) {
|
|
2561
|
+
clearUnsupportedTimer();
|
|
2562
|
+
waitingOn = message;
|
|
2563
|
+
unsupportedTimer = setTimeout(() => {
|
|
2564
|
+
reported = true;
|
|
2565
|
+
onUnsupportedPrompt(message);
|
|
2566
|
+
}, unsupportedPromptDelayMs);
|
|
2567
|
+
unsupportedTimer.unref?.();
|
|
2568
|
+
}
|
|
2569
|
+
if (canAnswer && SUMMARY_PATTERN.test(text)) stdin.end();
|
|
2570
|
+
}
|
|
2571
|
+
for (const stream of [subprocess.stdout, subprocess.stderr]) {
|
|
2572
|
+
const decoder = new StringDecoder("utf8");
|
|
2573
|
+
const answered = /* @__PURE__ */ new Set();
|
|
2574
|
+
let pending = "";
|
|
2575
|
+
stream?.on("data", (chunk) => {
|
|
2576
|
+
pending += typeof chunk === "string" ? chunk : decoder.write(chunk);
|
|
2577
|
+
const lines = pending.split("\n");
|
|
2578
|
+
pending = lines.pop();
|
|
2579
|
+
for (const line of lines) {
|
|
2580
|
+
inspect(line, answered);
|
|
2581
|
+
answered.clear();
|
|
2582
|
+
}
|
|
2583
|
+
inspect(pending, answered);
|
|
2584
|
+
});
|
|
2585
|
+
stream?.on("end", clearUnsupportedTimer);
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2274
2589
|
//#endregion
|
|
2275
2590
|
//#region src/commands/add.ts
|
|
2591
|
+
/** shadcn failed; the output has already been reported. */
|
|
2592
|
+
var InstallFailure = class extends Error {
|
|
2593
|
+
constructor(exitCode) {
|
|
2594
|
+
super(`shadcn exited with code ${exitCode}`);
|
|
2595
|
+
this.exitCode = exitCode;
|
|
2596
|
+
}
|
|
2597
|
+
};
|
|
2598
|
+
function isUiRegistryItem(item) {
|
|
2599
|
+
return !item.type || item.type === "registry:ui";
|
|
2600
|
+
}
|
|
2601
|
+
function isBlockRegistryItem(item) {
|
|
2602
|
+
return item?.type === "registry:block";
|
|
2603
|
+
}
|
|
2604
|
+
/** Items a user can pick by name: UI components and blocks. */
|
|
2605
|
+
function isAddableRegistryItem(item) {
|
|
2606
|
+
return isUiRegistryItem(item) || isBlockRegistryItem(item);
|
|
2607
|
+
}
|
|
2608
|
+
/** `--all` is expanded locally, so shadcn must not expand it a second time. */
|
|
2609
|
+
function withoutExpandedAllOption(forwardedOptions) {
|
|
2610
|
+
return forwardedOptions.filter((option) => option !== "--all" && option !== "-a");
|
|
2611
|
+
}
|
|
2612
|
+
/**
|
|
2613
|
+
* shadcn output is captured and re-reported by this command, and silent mode
|
|
2614
|
+
* would hide the file list needed for post-install repair.
|
|
2615
|
+
*/
|
|
2616
|
+
function withoutShadcnSilentOption(forwardedOptions) {
|
|
2617
|
+
return forwardedOptions.filter((option) => option !== "--silent" && option !== "-s");
|
|
2618
|
+
}
|
|
2619
|
+
/**
|
|
2620
|
+
* shadcn only knows the registries declared in components.json. The built-in
|
|
2621
|
+
* `@bejamas/<item>` namespace is the default registry (REGISTRY_URL), so it is
|
|
2622
|
+
* passed to shadcn as the bare item name, which resolves to the styled payload.
|
|
2623
|
+
* Bare names, URLs, and third-party namespaces are passed through unchanged.
|
|
2624
|
+
*/
|
|
2625
|
+
function toShadcnAddArgument(item) {
|
|
2626
|
+
if (!item.startsWith("@bejamas/")) return item;
|
|
2627
|
+
return resolveBejamasRegistryItemName(item) ?? item;
|
|
2628
|
+
}
|
|
2276
2629
|
function extractOptionsForShadcn(rawArgv, cmd) {
|
|
2277
2630
|
if (typeof cmd.getOptionValueSource === "function") {
|
|
2278
2631
|
const opts = cmd.optsWithGlobals();
|
|
2279
|
-
const forwarded
|
|
2632
|
+
const forwarded = [];
|
|
2280
2633
|
const getSource = (key) => cmd.getOptionValueSource(key);
|
|
2281
2634
|
const addBoolean = (key, flag, negateFlag) => {
|
|
2282
2635
|
if (getSource(key) !== "cli") return;
|
|
2283
2636
|
const value = opts[key];
|
|
2284
2637
|
if (typeof value !== "boolean") return;
|
|
2285
|
-
if (value) forwarded
|
|
2286
|
-
else if (negateFlag) forwarded
|
|
2638
|
+
if (value) forwarded.push(flag);
|
|
2639
|
+
else if (negateFlag) forwarded.push(negateFlag);
|
|
2287
2640
|
};
|
|
2288
2641
|
const addString = (key, flag) => {
|
|
2289
2642
|
if (getSource(key) !== "cli") return;
|
|
2290
2643
|
const value = opts[key];
|
|
2291
|
-
if (typeof value === "string") forwarded
|
|
2644
|
+
if (typeof value === "string") forwarded.push(flag, value);
|
|
2292
2645
|
};
|
|
2293
2646
|
const addOptionalString = (key, flag) => {
|
|
2294
2647
|
if (getSource(key) !== "cli") return;
|
|
2295
2648
|
const value = opts[key];
|
|
2296
2649
|
if (value === true) {
|
|
2297
|
-
forwarded
|
|
2650
|
+
forwarded.push(flag);
|
|
2298
2651
|
return;
|
|
2299
2652
|
}
|
|
2300
|
-
if (typeof value === "string") forwarded
|
|
2653
|
+
if (typeof value === "string") forwarded.push(flag, value);
|
|
2301
2654
|
};
|
|
2302
2655
|
addBoolean("yes", "--yes");
|
|
2303
2656
|
addBoolean("overwrite", "--overwrite");
|
|
@@ -2309,19 +2662,19 @@ function extractOptionsForShadcn(rawArgv, cmd) {
|
|
|
2309
2662
|
addBoolean("srcDir", "--src-dir", "--no-src-dir");
|
|
2310
2663
|
addOptionalString("diff", "--diff");
|
|
2311
2664
|
addOptionalString("view", "--view");
|
|
2312
|
-
const addIndex
|
|
2313
|
-
if (addIndex
|
|
2314
|
-
const rest
|
|
2315
|
-
const doubleDashIndex = rest
|
|
2316
|
-
if (doubleDashIndex !== -1) forwarded
|
|
2665
|
+
const addIndex = rawArgv.findIndex((arg) => arg === "add");
|
|
2666
|
+
if (addIndex !== -1) {
|
|
2667
|
+
const rest = rawArgv.slice(addIndex + 1);
|
|
2668
|
+
const doubleDashIndex = rest.indexOf("--");
|
|
2669
|
+
if (doubleDashIndex !== -1) forwarded.push(...rest.slice(doubleDashIndex));
|
|
2317
2670
|
}
|
|
2318
|
-
return forwarded
|
|
2671
|
+
return forwarded;
|
|
2319
2672
|
}
|
|
2320
2673
|
const addIndex = rawArgv.findIndex((arg) => arg === "add");
|
|
2321
2674
|
if (addIndex === -1) return [];
|
|
2322
2675
|
const rest = rawArgv.slice(addIndex + 1);
|
|
2323
2676
|
const forwarded = [];
|
|
2324
|
-
const optionsWithValues = new Set([
|
|
2677
|
+
const optionsWithValues = /* @__PURE__ */ new Set([
|
|
2325
2678
|
"-c",
|
|
2326
2679
|
"--cwd",
|
|
2327
2680
|
"-p",
|
|
@@ -2329,7 +2682,7 @@ function extractOptionsForShadcn(rawArgv, cmd) {
|
|
|
2329
2682
|
"--diff",
|
|
2330
2683
|
"--view"
|
|
2331
2684
|
]);
|
|
2332
|
-
const filteredFlags = new Set(["-v", "--verbose"]);
|
|
2685
|
+
const filteredFlags = /* @__PURE__ */ new Set(["-v", "--verbose"]);
|
|
2333
2686
|
for (let index = 0; index < rest.length; index += 1) {
|
|
2334
2687
|
const token = rest[index];
|
|
2335
2688
|
if (token === "--") {
|
|
@@ -2365,34 +2718,6 @@ function writeCapturedShadcnOutput(stdout, stderr) {
|
|
|
2365
2718
|
if (stdout) process.stdout.write(ensureTrailingNewline(stdout));
|
|
2366
2719
|
if (stderr) process.stderr.write(ensureTrailingNewline(stderr));
|
|
2367
2720
|
}
|
|
2368
|
-
async function buildSubfolderMap(components, uiDir, registryUrl, style) {
|
|
2369
|
-
const filenameToSubfolders = /* @__PURE__ */ new Map();
|
|
2370
|
-
let requiresReorganization = false;
|
|
2371
|
-
for (const componentName of components) {
|
|
2372
|
-
const registryItem = await fetchRegistryItem(componentName, registryUrl, style);
|
|
2373
|
-
if (!registryItem) continue;
|
|
2374
|
-
if (shouldReorganizeRegistryUiFiles(registryItem.files, uiDir)) requiresReorganization = true;
|
|
2375
|
-
const subfolder = getSubfolderFromPaths(registryItem.files);
|
|
2376
|
-
if (!subfolder) continue;
|
|
2377
|
-
for (const file of registryItem.files) if (file.type === "registry:ui") {
|
|
2378
|
-
const filename = path.basename(file.path);
|
|
2379
|
-
const subfolders = filenameToSubfolders.get(filename) || [];
|
|
2380
|
-
subfolders.push(subfolder);
|
|
2381
|
-
filenameToSubfolders.set(filename, subfolders);
|
|
2382
|
-
}
|
|
2383
|
-
}
|
|
2384
|
-
const uniqueMap = /* @__PURE__ */ new Map();
|
|
2385
|
-
const sharedFilenames = /* @__PURE__ */ new Set();
|
|
2386
|
-
filenameToSubfolders.forEach((subfolders, filename) => {
|
|
2387
|
-
if (subfolders.length === 1) uniqueMap.set(filename, `${subfolders[0]}/${filename}`);
|
|
2388
|
-
else sharedFilenames.add(filename);
|
|
2389
|
-
});
|
|
2390
|
-
return {
|
|
2391
|
-
uniqueMap,
|
|
2392
|
-
sharedFilenames,
|
|
2393
|
-
requiresReorganization
|
|
2394
|
-
};
|
|
2395
|
-
}
|
|
2396
2721
|
function rewritePaths(paths, mapResult) {
|
|
2397
2722
|
const { uniqueMap, sharedFilenames } = mapResult;
|
|
2398
2723
|
let currentSubfolder = null;
|
|
@@ -2434,14 +2759,16 @@ async function promptForComponents(registryUrl) {
|
|
|
2434
2759
|
logger.warn("No components available in registry.");
|
|
2435
2760
|
return null;
|
|
2436
2761
|
}
|
|
2762
|
+
const choices = components.filter(isAddableRegistryItem).map((component) => ({
|
|
2763
|
+
title: component.name,
|
|
2764
|
+
value: component.name,
|
|
2765
|
+
description: isBlockRegistryItem(component) ? "block" : void 0
|
|
2766
|
+
}));
|
|
2437
2767
|
const { selected } = await prompts({
|
|
2438
2768
|
type: "autocompleteMultiselect",
|
|
2439
2769
|
name: "selected",
|
|
2440
|
-
message: "Which components would you like to add?",
|
|
2441
|
-
choices
|
|
2442
|
-
title: component.name,
|
|
2443
|
-
value: component.name
|
|
2444
|
-
})),
|
|
2770
|
+
message: "Which components or blocks would you like to add?",
|
|
2771
|
+
choices,
|
|
2445
2772
|
hint: "- Space to select. Return to submit.",
|
|
2446
2773
|
instructions: false
|
|
2447
2774
|
});
|
|
@@ -2454,11 +2781,12 @@ function parseShadcnOutput(stdout, stderr) {
|
|
|
2454
2781
|
updated: [],
|
|
2455
2782
|
skipped: []
|
|
2456
2783
|
};
|
|
2457
|
-
const cleanStderr = stderr
|
|
2458
|
-
const cleanStdout = stdout
|
|
2459
|
-
const
|
|
2460
|
-
const
|
|
2461
|
-
const
|
|
2784
|
+
const cleanStderr = stripVTControlCharacters(stderr);
|
|
2785
|
+
const cleanStdout = stripVTControlCharacters(stdout);
|
|
2786
|
+
const cleanOutput = `${cleanStdout}\n${cleanStderr}`;
|
|
2787
|
+
const createdMatch = cleanOutput.match(/Created\s+(\d+)\s+file/i);
|
|
2788
|
+
const updatedMatch = cleanOutput.match(/Updated\s+(\d+)\s+file/i);
|
|
2789
|
+
const skippedMatch = cleanOutput.match(/Skipped\s+(\d+)\s+file/i);
|
|
2462
2790
|
const createdCount = createdMatch ? parseInt(createdMatch[1], 10) : 0;
|
|
2463
2791
|
const updatedCount = updatedMatch ? parseInt(updatedMatch[1], 10) : 0;
|
|
2464
2792
|
const skippedCount = skippedMatch ? parseInt(skippedMatch[1], 10) : 0;
|
|
@@ -2495,19 +2823,32 @@ async function addComponents(cwd, packages, forwardedOptions, isVerbose, isSilen
|
|
|
2495
2823
|
REGISTRY_URL: resolveRegistryUrl()
|
|
2496
2824
|
};
|
|
2497
2825
|
await ensurePinnedShadcnExecPrefix();
|
|
2498
|
-
const
|
|
2826
|
+
const shadcnArgs = buildShadcnAddArgs(packages, forwardedOptions);
|
|
2827
|
+
const invocation = buildPinnedShadcnInvocation(shadcnArgs);
|
|
2499
2828
|
if (isVerbose) logger.info(`[bejamas-ui] ${invocation.cmd} ${invocation.args.join(" ")}`);
|
|
2500
2829
|
const registrySpinner = spinner("Checking registry.", { silent: isSilent });
|
|
2501
2830
|
registrySpinner.start();
|
|
2502
2831
|
try {
|
|
2503
|
-
const
|
|
2832
|
+
const subprocess = execa(invocation.cmd, invocation.args, {
|
|
2504
2833
|
cwd,
|
|
2505
2834
|
env,
|
|
2506
|
-
|
|
2835
|
+
stdin: "pipe",
|
|
2507
2836
|
stdout: "pipe",
|
|
2508
2837
|
stderr: "pipe",
|
|
2509
2838
|
reject: false
|
|
2510
2839
|
});
|
|
2840
|
+
let unsupportedPrompt;
|
|
2841
|
+
respondToShadcnPrompts(subprocess, { onUnsupportedPrompt(message) {
|
|
2842
|
+
unsupportedPrompt = message;
|
|
2843
|
+
subprocess.kill();
|
|
2844
|
+
} });
|
|
2845
|
+
const result = await subprocess;
|
|
2846
|
+
if (unsupportedPrompt) {
|
|
2847
|
+
registrySpinner.fail();
|
|
2848
|
+
logger.error(`shadcn asked a question that bejamas add cannot answer: "${unsupportedPrompt}"`);
|
|
2849
|
+
writeCapturedShadcnOutput(result.stdout || "", result.stderr || "");
|
|
2850
|
+
throw new InstallFailure(1);
|
|
2851
|
+
}
|
|
2511
2852
|
registrySpinner.succeed();
|
|
2512
2853
|
spinner("Installing components.", { silent: isSilent }).succeed();
|
|
2513
2854
|
const stdout = result.stdout || "";
|
|
@@ -2524,13 +2865,14 @@ async function addComponents(cwd, packages, forwardedOptions, isVerbose, isSilen
|
|
|
2524
2865
|
} : parseShadcnOutput(stdout, stderr);
|
|
2525
2866
|
if (result.exitCode !== 0) {
|
|
2526
2867
|
if (!inspectionMode) writeCapturedShadcnOutput(stdout, stderr);
|
|
2527
|
-
|
|
2868
|
+
throw new InstallFailure(result.exitCode ?? 1);
|
|
2528
2869
|
}
|
|
2529
2870
|
return parsed;
|
|
2530
|
-
} catch {
|
|
2871
|
+
} catch (error) {
|
|
2872
|
+
if (error instanceof InstallFailure) throw error;
|
|
2531
2873
|
registrySpinner.fail();
|
|
2532
2874
|
logger.error("Failed to add components");
|
|
2533
|
-
|
|
2875
|
+
throw new InstallFailure(1);
|
|
2534
2876
|
}
|
|
2535
2877
|
}
|
|
2536
2878
|
function buildShadcnAddArgs(packages, forwardedOptions) {
|
|
@@ -2552,13 +2894,13 @@ const add = new Command().name("add").description("Add components via the Bejama
|
|
|
2552
2894
|
const overwriteUsed = forwardedOptions.includes("--overwrite") || forwardedOptions.includes("-o");
|
|
2553
2895
|
const cwd = opts.cwd || process.cwd();
|
|
2554
2896
|
let componentsToAdd = packages || [];
|
|
2555
|
-
const
|
|
2897
|
+
const expandsAll = Boolean(opts.all) && componentsToAdd.length === 0;
|
|
2556
2898
|
const isSilent = opts.silent || false;
|
|
2557
2899
|
const registryUrl = resolveRegistryUrl();
|
|
2558
|
-
if (
|
|
2900
|
+
if (expandsAll) {
|
|
2559
2901
|
const fetchingSpinner = spinner("Fetching available components.", { silent: isSilent }).start();
|
|
2560
2902
|
try {
|
|
2561
|
-
componentsToAdd = (await fetchAvailableComponents(registryUrl)).filter(
|
|
2903
|
+
componentsToAdd = (await fetchAvailableComponents(registryUrl)).filter(isUiRegistryItem).map((component) => component.name);
|
|
2562
2904
|
fetchingSpinner.succeed();
|
|
2563
2905
|
} catch {
|
|
2564
2906
|
fetchingSpinner.fail();
|
|
@@ -2588,54 +2930,60 @@ const add = new Command().name("add").description("Add components via the Bejama
|
|
|
2588
2930
|
}
|
|
2589
2931
|
const activeStyle = uiConfig?.style || config?.style || "bejamas-juno";
|
|
2590
2932
|
const totalComponents = componentsToAdd.length;
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
const nextFont = toManagedAstroFont(registryItem.name);
|
|
2608
|
-
if (nextFont) {
|
|
2609
|
-
await syncAstroFontsInProject(cwd, mergeManagedAstroFonts(await readManagedAstroFontsFromProject(cwd), nextFont), nextFont.cssVariable);
|
|
2610
|
-
await syncAstroManagedFontCss(cwd, nextFont.cssVariable);
|
|
2611
|
-
await cleanupAstroFontPackages(cwd);
|
|
2612
|
-
}
|
|
2613
|
-
}
|
|
2614
|
-
}
|
|
2615
|
-
let skippedCount = 0;
|
|
2616
|
-
if (!inspectionMode && uiDir && subfolderMapResult.requiresReorganization) skippedCount = (await reorganizeComponents([component], uiDir, registryUrl, verbose, activeStyle)).skippedFiles.length;
|
|
2617
|
-
if (!isSilent && !inspectionMode) {
|
|
2618
|
-
const actuallyCreated = Math.max(0, parsed.created.length - skippedCount);
|
|
2619
|
-
if (actuallyCreated > 0) {
|
|
2620
|
-
const createdPaths = rewritePaths(parsed.created.slice(0, actuallyCreated), subfolderMapResult);
|
|
2621
|
-
logger.success(`Created ${createdPaths.length} file${createdPaths.length > 1 ? "s" : ""}:`);
|
|
2622
|
-
for (const file of createdPaths) logger.log(` ${highlighter.info("-")} ${file}`);
|
|
2623
|
-
}
|
|
2624
|
-
if (parsed.updated.length > 0) {
|
|
2625
|
-
const updatedPaths = rewritePaths(Array.from(new Set(parsed.updated)), subfolderMapResult);
|
|
2626
|
-
logger.info(`Updated ${updatedPaths.length} file${updatedPaths.length > 1 ? "s" : ""}:`);
|
|
2627
|
-
for (const file of updatedPaths) logger.log(` ${highlighter.info("-")} ${file}`);
|
|
2933
|
+
const outputBearingOptions = withoutShadcnSilentOption(forwardedOptions);
|
|
2934
|
+
const addOptions = expandsAll ? withoutExpandedAllOption(outputBearingOptions) : outputBearingOptions;
|
|
2935
|
+
const batch = new RegistryInstallBatch({
|
|
2936
|
+
cwd,
|
|
2937
|
+
config,
|
|
2938
|
+
uiConfig,
|
|
2939
|
+
uiDir,
|
|
2940
|
+
verbose,
|
|
2941
|
+
overwrite: overwriteUsed
|
|
2942
|
+
});
|
|
2943
|
+
try {
|
|
2944
|
+
for (let index = 0; index < componentsToAdd.length; index += 1) {
|
|
2945
|
+
const component = componentsToAdd[index];
|
|
2946
|
+
if (totalComponents > 1 && !isSilent) {
|
|
2947
|
+
logger.break();
|
|
2948
|
+
logger.info(highlighter.info(`[${index + 1}/${totalComponents}]`) + ` Adding ${highlighter.success(component)}...`);
|
|
2628
2949
|
}
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2950
|
+
const items = inspectionMode ? [] : await fetchRegistryTree([component], registryUrl, activeStyle);
|
|
2951
|
+
const subfolderMapResult = buildSubfolderMap(items);
|
|
2952
|
+
const parsed = await addComponents(cwd, [toShadcnAddArgument(component)], addOptions, verbose, isSilent, inspectionMode);
|
|
2953
|
+
if (inspectionMode) continue;
|
|
2954
|
+
const { skippedFiles } = await batch.install({
|
|
2955
|
+
items,
|
|
2956
|
+
writtenFiles: [...parsed.created, ...parsed.updated],
|
|
2957
|
+
skippedFiles: parsed.skipped
|
|
2958
|
+
});
|
|
2959
|
+
const skippedCount = skippedFiles.length;
|
|
2960
|
+
if (!isSilent) {
|
|
2961
|
+
const actuallyCreated = Math.max(0, parsed.created.length - skippedCount);
|
|
2962
|
+
if (actuallyCreated > 0) {
|
|
2963
|
+
const createdPaths = rewritePaths(parsed.created.slice(0, actuallyCreated), subfolderMapResult);
|
|
2964
|
+
logger.success(`Created ${createdPaths.length} file${createdPaths.length > 1 ? "s" : ""}:`);
|
|
2965
|
+
for (const file of createdPaths) logger.log(` ${highlighter.info("-")} ${file}`);
|
|
2966
|
+
}
|
|
2967
|
+
if (parsed.updated.length > 0) {
|
|
2968
|
+
const updatedPaths = rewritePaths(Array.from(new Set(parsed.updated)), subfolderMapResult);
|
|
2969
|
+
logger.info(`Updated ${updatedPaths.length} file${updatedPaths.length > 1 ? "s" : ""}:`);
|
|
2970
|
+
for (const file of updatedPaths) logger.log(` ${highlighter.info("-")} ${file}`);
|
|
2971
|
+
}
|
|
2972
|
+
if (skippedCount > 0) logger.info(`Skipped ${skippedCount} file${skippedCount > 1 ? "s" : ""}: (already exists)`);
|
|
2973
|
+
if (parsed.skipped.length > 0) {
|
|
2974
|
+
const skippedPaths = rewritePaths(parsed.skipped, subfolderMapResult);
|
|
2975
|
+
logger.info(formatSkippedFilesHeading(skippedPaths.length, overwriteUsed));
|
|
2976
|
+
for (const file of skippedPaths) logger.log(` ${highlighter.info("-")} ${file}`);
|
|
2977
|
+
}
|
|
2978
|
+
if (actuallyCreated === 0 && parsed.updated.length === 0 && skippedCount === 0 && parsed.skipped.length === 0) logger.info("Already up to date.");
|
|
2634
2979
|
}
|
|
2635
|
-
if (actuallyCreated === 0 && parsed.updated.length === 0 && skippedCount === 0 && parsed.skipped.length === 0) logger.info("Already up to date.");
|
|
2636
2980
|
}
|
|
2981
|
+
} catch (error) {
|
|
2982
|
+
await batch.finish();
|
|
2983
|
+
if (error instanceof InstallFailure) process.exit(error.exitCode);
|
|
2984
|
+
throw error;
|
|
2637
2985
|
}
|
|
2638
|
-
|
|
2986
|
+
await batch.finish();
|
|
2639
2987
|
});
|
|
2640
2988
|
|
|
2641
2989
|
//#endregion
|
|
@@ -2802,14 +3150,14 @@ const apply = new Command().name("apply").description("apply a preset to an exis
|
|
|
2802
3150
|
only: explicitOnly
|
|
2803
3151
|
});
|
|
2804
3152
|
const preflight = await preFlightApply(options);
|
|
2805
|
-
if (preflight.errors[
|
|
3153
|
+
if (preflight.errors["1"]) {
|
|
2806
3154
|
logger.break();
|
|
2807
3155
|
logger.error(`The ${highlighter.info("apply")} command only works in an existing project.`);
|
|
2808
3156
|
logger.error(`Run ${highlighter.info(getInitCommand(rawPreset))} first.`);
|
|
2809
3157
|
logger.break();
|
|
2810
3158
|
process.exit(1);
|
|
2811
3159
|
}
|
|
2812
|
-
if (preflight.errors[
|
|
3160
|
+
if (preflight.errors["3"]) {
|
|
2813
3161
|
logger.break();
|
|
2814
3162
|
logger.error(`No ${highlighter.info("components.json")} found at ${highlighter.info(options.cwd)}.`);
|
|
2815
3163
|
logger.error(`Run ${highlighter.info(getInitCommand(rawPreset))} first.`);
|
|
@@ -2890,9 +3238,9 @@ function resolveApplyPreset(options) {
|
|
|
2890
3238
|
if (positionalPreset && flagPreset && positionalPreset !== flagPreset) throw new ApplyPresetError(`Received two different preset values. Use either the positional preset or ${highlighter.info("--preset")}, or pass the same value to both.`);
|
|
2891
3239
|
return flagPreset ?? positionalPreset;
|
|
2892
3240
|
}
|
|
2893
|
-
function getPresetUrlOnly(preset
|
|
2894
|
-
if (!isUrl(preset
|
|
2895
|
-
return new URL(preset
|
|
3241
|
+
function getPresetUrlOnly(preset) {
|
|
3242
|
+
if (!isUrl(preset)) return;
|
|
3243
|
+
return new URL(preset).searchParams.get("only") ?? void 0;
|
|
2896
3244
|
}
|
|
2897
3245
|
function resolveApplyOnly(value) {
|
|
2898
3246
|
if (value === void 0 || value === false) return;
|
|
@@ -2922,27 +3270,27 @@ function validateApplyOnlyPreset(options) {
|
|
|
2922
3270
|
if (!options.only || options.preset) return;
|
|
2923
3271
|
throw new ApplyOnlyError(["Missing preset for --only.", "Use: bejamas apply <preset> --only theme,font."].join("\n"));
|
|
2924
3272
|
}
|
|
2925
|
-
function resolveApplyPresetSource(preset
|
|
2926
|
-
if (isPresetCode(preset
|
|
2927
|
-
validatePresetCode(preset
|
|
2928
|
-
return { preset
|
|
3273
|
+
function resolveApplyPresetSource(preset) {
|
|
3274
|
+
if (isPresetCode(preset)) {
|
|
3275
|
+
validatePresetCode(preset);
|
|
3276
|
+
return { preset };
|
|
2929
3277
|
}
|
|
2930
|
-
if (!isUrl(preset
|
|
2931
|
-
const url
|
|
2932
|
-
if (!isSupportedPresetUrl(url
|
|
2933
|
-
const code = url
|
|
2934
|
-
if (!code) throw new ApplyPresetError(`Invalid preset URL: ${highlighter.info(preset
|
|
3278
|
+
if (!isUrl(preset)) throw new ApplyPresetError(`Invalid preset: ${highlighter.info(preset)}. Use a preset code or a Bejamas create/init URL containing a preset code.`);
|
|
3279
|
+
const url = new URL(preset);
|
|
3280
|
+
if (!isSupportedPresetUrl(url)) throw new ApplyPresetError(`Invalid preset URL: ${highlighter.info(preset)}. Use a Bejamas create or init URL containing a preset code.`);
|
|
3281
|
+
const code = url.searchParams.get("preset")?.trim();
|
|
3282
|
+
if (!code) throw new ApplyPresetError(`Invalid preset URL: ${highlighter.info(preset)}. Expected a URL containing a preset query parameter.`);
|
|
2935
3283
|
validatePresetCode(code);
|
|
2936
3284
|
return {
|
|
2937
3285
|
preset: code,
|
|
2938
|
-
themeRef: url
|
|
2939
|
-
only: url
|
|
3286
|
+
themeRef: url.searchParams.get("themeRef") ?? void 0,
|
|
3287
|
+
only: url.searchParams.get("only") ?? void 0
|
|
2940
3288
|
};
|
|
2941
3289
|
}
|
|
2942
3290
|
async function preFlightApply(options) {
|
|
2943
3291
|
const errors = {};
|
|
2944
3292
|
if (!fs.existsSync(options.cwd) || !fs.existsSync(path.resolve(options.cwd, "package.json"))) {
|
|
2945
|
-
errors[
|
|
3293
|
+
errors["1"] = true;
|
|
2946
3294
|
return {
|
|
2947
3295
|
errors,
|
|
2948
3296
|
config: null
|
|
@@ -2964,7 +3312,7 @@ async function preFlightApply(options) {
|
|
|
2964
3312
|
process.exit(1);
|
|
2965
3313
|
}
|
|
2966
3314
|
}
|
|
2967
|
-
errors[
|
|
3315
|
+
errors["3"] = true;
|
|
2968
3316
|
return {
|
|
2969
3317
|
errors,
|
|
2970
3318
|
config: null
|
|
@@ -3015,28 +3363,29 @@ async function confirmApply(options) {
|
|
|
3015
3363
|
process.exit(1);
|
|
3016
3364
|
}
|
|
3017
3365
|
}
|
|
3018
|
-
async function runPartialApply(cwd, designConfig, preset
|
|
3366
|
+
async function runPartialApply(cwd, designConfig, preset, only) {
|
|
3019
3367
|
if (only.includes("theme")) {
|
|
3020
|
-
const initUrl = buildInitUrl(designConfig, preset
|
|
3021
|
-
|
|
3368
|
+
const initUrl = buildInitUrl(designConfig, preset.themeRef);
|
|
3369
|
+
const themeVars = preset.themeRef ? await fetchInitThemeVars(initUrl) ?? void 0 : void 0;
|
|
3370
|
+
await applyDesignSystemThemeToProject(cwd, designConfig, { themeVars });
|
|
3022
3371
|
await fixAstroImports(cwd, false);
|
|
3023
3372
|
}
|
|
3024
3373
|
if (only.includes("font")) await applyDesignSystemFontToProject(cwd, designConfig);
|
|
3025
3374
|
}
|
|
3026
|
-
function resolveApplyDesignSystemConfig(preset
|
|
3375
|
+
function resolveApplyDesignSystemConfig(preset, existingConfig) {
|
|
3027
3376
|
return resolveDesignSystemConfig({
|
|
3028
|
-
preset: preset
|
|
3377
|
+
preset: preset.preset,
|
|
3029
3378
|
template: "astro",
|
|
3030
3379
|
rtl: existingConfig.rtl ?? false,
|
|
3031
3380
|
baseColor: void 0,
|
|
3032
3381
|
lang: void 0
|
|
3033
3382
|
});
|
|
3034
3383
|
}
|
|
3035
|
-
function validatePresetCode(preset
|
|
3036
|
-
if (!isPresetCode(preset
|
|
3384
|
+
function validatePresetCode(preset) {
|
|
3385
|
+
if (!isPresetCode(preset) || !decodePreset(preset)) throw new ApplyPresetError(`Invalid preset code: ${highlighter.info(preset)}.`);
|
|
3037
3386
|
}
|
|
3038
3387
|
async function getApplyConfigPaths(config) {
|
|
3039
|
-
const configPaths = new Set([path.resolve(config.resolvedPaths.cwd, "components.json")]);
|
|
3388
|
+
const configPaths = /* @__PURE__ */ new Set([path.resolve(config.resolvedPaths.cwd, "components.json")]);
|
|
3040
3389
|
const workspaceConfig = await getWorkspaceConfig(config);
|
|
3041
3390
|
if (workspaceConfig) for (const linkedConfig of Object.values(workspaceConfig)) configPaths.add(path.resolve(linkedConfig.resolvedPaths.cwd, "components.json"));
|
|
3042
3391
|
const existingPaths = [];
|
|
@@ -3110,9 +3459,9 @@ async function getApplyWorkspaceConfigs(config) {
|
|
|
3110
3459
|
function quoteShellArg(value) {
|
|
3111
3460
|
return /[^A-Za-z0-9_./:-]/.test(value) ? JSON.stringify(value) : value;
|
|
3112
3461
|
}
|
|
3113
|
-
function getInitCommand(preset
|
|
3114
|
-
if (!preset
|
|
3115
|
-
return `bejamas init --preset ${quoteShellArg(preset
|
|
3462
|
+
function getInitCommand(preset) {
|
|
3463
|
+
if (!preset) return "bejamas init";
|
|
3464
|
+
return `bejamas init --preset ${quoteShellArg(preset)}`;
|
|
3116
3465
|
}
|
|
3117
3466
|
function isUrl(value) {
|
|
3118
3467
|
try {
|
|
@@ -3122,8 +3471,8 @@ function isUrl(value) {
|
|
|
3122
3471
|
return false;
|
|
3123
3472
|
}
|
|
3124
3473
|
}
|
|
3125
|
-
function isSupportedPresetUrl(url
|
|
3126
|
-
const pathname = url
|
|
3474
|
+
function isSupportedPresetUrl(url) {
|
|
3475
|
+
const pathname = url.pathname.replace(/\/+$/, "");
|
|
3127
3476
|
return pathname === "/create" || pathname === "/init";
|
|
3128
3477
|
}
|
|
3129
3478
|
|
|
@@ -3159,13 +3508,14 @@ const PRESET_ICON_LIBRARY_SET = new Set(PRESET_ICON_LIBRARIES);
|
|
|
3159
3508
|
const PRESET_MENU_ACCENT_SET = new Set(PRESET_MENU_ACCENTS);
|
|
3160
3509
|
const PRESET_MENU_COLOR_SET = new Set(PRESET_MENU_COLORS);
|
|
3161
3510
|
const PRESET_STYLE_SET = new Set(PRESET_STYLES);
|
|
3511
|
+
new Set(PRESET_THEMES);
|
|
3162
3512
|
const ROOT_FONT_VARIABLES = [
|
|
3163
3513
|
"--font-sans",
|
|
3164
3514
|
"--font-serif",
|
|
3165
3515
|
"--font-mono"
|
|
3166
3516
|
];
|
|
3167
3517
|
const ROOT_FONT_VARIABLE_SET = new Set(ROOT_FONT_VARIABLES);
|
|
3168
|
-
const FONT_VARIABLE_SET = new Set([...ROOT_FONT_VARIABLES, "--font-heading"]);
|
|
3518
|
+
const FONT_VARIABLE_SET = /* @__PURE__ */ new Set([...ROOT_FONT_VARIABLES, "--font-heading"]);
|
|
3169
3519
|
async function resolveProjectPreset(config) {
|
|
3170
3520
|
const style = normalizePresetStyle(config.style);
|
|
3171
3521
|
if (!style) return {
|
|
@@ -3463,31 +3813,31 @@ function printPresetDecode(result) {
|
|
|
3463
3813
|
values: result.values
|
|
3464
3814
|
}, { fallbackNote: " * Compatibility value for older preset versions." });
|
|
3465
3815
|
}
|
|
3466
|
-
function printPresetInfo(preset
|
|
3816
|
+
function printPresetInfo(preset, options = {}) {
|
|
3467
3817
|
logger.log(highlighter.info("Preset"));
|
|
3468
|
-
if (!preset
|
|
3818
|
+
if (!preset.code || !preset.values) {
|
|
3469
3819
|
printEntries({ code: "-" });
|
|
3470
3820
|
return;
|
|
3471
3821
|
}
|
|
3472
|
-
const fallbacks = preset
|
|
3822
|
+
const fallbacks = preset.fallbacks ?? [];
|
|
3473
3823
|
const formatPresetValue = (key, value) => {
|
|
3474
3824
|
const suffix = fallbacks.includes(key) ? "*" : "";
|
|
3475
3825
|
return `${value ?? "-"}${suffix}`;
|
|
3476
3826
|
};
|
|
3477
3827
|
printEntries({
|
|
3478
|
-
code: preset
|
|
3479
|
-
version: preset
|
|
3480
|
-
style: preset
|
|
3481
|
-
baseColor: formatPresetValue("baseColor", preset
|
|
3482
|
-
theme: formatPresetValue("theme", preset
|
|
3483
|
-
chartColor: formatPresetValue("chartColor", preset
|
|
3484
|
-
iconLibrary: formatPresetValue("iconLibrary", preset
|
|
3485
|
-
font: formatPresetValue("font", preset
|
|
3486
|
-
fontHeading: formatPresetValue("fontHeading", preset
|
|
3487
|
-
radius: formatPresetValue("radius", preset
|
|
3488
|
-
menuAccent: formatPresetValue("menuAccent", preset
|
|
3489
|
-
menuColor: formatPresetValue("menuColor", preset
|
|
3490
|
-
url: getPresetUrl(preset
|
|
3828
|
+
code: preset.code,
|
|
3829
|
+
version: preset.code[0],
|
|
3830
|
+
style: preset.values.style,
|
|
3831
|
+
baseColor: formatPresetValue("baseColor", preset.values.baseColor),
|
|
3832
|
+
theme: formatPresetValue("theme", preset.values.theme),
|
|
3833
|
+
chartColor: formatPresetValue("chartColor", preset.values.chartColor),
|
|
3834
|
+
iconLibrary: formatPresetValue("iconLibrary", preset.values.iconLibrary),
|
|
3835
|
+
font: formatPresetValue("font", preset.values.font),
|
|
3836
|
+
fontHeading: formatPresetValue("fontHeading", preset.values.fontHeading),
|
|
3837
|
+
radius: formatPresetValue("radius", preset.values.radius),
|
|
3838
|
+
menuAccent: formatPresetValue("menuAccent", preset.values.menuAccent),
|
|
3839
|
+
menuColor: formatPresetValue("menuColor", preset.values.menuColor),
|
|
3840
|
+
url: getPresetUrl(preset.code)
|
|
3491
3841
|
});
|
|
3492
3842
|
if (fallbacks.length > 0) {
|
|
3493
3843
|
logger.log("");
|
|
@@ -3600,8 +3950,7 @@ program.addCommand(docs);
|
|
|
3600
3950
|
program.addCommand(docsBuild);
|
|
3601
3951
|
program.addCommand(docsCheck);
|
|
3602
3952
|
program.parse(process.argv);
|
|
3603
|
-
var src_default = program;
|
|
3604
3953
|
|
|
3605
3954
|
//#endregion
|
|
3606
|
-
export {
|
|
3955
|
+
export { program as default };
|
|
3607
3956
|
//# sourceMappingURL=index.js.map
|