@metacells/mcellui-cli 0.1.5 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +466 -227
- package/package.json +9 -1
package/dist/index.js
CHANGED
|
@@ -2,10 +2,84 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command as Command9 } from "commander";
|
|
5
|
+
import chalk11 from "chalk";
|
|
6
|
+
|
|
7
|
+
// src/utils/errors.ts
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
function handleError(error) {
|
|
10
|
+
process.stderr.write("\n");
|
|
11
|
+
process.stderr.write(chalk.red(`Error: ${error.message}
|
|
12
|
+
`));
|
|
13
|
+
if (error.hint) {
|
|
14
|
+
process.stderr.write("\n");
|
|
15
|
+
process.stderr.write(chalk.dim(error.hint + "\n"));
|
|
16
|
+
}
|
|
17
|
+
process.stderr.write("\n");
|
|
18
|
+
process.exit(error.exitCode ?? 1);
|
|
19
|
+
}
|
|
20
|
+
var errors = {
|
|
21
|
+
/**
|
|
22
|
+
* Error when no valid project is found
|
|
23
|
+
*/
|
|
24
|
+
noProject() {
|
|
25
|
+
return handleError({
|
|
26
|
+
message: "Could not find a valid Expo/React Native project",
|
|
27
|
+
hint: "Run this command from a project directory containing package.json",
|
|
28
|
+
code: "NO_PROJECT",
|
|
29
|
+
exitCode: 1
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
/**
|
|
33
|
+
* Error when project is not initialized with mcellui
|
|
34
|
+
*/
|
|
35
|
+
notInitialized() {
|
|
36
|
+
return handleError({
|
|
37
|
+
message: "Project not initialized",
|
|
38
|
+
hint: "Run: npx mcellui init",
|
|
39
|
+
code: "NOT_INITIALIZED",
|
|
40
|
+
exitCode: 1
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
/**
|
|
44
|
+
* Error when component registry fetch fails
|
|
45
|
+
*/
|
|
46
|
+
registryFetch(cause) {
|
|
47
|
+
return handleError({
|
|
48
|
+
message: "Failed to fetch component registry",
|
|
49
|
+
hint: cause ? `${cause}
|
|
50
|
+
|
|
51
|
+
Check your internet connection and try again` : "Check your internet connection and try again",
|
|
52
|
+
code: "REGISTRY_FETCH_FAILED",
|
|
53
|
+
exitCode: 1
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
/**
|
|
57
|
+
* Error when component is not found in registry
|
|
58
|
+
*/
|
|
59
|
+
componentNotFound(name) {
|
|
60
|
+
return handleError({
|
|
61
|
+
message: `Component "${name}" not found in registry`,
|
|
62
|
+
hint: "Run: npx mcellui list",
|
|
63
|
+
code: "COMPONENT_NOT_FOUND",
|
|
64
|
+
exitCode: 1
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
/**
|
|
68
|
+
* Error when configuration is invalid
|
|
69
|
+
*/
|
|
70
|
+
configInvalid(detail) {
|
|
71
|
+
return handleError({
|
|
72
|
+
message: "Invalid configuration",
|
|
73
|
+
hint: detail || "Check mcellui.config.ts",
|
|
74
|
+
code: "CONFIG_INVALID",
|
|
75
|
+
exitCode: 1
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
};
|
|
5
79
|
|
|
6
80
|
// src/commands/init.ts
|
|
7
81
|
import { Command } from "commander";
|
|
8
|
-
import
|
|
82
|
+
import chalk3 from "chalk";
|
|
9
83
|
import ora from "ora";
|
|
10
84
|
import prompts from "prompts";
|
|
11
85
|
import fs2 from "fs-extra";
|
|
@@ -16,7 +90,7 @@ import fs from "fs-extra";
|
|
|
16
90
|
import path from "path";
|
|
17
91
|
import { fileURLToPath } from "url";
|
|
18
92
|
import createJiti from "jiti";
|
|
19
|
-
import
|
|
93
|
+
import chalk2 from "chalk";
|
|
20
94
|
|
|
21
95
|
// src/utils/config-schema.ts
|
|
22
96
|
import { z } from "zod";
|
|
@@ -115,11 +189,11 @@ function validateConfig(config) {
|
|
|
115
189
|
if (result.success) {
|
|
116
190
|
return { success: true, data: result.data };
|
|
117
191
|
}
|
|
118
|
-
const
|
|
192
|
+
const errors2 = result.error.issues.map((issue) => {
|
|
119
193
|
const path12 = issue.path.join(".");
|
|
120
194
|
return path12 ? `${path12}: ${issue.message}` : issue.message;
|
|
121
195
|
});
|
|
122
|
-
return { success: false, errors };
|
|
196
|
+
return { success: false, errors: errors2 };
|
|
123
197
|
}
|
|
124
198
|
function validateConfigOrThrow(config, configPath) {
|
|
125
199
|
const result = validateConfig(config);
|
|
@@ -129,7 +203,7 @@ function validateConfigOrThrow(config, configPath) {
|
|
|
129
203
|
`Invalid configuration in ${configPath}:
|
|
130
204
|
${errorList}
|
|
131
205
|
|
|
132
|
-
See https://
|
|
206
|
+
See https://mcellui.dev/docs/config for valid options.`
|
|
133
207
|
);
|
|
134
208
|
}
|
|
135
209
|
return result.data;
|
|
@@ -238,7 +312,7 @@ async function getConfig(projectRoot) {
|
|
|
238
312
|
return resolveConfig(validatedConfig);
|
|
239
313
|
} catch (error) {
|
|
240
314
|
if (error instanceof Error && error.message.includes("Invalid configuration")) {
|
|
241
|
-
console.error(
|
|
315
|
+
console.error(chalk2.red(error.message));
|
|
242
316
|
throw error;
|
|
243
317
|
}
|
|
244
318
|
throw error;
|
|
@@ -259,10 +333,10 @@ async function loadTsConfig(configPath) {
|
|
|
259
333
|
return resolveConfig(validatedConfig);
|
|
260
334
|
} catch (error) {
|
|
261
335
|
if (error instanceof Error && error.message.includes("Invalid configuration")) {
|
|
262
|
-
console.error(
|
|
336
|
+
console.error(chalk2.red(error.message));
|
|
263
337
|
throw error;
|
|
264
338
|
}
|
|
265
|
-
console.error(
|
|
339
|
+
console.error(chalk2.red("Failed to load config:"), error);
|
|
266
340
|
return getDefaultConfig();
|
|
267
341
|
}
|
|
268
342
|
}
|
|
@@ -274,10 +348,10 @@ async function loadJsConfig(configPath) {
|
|
|
274
348
|
return resolveConfig(validatedConfig);
|
|
275
349
|
} catch (error) {
|
|
276
350
|
if (error instanceof Error && error.message.includes("Invalid configuration")) {
|
|
277
|
-
console.error(
|
|
351
|
+
console.error(chalk2.red(error.message));
|
|
278
352
|
throw error;
|
|
279
353
|
}
|
|
280
|
-
console.error(
|
|
354
|
+
console.error(chalk2.red("Failed to load config:"), error);
|
|
281
355
|
return getDefaultConfig();
|
|
282
356
|
}
|
|
283
357
|
}
|
|
@@ -311,27 +385,25 @@ var initCommand = new Command().name("init").description("Initialize mcellui in
|
|
|
311
385
|
const cwd = path2.resolve(options.cwd);
|
|
312
386
|
const projectRoot = await getProjectRoot(cwd);
|
|
313
387
|
if (!projectRoot) {
|
|
314
|
-
|
|
315
|
-
console.log(chalk2.dim("Make sure you run this command in a project with package.json"));
|
|
316
|
-
process.exit(1);
|
|
388
|
+
errors.noProject();
|
|
317
389
|
}
|
|
318
390
|
console.log();
|
|
319
|
-
console.log(
|
|
320
|
-
console.log(
|
|
391
|
+
console.log(chalk3.bold("Welcome to mcellui!"));
|
|
392
|
+
console.log(chalk3.dim("The copy-paste component library for Expo/React Native"));
|
|
321
393
|
console.log();
|
|
322
394
|
const projectType = await detectProjectType(projectRoot);
|
|
323
|
-
console.log(
|
|
395
|
+
console.log(chalk3.dim(`Detected: ${projectType}`));
|
|
324
396
|
const configPath = path2.join(projectRoot, "mcellui.config.ts");
|
|
325
397
|
const legacyConfigPath = path2.join(projectRoot, "nativeui.config.ts");
|
|
326
398
|
if (await fs2.pathExists(configPath)) {
|
|
327
|
-
console.log(
|
|
328
|
-
console.log(
|
|
399
|
+
console.log(chalk3.yellow("Project already initialized."));
|
|
400
|
+
console.log(chalk3.dim(`Config found at: ${configPath}`));
|
|
329
401
|
return;
|
|
330
402
|
}
|
|
331
403
|
if (await fs2.pathExists(legacyConfigPath)) {
|
|
332
|
-
console.log(
|
|
333
|
-
console.log(
|
|
334
|
-
console.log(
|
|
404
|
+
console.log(chalk3.yellow("Project already initialized with legacy config."));
|
|
405
|
+
console.log(chalk3.dim(`Config found at: ${legacyConfigPath}`));
|
|
406
|
+
console.log(chalk3.dim("Consider renaming to mcellui.config.ts"));
|
|
335
407
|
return;
|
|
336
408
|
}
|
|
337
409
|
let config = {
|
|
@@ -364,6 +436,9 @@ var initCommand = new Command().name("init").description("Initialize mcellui in
|
|
|
364
436
|
]
|
|
365
437
|
}
|
|
366
438
|
]);
|
|
439
|
+
if (response.componentsPath === void 0) {
|
|
440
|
+
process.exit(0);
|
|
441
|
+
}
|
|
367
442
|
config = { ...config, ...response };
|
|
368
443
|
}
|
|
369
444
|
spinner.start("Creating configuration...");
|
|
@@ -402,7 +477,7 @@ export default defineConfig({
|
|
|
402
477
|
// },
|
|
403
478
|
|
|
404
479
|
// ============================================
|
|
405
|
-
// CLI Configuration (used by npx
|
|
480
|
+
// CLI Configuration (used by npx mcellui add)
|
|
406
481
|
// ============================================
|
|
407
482
|
|
|
408
483
|
// Path where components will be installed
|
|
@@ -472,25 +547,27 @@ export function cn(...inputs: StyleInput[]): Style {
|
|
|
472
547
|
);
|
|
473
548
|
spinner.succeed("Utilities installed");
|
|
474
549
|
console.log();
|
|
475
|
-
console.log(
|
|
550
|
+
console.log(chalk3.green("Success!") + " mcellui initialized.");
|
|
476
551
|
console.log();
|
|
477
552
|
console.log("Next steps:");
|
|
478
|
-
console.log(
|
|
479
|
-
console.log(
|
|
553
|
+
console.log(chalk3.dim(" 1."), "Add your first component:");
|
|
554
|
+
console.log(chalk3.cyan(" npx mcellui add button"));
|
|
480
555
|
console.log();
|
|
481
|
-
console.log(
|
|
482
|
-
console.log(
|
|
556
|
+
console.log(chalk3.dim(" 2."), "Browse available components:");
|
|
557
|
+
console.log(chalk3.cyan(" npx mcellui list"));
|
|
483
558
|
console.log();
|
|
484
559
|
} catch (error) {
|
|
485
560
|
spinner.fail("Failed to initialize");
|
|
486
|
-
|
|
487
|
-
|
|
561
|
+
handleError({
|
|
562
|
+
message: "Initialization failed",
|
|
563
|
+
hint: error instanceof Error ? error.message : "Check file permissions and try again"
|
|
564
|
+
});
|
|
488
565
|
}
|
|
489
566
|
});
|
|
490
567
|
|
|
491
568
|
// src/commands/add.ts
|
|
492
569
|
import { Command as Command2 } from "commander";
|
|
493
|
-
import
|
|
570
|
+
import chalk4 from "chalk";
|
|
494
571
|
import ora2 from "ora";
|
|
495
572
|
import prompts2 from "prompts";
|
|
496
573
|
import fs5 from "fs-extra";
|
|
@@ -508,6 +585,54 @@ var REGISTRY_URL = hasEnvOverride ? process.env.MCELLUI_REGISTRY_URL || process.
|
|
|
508
585
|
function getLocalRegistryPath() {
|
|
509
586
|
return path3.resolve(__dirname2, "..", "..", "registry");
|
|
510
587
|
}
|
|
588
|
+
function sleep(ms) {
|
|
589
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
590
|
+
}
|
|
591
|
+
function isNetworkError(error) {
|
|
592
|
+
if (!error) return false;
|
|
593
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
594
|
+
return true;
|
|
595
|
+
}
|
|
596
|
+
const err = error;
|
|
597
|
+
const errorCodes = ["ECONNRESET", "ENOTFOUND", "ETIMEDOUT", "ECONNREFUSED", "ECONNABORTED"];
|
|
598
|
+
if (err.code && errorCodes.includes(err.code)) {
|
|
599
|
+
return true;
|
|
600
|
+
}
|
|
601
|
+
if (err.message && typeof err.message === "string") {
|
|
602
|
+
const message = err.message.toLowerCase();
|
|
603
|
+
if (errorCodes.some((code) => message.includes(code.toLowerCase()))) {
|
|
604
|
+
return true;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
if (err.cause) {
|
|
608
|
+
return isNetworkError(err.cause);
|
|
609
|
+
}
|
|
610
|
+
return false;
|
|
611
|
+
}
|
|
612
|
+
async function fetchWithRetry(url, maxRetries = 3) {
|
|
613
|
+
let lastError;
|
|
614
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
615
|
+
try {
|
|
616
|
+
const controller = new AbortController();
|
|
617
|
+
const timeoutId = setTimeout(() => controller.abort(), 3e4);
|
|
618
|
+
const response = await fetch(url, {
|
|
619
|
+
signal: controller.signal
|
|
620
|
+
});
|
|
621
|
+
clearTimeout(timeoutId);
|
|
622
|
+
return response;
|
|
623
|
+
} catch (error) {
|
|
624
|
+
lastError = error;
|
|
625
|
+
if (!isNetworkError(error) || attempt === maxRetries) {
|
|
626
|
+
throw error;
|
|
627
|
+
}
|
|
628
|
+
const baseDelay = Math.min(1e3 * Math.pow(2, attempt - 1), 5e3);
|
|
629
|
+
const jitter = Math.random() * 200;
|
|
630
|
+
const delay = baseDelay + jitter;
|
|
631
|
+
await sleep(delay);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
throw lastError;
|
|
635
|
+
}
|
|
511
636
|
function isLocalMode() {
|
|
512
637
|
if (REGISTRY_URL) return false;
|
|
513
638
|
const localPath = getLocalRegistryPath();
|
|
@@ -525,18 +650,23 @@ async function getLocalRegistry() {
|
|
|
525
650
|
const registry = await fs3.readJson(registryPath);
|
|
526
651
|
return registry.components;
|
|
527
652
|
} catch (error) {
|
|
528
|
-
|
|
529
|
-
|
|
653
|
+
throw new Error(
|
|
654
|
+
"Failed to load local registry: " + (error instanceof Error ? error.message : String(error))
|
|
655
|
+
);
|
|
530
656
|
}
|
|
531
657
|
}
|
|
532
658
|
async function getRemoteRegistry() {
|
|
533
659
|
try {
|
|
534
|
-
const response = await
|
|
660
|
+
const response = await fetchWithRetry(`${REGISTRY_URL}/registry.json`);
|
|
661
|
+
if (!response.ok) {
|
|
662
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
663
|
+
}
|
|
535
664
|
const registry = await response.json();
|
|
536
665
|
return registry.components;
|
|
537
666
|
} catch (error) {
|
|
538
|
-
|
|
539
|
-
|
|
667
|
+
throw new Error(
|
|
668
|
+
"Failed to fetch registry: " + (error instanceof Error ? error.message : String(error))
|
|
669
|
+
);
|
|
540
670
|
}
|
|
541
671
|
}
|
|
542
672
|
async function fetchComponent(name) {
|
|
@@ -571,7 +701,12 @@ async function fetchLocalComponent(item) {
|
|
|
571
701
|
async function fetchRemoteComponent(item) {
|
|
572
702
|
const files = await Promise.all(
|
|
573
703
|
item.files.map(async (filePath) => {
|
|
574
|
-
const response = await
|
|
704
|
+
const response = await fetchWithRetry(`${REGISTRY_URL}/${filePath}`);
|
|
705
|
+
if (!response.ok) {
|
|
706
|
+
throw new Error(
|
|
707
|
+
`Failed to fetch ${filePath}: HTTP ${response.status} ${response.statusText}`
|
|
708
|
+
);
|
|
709
|
+
}
|
|
575
710
|
const content = await response.text();
|
|
576
711
|
const name = path3.basename(filePath);
|
|
577
712
|
return { name, content };
|
|
@@ -748,41 +883,42 @@ function getInstalledNames(installedFiles) {
|
|
|
748
883
|
}
|
|
749
884
|
|
|
750
885
|
// src/commands/add.ts
|
|
751
|
-
var addCommand = new Command2().name("add").description("Add a component to your project").argument("[components...]", "Components to add").option("-y, --yes", "Skip confirmation").option("-o, --overwrite", "Overwrite existing files").option("--cwd <path>", "Working directory", process.cwd()).action(async (components, options) => {
|
|
886
|
+
var addCommand = new Command2().name("add").description("Add a component to your project").argument("[components...]", "Components to add").option("-y, --yes", "Skip confirmation").option("-o, --overwrite", "Overwrite existing files").option("--no-barrel", "Skip index.ts barrel file generation").option("--cwd <path>", "Working directory", process.cwd()).action(async (components, options) => {
|
|
752
887
|
const spinner = ora2();
|
|
753
888
|
try {
|
|
754
889
|
const cwd = path5.resolve(options.cwd);
|
|
755
890
|
const projectRoot = await getProjectRoot(cwd);
|
|
756
891
|
if (!projectRoot) {
|
|
757
|
-
|
|
758
|
-
console.log(chalk3.dim("Run `npx nativeui init` first."));
|
|
759
|
-
process.exit(1);
|
|
892
|
+
errors.noProject();
|
|
760
893
|
}
|
|
761
894
|
const config = await getConfig(projectRoot);
|
|
762
895
|
if (!config) {
|
|
763
|
-
|
|
764
|
-
console.log(chalk3.dim("Run `npx nativeui init` first."));
|
|
765
|
-
process.exit(1);
|
|
896
|
+
errors.notInitialized();
|
|
766
897
|
}
|
|
767
898
|
if (!components.length) {
|
|
768
899
|
const registry2 = await getRegistry();
|
|
769
900
|
if (!registry2.length) {
|
|
770
|
-
|
|
771
|
-
|
|
901
|
+
handleError({
|
|
902
|
+
message: "No components found in registry",
|
|
903
|
+
hint: "Check your internet connection or try again later"
|
|
904
|
+
});
|
|
772
905
|
}
|
|
773
906
|
const { selected } = await prompts2({
|
|
774
907
|
type: "multiselect",
|
|
775
908
|
name: "selected",
|
|
776
909
|
message: "Which components would you like to add?",
|
|
777
910
|
choices: registry2.map((item) => ({
|
|
778
|
-
title: `${item.name} ${
|
|
911
|
+
title: `${item.name} ${chalk4.dim(`(${item.status})`)}`,
|
|
779
912
|
value: item.name,
|
|
780
913
|
description: item.description
|
|
781
914
|
})),
|
|
782
915
|
hint: "- Space to select, Enter to confirm"
|
|
783
916
|
});
|
|
917
|
+
if (selected === void 0) {
|
|
918
|
+
process.exit(0);
|
|
919
|
+
}
|
|
784
920
|
if (!selected?.length) {
|
|
785
|
-
console.log(
|
|
921
|
+
console.log(chalk4.dim("No components selected."));
|
|
786
922
|
return;
|
|
787
923
|
}
|
|
788
924
|
components = selected;
|
|
@@ -792,8 +928,11 @@ var addCommand = new Command2().name("add").description("Add a component to your
|
|
|
792
928
|
const { resolved, circular } = resolveDependencies(components, registry);
|
|
793
929
|
if (circular) {
|
|
794
930
|
spinner.fail("Circular dependency detected");
|
|
795
|
-
|
|
796
|
-
|
|
931
|
+
handleError({
|
|
932
|
+
message: `Circular dependency: ${formatCircularError(circular)}`,
|
|
933
|
+
hint: "Check component dependencies for cycles",
|
|
934
|
+
code: "CIRCULAR_DEPENDENCY"
|
|
935
|
+
});
|
|
797
936
|
}
|
|
798
937
|
spinner.stop();
|
|
799
938
|
const componentsDir = path5.join(projectRoot, config.componentsPath);
|
|
@@ -801,19 +940,19 @@ var addCommand = new Command2().name("add").description("Add a component to your
|
|
|
801
940
|
const installedNames = new Set(getInstalledNames(installedFiles));
|
|
802
941
|
const toInstall = options.overwrite ? resolved : resolved.filter((name) => !installedNames.has(name));
|
|
803
942
|
if (toInstall.length === 0) {
|
|
804
|
-
console.log(
|
|
805
|
-
console.log(
|
|
943
|
+
console.log(chalk4.yellow("All components are already installed."));
|
|
944
|
+
console.log(chalk4.dim("Use --overwrite to reinstall."));
|
|
806
945
|
return;
|
|
807
946
|
}
|
|
808
947
|
const requested = new Set(components);
|
|
809
948
|
const dependencies = toInstall.filter((name) => !requested.has(name));
|
|
810
949
|
console.log();
|
|
811
|
-
console.log(
|
|
950
|
+
console.log(chalk4.bold("Adding components:"));
|
|
812
951
|
for (const name of toInstall) {
|
|
813
952
|
if (requested.has(name)) {
|
|
814
|
-
console.log(
|
|
953
|
+
console.log(chalk4.dim(` - ${name}`));
|
|
815
954
|
} else {
|
|
816
|
-
console.log(
|
|
955
|
+
console.log(chalk4.dim(` - ${name} ${chalk4.cyan("(dependency)")}`));
|
|
817
956
|
}
|
|
818
957
|
}
|
|
819
958
|
console.log();
|
|
@@ -824,19 +963,25 @@ var addCommand = new Command2().name("add").description("Add a component to your
|
|
|
824
963
|
message: `Add ${dependencies.length} additional dependencies?`,
|
|
825
964
|
initial: true
|
|
826
965
|
});
|
|
966
|
+
if (confirm === void 0) {
|
|
967
|
+
process.exit(0);
|
|
968
|
+
}
|
|
827
969
|
if (!confirm) {
|
|
828
|
-
console.log(
|
|
970
|
+
console.log(chalk4.dim("Cancelled."));
|
|
829
971
|
return;
|
|
830
972
|
}
|
|
831
973
|
}
|
|
832
974
|
const allDependencies = [];
|
|
833
975
|
const allDevDependencies = [];
|
|
976
|
+
let failCount = 0;
|
|
977
|
+
const registryMap = new Map(registry.map((item) => [item.name, item]));
|
|
834
978
|
for (const componentName of toInstall) {
|
|
835
979
|
spinner.start(`Fetching ${componentName}...`);
|
|
836
980
|
try {
|
|
837
981
|
const component = await fetchComponent(componentName);
|
|
838
982
|
if (!component) {
|
|
839
983
|
spinner.fail(`Component "${componentName}" not found`);
|
|
984
|
+
failCount++;
|
|
840
985
|
continue;
|
|
841
986
|
}
|
|
842
987
|
const targetDir = path5.join(projectRoot, config.componentsPath);
|
|
@@ -851,6 +996,14 @@ var addCommand = new Command2().name("add").description("Add a component to your
|
|
|
851
996
|
await fs5.writeFile(targetPath, transformedContent);
|
|
852
997
|
}
|
|
853
998
|
spinner.succeed(`Added ${componentName}`);
|
|
999
|
+
if (requested.has(componentName)) {
|
|
1000
|
+
const registryItem = registryMap.get(componentName);
|
|
1001
|
+
if (registryItem?.props?.length) {
|
|
1002
|
+
console.log(chalk4.dim(` Props: ${registryItem.props.join(", ")}`));
|
|
1003
|
+
}
|
|
1004
|
+
const pascalName = toPascalCase(componentName);
|
|
1005
|
+
console.log(chalk4.dim(` Import: import { ${pascalName} } from '${config.alias}/components/${componentName}';`));
|
|
1006
|
+
}
|
|
854
1007
|
if (component.dependencies?.length) {
|
|
855
1008
|
allDependencies.push(...component.dependencies);
|
|
856
1009
|
}
|
|
@@ -859,36 +1012,70 @@ var addCommand = new Command2().name("add").description("Add a component to your
|
|
|
859
1012
|
}
|
|
860
1013
|
} catch (error) {
|
|
861
1014
|
spinner.fail(`Failed to add ${componentName}`);
|
|
862
|
-
console.error(
|
|
1015
|
+
console.error(chalk4.dim(String(error)));
|
|
1016
|
+
failCount++;
|
|
863
1017
|
}
|
|
864
1018
|
}
|
|
1019
|
+
if (failCount > 0) {
|
|
1020
|
+
process.exit(1);
|
|
1021
|
+
}
|
|
1022
|
+
if (options.barrel !== false) {
|
|
1023
|
+
const targetDir = path5.join(projectRoot, config.componentsPath);
|
|
1024
|
+
await generateBarrelFile(targetDir);
|
|
1025
|
+
}
|
|
865
1026
|
const uniqueDeps = [...new Set(allDependencies)];
|
|
866
1027
|
const uniqueDevDeps = [...new Set(allDevDependencies)];
|
|
867
1028
|
if (uniqueDeps.length || uniqueDevDeps.length) {
|
|
868
1029
|
console.log();
|
|
869
|
-
console.log(
|
|
1030
|
+
console.log(chalk4.bold("Install dependencies:"));
|
|
870
1031
|
if (uniqueDeps.length) {
|
|
871
|
-
console.log(
|
|
1032
|
+
console.log(chalk4.cyan(` npx expo install ${uniqueDeps.join(" ")}`));
|
|
872
1033
|
}
|
|
873
1034
|
if (uniqueDevDeps.length) {
|
|
874
|
-
console.log(
|
|
1035
|
+
console.log(chalk4.cyan(` npm install -D ${uniqueDevDeps.join(" ")}`));
|
|
875
1036
|
}
|
|
876
1037
|
}
|
|
877
1038
|
console.log();
|
|
878
|
-
console.log(
|
|
1039
|
+
console.log(chalk4.green("Done!"));
|
|
879
1040
|
} catch (error) {
|
|
880
1041
|
spinner.fail("Failed");
|
|
881
|
-
|
|
882
|
-
|
|
1042
|
+
handleError({
|
|
1043
|
+
message: "Failed to add components",
|
|
1044
|
+
hint: error instanceof Error ? error.message : "Check your network connection and try again"
|
|
1045
|
+
});
|
|
883
1046
|
}
|
|
884
1047
|
});
|
|
1048
|
+
async function generateBarrelFile(componentsDir) {
|
|
1049
|
+
if (!await fs5.pathExists(componentsDir)) {
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
const files = await fs5.readdir(componentsDir);
|
|
1053
|
+
const componentFiles = files.filter((file) => (file.endsWith(".tsx") || file.endsWith(".ts")) && file !== "index.ts" && file !== "index.tsx").sort();
|
|
1054
|
+
if (componentFiles.length === 0) {
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
const exports = componentFiles.map((file) => {
|
|
1058
|
+
const name = file.replace(/\.tsx?$/, "");
|
|
1059
|
+
return `export * from './${name}';`;
|
|
1060
|
+
}).join("\n");
|
|
1061
|
+
const content = `// Auto-generated barrel file - do not edit manually
|
|
1062
|
+
// Re-run \`npx mcellui add\` to regenerate
|
|
1063
|
+
|
|
1064
|
+
${exports}
|
|
1065
|
+
`;
|
|
1066
|
+
const indexPath = path5.join(componentsDir, "index.ts");
|
|
1067
|
+
await fs5.writeFile(indexPath, content);
|
|
1068
|
+
}
|
|
1069
|
+
function toPascalCase(str) {
|
|
1070
|
+
return str.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
1071
|
+
}
|
|
885
1072
|
|
|
886
1073
|
// src/commands/list.ts
|
|
887
1074
|
import { Command as Command3 } from "commander";
|
|
888
|
-
import
|
|
1075
|
+
import chalk5 from "chalk";
|
|
889
1076
|
import ora3 from "ora";
|
|
890
1077
|
import path6 from "path";
|
|
891
|
-
var listCommand = new Command3().name("list").description("List available or installed components").option("-c, --category <category>", "Filter by category").option("-i, --installed", "Show installed components and their sync status").option("--cwd <path>", "Working directory", process.cwd()).action(async (options) => {
|
|
1078
|
+
var listCommand = new Command3().name("list").description("List available or installed components").option("-c, --category <category>", "Filter by category").option("-i, --installed", "Show installed components and their sync status").option("--json", "Output as JSON").option("--cwd <path>", "Working directory", process.cwd()).action(async (options) => {
|
|
892
1079
|
if (options.installed) {
|
|
893
1080
|
await listInstalledComponents(options);
|
|
894
1081
|
} else {
|
|
@@ -900,8 +1087,13 @@ async function listAvailableComponents(options) {
|
|
|
900
1087
|
try {
|
|
901
1088
|
const registry = await getRegistry();
|
|
902
1089
|
spinner.stop();
|
|
1090
|
+
if (options.json) {
|
|
1091
|
+
const items = options.category ? registry.filter((item) => (item.category || "Other").toLowerCase() === options.category.toLowerCase()) : registry;
|
|
1092
|
+
console.log(JSON.stringify(items, null, 2));
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
903
1095
|
console.log();
|
|
904
|
-
console.log(
|
|
1096
|
+
console.log(chalk5.bold("Available Components"));
|
|
905
1097
|
console.log();
|
|
906
1098
|
const categories = /* @__PURE__ */ new Map();
|
|
907
1099
|
for (const item of registry) {
|
|
@@ -915,20 +1107,22 @@ async function listAvailableComponents(options) {
|
|
|
915
1107
|
categories.get(category).push(item);
|
|
916
1108
|
}
|
|
917
1109
|
for (const [category, items] of categories) {
|
|
918
|
-
console.log(
|
|
1110
|
+
console.log(chalk5.cyan.bold(`${category}`));
|
|
919
1111
|
for (const item of items) {
|
|
920
|
-
const status = item.status === "stable" ? "" :
|
|
921
|
-
console.log(` ${
|
|
922
|
-
console.log(
|
|
1112
|
+
const status = item.status === "stable" ? "" : chalk5.yellow(` [${item.status}]`);
|
|
1113
|
+
console.log(` ${chalk5.white(item.name)}${status}`);
|
|
1114
|
+
console.log(chalk5.dim(` ${item.description}`));
|
|
923
1115
|
}
|
|
924
1116
|
console.log();
|
|
925
1117
|
}
|
|
926
|
-
console.log(
|
|
1118
|
+
console.log(chalk5.dim("Add a component: npx mcellui add <component>"));
|
|
927
1119
|
console.log();
|
|
928
1120
|
} catch (error) {
|
|
929
1121
|
spinner.fail("Failed to fetch components");
|
|
930
|
-
|
|
931
|
-
|
|
1122
|
+
handleError({
|
|
1123
|
+
message: "Failed to fetch components",
|
|
1124
|
+
hint: error instanceof Error ? error.message : "Check your network connection and try again"
|
|
1125
|
+
});
|
|
932
1126
|
}
|
|
933
1127
|
}
|
|
934
1128
|
async function listInstalledComponents(options) {
|
|
@@ -937,22 +1131,23 @@ async function listInstalledComponents(options) {
|
|
|
937
1131
|
const cwd = path6.resolve(options.cwd || process.cwd());
|
|
938
1132
|
const projectRoot = await getProjectRoot(cwd);
|
|
939
1133
|
if (!projectRoot) {
|
|
940
|
-
|
|
941
|
-
console.log(chalk4.dim("Run `npx mcellui init` first."));
|
|
942
|
-
process.exit(1);
|
|
1134
|
+
errors.noProject();
|
|
943
1135
|
}
|
|
944
1136
|
const config = await getConfig(projectRoot);
|
|
945
1137
|
if (!config) {
|
|
946
|
-
|
|
947
|
-
console.log(chalk4.dim("Run `npx mcellui init` first."));
|
|
948
|
-
process.exit(1);
|
|
1138
|
+
errors.notInitialized();
|
|
949
1139
|
}
|
|
950
1140
|
spinner.start("Scanning installed components...");
|
|
951
1141
|
const componentsDir = path6.join(projectRoot, config.componentsPath);
|
|
952
1142
|
const installedFiles = await getInstalledFiles(componentsDir);
|
|
953
1143
|
if (installedFiles.length === 0) {
|
|
1144
|
+
spinner.stop();
|
|
1145
|
+
if (options.json) {
|
|
1146
|
+
console.log(JSON.stringify([], null, 2));
|
|
1147
|
+
return;
|
|
1148
|
+
}
|
|
954
1149
|
spinner.info("No components installed yet.");
|
|
955
|
-
console.log(
|
|
1150
|
+
console.log(chalk5.dim("\nAdd components with: npx mcellui add <component>"));
|
|
956
1151
|
return;
|
|
957
1152
|
}
|
|
958
1153
|
spinner.text = "Fetching registry...";
|
|
@@ -960,13 +1155,17 @@ async function listInstalledComponents(options) {
|
|
|
960
1155
|
spinner.text = "Comparing components...";
|
|
961
1156
|
const installed = await getInstallStatus(installedFiles, registry, config);
|
|
962
1157
|
spinner.stop();
|
|
1158
|
+
if (options.json) {
|
|
1159
|
+
console.log(JSON.stringify(installed, null, 2));
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
963
1162
|
const identical = installed.filter((c) => c.status === "identical");
|
|
964
1163
|
const modified = installed.filter((c) => c.status === "modified");
|
|
965
1164
|
const localOnly = installed.filter((c) => c.status === "local-only");
|
|
966
1165
|
const installedNames = new Set(installed.map((c) => c.name));
|
|
967
1166
|
const notInstalled = registry.filter((item) => !installedNames.has(item.name));
|
|
968
1167
|
console.log();
|
|
969
|
-
console.log(
|
|
1168
|
+
console.log(chalk5.bold(`Installed Components (${installed.length})`));
|
|
970
1169
|
console.log();
|
|
971
1170
|
const categories = /* @__PURE__ */ new Map();
|
|
972
1171
|
for (const comp of installed) {
|
|
@@ -978,56 +1177,58 @@ async function listInstalledComponents(options) {
|
|
|
978
1177
|
categories.get(category).push(comp);
|
|
979
1178
|
}
|
|
980
1179
|
for (const [category, components] of categories) {
|
|
981
|
-
console.log(
|
|
1180
|
+
console.log(chalk5.cyan.bold(category));
|
|
982
1181
|
for (const comp of components) {
|
|
983
1182
|
let statusIcon;
|
|
984
1183
|
let statusText;
|
|
985
1184
|
switch (comp.status) {
|
|
986
1185
|
case "identical":
|
|
987
|
-
statusIcon =
|
|
988
|
-
statusText =
|
|
1186
|
+
statusIcon = chalk5.green("\u2713");
|
|
1187
|
+
statusText = chalk5.dim("(up to date)");
|
|
989
1188
|
break;
|
|
990
1189
|
case "modified":
|
|
991
|
-
statusIcon =
|
|
992
|
-
statusText =
|
|
1190
|
+
statusIcon = chalk5.yellow("\u26A0");
|
|
1191
|
+
statusText = chalk5.yellow("(modified locally)");
|
|
993
1192
|
break;
|
|
994
1193
|
case "local-only":
|
|
995
|
-
statusIcon =
|
|
996
|
-
statusText =
|
|
1194
|
+
statusIcon = chalk5.blue("?");
|
|
1195
|
+
statusText = chalk5.dim("(custom component)");
|
|
997
1196
|
break;
|
|
998
1197
|
}
|
|
999
|
-
console.log(` ${statusIcon} ${
|
|
1198
|
+
console.log(` ${statusIcon} ${chalk5.white(comp.name)} ${statusText}`);
|
|
1000
1199
|
}
|
|
1001
1200
|
console.log();
|
|
1002
1201
|
}
|
|
1003
1202
|
if (notInstalled.length > 0) {
|
|
1004
|
-
console.log(
|
|
1203
|
+
console.log(chalk5.dim("Not Installed"));
|
|
1005
1204
|
const notInstalledNames = notInstalled.map((c) => c.name).slice(0, 10);
|
|
1006
1205
|
const remaining = notInstalled.length - 10;
|
|
1007
|
-
console.log(
|
|
1206
|
+
console.log(chalk5.dim(` ${notInstalledNames.join(", ")}${remaining > 0 ? `, ... +${remaining} more` : ""}`));
|
|
1008
1207
|
console.log();
|
|
1009
1208
|
}
|
|
1010
|
-
console.log(
|
|
1209
|
+
console.log(chalk5.dim("\u2500".repeat(50)));
|
|
1011
1210
|
const parts = [];
|
|
1012
|
-
if (identical.length > 0) parts.push(
|
|
1013
|
-
if (modified.length > 0) parts.push(
|
|
1014
|
-
if (localOnly.length > 0) parts.push(
|
|
1211
|
+
if (identical.length > 0) parts.push(chalk5.green(`${identical.length} up to date`));
|
|
1212
|
+
if (modified.length > 0) parts.push(chalk5.yellow(`${modified.length} modified`));
|
|
1213
|
+
if (localOnly.length > 0) parts.push(chalk5.blue(`${localOnly.length} custom`));
|
|
1015
1214
|
console.log(parts.join(" \u2022 "));
|
|
1016
1215
|
if (modified.length > 0) {
|
|
1017
1216
|
console.log();
|
|
1018
|
-
console.log(
|
|
1019
|
-
console.log(
|
|
1217
|
+
console.log(chalk5.dim("Sync modified components:"));
|
|
1218
|
+
console.log(chalk5.cyan(` npx mcellui diff`));
|
|
1020
1219
|
}
|
|
1021
1220
|
} catch (error) {
|
|
1022
1221
|
spinner.fail("Failed to list installed components");
|
|
1023
|
-
|
|
1024
|
-
|
|
1222
|
+
handleError({
|
|
1223
|
+
message: "Failed to list installed components",
|
|
1224
|
+
hint: error instanceof Error ? error.message : "Check your network connection and try again"
|
|
1225
|
+
});
|
|
1025
1226
|
}
|
|
1026
1227
|
}
|
|
1027
1228
|
|
|
1028
1229
|
// src/commands/doctor.ts
|
|
1029
1230
|
import { Command as Command4 } from "commander";
|
|
1030
|
-
import
|
|
1231
|
+
import chalk6 from "chalk";
|
|
1031
1232
|
import fs6 from "fs-extra";
|
|
1032
1233
|
import path7 from "path";
|
|
1033
1234
|
var REQUIRED_PEER_DEPS = [
|
|
@@ -1408,43 +1609,43 @@ async function checkExpoGo(projectRoot) {
|
|
|
1408
1609
|
}
|
|
1409
1610
|
function printReport(report) {
|
|
1410
1611
|
console.log();
|
|
1411
|
-
console.log(
|
|
1412
|
-
console.log(
|
|
1612
|
+
console.log(chalk6.bold("mcellui Doctor"));
|
|
1613
|
+
console.log(chalk6.dim("Checking your project setup..."));
|
|
1413
1614
|
console.log();
|
|
1414
|
-
console.log(
|
|
1415
|
-
console.log(
|
|
1416
|
-
console.log(
|
|
1615
|
+
console.log(chalk6.dim("Project:"), report.projectRoot);
|
|
1616
|
+
console.log(chalk6.dim("Type:"), report.projectType);
|
|
1617
|
+
console.log(chalk6.dim("Package Manager:"), report.packageManager);
|
|
1417
1618
|
console.log();
|
|
1418
|
-
console.log(
|
|
1619
|
+
console.log(chalk6.bold("Checks"));
|
|
1419
1620
|
console.log();
|
|
1420
1621
|
for (const check of report.checks) {
|
|
1421
|
-
const icon = check.status === "pass" ?
|
|
1422
|
-
const statusColor = check.status === "pass" ?
|
|
1423
|
-
console.log(` ${icon} ${
|
|
1622
|
+
const icon = check.status === "pass" ? chalk6.green("\u2713") : check.status === "warn" ? chalk6.yellow("!") : chalk6.red("\u2717");
|
|
1623
|
+
const statusColor = check.status === "pass" ? chalk6.green : check.status === "warn" ? chalk6.yellow : chalk6.red;
|
|
1624
|
+
console.log(` ${icon} ${chalk6.white(check.name)}`);
|
|
1424
1625
|
console.log(` ${statusColor(check.message)}`);
|
|
1425
1626
|
if (check.fix && check.status !== "pass") {
|
|
1426
|
-
console.log(
|
|
1627
|
+
console.log(chalk6.dim(` Fix: ${check.fix}`));
|
|
1427
1628
|
}
|
|
1428
1629
|
}
|
|
1429
1630
|
console.log();
|
|
1430
1631
|
const summaryParts = [];
|
|
1431
1632
|
if (report.passed > 0) {
|
|
1432
|
-
summaryParts.push(
|
|
1633
|
+
summaryParts.push(chalk6.green(`${report.passed} passed`));
|
|
1433
1634
|
}
|
|
1434
1635
|
if (report.warnings > 0) {
|
|
1435
|
-
summaryParts.push(
|
|
1636
|
+
summaryParts.push(chalk6.yellow(`${report.warnings} warnings`));
|
|
1436
1637
|
}
|
|
1437
1638
|
if (report.failed > 0) {
|
|
1438
|
-
summaryParts.push(
|
|
1639
|
+
summaryParts.push(chalk6.red(`${report.failed} failed`));
|
|
1439
1640
|
}
|
|
1440
|
-
console.log(
|
|
1641
|
+
console.log(chalk6.bold("Summary:"), summaryParts.join(", "));
|
|
1441
1642
|
console.log();
|
|
1442
1643
|
if (report.failed > 0) {
|
|
1443
|
-
console.log(
|
|
1644
|
+
console.log(chalk6.red("Some checks failed. Please fix the issues above."));
|
|
1444
1645
|
} else if (report.warnings > 0) {
|
|
1445
|
-
console.log(
|
|
1646
|
+
console.log(chalk6.yellow("Your project has some warnings but should work."));
|
|
1446
1647
|
} else {
|
|
1447
|
-
console.log(
|
|
1648
|
+
console.log(chalk6.green("Your project is properly configured!"));
|
|
1448
1649
|
}
|
|
1449
1650
|
console.log();
|
|
1450
1651
|
}
|
|
@@ -1453,9 +1654,7 @@ var doctorCommand = new Command4().name("doctor").description("Check project set
|
|
|
1453
1654
|
const cwd = path7.resolve(options.cwd);
|
|
1454
1655
|
const projectRoot = await getProjectRoot(cwd);
|
|
1455
1656
|
if (!projectRoot) {
|
|
1456
|
-
|
|
1457
|
-
console.log(chalk5.dim("Make sure you run this command in a project directory."));
|
|
1458
|
-
process.exit(1);
|
|
1657
|
+
errors.noProject();
|
|
1459
1658
|
}
|
|
1460
1659
|
const projectType = await detectProjectType(projectRoot);
|
|
1461
1660
|
const packageManager = await detectPackageManager(projectRoot);
|
|
@@ -1493,14 +1692,16 @@ var doctorCommand = new Command4().name("doctor").description("Check project set
|
|
|
1493
1692
|
process.exit(1);
|
|
1494
1693
|
}
|
|
1495
1694
|
} catch (error) {
|
|
1496
|
-
|
|
1497
|
-
|
|
1695
|
+
handleError({
|
|
1696
|
+
message: "Doctor check failed",
|
|
1697
|
+
hint: error instanceof Error ? error.message : "Run again with --json for details"
|
|
1698
|
+
});
|
|
1498
1699
|
}
|
|
1499
1700
|
});
|
|
1500
1701
|
|
|
1501
1702
|
// src/commands/diff.ts
|
|
1502
1703
|
import { Command as Command5 } from "commander";
|
|
1503
|
-
import
|
|
1704
|
+
import chalk7 from "chalk";
|
|
1504
1705
|
import ora4 from "ora";
|
|
1505
1706
|
import fs7 from "fs-extra";
|
|
1506
1707
|
import path8 from "path";
|
|
@@ -1511,22 +1712,18 @@ var diffCommand = new Command5().name("diff").description("Compare locally insta
|
|
|
1511
1712
|
const cwd = path8.resolve(options.cwd);
|
|
1512
1713
|
const projectRoot = await getProjectRoot(cwd);
|
|
1513
1714
|
if (!projectRoot) {
|
|
1514
|
-
|
|
1515
|
-
console.log(chalk6.dim("Run `npx mcellui init` first."));
|
|
1516
|
-
process.exit(1);
|
|
1715
|
+
errors.noProject();
|
|
1517
1716
|
}
|
|
1518
1717
|
const config = await getConfig(projectRoot);
|
|
1519
1718
|
if (!config) {
|
|
1520
|
-
|
|
1521
|
-
console.log(chalk6.dim("Run `npx mcellui init` first."));
|
|
1522
|
-
process.exit(1);
|
|
1719
|
+
errors.notInitialized();
|
|
1523
1720
|
}
|
|
1524
1721
|
spinner.start("Scanning installed components...");
|
|
1525
1722
|
const componentsDir = path8.join(projectRoot, config.componentsPath);
|
|
1526
1723
|
const installedFiles = await getInstalledFiles(componentsDir);
|
|
1527
1724
|
if (installedFiles.length === 0) {
|
|
1528
1725
|
spinner.info("No components installed yet.");
|
|
1529
|
-
console.log(
|
|
1726
|
+
console.log(chalk7.dim("\nAdd components with: npx mcellui add <component>"));
|
|
1530
1727
|
return;
|
|
1531
1728
|
}
|
|
1532
1729
|
spinner.text = "Fetching registry...";
|
|
@@ -1548,8 +1745,11 @@ var diffCommand = new Command5().name("diff").description("Compare locally insta
|
|
|
1548
1745
|
return componentFileNames.includes(fileName);
|
|
1549
1746
|
});
|
|
1550
1747
|
if (filesToCompare.length === 0) {
|
|
1551
|
-
spinner.
|
|
1552
|
-
|
|
1748
|
+
spinner.stop();
|
|
1749
|
+
handleError({
|
|
1750
|
+
message: "None of the specified components are installed",
|
|
1751
|
+
hint: "Check component names: npx mcellui list --installed"
|
|
1752
|
+
});
|
|
1553
1753
|
}
|
|
1554
1754
|
}
|
|
1555
1755
|
spinner.text = "Comparing components...";
|
|
@@ -1633,35 +1833,37 @@ var diffCommand = new Command5().name("diff").description("Compare locally insta
|
|
|
1633
1833
|
const hasChanges = results.some((r) => r.status === "modified");
|
|
1634
1834
|
process.exit(hasChanges ? 1 : 0);
|
|
1635
1835
|
} catch (error) {
|
|
1636
|
-
spinner.
|
|
1637
|
-
|
|
1638
|
-
|
|
1836
|
+
spinner.stop();
|
|
1837
|
+
handleError({
|
|
1838
|
+
message: "Failed to diff components",
|
|
1839
|
+
hint: error instanceof Error ? error.message : "Check your network connection"
|
|
1840
|
+
});
|
|
1639
1841
|
}
|
|
1640
1842
|
});
|
|
1641
1843
|
function printResults(results, listOnly) {
|
|
1642
1844
|
const identical = results.filter((r) => r.status === "identical");
|
|
1643
1845
|
const modified = results.filter((r) => r.status === "modified");
|
|
1644
1846
|
const localOnly = results.filter((r) => r.status === "local-only");
|
|
1645
|
-
const
|
|
1847
|
+
const errors2 = results.filter((r) => r.status === "error");
|
|
1646
1848
|
console.log();
|
|
1647
|
-
console.log(
|
|
1849
|
+
console.log(chalk7.bold("Comparing components..."));
|
|
1648
1850
|
console.log();
|
|
1649
1851
|
for (const result of results) {
|
|
1650
1852
|
switch (result.status) {
|
|
1651
1853
|
case "identical":
|
|
1652
|
-
console.log(`${
|
|
1854
|
+
console.log(`${chalk7.green("\u2713")} ${result.fileName} ${chalk7.dim("(identical)")}`);
|
|
1653
1855
|
break;
|
|
1654
1856
|
case "modified":
|
|
1655
|
-
console.log(`${
|
|
1857
|
+
console.log(`${chalk7.red("\u2717")} ${result.fileName} ${chalk7.yellow("(modified)")}`);
|
|
1656
1858
|
if (!listOnly && result.diff) {
|
|
1657
1859
|
printColoredDiff(result.diff);
|
|
1658
1860
|
}
|
|
1659
1861
|
break;
|
|
1660
1862
|
case "local-only":
|
|
1661
|
-
console.log(`${
|
|
1863
|
+
console.log(`${chalk7.yellow("\u26A0")} ${result.fileName} ${chalk7.dim("(not in registry)")}`);
|
|
1662
1864
|
break;
|
|
1663
1865
|
case "error":
|
|
1664
|
-
console.log(`${
|
|
1866
|
+
console.log(`${chalk7.red("!")} ${result.fileName} ${chalk7.red(`(error: ${result.error})`)}`);
|
|
1665
1867
|
break;
|
|
1666
1868
|
}
|
|
1667
1869
|
}
|
|
@@ -1670,12 +1872,12 @@ function printResults(results, listOnly) {
|
|
|
1670
1872
|
if (identical.length > 0) parts.push(`${identical.length} identical`);
|
|
1671
1873
|
if (modified.length > 0) parts.push(`${modified.length} modified`);
|
|
1672
1874
|
if (localOnly.length > 0) parts.push(`${localOnly.length} custom`);
|
|
1673
|
-
if (
|
|
1674
|
-
console.log(
|
|
1875
|
+
if (errors2.length > 0) parts.push(`${errors2.length} errors`);
|
|
1876
|
+
console.log(chalk7.dim(`Summary: ${parts.join(", ")}`));
|
|
1675
1877
|
if (modified.length > 0) {
|
|
1676
1878
|
console.log();
|
|
1677
|
-
console.log(
|
|
1678
|
-
console.log(
|
|
1879
|
+
console.log(chalk7.dim("Update modified components with:"));
|
|
1880
|
+
console.log(chalk7.cyan(` npx mcellui add ${modified.map((m) => m.name).join(" ")} --overwrite`));
|
|
1679
1881
|
}
|
|
1680
1882
|
}
|
|
1681
1883
|
function printColoredDiff(diffOutput) {
|
|
@@ -1683,20 +1885,20 @@ function printColoredDiff(diffOutput) {
|
|
|
1683
1885
|
const contentLines = lines.slice(4);
|
|
1684
1886
|
for (const line of contentLines) {
|
|
1685
1887
|
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
1686
|
-
console.log(
|
|
1888
|
+
console.log(chalk7.green(` ${line}`));
|
|
1687
1889
|
} else if (line.startsWith("-") && !line.startsWith("---")) {
|
|
1688
|
-
console.log(
|
|
1890
|
+
console.log(chalk7.red(` ${line}`));
|
|
1689
1891
|
} else if (line.startsWith("@@")) {
|
|
1690
|
-
console.log(
|
|
1892
|
+
console.log(chalk7.cyan(` ${line}`));
|
|
1691
1893
|
} else if (line.trim()) {
|
|
1692
|
-
console.log(
|
|
1894
|
+
console.log(chalk7.dim(` ${line}`));
|
|
1693
1895
|
}
|
|
1694
1896
|
}
|
|
1695
1897
|
}
|
|
1696
1898
|
|
|
1697
1899
|
// src/commands/update.ts
|
|
1698
1900
|
import { Command as Command6 } from "commander";
|
|
1699
|
-
import
|
|
1901
|
+
import chalk8 from "chalk";
|
|
1700
1902
|
import ora5 from "ora";
|
|
1701
1903
|
import prompts3 from "prompts";
|
|
1702
1904
|
import fs8 from "fs-extra";
|
|
@@ -1707,22 +1909,18 @@ var updateCommand = new Command6().name("update").description("Update installed
|
|
|
1707
1909
|
const cwd = path9.resolve(options.cwd);
|
|
1708
1910
|
const projectRoot = await getProjectRoot(cwd);
|
|
1709
1911
|
if (!projectRoot) {
|
|
1710
|
-
|
|
1711
|
-
console.log(chalk7.dim("Run `npx nativeui init` first."));
|
|
1712
|
-
process.exit(1);
|
|
1912
|
+
errors.noProject();
|
|
1713
1913
|
}
|
|
1714
1914
|
const config = await getConfig(projectRoot);
|
|
1715
1915
|
if (!config) {
|
|
1716
|
-
|
|
1717
|
-
console.log(chalk7.dim("Run `npx nativeui init` first."));
|
|
1718
|
-
process.exit(1);
|
|
1916
|
+
errors.notInitialized();
|
|
1719
1917
|
}
|
|
1720
1918
|
spinner.start("Checking for updates...");
|
|
1721
1919
|
const componentsDir = path9.join(projectRoot, config.componentsPath);
|
|
1722
1920
|
const diffs = await getComponentDiffs(componentsDir, config);
|
|
1723
1921
|
if (diffs.length === 0) {
|
|
1724
1922
|
spinner.info("No components installed yet.");
|
|
1725
|
-
console.log(
|
|
1923
|
+
console.log(chalk8.dim("\nAdd components with: npx mcellui add <component>"));
|
|
1726
1924
|
return;
|
|
1727
1925
|
}
|
|
1728
1926
|
spinner.stop();
|
|
@@ -1731,7 +1929,7 @@ var updateCommand = new Command6().name("update").description("Update installed
|
|
|
1731
1929
|
toUpdate = diffs.filter((d) => components.includes(d.name));
|
|
1732
1930
|
const notFound = components.filter((c) => !diffs.some((d) => d.name === c));
|
|
1733
1931
|
if (notFound.length > 0) {
|
|
1734
|
-
console.log(
|
|
1932
|
+
console.log(chalk8.yellow(`Components not found: ${notFound.join(", ")}`));
|
|
1735
1933
|
}
|
|
1736
1934
|
} else if (options.all) {
|
|
1737
1935
|
toUpdate = diffs;
|
|
@@ -1739,19 +1937,19 @@ var updateCommand = new Command6().name("update").description("Update installed
|
|
|
1739
1937
|
toUpdate = diffs.filter((d) => d.hasUpdate);
|
|
1740
1938
|
}
|
|
1741
1939
|
if (toUpdate.length === 0) {
|
|
1742
|
-
console.log(
|
|
1940
|
+
console.log(chalk8.green("\n\u2713 All components are up to date!"));
|
|
1743
1941
|
return;
|
|
1744
1942
|
}
|
|
1745
1943
|
console.log();
|
|
1746
|
-
console.log(
|
|
1944
|
+
console.log(chalk8.bold(`Components to update (${toUpdate.length}):`));
|
|
1747
1945
|
for (const comp of toUpdate) {
|
|
1748
|
-
const status = comp.hasUpdate ?
|
|
1749
|
-
const label = comp.hasUpdate ?
|
|
1946
|
+
const status = comp.hasUpdate ? chalk8.yellow("\u25CF") : chalk8.green("\u25CF");
|
|
1947
|
+
const label = comp.hasUpdate ? chalk8.dim("(update available)") : chalk8.dim("(re-sync)");
|
|
1750
1948
|
console.log(` ${status} ${comp.name} ${label}`);
|
|
1751
1949
|
}
|
|
1752
1950
|
console.log();
|
|
1753
1951
|
if (options.dryRun) {
|
|
1754
|
-
console.log(
|
|
1952
|
+
console.log(chalk8.dim("Dry run mode - no changes made."));
|
|
1755
1953
|
return;
|
|
1756
1954
|
}
|
|
1757
1955
|
if (!options.yes) {
|
|
@@ -1761,8 +1959,11 @@ var updateCommand = new Command6().name("update").description("Update installed
|
|
|
1761
1959
|
message: `Update ${toUpdate.length} component${toUpdate.length !== 1 ? "s" : ""}?`,
|
|
1762
1960
|
initial: true
|
|
1763
1961
|
});
|
|
1962
|
+
if (confirm === void 0) {
|
|
1963
|
+
process.exit(0);
|
|
1964
|
+
}
|
|
1764
1965
|
if (!confirm) {
|
|
1765
|
-
console.log(
|
|
1966
|
+
console.log(chalk8.dim("Cancelled."));
|
|
1766
1967
|
return;
|
|
1767
1968
|
}
|
|
1768
1969
|
}
|
|
@@ -1802,27 +2003,32 @@ var updateCommand = new Command6().name("update").description("Update installed
|
|
|
1802
2003
|
}
|
|
1803
2004
|
console.log();
|
|
1804
2005
|
if (successCount > 0) {
|
|
1805
|
-
console.log(
|
|
2006
|
+
console.log(chalk8.green(`\u2713 Updated ${successCount} component${successCount !== 1 ? "s" : ""}`));
|
|
1806
2007
|
}
|
|
1807
2008
|
if (failCount > 0) {
|
|
1808
|
-
console.log(
|
|
2009
|
+
console.log(chalk8.red(`\u2717 Failed to update ${failCount} component${failCount !== 1 ? "s" : ""}`));
|
|
1809
2010
|
}
|
|
1810
2011
|
const uniqueDeps = [...new Set(allDependencies)];
|
|
1811
2012
|
const uniqueDevDeps = [...new Set(allDevDependencies)];
|
|
1812
2013
|
if (uniqueDeps.length || uniqueDevDeps.length) {
|
|
1813
2014
|
console.log();
|
|
1814
|
-
console.log(
|
|
2015
|
+
console.log(chalk8.bold("Install/update dependencies:"));
|
|
1815
2016
|
if (uniqueDeps.length) {
|
|
1816
|
-
console.log(
|
|
2017
|
+
console.log(chalk8.cyan(` npx expo install ${uniqueDeps.join(" ")}`));
|
|
1817
2018
|
}
|
|
1818
2019
|
if (uniqueDevDeps.length) {
|
|
1819
|
-
console.log(
|
|
2020
|
+
console.log(chalk8.cyan(` npm install -D ${uniqueDevDeps.join(" ")}`));
|
|
1820
2021
|
}
|
|
1821
2022
|
}
|
|
2023
|
+
if (failCount > 0) {
|
|
2024
|
+
process.exit(1);
|
|
2025
|
+
}
|
|
1822
2026
|
} catch (error) {
|
|
1823
2027
|
spinner.fail("Failed to update");
|
|
1824
|
-
|
|
1825
|
-
|
|
2028
|
+
handleError({
|
|
2029
|
+
message: "Failed to update components",
|
|
2030
|
+
hint: error instanceof Error ? error.message : "Check your network connection and try again"
|
|
2031
|
+
});
|
|
1826
2032
|
}
|
|
1827
2033
|
});
|
|
1828
2034
|
async function getComponentDiffs(componentsDir, config) {
|
|
@@ -1878,7 +2084,7 @@ async function checkForUpdate(localFile, registryItem, config) {
|
|
|
1878
2084
|
|
|
1879
2085
|
// src/commands/create.ts
|
|
1880
2086
|
import { Command as Command7 } from "commander";
|
|
1881
|
-
import
|
|
2087
|
+
import chalk9 from "chalk";
|
|
1882
2088
|
import ora6 from "ora";
|
|
1883
2089
|
import prompts4 from "prompts";
|
|
1884
2090
|
import fs9 from "fs-extra";
|
|
@@ -1889,33 +2095,31 @@ var createCommand = new Command7().name("create").description("Scaffold a new cu
|
|
|
1889
2095
|
const cwd = path10.resolve(options.cwd);
|
|
1890
2096
|
const projectRoot = await getProjectRoot(cwd);
|
|
1891
2097
|
if (!projectRoot) {
|
|
1892
|
-
|
|
1893
|
-
console.log(chalk8.dim("Run `npx nativeui init` first."));
|
|
1894
|
-
process.exit(1);
|
|
2098
|
+
errors.noProject();
|
|
1895
2099
|
}
|
|
1896
2100
|
const config = await getConfig(projectRoot);
|
|
1897
2101
|
if (!config) {
|
|
1898
|
-
|
|
1899
|
-
console.log(chalk8.dim("Run `npx nativeui init` first."));
|
|
1900
|
-
process.exit(1);
|
|
2102
|
+
errors.notInitialized();
|
|
1901
2103
|
}
|
|
1902
|
-
const componentName =
|
|
2104
|
+
const componentName = toPascalCase2(name);
|
|
1903
2105
|
const fileName = toKebabCase(name) + ".tsx";
|
|
1904
2106
|
const targetDir = path10.join(projectRoot, config.componentsPath);
|
|
1905
2107
|
const targetPath = path10.join(targetDir, fileName);
|
|
1906
2108
|
if (await fs9.pathExists(targetPath)) {
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
2109
|
+
handleError({
|
|
2110
|
+
message: `Component already exists: ${fileName}`,
|
|
2111
|
+
hint: "Choose a different name or delete the existing file",
|
|
2112
|
+
code: "COMPONENT_EXISTS"
|
|
2113
|
+
});
|
|
1910
2114
|
}
|
|
1911
2115
|
if (!options.yes) {
|
|
1912
2116
|
console.log();
|
|
1913
|
-
console.log(
|
|
1914
|
-
console.log(` Name: ${
|
|
1915
|
-
console.log(` File: ${
|
|
1916
|
-
console.log(` Path: ${
|
|
1917
|
-
console.log(` Template: ${
|
|
1918
|
-
console.log(` ForwardRef: ${
|
|
2117
|
+
console.log(chalk9.bold("Create new component:"));
|
|
2118
|
+
console.log(` Name: ${chalk9.cyan(componentName)}`);
|
|
2119
|
+
console.log(` File: ${chalk9.dim(fileName)}`);
|
|
2120
|
+
console.log(` Path: ${chalk9.dim(targetPath)}`);
|
|
2121
|
+
console.log(` Template: ${chalk9.dim(options.template)}`);
|
|
2122
|
+
console.log(` ForwardRef: ${chalk9.dim(options.forwardRef ? "Yes" : "No")}`);
|
|
1919
2123
|
console.log();
|
|
1920
2124
|
const { confirm } = await prompts4({
|
|
1921
2125
|
type: "confirm",
|
|
@@ -1923,8 +2127,11 @@ var createCommand = new Command7().name("create").description("Scaffold a new cu
|
|
|
1923
2127
|
message: "Create this component?",
|
|
1924
2128
|
initial: true
|
|
1925
2129
|
});
|
|
2130
|
+
if (confirm === void 0) {
|
|
2131
|
+
process.exit(0);
|
|
2132
|
+
}
|
|
1926
2133
|
if (!confirm) {
|
|
1927
|
-
console.log(
|
|
2134
|
+
console.log(chalk9.dim("Cancelled."));
|
|
1928
2135
|
return;
|
|
1929
2136
|
}
|
|
1930
2137
|
}
|
|
@@ -1934,18 +2141,20 @@ var createCommand = new Command7().name("create").description("Scaffold a new cu
|
|
|
1934
2141
|
await fs9.writeFile(targetPath, code);
|
|
1935
2142
|
spinner.succeed(`Created ${fileName}`);
|
|
1936
2143
|
console.log();
|
|
1937
|
-
console.log(
|
|
1938
|
-
console.log(` 1. Edit your component: ${
|
|
2144
|
+
console.log(chalk9.bold("Next steps:"));
|
|
2145
|
+
console.log(` 1. Edit your component: ${chalk9.cyan(targetPath)}`);
|
|
1939
2146
|
console.log(` 2. Import it in your app:`);
|
|
1940
|
-
console.log(
|
|
2147
|
+
console.log(chalk9.dim(` import { ${componentName} } from '${config.aliases?.components || "@/components"}/ui/${toKebabCase(name)}';`));
|
|
1941
2148
|
console.log();
|
|
1942
2149
|
} catch (error) {
|
|
1943
2150
|
spinner.fail("Failed to create component");
|
|
1944
|
-
|
|
1945
|
-
|
|
2151
|
+
handleError({
|
|
2152
|
+
message: "Failed to create component",
|
|
2153
|
+
hint: error instanceof Error ? error.message : "Check file permissions and try again"
|
|
2154
|
+
});
|
|
1946
2155
|
}
|
|
1947
2156
|
});
|
|
1948
|
-
function
|
|
2157
|
+
function toPascalCase2(str) {
|
|
1949
2158
|
return str.replace(/[-_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : "").replace(/^(.)/, (c) => c.toUpperCase());
|
|
1950
2159
|
}
|
|
1951
2160
|
function toKebabCase(str) {
|
|
@@ -1976,7 +2185,7 @@ export interface ${name}Props extends ViewProps {
|
|
|
1976
2185
|
/**
|
|
1977
2186
|
* ${name}
|
|
1978
2187
|
*
|
|
1979
|
-
* A custom component created with
|
|
2188
|
+
* A custom component created with mcellui create.
|
|
1980
2189
|
*
|
|
1981
2190
|
* @example
|
|
1982
2191
|
* \`\`\`tsx
|
|
@@ -2036,7 +2245,7 @@ export interface ${name}Props extends ViewProps {
|
|
|
2036
2245
|
/**
|
|
2037
2246
|
* ${name}
|
|
2038
2247
|
*
|
|
2039
|
-
* A custom component created with
|
|
2248
|
+
* A custom component created with mcellui create.
|
|
2040
2249
|
*
|
|
2041
2250
|
* @example
|
|
2042
2251
|
* \`\`\`tsx
|
|
@@ -2103,7 +2312,7 @@ export interface ${name}Props extends ViewProps {
|
|
|
2103
2312
|
/**
|
|
2104
2313
|
* ${name}
|
|
2105
2314
|
*
|
|
2106
|
-
* An animated component created with
|
|
2315
|
+
* An animated component created with mcellui create.
|
|
2107
2316
|
*
|
|
2108
2317
|
* @example
|
|
2109
2318
|
* \`\`\`tsx
|
|
@@ -2178,7 +2387,7 @@ export interface ${name}Props extends Omit<PressableProps, 'style'> {
|
|
|
2178
2387
|
/**
|
|
2179
2388
|
* ${name}
|
|
2180
2389
|
*
|
|
2181
|
-
* A pressable component created with
|
|
2390
|
+
* A pressable component created with mcellui create.
|
|
2182
2391
|
*
|
|
2183
2392
|
* @example
|
|
2184
2393
|
* \`\`\`tsx
|
|
@@ -2271,7 +2480,7 @@ export interface ${name}Props extends Omit<PressableProps, 'style'> {
|
|
|
2271
2480
|
/**
|
|
2272
2481
|
* ${name}
|
|
2273
2482
|
*
|
|
2274
|
-
* A pressable component created with
|
|
2483
|
+
* A pressable component created with mcellui create.
|
|
2275
2484
|
*
|
|
2276
2485
|
* @example
|
|
2277
2486
|
* \`\`\`tsx
|
|
@@ -2359,7 +2568,7 @@ export interface ${name}Props extends TextInputProps {
|
|
|
2359
2568
|
/**
|
|
2360
2569
|
* ${name}
|
|
2361
2570
|
*
|
|
2362
|
-
* A custom input component created with
|
|
2571
|
+
* A custom input component created with mcellui create.
|
|
2363
2572
|
*
|
|
2364
2573
|
* @example
|
|
2365
2574
|
* \`\`\`tsx
|
|
@@ -2484,7 +2693,7 @@ export interface ${name}Props extends TextInputProps {
|
|
|
2484
2693
|
/**
|
|
2485
2694
|
* ${name}
|
|
2486
2695
|
*
|
|
2487
|
-
* A custom input component created with
|
|
2696
|
+
* A custom input component created with mcellui create.
|
|
2488
2697
|
*
|
|
2489
2698
|
* @example
|
|
2490
2699
|
* \`\`\`tsx
|
|
@@ -2584,7 +2793,7 @@ const styles = StyleSheet.create({
|
|
|
2584
2793
|
|
|
2585
2794
|
// src/commands/pick.ts
|
|
2586
2795
|
import { Command as Command8 } from "commander";
|
|
2587
|
-
import
|
|
2796
|
+
import chalk10 from "chalk";
|
|
2588
2797
|
import prompts5 from "prompts";
|
|
2589
2798
|
import ora7 from "ora";
|
|
2590
2799
|
import fs10 from "fs-extra";
|
|
@@ -2636,7 +2845,7 @@ function formatCategoryName(category) {
|
|
|
2636
2845
|
}
|
|
2637
2846
|
function formatComponentChoice(item, installed) {
|
|
2638
2847
|
const isInstalled = installed.has(item.name);
|
|
2639
|
-
const status = isInstalled ?
|
|
2848
|
+
const status = isInstalled ? chalk10.green(" \u2713") : "";
|
|
2640
2849
|
const description = item.description || "";
|
|
2641
2850
|
return {
|
|
2642
2851
|
title: `${item.name}${status}`,
|
|
@@ -2646,24 +2855,24 @@ function formatComponentChoice(item, installed) {
|
|
|
2646
2855
|
};
|
|
2647
2856
|
}
|
|
2648
2857
|
var pickCommand = new Command8().name("pick").description("Interactively browse and select components to add").option("--all", "Show all components without category selection").option("-o, --overwrite", "Overwrite existing files").option("--cwd <path>", "Working directory", process.cwd()).action(async (options) => {
|
|
2649
|
-
console.log(
|
|
2858
|
+
console.log(chalk10.bold("\n\u{1F3A8} mcellui Component Picker\n"));
|
|
2650
2859
|
const cwd = path11.resolve(options.cwd);
|
|
2651
2860
|
const projectRoot = await getProjectRoot(cwd);
|
|
2652
2861
|
if (!projectRoot) {
|
|
2653
|
-
|
|
2654
|
-
console.log(chalk9.dim("Run `npx nativeui init` first.\n"));
|
|
2655
|
-
return;
|
|
2862
|
+
errors.noProject();
|
|
2656
2863
|
}
|
|
2657
2864
|
const config = await getConfig(projectRoot);
|
|
2658
2865
|
if (!config) {
|
|
2659
|
-
|
|
2660
|
-
return;
|
|
2866
|
+
errors.notInitialized();
|
|
2661
2867
|
}
|
|
2662
2868
|
const spinner = ora7("Loading component registry...").start();
|
|
2663
2869
|
const registry = await getRegistry();
|
|
2664
2870
|
if (!registry.length) {
|
|
2665
|
-
spinner.
|
|
2666
|
-
|
|
2871
|
+
spinner.stop();
|
|
2872
|
+
handleError({
|
|
2873
|
+
message: "Could not load component registry",
|
|
2874
|
+
hint: "Check your internet connection and try again"
|
|
2875
|
+
});
|
|
2667
2876
|
}
|
|
2668
2877
|
spinner.succeed(`Loaded ${registry.length} components`);
|
|
2669
2878
|
const componentsDir = path11.join(projectRoot, config.componentsPath);
|
|
@@ -2693,8 +2902,11 @@ var pickCommand = new Command8().name("pick").description("Interactively browse
|
|
|
2693
2902
|
message: "Select a category",
|
|
2694
2903
|
choices: categoryChoices
|
|
2695
2904
|
});
|
|
2905
|
+
if (categoryResponse.category === void 0) {
|
|
2906
|
+
process.exit(0);
|
|
2907
|
+
}
|
|
2696
2908
|
if (!categoryResponse.category) {
|
|
2697
|
-
console.log(
|
|
2909
|
+
console.log(chalk10.yellow("\nCancelled.\n"));
|
|
2698
2910
|
return;
|
|
2699
2911
|
}
|
|
2700
2912
|
selectedCategory = categoryResponse.category;
|
|
@@ -2707,10 +2919,10 @@ var pickCommand = new Command8().name("pick").description("Interactively browse
|
|
|
2707
2919
|
);
|
|
2708
2920
|
const availableCount = componentChoices.filter((c) => !c.disabled).length;
|
|
2709
2921
|
if (availableCount === 0) {
|
|
2710
|
-
console.log(
|
|
2922
|
+
console.log(chalk10.green("\n\u2713 All components in this category are already installed!\n"));
|
|
2711
2923
|
return;
|
|
2712
2924
|
}
|
|
2713
|
-
console.log(
|
|
2925
|
+
console.log(chalk10.dim(`
|
|
2714
2926
|
${installed.size} already installed, ${availableCount} available
|
|
2715
2927
|
`));
|
|
2716
2928
|
const componentResponse = await prompts5({
|
|
@@ -2721,14 +2933,17 @@ ${installed.size} already installed, ${availableCount} available
|
|
|
2721
2933
|
hint: "- Space to select. Return to submit",
|
|
2722
2934
|
instructions: false
|
|
2723
2935
|
});
|
|
2936
|
+
if (componentResponse.components === void 0) {
|
|
2937
|
+
process.exit(0);
|
|
2938
|
+
}
|
|
2724
2939
|
if (!componentResponse.components || componentResponse.components.length === 0) {
|
|
2725
|
-
console.log(
|
|
2940
|
+
console.log(chalk10.yellow("\nNo components selected.\n"));
|
|
2726
2941
|
return;
|
|
2727
2942
|
}
|
|
2728
2943
|
const selectedComponents = componentResponse.components;
|
|
2729
|
-
console.log(
|
|
2944
|
+
console.log(chalk10.bold("\nComponents to install:"));
|
|
2730
2945
|
for (const name of selectedComponents) {
|
|
2731
|
-
console.log(
|
|
2946
|
+
console.log(chalk10.cyan(` \u2022 ${name}`));
|
|
2732
2947
|
}
|
|
2733
2948
|
const confirmResponse = await prompts5({
|
|
2734
2949
|
type: "confirm",
|
|
@@ -2736,12 +2951,16 @@ ${installed.size} already installed, ${availableCount} available
|
|
|
2736
2951
|
message: `Install ${selectedComponents.length} component(s)?`,
|
|
2737
2952
|
initial: true
|
|
2738
2953
|
});
|
|
2954
|
+
if (confirmResponse.proceed === void 0) {
|
|
2955
|
+
process.exit(0);
|
|
2956
|
+
}
|
|
2739
2957
|
if (!confirmResponse.proceed) {
|
|
2740
|
-
console.log(
|
|
2958
|
+
console.log(chalk10.yellow("\nCancelled.\n"));
|
|
2741
2959
|
return;
|
|
2742
2960
|
}
|
|
2743
2961
|
console.log("");
|
|
2744
2962
|
let successCount = 0;
|
|
2963
|
+
let failCount = 0;
|
|
2745
2964
|
const allDependencies = [];
|
|
2746
2965
|
const allDevDependencies = [];
|
|
2747
2966
|
for (const name of selectedComponents) {
|
|
@@ -2750,6 +2969,7 @@ ${installed.size} already installed, ${availableCount} available
|
|
|
2750
2969
|
const component = await fetchComponent(name);
|
|
2751
2970
|
if (!component) {
|
|
2752
2971
|
installSpinner.fail(`Component "${name}" not found`);
|
|
2972
|
+
failCount++;
|
|
2753
2973
|
continue;
|
|
2754
2974
|
}
|
|
2755
2975
|
const targetDir = path11.join(projectRoot, config.componentsPath);
|
|
@@ -2763,7 +2983,7 @@ ${installed.size} already installed, ${availableCount} available
|
|
|
2763
2983
|
const transformedContent = transformToInstalled(file.content, config);
|
|
2764
2984
|
await fs10.writeFile(targetPath, transformedContent);
|
|
2765
2985
|
}
|
|
2766
|
-
installSpinner.succeed(`Installed ${
|
|
2986
|
+
installSpinner.succeed(`Installed ${chalk10.green(name)}`);
|
|
2767
2987
|
successCount++;
|
|
2768
2988
|
if (component.dependencies?.length) {
|
|
2769
2989
|
allDependencies.push(...component.dependencies);
|
|
@@ -2772,35 +2992,39 @@ ${installed.size} already installed, ${availableCount} available
|
|
|
2772
2992
|
allDevDependencies.push(...component.devDependencies);
|
|
2773
2993
|
}
|
|
2774
2994
|
if (component.registryDependencies?.length) {
|
|
2775
|
-
console.log(
|
|
2995
|
+
console.log(chalk10.dim(` Requires: ${component.registryDependencies.join(", ")}`));
|
|
2776
2996
|
}
|
|
2777
2997
|
} catch (error) {
|
|
2778
2998
|
installSpinner.fail(`Failed to install ${name}: ${error}`);
|
|
2999
|
+
failCount++;
|
|
2779
3000
|
}
|
|
2780
3001
|
}
|
|
3002
|
+
if (failCount > 0) {
|
|
3003
|
+
process.exit(1);
|
|
3004
|
+
}
|
|
2781
3005
|
console.log(
|
|
2782
|
-
|
|
3006
|
+
chalk10.bold.green(`
|
|
2783
3007
|
\u2713 Successfully installed ${successCount}/${selectedComponents.length} components
|
|
2784
3008
|
`)
|
|
2785
3009
|
);
|
|
2786
3010
|
const uniqueDeps = [...new Set(allDependencies)];
|
|
2787
3011
|
const uniqueDevDeps = [...new Set(allDevDependencies)];
|
|
2788
3012
|
if (uniqueDeps.length || uniqueDevDeps.length) {
|
|
2789
|
-
console.log(
|
|
3013
|
+
console.log(chalk10.bold("Install dependencies:"));
|
|
2790
3014
|
if (uniqueDeps.length) {
|
|
2791
|
-
console.log(
|
|
3015
|
+
console.log(chalk10.cyan(` npx expo install ${uniqueDeps.join(" ")}`));
|
|
2792
3016
|
}
|
|
2793
3017
|
if (uniqueDevDeps.length) {
|
|
2794
|
-
console.log(
|
|
3018
|
+
console.log(chalk10.cyan(` npm install -D ${uniqueDevDeps.join(" ")}`));
|
|
2795
3019
|
}
|
|
2796
3020
|
console.log("");
|
|
2797
3021
|
}
|
|
2798
3022
|
if (successCount > 0) {
|
|
2799
|
-
console.log(
|
|
3023
|
+
console.log(chalk10.dim("Import example:"));
|
|
2800
3024
|
const firstComponent = selectedComponents[0];
|
|
2801
3025
|
const pascalName = firstComponent.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
|
|
2802
3026
|
const alias = config.aliases?.components || "@/components/ui";
|
|
2803
|
-
console.log(
|
|
3027
|
+
console.log(chalk10.dim(` import { ${pascalName} } from '${alias}/${firstComponent}';
|
|
2804
3028
|
`));
|
|
2805
3029
|
}
|
|
2806
3030
|
});
|
|
@@ -2808,6 +3032,11 @@ ${installed.size} already installed, ${availableCount} available
|
|
|
2808
3032
|
// src/index.ts
|
|
2809
3033
|
var program = new Command9();
|
|
2810
3034
|
program.name("mcellui").description("Add beautiful UI components to your Expo/React Native project").version("0.1.4");
|
|
3035
|
+
program.configureOutput({
|
|
3036
|
+
writeOut: (str) => process.stdout.write(str),
|
|
3037
|
+
writeErr: (str) => process.stderr.write(str),
|
|
3038
|
+
outputError: (str, write) => write(chalk11.red(str))
|
|
3039
|
+
});
|
|
2811
3040
|
program.addCommand(initCommand);
|
|
2812
3041
|
program.addCommand(addCommand);
|
|
2813
3042
|
program.addCommand(listCommand);
|
|
@@ -2816,4 +3045,14 @@ program.addCommand(diffCommand);
|
|
|
2816
3045
|
program.addCommand(updateCommand);
|
|
2817
3046
|
program.addCommand(createCommand);
|
|
2818
3047
|
program.addCommand(pickCommand);
|
|
2819
|
-
|
|
3048
|
+
async function main() {
|
|
3049
|
+
try {
|
|
3050
|
+
await program.parseAsync(process.argv);
|
|
3051
|
+
} catch (error) {
|
|
3052
|
+
handleError({
|
|
3053
|
+
message: error instanceof Error ? error.message : "An unexpected error occurred",
|
|
3054
|
+
hint: "If this persists, run: npx mcellui doctor"
|
|
3055
|
+
});
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3058
|
+
main();
|