@dinachi/cli 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -5
- package/dist/index.js +771 -349
- package/package.json +6 -5
package/dist/index.js
CHANGED
|
@@ -6,8 +6,8 @@ import { Command as Command3 } from "commander";
|
|
|
6
6
|
// src/commands/add.ts
|
|
7
7
|
import { Command } from "commander";
|
|
8
8
|
import { execSync } from "child_process";
|
|
9
|
-
import
|
|
10
|
-
import
|
|
9
|
+
import fs3 from "fs-extra";
|
|
10
|
+
import path3 from "path";
|
|
11
11
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
12
12
|
import ora from "ora";
|
|
13
13
|
import chalk from "chalk";
|
|
@@ -18,6 +18,48 @@ import path from "path";
|
|
|
18
18
|
import { fileURLToPath } from "url";
|
|
19
19
|
var __filename = fileURLToPath(import.meta.url);
|
|
20
20
|
var __dirname = path.dirname(__filename);
|
|
21
|
+
function dirnameLike(input) {
|
|
22
|
+
const normalized = input.replace(/\/+$/, "");
|
|
23
|
+
const idx = normalized.lastIndexOf("/");
|
|
24
|
+
if (idx <= 0) {
|
|
25
|
+
return normalized;
|
|
26
|
+
}
|
|
27
|
+
return normalized.slice(0, idx);
|
|
28
|
+
}
|
|
29
|
+
function normalizeConfig(raw) {
|
|
30
|
+
const style = typeof raw.style === "string" ? raw.style : "default";
|
|
31
|
+
const rsc = typeof raw.rsc === "boolean" ? raw.rsc : false;
|
|
32
|
+
const tsx = typeof raw.tsx === "boolean" ? raw.tsx : true;
|
|
33
|
+
const tailwindConfig = typeof raw.tailwind?.config === "string" ? raw.tailwind.config : "tailwind.config.js";
|
|
34
|
+
const tailwindCss = typeof raw.tailwind?.css === "string" ? raw.tailwind.css : "src/index.css";
|
|
35
|
+
const tailwindBaseColor = typeof raw.tailwind?.baseColor === "string" ? raw.tailwind.baseColor : "slate";
|
|
36
|
+
const tailwindCssVariables = typeof raw.tailwind?.cssVariables === "boolean" ? raw.tailwind.cssVariables : true;
|
|
37
|
+
const rawComponentsAlias = typeof raw.aliases?.components === "string" ? raw.aliases.components : "./src/components";
|
|
38
|
+
const hasLegacyUiPathInComponents = rawComponentsAlias.replace(/\/+$/, "").endsWith("/ui");
|
|
39
|
+
const componentsAlias = hasLegacyUiPathInComponents ? dirnameLike(rawComponentsAlias) : rawComponentsAlias;
|
|
40
|
+
const uiAlias = typeof raw.aliases?.ui === "string" ? raw.aliases.ui : hasLegacyUiPathInComponents ? rawComponentsAlias : `${componentsAlias}/ui`;
|
|
41
|
+
const utilsAlias = typeof raw.aliases?.utils === "string" ? raw.aliases.utils : "./src/lib/utils";
|
|
42
|
+
const libAlias = typeof raw.aliases?.lib === "string" ? raw.aliases.lib : dirnameLike(utilsAlias);
|
|
43
|
+
const hooksAlias = typeof raw.aliases?.hooks === "string" ? raw.aliases.hooks : "./src/hooks";
|
|
44
|
+
return {
|
|
45
|
+
style,
|
|
46
|
+
rsc,
|
|
47
|
+
tsx,
|
|
48
|
+
tailwind: {
|
|
49
|
+
config: tailwindConfig,
|
|
50
|
+
css: tailwindCss,
|
|
51
|
+
baseColor: tailwindBaseColor,
|
|
52
|
+
cssVariables: tailwindCssVariables
|
|
53
|
+
},
|
|
54
|
+
aliases: {
|
|
55
|
+
components: componentsAlias,
|
|
56
|
+
utils: utilsAlias,
|
|
57
|
+
ui: uiAlias,
|
|
58
|
+
lib: libAlias,
|
|
59
|
+
hooks: hooksAlias
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
21
63
|
function getUtilityRegistry() {
|
|
22
64
|
return {
|
|
23
65
|
cn: {
|
|
@@ -65,7 +107,6 @@ function getComponentRegistry() {
|
|
|
65
107
|
description: "A customizable button component with multiple variants.",
|
|
66
108
|
files: [{ name: "button.tsx" }, { name: "index.ts" }],
|
|
67
109
|
dependencies: ["@base-ui/react", "class-variance-authority"],
|
|
68
|
-
componentDependencies: ["core"],
|
|
69
110
|
utilityDependencies: ["cn", "variants"]
|
|
70
111
|
},
|
|
71
112
|
checkbox: {
|
|
@@ -295,46 +336,327 @@ async function getConfig() {
|
|
|
295
336
|
}
|
|
296
337
|
try {
|
|
297
338
|
const configContent = await fs.readFile(configPath, "utf-8");
|
|
298
|
-
|
|
299
|
-
|
|
339
|
+
const parsed = JSON.parse(configContent);
|
|
340
|
+
return normalizeConfig(parsed);
|
|
341
|
+
} catch {
|
|
300
342
|
return null;
|
|
301
343
|
}
|
|
302
344
|
}
|
|
303
345
|
|
|
346
|
+
// src/utils/package-manager.ts
|
|
347
|
+
import fs2 from "fs-extra";
|
|
348
|
+
import path2 from "path";
|
|
349
|
+
var LOCK_FILE_MAP = [
|
|
350
|
+
{ file: "bun.lockb", manager: "bun" },
|
|
351
|
+
{ file: "bun.lock", manager: "bun" },
|
|
352
|
+
{ file: "pnpm-lock.yaml", manager: "pnpm" },
|
|
353
|
+
{ file: "yarn.lock", manager: "yarn" },
|
|
354
|
+
{ file: "package-lock.json", manager: "npm" }
|
|
355
|
+
];
|
|
356
|
+
function walkUpDirectories(startDir) {
|
|
357
|
+
const dirs = [];
|
|
358
|
+
let current = path2.resolve(startDir);
|
|
359
|
+
while (true) {
|
|
360
|
+
dirs.push(current);
|
|
361
|
+
const parent = path2.dirname(current);
|
|
362
|
+
if (parent === current) {
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
current = parent;
|
|
366
|
+
}
|
|
367
|
+
return dirs;
|
|
368
|
+
}
|
|
369
|
+
function detectManagerFromPackageJson(startDir) {
|
|
370
|
+
for (const dir of walkUpDirectories(startDir)) {
|
|
371
|
+
const packageJsonPath = path2.join(dir, "package.json");
|
|
372
|
+
if (!fs2.existsSync(packageJsonPath)) {
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
try {
|
|
376
|
+
const packageJson = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
|
|
377
|
+
const value = packageJson.packageManager ?? "";
|
|
378
|
+
if (value.startsWith("pnpm@")) return "pnpm";
|
|
379
|
+
if (value.startsWith("yarn@")) return "yarn";
|
|
380
|
+
if (value.startsWith("bun@")) return "bun";
|
|
381
|
+
if (value.startsWith("npm@")) return "npm";
|
|
382
|
+
} catch {
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
function detectPackageManager(startDir = process.cwd()) {
|
|
389
|
+
const packageJsonManager = detectManagerFromPackageJson(startDir);
|
|
390
|
+
if (packageJsonManager) {
|
|
391
|
+
return packageJsonManager;
|
|
392
|
+
}
|
|
393
|
+
for (const dir of walkUpDirectories(startDir)) {
|
|
394
|
+
for (const entry of LOCK_FILE_MAP) {
|
|
395
|
+
if (fs2.existsSync(path2.join(dir, entry.file))) {
|
|
396
|
+
return entry.manager;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return "npm";
|
|
401
|
+
}
|
|
402
|
+
function getInstallCommand(pm, deps) {
|
|
403
|
+
const depsStr = deps.join(" ");
|
|
404
|
+
switch (pm) {
|
|
405
|
+
case "bun":
|
|
406
|
+
return `bun add ${depsStr}`;
|
|
407
|
+
case "pnpm":
|
|
408
|
+
return `pnpm add ${depsStr}`;
|
|
409
|
+
case "yarn":
|
|
410
|
+
return `yarn add ${depsStr}`;
|
|
411
|
+
default:
|
|
412
|
+
return `npm install ${depsStr}`;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// src/utils/json.ts
|
|
417
|
+
function parseJsonWithComments(content) {
|
|
418
|
+
let result = "";
|
|
419
|
+
let inString = false;
|
|
420
|
+
let inSingleLineComment = false;
|
|
421
|
+
let inMultiLineComment = false;
|
|
422
|
+
let isEscaped = false;
|
|
423
|
+
for (let i = 0; i < content.length; i += 1) {
|
|
424
|
+
const char = content[i];
|
|
425
|
+
const next = content[i + 1];
|
|
426
|
+
if (inSingleLineComment) {
|
|
427
|
+
if (char === "\n") {
|
|
428
|
+
inSingleLineComment = false;
|
|
429
|
+
result += char;
|
|
430
|
+
}
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
if (inMultiLineComment) {
|
|
434
|
+
if (char === "*" && next === "/") {
|
|
435
|
+
inMultiLineComment = false;
|
|
436
|
+
i += 1;
|
|
437
|
+
} else if (char === "\n") {
|
|
438
|
+
result += char;
|
|
439
|
+
}
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
if (inString) {
|
|
443
|
+
result += char;
|
|
444
|
+
if (!isEscaped && char === '"') {
|
|
445
|
+
inString = false;
|
|
446
|
+
}
|
|
447
|
+
isEscaped = !isEscaped && char === "\\";
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
if (char === '"') {
|
|
451
|
+
inString = true;
|
|
452
|
+
isEscaped = false;
|
|
453
|
+
result += char;
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
if (char === "/" && next === "/") {
|
|
457
|
+
inSingleLineComment = true;
|
|
458
|
+
i += 1;
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
if (char === "/" && next === "*") {
|
|
462
|
+
inMultiLineComment = true;
|
|
463
|
+
i += 1;
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
result += char;
|
|
467
|
+
}
|
|
468
|
+
const withoutLineComments = result;
|
|
469
|
+
const withoutTrailingCommas = withoutLineComments.replace(/,\s*([}\]])/g, "$1");
|
|
470
|
+
return JSON.parse(withoutTrailingCommas);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// src/utils/dependencies.ts
|
|
474
|
+
var DEPENDENCY_VERSION_MAP = {
|
|
475
|
+
"@base-ui/react": "^1.2.0",
|
|
476
|
+
"lucide-react": "^0.552.0",
|
|
477
|
+
"class-variance-authority": "^0.7.1",
|
|
478
|
+
"tailwindcss-animate": "^1.0.7",
|
|
479
|
+
"clsx": "^2.1.1",
|
|
480
|
+
"tailwind-merge": "^3.3.1"
|
|
481
|
+
};
|
|
482
|
+
function toInstallSpec(dep) {
|
|
483
|
+
const version = DEPENDENCY_VERSION_MAP[dep];
|
|
484
|
+
return version ? `${dep}@${version}` : dep;
|
|
485
|
+
}
|
|
486
|
+
|
|
304
487
|
// src/commands/add.ts
|
|
305
488
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
306
|
-
var __dirname2 =
|
|
307
|
-
function
|
|
308
|
-
|
|
309
|
-
|
|
489
|
+
var __dirname2 = path3.dirname(__filename2);
|
|
490
|
+
function stripTemplateDirective(content) {
|
|
491
|
+
return content.replace(/^\/\/ @ts-nocheck\s*\n/m, "");
|
|
492
|
+
}
|
|
493
|
+
function stripExtension(filePath) {
|
|
494
|
+
return filePath.replace(/\.[^./\\]+$/, "");
|
|
310
495
|
}
|
|
311
|
-
function
|
|
496
|
+
function toImportPath(fromFilePath, toFilePath) {
|
|
497
|
+
const relativePath = path3.relative(path3.dirname(fromFilePath), stripExtension(toFilePath)).replace(/\\/g, "/");
|
|
498
|
+
return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
499
|
+
}
|
|
500
|
+
function matchPathPattern(pattern, input) {
|
|
501
|
+
if (!pattern.includes("*")) {
|
|
502
|
+
return pattern === input ? "" : null;
|
|
503
|
+
}
|
|
504
|
+
const [prefix, suffix] = pattern.split("*");
|
|
505
|
+
if (!input.startsWith(prefix) || !input.endsWith(suffix)) {
|
|
506
|
+
return null;
|
|
507
|
+
}
|
|
508
|
+
return input.slice(prefix.length, input.length - suffix.length);
|
|
509
|
+
}
|
|
510
|
+
function readCompilerPathConfig(projectRoot) {
|
|
511
|
+
const configFiles = ["tsconfig.json", "jsconfig.json"];
|
|
512
|
+
for (const configFile of configFiles) {
|
|
513
|
+
const configPath = path3.join(projectRoot, configFile);
|
|
514
|
+
if (!fs3.existsSync(configPath)) {
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
try {
|
|
518
|
+
const content = fs3.readFileSync(configPath, "utf-8");
|
|
519
|
+
const parsed = parseJsonWithComments(content);
|
|
520
|
+
const compilerOptions = parsed.compilerOptions ?? {};
|
|
521
|
+
const baseUrl = path3.resolve(
|
|
522
|
+
projectRoot,
|
|
523
|
+
typeof compilerOptions.baseUrl === "string" ? compilerOptions.baseUrl : "."
|
|
524
|
+
);
|
|
525
|
+
const rawPaths = compilerOptions.paths ?? {};
|
|
526
|
+
const paths = {};
|
|
527
|
+
for (const [key, value] of Object.entries(rawPaths)) {
|
|
528
|
+
if (!Array.isArray(value)) {
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
const targets = value.filter((entry) => typeof entry === "string");
|
|
532
|
+
if (targets.length > 0) {
|
|
533
|
+
paths[key] = targets;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
return { baseUrl, paths };
|
|
537
|
+
} catch {
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
return null;
|
|
542
|
+
}
|
|
543
|
+
function resolveConfiguredPath(aliasOrPath, projectRoot, compilerConfig) {
|
|
544
|
+
const normalized = aliasOrPath.replace(/\\/g, "/").trim();
|
|
545
|
+
if (path3.isAbsolute(normalized)) {
|
|
546
|
+
return normalized;
|
|
547
|
+
}
|
|
548
|
+
if (normalized.startsWith("./") || normalized.startsWith("../")) {
|
|
549
|
+
return path3.resolve(projectRoot, normalized);
|
|
550
|
+
}
|
|
551
|
+
if (normalized.startsWith("/")) {
|
|
552
|
+
return path3.resolve(projectRoot, `.${normalized}`);
|
|
553
|
+
}
|
|
554
|
+
if (compilerConfig) {
|
|
555
|
+
for (const [pattern, targets] of Object.entries(compilerConfig.paths)) {
|
|
556
|
+
const wildcard = matchPathPattern(pattern, normalized);
|
|
557
|
+
if (wildcard === null) {
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
const target = targets[0];
|
|
561
|
+
if (!target) {
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
const mappedTarget = target.includes("*") ? target.replace("*", wildcard) : target;
|
|
565
|
+
return path3.resolve(compilerConfig.baseUrl, mappedTarget);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
if (normalized.startsWith("@/") || normalized.startsWith("~/")) {
|
|
569
|
+
return path3.resolve(projectRoot, normalized.slice(2));
|
|
570
|
+
}
|
|
571
|
+
return path3.resolve(projectRoot, normalized);
|
|
572
|
+
}
|
|
573
|
+
function rewriteTemplateImports(content, targetFilePath, utilsFilePath, libDirPath) {
|
|
574
|
+
const utilsImportPath = toImportPath(targetFilePath, utilsFilePath);
|
|
575
|
+
const variantsImportPath = toImportPath(targetFilePath, path3.join(libDirPath, "variants.ts"));
|
|
576
|
+
return content.replace(/(['"])@\/lib\/utils\1/g, `$1${utilsImportPath}$1`).replace(/(['"])@\/lib\/variants\1/g, `$1${variantsImportPath}$1`);
|
|
577
|
+
}
|
|
578
|
+
function getComponentDependencies(componentName, visited = /* @__PURE__ */ new Set()) {
|
|
579
|
+
if (visited.has(componentName)) {
|
|
580
|
+
return [];
|
|
581
|
+
}
|
|
582
|
+
visited.add(componentName);
|
|
312
583
|
const registry = getComponentRegistry();
|
|
313
584
|
const component = registry[componentName];
|
|
314
585
|
if (!component) return [];
|
|
315
|
-
|
|
586
|
+
const dependencies = [];
|
|
316
587
|
for (const dep of component.componentDependencies || []) {
|
|
317
|
-
|
|
588
|
+
if (!registry[dep]) {
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
dependencies.push(dep, ...getComponentDependencies(dep, visited));
|
|
318
592
|
}
|
|
319
593
|
return [...new Set(dependencies)];
|
|
320
594
|
}
|
|
321
|
-
|
|
322
|
-
const
|
|
323
|
-
if (
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
595
|
+
function detectTailwindConfigPath(projectRoot, configuredName) {
|
|
596
|
+
const preferred = resolveConfiguredPath(configuredName, projectRoot, null);
|
|
597
|
+
if (fs3.existsSync(preferred)) {
|
|
598
|
+
return preferred;
|
|
599
|
+
}
|
|
600
|
+
const alternatives = [
|
|
601
|
+
"tailwind.config.ts",
|
|
602
|
+
"tailwind.config.js",
|
|
603
|
+
"tailwind.config.mjs",
|
|
604
|
+
"tailwind.config.cjs",
|
|
605
|
+
"tailwind.config.cts",
|
|
606
|
+
"tailwind.config.mts"
|
|
607
|
+
];
|
|
608
|
+
for (const candidate of alternatives) {
|
|
609
|
+
const candidatePath = path3.join(projectRoot, candidate);
|
|
610
|
+
if (fs3.existsSync(candidatePath)) {
|
|
611
|
+
return candidatePath;
|
|
333
612
|
}
|
|
334
613
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
614
|
+
return preferred;
|
|
615
|
+
}
|
|
616
|
+
function insertTailwindPlugin(content, pluginExpression) {
|
|
617
|
+
if (/plugins\s*:\s*\[/.test(content)) {
|
|
618
|
+
return content.replace(/plugins\s*:\s*\[([\s\S]*?)\]/m, (_match, pluginsContent) => {
|
|
619
|
+
const trimmedPlugins = pluginsContent.trim();
|
|
620
|
+
if (trimmedPlugins.length === 0) {
|
|
621
|
+
return `plugins: [
|
|
622
|
+
${pluginExpression},
|
|
623
|
+
]`;
|
|
624
|
+
}
|
|
625
|
+
const normalizedPlugins = pluginsContent.trimEnd();
|
|
626
|
+
const withTrailingComma = normalizedPlugins.endsWith(",") ? normalizedPlugins : `${normalizedPlugins},`;
|
|
627
|
+
return `plugins: [
|
|
628
|
+
${withTrailingComma}
|
|
629
|
+
${pluginExpression},
|
|
630
|
+
]`;
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
const trimmed = content.trimEnd();
|
|
634
|
+
const hasSemicolon = trimmed.endsWith(";");
|
|
635
|
+
const withoutSemicolon = hasSemicolon ? trimmed.slice(0, -1) : trimmed;
|
|
636
|
+
const closingBraceIndex = withoutSemicolon.lastIndexOf("}");
|
|
637
|
+
if (closingBraceIndex === -1) {
|
|
638
|
+
return null;
|
|
639
|
+
}
|
|
640
|
+
const beforeClosingBrace = withoutSemicolon.slice(0, closingBraceIndex).trimEnd();
|
|
641
|
+
const needsComma = beforeClosingBrace.length > 0 && !beforeClosingBrace.endsWith(",") && !beforeClosingBrace.endsWith("{");
|
|
642
|
+
const next = `${withoutSemicolon.slice(0, closingBraceIndex)}${needsComma ? "," : ""}
|
|
643
|
+
plugins: [
|
|
644
|
+
${pluginExpression},
|
|
645
|
+
],
|
|
646
|
+
}${hasSemicolon ? ";" : ""}
|
|
647
|
+
`;
|
|
648
|
+
return next;
|
|
649
|
+
}
|
|
650
|
+
async function ensureTailwindConfig(deps, projectRoot, configuredFileName) {
|
|
651
|
+
if (!deps.includes("tailwindcss-animate")) {
|
|
652
|
+
return null;
|
|
653
|
+
}
|
|
654
|
+
const configPath = detectTailwindConfigPath(projectRoot, configuredFileName || "tailwind.config.js");
|
|
655
|
+
if (!fs3.existsSync(configPath)) {
|
|
656
|
+
const ext2 = path3.extname(configPath);
|
|
657
|
+
const isCjs2 = ext2 === ".cjs";
|
|
658
|
+
const configContent = isCjs2 ? `/** @type {import('tailwindcss').Config} */
|
|
659
|
+
module.exports = {
|
|
338
660
|
content: [
|
|
339
661
|
"./src/**/*.{js,ts,jsx,tsx}",
|
|
340
662
|
"./app/**/*.{js,ts,jsx,tsx}",
|
|
@@ -344,265 +666,346 @@ export default {
|
|
|
344
666
|
theme: {
|
|
345
667
|
extend: {},
|
|
346
668
|
},
|
|
347
|
-
plugins: [
|
|
348
|
-
|
|
669
|
+
plugins: [require("tailwindcss-animate")],
|
|
670
|
+
}
|
|
671
|
+
` : `import tailwindcssAnimate from "tailwindcss-animate"
|
|
672
|
+
|
|
673
|
+
export default {
|
|
674
|
+
content: [
|
|
675
|
+
"./src/**/*.{js,ts,jsx,tsx}",
|
|
676
|
+
"./app/**/*.{js,ts,jsx,tsx}",
|
|
677
|
+
"./components/**/*.{js,ts,jsx,tsx}",
|
|
678
|
+
"./pages/**/*.{js,ts,jsx,tsx}",
|
|
349
679
|
],
|
|
350
|
-
|
|
351
|
-
|
|
680
|
+
theme: {
|
|
681
|
+
extend: {},
|
|
682
|
+
},
|
|
683
|
+
plugins: [tailwindcssAnimate],
|
|
684
|
+
}
|
|
685
|
+
`;
|
|
686
|
+
await fs3.ensureDir(path3.dirname(configPath));
|
|
687
|
+
await fs3.writeFile(configPath, configContent);
|
|
352
688
|
return { created: true, path: configPath };
|
|
353
|
-
} else {
|
|
354
|
-
const configContent = await fs2.readFile(configPath, "utf-8");
|
|
355
|
-
if (!configContent.includes("tailwindcss-animate")) {
|
|
356
|
-
let updatedContent = configContent;
|
|
357
|
-
if (configContent.includes("plugins:")) {
|
|
358
|
-
updatedContent = configContent.replace(
|
|
359
|
-
/plugins:\s*\[([\s\S]*?)\]/,
|
|
360
|
-
(match, pluginsContent) => {
|
|
361
|
-
const cleanPlugins = pluginsContent.trim();
|
|
362
|
-
const newPlugin = 'require("tailwindcss-animate")';
|
|
363
|
-
if (cleanPlugins === "") {
|
|
364
|
-
return `plugins: [
|
|
365
|
-
${newPlugin},
|
|
366
|
-
]`;
|
|
367
|
-
} else {
|
|
368
|
-
return `plugins: [
|
|
369
|
-
${pluginsContent},
|
|
370
|
-
${newPlugin},
|
|
371
|
-
]`;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
);
|
|
375
|
-
} else {
|
|
376
|
-
updatedContent = configContent.replace(
|
|
377
|
-
/}\s*;?\s*$/,
|
|
378
|
-
' plugins: [\n require("tailwindcss-animate"),\n ],\n};'
|
|
379
|
-
);
|
|
380
|
-
}
|
|
381
|
-
await fs2.writeFile(configPath, updatedContent);
|
|
382
|
-
return { updated: true, path: configPath };
|
|
383
|
-
}
|
|
384
689
|
}
|
|
385
|
-
|
|
690
|
+
const currentContent = await fs3.readFile(configPath, "utf-8");
|
|
691
|
+
if (currentContent.includes("tailwindcss-animate")) {
|
|
692
|
+
return { exists: true, path: configPath };
|
|
693
|
+
}
|
|
694
|
+
const ext = path3.extname(configPath);
|
|
695
|
+
const isCjs = ext === ".cjs" || /module\.exports\s*=/.test(currentContent);
|
|
696
|
+
const pluginExpression = isCjs ? 'require("tailwindcss-animate")' : "tailwindcssAnimate";
|
|
697
|
+
let updatedContent = currentContent;
|
|
698
|
+
if (!isCjs && !/from\s+['"]tailwindcss-animate['"]/.test(updatedContent)) {
|
|
699
|
+
updatedContent = `import tailwindcssAnimate from "tailwindcss-animate"
|
|
700
|
+
${updatedContent}`;
|
|
701
|
+
}
|
|
702
|
+
const merged = insertTailwindPlugin(updatedContent, pluginExpression);
|
|
703
|
+
if (!merged) {
|
|
704
|
+
return { skipped: true, path: configPath };
|
|
705
|
+
}
|
|
706
|
+
await fs3.writeFile(configPath, merged);
|
|
707
|
+
return { updated: true, path: configPath };
|
|
708
|
+
}
|
|
709
|
+
function escapeRegex(value) {
|
|
710
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
386
711
|
}
|
|
387
|
-
async function handleIndexFile(sourcePath, targetPath,
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
712
|
+
async function handleIndexFile(sourcePath, targetPath, allFilesAdded, targetDir) {
|
|
713
|
+
const templateContent = stripTemplateDirective(await fs3.readFile(sourcePath, "utf-8"));
|
|
714
|
+
if (!fs3.existsSync(targetPath)) {
|
|
715
|
+
await fs3.writeFile(targetPath, templateContent);
|
|
716
|
+
allFilesAdded.push({ name: "index.ts", path: path3.join(targetDir, "index.ts") });
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
const existingContent = await fs3.readFile(targetPath, "utf-8");
|
|
720
|
+
const exportLines = templateContent.split("\n").map((line) => line.trim()).filter((line) => /^export\s+/.test(line) && /from\s+['"]\.\/[^'"]+['"]/.test(line));
|
|
721
|
+
const linesToAppend = [];
|
|
722
|
+
for (const line of exportLines) {
|
|
723
|
+
const match = line.match(/from\s+['"]\.\/([^'"]+)['"]/);
|
|
724
|
+
if (!match) {
|
|
725
|
+
continue;
|
|
400
726
|
}
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
await fs2.writeFile(targetPath, updatedContent);
|
|
406
|
-
allFilesAdded.push({ name: "index.ts", path: path2.join(targetDir, "index.ts") });
|
|
727
|
+
const modulePath = match[1];
|
|
728
|
+
const modulePathPattern = new RegExp(`from\\s+['"]\\./${escapeRegex(modulePath)}['"]`);
|
|
729
|
+
if (modulePathPattern.test(existingContent)) {
|
|
730
|
+
continue;
|
|
407
731
|
}
|
|
732
|
+
linesToAppend.push(line.endsWith(";") ? line : `${line};`);
|
|
733
|
+
}
|
|
734
|
+
if (linesToAppend.length === 0) {
|
|
735
|
+
return;
|
|
408
736
|
}
|
|
737
|
+
const updatedContent = `${existingContent.trimEnd()}
|
|
738
|
+
${linesToAppend.join("\n")}
|
|
739
|
+
`;
|
|
740
|
+
await fs3.writeFile(targetPath, updatedContent);
|
|
741
|
+
allFilesAdded.push({ name: "index.ts", path: path3.join(targetDir, "index.ts") });
|
|
409
742
|
}
|
|
410
|
-
var addCommand = new Command("add").description("Add a component to your project").argument("[component]", "Name of the component (optional when using --all)").option("-y, --yes", "Skip confirmation prompts").option("-o, --overwrite", "Overwrite existing files").option("-a, --all", "Install all available components").
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
}
|
|
418
|
-
const registry = getComponentRegistry();
|
|
419
|
-
let componentsToInstall = [];
|
|
420
|
-
if (options.all) {
|
|
421
|
-
const allComponents = Object.keys(registry);
|
|
422
|
-
spinner.text = `Installing all ${allComponents.length} components...`;
|
|
423
|
-
const allComponentsWithDeps = /* @__PURE__ */ new Set();
|
|
424
|
-
for (const name of allComponents) {
|
|
425
|
-
allComponentsWithDeps.add(name);
|
|
426
|
-
const deps = getComponentDependencies(name);
|
|
427
|
-
deps.forEach((dep) => allComponentsWithDeps.add(dep));
|
|
428
|
-
}
|
|
429
|
-
componentsToInstall = Array.from(allComponentsWithDeps);
|
|
430
|
-
} else {
|
|
431
|
-
if (!componentName) {
|
|
432
|
-
spinner.fail("\u274C Component name is required when not using --all flag.");
|
|
433
|
-
console.log("Available components:");
|
|
434
|
-
Object.keys(registry).forEach((name) => {
|
|
435
|
-
console.log(` ${chalk.cyan(name)}`);
|
|
436
|
-
});
|
|
743
|
+
var addCommand = new Command("add").description("Add a component to your project").argument("[component]", "Name of the component (optional when using --all)").option("-y, --yes", "Skip confirmation prompts").option("-o, --overwrite", "Overwrite existing files").option("-a, --all", "Install all available components").option("--skip-install", "Skip package installation").action(
|
|
744
|
+
async (componentName, options) => {
|
|
745
|
+
const spinner = ora("Adding component...").start();
|
|
746
|
+
try {
|
|
747
|
+
const config = await getConfig();
|
|
748
|
+
if (!config) {
|
|
749
|
+
spinner.fail("\u274C No components.json found. Run `dinachi init` first.");
|
|
437
750
|
process.exit(1);
|
|
438
751
|
}
|
|
439
|
-
const
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
}
|
|
446
|
-
|
|
752
|
+
const projectRoot = process.cwd();
|
|
753
|
+
const compilerPathConfig = readCompilerPathConfig(projectRoot);
|
|
754
|
+
const registry = getComponentRegistry();
|
|
755
|
+
let componentsToInstall = [];
|
|
756
|
+
if (options.all) {
|
|
757
|
+
const allComponents = Object.keys(registry);
|
|
758
|
+
spinner.text = `Installing all ${allComponents.length} components...`;
|
|
759
|
+
const allComponentsWithDeps = /* @__PURE__ */ new Set();
|
|
760
|
+
for (const name of allComponents) {
|
|
761
|
+
allComponentsWithDeps.add(name);
|
|
762
|
+
const deps = getComponentDependencies(name);
|
|
763
|
+
deps.forEach((dep) => allComponentsWithDeps.add(dep));
|
|
764
|
+
}
|
|
765
|
+
componentsToInstall = Array.from(allComponentsWithDeps);
|
|
766
|
+
} else {
|
|
767
|
+
if (!componentName) {
|
|
768
|
+
spinner.fail("\u274C Component name is required when not using --all flag.");
|
|
769
|
+
console.log("Available components:");
|
|
770
|
+
Object.keys(registry).forEach((name) => {
|
|
771
|
+
console.log(` ${chalk.cyan(name)}`);
|
|
772
|
+
});
|
|
773
|
+
process.exit(1);
|
|
774
|
+
}
|
|
775
|
+
const component = registry[componentName];
|
|
776
|
+
if (!component) {
|
|
777
|
+
spinner.fail(`\u274C Component "${componentName}" not found.`);
|
|
778
|
+
console.log("Available components:");
|
|
779
|
+
Object.keys(registry).forEach((name) => {
|
|
780
|
+
console.log(` ${chalk.cyan(name)}`);
|
|
781
|
+
});
|
|
782
|
+
process.exit(1);
|
|
783
|
+
}
|
|
784
|
+
componentsToInstall = [componentName, ...getComponentDependencies(componentName)];
|
|
447
785
|
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
if (!options.all) {
|
|
451
|
-
spinner.text = `Installing ${componentsToInstall.join(", ")}...`;
|
|
452
|
-
}
|
|
453
|
-
const componentDir = resolveAliasPath(config.aliases.ui, process.cwd());
|
|
454
|
-
await fs2.ensureDir(componentDir);
|
|
455
|
-
let allFilesAdded = [];
|
|
456
|
-
let allDepsInstalled = [];
|
|
457
|
-
let allUtilityDeps = [];
|
|
458
|
-
for (const name of componentsToInstall) {
|
|
459
|
-
const comp = registry[name];
|
|
460
|
-
if (!comp) continue;
|
|
461
|
-
if (comp.utilityDependencies?.length) {
|
|
462
|
-
allUtilityDeps.push(...comp.utilityDependencies);
|
|
786
|
+
if (!options.all) {
|
|
787
|
+
spinner.text = `Installing ${componentsToInstall.join(", ")}...`;
|
|
463
788
|
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
const
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
789
|
+
const componentDir = resolveConfiguredPath(config.aliases.ui, projectRoot, compilerPathConfig);
|
|
790
|
+
const libDir = resolveConfiguredPath(config.aliases.lib, projectRoot, compilerPathConfig);
|
|
791
|
+
const utilsFilePath = resolveConfiguredPath(config.aliases.utils, projectRoot, compilerPathConfig);
|
|
792
|
+
await fs3.ensureDir(componentDir);
|
|
793
|
+
await fs3.ensureDir(libDir);
|
|
794
|
+
const allFilesAdded = [];
|
|
795
|
+
const allDepsInstalled = [];
|
|
796
|
+
const allUtilityDeps = [];
|
|
797
|
+
for (const name of componentsToInstall) {
|
|
798
|
+
const comp = registry[name];
|
|
799
|
+
if (!comp) continue;
|
|
800
|
+
if (comp.utilityDependencies?.length) {
|
|
801
|
+
allUtilityDeps.push(...comp.utilityDependencies);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
const utilityRegistry = getUtilityRegistry();
|
|
805
|
+
const uniqueUtilityDeps = [...new Set(allUtilityDeps)];
|
|
806
|
+
if (uniqueUtilityDeps.length > 0) {
|
|
807
|
+
for (const utilityName of uniqueUtilityDeps) {
|
|
808
|
+
const utility = utilityRegistry[utilityName];
|
|
809
|
+
if (!utility) continue;
|
|
810
|
+
const utilityFilename = `${utility.name}.ts`;
|
|
811
|
+
const sourcePath = path3.join(__dirname2, "../templates/utils", utilityFilename);
|
|
812
|
+
const targetPath = path3.join(libDir, utilityFilename);
|
|
813
|
+
if (!fs3.existsSync(targetPath)) {
|
|
814
|
+
const content = stripTemplateDirective(await fs3.readFile(sourcePath, "utf-8"));
|
|
815
|
+
await fs3.writeFile(targetPath, content);
|
|
816
|
+
allFilesAdded.push({
|
|
817
|
+
name: utilityFilename,
|
|
818
|
+
path: targetPath
|
|
819
|
+
});
|
|
820
|
+
}
|
|
484
821
|
if (utility.dependencies?.length) {
|
|
485
822
|
allDepsInstalled.push(...utility.dependencies);
|
|
486
823
|
}
|
|
487
824
|
}
|
|
488
825
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
if (
|
|
826
|
+
for (const name of componentsToInstall) {
|
|
827
|
+
const comp = registry[name];
|
|
828
|
+
if (!comp) continue;
|
|
829
|
+
for (const file of comp.files) {
|
|
830
|
+
const sourcePath = path3.join(__dirname2, "../templates", name, file.name);
|
|
831
|
+
const targetPath = path3.join(componentDir, file.name);
|
|
832
|
+
if (file.name === "index.ts") {
|
|
833
|
+
await handleIndexFile(sourcePath, targetPath, allFilesAdded, componentDir);
|
|
834
|
+
continue;
|
|
835
|
+
}
|
|
836
|
+
if (fs3.existsSync(targetPath) && !options.overwrite) {
|
|
500
837
|
spinner.warn(`\u26A0\uFE0F ${file.name} already exists. Use --overwrite to replace it.`);
|
|
501
838
|
continue;
|
|
502
839
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
await
|
|
506
|
-
allFilesAdded.push({ name: file.name, path:
|
|
840
|
+
const templateContent = stripTemplateDirective(await fs3.readFile(sourcePath, "utf-8"));
|
|
841
|
+
const rewrittenContent = rewriteTemplateImports(templateContent, targetPath, utilsFilePath, libDir);
|
|
842
|
+
await fs3.writeFile(targetPath, rewrittenContent);
|
|
843
|
+
allFilesAdded.push({ name: file.name, path: targetPath });
|
|
844
|
+
}
|
|
845
|
+
if (comp.dependencies?.length) {
|
|
846
|
+
allDepsInstalled.push(...comp.dependencies);
|
|
507
847
|
}
|
|
508
848
|
}
|
|
509
|
-
if (comp.dependencies?.length) {
|
|
510
|
-
allDepsInstalled.push(...comp.dependencies);
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
let tailwindConfigInfo = null;
|
|
514
|
-
if (allDepsInstalled.includes("tailwindcss-animate")) {
|
|
515
849
|
spinner.text = "Updating Tailwind configuration...";
|
|
516
|
-
const
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
850
|
+
const tailwindConfigInfo = await ensureTailwindConfig(
|
|
851
|
+
allDepsInstalled,
|
|
852
|
+
projectRoot,
|
|
853
|
+
config.tailwind?.config || "tailwind.config.js"
|
|
854
|
+
);
|
|
855
|
+
const packageJsonPath = path3.join(projectRoot, "package.json");
|
|
856
|
+
if (!fs3.existsSync(packageJsonPath)) {
|
|
857
|
+
throw new Error("No package.json found in the current directory.");
|
|
858
|
+
}
|
|
859
|
+
const packageJson = JSON.parse(await fs3.readFile(packageJsonPath, "utf-8"));
|
|
860
|
+
const declaredDeps = { ...packageJson.dependencies ?? {}, ...packageJson.devDependencies ?? {} };
|
|
861
|
+
const uniqueDeps = [...new Set(allDepsInstalled)];
|
|
862
|
+
const missingDeps = uniqueDeps.filter((dep) => !declaredDeps[dep]);
|
|
863
|
+
if (!options.skipInstall && missingDeps.length > 0) {
|
|
864
|
+
spinner.text = "Installing dependencies...";
|
|
526
865
|
try {
|
|
527
|
-
const packageManager =
|
|
528
|
-
const installCmd = getInstallCommand(packageManager, missingDeps);
|
|
529
|
-
execSync(installCmd, { stdio: "inherit" });
|
|
530
|
-
} catch
|
|
866
|
+
const packageManager = detectPackageManager(projectRoot);
|
|
867
|
+
const installCmd = getInstallCommand(packageManager, missingDeps.map(toInstallSpec));
|
|
868
|
+
execSync(installCmd, { stdio: "inherit", cwd: projectRoot });
|
|
869
|
+
} catch {
|
|
531
870
|
spinner.warn(`\u26A0\uFE0F Failed to install dependencies. Please install manually: ${missingDeps.join(" ")}`);
|
|
532
871
|
}
|
|
533
|
-
} else {
|
|
872
|
+
} else if (!options.skipInstall && uniqueDeps.length > 0) {
|
|
534
873
|
spinner.text = "All dependencies already installed.";
|
|
535
874
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
spinner.succeed(`\u2705 Added ${componentsToInstall.join(", ")}!`);
|
|
541
|
-
}
|
|
542
|
-
console.log();
|
|
543
|
-
console.log("Files added:");
|
|
544
|
-
allFilesAdded.forEach((file) => {
|
|
545
|
-
console.log(` ${chalk.green("+")} ${file.path}`);
|
|
546
|
-
});
|
|
547
|
-
if (tailwindConfigInfo) {
|
|
548
|
-
console.log();
|
|
549
|
-
if (tailwindConfigInfo.created) {
|
|
550
|
-
console.log(` ${chalk.green("+")} ${tailwindConfigInfo.path} (created with tailwindcss-animate plugin)`);
|
|
551
|
-
} else if (tailwindConfigInfo.updated) {
|
|
552
|
-
console.log(` ${chalk.blue("~")} ${tailwindConfigInfo.path} (updated with tailwindcss-animate plugin)`);
|
|
875
|
+
if (options.all) {
|
|
876
|
+
spinner.succeed(`\u2705 Added all ${componentsToInstall.length} components!`);
|
|
877
|
+
} else {
|
|
878
|
+
spinner.succeed(`\u2705 Added ${componentsToInstall.join(", ")}!`);
|
|
553
879
|
}
|
|
554
|
-
}
|
|
555
|
-
if (missingDeps.length > 0) {
|
|
556
|
-
console.log();
|
|
557
|
-
console.log("Dependencies installed:");
|
|
558
|
-
missingDeps.forEach((dep) => {
|
|
559
|
-
console.log(` ${chalk.green("\u2713")} ${dep}`);
|
|
560
|
-
});
|
|
561
|
-
} else if (allDepsInstalled.length > 0) {
|
|
562
880
|
console.log();
|
|
563
|
-
console.log("
|
|
564
|
-
|
|
565
|
-
console.log(` ${chalk.
|
|
881
|
+
console.log("Files added:");
|
|
882
|
+
allFilesAdded.forEach((file) => {
|
|
883
|
+
console.log(` ${chalk.green("+")} ${file.path}`);
|
|
566
884
|
});
|
|
885
|
+
if (tailwindConfigInfo) {
|
|
886
|
+
console.log();
|
|
887
|
+
if (tailwindConfigInfo.created) {
|
|
888
|
+
console.log(` ${chalk.green("+")} ${tailwindConfigInfo.path} (created with tailwindcss-animate plugin)`);
|
|
889
|
+
} else if (tailwindConfigInfo.updated) {
|
|
890
|
+
console.log(` ${chalk.blue("~")} ${tailwindConfigInfo.path} (updated with tailwindcss-animate plugin)`);
|
|
891
|
+
} else if (tailwindConfigInfo.skipped) {
|
|
892
|
+
console.log(
|
|
893
|
+
` ${chalk.yellow("!")} ${tailwindConfigInfo.path} (could not safely update automatically; add tailwindcss-animate manually)`
|
|
894
|
+
);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
if (options.skipInstall && missingDeps.length > 0) {
|
|
898
|
+
console.log();
|
|
899
|
+
console.log("Dependencies to install manually:");
|
|
900
|
+
missingDeps.forEach((dep) => {
|
|
901
|
+
console.log(` ${chalk.yellow("\u2022")} ${toInstallSpec(dep)}`);
|
|
902
|
+
});
|
|
903
|
+
} else if (missingDeps.length > 0) {
|
|
904
|
+
console.log();
|
|
905
|
+
console.log("Dependencies installed:");
|
|
906
|
+
missingDeps.forEach((dep) => {
|
|
907
|
+
console.log(` ${chalk.green("\u2713")} ${toInstallSpec(dep)}`);
|
|
908
|
+
});
|
|
909
|
+
} else if (uniqueDeps.length > 0) {
|
|
910
|
+
console.log();
|
|
911
|
+
console.log("Dependencies (already installed):");
|
|
912
|
+
uniqueDeps.forEach((dep) => {
|
|
913
|
+
console.log(` ${chalk.blue("~")} ${dep}`);
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
} catch (error) {
|
|
917
|
+
spinner.fail(`\u274C Failed to add component: ${error instanceof Error ? error.message : error}`);
|
|
918
|
+
process.exit(1);
|
|
567
919
|
}
|
|
568
|
-
} catch (error) {
|
|
569
|
-
spinner.fail(`\u274C Failed to add component: ${error instanceof Error ? error.message : error}`);
|
|
570
|
-
process.exit(1);
|
|
571
920
|
}
|
|
572
|
-
|
|
573
|
-
function getPackageManager() {
|
|
574
|
-
if (fs2.existsSync("bun.lockb") || fs2.existsSync("bun.lock")) return "bun";
|
|
575
|
-
if (fs2.existsSync("pnpm-lock.yaml")) return "pnpm";
|
|
576
|
-
if (fs2.existsSync("yarn.lock")) return "yarn";
|
|
577
|
-
return "npm";
|
|
578
|
-
}
|
|
579
|
-
function getInstallCommand(pm, deps) {
|
|
580
|
-
const depsStr = deps.join(" ");
|
|
581
|
-
switch (pm) {
|
|
582
|
-
case "bun":
|
|
583
|
-
return `bun add ${depsStr}`;
|
|
584
|
-
case "pnpm":
|
|
585
|
-
return `pnpm add ${depsStr}`;
|
|
586
|
-
case "yarn":
|
|
587
|
-
return `yarn add ${depsStr}`;
|
|
588
|
-
default:
|
|
589
|
-
return `npm install ${depsStr}`;
|
|
590
|
-
}
|
|
591
|
-
}
|
|
921
|
+
);
|
|
592
922
|
|
|
593
923
|
// src/commands/init.ts
|
|
594
924
|
import { Command as Command2 } from "commander";
|
|
595
925
|
import { execSync as execSync2 } from "child_process";
|
|
596
|
-
import
|
|
597
|
-
import
|
|
926
|
+
import fs4 from "fs-extra";
|
|
927
|
+
import path4 from "path";
|
|
598
928
|
import prompts from "prompts";
|
|
599
929
|
import chalk2 from "chalk";
|
|
600
930
|
import ora2 from "ora";
|
|
601
|
-
|
|
931
|
+
function normalizeProjectPath(inputPath, projectRoot) {
|
|
932
|
+
const absolutePath = path4.isAbsolute(inputPath) ? path4.normalize(inputPath) : path4.resolve(projectRoot, inputPath);
|
|
933
|
+
const relativePath = path4.relative(projectRoot, absolutePath).replace(/\\/g, "/");
|
|
934
|
+
const withoutPrefix = relativePath.replace(/^\.\//, "").replace(/\/$/, "");
|
|
935
|
+
return withoutPrefix.length > 0 ? withoutPrefix : ".";
|
|
936
|
+
}
|
|
937
|
+
function toConfigPath(relativePath) {
|
|
938
|
+
return relativePath === "." ? "." : `./${relativePath.replace(/\\/g, "/")}`;
|
|
939
|
+
}
|
|
940
|
+
function createUtilsFileContent() {
|
|
941
|
+
return `import { type ClassValue, clsx } from "clsx"
|
|
942
|
+
import { twMerge } from "tailwind-merge"
|
|
943
|
+
|
|
944
|
+
export function cn(...inputs: ClassValue[]) {
|
|
945
|
+
return twMerge(clsx(inputs))
|
|
946
|
+
}
|
|
947
|
+
`;
|
|
948
|
+
}
|
|
949
|
+
function readJsonConfig(filePath) {
|
|
950
|
+
try {
|
|
951
|
+
const content = fs4.readFileSync(filePath, "utf-8");
|
|
952
|
+
return parseJsonWithComments(content);
|
|
953
|
+
} catch {
|
|
954
|
+
return null;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
async function ensureAtAlias(projectRoot, srcDir, isTypeScript) {
|
|
958
|
+
const tsConfigPath = path4.join(projectRoot, "tsconfig.json");
|
|
959
|
+
const jsConfigPath = path4.join(projectRoot, "jsconfig.json");
|
|
960
|
+
const configPath = fs4.existsSync(tsConfigPath) ? tsConfigPath : fs4.existsSync(jsConfigPath) ? jsConfigPath : path4.join(projectRoot, isTypeScript ? "tsconfig.json" : "jsconfig.json");
|
|
961
|
+
const existedBefore = fs4.existsSync(configPath);
|
|
962
|
+
const parsedConfig = readJsonConfig(configPath);
|
|
963
|
+
if (existedBefore && !parsedConfig) {
|
|
964
|
+
return { path: configPath, skipped: true };
|
|
965
|
+
}
|
|
966
|
+
const parsed = parsedConfig ?? {};
|
|
967
|
+
const compilerOptions = parsed.compilerOptions ?? {};
|
|
968
|
+
const rawPaths = compilerOptions.paths ?? {};
|
|
969
|
+
const paths = {};
|
|
970
|
+
for (const [key, value] of Object.entries(rawPaths)) {
|
|
971
|
+
if (!Array.isArray(value)) {
|
|
972
|
+
continue;
|
|
973
|
+
}
|
|
974
|
+
const targets = value.filter((entry) => typeof entry === "string");
|
|
975
|
+
if (targets.length > 0) {
|
|
976
|
+
paths[key] = targets;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
const aliasTarget = srcDir === "." ? "*" : `${srcDir}/*`;
|
|
980
|
+
const alreadyConfigured = compilerOptions.baseUrl === "." && Array.isArray(paths["@/*"]) && paths["@/*"][0] === aliasTarget;
|
|
981
|
+
if (alreadyConfigured) {
|
|
982
|
+
return { path: configPath };
|
|
983
|
+
}
|
|
984
|
+
const nextConfig = {
|
|
985
|
+
...parsed,
|
|
986
|
+
compilerOptions: {
|
|
987
|
+
...compilerOptions,
|
|
988
|
+
baseUrl: ".",
|
|
989
|
+
paths: {
|
|
990
|
+
...paths,
|
|
991
|
+
"@/*": [aliasTarget]
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
};
|
|
995
|
+
try {
|
|
996
|
+
await fs4.writeFile(configPath, `${JSON.stringify(nextConfig, null, 2)}
|
|
997
|
+
`);
|
|
998
|
+
return { path: configPath, [existedBefore ? "updated" : "created"]: true };
|
|
999
|
+
} catch {
|
|
1000
|
+
return { path: configPath, skipped: true };
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
var initCommand = new Command2("init").description("Initialize Dinachi UI in your project").option("--skip-install", "Skip package installation").action(async (options) => {
|
|
602
1004
|
console.log(chalk2.bold.cyan("\u{1F3A8} Welcome to Dinachi UI!"));
|
|
603
1005
|
console.log();
|
|
604
|
-
const
|
|
605
|
-
|
|
1006
|
+
const projectRoot = process.cwd();
|
|
1007
|
+
const packageJsonPath = path4.join(projectRoot, "package.json");
|
|
1008
|
+
if (!fs4.existsSync(packageJsonPath)) {
|
|
606
1009
|
console.log(chalk2.red("\u274C No package.json found. Please run this command in a valid project."));
|
|
607
1010
|
process.exit(1);
|
|
608
1011
|
}
|
|
@@ -629,69 +1032,91 @@ var initCommand = new Command2("init").description("Initialize Dinachi UI in you
|
|
|
629
1032
|
}
|
|
630
1033
|
const spinner = ora2("Setting up Dinachi UI...").start();
|
|
631
1034
|
try {
|
|
632
|
-
const normalizedComponentsPath =
|
|
633
|
-
const normalizedUtilsPath =
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
const
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
}
|
|
642
|
-
`;
|
|
643
|
-
await fs3.writeFile(path3.join(normalizedUtilsPath, "utils.ts"), utilsContent);
|
|
1035
|
+
const normalizedComponentsPath = normalizeProjectPath(response.componentsPath, projectRoot);
|
|
1036
|
+
const normalizedUtilsPath = normalizeProjectPath(response.utilsPath, projectRoot);
|
|
1037
|
+
const componentsDirPath = path4.resolve(projectRoot, normalizedComponentsPath);
|
|
1038
|
+
const utilsDirPath = path4.resolve(projectRoot, normalizedUtilsPath);
|
|
1039
|
+
const utilsFilePath = path4.join(utilsDirPath, "utils.ts");
|
|
1040
|
+
await fs4.ensureDir(componentsDirPath);
|
|
1041
|
+
await fs4.ensureDir(utilsDirPath);
|
|
1042
|
+
const utilsContent = createUtilsFileContent();
|
|
1043
|
+
await fs4.writeFile(utilsFilePath, utilsContent);
|
|
644
1044
|
spinner.text = "Installing dependencies...";
|
|
645
|
-
const deps = [
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
const
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
ui: uiAlias,
|
|
672
|
-
lib: libAlias,
|
|
673
|
-
hooks: `${pathToAlias(projectConfig.srcDir)}/hooks`
|
|
1045
|
+
const deps = ["class-variance-authority", "clsx", "tailwind-merge"];
|
|
1046
|
+
if (!options.skipInstall) {
|
|
1047
|
+
const packageManager = detectPackageManager(projectRoot);
|
|
1048
|
+
const installCmd = getInstallCommand(packageManager, deps.map(toInstallSpec));
|
|
1049
|
+
execSync2(installCmd, { stdio: "inherit", cwd: projectRoot });
|
|
1050
|
+
}
|
|
1051
|
+
const hooksPath = projectConfig.srcDir === "." ? "hooks" : path4.join(projectConfig.srcDir, "hooks").replace(/\\/g, "/");
|
|
1052
|
+
const configContent = JSON.stringify(
|
|
1053
|
+
{
|
|
1054
|
+
style: "default",
|
|
1055
|
+
rsc: projectConfig.framework === "next.js",
|
|
1056
|
+
tsx: true,
|
|
1057
|
+
tailwind: {
|
|
1058
|
+
config: projectConfig.tailwindConfig,
|
|
1059
|
+
css: projectConfig.cssPath,
|
|
1060
|
+
baseColor: "slate",
|
|
1061
|
+
cssVariables: true
|
|
1062
|
+
},
|
|
1063
|
+
aliases: {
|
|
1064
|
+
components: toConfigPath(path4.dirname(normalizedComponentsPath)),
|
|
1065
|
+
utils: toConfigPath(path4.join(normalizedUtilsPath, "utils")),
|
|
1066
|
+
ui: toConfigPath(normalizedComponentsPath),
|
|
1067
|
+
lib: toConfigPath(normalizedUtilsPath),
|
|
1068
|
+
hooks: toConfigPath(hooksPath)
|
|
1069
|
+
},
|
|
1070
|
+
iconLibrary: "lucide"
|
|
674
1071
|
},
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
1072
|
+
null,
|
|
1073
|
+
2
|
|
1074
|
+
);
|
|
1075
|
+
await fs4.writeFile(path4.join(projectRoot, "components.json"), `${configContent}
|
|
1076
|
+
`);
|
|
1077
|
+
const aliasConfigUpdate = await ensureAtAlias(projectRoot, projectConfig.srcDir, projectConfig.isTypeScript);
|
|
678
1078
|
spinner.succeed("\u2705 Dinachi UI setup complete!");
|
|
679
1079
|
console.log();
|
|
680
1080
|
console.log("Next steps:");
|
|
681
1081
|
console.log(` 1. Add a component: ${chalk2.cyan("npx @dinachi/cli add button")}`);
|
|
682
|
-
console.log(` 2. Components will be installed to: ${chalk2.cyan(
|
|
683
|
-
console.log(` 3. Utils available at: ${chalk2.cyan(
|
|
1082
|
+
console.log(` 2. Components will be installed to: ${chalk2.cyan(componentsDirPath)}`);
|
|
1083
|
+
console.log(` 3. Utils available at: ${chalk2.cyan(utilsFilePath)}`);
|
|
1084
|
+
console.log();
|
|
1085
|
+
if (aliasConfigUpdate.created) {
|
|
1086
|
+
console.log(` ${chalk2.green("+")} Added @/* path alias in ${aliasConfigUpdate.path}`);
|
|
1087
|
+
} else if (aliasConfigUpdate.updated) {
|
|
1088
|
+
console.log(` ${chalk2.blue("~")} Updated @/* path alias in ${aliasConfigUpdate.path}`);
|
|
1089
|
+
} else if (aliasConfigUpdate.skipped) {
|
|
1090
|
+
console.log(
|
|
1091
|
+
` ${chalk2.yellow("!")} Could not update ${aliasConfigUpdate.path}. Configure @/* manually if you use alias imports.`
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
if (!projectConfig.isTypeScript) {
|
|
1095
|
+
console.log();
|
|
1096
|
+
console.log(
|
|
1097
|
+
chalk2.yellow(
|
|
1098
|
+
"\u26A0\uFE0F Dinachi components are TypeScript-first. Your project can still consume TSX files, but type-check tooling is recommended."
|
|
1099
|
+
)
|
|
1100
|
+
);
|
|
1101
|
+
}
|
|
684
1102
|
if (projectConfig.framework === "next.js") {
|
|
685
1103
|
console.log();
|
|
686
1104
|
console.log(chalk2.blue("\u{1F4DD} Next.js specific notes:"));
|
|
687
|
-
console.log(
|
|
688
|
-
console.log(
|
|
1105
|
+
console.log(" - RSC (React Server Components) enabled in config");
|
|
1106
|
+
console.log(' - Add "use client" for interactive components where needed');
|
|
689
1107
|
console.log(` - Tailwind config: ${chalk2.cyan(projectConfig.tailwindConfig)}`);
|
|
690
1108
|
} else if (projectConfig.framework === "remix") {
|
|
691
1109
|
console.log();
|
|
692
1110
|
console.log(chalk2.blue("\u{1F4DD} Remix specific notes:"));
|
|
693
|
-
console.log(` - Components
|
|
694
|
-
console.log(` -
|
|
1111
|
+
console.log(` - Components directory: ${chalk2.cyan(componentsDirPath)}`);
|
|
1112
|
+
console.log(` - Utilities directory: ${chalk2.cyan(utilsDirPath)}`);
|
|
1113
|
+
}
|
|
1114
|
+
if (options.skipInstall) {
|
|
1115
|
+
console.log();
|
|
1116
|
+
console.log("Dependencies to install manually:");
|
|
1117
|
+
deps.forEach((dep) => {
|
|
1118
|
+
console.log(` ${chalk2.yellow("\u2022")} ${toInstallSpec(dep)}`);
|
|
1119
|
+
});
|
|
695
1120
|
}
|
|
696
1121
|
console.log();
|
|
697
1122
|
console.log("\u{1F4A1} Tip: Install globally for shorter commands:");
|
|
@@ -702,42 +1127,17 @@ export function cn(...inputs: ClassValue[]) {
|
|
|
702
1127
|
process.exit(1);
|
|
703
1128
|
}
|
|
704
1129
|
});
|
|
705
|
-
function normalizePath(inputPath) {
|
|
706
|
-
return inputPath.replace(/^\.\//, "").replace(/\/$/, "");
|
|
707
|
-
}
|
|
708
|
-
function pathToAlias(filePath) {
|
|
709
|
-
const normalized = normalizePath(filePath);
|
|
710
|
-
return `@/${normalized}`;
|
|
711
|
-
}
|
|
712
|
-
function getPackageManager2() {
|
|
713
|
-
if (fs3.existsSync("bun.lockb") || fs3.existsSync("bun.lock")) return "bun";
|
|
714
|
-
if (fs3.existsSync("pnpm-lock.yaml")) return "pnpm";
|
|
715
|
-
if (fs3.existsSync("yarn.lock")) return "yarn";
|
|
716
|
-
return "npm";
|
|
717
|
-
}
|
|
718
|
-
function getInstallCommand2(pm, deps) {
|
|
719
|
-
const depsStr = deps.join(" ");
|
|
720
|
-
switch (pm) {
|
|
721
|
-
case "bun":
|
|
722
|
-
return `bun add ${depsStr}`;
|
|
723
|
-
case "pnpm":
|
|
724
|
-
return `pnpm add ${depsStr}`;
|
|
725
|
-
case "yarn":
|
|
726
|
-
return `yarn add ${depsStr}`;
|
|
727
|
-
default:
|
|
728
|
-
return `npm install ${depsStr}`;
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
1130
|
function detectProjectType() {
|
|
732
|
-
const packageJsonPath =
|
|
733
|
-
if (!
|
|
1131
|
+
const packageJsonPath = path4.join(process.cwd(), "package.json");
|
|
1132
|
+
if (!fs4.existsSync(packageJsonPath)) {
|
|
734
1133
|
return getDefaultConfig("react", false);
|
|
735
1134
|
}
|
|
736
|
-
const packageJson = JSON.parse(
|
|
737
|
-
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
738
|
-
const hasSrcDir =
|
|
739
|
-
const hasAppDir =
|
|
740
|
-
const hasSrcAppDir =
|
|
1135
|
+
const packageJson = JSON.parse(fs4.readFileSync(packageJsonPath, "utf-8"));
|
|
1136
|
+
const deps = { ...packageJson.dependencies ?? {}, ...packageJson.devDependencies ?? {} };
|
|
1137
|
+
const hasSrcDir = fs4.existsSync(path4.join(process.cwd(), "src"));
|
|
1138
|
+
const hasAppDir = fs4.existsSync(path4.join(process.cwd(), "app"));
|
|
1139
|
+
const hasSrcAppDir = fs4.existsSync(path4.join(process.cwd(), "src", "app"));
|
|
1140
|
+
const isTypeScript = fs4.existsSync(path4.join(process.cwd(), "tsconfig.json")) || fs4.existsSync(path4.join(process.cwd(), "tsconfig.base.json")) || Boolean(deps.typescript);
|
|
741
1141
|
const tailwindConfig = detectTailwindConfig();
|
|
742
1142
|
const cssPath = detectCssPath(hasSrcDir, hasSrcAppDir);
|
|
743
1143
|
if (deps.next) {
|
|
@@ -748,7 +1148,8 @@ function detectProjectType() {
|
|
|
748
1148
|
utilsPath: "./src/lib",
|
|
749
1149
|
tailwindConfig,
|
|
750
1150
|
cssPath,
|
|
751
|
-
srcDir: "src"
|
|
1151
|
+
srcDir: "src",
|
|
1152
|
+
isTypeScript
|
|
752
1153
|
};
|
|
753
1154
|
}
|
|
754
1155
|
if (hasAppDir && !hasSrcDir) {
|
|
@@ -758,7 +1159,8 @@ function detectProjectType() {
|
|
|
758
1159
|
utilsPath: "./lib",
|
|
759
1160
|
tailwindConfig,
|
|
760
1161
|
cssPath,
|
|
761
|
-
srcDir: "."
|
|
1162
|
+
srcDir: ".",
|
|
1163
|
+
isTypeScript
|
|
762
1164
|
};
|
|
763
1165
|
}
|
|
764
1166
|
return {
|
|
@@ -767,7 +1169,8 @@ function detectProjectType() {
|
|
|
767
1169
|
utilsPath: hasSrcDir ? "./src/lib" : "./lib",
|
|
768
1170
|
tailwindConfig,
|
|
769
1171
|
cssPath,
|
|
770
|
-
srcDir: hasSrcDir ? "src" : "."
|
|
1172
|
+
srcDir: hasSrcDir ? "src" : ".",
|
|
1173
|
+
isTypeScript
|
|
771
1174
|
};
|
|
772
1175
|
}
|
|
773
1176
|
if (deps.vite || deps["@vitejs/plugin-react"]) {
|
|
@@ -777,7 +1180,8 @@ function detectProjectType() {
|
|
|
777
1180
|
utilsPath: hasSrcDir ? "./src/lib" : "./lib",
|
|
778
1181
|
tailwindConfig,
|
|
779
1182
|
cssPath,
|
|
780
|
-
srcDir: hasSrcDir ? "src" : "."
|
|
1183
|
+
srcDir: hasSrcDir ? "src" : ".",
|
|
1184
|
+
isTypeScript
|
|
781
1185
|
};
|
|
782
1186
|
}
|
|
783
1187
|
if (deps["react-scripts"]) {
|
|
@@ -787,7 +1191,8 @@ function detectProjectType() {
|
|
|
787
1191
|
utilsPath: "./src/lib",
|
|
788
1192
|
tailwindConfig,
|
|
789
1193
|
cssPath,
|
|
790
|
-
srcDir: "src"
|
|
1194
|
+
srcDir: "src",
|
|
1195
|
+
isTypeScript
|
|
791
1196
|
};
|
|
792
1197
|
}
|
|
793
1198
|
if (deps["@remix-run/react"]) {
|
|
@@ -797,62 +1202,79 @@ function detectProjectType() {
|
|
|
797
1202
|
utilsPath: "./app/lib",
|
|
798
1203
|
tailwindConfig,
|
|
799
1204
|
cssPath: detectCssPath(false, false, true),
|
|
800
|
-
srcDir: "app"
|
|
1205
|
+
srcDir: "app",
|
|
1206
|
+
isTypeScript
|
|
801
1207
|
};
|
|
802
1208
|
}
|
|
803
1209
|
return getDefaultConfig("react", hasSrcDir);
|
|
804
1210
|
}
|
|
805
1211
|
function getDefaultConfig(framework, hasSrcDir) {
|
|
1212
|
+
const isTypeScript = fs4.existsSync(path4.join(process.cwd(), "tsconfig.json")) || fs4.existsSync(path4.join(process.cwd(), "tsconfig.base.json"));
|
|
806
1213
|
return {
|
|
807
1214
|
framework,
|
|
808
1215
|
componentsPath: hasSrcDir ? "./src/components/ui" : "./components/ui",
|
|
809
1216
|
utilsPath: hasSrcDir ? "./src/lib" : "./lib",
|
|
810
1217
|
tailwindConfig: detectTailwindConfig(),
|
|
811
1218
|
cssPath: hasSrcDir ? "src/index.css" : "index.css",
|
|
812
|
-
srcDir: hasSrcDir ? "src" : "."
|
|
1219
|
+
srcDir: hasSrcDir ? "src" : ".",
|
|
1220
|
+
isTypeScript
|
|
813
1221
|
};
|
|
814
1222
|
}
|
|
815
1223
|
function detectTailwindConfig() {
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
1224
|
+
const configCandidates = [
|
|
1225
|
+
"tailwind.config.ts",
|
|
1226
|
+
"tailwind.config.js",
|
|
1227
|
+
"tailwind.config.mjs",
|
|
1228
|
+
"tailwind.config.cjs",
|
|
1229
|
+
"tailwind.config.cts",
|
|
1230
|
+
"tailwind.config.mts"
|
|
1231
|
+
];
|
|
1232
|
+
for (const config of configCandidates) {
|
|
1233
|
+
if (fs4.existsSync(path4.join(process.cwd(), config))) {
|
|
1234
|
+
return config;
|
|
1235
|
+
}
|
|
824
1236
|
}
|
|
825
1237
|
return "tailwind.config.js";
|
|
826
1238
|
}
|
|
827
1239
|
function detectCssPath(hasSrcDir, hasSrcAppDir, isRemix = false) {
|
|
828
1240
|
const cwd = process.cwd();
|
|
829
1241
|
const possiblePaths = [
|
|
830
|
-
// Next.js App Router
|
|
831
1242
|
"app/globals.css",
|
|
832
1243
|
"src/app/globals.css",
|
|
833
|
-
// Next.js Pages / General
|
|
834
1244
|
"styles/globals.css",
|
|
835
1245
|
"src/styles/globals.css",
|
|
836
|
-
// Vite / CRA
|
|
837
1246
|
"src/index.css",
|
|
838
1247
|
"index.css",
|
|
839
|
-
// Remix
|
|
840
1248
|
"app/tailwind.css",
|
|
841
1249
|
"app/styles/tailwind.css"
|
|
842
1250
|
];
|
|
843
1251
|
for (const cssPath of possiblePaths) {
|
|
844
|
-
if (
|
|
1252
|
+
if (fs4.existsSync(path4.join(cwd, cssPath))) {
|
|
845
1253
|
return cssPath;
|
|
846
1254
|
}
|
|
847
1255
|
}
|
|
848
1256
|
if (isRemix) return "app/tailwind.css";
|
|
849
1257
|
if (hasSrcAppDir) return "src/app/globals.css";
|
|
850
1258
|
if (hasSrcDir) return "src/index.css";
|
|
851
|
-
return "
|
|
1259
|
+
return "index.css";
|
|
852
1260
|
}
|
|
853
1261
|
|
|
854
1262
|
// src/index.ts
|
|
1263
|
+
import fs5 from "fs";
|
|
1264
|
+
import path5 from "path";
|
|
1265
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
855
1266
|
var program = new Command3();
|
|
856
|
-
|
|
1267
|
+
var __filename3 = fileURLToPath3(import.meta.url);
|
|
1268
|
+
var __dirname3 = path5.dirname(__filename3);
|
|
1269
|
+
function getCliVersion() {
|
|
1270
|
+
try {
|
|
1271
|
+
const packageJsonPath = path5.resolve(__dirname3, "../package.json");
|
|
1272
|
+
const packageJson = JSON.parse(fs5.readFileSync(packageJsonPath, "utf-8"));
|
|
1273
|
+
return packageJson.version ?? "0.0.0";
|
|
1274
|
+
} catch {
|
|
1275
|
+
return "0.0.0";
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
program.name("dinachi").description("Add Dinachi UI components to your project").version(getCliVersion());
|
|
857
1279
|
program.addCommand(addCommand).addCommand(initCommand);
|
|
858
1280
|
program.parse();
|