handle method

  1. @override
Future<int> handle(
  1. ArtisanContext ctx
)

Execute the command. Returns the process exit code.

Implementation

@override
Future<int> handle(ArtisanContext ctx) async {
  // 1. Read all CLI option values — no defaults live in this method.
  final root = ctx.input.option('root') as String? ?? '.';
  final outputDir = ctx.input.option('output') as String? ?? 'public';
  String teamId = ctx.input.option('team-id') as String? ?? '';
  String bundleId = ctx.input.option('bundle-id') as String? ?? '';
  String packageName = ctx.input.option('package-name') as String? ?? '';
  List<String> fingerprints =
      ctx.input.option('sha256-fingerprints') as List<String>? ?? [];
  List<String> paths = ctx.input.option('paths') as List<String>? ?? [];

  // 2. Resolve paths for the operation.
  final projectRoot = getProjectRoot();
  final effectiveRoot = root == '.' ? projectRoot : root;
  final outputPath = '$effectiveRoot/$outputDir';

  // 3. Try to read lib/config/deeplink.dart.
  final configFile = File('$effectiveRoot/lib/config/deeplink.dart');
  if (configFile.existsSync()) {
    final content = configFile.readAsStringSync();
    final config = parseDeeplinkConfig(content);

    // 4. Merge: CLI flags override config values.
    if (teamId.isEmpty) {
      teamId = config['teamId'] as String? ?? '';
    }
    if (bundleId.isEmpty) {
      bundleId = config['bundleId'] as String? ?? '';
    }
    if (packageName.isEmpty) {
      packageName = config['packageName'] as String? ?? '';
    }
    if (fingerprints.isEmpty) {
      fingerprints = config['fingerprints'] as List<String>? ?? [];
    }

    // Only use config paths if CLI didn't explicitly provide paths.
    // `paths` has a default value `['/*']` in `configure()`. We only override it
    // if it equals the default AND config has paths.
    if (paths.length == 1 &&
        paths.first == '/*' &&
        (config['paths'] as List<String>? ?? []).isNotEmpty) {
      paths = config['paths'] as List<String>;
    }
  }

  ctx.output.info('Generating deep link files in $outputPath...');

  // 5. Detect iOS platform via PlatformHelper — inform user about AASA placement.
  if (PlatformHelper.hasPlatform(effectiveRoot, 'ios')) {
    ctx.output.info(
      'iOS platform detected — upload apple-app-site-association to your web server root.',
    );
  }

  // 6. Build and write apple-app-site-association (iOS Universal Links).
  if (teamId.isNotEmpty && bundleId.isNotEmpty) {
    final aasaData = buildAppleAppSiteAssociation(teamId, bundleId, paths);
    JsonEditor.writeJson('$outputPath/apple-app-site-association', aasaData);
    ctx.output.success('Created $outputPath/apple-app-site-association');
  } else {
    ctx.output.warning(
      'Skipping apple-app-site-association — provide --team-id and --bundle-id.',
    );
  }

  // 7. Build and write assetlinks.json (Android App Links).
  if (packageName.isNotEmpty && fingerprints.isNotEmpty) {
    final assetLinksData = buildAssetLinks(packageName, fingerprints);
    JsonEditor.writeJson('$outputPath/assetlinks.json', assetLinksData);
    ctx.output.success('Created $outputPath/assetlinks.json');
  } else {
    ctx.output.warning(
      'Skipping assetlinks.json — provide --package-name and --sha256-fingerprints.',
    );
  }

  return 0;
}