@metacells/mcellui-cli 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/index.js +537 -338
- 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;
|
|
@@ -212,27 +286,38 @@ async function detectProjectType(projectRoot) {
|
|
|
212
286
|
return "unknown";
|
|
213
287
|
}
|
|
214
288
|
}
|
|
289
|
+
var CONFIG_FILES = [
|
|
290
|
+
"mcellui.config.ts",
|
|
291
|
+
"mcellui.config.js",
|
|
292
|
+
"mcellui.config.json",
|
|
293
|
+
"nativeui.config.ts",
|
|
294
|
+
// Legacy
|
|
295
|
+
"nativeui.config.js",
|
|
296
|
+
// Legacy
|
|
297
|
+
"nativeui.config.json"
|
|
298
|
+
// Legacy
|
|
299
|
+
];
|
|
215
300
|
async function getConfig(projectRoot) {
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
301
|
+
for (const fileName of CONFIG_FILES) {
|
|
302
|
+
const configPath = path.join(projectRoot, fileName);
|
|
303
|
+
if (await fs.pathExists(configPath)) {
|
|
304
|
+
if (fileName.endsWith(".ts")) {
|
|
305
|
+
return loadTsConfig(configPath);
|
|
306
|
+
} else if (fileName.endsWith(".js")) {
|
|
307
|
+
return loadJsConfig(configPath);
|
|
308
|
+
} else if (fileName.endsWith(".json")) {
|
|
309
|
+
try {
|
|
310
|
+
const rawConfig = await fs.readJson(configPath);
|
|
311
|
+
const validatedConfig = validateConfigOrThrow(rawConfig, configPath);
|
|
312
|
+
return resolveConfig(validatedConfig);
|
|
313
|
+
} catch (error) {
|
|
314
|
+
if (error instanceof Error && error.message.includes("Invalid configuration")) {
|
|
315
|
+
console.error(chalk2.red(error.message));
|
|
316
|
+
throw error;
|
|
317
|
+
}
|
|
318
|
+
throw error;
|
|
319
|
+
}
|
|
234
320
|
}
|
|
235
|
-
throw error;
|
|
236
321
|
}
|
|
237
322
|
}
|
|
238
323
|
return null;
|
|
@@ -248,10 +333,10 @@ async function loadTsConfig(configPath) {
|
|
|
248
333
|
return resolveConfig(validatedConfig);
|
|
249
334
|
} catch (error) {
|
|
250
335
|
if (error instanceof Error && error.message.includes("Invalid configuration")) {
|
|
251
|
-
console.error(
|
|
336
|
+
console.error(chalk2.red(error.message));
|
|
252
337
|
throw error;
|
|
253
338
|
}
|
|
254
|
-
console.error(
|
|
339
|
+
console.error(chalk2.red("Failed to load config:"), error);
|
|
255
340
|
return getDefaultConfig();
|
|
256
341
|
}
|
|
257
342
|
}
|
|
@@ -263,10 +348,10 @@ async function loadJsConfig(configPath) {
|
|
|
263
348
|
return resolveConfig(validatedConfig);
|
|
264
349
|
} catch (error) {
|
|
265
350
|
if (error instanceof Error && error.message.includes("Invalid configuration")) {
|
|
266
|
-
console.error(
|
|
351
|
+
console.error(chalk2.red(error.message));
|
|
267
352
|
throw error;
|
|
268
353
|
}
|
|
269
|
-
console.error(
|
|
354
|
+
console.error(chalk2.red("Failed to load config:"), error);
|
|
270
355
|
return getDefaultConfig();
|
|
271
356
|
}
|
|
272
357
|
}
|
|
@@ -294,26 +379,31 @@ async function detectPackageManager(projectRoot) {
|
|
|
294
379
|
}
|
|
295
380
|
|
|
296
381
|
// src/commands/init.ts
|
|
297
|
-
var initCommand = new Command().name("init").description("Initialize
|
|
382
|
+
var initCommand = new Command().name("init").description("Initialize mcellui in your project").option("-y, --yes", "Skip prompts and use defaults").option("--cwd <path>", "Working directory", process.cwd()).action(async (options) => {
|
|
298
383
|
const spinner = ora();
|
|
299
384
|
try {
|
|
300
385
|
const cwd = path2.resolve(options.cwd);
|
|
301
386
|
const projectRoot = await getProjectRoot(cwd);
|
|
302
387
|
if (!projectRoot) {
|
|
303
|
-
|
|
304
|
-
console.log(chalk2.dim("Make sure you run this command in a project with package.json"));
|
|
305
|
-
process.exit(1);
|
|
388
|
+
errors.noProject();
|
|
306
389
|
}
|
|
307
390
|
console.log();
|
|
308
|
-
console.log(
|
|
309
|
-
console.log(
|
|
391
|
+
console.log(chalk3.bold("Welcome to mcellui!"));
|
|
392
|
+
console.log(chalk3.dim("The copy-paste component library for Expo/React Native"));
|
|
310
393
|
console.log();
|
|
311
394
|
const projectType = await detectProjectType(projectRoot);
|
|
312
|
-
console.log(
|
|
313
|
-
const configPath = path2.join(projectRoot, "
|
|
395
|
+
console.log(chalk3.dim(`Detected: ${projectType}`));
|
|
396
|
+
const configPath = path2.join(projectRoot, "mcellui.config.ts");
|
|
397
|
+
const legacyConfigPath = path2.join(projectRoot, "nativeui.config.ts");
|
|
314
398
|
if (await fs2.pathExists(configPath)) {
|
|
315
|
-
console.log(
|
|
316
|
-
console.log(
|
|
399
|
+
console.log(chalk3.yellow("Project already initialized."));
|
|
400
|
+
console.log(chalk3.dim(`Config found at: ${configPath}`));
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
if (await fs2.pathExists(legacyConfigPath)) {
|
|
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"));
|
|
317
407
|
return;
|
|
318
408
|
}
|
|
319
409
|
let config = {
|
|
@@ -346,6 +436,9 @@ var initCommand = new Command().name("init").description("Initialize nativeui in
|
|
|
346
436
|
]
|
|
347
437
|
}
|
|
348
438
|
]);
|
|
439
|
+
if (response.componentsPath === void 0) {
|
|
440
|
+
process.exit(0);
|
|
441
|
+
}
|
|
349
442
|
config = { ...config, ...response };
|
|
350
443
|
}
|
|
351
444
|
spinner.start("Creating configuration...");
|
|
@@ -384,7 +477,7 @@ export default defineConfig({
|
|
|
384
477
|
// },
|
|
385
478
|
|
|
386
479
|
// ============================================
|
|
387
|
-
// CLI Configuration (used by npx
|
|
480
|
+
// CLI Configuration (used by npx mcellui add)
|
|
388
481
|
// ============================================
|
|
389
482
|
|
|
390
483
|
// Path where components will be installed
|
|
@@ -454,25 +547,27 @@ export function cn(...inputs: StyleInput[]): Style {
|
|
|
454
547
|
);
|
|
455
548
|
spinner.succeed("Utilities installed");
|
|
456
549
|
console.log();
|
|
457
|
-
console.log(
|
|
550
|
+
console.log(chalk3.green("Success!") + " mcellui initialized.");
|
|
458
551
|
console.log();
|
|
459
552
|
console.log("Next steps:");
|
|
460
|
-
console.log(
|
|
461
|
-
console.log(
|
|
553
|
+
console.log(chalk3.dim(" 1."), "Add your first component:");
|
|
554
|
+
console.log(chalk3.cyan(" npx mcellui add button"));
|
|
462
555
|
console.log();
|
|
463
|
-
console.log(
|
|
464
|
-
console.log(
|
|
556
|
+
console.log(chalk3.dim(" 2."), "Browse available components:");
|
|
557
|
+
console.log(chalk3.cyan(" npx mcellui list"));
|
|
465
558
|
console.log();
|
|
466
559
|
} catch (error) {
|
|
467
560
|
spinner.fail("Failed to initialize");
|
|
468
|
-
|
|
469
|
-
|
|
561
|
+
handleError({
|
|
562
|
+
message: "Initialization failed",
|
|
563
|
+
hint: error instanceof Error ? error.message : "Check file permissions and try again"
|
|
564
|
+
});
|
|
470
565
|
}
|
|
471
566
|
});
|
|
472
567
|
|
|
473
568
|
// src/commands/add.ts
|
|
474
569
|
import { Command as Command2 } from "commander";
|
|
475
|
-
import
|
|
570
|
+
import chalk4 from "chalk";
|
|
476
571
|
import ora2 from "ora";
|
|
477
572
|
import prompts2 from "prompts";
|
|
478
573
|
import fs5 from "fs-extra";
|
|
@@ -485,10 +580,59 @@ import { fileURLToPath as fileURLToPath2 } from "url";
|
|
|
485
580
|
var __filename3 = fileURLToPath2(import.meta.url);
|
|
486
581
|
var __dirname2 = path3.dirname(__filename3);
|
|
487
582
|
var DEFAULT_REGISTRY_URL = "https://raw.githubusercontent.com/metacells-development/mcellui/main/packages/registry";
|
|
488
|
-
var
|
|
583
|
+
var hasEnvOverride = "MCELLUI_REGISTRY_URL" in process.env || "NATIVEUI_REGISTRY_URL" in process.env;
|
|
584
|
+
var REGISTRY_URL = hasEnvOverride ? process.env.MCELLUI_REGISTRY_URL || process.env.NATIVEUI_REGISTRY_URL || "" : DEFAULT_REGISTRY_URL;
|
|
489
585
|
function getLocalRegistryPath() {
|
|
490
586
|
return path3.resolve(__dirname2, "..", "..", "registry");
|
|
491
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
|
+
}
|
|
492
636
|
function isLocalMode() {
|
|
493
637
|
if (REGISTRY_URL) return false;
|
|
494
638
|
const localPath = getLocalRegistryPath();
|
|
@@ -506,18 +650,23 @@ async function getLocalRegistry() {
|
|
|
506
650
|
const registry = await fs3.readJson(registryPath);
|
|
507
651
|
return registry.components;
|
|
508
652
|
} catch (error) {
|
|
509
|
-
|
|
510
|
-
|
|
653
|
+
throw new Error(
|
|
654
|
+
"Failed to load local registry: " + (error instanceof Error ? error.message : String(error))
|
|
655
|
+
);
|
|
511
656
|
}
|
|
512
657
|
}
|
|
513
658
|
async function getRemoteRegistry() {
|
|
514
659
|
try {
|
|
515
|
-
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
|
+
}
|
|
516
664
|
const registry = await response.json();
|
|
517
665
|
return registry.components;
|
|
518
666
|
} catch (error) {
|
|
519
|
-
|
|
520
|
-
|
|
667
|
+
throw new Error(
|
|
668
|
+
"Failed to fetch registry: " + (error instanceof Error ? error.message : String(error))
|
|
669
|
+
);
|
|
521
670
|
}
|
|
522
671
|
}
|
|
523
672
|
async function fetchComponent(name) {
|
|
@@ -552,7 +701,12 @@ async function fetchLocalComponent(item) {
|
|
|
552
701
|
async function fetchRemoteComponent(item) {
|
|
553
702
|
const files = await Promise.all(
|
|
554
703
|
item.files.map(async (filePath) => {
|
|
555
|
-
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
|
+
}
|
|
556
710
|
const content = await response.text();
|
|
557
711
|
const name = path3.basename(filePath);
|
|
558
712
|
return { name, content };
|
|
@@ -621,6 +775,25 @@ function formatCircularError(chain) {
|
|
|
621
775
|
// src/utils/installed.ts
|
|
622
776
|
import fs4 from "fs-extra";
|
|
623
777
|
import path4 from "path";
|
|
778
|
+
|
|
779
|
+
// src/utils/imports.ts
|
|
780
|
+
function transformToInstalled(code, config) {
|
|
781
|
+
if (!config) return code;
|
|
782
|
+
let result = code;
|
|
783
|
+
const utilsAlias = config.aliases?.utils || "@/lib/utils";
|
|
784
|
+
if (utilsAlias !== "@/lib/utils") {
|
|
785
|
+
result = result.replace(
|
|
786
|
+
/from ['"]@\/lib\/utils['"]/g,
|
|
787
|
+
`from '${utilsAlias}'`
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
return result;
|
|
791
|
+
}
|
|
792
|
+
function normalizeForComparison(content) {
|
|
793
|
+
return content.replace(/\r\n/g, "\n").replace(/\s+$/gm, "").trim();
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// src/utils/installed.ts
|
|
624
797
|
async function getInstalledFiles(componentsDir) {
|
|
625
798
|
if (!await fs4.pathExists(componentsDir)) {
|
|
626
799
|
return [];
|
|
@@ -637,24 +810,6 @@ async function getInstalledFiles(componentsDir) {
|
|
|
637
810
|
}
|
|
638
811
|
return componentFiles.sort();
|
|
639
812
|
}
|
|
640
|
-
function normalizeContent(content) {
|
|
641
|
-
return content.replace(/\r\n/g, "\n").replace(/\s+$/gm, "").trim();
|
|
642
|
-
}
|
|
643
|
-
function transformImports(code, config) {
|
|
644
|
-
let transformed = code;
|
|
645
|
-
transformed = transformed.replace(
|
|
646
|
-
/from ['"]@nativeui\/core['"]/g,
|
|
647
|
-
`from '@metacells/mcellui-core'`
|
|
648
|
-
);
|
|
649
|
-
const utilsAlias = config.aliases?.utils || "@/lib/utils";
|
|
650
|
-
if (utilsAlias !== "@/lib/utils") {
|
|
651
|
-
transformed = transformed.replace(
|
|
652
|
-
/from ['"]@\/lib\/utils['"]/g,
|
|
653
|
-
`from '${utilsAlias}'`
|
|
654
|
-
);
|
|
655
|
-
}
|
|
656
|
-
return transformed;
|
|
657
|
-
}
|
|
658
813
|
async function getInstallStatus(installedFiles, registry, config) {
|
|
659
814
|
const results = [];
|
|
660
815
|
const registryMap = /* @__PURE__ */ new Map();
|
|
@@ -700,10 +855,8 @@ async function getInstallStatus(installedFiles, registry, config) {
|
|
|
700
855
|
continue;
|
|
701
856
|
}
|
|
702
857
|
const localContent = await fs4.readFile(localFile, "utf-8");
|
|
703
|
-
const normalizedLocal =
|
|
704
|
-
const normalizedRegistry =
|
|
705
|
-
transformImports(registryFile.content, config)
|
|
706
|
-
);
|
|
858
|
+
const normalizedLocal = normalizeForComparison(localContent);
|
|
859
|
+
const normalizedRegistry = normalizeForComparison(registryFile.content);
|
|
707
860
|
results.push({
|
|
708
861
|
name: registryItem.name,
|
|
709
862
|
fileName,
|
|
@@ -736,35 +889,36 @@ var addCommand = new Command2().name("add").description("Add a component to your
|
|
|
736
889
|
const cwd = path5.resolve(options.cwd);
|
|
737
890
|
const projectRoot = await getProjectRoot(cwd);
|
|
738
891
|
if (!projectRoot) {
|
|
739
|
-
|
|
740
|
-
console.log(chalk3.dim("Run `npx nativeui init` first."));
|
|
741
|
-
process.exit(1);
|
|
892
|
+
errors.noProject();
|
|
742
893
|
}
|
|
743
894
|
const config = await getConfig(projectRoot);
|
|
744
895
|
if (!config) {
|
|
745
|
-
|
|
746
|
-
console.log(chalk3.dim("Run `npx nativeui init` first."));
|
|
747
|
-
process.exit(1);
|
|
896
|
+
errors.notInitialized();
|
|
748
897
|
}
|
|
749
898
|
if (!components.length) {
|
|
750
899
|
const registry2 = await getRegistry();
|
|
751
900
|
if (!registry2.length) {
|
|
752
|
-
|
|
753
|
-
|
|
901
|
+
handleError({
|
|
902
|
+
message: "No components found in registry",
|
|
903
|
+
hint: "Check your internet connection or try again later"
|
|
904
|
+
});
|
|
754
905
|
}
|
|
755
906
|
const { selected } = await prompts2({
|
|
756
907
|
type: "multiselect",
|
|
757
908
|
name: "selected",
|
|
758
909
|
message: "Which components would you like to add?",
|
|
759
910
|
choices: registry2.map((item) => ({
|
|
760
|
-
title: `${item.name} ${
|
|
911
|
+
title: `${item.name} ${chalk4.dim(`(${item.status})`)}`,
|
|
761
912
|
value: item.name,
|
|
762
913
|
description: item.description
|
|
763
914
|
})),
|
|
764
915
|
hint: "- Space to select, Enter to confirm"
|
|
765
916
|
});
|
|
917
|
+
if (selected === void 0) {
|
|
918
|
+
process.exit(0);
|
|
919
|
+
}
|
|
766
920
|
if (!selected?.length) {
|
|
767
|
-
console.log(
|
|
921
|
+
console.log(chalk4.dim("No components selected."));
|
|
768
922
|
return;
|
|
769
923
|
}
|
|
770
924
|
components = selected;
|
|
@@ -774,8 +928,11 @@ var addCommand = new Command2().name("add").description("Add a component to your
|
|
|
774
928
|
const { resolved, circular } = resolveDependencies(components, registry);
|
|
775
929
|
if (circular) {
|
|
776
930
|
spinner.fail("Circular dependency detected");
|
|
777
|
-
|
|
778
|
-
|
|
931
|
+
handleError({
|
|
932
|
+
message: `Circular dependency: ${formatCircularError(circular)}`,
|
|
933
|
+
hint: "Check component dependencies for cycles",
|
|
934
|
+
code: "CIRCULAR_DEPENDENCY"
|
|
935
|
+
});
|
|
779
936
|
}
|
|
780
937
|
spinner.stop();
|
|
781
938
|
const componentsDir = path5.join(projectRoot, config.componentsPath);
|
|
@@ -783,19 +940,19 @@ var addCommand = new Command2().name("add").description("Add a component to your
|
|
|
783
940
|
const installedNames = new Set(getInstalledNames(installedFiles));
|
|
784
941
|
const toInstall = options.overwrite ? resolved : resolved.filter((name) => !installedNames.has(name));
|
|
785
942
|
if (toInstall.length === 0) {
|
|
786
|
-
console.log(
|
|
787
|
-
console.log(
|
|
943
|
+
console.log(chalk4.yellow("All components are already installed."));
|
|
944
|
+
console.log(chalk4.dim("Use --overwrite to reinstall."));
|
|
788
945
|
return;
|
|
789
946
|
}
|
|
790
947
|
const requested = new Set(components);
|
|
791
948
|
const dependencies = toInstall.filter((name) => !requested.has(name));
|
|
792
949
|
console.log();
|
|
793
|
-
console.log(
|
|
950
|
+
console.log(chalk4.bold("Adding components:"));
|
|
794
951
|
for (const name of toInstall) {
|
|
795
952
|
if (requested.has(name)) {
|
|
796
|
-
console.log(
|
|
953
|
+
console.log(chalk4.dim(` - ${name}`));
|
|
797
954
|
} else {
|
|
798
|
-
console.log(
|
|
955
|
+
console.log(chalk4.dim(` - ${name} ${chalk4.cyan("(dependency)")}`));
|
|
799
956
|
}
|
|
800
957
|
}
|
|
801
958
|
console.log();
|
|
@@ -806,19 +963,24 @@ var addCommand = new Command2().name("add").description("Add a component to your
|
|
|
806
963
|
message: `Add ${dependencies.length} additional dependencies?`,
|
|
807
964
|
initial: true
|
|
808
965
|
});
|
|
966
|
+
if (confirm === void 0) {
|
|
967
|
+
process.exit(0);
|
|
968
|
+
}
|
|
809
969
|
if (!confirm) {
|
|
810
|
-
console.log(
|
|
970
|
+
console.log(chalk4.dim("Cancelled."));
|
|
811
971
|
return;
|
|
812
972
|
}
|
|
813
973
|
}
|
|
814
974
|
const allDependencies = [];
|
|
815
975
|
const allDevDependencies = [];
|
|
976
|
+
let failCount = 0;
|
|
816
977
|
for (const componentName of toInstall) {
|
|
817
978
|
spinner.start(`Fetching ${componentName}...`);
|
|
818
979
|
try {
|
|
819
980
|
const component = await fetchComponent(componentName);
|
|
820
981
|
if (!component) {
|
|
821
982
|
spinner.fail(`Component "${componentName}" not found`);
|
|
983
|
+
failCount++;
|
|
822
984
|
continue;
|
|
823
985
|
}
|
|
824
986
|
const targetDir = path5.join(projectRoot, config.componentsPath);
|
|
@@ -829,7 +991,7 @@ var addCommand = new Command2().name("add").description("Add a component to your
|
|
|
829
991
|
continue;
|
|
830
992
|
}
|
|
831
993
|
await fs5.ensureDir(targetDir);
|
|
832
|
-
const transformedContent =
|
|
994
|
+
const transformedContent = transformToInstalled(file.content, config);
|
|
833
995
|
await fs5.writeFile(targetPath, transformedContent);
|
|
834
996
|
}
|
|
835
997
|
spinner.succeed(`Added ${componentName}`);
|
|
@@ -841,48 +1003,42 @@ var addCommand = new Command2().name("add").description("Add a component to your
|
|
|
841
1003
|
}
|
|
842
1004
|
} catch (error) {
|
|
843
1005
|
spinner.fail(`Failed to add ${componentName}`);
|
|
844
|
-
console.error(
|
|
1006
|
+
console.error(chalk4.dim(String(error)));
|
|
1007
|
+
failCount++;
|
|
845
1008
|
}
|
|
846
1009
|
}
|
|
1010
|
+
if (failCount > 0) {
|
|
1011
|
+
process.exit(1);
|
|
1012
|
+
}
|
|
847
1013
|
const uniqueDeps = [...new Set(allDependencies)];
|
|
848
1014
|
const uniqueDevDeps = [...new Set(allDevDependencies)];
|
|
849
1015
|
if (uniqueDeps.length || uniqueDevDeps.length) {
|
|
850
1016
|
console.log();
|
|
851
|
-
console.log(
|
|
1017
|
+
console.log(chalk4.bold("Install dependencies:"));
|
|
852
1018
|
if (uniqueDeps.length) {
|
|
853
|
-
console.log(
|
|
1019
|
+
console.log(chalk4.cyan(` npx expo install ${uniqueDeps.join(" ")}`));
|
|
854
1020
|
}
|
|
855
1021
|
if (uniqueDevDeps.length) {
|
|
856
|
-
console.log(
|
|
1022
|
+
console.log(chalk4.cyan(` npm install -D ${uniqueDevDeps.join(" ")}`));
|
|
857
1023
|
}
|
|
858
1024
|
}
|
|
859
1025
|
console.log();
|
|
860
|
-
console.log(
|
|
1026
|
+
console.log(chalk4.green("Done!"));
|
|
861
1027
|
} catch (error) {
|
|
862
1028
|
spinner.fail("Failed");
|
|
863
|
-
|
|
864
|
-
|
|
1029
|
+
handleError({
|
|
1030
|
+
message: "Failed to add components",
|
|
1031
|
+
hint: error instanceof Error ? error.message : "Check your network connection and try again"
|
|
1032
|
+
});
|
|
865
1033
|
}
|
|
866
1034
|
});
|
|
867
|
-
function transformImports2(code, config) {
|
|
868
|
-
let transformed = code;
|
|
869
|
-
const utilsAlias = config.aliases?.utils || "@/lib/utils";
|
|
870
|
-
if (utilsAlias === "@/lib/utils") {
|
|
871
|
-
return transformed;
|
|
872
|
-
}
|
|
873
|
-
transformed = transformed.replace(
|
|
874
|
-
/from ['"]@\/lib\/utils['"]/g,
|
|
875
|
-
`from '${utilsAlias}'`
|
|
876
|
-
);
|
|
877
|
-
return transformed;
|
|
878
|
-
}
|
|
879
1035
|
|
|
880
1036
|
// src/commands/list.ts
|
|
881
1037
|
import { Command as Command3 } from "commander";
|
|
882
|
-
import
|
|
1038
|
+
import chalk5 from "chalk";
|
|
883
1039
|
import ora3 from "ora";
|
|
884
1040
|
import path6 from "path";
|
|
885
|
-
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) => {
|
|
1041
|
+
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) => {
|
|
886
1042
|
if (options.installed) {
|
|
887
1043
|
await listInstalledComponents(options);
|
|
888
1044
|
} else {
|
|
@@ -894,8 +1050,13 @@ async function listAvailableComponents(options) {
|
|
|
894
1050
|
try {
|
|
895
1051
|
const registry = await getRegistry();
|
|
896
1052
|
spinner.stop();
|
|
1053
|
+
if (options.json) {
|
|
1054
|
+
const items = options.category ? registry.filter((item) => (item.category || "Other").toLowerCase() === options.category.toLowerCase()) : registry;
|
|
1055
|
+
console.log(JSON.stringify(items, null, 2));
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
897
1058
|
console.log();
|
|
898
|
-
console.log(
|
|
1059
|
+
console.log(chalk5.bold("Available Components"));
|
|
899
1060
|
console.log();
|
|
900
1061
|
const categories = /* @__PURE__ */ new Map();
|
|
901
1062
|
for (const item of registry) {
|
|
@@ -909,20 +1070,22 @@ async function listAvailableComponents(options) {
|
|
|
909
1070
|
categories.get(category).push(item);
|
|
910
1071
|
}
|
|
911
1072
|
for (const [category, items] of categories) {
|
|
912
|
-
console.log(
|
|
1073
|
+
console.log(chalk5.cyan.bold(`${category}`));
|
|
913
1074
|
for (const item of items) {
|
|
914
|
-
const status = item.status === "stable" ? "" :
|
|
915
|
-
console.log(` ${
|
|
916
|
-
console.log(
|
|
1075
|
+
const status = item.status === "stable" ? "" : chalk5.yellow(` [${item.status}]`);
|
|
1076
|
+
console.log(` ${chalk5.white(item.name)}${status}`);
|
|
1077
|
+
console.log(chalk5.dim(` ${item.description}`));
|
|
917
1078
|
}
|
|
918
1079
|
console.log();
|
|
919
1080
|
}
|
|
920
|
-
console.log(
|
|
1081
|
+
console.log(chalk5.dim("Add a component: npx mcellui add <component>"));
|
|
921
1082
|
console.log();
|
|
922
1083
|
} catch (error) {
|
|
923
1084
|
spinner.fail("Failed to fetch components");
|
|
924
|
-
|
|
925
|
-
|
|
1085
|
+
handleError({
|
|
1086
|
+
message: "Failed to fetch components",
|
|
1087
|
+
hint: error instanceof Error ? error.message : "Check your network connection and try again"
|
|
1088
|
+
});
|
|
926
1089
|
}
|
|
927
1090
|
}
|
|
928
1091
|
async function listInstalledComponents(options) {
|
|
@@ -931,22 +1094,23 @@ async function listInstalledComponents(options) {
|
|
|
931
1094
|
const cwd = path6.resolve(options.cwd || process.cwd());
|
|
932
1095
|
const projectRoot = await getProjectRoot(cwd);
|
|
933
1096
|
if (!projectRoot) {
|
|
934
|
-
|
|
935
|
-
console.log(chalk4.dim("Run `npx mcellui init` first."));
|
|
936
|
-
process.exit(1);
|
|
1097
|
+
errors.noProject();
|
|
937
1098
|
}
|
|
938
1099
|
const config = await getConfig(projectRoot);
|
|
939
1100
|
if (!config) {
|
|
940
|
-
|
|
941
|
-
console.log(chalk4.dim("Run `npx mcellui init` first."));
|
|
942
|
-
process.exit(1);
|
|
1101
|
+
errors.notInitialized();
|
|
943
1102
|
}
|
|
944
1103
|
spinner.start("Scanning installed components...");
|
|
945
1104
|
const componentsDir = path6.join(projectRoot, config.componentsPath);
|
|
946
1105
|
const installedFiles = await getInstalledFiles(componentsDir);
|
|
947
1106
|
if (installedFiles.length === 0) {
|
|
1107
|
+
spinner.stop();
|
|
1108
|
+
if (options.json) {
|
|
1109
|
+
console.log(JSON.stringify([], null, 2));
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
948
1112
|
spinner.info("No components installed yet.");
|
|
949
|
-
console.log(
|
|
1113
|
+
console.log(chalk5.dim("\nAdd components with: npx mcellui add <component>"));
|
|
950
1114
|
return;
|
|
951
1115
|
}
|
|
952
1116
|
spinner.text = "Fetching registry...";
|
|
@@ -954,13 +1118,17 @@ async function listInstalledComponents(options) {
|
|
|
954
1118
|
spinner.text = "Comparing components...";
|
|
955
1119
|
const installed = await getInstallStatus(installedFiles, registry, config);
|
|
956
1120
|
spinner.stop();
|
|
1121
|
+
if (options.json) {
|
|
1122
|
+
console.log(JSON.stringify(installed, null, 2));
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
957
1125
|
const identical = installed.filter((c) => c.status === "identical");
|
|
958
1126
|
const modified = installed.filter((c) => c.status === "modified");
|
|
959
1127
|
const localOnly = installed.filter((c) => c.status === "local-only");
|
|
960
1128
|
const installedNames = new Set(installed.map((c) => c.name));
|
|
961
1129
|
const notInstalled = registry.filter((item) => !installedNames.has(item.name));
|
|
962
1130
|
console.log();
|
|
963
|
-
console.log(
|
|
1131
|
+
console.log(chalk5.bold(`Installed Components (${installed.length})`));
|
|
964
1132
|
console.log();
|
|
965
1133
|
const categories = /* @__PURE__ */ new Map();
|
|
966
1134
|
for (const comp of installed) {
|
|
@@ -972,56 +1140,58 @@ async function listInstalledComponents(options) {
|
|
|
972
1140
|
categories.get(category).push(comp);
|
|
973
1141
|
}
|
|
974
1142
|
for (const [category, components] of categories) {
|
|
975
|
-
console.log(
|
|
1143
|
+
console.log(chalk5.cyan.bold(category));
|
|
976
1144
|
for (const comp of components) {
|
|
977
1145
|
let statusIcon;
|
|
978
1146
|
let statusText;
|
|
979
1147
|
switch (comp.status) {
|
|
980
1148
|
case "identical":
|
|
981
|
-
statusIcon =
|
|
982
|
-
statusText =
|
|
1149
|
+
statusIcon = chalk5.green("\u2713");
|
|
1150
|
+
statusText = chalk5.dim("(up to date)");
|
|
983
1151
|
break;
|
|
984
1152
|
case "modified":
|
|
985
|
-
statusIcon =
|
|
986
|
-
statusText =
|
|
1153
|
+
statusIcon = chalk5.yellow("\u26A0");
|
|
1154
|
+
statusText = chalk5.yellow("(modified locally)");
|
|
987
1155
|
break;
|
|
988
1156
|
case "local-only":
|
|
989
|
-
statusIcon =
|
|
990
|
-
statusText =
|
|
1157
|
+
statusIcon = chalk5.blue("?");
|
|
1158
|
+
statusText = chalk5.dim("(custom component)");
|
|
991
1159
|
break;
|
|
992
1160
|
}
|
|
993
|
-
console.log(` ${statusIcon} ${
|
|
1161
|
+
console.log(` ${statusIcon} ${chalk5.white(comp.name)} ${statusText}`);
|
|
994
1162
|
}
|
|
995
1163
|
console.log();
|
|
996
1164
|
}
|
|
997
1165
|
if (notInstalled.length > 0) {
|
|
998
|
-
console.log(
|
|
1166
|
+
console.log(chalk5.dim("Not Installed"));
|
|
999
1167
|
const notInstalledNames = notInstalled.map((c) => c.name).slice(0, 10);
|
|
1000
1168
|
const remaining = notInstalled.length - 10;
|
|
1001
|
-
console.log(
|
|
1169
|
+
console.log(chalk5.dim(` ${notInstalledNames.join(", ")}${remaining > 0 ? `, ... +${remaining} more` : ""}`));
|
|
1002
1170
|
console.log();
|
|
1003
1171
|
}
|
|
1004
|
-
console.log(
|
|
1172
|
+
console.log(chalk5.dim("\u2500".repeat(50)));
|
|
1005
1173
|
const parts = [];
|
|
1006
|
-
if (identical.length > 0) parts.push(
|
|
1007
|
-
if (modified.length > 0) parts.push(
|
|
1008
|
-
if (localOnly.length > 0) parts.push(
|
|
1174
|
+
if (identical.length > 0) parts.push(chalk5.green(`${identical.length} up to date`));
|
|
1175
|
+
if (modified.length > 0) parts.push(chalk5.yellow(`${modified.length} modified`));
|
|
1176
|
+
if (localOnly.length > 0) parts.push(chalk5.blue(`${localOnly.length} custom`));
|
|
1009
1177
|
console.log(parts.join(" \u2022 "));
|
|
1010
1178
|
if (modified.length > 0) {
|
|
1011
1179
|
console.log();
|
|
1012
|
-
console.log(
|
|
1013
|
-
console.log(
|
|
1180
|
+
console.log(chalk5.dim("Sync modified components:"));
|
|
1181
|
+
console.log(chalk5.cyan(` npx mcellui diff`));
|
|
1014
1182
|
}
|
|
1015
1183
|
} catch (error) {
|
|
1016
1184
|
spinner.fail("Failed to list installed components");
|
|
1017
|
-
|
|
1018
|
-
|
|
1185
|
+
handleError({
|
|
1186
|
+
message: "Failed to list installed components",
|
|
1187
|
+
hint: error instanceof Error ? error.message : "Check your network connection and try again"
|
|
1188
|
+
});
|
|
1019
1189
|
}
|
|
1020
1190
|
}
|
|
1021
1191
|
|
|
1022
1192
|
// src/commands/doctor.ts
|
|
1023
1193
|
import { Command as Command4 } from "commander";
|
|
1024
|
-
import
|
|
1194
|
+
import chalk6 from "chalk";
|
|
1025
1195
|
import fs6 from "fs-extra";
|
|
1026
1196
|
import path7 from "path";
|
|
1027
1197
|
var REQUIRED_PEER_DEPS = [
|
|
@@ -1030,7 +1200,7 @@ var REQUIRED_PEER_DEPS = [
|
|
|
1030
1200
|
{ name: "react-native-safe-area-context", minVersion: "4.0.0" }
|
|
1031
1201
|
];
|
|
1032
1202
|
var RECOMMENDED_DEPS = [
|
|
1033
|
-
{ name: "@
|
|
1203
|
+
{ name: "@metacells/mcellui-core", reason: "Theme system and utilities" }
|
|
1034
1204
|
];
|
|
1035
1205
|
function parseVersion(version) {
|
|
1036
1206
|
const cleaned = version.replace(/^[\^~>=<]+/, "").replace(/^workspace:\*?/, "");
|
|
@@ -1075,7 +1245,7 @@ async function checkProjectType(projectRoot) {
|
|
|
1075
1245
|
name: "Project Type",
|
|
1076
1246
|
status: "fail",
|
|
1077
1247
|
message: "Not an Expo or React Native project",
|
|
1078
|
-
fix: "
|
|
1248
|
+
fix: "mcellui requires Expo or React Native"
|
|
1079
1249
|
};
|
|
1080
1250
|
}
|
|
1081
1251
|
return {
|
|
@@ -1086,23 +1256,39 @@ async function checkProjectType(projectRoot) {
|
|
|
1086
1256
|
}
|
|
1087
1257
|
async function checkInitialized(projectRoot) {
|
|
1088
1258
|
const configFiles = [
|
|
1259
|
+
"mcellui.config.ts",
|
|
1260
|
+
"mcellui.config.js",
|
|
1261
|
+
"mcellui.config.json",
|
|
1089
1262
|
"nativeui.config.ts",
|
|
1263
|
+
// Legacy
|
|
1090
1264
|
"nativeui.config.js",
|
|
1265
|
+
// Legacy
|
|
1091
1266
|
"nativeui.config.json"
|
|
1267
|
+
// Legacy
|
|
1092
1268
|
];
|
|
1093
1269
|
let foundConfig = null;
|
|
1270
|
+
let isLegacy = false;
|
|
1094
1271
|
for (const file of configFiles) {
|
|
1095
1272
|
if (await fs6.pathExists(path7.join(projectRoot, file))) {
|
|
1096
1273
|
foundConfig = file;
|
|
1274
|
+
isLegacy = file.startsWith("nativeui.");
|
|
1097
1275
|
break;
|
|
1098
1276
|
}
|
|
1099
1277
|
}
|
|
1100
1278
|
if (!foundConfig) {
|
|
1101
1279
|
return {
|
|
1102
|
-
name: "
|
|
1280
|
+
name: "mcellui Config",
|
|
1103
1281
|
status: "fail",
|
|
1104
|
-
message: "
|
|
1105
|
-
fix: "Run: npx
|
|
1282
|
+
message: "mcellui.config.ts not found",
|
|
1283
|
+
fix: "Run: npx mcellui init"
|
|
1284
|
+
};
|
|
1285
|
+
}
|
|
1286
|
+
if (isLegacy) {
|
|
1287
|
+
return {
|
|
1288
|
+
name: "mcellui Config",
|
|
1289
|
+
status: "warn",
|
|
1290
|
+
message: `Found legacy config: ${foundConfig}`,
|
|
1291
|
+
fix: "Consider renaming to mcellui.config.ts"
|
|
1106
1292
|
};
|
|
1107
1293
|
}
|
|
1108
1294
|
try {
|
|
@@ -1113,7 +1299,7 @@ async function checkInitialized(projectRoot) {
|
|
|
1113
1299
|
const hasExport = content.includes("export default");
|
|
1114
1300
|
if (!hasExport) {
|
|
1115
1301
|
return {
|
|
1116
|
-
name: "
|
|
1302
|
+
name: "mcellui Config",
|
|
1117
1303
|
status: "warn",
|
|
1118
1304
|
message: "Config file missing default export",
|
|
1119
1305
|
fix: "Add: export default defineConfig({ ... })"
|
|
@@ -1121,7 +1307,7 @@ async function checkInitialized(projectRoot) {
|
|
|
1121
1307
|
}
|
|
1122
1308
|
if (!hasDefineConfig) {
|
|
1123
1309
|
return {
|
|
1124
|
-
name: "
|
|
1310
|
+
name: "mcellui Config",
|
|
1125
1311
|
status: "warn",
|
|
1126
1312
|
message: "Config not using defineConfig helper",
|
|
1127
1313
|
fix: "Wrap config with: defineConfig({ ... })"
|
|
@@ -1133,21 +1319,21 @@ async function checkInitialized(projectRoot) {
|
|
|
1133
1319
|
JSON.parse(content);
|
|
1134
1320
|
} catch {
|
|
1135
1321
|
return {
|
|
1136
|
-
name: "
|
|
1322
|
+
name: "mcellui Config",
|
|
1137
1323
|
status: "fail",
|
|
1138
1324
|
message: "Invalid JSON in config file",
|
|
1139
|
-
fix: "Check JSON syntax in
|
|
1325
|
+
fix: "Check JSON syntax in mcellui.config.json"
|
|
1140
1326
|
};
|
|
1141
1327
|
}
|
|
1142
1328
|
}
|
|
1143
1329
|
return {
|
|
1144
|
-
name: "
|
|
1330
|
+
name: "mcellui Config",
|
|
1145
1331
|
status: "pass",
|
|
1146
1332
|
message: `Found ${foundConfig}`
|
|
1147
1333
|
};
|
|
1148
1334
|
} catch (error) {
|
|
1149
1335
|
return {
|
|
1150
|
-
name: "
|
|
1336
|
+
name: "mcellui Config",
|
|
1151
1337
|
status: "fail",
|
|
1152
1338
|
message: "Could not read config file",
|
|
1153
1339
|
fix: error instanceof Error ? error.message : "Check file permissions"
|
|
@@ -1159,7 +1345,14 @@ async function checkPaths(projectRoot) {
|
|
|
1159
1345
|
const defaultUtilsPath = "./lib/utils";
|
|
1160
1346
|
let componentsPathValue = defaultComponentsPath;
|
|
1161
1347
|
let utilsPathValue = defaultUtilsPath;
|
|
1162
|
-
const configFiles = [
|
|
1348
|
+
const configFiles = [
|
|
1349
|
+
"mcellui.config.ts",
|
|
1350
|
+
"mcellui.config.js",
|
|
1351
|
+
"mcellui.config.json",
|
|
1352
|
+
"nativeui.config.ts",
|
|
1353
|
+
"nativeui.config.js",
|
|
1354
|
+
"nativeui.config.json"
|
|
1355
|
+
];
|
|
1163
1356
|
for (const file of configFiles) {
|
|
1164
1357
|
const configPath = path7.join(projectRoot, file);
|
|
1165
1358
|
if (await fs6.pathExists(configPath)) {
|
|
@@ -1183,7 +1376,7 @@ async function checkPaths(projectRoot) {
|
|
|
1183
1376
|
name: "Component Paths",
|
|
1184
1377
|
status: "warn",
|
|
1185
1378
|
message: "Component and utils directories not created yet",
|
|
1186
|
-
fix: `Add a component: npx
|
|
1379
|
+
fix: `Add a component: npx mcellui add button`
|
|
1187
1380
|
};
|
|
1188
1381
|
}
|
|
1189
1382
|
if (!componentsExist) {
|
|
@@ -1191,7 +1384,7 @@ async function checkPaths(projectRoot) {
|
|
|
1191
1384
|
name: "Component Paths",
|
|
1192
1385
|
status: "warn",
|
|
1193
1386
|
message: `Components directory not found: ${componentsPathValue}`,
|
|
1194
|
-
fix: "Add a component to create it: npx
|
|
1387
|
+
fix: "Add a component to create it: npx mcellui add button"
|
|
1195
1388
|
};
|
|
1196
1389
|
}
|
|
1197
1390
|
return {
|
|
@@ -1379,43 +1572,43 @@ async function checkExpoGo(projectRoot) {
|
|
|
1379
1572
|
}
|
|
1380
1573
|
function printReport(report) {
|
|
1381
1574
|
console.log();
|
|
1382
|
-
console.log(
|
|
1383
|
-
console.log(
|
|
1575
|
+
console.log(chalk6.bold("mcellui Doctor"));
|
|
1576
|
+
console.log(chalk6.dim("Checking your project setup..."));
|
|
1384
1577
|
console.log();
|
|
1385
|
-
console.log(
|
|
1386
|
-
console.log(
|
|
1387
|
-
console.log(
|
|
1578
|
+
console.log(chalk6.dim("Project:"), report.projectRoot);
|
|
1579
|
+
console.log(chalk6.dim("Type:"), report.projectType);
|
|
1580
|
+
console.log(chalk6.dim("Package Manager:"), report.packageManager);
|
|
1388
1581
|
console.log();
|
|
1389
|
-
console.log(
|
|
1582
|
+
console.log(chalk6.bold("Checks"));
|
|
1390
1583
|
console.log();
|
|
1391
1584
|
for (const check of report.checks) {
|
|
1392
|
-
const icon = check.status === "pass" ?
|
|
1393
|
-
const statusColor = check.status === "pass" ?
|
|
1394
|
-
console.log(` ${icon} ${
|
|
1585
|
+
const icon = check.status === "pass" ? chalk6.green("\u2713") : check.status === "warn" ? chalk6.yellow("!") : chalk6.red("\u2717");
|
|
1586
|
+
const statusColor = check.status === "pass" ? chalk6.green : check.status === "warn" ? chalk6.yellow : chalk6.red;
|
|
1587
|
+
console.log(` ${icon} ${chalk6.white(check.name)}`);
|
|
1395
1588
|
console.log(` ${statusColor(check.message)}`);
|
|
1396
1589
|
if (check.fix && check.status !== "pass") {
|
|
1397
|
-
console.log(
|
|
1590
|
+
console.log(chalk6.dim(` Fix: ${check.fix}`));
|
|
1398
1591
|
}
|
|
1399
1592
|
}
|
|
1400
1593
|
console.log();
|
|
1401
1594
|
const summaryParts = [];
|
|
1402
1595
|
if (report.passed > 0) {
|
|
1403
|
-
summaryParts.push(
|
|
1596
|
+
summaryParts.push(chalk6.green(`${report.passed} passed`));
|
|
1404
1597
|
}
|
|
1405
1598
|
if (report.warnings > 0) {
|
|
1406
|
-
summaryParts.push(
|
|
1599
|
+
summaryParts.push(chalk6.yellow(`${report.warnings} warnings`));
|
|
1407
1600
|
}
|
|
1408
1601
|
if (report.failed > 0) {
|
|
1409
|
-
summaryParts.push(
|
|
1602
|
+
summaryParts.push(chalk6.red(`${report.failed} failed`));
|
|
1410
1603
|
}
|
|
1411
|
-
console.log(
|
|
1604
|
+
console.log(chalk6.bold("Summary:"), summaryParts.join(", "));
|
|
1412
1605
|
console.log();
|
|
1413
1606
|
if (report.failed > 0) {
|
|
1414
|
-
console.log(
|
|
1607
|
+
console.log(chalk6.red("Some checks failed. Please fix the issues above."));
|
|
1415
1608
|
} else if (report.warnings > 0) {
|
|
1416
|
-
console.log(
|
|
1609
|
+
console.log(chalk6.yellow("Your project has some warnings but should work."));
|
|
1417
1610
|
} else {
|
|
1418
|
-
console.log(
|
|
1611
|
+
console.log(chalk6.green("Your project is properly configured!"));
|
|
1419
1612
|
}
|
|
1420
1613
|
console.log();
|
|
1421
1614
|
}
|
|
@@ -1424,9 +1617,7 @@ var doctorCommand = new Command4().name("doctor").description("Check project set
|
|
|
1424
1617
|
const cwd = path7.resolve(options.cwd);
|
|
1425
1618
|
const projectRoot = await getProjectRoot(cwd);
|
|
1426
1619
|
if (!projectRoot) {
|
|
1427
|
-
|
|
1428
|
-
console.log(chalk5.dim("Make sure you run this command in a project directory."));
|
|
1429
|
-
process.exit(1);
|
|
1620
|
+
errors.noProject();
|
|
1430
1621
|
}
|
|
1431
1622
|
const projectType = await detectProjectType(projectRoot);
|
|
1432
1623
|
const packageManager = await detectPackageManager(projectRoot);
|
|
@@ -1464,14 +1655,16 @@ var doctorCommand = new Command4().name("doctor").description("Check project set
|
|
|
1464
1655
|
process.exit(1);
|
|
1465
1656
|
}
|
|
1466
1657
|
} catch (error) {
|
|
1467
|
-
|
|
1468
|
-
|
|
1658
|
+
handleError({
|
|
1659
|
+
message: "Doctor check failed",
|
|
1660
|
+
hint: error instanceof Error ? error.message : "Run again with --json for details"
|
|
1661
|
+
});
|
|
1469
1662
|
}
|
|
1470
1663
|
});
|
|
1471
1664
|
|
|
1472
1665
|
// src/commands/diff.ts
|
|
1473
1666
|
import { Command as Command5 } from "commander";
|
|
1474
|
-
import
|
|
1667
|
+
import chalk7 from "chalk";
|
|
1475
1668
|
import ora4 from "ora";
|
|
1476
1669
|
import fs7 from "fs-extra";
|
|
1477
1670
|
import path8 from "path";
|
|
@@ -1482,22 +1675,18 @@ var diffCommand = new Command5().name("diff").description("Compare locally insta
|
|
|
1482
1675
|
const cwd = path8.resolve(options.cwd);
|
|
1483
1676
|
const projectRoot = await getProjectRoot(cwd);
|
|
1484
1677
|
if (!projectRoot) {
|
|
1485
|
-
|
|
1486
|
-
console.log(chalk6.dim("Run `npx mcellui init` first."));
|
|
1487
|
-
process.exit(1);
|
|
1678
|
+
errors.noProject();
|
|
1488
1679
|
}
|
|
1489
1680
|
const config = await getConfig(projectRoot);
|
|
1490
1681
|
if (!config) {
|
|
1491
|
-
|
|
1492
|
-
console.log(chalk6.dim("Run `npx mcellui init` first."));
|
|
1493
|
-
process.exit(1);
|
|
1682
|
+
errors.notInitialized();
|
|
1494
1683
|
}
|
|
1495
1684
|
spinner.start("Scanning installed components...");
|
|
1496
1685
|
const componentsDir = path8.join(projectRoot, config.componentsPath);
|
|
1497
1686
|
const installedFiles = await getInstalledFiles(componentsDir);
|
|
1498
1687
|
if (installedFiles.length === 0) {
|
|
1499
1688
|
spinner.info("No components installed yet.");
|
|
1500
|
-
console.log(
|
|
1689
|
+
console.log(chalk7.dim("\nAdd components with: npx mcellui add <component>"));
|
|
1501
1690
|
return;
|
|
1502
1691
|
}
|
|
1503
1692
|
spinner.text = "Fetching registry...";
|
|
@@ -1519,8 +1708,11 @@ var diffCommand = new Command5().name("diff").description("Compare locally insta
|
|
|
1519
1708
|
return componentFileNames.includes(fileName);
|
|
1520
1709
|
});
|
|
1521
1710
|
if (filesToCompare.length === 0) {
|
|
1522
|
-
spinner.
|
|
1523
|
-
|
|
1711
|
+
spinner.stop();
|
|
1712
|
+
handleError({
|
|
1713
|
+
message: "None of the specified components are installed",
|
|
1714
|
+
hint: "Check component names: npx mcellui list --installed"
|
|
1715
|
+
});
|
|
1524
1716
|
}
|
|
1525
1717
|
}
|
|
1526
1718
|
spinner.text = "Comparing components...";
|
|
@@ -1560,10 +1752,8 @@ var diffCommand = new Command5().name("diff").description("Compare locally insta
|
|
|
1560
1752
|
continue;
|
|
1561
1753
|
}
|
|
1562
1754
|
const localContent = await fs7.readFile(localFile, "utf-8");
|
|
1563
|
-
const normalizedLocal =
|
|
1564
|
-
const normalizedRegistry =
|
|
1565
|
-
transformImports(registryFile.content, config)
|
|
1566
|
-
);
|
|
1755
|
+
const normalizedLocal = normalizeForComparison(localContent);
|
|
1756
|
+
const normalizedRegistry = normalizeForComparison(registryFile.content);
|
|
1567
1757
|
if (normalizedLocal === normalizedRegistry) {
|
|
1568
1758
|
results.push({
|
|
1569
1759
|
name: registryItem.name,
|
|
@@ -1606,35 +1796,37 @@ var diffCommand = new Command5().name("diff").description("Compare locally insta
|
|
|
1606
1796
|
const hasChanges = results.some((r) => r.status === "modified");
|
|
1607
1797
|
process.exit(hasChanges ? 1 : 0);
|
|
1608
1798
|
} catch (error) {
|
|
1609
|
-
spinner.
|
|
1610
|
-
|
|
1611
|
-
|
|
1799
|
+
spinner.stop();
|
|
1800
|
+
handleError({
|
|
1801
|
+
message: "Failed to diff components",
|
|
1802
|
+
hint: error instanceof Error ? error.message : "Check your network connection"
|
|
1803
|
+
});
|
|
1612
1804
|
}
|
|
1613
1805
|
});
|
|
1614
1806
|
function printResults(results, listOnly) {
|
|
1615
1807
|
const identical = results.filter((r) => r.status === "identical");
|
|
1616
1808
|
const modified = results.filter((r) => r.status === "modified");
|
|
1617
1809
|
const localOnly = results.filter((r) => r.status === "local-only");
|
|
1618
|
-
const
|
|
1810
|
+
const errors2 = results.filter((r) => r.status === "error");
|
|
1619
1811
|
console.log();
|
|
1620
|
-
console.log(
|
|
1812
|
+
console.log(chalk7.bold("Comparing components..."));
|
|
1621
1813
|
console.log();
|
|
1622
1814
|
for (const result of results) {
|
|
1623
1815
|
switch (result.status) {
|
|
1624
1816
|
case "identical":
|
|
1625
|
-
console.log(`${
|
|
1817
|
+
console.log(`${chalk7.green("\u2713")} ${result.fileName} ${chalk7.dim("(identical)")}`);
|
|
1626
1818
|
break;
|
|
1627
1819
|
case "modified":
|
|
1628
|
-
console.log(`${
|
|
1820
|
+
console.log(`${chalk7.red("\u2717")} ${result.fileName} ${chalk7.yellow("(modified)")}`);
|
|
1629
1821
|
if (!listOnly && result.diff) {
|
|
1630
1822
|
printColoredDiff(result.diff);
|
|
1631
1823
|
}
|
|
1632
1824
|
break;
|
|
1633
1825
|
case "local-only":
|
|
1634
|
-
console.log(`${
|
|
1826
|
+
console.log(`${chalk7.yellow("\u26A0")} ${result.fileName} ${chalk7.dim("(not in registry)")}`);
|
|
1635
1827
|
break;
|
|
1636
1828
|
case "error":
|
|
1637
|
-
console.log(`${
|
|
1829
|
+
console.log(`${chalk7.red("!")} ${result.fileName} ${chalk7.red(`(error: ${result.error})`)}`);
|
|
1638
1830
|
break;
|
|
1639
1831
|
}
|
|
1640
1832
|
}
|
|
@@ -1643,12 +1835,12 @@ function printResults(results, listOnly) {
|
|
|
1643
1835
|
if (identical.length > 0) parts.push(`${identical.length} identical`);
|
|
1644
1836
|
if (modified.length > 0) parts.push(`${modified.length} modified`);
|
|
1645
1837
|
if (localOnly.length > 0) parts.push(`${localOnly.length} custom`);
|
|
1646
|
-
if (
|
|
1647
|
-
console.log(
|
|
1838
|
+
if (errors2.length > 0) parts.push(`${errors2.length} errors`);
|
|
1839
|
+
console.log(chalk7.dim(`Summary: ${parts.join(", ")}`));
|
|
1648
1840
|
if (modified.length > 0) {
|
|
1649
1841
|
console.log();
|
|
1650
|
-
console.log(
|
|
1651
|
-
console.log(
|
|
1842
|
+
console.log(chalk7.dim("Update modified components with:"));
|
|
1843
|
+
console.log(chalk7.cyan(` npx mcellui add ${modified.map((m) => m.name).join(" ")} --overwrite`));
|
|
1652
1844
|
}
|
|
1653
1845
|
}
|
|
1654
1846
|
function printColoredDiff(diffOutput) {
|
|
@@ -1656,47 +1848,42 @@ function printColoredDiff(diffOutput) {
|
|
|
1656
1848
|
const contentLines = lines.slice(4);
|
|
1657
1849
|
for (const line of contentLines) {
|
|
1658
1850
|
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
1659
|
-
console.log(
|
|
1851
|
+
console.log(chalk7.green(` ${line}`));
|
|
1660
1852
|
} else if (line.startsWith("-") && !line.startsWith("---")) {
|
|
1661
|
-
console.log(
|
|
1853
|
+
console.log(chalk7.red(` ${line}`));
|
|
1662
1854
|
} else if (line.startsWith("@@")) {
|
|
1663
|
-
console.log(
|
|
1855
|
+
console.log(chalk7.cyan(` ${line}`));
|
|
1664
1856
|
} else if (line.trim()) {
|
|
1665
|
-
console.log(
|
|
1857
|
+
console.log(chalk7.dim(` ${line}`));
|
|
1666
1858
|
}
|
|
1667
1859
|
}
|
|
1668
1860
|
}
|
|
1669
1861
|
|
|
1670
1862
|
// src/commands/update.ts
|
|
1671
1863
|
import { Command as Command6 } from "commander";
|
|
1672
|
-
import
|
|
1864
|
+
import chalk8 from "chalk";
|
|
1673
1865
|
import ora5 from "ora";
|
|
1674
1866
|
import prompts3 from "prompts";
|
|
1675
1867
|
import fs8 from "fs-extra";
|
|
1676
1868
|
import path9 from "path";
|
|
1677
|
-
import crypto from "crypto";
|
|
1678
1869
|
var updateCommand = new Command6().name("update").description("Update installed components to latest registry versions").argument("[components...]", "Specific components to update (default: all outdated)").option("-y, --yes", "Skip confirmation prompt").option("--all", "Update all components (including up-to-date)").option("--dry-run", "Show what would be updated without making changes").option("--cwd <path>", "Working directory", process.cwd()).action(async (components, options) => {
|
|
1679
1870
|
const spinner = ora5();
|
|
1680
1871
|
try {
|
|
1681
1872
|
const cwd = path9.resolve(options.cwd);
|
|
1682
1873
|
const projectRoot = await getProjectRoot(cwd);
|
|
1683
1874
|
if (!projectRoot) {
|
|
1684
|
-
|
|
1685
|
-
console.log(chalk7.dim("Run `npx nativeui init` first."));
|
|
1686
|
-
process.exit(1);
|
|
1875
|
+
errors.noProject();
|
|
1687
1876
|
}
|
|
1688
1877
|
const config = await getConfig(projectRoot);
|
|
1689
1878
|
if (!config) {
|
|
1690
|
-
|
|
1691
|
-
console.log(chalk7.dim("Run `npx nativeui init` first."));
|
|
1692
|
-
process.exit(1);
|
|
1879
|
+
errors.notInitialized();
|
|
1693
1880
|
}
|
|
1694
1881
|
spinner.start("Checking for updates...");
|
|
1695
1882
|
const componentsDir = path9.join(projectRoot, config.componentsPath);
|
|
1696
1883
|
const diffs = await getComponentDiffs(componentsDir, config);
|
|
1697
1884
|
if (diffs.length === 0) {
|
|
1698
1885
|
spinner.info("No components installed yet.");
|
|
1699
|
-
console.log(
|
|
1886
|
+
console.log(chalk8.dim("\nAdd components with: npx mcellui add <component>"));
|
|
1700
1887
|
return;
|
|
1701
1888
|
}
|
|
1702
1889
|
spinner.stop();
|
|
@@ -1705,7 +1892,7 @@ var updateCommand = new Command6().name("update").description("Update installed
|
|
|
1705
1892
|
toUpdate = diffs.filter((d) => components.includes(d.name));
|
|
1706
1893
|
const notFound = components.filter((c) => !diffs.some((d) => d.name === c));
|
|
1707
1894
|
if (notFound.length > 0) {
|
|
1708
|
-
console.log(
|
|
1895
|
+
console.log(chalk8.yellow(`Components not found: ${notFound.join(", ")}`));
|
|
1709
1896
|
}
|
|
1710
1897
|
} else if (options.all) {
|
|
1711
1898
|
toUpdate = diffs;
|
|
@@ -1713,19 +1900,19 @@ var updateCommand = new Command6().name("update").description("Update installed
|
|
|
1713
1900
|
toUpdate = diffs.filter((d) => d.hasUpdate);
|
|
1714
1901
|
}
|
|
1715
1902
|
if (toUpdate.length === 0) {
|
|
1716
|
-
console.log(
|
|
1903
|
+
console.log(chalk8.green("\n\u2713 All components are up to date!"));
|
|
1717
1904
|
return;
|
|
1718
1905
|
}
|
|
1719
1906
|
console.log();
|
|
1720
|
-
console.log(
|
|
1907
|
+
console.log(chalk8.bold(`Components to update (${toUpdate.length}):`));
|
|
1721
1908
|
for (const comp of toUpdate) {
|
|
1722
|
-
const status = comp.hasUpdate ?
|
|
1723
|
-
const label = comp.hasUpdate ?
|
|
1909
|
+
const status = comp.hasUpdate ? chalk8.yellow("\u25CF") : chalk8.green("\u25CF");
|
|
1910
|
+
const label = comp.hasUpdate ? chalk8.dim("(update available)") : chalk8.dim("(re-sync)");
|
|
1724
1911
|
console.log(` ${status} ${comp.name} ${label}`);
|
|
1725
1912
|
}
|
|
1726
1913
|
console.log();
|
|
1727
1914
|
if (options.dryRun) {
|
|
1728
|
-
console.log(
|
|
1915
|
+
console.log(chalk8.dim("Dry run mode - no changes made."));
|
|
1729
1916
|
return;
|
|
1730
1917
|
}
|
|
1731
1918
|
if (!options.yes) {
|
|
@@ -1735,8 +1922,11 @@ var updateCommand = new Command6().name("update").description("Update installed
|
|
|
1735
1922
|
message: `Update ${toUpdate.length} component${toUpdate.length !== 1 ? "s" : ""}?`,
|
|
1736
1923
|
initial: true
|
|
1737
1924
|
});
|
|
1925
|
+
if (confirm === void 0) {
|
|
1926
|
+
process.exit(0);
|
|
1927
|
+
}
|
|
1738
1928
|
if (!confirm) {
|
|
1739
|
-
console.log(
|
|
1929
|
+
console.log(chalk8.dim("Cancelled."));
|
|
1740
1930
|
return;
|
|
1741
1931
|
}
|
|
1742
1932
|
}
|
|
@@ -1758,7 +1948,7 @@ var updateCommand = new Command6().name("update").description("Update installed
|
|
|
1758
1948
|
for (const file of component.files) {
|
|
1759
1949
|
const targetPath = path9.join(targetDir, file.name);
|
|
1760
1950
|
await fs8.ensureDir(targetDir);
|
|
1761
|
-
const transformedContent =
|
|
1951
|
+
const transformedContent = transformToInstalled(file.content, config);
|
|
1762
1952
|
await fs8.writeFile(targetPath, transformedContent);
|
|
1763
1953
|
}
|
|
1764
1954
|
spinner.succeed(`Updated ${comp.name}`);
|
|
@@ -1776,27 +1966,32 @@ var updateCommand = new Command6().name("update").description("Update installed
|
|
|
1776
1966
|
}
|
|
1777
1967
|
console.log();
|
|
1778
1968
|
if (successCount > 0) {
|
|
1779
|
-
console.log(
|
|
1969
|
+
console.log(chalk8.green(`\u2713 Updated ${successCount} component${successCount !== 1 ? "s" : ""}`));
|
|
1780
1970
|
}
|
|
1781
1971
|
if (failCount > 0) {
|
|
1782
|
-
console.log(
|
|
1972
|
+
console.log(chalk8.red(`\u2717 Failed to update ${failCount} component${failCount !== 1 ? "s" : ""}`));
|
|
1783
1973
|
}
|
|
1784
1974
|
const uniqueDeps = [...new Set(allDependencies)];
|
|
1785
1975
|
const uniqueDevDeps = [...new Set(allDevDependencies)];
|
|
1786
1976
|
if (uniqueDeps.length || uniqueDevDeps.length) {
|
|
1787
1977
|
console.log();
|
|
1788
|
-
console.log(
|
|
1978
|
+
console.log(chalk8.bold("Install/update dependencies:"));
|
|
1789
1979
|
if (uniqueDeps.length) {
|
|
1790
|
-
console.log(
|
|
1980
|
+
console.log(chalk8.cyan(` npx expo install ${uniqueDeps.join(" ")}`));
|
|
1791
1981
|
}
|
|
1792
1982
|
if (uniqueDevDeps.length) {
|
|
1793
|
-
console.log(
|
|
1983
|
+
console.log(chalk8.cyan(` npm install -D ${uniqueDevDeps.join(" ")}`));
|
|
1794
1984
|
}
|
|
1795
1985
|
}
|
|
1986
|
+
if (failCount > 0) {
|
|
1987
|
+
process.exit(1);
|
|
1988
|
+
}
|
|
1796
1989
|
} catch (error) {
|
|
1797
1990
|
spinner.fail("Failed to update");
|
|
1798
|
-
|
|
1799
|
-
|
|
1991
|
+
handleError({
|
|
1992
|
+
message: "Failed to update components",
|
|
1993
|
+
hint: error instanceof Error ? error.message : "Check your network connection and try again"
|
|
1994
|
+
});
|
|
1800
1995
|
}
|
|
1801
1996
|
});
|
|
1802
1997
|
async function getComponentDiffs(componentsDir, config) {
|
|
@@ -1842,34 +2037,17 @@ async function checkForUpdate(localFile, registryItem, config) {
|
|
|
1842
2037
|
const registryFile = component.files.find((f) => f.name === fileName);
|
|
1843
2038
|
if (!registryFile) return false;
|
|
1844
2039
|
const localContent = await fs8.readFile(localFile, "utf-8");
|
|
1845
|
-
const
|
|
1846
|
-
const
|
|
1847
|
-
|
|
1848
|
-
return localHash !== registryHash;
|
|
2040
|
+
const normalizedLocal = normalizeForComparison(localContent);
|
|
2041
|
+
const normalizedRegistry = normalizeForComparison(registryFile.content);
|
|
2042
|
+
return normalizedLocal !== normalizedRegistry;
|
|
1849
2043
|
} catch {
|
|
1850
2044
|
return false;
|
|
1851
2045
|
}
|
|
1852
2046
|
}
|
|
1853
|
-
function hashContent(content) {
|
|
1854
|
-
const normalized = content.replace(/\r\n/g, "\n").replace(/\s+$/gm, "").trim();
|
|
1855
|
-
return crypto.createHash("md5").update(normalized).digest("hex");
|
|
1856
|
-
}
|
|
1857
|
-
function transformImports3(code, config) {
|
|
1858
|
-
let transformed = code;
|
|
1859
|
-
const utilsAlias = config.aliases?.utils || "@/lib/utils";
|
|
1860
|
-
if (utilsAlias === "@/lib/utils") {
|
|
1861
|
-
return transformed;
|
|
1862
|
-
}
|
|
1863
|
-
transformed = transformed.replace(
|
|
1864
|
-
/from ['"]@\/lib\/utils['"]/g,
|
|
1865
|
-
`from '${utilsAlias}'`
|
|
1866
|
-
);
|
|
1867
|
-
return transformed;
|
|
1868
|
-
}
|
|
1869
2047
|
|
|
1870
2048
|
// src/commands/create.ts
|
|
1871
2049
|
import { Command as Command7 } from "commander";
|
|
1872
|
-
import
|
|
2050
|
+
import chalk9 from "chalk";
|
|
1873
2051
|
import ora6 from "ora";
|
|
1874
2052
|
import prompts4 from "prompts";
|
|
1875
2053
|
import fs9 from "fs-extra";
|
|
@@ -1880,33 +2058,31 @@ var createCommand = new Command7().name("create").description("Scaffold a new cu
|
|
|
1880
2058
|
const cwd = path10.resolve(options.cwd);
|
|
1881
2059
|
const projectRoot = await getProjectRoot(cwd);
|
|
1882
2060
|
if (!projectRoot) {
|
|
1883
|
-
|
|
1884
|
-
console.log(chalk8.dim("Run `npx nativeui init` first."));
|
|
1885
|
-
process.exit(1);
|
|
2061
|
+
errors.noProject();
|
|
1886
2062
|
}
|
|
1887
2063
|
const config = await getConfig(projectRoot);
|
|
1888
2064
|
if (!config) {
|
|
1889
|
-
|
|
1890
|
-
console.log(chalk8.dim("Run `npx nativeui init` first."));
|
|
1891
|
-
process.exit(1);
|
|
2065
|
+
errors.notInitialized();
|
|
1892
2066
|
}
|
|
1893
2067
|
const componentName = toPascalCase(name);
|
|
1894
2068
|
const fileName = toKebabCase(name) + ".tsx";
|
|
1895
2069
|
const targetDir = path10.join(projectRoot, config.componentsPath);
|
|
1896
2070
|
const targetPath = path10.join(targetDir, fileName);
|
|
1897
2071
|
if (await fs9.pathExists(targetPath)) {
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
2072
|
+
handleError({
|
|
2073
|
+
message: `Component already exists: ${fileName}`,
|
|
2074
|
+
hint: "Choose a different name or delete the existing file",
|
|
2075
|
+
code: "COMPONENT_EXISTS"
|
|
2076
|
+
});
|
|
1901
2077
|
}
|
|
1902
2078
|
if (!options.yes) {
|
|
1903
2079
|
console.log();
|
|
1904
|
-
console.log(
|
|
1905
|
-
console.log(` Name: ${
|
|
1906
|
-
console.log(` File: ${
|
|
1907
|
-
console.log(` Path: ${
|
|
1908
|
-
console.log(` Template: ${
|
|
1909
|
-
console.log(` ForwardRef: ${
|
|
2080
|
+
console.log(chalk9.bold("Create new component:"));
|
|
2081
|
+
console.log(` Name: ${chalk9.cyan(componentName)}`);
|
|
2082
|
+
console.log(` File: ${chalk9.dim(fileName)}`);
|
|
2083
|
+
console.log(` Path: ${chalk9.dim(targetPath)}`);
|
|
2084
|
+
console.log(` Template: ${chalk9.dim(options.template)}`);
|
|
2085
|
+
console.log(` ForwardRef: ${chalk9.dim(options.forwardRef ? "Yes" : "No")}`);
|
|
1910
2086
|
console.log();
|
|
1911
2087
|
const { confirm } = await prompts4({
|
|
1912
2088
|
type: "confirm",
|
|
@@ -1914,8 +2090,11 @@ var createCommand = new Command7().name("create").description("Scaffold a new cu
|
|
|
1914
2090
|
message: "Create this component?",
|
|
1915
2091
|
initial: true
|
|
1916
2092
|
});
|
|
2093
|
+
if (confirm === void 0) {
|
|
2094
|
+
process.exit(0);
|
|
2095
|
+
}
|
|
1917
2096
|
if (!confirm) {
|
|
1918
|
-
console.log(
|
|
2097
|
+
console.log(chalk9.dim("Cancelled."));
|
|
1919
2098
|
return;
|
|
1920
2099
|
}
|
|
1921
2100
|
}
|
|
@@ -1925,15 +2104,17 @@ var createCommand = new Command7().name("create").description("Scaffold a new cu
|
|
|
1925
2104
|
await fs9.writeFile(targetPath, code);
|
|
1926
2105
|
spinner.succeed(`Created ${fileName}`);
|
|
1927
2106
|
console.log();
|
|
1928
|
-
console.log(
|
|
1929
|
-
console.log(` 1. Edit your component: ${
|
|
2107
|
+
console.log(chalk9.bold("Next steps:"));
|
|
2108
|
+
console.log(` 1. Edit your component: ${chalk9.cyan(targetPath)}`);
|
|
1930
2109
|
console.log(` 2. Import it in your app:`);
|
|
1931
|
-
console.log(
|
|
2110
|
+
console.log(chalk9.dim(` import { ${componentName} } from '${config.aliases?.components || "@/components"}/ui/${toKebabCase(name)}';`));
|
|
1932
2111
|
console.log();
|
|
1933
2112
|
} catch (error) {
|
|
1934
2113
|
spinner.fail("Failed to create component");
|
|
1935
|
-
|
|
1936
|
-
|
|
2114
|
+
handleError({
|
|
2115
|
+
message: "Failed to create component",
|
|
2116
|
+
hint: error instanceof Error ? error.message : "Check file permissions and try again"
|
|
2117
|
+
});
|
|
1937
2118
|
}
|
|
1938
2119
|
});
|
|
1939
2120
|
function toPascalCase(str) {
|
|
@@ -1955,7 +2136,7 @@ function generateBasicComponent(name, forwardRef) {
|
|
|
1955
2136
|
if (forwardRef) {
|
|
1956
2137
|
return `import React, { forwardRef } from 'react';
|
|
1957
2138
|
import { View, Text, StyleSheet, ViewProps } from 'react-native';
|
|
1958
|
-
import { useTheme } from '@
|
|
2139
|
+
import { useTheme } from '@metacells/mcellui-core';
|
|
1959
2140
|
|
|
1960
2141
|
export interface ${name}Props extends ViewProps {
|
|
1961
2142
|
/**
|
|
@@ -1967,7 +2148,7 @@ export interface ${name}Props extends ViewProps {
|
|
|
1967
2148
|
/**
|
|
1968
2149
|
* ${name}
|
|
1969
2150
|
*
|
|
1970
|
-
* A custom component created with
|
|
2151
|
+
* A custom component created with mcellui create.
|
|
1971
2152
|
*
|
|
1972
2153
|
* @example
|
|
1973
2154
|
* \`\`\`tsx
|
|
@@ -2015,7 +2196,7 @@ const styles = StyleSheet.create({
|
|
|
2015
2196
|
}
|
|
2016
2197
|
return `import React from 'react';
|
|
2017
2198
|
import { View, Text, StyleSheet, ViewProps } from 'react-native';
|
|
2018
|
-
import { useTheme } from '@
|
|
2199
|
+
import { useTheme } from '@metacells/mcellui-core';
|
|
2019
2200
|
|
|
2020
2201
|
export interface ${name}Props extends ViewProps {
|
|
2021
2202
|
/**
|
|
@@ -2027,7 +2208,7 @@ export interface ${name}Props extends ViewProps {
|
|
|
2027
2208
|
/**
|
|
2028
2209
|
* ${name}
|
|
2029
2210
|
*
|
|
2030
|
-
* A custom component created with
|
|
2211
|
+
* A custom component created with mcellui create.
|
|
2031
2212
|
*
|
|
2032
2213
|
* @example
|
|
2033
2214
|
* \`\`\`tsx
|
|
@@ -2082,7 +2263,7 @@ import Animated, {
|
|
|
2082
2263
|
useSharedValue,
|
|
2083
2264
|
withSpring,
|
|
2084
2265
|
} from 'react-native-reanimated';
|
|
2085
|
-
import { useTheme } from '@
|
|
2266
|
+
import { useTheme } from '@metacells/mcellui-core';
|
|
2086
2267
|
|
|
2087
2268
|
export interface ${name}Props extends ViewProps {
|
|
2088
2269
|
/**
|
|
@@ -2094,7 +2275,7 @@ export interface ${name}Props extends ViewProps {
|
|
|
2094
2275
|
/**
|
|
2095
2276
|
* ${name}
|
|
2096
2277
|
*
|
|
2097
|
-
* An animated component created with
|
|
2278
|
+
* An animated component created with mcellui create.
|
|
2098
2279
|
*
|
|
2099
2280
|
* @example
|
|
2100
2281
|
* \`\`\`tsx
|
|
@@ -2151,7 +2332,7 @@ import Animated, {
|
|
|
2151
2332
|
useSharedValue,
|
|
2152
2333
|
withTiming,
|
|
2153
2334
|
} from 'react-native-reanimated';
|
|
2154
|
-
import { useTheme } from '@
|
|
2335
|
+
import { useTheme } from '@metacells/mcellui-core';
|
|
2155
2336
|
|
|
2156
2337
|
const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
|
|
2157
2338
|
|
|
@@ -2169,7 +2350,7 @@ export interface ${name}Props extends Omit<PressableProps, 'style'> {
|
|
|
2169
2350
|
/**
|
|
2170
2351
|
* ${name}
|
|
2171
2352
|
*
|
|
2172
|
-
* A pressable component created with
|
|
2353
|
+
* A pressable component created with mcellui create.
|
|
2173
2354
|
*
|
|
2174
2355
|
* @example
|
|
2175
2356
|
* \`\`\`tsx
|
|
@@ -2244,7 +2425,7 @@ import Animated, {
|
|
|
2244
2425
|
useSharedValue,
|
|
2245
2426
|
withTiming,
|
|
2246
2427
|
} from 'react-native-reanimated';
|
|
2247
|
-
import { useTheme } from '@
|
|
2428
|
+
import { useTheme } from '@metacells/mcellui-core';
|
|
2248
2429
|
|
|
2249
2430
|
const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
|
|
2250
2431
|
|
|
@@ -2262,7 +2443,7 @@ export interface ${name}Props extends Omit<PressableProps, 'style'> {
|
|
|
2262
2443
|
/**
|
|
2263
2444
|
* ${name}
|
|
2264
2445
|
*
|
|
2265
|
-
* A pressable component created with
|
|
2446
|
+
* A pressable component created with mcellui create.
|
|
2266
2447
|
*
|
|
2267
2448
|
* @example
|
|
2268
2449
|
* \`\`\`tsx
|
|
@@ -2334,7 +2515,7 @@ import Animated, {
|
|
|
2334
2515
|
useSharedValue,
|
|
2335
2516
|
withTiming,
|
|
2336
2517
|
} from 'react-native-reanimated';
|
|
2337
|
-
import { useTheme } from '@
|
|
2518
|
+
import { useTheme } from '@metacells/mcellui-core';
|
|
2338
2519
|
|
|
2339
2520
|
export interface ${name}Props extends TextInputProps {
|
|
2340
2521
|
/**
|
|
@@ -2350,7 +2531,7 @@ export interface ${name}Props extends TextInputProps {
|
|
|
2350
2531
|
/**
|
|
2351
2532
|
* ${name}
|
|
2352
2533
|
*
|
|
2353
|
-
* A custom input component created with
|
|
2534
|
+
* A custom input component created with mcellui create.
|
|
2354
2535
|
*
|
|
2355
2536
|
* @example
|
|
2356
2537
|
* \`\`\`tsx
|
|
@@ -2459,7 +2640,7 @@ import Animated, {
|
|
|
2459
2640
|
useSharedValue,
|
|
2460
2641
|
withTiming,
|
|
2461
2642
|
} from 'react-native-reanimated';
|
|
2462
|
-
import { useTheme } from '@
|
|
2643
|
+
import { useTheme } from '@metacells/mcellui-core';
|
|
2463
2644
|
|
|
2464
2645
|
export interface ${name}Props extends TextInputProps {
|
|
2465
2646
|
/**
|
|
@@ -2475,7 +2656,7 @@ export interface ${name}Props extends TextInputProps {
|
|
|
2475
2656
|
/**
|
|
2476
2657
|
* ${name}
|
|
2477
2658
|
*
|
|
2478
|
-
* A custom input component created with
|
|
2659
|
+
* A custom input component created with mcellui create.
|
|
2479
2660
|
*
|
|
2480
2661
|
* @example
|
|
2481
2662
|
* \`\`\`tsx
|
|
@@ -2575,7 +2756,7 @@ const styles = StyleSheet.create({
|
|
|
2575
2756
|
|
|
2576
2757
|
// src/commands/pick.ts
|
|
2577
2758
|
import { Command as Command8 } from "commander";
|
|
2578
|
-
import
|
|
2759
|
+
import chalk10 from "chalk";
|
|
2579
2760
|
import prompts5 from "prompts";
|
|
2580
2761
|
import ora7 from "ora";
|
|
2581
2762
|
import fs10 from "fs-extra";
|
|
@@ -2627,7 +2808,7 @@ function formatCategoryName(category) {
|
|
|
2627
2808
|
}
|
|
2628
2809
|
function formatComponentChoice(item, installed) {
|
|
2629
2810
|
const isInstalled = installed.has(item.name);
|
|
2630
|
-
const status = isInstalled ?
|
|
2811
|
+
const status = isInstalled ? chalk10.green(" \u2713") : "";
|
|
2631
2812
|
const description = item.description || "";
|
|
2632
2813
|
return {
|
|
2633
2814
|
title: `${item.name}${status}`,
|
|
@@ -2636,37 +2817,25 @@ function formatComponentChoice(item, installed) {
|
|
|
2636
2817
|
disabled: isInstalled
|
|
2637
2818
|
};
|
|
2638
2819
|
}
|
|
2639
|
-
function transformImports4(code, config) {
|
|
2640
|
-
let transformed = code;
|
|
2641
|
-
const utilsAlias = config.aliases?.utils || "@/lib/utils";
|
|
2642
|
-
if (utilsAlias === "@/lib/utils") {
|
|
2643
|
-
return transformed;
|
|
2644
|
-
}
|
|
2645
|
-
transformed = transformed.replace(
|
|
2646
|
-
/from ['"]@\/lib\/utils['"]/g,
|
|
2647
|
-
`from '${utilsAlias}'`
|
|
2648
|
-
);
|
|
2649
|
-
return transformed;
|
|
2650
|
-
}
|
|
2651
2820
|
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) => {
|
|
2652
|
-
console.log(
|
|
2821
|
+
console.log(chalk10.bold("\n\u{1F3A8} mcellui Component Picker\n"));
|
|
2653
2822
|
const cwd = path11.resolve(options.cwd);
|
|
2654
2823
|
const projectRoot = await getProjectRoot(cwd);
|
|
2655
2824
|
if (!projectRoot) {
|
|
2656
|
-
|
|
2657
|
-
console.log(chalk9.dim("Run `npx nativeui init` first.\n"));
|
|
2658
|
-
return;
|
|
2825
|
+
errors.noProject();
|
|
2659
2826
|
}
|
|
2660
2827
|
const config = await getConfig(projectRoot);
|
|
2661
2828
|
if (!config) {
|
|
2662
|
-
|
|
2663
|
-
return;
|
|
2829
|
+
errors.notInitialized();
|
|
2664
2830
|
}
|
|
2665
2831
|
const spinner = ora7("Loading component registry...").start();
|
|
2666
2832
|
const registry = await getRegistry();
|
|
2667
2833
|
if (!registry.length) {
|
|
2668
|
-
spinner.
|
|
2669
|
-
|
|
2834
|
+
spinner.stop();
|
|
2835
|
+
handleError({
|
|
2836
|
+
message: "Could not load component registry",
|
|
2837
|
+
hint: "Check your internet connection and try again"
|
|
2838
|
+
});
|
|
2670
2839
|
}
|
|
2671
2840
|
spinner.succeed(`Loaded ${registry.length} components`);
|
|
2672
2841
|
const componentsDir = path11.join(projectRoot, config.componentsPath);
|
|
@@ -2696,8 +2865,11 @@ var pickCommand = new Command8().name("pick").description("Interactively browse
|
|
|
2696
2865
|
message: "Select a category",
|
|
2697
2866
|
choices: categoryChoices
|
|
2698
2867
|
});
|
|
2868
|
+
if (categoryResponse.category === void 0) {
|
|
2869
|
+
process.exit(0);
|
|
2870
|
+
}
|
|
2699
2871
|
if (!categoryResponse.category) {
|
|
2700
|
-
console.log(
|
|
2872
|
+
console.log(chalk10.yellow("\nCancelled.\n"));
|
|
2701
2873
|
return;
|
|
2702
2874
|
}
|
|
2703
2875
|
selectedCategory = categoryResponse.category;
|
|
@@ -2710,10 +2882,10 @@ var pickCommand = new Command8().name("pick").description("Interactively browse
|
|
|
2710
2882
|
);
|
|
2711
2883
|
const availableCount = componentChoices.filter((c) => !c.disabled).length;
|
|
2712
2884
|
if (availableCount === 0) {
|
|
2713
|
-
console.log(
|
|
2885
|
+
console.log(chalk10.green("\n\u2713 All components in this category are already installed!\n"));
|
|
2714
2886
|
return;
|
|
2715
2887
|
}
|
|
2716
|
-
console.log(
|
|
2888
|
+
console.log(chalk10.dim(`
|
|
2717
2889
|
${installed.size} already installed, ${availableCount} available
|
|
2718
2890
|
`));
|
|
2719
2891
|
const componentResponse = await prompts5({
|
|
@@ -2724,14 +2896,17 @@ ${installed.size} already installed, ${availableCount} available
|
|
|
2724
2896
|
hint: "- Space to select. Return to submit",
|
|
2725
2897
|
instructions: false
|
|
2726
2898
|
});
|
|
2899
|
+
if (componentResponse.components === void 0) {
|
|
2900
|
+
process.exit(0);
|
|
2901
|
+
}
|
|
2727
2902
|
if (!componentResponse.components || componentResponse.components.length === 0) {
|
|
2728
|
-
console.log(
|
|
2903
|
+
console.log(chalk10.yellow("\nNo components selected.\n"));
|
|
2729
2904
|
return;
|
|
2730
2905
|
}
|
|
2731
2906
|
const selectedComponents = componentResponse.components;
|
|
2732
|
-
console.log(
|
|
2907
|
+
console.log(chalk10.bold("\nComponents to install:"));
|
|
2733
2908
|
for (const name of selectedComponents) {
|
|
2734
|
-
console.log(
|
|
2909
|
+
console.log(chalk10.cyan(` \u2022 ${name}`));
|
|
2735
2910
|
}
|
|
2736
2911
|
const confirmResponse = await prompts5({
|
|
2737
2912
|
type: "confirm",
|
|
@@ -2739,12 +2914,16 @@ ${installed.size} already installed, ${availableCount} available
|
|
|
2739
2914
|
message: `Install ${selectedComponents.length} component(s)?`,
|
|
2740
2915
|
initial: true
|
|
2741
2916
|
});
|
|
2917
|
+
if (confirmResponse.proceed === void 0) {
|
|
2918
|
+
process.exit(0);
|
|
2919
|
+
}
|
|
2742
2920
|
if (!confirmResponse.proceed) {
|
|
2743
|
-
console.log(
|
|
2921
|
+
console.log(chalk10.yellow("\nCancelled.\n"));
|
|
2744
2922
|
return;
|
|
2745
2923
|
}
|
|
2746
2924
|
console.log("");
|
|
2747
2925
|
let successCount = 0;
|
|
2926
|
+
let failCount = 0;
|
|
2748
2927
|
const allDependencies = [];
|
|
2749
2928
|
const allDevDependencies = [];
|
|
2750
2929
|
for (const name of selectedComponents) {
|
|
@@ -2753,6 +2932,7 @@ ${installed.size} already installed, ${availableCount} available
|
|
|
2753
2932
|
const component = await fetchComponent(name);
|
|
2754
2933
|
if (!component) {
|
|
2755
2934
|
installSpinner.fail(`Component "${name}" not found`);
|
|
2935
|
+
failCount++;
|
|
2756
2936
|
continue;
|
|
2757
2937
|
}
|
|
2758
2938
|
const targetDir = path11.join(projectRoot, config.componentsPath);
|
|
@@ -2763,10 +2943,10 @@ ${installed.size} already installed, ${availableCount} available
|
|
|
2763
2943
|
continue;
|
|
2764
2944
|
}
|
|
2765
2945
|
await fs10.ensureDir(targetDir);
|
|
2766
|
-
const transformedContent =
|
|
2946
|
+
const transformedContent = transformToInstalled(file.content, config);
|
|
2767
2947
|
await fs10.writeFile(targetPath, transformedContent);
|
|
2768
2948
|
}
|
|
2769
|
-
installSpinner.succeed(`Installed ${
|
|
2949
|
+
installSpinner.succeed(`Installed ${chalk10.green(name)}`);
|
|
2770
2950
|
successCount++;
|
|
2771
2951
|
if (component.dependencies?.length) {
|
|
2772
2952
|
allDependencies.push(...component.dependencies);
|
|
@@ -2775,42 +2955,51 @@ ${installed.size} already installed, ${availableCount} available
|
|
|
2775
2955
|
allDevDependencies.push(...component.devDependencies);
|
|
2776
2956
|
}
|
|
2777
2957
|
if (component.registryDependencies?.length) {
|
|
2778
|
-
console.log(
|
|
2958
|
+
console.log(chalk10.dim(` Requires: ${component.registryDependencies.join(", ")}`));
|
|
2779
2959
|
}
|
|
2780
2960
|
} catch (error) {
|
|
2781
2961
|
installSpinner.fail(`Failed to install ${name}: ${error}`);
|
|
2962
|
+
failCount++;
|
|
2782
2963
|
}
|
|
2783
2964
|
}
|
|
2965
|
+
if (failCount > 0) {
|
|
2966
|
+
process.exit(1);
|
|
2967
|
+
}
|
|
2784
2968
|
console.log(
|
|
2785
|
-
|
|
2969
|
+
chalk10.bold.green(`
|
|
2786
2970
|
\u2713 Successfully installed ${successCount}/${selectedComponents.length} components
|
|
2787
2971
|
`)
|
|
2788
2972
|
);
|
|
2789
2973
|
const uniqueDeps = [...new Set(allDependencies)];
|
|
2790
2974
|
const uniqueDevDeps = [...new Set(allDevDependencies)];
|
|
2791
2975
|
if (uniqueDeps.length || uniqueDevDeps.length) {
|
|
2792
|
-
console.log(
|
|
2976
|
+
console.log(chalk10.bold("Install dependencies:"));
|
|
2793
2977
|
if (uniqueDeps.length) {
|
|
2794
|
-
console.log(
|
|
2978
|
+
console.log(chalk10.cyan(` npx expo install ${uniqueDeps.join(" ")}`));
|
|
2795
2979
|
}
|
|
2796
2980
|
if (uniqueDevDeps.length) {
|
|
2797
|
-
console.log(
|
|
2981
|
+
console.log(chalk10.cyan(` npm install -D ${uniqueDevDeps.join(" ")}`));
|
|
2798
2982
|
}
|
|
2799
2983
|
console.log("");
|
|
2800
2984
|
}
|
|
2801
2985
|
if (successCount > 0) {
|
|
2802
|
-
console.log(
|
|
2986
|
+
console.log(chalk10.dim("Import example:"));
|
|
2803
2987
|
const firstComponent = selectedComponents[0];
|
|
2804
2988
|
const pascalName = firstComponent.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
|
|
2805
2989
|
const alias = config.aliases?.components || "@/components/ui";
|
|
2806
|
-
console.log(
|
|
2990
|
+
console.log(chalk10.dim(` import { ${pascalName} } from '${alias}/${firstComponent}';
|
|
2807
2991
|
`));
|
|
2808
2992
|
}
|
|
2809
2993
|
});
|
|
2810
2994
|
|
|
2811
2995
|
// src/index.ts
|
|
2812
2996
|
var program = new Command9();
|
|
2813
|
-
program.name("
|
|
2997
|
+
program.name("mcellui").description("Add beautiful UI components to your Expo/React Native project").version("0.1.4");
|
|
2998
|
+
program.configureOutput({
|
|
2999
|
+
writeOut: (str) => process.stdout.write(str),
|
|
3000
|
+
writeErr: (str) => process.stderr.write(str),
|
|
3001
|
+
outputError: (str, write) => write(chalk11.red(str))
|
|
3002
|
+
});
|
|
2814
3003
|
program.addCommand(initCommand);
|
|
2815
3004
|
program.addCommand(addCommand);
|
|
2816
3005
|
program.addCommand(listCommand);
|
|
@@ -2819,4 +3008,14 @@ program.addCommand(diffCommand);
|
|
|
2819
3008
|
program.addCommand(updateCommand);
|
|
2820
3009
|
program.addCommand(createCommand);
|
|
2821
3010
|
program.addCommand(pickCommand);
|
|
2822
|
-
|
|
3011
|
+
async function main() {
|
|
3012
|
+
try {
|
|
3013
|
+
await program.parseAsync(process.argv);
|
|
3014
|
+
} catch (error) {
|
|
3015
|
+
handleError({
|
|
3016
|
+
message: error instanceof Error ? error.message : "An unexpected error occurred",
|
|
3017
|
+
hint: "If this persists, run: npx mcellui doctor"
|
|
3018
|
+
});
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
main();
|