expo-bbase 1.1.1 → 1.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/dist/index.js CHANGED
@@ -30,8 +30,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
+ addModule: () => addModule,
33
34
  createProject: () => createProject,
34
- run: () => run
35
+ run: () => run,
36
+ upgradeProject: () => upgradeProject
35
37
  });
36
38
  module.exports = __toCommonJS(src_exports);
37
39
  var import_chalk = __toESM(require("chalk"));
@@ -47,6 +49,16 @@ function registerCreateCommand(program) {
47
49
  await createProject(projectName);
48
50
  });
49
51
  }
52
+ function registerUpgradeCommand(program) {
53
+ program.command("upgrade").description("Upgrade an existing expo-bbase project to the latest module versions").option("--dir <path>", "Project directory (default: current directory)", process.cwd()).action(async (options) => {
54
+ await upgradeProject(options.dir);
55
+ });
56
+ }
57
+ function registerAddCommand(program) {
58
+ program.command("add [modules...]").description("Add one or more modules to an existing expo-bbase project").option("--dir <path>", "Project directory (default: current directory)", process.cwd()).action(async (moduleIds, options) => {
59
+ await addModule(moduleIds, options.dir);
60
+ });
61
+ }
50
62
 
51
63
  // src/utils/lines.ts
52
64
  function lines(...args) {
@@ -3322,6 +3334,9 @@ async function writeFile(filePath, content) {
3322
3334
  await import_fs_extra.default.ensureDir(dir);
3323
3335
  await import_fs_extra.default.writeFile(filePath, content, "utf-8");
3324
3336
  }
3337
+ async function readJson(filePath) {
3338
+ return import_fs_extra.default.readJson(filePath);
3339
+ }
3325
3340
  async function writeJson(filePath, data, spaces = 2) {
3326
3341
  const dir = import_path.default.dirname(filePath);
3327
3342
  await import_fs_extra.default.ensureDir(dir);
@@ -3337,6 +3352,18 @@ function replaceTemplateVars(content, vars) {
3337
3352
  }
3338
3353
 
3339
3354
  // src/utils/package.ts
3355
+ async function mergeDependencies(pkgPath, deps, devDeps) {
3356
+ const pkg = await readJson(pkgPath);
3357
+ pkg.dependencies = {
3358
+ ...pkg.dependencies || {},
3359
+ ...deps
3360
+ };
3361
+ pkg.devDependencies = {
3362
+ ...pkg.devDependencies || {},
3363
+ ...devDeps
3364
+ };
3365
+ await writeJson(pkgPath, pkg);
3366
+ }
3340
3367
  function generateBasePackageJson(projectName) {
3341
3368
  return {
3342
3369
  name: projectName,
@@ -3372,9 +3399,11 @@ function generateBasePackageJson(projectName) {
3372
3399
 
3373
3400
  // src/index.ts
3374
3401
  var import_execa = require("execa");
3402
+ var CLI_VERSION = "1.2.0";
3403
+ var CONFIG_FILE = ".expo-bbase.json";
3375
3404
  async function run() {
3376
3405
  const program = new import_commander.Command();
3377
- program.name("expo-bbase").description("Expo SDK 54+ \u811A\u624B\u67B6 CLI \u5DE5\u5177").version("1.0.0");
3406
+ program.name("expo-bbase").description("Expo SDK 54+ scaffolding CLI tool").version(CLI_VERSION);
3378
3407
  program.argument("[project-name]", "Name of the project to create").action(async (projectName) => {
3379
3408
  if (!projectName) {
3380
3409
  console.error(import_chalk.default.red("Error: Please provide a project name."));
@@ -3384,15 +3413,28 @@ async function run() {
3384
3413
  await createProject(projectName);
3385
3414
  });
3386
3415
  registerCreateCommand(program);
3416
+ registerUpgradeCommand(program);
3417
+ registerAddCommand(program);
3387
3418
  await program.parseAsync(process.argv);
3388
3419
  }
3420
+ async function readProjectConfig(targetDir) {
3421
+ const configPath = import_path2.default.join(targetDir, CONFIG_FILE);
3422
+ if (!await import_fs_extra2.default.pathExists(configPath)) {
3423
+ return null;
3424
+ }
3425
+ return import_fs_extra2.default.readJson(configPath);
3426
+ }
3427
+ async function writeProjectConfig(targetDir, config) {
3428
+ const configPath = import_path2.default.join(targetDir, CONFIG_FILE);
3429
+ await writeJson(configPath, config);
3430
+ }
3389
3431
  async function createProject(projectName) {
3390
3432
  console.log();
3391
3433
  console.log(
3392
3434
  import_chalk.default.bold.cyan(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557")
3393
3435
  );
3394
3436
  console.log(
3395
- import_chalk.default.bold.cyan(" \u2551 expo-bbase \u2014 Expo \u811A\u624B\u67B6\u5DE5\u5177 \u2551")
3437
+ import_chalk.default.bold.cyan(" \u2551 expo-bbase \u2014 Expo Scaffolding \u2551")
3396
3438
  );
3397
3439
  console.log(
3398
3440
  import_chalk.default.bold.cyan(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D")
@@ -3406,49 +3448,43 @@ async function createProject(projectName) {
3406
3448
  const { selectedModules } = await (0, import_prompts.default)({
3407
3449
  type: "multiselect",
3408
3450
  name: "selectedModules",
3409
- message: "\u9009\u62E9\u9700\u8981\u7684\u529F\u80FD\u6A21\u5757\uFF08\u7A7A\u683C\u5207\u6362\uFF0C\u56DE\u8F66\u786E\u8BA4\uFF09",
3451
+ message: "Select modules (Space to toggle, Enter to confirm)",
3410
3452
  choices,
3411
- hint: "- \u7A7A\u683C\u5207\u6362\u9009\u62E9 \xB7 a \u5168\u9009/\u53D6\u6D88 \xB7 \u56DE\u8F66\u786E\u8BA4",
3453
+ hint: "- Space toggle \xB7 a select all/none \xB7 Enter confirm",
3412
3454
  instructions: false
3413
3455
  });
3414
3456
  if (selectedModules === void 0) {
3415
- console.log(import_chalk.default.yellow("\n\u5DF2\u53D6\u6D88\u521B\u5EFA\u9879\u76EE\u3002"));
3457
+ console.log(import_chalk.default.yellow("\nCancelled."));
3416
3458
  process.exit(0);
3417
3459
  }
3418
3460
  const selectedModuleDefs = getModulesByIds(selectedModules);
3419
3461
  const targetDir = import_path2.default.resolve(process.cwd(), projectName);
3420
3462
  console.log();
3421
- console.log(import_chalk.default.white(` \u{1F4E6} \u9879\u76EE\u540D\u79F0: ${import_chalk.default.bold(projectName)}`));
3422
- console.log(
3423
- import_chalk.default.white(` \u{1F4C2} \u76EE\u6807\u8DEF\u5F84: ${import_chalk.default.gray(targetDir)}`)
3424
- );
3463
+ console.log(import_chalk.default.white(` \u{1F4E6} Project: ${import_chalk.default.bold(projectName)}`));
3464
+ console.log(import_chalk.default.white(` \u{1F4C2} Path: ${import_chalk.default.gray(targetDir)}`));
3425
3465
  console.log(
3426
3466
  import_chalk.default.white(
3427
- ` \u{1F9E9} \u9009\u62E9\u6A21\u5757: ${import_chalk.default.green(selectedModuleDefs.map((m) => m.name).join(", ") || "\u65E0")}`
3467
+ ` \u{1F9E9} Modules: ${import_chalk.default.green(selectedModuleDefs.map((m) => m.name).join(", ") || "none")}`
3428
3468
  )
3429
3469
  );
3430
3470
  console.log();
3431
- const spinner = (0, import_ora.default)("\u6B63\u5728\u521B\u5EFA\u9879\u76EE...").start();
3471
+ const spinner = (0, import_ora.default)("Creating project...").start();
3432
3472
  try {
3433
3473
  const baseTemplates = generateBaseTemplates(projectName);
3434
3474
  for (const file of baseTemplates) {
3435
3475
  const filePath = import_path2.default.join(targetDir, file.path);
3436
- const content = replaceTemplateVars(file.content, {
3437
- projectName
3438
- });
3476
+ const content = replaceTemplateVars(file.content, { projectName });
3439
3477
  await writeFile(filePath, content);
3440
3478
  }
3441
- spinner.text = "\u6B63\u5728\u5199\u5165\u6A21\u5757\u6587\u4EF6...";
3479
+ spinner.text = "Writing module files...";
3442
3480
  for (const mod of selectedModuleDefs) {
3443
3481
  for (const file of mod.files) {
3444
3482
  const filePath = import_path2.default.join(targetDir, file.path);
3445
- const content = replaceTemplateVars(file.content, {
3446
- projectName
3447
- });
3483
+ const content = replaceTemplateVars(file.content, { projectName });
3448
3484
  await writeFile(filePath, content);
3449
3485
  }
3450
3486
  }
3451
- spinner.text = "\u6B63\u5728\u751F\u6210 package.json...";
3487
+ spinner.text = "Generating package.json...";
3452
3488
  const pkgJson = generateBasePackageJson(projectName);
3453
3489
  const allDeps = {};
3454
3490
  const allDevDeps = {};
@@ -3463,48 +3499,298 @@ async function createProject(projectName) {
3463
3499
  );
3464
3500
  const pkgPath = import_path2.default.join(targetDir, "package.json");
3465
3501
  await writeJson(pkgPath, pkgJson);
3466
- spinner.text = "\u6B63\u5728\u914D\u7F6E app.json...";
3502
+ spinner.text = "Configuring app.json...";
3467
3503
  await updateAppJson(targetDir, selectedModuleDefs, projectName);
3468
- spinner.text = "\u6B63\u5728\u914D\u7F6E Babel...";
3504
+ spinner.text = "Configuring Babel...";
3469
3505
  await updateBabelConfig(targetDir, selectedModuleDefs);
3470
- spinner.text = "\u6B63\u5728\u914D\u7F6E\u5165\u53E3\u6587\u4EF6...";
3506
+ spinner.text = "Configuring layout...";
3471
3507
  await updateLayoutFile(targetDir, selectedModuleDefs);
3472
- spinner.text = "\u6B63\u5728\u5B89\u88C5\u4F9D\u8D56 (yarn install)...";
3508
+ await writeProjectConfig(targetDir, {
3509
+ projectName,
3510
+ selectedModules,
3511
+ cliVersion: CLI_VERSION
3512
+ });
3513
+ spinner.text = "Installing dependencies (yarn install)...";
3473
3514
  try {
3474
3515
  await (0, import_execa.execa)("yarn", ["install"], {
3475
3516
  cwd: targetDir,
3476
3517
  timeout: 3e5
3477
- // 5 minute timeout
3478
3518
  });
3479
3519
  } catch (installError) {
3480
3520
  const errMsg = installError instanceof Error ? installError.message : String(installError);
3481
- spinner.warn("yarn install \u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u5B89\u88C5\u4F9D\u8D56");
3482
- console.log(import_chalk.default.red(` \u9519\u8BEF: ${errMsg}`));
3483
- console.log(
3484
- import_chalk.default.gray(` cd ${projectName} && yarn install`)
3485
- );
3521
+ spinner.warn("yarn install failed, please install manually");
3522
+ console.log(import_chalk.default.red(` Error: ${errMsg}`));
3523
+ console.log(import_chalk.default.gray(` cd ${projectName} && yarn install`));
3486
3524
  }
3487
- spinner.succeed(import_chalk.default.green("\u9879\u76EE\u521B\u5EFA\u6210\u529F\uFF01"));
3525
+ spinner.succeed(import_chalk.default.green("Project created!"));
3488
3526
  console.log();
3489
- console.log(import_chalk.default.bold(" \u{1F389} \u4E0B\u4E00\u6B65\uFF1A"));
3527
+ console.log(import_chalk.default.bold(" \u{1F389} Next steps:"));
3490
3528
  console.log(import_chalk.default.white(` cd ${projectName}`));
3491
3529
  console.log(import_chalk.default.white(" npx expo start"));
3492
3530
  console.log();
3493
3531
  if (selectedModuleDefs.length > 0) {
3494
- console.log(import_chalk.default.bold(" \u{1F4CB} \u5DF2\u9009\u6A21\u5757\uFF1A"));
3532
+ console.log(import_chalk.default.bold(" \u{1F4CB} Selected modules:"));
3495
3533
  for (const mod of selectedModuleDefs) {
3496
3534
  console.log(import_chalk.default.white(` \u2713 ${mod.name}`));
3497
3535
  }
3498
3536
  console.log();
3499
3537
  }
3500
3538
  } catch (error) {
3501
- spinner.fail(import_chalk.default.red("\u9879\u76EE\u521B\u5EFA\u5931\u8D25"));
3539
+ spinner.fail(import_chalk.default.red("Project creation failed"));
3502
3540
  console.error(error);
3503
3541
  process.exit(1);
3504
3542
  }
3505
3543
  }
3506
- async function updateAppJson(targetDir, selectedModules, projectName) {
3544
+ async function upgradeProject(targetDir) {
3545
+ console.log();
3546
+ console.log(
3547
+ import_chalk.default.bold.cyan(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557")
3548
+ );
3549
+ console.log(
3550
+ import_chalk.default.bold.cyan(" \u2551 expo-bbase \u2014 Upgrade \u2551")
3551
+ );
3552
+ console.log(
3553
+ import_chalk.default.bold.cyan(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D")
3554
+ );
3555
+ console.log();
3556
+ const absDir = import_path2.default.resolve(targetDir);
3557
+ const config = await readProjectConfig(absDir);
3558
+ if (!config) {
3559
+ console.error(
3560
+ import_chalk.default.red(
3561
+ ` \u2716 No ${CONFIG_FILE} found in ${absDir}
3562
+ This directory doesn't appear to be an expo-bbase project.
3563
+ If it is, run "expo-bbase add" to register modules.`
3564
+ )
3565
+ );
3566
+ process.exit(1);
3567
+ }
3568
+ console.log(
3569
+ import_chalk.default.white(` \u{1F4C2} Project: ${import_chalk.default.bold(config.projectName)}`)
3570
+ );
3571
+ console.log(
3572
+ import_chalk.default.white(` \u{1F4CB} CLI version: ${import_chalk.default.gray(config.cliVersion || "unknown")} \u2192 ${import_chalk.default.green(CLI_VERSION)}`)
3573
+ );
3574
+ console.log(
3575
+ import_chalk.default.white(
3576
+ ` \u{1F9E9} Modules: ${import_chalk.default.green(config.selectedModules.join(", ") || "none")}`
3577
+ )
3578
+ );
3579
+ console.log();
3580
+ const spinner = (0, import_ora.default)("Upgrading project...").start();
3581
+ try {
3582
+ const selectedModuleDefs = getModulesByIds(config.selectedModules);
3583
+ spinner.text = "Updating module files...";
3584
+ for (const mod of selectedModuleDefs) {
3585
+ for (const file of mod.files) {
3586
+ const filePath = import_path2.default.join(absDir, file.path);
3587
+ const content = replaceTemplateVars(file.content, {
3588
+ projectName: config.projectName
3589
+ });
3590
+ await writeFile(filePath, content);
3591
+ }
3592
+ }
3593
+ spinner.text = "Updating dependencies...";
3594
+ const allDeps = {};
3595
+ const allDevDeps = {};
3596
+ for (const mod of selectedModuleDefs) {
3597
+ Object.assign(allDeps, mod.dependencies);
3598
+ Object.assign(allDevDeps, mod.devDependencies);
3599
+ }
3600
+ const basePkg = generateBasePackageJson(config.projectName);
3601
+ Object.assign(allDeps, basePkg.dependencies);
3602
+ Object.assign(
3603
+ allDevDeps,
3604
+ basePkg.devDependencies
3605
+ );
3606
+ const pkgPath = import_path2.default.join(absDir, "package.json");
3607
+ await mergeDependencies(pkgPath, allDeps, allDevDeps);
3608
+ spinner.text = "Updating app.json...";
3609
+ await updateAppJson(absDir, selectedModuleDefs, config.projectName);
3610
+ spinner.text = "Updating Babel config...";
3611
+ await updateBabelConfig(absDir, selectedModuleDefs);
3612
+ spinner.text = "Updating layout...";
3613
+ await updateLayoutFile(absDir, selectedModuleDefs);
3614
+ config.cliVersion = CLI_VERSION;
3615
+ await writeProjectConfig(absDir, config);
3616
+ spinner.text = "Installing updated dependencies (yarn install)...";
3617
+ try {
3618
+ await (0, import_execa.execa)("yarn", ["install"], {
3619
+ cwd: absDir,
3620
+ timeout: 3e5
3621
+ });
3622
+ } catch (installError) {
3623
+ const errMsg = installError instanceof Error ? installError.message : String(installError);
3624
+ spinner.warn("yarn install failed, please install manually");
3625
+ console.log(import_chalk.default.red(` Error: ${errMsg}`));
3626
+ }
3627
+ spinner.succeed(import_chalk.default.green("Project upgraded!"));
3628
+ console.log();
3629
+ console.log(import_chalk.default.bold(" \u{1F4CB} Upgrade summary:"));
3630
+ console.log(import_chalk.default.white(` CLI: ${import_chalk.default.gray(config.cliVersion)} (before)`));
3631
+ console.log(import_chalk.default.white(` Modules: ${import_chalk.default.green(config.selectedModules.join(", "))}`));
3632
+ console.log();
3633
+ console.log(import_chalk.default.bold(" \u{1F389} Run your project:"));
3634
+ console.log(import_chalk.default.white(" npx expo start"));
3635
+ console.log();
3636
+ } catch (error) {
3637
+ spinner.fail(import_chalk.default.red("Upgrade failed"));
3638
+ console.error(error);
3639
+ process.exit(1);
3640
+ }
3641
+ }
3642
+ async function addModule(moduleIds, targetDir) {
3643
+ console.log();
3644
+ const absDir = import_path2.default.resolve(targetDir);
3645
+ let config = await readProjectConfig(absDir);
3646
+ if (!config) {
3647
+ const pkgPath = import_path2.default.join(absDir, "package.json");
3648
+ if (!await import_fs_extra2.default.pathExists(pkgPath)) {
3649
+ console.error(
3650
+ import_chalk.default.red(` \u2716 No package.json found in ${absDir}`)
3651
+ );
3652
+ process.exit(1);
3653
+ }
3654
+ const pkg = await import_fs_extra2.default.readJson(pkgPath);
3655
+ config = {
3656
+ projectName: pkg.name || import_path2.default.basename(absDir),
3657
+ selectedModules: [],
3658
+ cliVersion: CLI_VERSION
3659
+ };
3660
+ console.log(
3661
+ import_chalk.default.yellow(
3662
+ ` \u26A0 No ${CONFIG_FILE} found. Creating one for project "${config.projectName}".`
3663
+ )
3664
+ );
3665
+ }
3666
+ if (moduleIds.length === 0) {
3667
+ const availableModules = modules.filter(
3668
+ (m) => !config.selectedModules.includes(m.id)
3669
+ );
3670
+ if (availableModules.length === 0) {
3671
+ console.log(import_chalk.default.green(" \u2713 All modules are already installed!"));
3672
+ process.exit(0);
3673
+ }
3674
+ const choices = availableModules.map((m) => ({
3675
+ title: `${import_chalk.default.bold(m.name)} \u2014 ${import_chalk.default.gray(m.description)}`,
3676
+ value: m.id,
3677
+ selected: false
3678
+ }));
3679
+ const { selected } = await (0, import_prompts.default)({
3680
+ type: "multiselect",
3681
+ name: "selected",
3682
+ message: "Select modules to add (Space to toggle, Enter to confirm)",
3683
+ choices,
3684
+ hint: "- Space toggle \xB7 a select all/none \xB7 Enter confirm",
3685
+ instructions: false
3686
+ });
3687
+ if (selected === void 0 || selected.length === 0) {
3688
+ console.log(import_chalk.default.yellow(" No modules selected."));
3689
+ process.exit(0);
3690
+ }
3691
+ moduleIds = selected;
3692
+ }
3693
+ const invalidIds = moduleIds.filter((id) => !getModuleById(id));
3694
+ if (invalidIds.length > 0) {
3695
+ console.error(
3696
+ import_chalk.default.red(` \u2716 Unknown module(s): ${invalidIds.join(", ")}`)
3697
+ );
3698
+ console.log(
3699
+ import_chalk.default.gray(
3700
+ ` Available: ${modules.map((m) => m.id).join(", ")}`
3701
+ )
3702
+ );
3703
+ process.exit(1);
3704
+ }
3705
+ const newModuleIds = moduleIds.filter(
3706
+ (id) => !config.selectedModules.includes(id)
3707
+ );
3708
+ if (newModuleIds.length === 0) {
3709
+ console.log(
3710
+ import_chalk.default.yellow(" All specified modules are already installed.")
3711
+ );
3712
+ process.exit(0);
3713
+ }
3714
+ const newModuleDefs = getModulesByIds(newModuleIds);
3715
+ console.log(
3716
+ import_chalk.default.white(` \u{1F4C2} Project: ${import_chalk.default.bold(config.projectName)}`)
3717
+ );
3718
+ console.log(
3719
+ import_chalk.default.white(
3720
+ ` \u2795 Adding: ${import_chalk.default.green(newModuleDefs.map((m) => m.name).join(", "))}`
3721
+ )
3722
+ );
3723
+ console.log();
3724
+ const spinner = (0, import_ora.default)("Adding modules...").start();
3725
+ try {
3726
+ spinner.text = "Writing module files...";
3727
+ for (const mod of newModuleDefs) {
3728
+ for (const file of mod.files) {
3729
+ const filePath = import_path2.default.join(absDir, file.path);
3730
+ const content = replaceTemplateVars(file.content, {
3731
+ projectName: config.projectName
3732
+ });
3733
+ await writeFile(filePath, content);
3734
+ }
3735
+ }
3736
+ spinner.text = "Updating dependencies...";
3737
+ const allDeps = {};
3738
+ const allDevDeps = {};
3739
+ for (const mod of newModuleDefs) {
3740
+ Object.assign(allDeps, mod.dependencies);
3741
+ Object.assign(allDevDeps, mod.devDependencies);
3742
+ }
3743
+ const pkgPath = import_path2.default.join(absDir, "package.json");
3744
+ await mergeDependencies(pkgPath, allDeps, allDevDeps);
3745
+ spinner.text = "Updating app.json...";
3746
+ const existingModules = getModulesByIds(config.selectedModules);
3747
+ await updateAppJson(
3748
+ absDir,
3749
+ [...existingModules, ...newModuleDefs],
3750
+ config.projectName
3751
+ );
3752
+ spinner.text = "Updating Babel config...";
3753
+ await updateBabelConfig(absDir, newModuleDefs);
3754
+ spinner.text = "Updating layout...";
3755
+ await updateLayoutFile(absDir, newModuleDefs);
3756
+ config.selectedModules.push(...newModuleIds);
3757
+ config.cliVersion = CLI_VERSION;
3758
+ await writeProjectConfig(absDir, config);
3759
+ spinner.text = "Installing dependencies (yarn install)...";
3760
+ try {
3761
+ await (0, import_execa.execa)("yarn", ["install"], {
3762
+ cwd: absDir,
3763
+ timeout: 3e5
3764
+ });
3765
+ } catch (installError) {
3766
+ const errMsg = installError instanceof Error ? installError.message : String(installError);
3767
+ spinner.warn("yarn install failed, please install manually");
3768
+ console.log(import_chalk.default.red(` Error: ${errMsg}`));
3769
+ }
3770
+ spinner.succeed(import_chalk.default.green("Modules added!"));
3771
+ console.log();
3772
+ console.log(import_chalk.default.bold(" \u{1F4CB} Added modules:"));
3773
+ for (const mod of newModuleDefs) {
3774
+ console.log(import_chalk.default.white(` \u2713 ${mod.name} (${mod.id})`));
3775
+ }
3776
+ console.log();
3777
+ console.log(import_chalk.default.bold(" \u{1F9E9} All installed modules:"));
3778
+ for (const id of config.selectedModules) {
3779
+ const m = getModuleById(id);
3780
+ console.log(import_chalk.default.white(` \u2022 ${m?.name || id}`));
3781
+ }
3782
+ console.log();
3783
+ } catch (error) {
3784
+ spinner.fail(import_chalk.default.red("Failed to add modules"));
3785
+ console.error(error);
3786
+ process.exit(1);
3787
+ }
3788
+ }
3789
+ async function updateAppJson(targetDir, selectedModules, _projectName) {
3507
3790
  const appJsonPath = import_path2.default.join(targetDir, "app.json");
3791
+ if (!await import_fs_extra2.default.pathExists(appJsonPath)) {
3792
+ return;
3793
+ }
3508
3794
  const appJson = await import_fs_extra2.default.readJson(appJsonPath);
3509
3795
  const existingPlugins = appJson.expo?.plugins || [];
3510
3796
  for (const mod of selectedModules) {
@@ -3526,41 +3812,55 @@ async function updateAppJson(targetDir, selectedModules, projectName) {
3526
3812
  }
3527
3813
  async function updateBabelConfig(targetDir, selectedModules) {
3528
3814
  const babelPath = import_path2.default.join(targetDir, "babel.config.js");
3815
+ if (!await import_fs_extra2.default.pathExists(babelPath)) {
3816
+ return;
3817
+ }
3529
3818
  let content = await import_fs_extra2.default.readFile(babelPath, "utf-8");
3530
3819
  const extraPlugins = [];
3531
3820
  for (const mod of selectedModules) {
3532
- if (mod.babelPlugins) {
3821
+ if (mod.babelPlugins && mod.babelPlugins.length > 0) {
3533
3822
  extraPlugins.push(...mod.babelPlugins);
3534
3823
  }
3535
3824
  }
3536
3825
  if (extraPlugins.length > 0) {
3537
- const pluginStrings = extraPlugins.map((p) => ` "${p}"`).join(",\n");
3538
- content = content.replace(
3539
- /plugins:\s*\[([^\]]*)\]/,
3540
- `plugins: [$1${pluginStrings ? ",\n" + pluginStrings : ""}]`
3541
- );
3542
- await import_fs_extra2.default.writeFile(babelPath, content, "utf-8");
3826
+ const pluginsToAdd = extraPlugins.filter((p) => !content.includes(p));
3827
+ if (pluginsToAdd.length > 0) {
3828
+ const pluginStrings = pluginsToAdd.map((p) => ` "${p}"`).join(",\n");
3829
+ content = content.replace(
3830
+ /plugins:\s*\[([^\]]*)\]/,
3831
+ `plugins: [$1${pluginStrings ? ",\n" + pluginStrings : ""}]`
3832
+ );
3833
+ await import_fs_extra2.default.writeFile(babelPath, content, "utf-8");
3834
+ }
3543
3835
  }
3544
3836
  }
3545
3837
  async function updateLayoutFile(targetDir, selectedModules) {
3546
3838
  const layoutPath = import_path2.default.join(targetDir, "app/_layout.tsx");
3547
- const fs2 = import_fs_extra2.default;
3548
- let content = await fs2.readFile(layoutPath, "utf-8");
3839
+ if (!await import_fs_extra2.default.pathExists(layoutPath)) {
3840
+ return;
3841
+ }
3842
+ let content = await import_fs_extra2.default.readFile(layoutPath, "utf-8");
3549
3843
  const extraImports = [];
3550
3844
  const extraProviderPairs = [];
3551
3845
  for (const mod of selectedModules) {
3552
3846
  if (mod.layoutImports) {
3553
- extraImports.push(...mod.layoutImports);
3847
+ for (const imp of mod.layoutImports) {
3848
+ if (!content.includes(imp)) {
3849
+ extraImports.push(imp);
3850
+ }
3851
+ }
3554
3852
  }
3555
3853
  if (mod.layoutProviders) {
3556
3854
  for (const provider of mod.layoutProviders) {
3557
3855
  const match = provider.match(/^<(\w+)/);
3558
3856
  if (match) {
3559
3857
  const tagName = match[1];
3560
- extraProviderPairs.push({
3561
- open: ` ${provider}`,
3562
- close: ` </${tagName}>`
3563
- });
3858
+ if (!content.includes(`<${tagName}`)) {
3859
+ extraProviderPairs.push({
3860
+ open: ` ${provider}`,
3861
+ close: ` </${tagName}>`
3862
+ });
3863
+ }
3564
3864
  }
3565
3865
  }
3566
3866
  }
@@ -3589,7 +3889,7 @@ async function updateLayoutFile(targetDir, selectedModules) {
3589
3889
  }
3590
3890
  }
3591
3891
  }
3592
- await fs2.writeFile(layoutPath, content, "utf-8");
3892
+ await import_fs_extra2.default.writeFile(layoutPath, content, "utf-8");
3593
3893
  }
3594
3894
  run().catch((error) => {
3595
3895
  console.error(import_chalk.default.red("Fatal error:"), error);
@@ -3597,7 +3897,9 @@ run().catch((error) => {
3597
3897
  });
3598
3898
  // Annotate the CommonJS export names for ESM import in node:
3599
3899
  0 && (module.exports = {
3900
+ addModule,
3600
3901
  createProject,
3601
- run
3902
+ run,
3903
+ upgradeProject
3602
3904
  });
3603
3905
  //# sourceMappingURL=index.js.map