prune method

Future<FixResult> prune(
  1. ComparisonResult comparison
)

Prune orphaned keys from JSON files.

Implementation

Future<FixResult> prune(ComparisonResult comparison) async {
  final filesModified = <String>{};
  final warnings = <String>[];
  var keysRemoved = 0;

  if (comparison.orphanedInJson.isEmpty) {
    _log('No orphaned keys to remove.');
    return FixResult(
      filesModified: [],
      keysAdded: 0,
      keysRemoved: 0,
      isDryRun: dryRun,
    );
  }

  // Load all JSON files and remove orphaned keys
  final localeDir = Directory(p.join(i18nPath, referenceLocale));
  if (!await localeDir.exists()) {
    warnings.add('Locale directory not found: ${localeDir.path}');
    return FixResult(
      filesModified: [],
      keysAdded: 0,
      keysRemoved: 0,
      warnings: warnings,
      isDryRun: dryRun,
    );
  }

  await for (final entity in localeDir.list()) {
    if (entity is! File || !entity.path.endsWith('.json')) continue;

    try {
      final content = await entity.readAsString();
      final Map<String, dynamic> data = json.decode(content);

      // Find keys to remove from this file
      final keysToRemove = data.keys
          .where((k) => comparison.orphanedInJson.contains(k))
          .toList();

      if (keysToRemove.isEmpty) continue;

      // Remove orphaned keys
      for (final key in keysToRemove) {
        data.remove(key);
      }

      if (!dryRun) {
        const encoder = JsonEncoder.withIndent('  ');
        await entity.writeAsString('${encoder.convert(data)}\n');
      }

      filesModified.add(entity.path);
      keysRemoved += keysToRemove.length;
      _log(
        '${dryRun ? "[DRY RUN] Would remove" : "Removed"} ${keysToRemove.length} key(s) from ${p.basename(entity.path)}',
      );
    } catch (e) {
      warnings.add('Could not process ${entity.path}: $e');
    }
  }

  return FixResult(
    filesModified: filesModified.toList(),
    keysAdded: 0,
    keysRemoved: keysRemoved,
    warnings: warnings,
    isDryRun: dryRun,
  );
}