load static method

FlavorConfig load([
  1. bool excludeValidation = false
])

Loads the flavor configuration from the YAML file. If excludeValidation is true, the config is loaded without full validation.

Implementation

static FlavorConfig load([bool excludeValidation = false]) {
  // Check for legacy JSON first for seamless loading before migration
  final legacyFile = File(p.join(root, '.flavor_cli.json'));
  if (legacyFile.existsSync() && !File(_configPath).existsSync()) {
    try {
      final content = legacyFile.readAsStringSync();
      final jsonMap = jsonDecode(content) as Map<String, dynamic>;
      if (jsonMap['platforms'] == null) {
        jsonMap['platforms'] = detectPlatforms();
      }
      if (excludeValidation) return FlavorConfig.fromJson(jsonMap);
      return ConfigValidator.validate(jsonMap);
    } catch (e) {
      // Fallthrough to yaml error
    }
  }

  final file = File(_configPath);
  if (!file.existsSync()) {
    throw Exception(
      '❌ flavor_cli: flavor_cli.yaml not found. Run init first.',
    );
  }

  try {
    final content = file.readAsStringSync();
    final yamlMap = loadYaml(content);
    final jsonMap = YamlUtils.yamlToMap(yamlMap);

    if (jsonMap['platforms'] == null) {
      jsonMap['platforms'] = detectPlatforms();
    }

    if (excludeValidation) {
      return FlavorConfig.fromJson(jsonMap);
    }

    // Will throw FormatException with properly formatted error if invalid
    try {
      return ConfigValidator.validate(jsonMap);
    } on FormatException catch (e) {
      var repaired = false;
      var config = FlavorConfig.fromJson(jsonMap);

      // Self-healing: If flavor_app_names contains keys not defined in flavors
      if (e.message.contains('flavor_app_names') &&
          !e.message.contains('application_id') &&
          !e.message.contains('bundle_id') &&
          config.flavorAppNames != null) {
        final flavorsSet = config.flavors.toSet();
        final validAppNames = Map<String, String>.from(config.flavorAppNames!)
          ..removeWhere((key, _) => !flavorsSet.contains(key));
        config = config.copyWith(flavorAppNames: validAppNames);
        repaired = true;
      }

      // Self-healing: If the production_flavor is not in flavors
      if (e.message.contains('production_flavor') &&
          !e.message.contains('application_id') &&
          !e.message.contains('bundle_id') &&
          config.flavors.isNotEmpty &&
          !config.flavors.contains(config.productionFlavor)) {
        config = config.copyWith(
          productionFlavor: config.flavors.first,
        );
        repaired = true;
      }

      if (repaired) {
        try {
          // Re-validate to ensure it's fully correct now
          final validated = ConfigValidator.validate(config.toJson());
          save(validated);
          return validated;
        } catch (_) {
          // Fall through and rethrow original if repair was insufficient
        }
      }
      rethrow;
    }
  } on FormatException {
    rethrow;
  } catch (e) {
    throw FormatException('❌ flavor_cli: invalid config YAML format.\n$e');
  }
}