refactorFiles function

Map<String, String> refactorFiles(
  1. Map<String, List<String>> extractedStrings, {
  2. bool dryRun = false,
  3. bool useAppLocalizations = true,
  4. String packageName = 'app',
  5. bool preserveOriginalImports = true,
  6. bool preserveConst = false,
  7. String? arbFilePath,
  8. String keyFormat = 'camelCase',
})

Refactor code to use localization keys with meaningful key names.

Automatically refactors Dart/Flutter source code to replace hardcoded strings with localization calls using generated meaningful keys. This function supports both dry-run mode for preview and actual code modification.

Parameters:

  • extractedStrings - Map of file paths to lists of extracted strings
  • dryRun - If true, only shows what would be changed without modifying files
  • useAppLocalizations - Whether to use AppLocalizations or Intl.message
  • packageName - Package name for import statements
  • preserveOriginalImports - Whether to keep existing import statements
  • preserveConst - Whether to preserve const keywords where possible

Returns a Map of generated keys to their corresponding string values.

Example:

final keys = refactorFiles(
  extractedStrings,
  dryRun: false,
  useAppLocalizations: true,
  packageName: 'my_app'
);

Implementation

Map<String, String> refactorFiles(
  Map<String, List<String>> extractedStrings, {
  bool dryRun = false,
  bool useAppLocalizations = true,
  String packageName = 'app',
  bool preserveOriginalImports = true,
  bool preserveConst = false,
  String? arbFilePath,
  String keyFormat = 'camelCase',
}) {
  var arbData = <String, String>{};

  // Try to load existing ARB keys first to reuse them
  Map<String, String> existingArbKeys = {};
  if (arbFilePath != null && arbFilePath.isNotEmpty) {
    existingArbKeys = ArbLoader.loadArbKeys(arbFilePath);
    print('📖 Loaded ${existingArbKeys.length} existing keys from ARB file');
  }

  // First, generate meaningful keys from strings
  // If a string already exists in ARB, use that key
  for (var entry in extractedStrings.entries) {
    for (var string in entry.value) {
      // Check if this string already has a key in the ARB file
      String? existingKey = existingArbKeys[string];

      String key;
      if (existingKey != null) {
        key = existingKey;
        print('🔄 Reusing existing ARB key "$existingKey" for: $string');
      } else {
        // Create a meaningful key based on the content
        key = KeyGenerator.generateKey(string, keyFormat: keyFormat);

        // Make sure key is unique by adding number if needed
        int suffix = 1;
        String baseKey = key;
        while (
            arbData.containsKey(key) || existingArbKeys.values.contains(key)) {
          key = '${baseKey}_$suffix';
          suffix++;
        }
      }

      // Store in ARB data map
      arbData[key] = string;
    }
  }

  // Now refactor each file with the consistent keys
  for (var entry in extractedStrings.entries) {
    var filePath = entry.key;
    var file = File(filePath);

    try {
      print('Processing ${file.path}...');
      var content = file.readAsStringSync();
      var originalContent = content;
      var fileChanged = false;

      // Create a map of all replacements for batch processing
      var replacements = <String, String>{};
      for (var string in entry.value) {
        // Find the key that was assigned to this string
        var key = arbData.entries.firstWhere((e) => e.value == string).key;
        replacements[string] = key;
      }

      // Apply all refactorings at once for better efficiency
      final result = LocalizationRefactorer.batchRefactor(
        content: content,
        replacements: replacements,
        useAppLocalizations: useAppLocalizations,
        preserveConst: preserveConst,
      );

      content = result['content'];

      // Track if any change was made
      if (result['changed'] == true) {
        fileChanged = true;
      }

      // Inject BuildContext parameter into Widget functions if needed
      if (fileChanged && !dryRun) {
        content = ContextInjector.injectContextParameter(content);
      }

      // Auto-fix common issues
      if (fileChanged && !dryRun) {
        content = AnalyzerValidator.autoFixCommonIssues(content);
      }

      // Only add import if file was changed and using AppLocalizations
      if (fileChanged && useAppLocalizations && !dryRun) {
        content =
            LocalizationRefactorer.addLocalizationImport(content, packageName);
      }

      if (dryRun) {
        if (fileChanged) {
          print('--- DRY RUN: ${file.path} ---');
          print('Changes would be made to this file.');
        }
      } else if (fileChanged && content != originalContent) {
        file.writeAsStringSync(content);
        print('✅ Updated file: ${file.path}');
      } else {
        print('â„šī¸ No changes needed in: ${file.path}');
      }
    } catch (e) {
      print('❌ Error processing ${file.path}: $e');
    }
  }

  // Return the ARB data for potential use
  return arbData;
}