bejamas 0.0.0-canary.0cf9645

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,783 @@
1
+ #!/usr/bin/env node
2
+ import { highlighter, logger, spinner } from "./spinner-9iMQF079.js";
3
+ import { Command } from "commander";
4
+ import { createRequire } from "module";
5
+ import path from "path";
6
+ import fsExtra from "fs-extra";
7
+ import os from "os";
8
+ import dotenv from "dotenv";
9
+ import { detect } from "@antfu/ni";
10
+ import { z } from "zod";
11
+ import { execa } from "execa";
12
+ import prompts from "prompts";
13
+ import { configSchema, rawConfigSchema } from "shadcn/schema";
14
+ import fg from "fast-glob";
15
+ import { createMatchPath, loadConfig } from "tsconfig-paths";
16
+ import { cosmiconfig } from "cosmiconfig";
17
+ import { dirname as dirname$1, isAbsolute, relative as relative$1, resolve } from "node:path";
18
+ import { existsSync, readFileSync } from "node:fs";
19
+ import { fileURLToPath } from "node:url";
20
+
21
+ //#region src/utils/errors.ts
22
+ const MISSING_DIR_OR_EMPTY_PROJECT = "1";
23
+
24
+ //#endregion
25
+ //#region src/preflights/preflight-init.ts
26
+ async function preFlightInit(options) {
27
+ const errors = {};
28
+ if (!fsExtra.existsSync(options.cwd) || !fsExtra.existsSync(path.resolve(options.cwd, "package.json"))) {
29
+ errors[MISSING_DIR_OR_EMPTY_PROJECT] = true;
30
+ return {
31
+ errors,
32
+ projectInfo: null
33
+ };
34
+ }
35
+ return {
36
+ errors,
37
+ projectInfo: null
38
+ };
39
+ }
40
+
41
+ //#endregion
42
+ //#region src/registry/constants.ts
43
+ const REGISTRY_URL = process.env.REGISTRY_URL ?? "http://localhost:4321/r";
44
+ const BASE_COLORS = [
45
+ {
46
+ name: "neutral",
47
+ label: "Neutral"
48
+ },
49
+ {
50
+ name: "gray",
51
+ label: "Gray"
52
+ },
53
+ {
54
+ name: "zinc",
55
+ label: "Zinc"
56
+ },
57
+ {
58
+ name: "stone",
59
+ label: "Stone"
60
+ },
61
+ {
62
+ name: "slate",
63
+ label: "Slate"
64
+ }
65
+ ];
66
+ const BUILTIN_REGISTRIES = { "@bejamas": `${REGISTRY_URL}/{name}.json` };
67
+
68
+ //#endregion
69
+ //#region src/registry/context.ts
70
+ let context = { headers: {} };
71
+ function clearRegistryContext() {
72
+ context.headers = {};
73
+ }
74
+
75
+ //#endregion
76
+ //#region src/utils/get-package-manager.ts
77
+ async function getPackageManager(targetDir, { withFallback } = { withFallback: false }) {
78
+ const packageManager = await detect({
79
+ programmatic: true,
80
+ cwd: targetDir
81
+ });
82
+ if (packageManager === "yarn@berry") return "yarn";
83
+ if (packageManager === "pnpm@6") return "pnpm";
84
+ if (packageManager === "bun") return "bun";
85
+ if (packageManager === "deno") return "deno";
86
+ if (!withFallback) return packageManager ?? "npm";
87
+ const userAgent = process.env.npm_config_user_agent || "";
88
+ if (userAgent.startsWith("yarn")) return "yarn";
89
+ if (userAgent.startsWith("pnpm")) return "pnpm";
90
+ if (userAgent.startsWith("bun")) return "bun";
91
+ return "npm";
92
+ }
93
+ async function getPackageRunner(cwd) {
94
+ const packageManager = await getPackageManager(cwd);
95
+ if (packageManager === "pnpm") return "pnpm dlx";
96
+ if (packageManager === "bun") return "bunx";
97
+ return "npx";
98
+ }
99
+
100
+ //#endregion
101
+ //#region src/registry/errors.ts
102
+ const RegistryErrorCode = {
103
+ NETWORK_ERROR: "NETWORK_ERROR",
104
+ NOT_FOUND: "NOT_FOUND",
105
+ UNAUTHORIZED: "UNAUTHORIZED",
106
+ FORBIDDEN: "FORBIDDEN",
107
+ FETCH_ERROR: "FETCH_ERROR",
108
+ NOT_CONFIGURED: "NOT_CONFIGURED",
109
+ INVALID_CONFIG: "INVALID_CONFIG",
110
+ MISSING_ENV_VARS: "MISSING_ENV_VARS",
111
+ LOCAL_FILE_ERROR: "LOCAL_FILE_ERROR",
112
+ PARSE_ERROR: "PARSE_ERROR",
113
+ VALIDATION_ERROR: "VALIDATION_ERROR",
114
+ UNKNOWN_ERROR: "UNKNOWN_ERROR"
115
+ };
116
+ var RegistryError = class extends Error {
117
+ constructor(message, options = {}) {
118
+ super(message);
119
+ this.name = "RegistryError";
120
+ this.code = options.code || RegistryErrorCode.UNKNOWN_ERROR;
121
+ this.statusCode = options.statusCode;
122
+ this.cause = options.cause;
123
+ this.context = options.context;
124
+ this.suggestion = options.suggestion;
125
+ this.timestamp = /* @__PURE__ */ new Date();
126
+ if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
127
+ }
128
+ toJSON() {
129
+ return {
130
+ name: this.name,
131
+ message: this.message,
132
+ code: this.code,
133
+ statusCode: this.statusCode,
134
+ context: this.context,
135
+ suggestion: this.suggestion,
136
+ timestamp: this.timestamp,
137
+ stack: this.stack
138
+ };
139
+ }
140
+ };
141
+
142
+ //#endregion
143
+ //#region src/utils/handle-error.ts
144
+ function handleError(error) {
145
+ logger.break();
146
+ logger.error(`Something went wrong. Please check the error below for more details.`);
147
+ logger.error(`If the problem persists, please open an issue on GitHub: https://github.com/bejamas/ui/issues`);
148
+ logger.error("");
149
+ if (typeof error === "string") {
150
+ logger.error(error);
151
+ logger.break();
152
+ process.exit(1);
153
+ }
154
+ if (error instanceof RegistryError) {
155
+ if (error.message) {
156
+ logger.error(error.cause ? "Error:" : "Message:");
157
+ logger.error(error.message);
158
+ }
159
+ if (error.cause) {
160
+ logger.error("\nMessage:");
161
+ logger.error(error.cause);
162
+ }
163
+ if (error.suggestion) {
164
+ logger.error("\nSuggestion:");
165
+ logger.error(error.suggestion);
166
+ }
167
+ logger.break();
168
+ process.exit(1);
169
+ }
170
+ if (error instanceof z.ZodError) {
171
+ logger.error("Validation failed:");
172
+ for (const [key, value] of Object.entries(error.flatten().fieldErrors)) logger.error(`- ${highlighter.info(key)}: ${value}`);
173
+ logger.break();
174
+ process.exit(1);
175
+ }
176
+ if (error instanceof Error) {
177
+ logger.error(error.message);
178
+ logger.break();
179
+ process.exit(1);
180
+ }
181
+ logger.break();
182
+ process.exit(1);
183
+ }
184
+
185
+ //#endregion
186
+ //#region src/utils/create-project.ts
187
+ const TEMPLATES = {
188
+ astro: "astro",
189
+ "astro-monorepo": "astro-monorepo",
190
+ "astro-with-component-docs-monorepo": "astro-with-component-docs-monorepo"
191
+ };
192
+ const MONOREPO_TEMPLATE_URL = "https://codeload.github.com/bejamas/ui/tar.gz/main";
193
+ async function createProject(options) {
194
+ options = {
195
+ srcDir: false,
196
+ ...options
197
+ };
198
+ let template = options.template && TEMPLATES[options.template] ? options.template : "astro";
199
+ let projectName = "my-app";
200
+ const isRemoteComponent = options.components?.length === 1 && !!options.components[0].match(/\/chat\/b\//);
201
+ if (!options.force) {
202
+ const { type, name } = await prompts([{
203
+ type: options.template || isRemoteComponent ? null : "select",
204
+ name: "type",
205
+ message: `The path ${highlighter.info(options.cwd)} does not contain a package.json file.\n Would you like to start a new project?`,
206
+ choices: [
207
+ {
208
+ title: "Astro",
209
+ value: "astro"
210
+ },
211
+ {
212
+ title: "Astro (Monorepo)",
213
+ value: "astro-monorepo"
214
+ },
215
+ {
216
+ title: "Astro with Component Docs (Monorepo)",
217
+ value: "astro-with-component-docs-monorepo"
218
+ }
219
+ ],
220
+ initial: 0
221
+ }, {
222
+ type: "text",
223
+ name: "name",
224
+ message: "What is your project named?",
225
+ initial: (_prev, values) => {
226
+ return (options.template && TEMPLATES[options.template] && options.template || values.type || template)?.endsWith("monorepo") ? "my-monorepo" : "my-app";
227
+ },
228
+ format: (value) => value.trim(),
229
+ validate: (value) => value.length > 128 ? `Name should be less than 128 characters.` : true
230
+ }]);
231
+ template = type ?? template;
232
+ projectName = name;
233
+ }
234
+ const packageManager = await getPackageManager(options.cwd, { withFallback: true });
235
+ const projectPath = `${options.cwd}/${projectName}`;
236
+ try {
237
+ await fsExtra.access(options.cwd, fsExtra.constants.W_OK);
238
+ } catch (error) {
239
+ logger.break();
240
+ logger.error(`The path ${highlighter.info(options.cwd)} is not writable.`);
241
+ logger.error(`It is likely you do not have write permissions for this folder or the path ${highlighter.info(options.cwd)} does not exist.`);
242
+ logger.break();
243
+ process.exit(1);
244
+ }
245
+ if (fsExtra.existsSync(path.resolve(options.cwd, projectName, "package.json"))) {
246
+ logger.break();
247
+ logger.error(`A project with the name ${highlighter.info(projectName)} already exists.`);
248
+ logger.error(`Please choose a different name and try again.`);
249
+ logger.break();
250
+ process.exit(1);
251
+ }
252
+ await createProjectFromTemplate(projectPath, {
253
+ templateKey: template,
254
+ packageManager,
255
+ cwd: options.cwd
256
+ });
257
+ return {
258
+ projectPath,
259
+ projectName,
260
+ template
261
+ };
262
+ }
263
+ async function createProjectFromTemplate(projectPath, options) {
264
+ const createSpinner = spinner(`Creating a new project from template. This may take a few minutes.`).start();
265
+ const TEMPLATE_TAR_SUBPATH = {
266
+ astro: "ui-main/templates/astro",
267
+ "astro-monorepo": "ui-main/templates/monorepo-astro",
268
+ "astro-with-component-docs-monorepo": "ui-main/templates/monorepo-astro-with-docs"
269
+ };
270
+ try {
271
+ dotenv.config({ quiet: true });
272
+ const templatePath = path.join(os.tmpdir(), `bejamas-template-${Date.now()}`);
273
+ await fsExtra.ensureDir(templatePath);
274
+ const authToken = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
275
+ const usedAuth = Boolean(authToken);
276
+ const headers = { "User-Agent": "bejamas-cli" };
277
+ if (authToken) headers["Authorization"] = `Bearer ${authToken}`;
278
+ const response = await fetch(MONOREPO_TEMPLATE_URL, { headers });
279
+ if (!response.ok) {
280
+ if (response.status === 401 || response.status === 403 || !usedAuth && response.status === 404) throw new Error("Unauthorized to access private template. Set GITHUB_TOKEN or GH_TOKEN (in .env or env) with repo access and try again.");
281
+ if (response.status === 404) throw new Error("Failed to download template: not found.");
282
+ throw new Error(`Failed to download template: ${response.status} ${response.statusText}`);
283
+ }
284
+ const tarPath = path.resolve(templatePath, "template.tar.gz");
285
+ await fsExtra.writeFile(tarPath, Buffer.from(await response.arrayBuffer()));
286
+ const tarSubpath = TEMPLATE_TAR_SUBPATH[options.templateKey];
287
+ const leafName = tarSubpath.split("/").pop();
288
+ await execa("tar", [
289
+ "-xzf",
290
+ tarPath,
291
+ "-C",
292
+ templatePath,
293
+ "--strip-components=2",
294
+ tarSubpath
295
+ ]);
296
+ const extractedPath = path.resolve(templatePath, leafName);
297
+ await fsExtra.move(extractedPath, projectPath);
298
+ await fsExtra.remove(templatePath);
299
+ await execa(options.packageManager, ["install"], { cwd: projectPath });
300
+ try {
301
+ const { stdout } = await execa("git", ["rev-parse", "--is-inside-work-tree"], { cwd: projectPath });
302
+ if (!(stdout.trim() === "true")) {
303
+ await execa("git", ["init"], { cwd: projectPath });
304
+ await execa("git", ["add", "-A"], { cwd: projectPath });
305
+ await execa("git", [
306
+ "commit",
307
+ "-m",
308
+ "Initial commit"
309
+ ], { cwd: projectPath });
310
+ }
311
+ } catch (_) {}
312
+ createSpinner?.succeed("Creating a new project from template.");
313
+ } catch (error) {
314
+ createSpinner?.fail("Something went wrong creating a new project from template.");
315
+ handleError(error);
316
+ }
317
+ }
318
+
319
+ //#endregion
320
+ //#region src/utils/get-package-info.ts
321
+ function getPackageInfo(cwd = "", shouldThrow = true) {
322
+ const packageJsonPath = path.join(cwd, "package.json");
323
+ return fsExtra.readJSONSync(packageJsonPath, { throws: shouldThrow });
324
+ }
325
+
326
+ //#endregion
327
+ //#region src/utils/get-project-info.ts
328
+ const PROJECT_SHARED_IGNORE = [
329
+ "**/node_modules/**",
330
+ ".astro",
331
+ "public",
332
+ "dist",
333
+ "build"
334
+ ];
335
+ const TS_CONFIG_SCHEMA = z.object({ compilerOptions: z.object({ paths: z.record(z.string().or(z.array(z.string()))) }) });
336
+ async function getProjectInfo(cwd) {
337
+ const [configFiles, tailwindConfigFile, tailwindCssFile, tailwindVersion, aliasPrefix, packageJson] = await Promise.all([
338
+ fg.glob("**/{next,vite,astro,app}.config.*|gatsby-config.*|composer.json|react-router.config.*", {
339
+ cwd,
340
+ deep: 3,
341
+ ignore: PROJECT_SHARED_IGNORE
342
+ }),
343
+ getTailwindConfigFile(cwd),
344
+ getTailwindCssFile(cwd),
345
+ getTailwindVersion(cwd),
346
+ getTsConfigAliasPrefix(cwd),
347
+ getPackageInfo(cwd, false)
348
+ ]);
349
+ const type = {
350
+ isAstro: false,
351
+ tailwindConfigFile,
352
+ tailwindCssFile,
353
+ tailwindVersion,
354
+ aliasPrefix
355
+ };
356
+ if (configFiles.find((file) => file.startsWith("astro.config."))?.length) {
357
+ type.isAstro = true;
358
+ return type;
359
+ }
360
+ return type;
361
+ }
362
+ async function getTailwindVersion(cwd) {
363
+ const [packageInfo, config] = await Promise.all([getPackageInfo(cwd, false), getConfig(cwd)]);
364
+ if (config?.tailwind?.config === "") return "v4";
365
+ if (!packageInfo?.dependencies?.tailwindcss && !packageInfo?.devDependencies?.tailwindcss) return null;
366
+ if (/^(?:\^|~)?3(?:\.\d+)*(?:-.*)?$/.test(packageInfo?.dependencies?.tailwindcss || packageInfo?.devDependencies?.tailwindcss || "")) return "v3";
367
+ return "v4";
368
+ }
369
+ async function getTailwindCssFile(cwd) {
370
+ const [files, tailwindVersion] = await Promise.all([fg.glob(["**/*.css", "**/*.scss"], {
371
+ cwd,
372
+ deep: 5,
373
+ ignore: PROJECT_SHARED_IGNORE
374
+ }), getTailwindVersion(cwd)]);
375
+ if (!files.length) return null;
376
+ for (const file of files) {
377
+ const contents = await fsExtra.readFile(path.resolve(cwd, file), "utf8");
378
+ if (contents.includes(`@import "tailwindcss"`) || contents.includes(`@import 'tailwindcss'`) || contents.includes(`@tailwind base`)) return file;
379
+ }
380
+ return null;
381
+ }
382
+ async function getTailwindConfigFile(cwd) {
383
+ const files = await fg.glob("tailwind.config.*", {
384
+ cwd,
385
+ deep: 3,
386
+ ignore: PROJECT_SHARED_IGNORE
387
+ });
388
+ if (!files.length) return null;
389
+ return files[0];
390
+ }
391
+ async function getTsConfigAliasPrefix(cwd) {
392
+ const tsConfig = await loadConfig(cwd);
393
+ if (tsConfig?.resultType === "failed" || !Object.entries(tsConfig?.paths).length) return null;
394
+ for (const [alias, paths] of Object.entries(tsConfig.paths)) if (paths.includes("./*") || paths.includes("./src/*") || paths.includes("./app/*") || paths.includes("./resources/js/*")) return alias.replace(/\/\*$/, "") ?? null;
395
+ return Object.keys(tsConfig?.paths)?.[0].replace(/\/\*$/, "") ?? null;
396
+ }
397
+
398
+ //#endregion
399
+ //#region src/utils/resolve-import.ts
400
+ async function resolveImport(importPath, config) {
401
+ return createMatchPath(config.absoluteBaseUrl, config.paths)(importPath, void 0, () => true, [
402
+ ".ts",
403
+ ".tsx",
404
+ ".jsx",
405
+ ".js",
406
+ ".css"
407
+ ]);
408
+ }
409
+
410
+ //#endregion
411
+ //#region src/utils/get-config.ts
412
+ const explorer = cosmiconfig("components", { searchPlaces: ["components.json"] });
413
+ async function getConfig(cwd) {
414
+ const config = await getRawConfig(cwd);
415
+ if (!config) return null;
416
+ if (!config.iconLibrary) config.iconLibrary = config.style === "new-york" ? "radix" : "lucide";
417
+ return await resolveConfigPaths(cwd, config);
418
+ }
419
+ async function resolveConfigPaths(cwd, config) {
420
+ config.registries = {
421
+ ...BUILTIN_REGISTRIES,
422
+ ...config.registries || {}
423
+ };
424
+ const tsConfig = await loadConfig(cwd);
425
+ if (tsConfig.resultType === "failed") throw new Error(`Failed to load ${config.tsx ? "tsconfig" : "jsconfig"}.json. ${tsConfig.message ?? ""}`.trim());
426
+ return configSchema.parse({
427
+ ...config,
428
+ resolvedPaths: {
429
+ cwd,
430
+ tailwindConfig: config.tailwind.config ? path.resolve(cwd, config.tailwind.config) : "",
431
+ tailwindCss: path.resolve(cwd, config.tailwind.css),
432
+ utils: await resolveImport(config.aliases["utils"], tsConfig),
433
+ components: await resolveImport(config.aliases["components"], tsConfig),
434
+ ui: config.aliases["ui"] ? await resolveImport(config.aliases["ui"], tsConfig) : path.resolve(await resolveImport(config.aliases["components"], tsConfig) ?? cwd, "ui"),
435
+ lib: config.aliases["lib"] ? await resolveImport(config.aliases["lib"], tsConfig) : path.resolve(await resolveImport(config.aliases["utils"], tsConfig) ?? cwd, ".."),
436
+ hooks: config.aliases["hooks"] ? await resolveImport(config.aliases["hooks"], tsConfig) : path.resolve(await resolveImport(config.aliases["components"], tsConfig) ?? cwd, "..", "hooks")
437
+ }
438
+ });
439
+ }
440
+ async function getRawConfig(cwd) {
441
+ try {
442
+ const configResult = await explorer.search(cwd);
443
+ if (!configResult) return null;
444
+ const config = rawConfigSchema.parse(configResult.config);
445
+ if (config.registries) {
446
+ for (const registryName of Object.keys(config.registries)) if (registryName in BUILTIN_REGISTRIES) throw new Error(`"${registryName}" is a built-in registry and cannot be overridden.`);
447
+ }
448
+ return config;
449
+ } catch (error) {
450
+ const componentPath = `${cwd}/components.json`;
451
+ if (error instanceof Error && error.message.includes("reserved registry")) throw error;
452
+ throw new Error(`Invalid configuration found in ${highlighter.info(componentPath)}.`);
453
+ }
454
+ }
455
+
456
+ //#endregion
457
+ //#region src/commands/init.ts
458
+ const initOptionsSchema = z.object({
459
+ cwd: z.string(),
460
+ components: z.array(z.string()).optional(),
461
+ yes: z.boolean(),
462
+ defaults: z.boolean(),
463
+ force: z.boolean(),
464
+ silent: z.boolean(),
465
+ isNewProject: z.boolean(),
466
+ srcDir: z.boolean().optional(),
467
+ cssVariables: z.boolean(),
468
+ template: z.string().optional().refine((val) => {
469
+ if (val) return TEMPLATES[val];
470
+ return true;
471
+ }, { message: "Invalid template. Please use 'next' or 'next-monorepo'." }),
472
+ baseColor: z.string().optional().refine((val) => {
473
+ if (val) return BASE_COLORS.find((color) => color.name === val);
474
+ return true;
475
+ }, { message: `Invalid base color. Please use '${BASE_COLORS.map((color) => color.name).join("', '")}'` }),
476
+ baseStyle: z.boolean()
477
+ });
478
+ const init = new Command().name("init").description("initialize your project and install dependencies").argument("[components...]", "names, url or local path to component").option("-t, --template <template>", "the template to use. (next, next-monorepo)").option("-b, --base-color <base-color>", "the base color to use. (neutral, gray, zinc, stone, slate)", void 0).option("-y, --yes", "skip confirmation prompt.", true).option("-d, --defaults,", "use default configuration.", false).option("-f, --force", "force overwrite of existing configuration.", false).option("-c, --cwd <cwd>", "the working directory. defaults to the current directory.", process.cwd()).option("-s, --silent", "mute output.", false).option("--src-dir", "use the src directory when creating a new project.", false).option("--no-src-dir", "do not use the src directory when creating a new project.").option("--css-variables", "use css variables for theming.", true).option("--no-css-variables", "do not use css variables for theming.").option("--no-base-style", "do not install the base shadcn style.").action(async (_components, opts) => {
479
+ try {
480
+ await runInit(opts);
481
+ } catch (error) {
482
+ logger.break();
483
+ handleError(error);
484
+ } finally {
485
+ clearRegistryContext();
486
+ }
487
+ });
488
+ async function runInit(options) {
489
+ let newProjectTemplate;
490
+ if (!options.skipPreflight) {
491
+ const preflight = await preFlightInit(options);
492
+ if (preflight.errors[MISSING_DIR_OR_EMPTY_PROJECT]) {
493
+ const { projectPath, template } = await createProject(options);
494
+ if (!projectPath) process.exit(1);
495
+ options.cwd = projectPath;
496
+ options.isNewProject = true;
497
+ newProjectTemplate = template;
498
+ }
499
+ preflight.projectInfo;
500
+ } else await getProjectInfo(options.cwd);
501
+ if (newProjectTemplate) {
502
+ options.cwd = path.resolve(options.cwd, {
503
+ "astro-monorepo": "apps/web",
504
+ "astro-with-component-docs-monorepo": "apps/web",
505
+ astro: ""
506
+ }[newProjectTemplate]);
507
+ logger.log(`${highlighter.success("Success!")} Project initialization completed.\nYou may now add components.`);
508
+ return await getConfig(options.cwd);
509
+ }
510
+ const shadcnBin = process.platform === "win32" ? "shadcn.cmd" : "shadcn";
511
+ const localShadcnPath = path.resolve(options.cwd, "node_modules", ".bin", shadcnBin);
512
+ try {
513
+ const env = { ...process.env };
514
+ if (process.env.REGISTRY_URL) env.REGISTRY_URL = process.env.REGISTRY_URL;
515
+ if (await fsExtra.pathExists(localShadcnPath)) await execa(localShadcnPath, [
516
+ "init",
517
+ "--base-color",
518
+ "neutral"
519
+ ], {
520
+ stdio: "inherit",
521
+ cwd: options.cwd,
522
+ env
523
+ });
524
+ else await execa("npx", [
525
+ "-y",
526
+ "shadcn@latest",
527
+ "init",
528
+ "--base-color",
529
+ "neutral"
530
+ ], {
531
+ stdio: "inherit",
532
+ cwd: options.cwd,
533
+ env
534
+ });
535
+ } catch (err) {
536
+ process.exit(1);
537
+ }
538
+ }
539
+
540
+ //#endregion
541
+ //#region src/commands/docs.ts
542
+ const __filename = fileURLToPath(import.meta.url);
543
+ dirname$1(__filename);
544
+ function readTsConfig(projectRoot) {
545
+ try {
546
+ const tsconfigPath = resolve(projectRoot, "tsconfig.json");
547
+ if (!existsSync(tsconfigPath)) return null;
548
+ const raw = readFileSync(tsconfigPath, "utf-8");
549
+ return JSON.parse(raw);
550
+ } catch {
551
+ return null;
552
+ }
553
+ }
554
+ function resolveAliasPathUsingTsConfig(inputPath, projectRoot) {
555
+ const cfg = readTsConfig(projectRoot);
556
+ if (!cfg || !cfg.compilerOptions) return null;
557
+ const baseUrl = cfg.compilerOptions.baseUrl || ".";
558
+ const paths = cfg.compilerOptions.paths || {};
559
+ for (const [key, values] of Object.entries(paths)) {
560
+ const pattern = key.replace(/\*/g, "(.*)");
561
+ const re = /* @__PURE__ */ new RegExp(`^${pattern}$`);
562
+ const match = inputPath.match(re);
563
+ if (!match) continue;
564
+ const wildcard = match[1] || "";
565
+ const first = Array.isArray(values) ? values[0] : values;
566
+ if (!first) continue;
567
+ const target = String(first).replace(/\*/g, wildcard);
568
+ return resolve(projectRoot, baseUrl, target);
569
+ }
570
+ return null;
571
+ }
572
+ async function generateDocs({ cwd, outDir, verbose }) {
573
+ const DEBUG = process.env.BEJAMAS_DEBUG === "1" || process.env.BEJAMAS_DEBUG === "true" || verbose;
574
+ try {
575
+ const shellCwd = process.cwd();
576
+ let projectRoot = shellCwd;
577
+ let probe = shellCwd;
578
+ for (let i = 0; i < 6 && probe; i += 1) {
579
+ const candidate = resolve(probe, "components.json");
580
+ if (existsSync(candidate)) {
581
+ projectRoot = probe;
582
+ try {
583
+ const raw = readFileSync(candidate, "utf-8");
584
+ const config = JSON.parse(raw);
585
+ if (!cwd && !process.env.BEJAMAS_UI_ROOT && config?.aliases?.ui) {
586
+ const mapped = String(config.aliases.ui);
587
+ let uiAbs = null;
588
+ if (mapped.startsWith("./") || mapped.startsWith("../") || isAbsolute(mapped)) uiAbs = resolve(projectRoot, mapped);
589
+ else uiAbs = resolveAliasPathUsingTsConfig(mapped, projectRoot);
590
+ if (!uiAbs && mapped.startsWith("@/")) uiAbs = resolve(projectRoot, "src", mapped.slice(2));
591
+ if (uiAbs) process.env.BEJAMAS_UI_ROOT = uiAbs;
592
+ }
593
+ if (!cwd && !process.env.BEJAMAS_UI_ROOT && config?.tailwind?.css) {
594
+ const cssRaw = String(config.tailwind.css);
595
+ let cssAbs = null;
596
+ if (cssRaw.startsWith("./") || cssRaw.startsWith("../") || isAbsolute(cssRaw)) cssAbs = resolve(projectRoot, cssRaw);
597
+ else cssAbs = resolveAliasPathUsingTsConfig(cssRaw, projectRoot);
598
+ if (!cssAbs && cssRaw.startsWith("@/")) cssAbs = resolve(projectRoot, "src", cssRaw.slice(2));
599
+ if (cssAbs) {
600
+ const uiRootFromCss = resolve(cssAbs, "..", "..", "..");
601
+ process.env.BEJAMAS_UI_ROOT = uiRootFromCss;
602
+ }
603
+ }
604
+ if (!outDir && config?.aliases?.docs) {
605
+ const mapped = String(config.aliases.docs);
606
+ let outResolved = null;
607
+ if (mapped.startsWith("./") || mapped.startsWith("../") || isAbsolute(mapped)) outResolved = mapped;
608
+ else {
609
+ const abs = resolveAliasPathUsingTsConfig(mapped, projectRoot);
610
+ if (abs) outResolved = relative$1(projectRoot, abs);
611
+ }
612
+ if (!outResolved && mapped.startsWith("@/")) outResolved = mapped.replace(/^@\//, "src/");
613
+ const finalOut = outResolved ?? mapped;
614
+ if (finalOut && !process.env.BEJAMAS_DOCS_OUT_DIR) {
615
+ process.env.BEJAMAS_DOCS_OUT_DIR = finalOut;
616
+ process.env.BEJAMAS_DOCS_CWD = projectRoot;
617
+ }
618
+ }
619
+ } catch {}
620
+ break;
621
+ }
622
+ const parent = resolve(probe, "..");
623
+ probe = parent === probe ? null : parent;
624
+ }
625
+ if (!process.env.BEJAMAS_DOCS_CWD) process.env.BEJAMAS_DOCS_CWD = shellCwd;
626
+ if (!process.env.BEJAMAS_UI_ROOT) {
627
+ const defaultGuess = (() => {
628
+ let current = shellCwd;
629
+ for (let i = 0; i < 6; i += 1) {
630
+ const cand = resolve(current, "packages/ui/package.json");
631
+ if (existsSync(cand)) {
632
+ const abs = resolve(current, "packages/ui");
633
+ return relative$1(shellCwd, abs) || abs;
634
+ }
635
+ const parent = resolve(current, "..");
636
+ if (parent === current) break;
637
+ current = parent;
638
+ }
639
+ const nm = resolve(shellCwd, "node_modules/@bejamas/ui/package.json");
640
+ if (existsSync(nm)) {
641
+ const abs = resolve(shellCwd, "node_modules/@bejamas/ui");
642
+ return relative$1(shellCwd, abs) || abs;
643
+ }
644
+ return "packages/ui";
645
+ })();
646
+ const { uiRoot } = await prompts({
647
+ type: "text",
648
+ name: "uiRoot",
649
+ message: "Path to @bejamas/ui package root:",
650
+ initial: defaultGuess,
651
+ validate: (val) => {
652
+ const p = resolve(shellCwd, val);
653
+ return existsSync(resolve(p, "package.json")) ? true : `No package.json found in ${p}`;
654
+ }
655
+ });
656
+ if (!uiRoot) {
657
+ logger.error("@bejamas/ui root is required to generate docs.");
658
+ process.exit(1);
659
+ }
660
+ process.env.BEJAMAS_UI_ROOT = resolve(shellCwd, uiRoot);
661
+ }
662
+ if (cwd && cwd.length) process.env.BEJAMAS_UI_ROOT = resolve(cwd);
663
+ if (outDir && outDir.length) process.env.BEJAMAS_DOCS_OUT_DIR = outDir;
664
+ if (!process.env.BEJAMAS_DOCS_OUT_DIR) {
665
+ const { out } = await prompts({
666
+ type: "text",
667
+ name: "out",
668
+ message: "Where should we output docs (relative to project root)?",
669
+ initial: "src/content/docs/components"
670
+ });
671
+ if (!out) {
672
+ logger.error("An output directory is required to generate docs.");
673
+ process.exit(1);
674
+ }
675
+ process.env.BEJAMAS_DOCS_OUT_DIR = out;
676
+ process.env.BEJAMAS_DOCS_CWD = process.env.BEJAMAS_DOCS_CWD || shellCwd;
677
+ }
678
+ process.env.BEJAMAS_SKIP_AUTO_RUN = "1";
679
+ logger.info(`Generating docs...`);
680
+ if (DEBUG) {
681
+ logger.info(`Generator entry: @/src/docs/generate-mdx/index`);
682
+ if (process.env.BEJAMAS_UI_ROOT) logger.info(`UI root: ${process.env.BEJAMAS_UI_ROOT}`);
683
+ if (process.env.BEJAMAS_DOCS_CWD) logger.info(`Docs CWD: ${process.env.BEJAMAS_DOCS_CWD}`);
684
+ if (process.env.BEJAMAS_DOCS_OUT_DIR) logger.info(`Docs out: ${process.env.BEJAMAS_DOCS_OUT_DIR}`);
685
+ }
686
+ const mod = await import("./generate-mdx-Bq9erbjr.js");
687
+ if (typeof mod.runDocsGenerator === "function") await mod.runDocsGenerator();
688
+ else throw new Error("Failed to load docs generator. Export 'runDocsGenerator' not found.");
689
+ } catch (err) {
690
+ logger.error(err?.message || String(err));
691
+ process.exit(1);
692
+ }
693
+ }
694
+ const docs = new Command().name("docs:build").alias("docs").description("generate docs from @bejamas/ui components").option("-c, --cwd <cwd>", "path to UI working directory").option("-o, --out <outDir>", "output directory for generated MDX files").action(async (opts) => {
695
+ await generateDocs({
696
+ cwd: opts.cwd,
697
+ outDir: opts.out,
698
+ verbose: Boolean(opts.verbose)
699
+ });
700
+ });
701
+
702
+ //#endregion
703
+ //#region src/commands/add.ts
704
+ const DEFAULT_REGISTRY_URL = "https://ui-web-nine.vercel.app/r";
705
+ function extractOptionsForShadcn(rawArgv) {
706
+ const addIndex = rawArgv.findIndex((arg) => arg === "add");
707
+ if (addIndex === -1) return [];
708
+ const rest = rawArgv.slice(addIndex + 1);
709
+ const forwarded = [];
710
+ for (let i = 0; i < rest.length; i += 1) {
711
+ const token = rest[i];
712
+ if (token === "--") {
713
+ forwarded.push("--", ...rest.slice(i + 1));
714
+ break;
715
+ }
716
+ if (token.startsWith("-")) {
717
+ if (token === "-v" || token === "--verbose") continue;
718
+ forwarded.push(token);
719
+ const next = rest[i + 1];
720
+ if (next && !next.startsWith("-")) {
721
+ forwarded.push(next);
722
+ i += 1;
723
+ }
724
+ continue;
725
+ }
726
+ }
727
+ return forwarded;
728
+ }
729
+ async function addComponents(packages, forwardedOptions, isVerbose) {
730
+ const runner = await getPackageRunner(process.cwd());
731
+ const env = {
732
+ ...process.env,
733
+ REGISTRY_URL: process.env.REGISTRY_URL || DEFAULT_REGISTRY_URL
734
+ };
735
+ const baseArgs = [
736
+ "shadcn@latest",
737
+ "add",
738
+ ...packages,
739
+ ...forwardedOptions
740
+ ];
741
+ let cmd = "npx";
742
+ let args = ["-y", ...baseArgs];
743
+ if (runner === "bunx") {
744
+ cmd = "bunx";
745
+ args = baseArgs;
746
+ } else if (runner === "pnpm dlx") {
747
+ cmd = "pnpm";
748
+ args = ["dlx", ...baseArgs];
749
+ } else if (runner === "npx") {
750
+ cmd = "npx";
751
+ args = ["-y", ...baseArgs];
752
+ }
753
+ if (isVerbose) logger.info(`[bejamas-ui] ${cmd} ${args.join(" ")}`);
754
+ try {
755
+ await execa(cmd, args, {
756
+ stdio: "inherit",
757
+ env
758
+ });
759
+ } catch (err) {
760
+ process.exit(1);
761
+ }
762
+ }
763
+ const add = new Command().name("add").description("Add components via shadcn@latest using registry URLs").argument("[components...]", "Component package names to add").option("-y, --yes", "skip confirmation prompt.", false).option("-o, --overwrite", "overwrite existing files.", false).option("-c, --cwd <cwd>", "the working directory. defaults to the current directory.", process.cwd()).option("-a, --all", "add all available components", false).option("-p, --path <path>", "the path to add the component to.").option("-s, --silent", "mute output.", false).option("--src-dir", "use the src directory when creating a new project.", false).option("--no-src-dir", "do not use the src directory when creating a new project.").action(async function action(packages, _opts, cmd) {
764
+ const root = cmd?.parent;
765
+ const verbose = Boolean(root?.opts?.().verbose);
766
+ const rawArgv = process.argv.slice(2);
767
+ const forwardedOptions = extractOptionsForShadcn(rawArgv);
768
+ await addComponents(packages || [], forwardedOptions, verbose);
769
+ });
770
+
771
+ //#endregion
772
+ //#region src/index.ts
773
+ const pkg = createRequire(import.meta.url)("../package.json");
774
+ const program = new Command().name("bejamas").description("bejamas/ui cli").configureHelp({ helpWidth: Math.min(100, process.stdout.columns || 100) }).version(pkg.version, "-v, --version", "output the version number");
775
+ program.addCommand(init);
776
+ program.addCommand(add);
777
+ program.addCommand(docs);
778
+ program.parse(process.argv);
779
+ var src_default = program;
780
+
781
+ //#endregion
782
+ export { src_default as default };
783
+ //# sourceMappingURL=index.js.map