run method

  1. @override
Future<void> run()
override

Runs this command.

The return value is wrapped in a Future if necessary and returned by CommandRunner.runCommand.

Implementation

@override
Future<void> run() async {
  if (argResults!.rest.isEmpty) {
    print('Error: You must specify a project name.');
    print(
      'Usage: learmond create <name> [--type flutter|react-native|ruby|npm] [--package] [--org com.example]',
    );
    return;
  }

  final name = argResults!.rest[0];
  final type = argResults!['type'] as String;
  final shouldCd = argResults!['cd'] as bool;

  if (type == 'flutter') {
    final isPackage = argResults!['package'] as bool;
    final org = argResults!['org'] as String?;
    final args = ['create', name];
    if (isPackage) args.add('--template=package');
    if (org != null) args.addAll(['--org', org]);

    print('Running: flutter ${args.join(' ')}');
    final result = await Process.run('flutter', args);

    stdout.write(result.stdout);
    stderr.write(result.stderr);

    if (result.exitCode != 0) {
      print('Flutter create failed with exit code ${result.exitCode}');
      exit(result.exitCode);
    }

    print('\nFlutter project "$name" created successfully.');
  } else if (type == 'react-native') {
    // Use Expo to create a React Native project; Expo includes web support by default.
    print('Running: npx create-expo-app $name');
    final result = await Process.run('npx', ['create-expo-app', name]);

    stdout.write(result.stdout);
    stderr.write(result.stderr);

    if (result.exitCode != 0) {
      print('Expo create failed with exit code ${result.exitCode}');
      exit(result.exitCode);
    }

    // Ensure dependencies are installed (safe no-op if already done by the tool).
    print('Ensuring dependencies are installed in $name...');
    final installResult = await Process.run('npm', [
      'install',
    ], workingDirectory: name);
    stdout.write(installResult.stdout);
    stderr.write(installResult.stderr);
    if (installResult.exitCode != 0) {
      print('npm install failed with exit code ${installResult.exitCode}');
      // don't exit; project was created, but warn the user
    }

    // Update package.json scripts to include convenient web/start scripts.
    try {
      final pkgFile = File('$name/package.json');
      if (await pkgFile.exists()) {
        final content = await pkgFile.readAsString();
        final data = jsonDecode(content) as Map<String, dynamic>;
        final scripts =
            (data['scripts'] as Map<String, dynamic>?) ?? <String, dynamic>{};
        scripts.putIfAbsent('web', () => 'expo start --web');
        scripts.putIfAbsent('start', () => 'expo start');
        data['scripts'] = scripts;
        final encoder = JsonEncoder.withIndent('  ');
        await pkgFile.writeAsString(encoder.convert(data));
        print('Added npm scripts: "web" and "start" to package.json');
      }
    } catch (e) {
      print('Warning: failed to update package.json scripts: $e');
    }

    print('\nExpo project "$name" created successfully with web support.');
  } else if (type == 'ruby') {
    print('Running: bundle gem $name');
    final result = await Process.run('bundle', ['gem', name]);

    stdout.write(result.stdout);
    stderr.write(result.stderr);

    if (result.exitCode != 0) {
      print('Ruby gem create failed with exit code ${result.exitCode}');
      exit(result.exitCode);
    }

    print('\nRuby gem "$name" created successfully.');
  } else if (type == 'npm') {
    print('Running: npm init -y in $name directory');
    final createDirResult = await Process.run('mkdir', [name]);
    if (createDirResult.exitCode != 0) {
      print(
        'Failed to create directory "$name" with exit code ${createDirResult.exitCode}',
      );
      exit(createDirResult.exitCode);
    }
    final result = await Process.run('npm', [
      'init',
      '-y',
    ], workingDirectory: name);

    stdout.write(result.stdout);
    stderr.write(result.stderr);

    if (result.exitCode != 0) {
      print('NPM project create failed with exit code ${result.exitCode}');
      exit(result.exitCode);
    }

    print('\nNPM project "$name" created successfully.');
  } else {
    print('Unsupported project type: $type');
    return;
  }

  // Suggest changing directory
  if (shouldCd) {
    print('\nNext steps:');
    print('  cd $name');
    if (type == 'flutter') {
      print('  flutter pub get');
    } else if (type == 'react-native') {
      print('  npm install');
      print('  npx expo start --web # start web dev server');
      print('  npx expo start # start dev server for all platforms');
    } else if (type == 'ruby') {
      print('  bundle install');
    } else if (type == 'npm') {
      print('  npm install');
    }
    print('Now you are ready to start developing!');
  }
}