build method

  1. @override
Future<void> build(
  1. BuildStep buildStep
)

Generates the outputs for a given BuildStep.

Implementation

@override
Future<void> build(BuildStep buildStep) async {
  final inputId = buildStep.inputId;
  final content = await buildStep.readAsString(inputId);

  AutoInteropConfig config;
  try {
    config = _configParser.parseYaml(content);
  } on ConfigParseException catch (e) {
    log.warning('Error parsing auto_interop.yaml: $e');
    return;
  }

  if (config.packages.isEmpty) {
    log.info('No packages in auto_interop.yaml');
    return;
  }

  final loader = await _createLoader();
  final overrideLoader = OverrideLoader(
    projectDir: config.overridesDir ?? 'auto_interop_overrides',
  );

  // Collect all per-package code and track additional imports needed
  final imports = <String>{
    "import 'package:auto_interop/auto_interop.dart';"
  };
  final codeSections = <String>[];

  for (final spec in config.packages) {
    // Check overrides first (project then global), then fall back to loader
    final overrideResult = overrideLoader.load(
      spec.package,
      source: spec.source.name,
      version: spec.version,
    );
    final schema =
        overrideResult?.schema ?? loader.loadForPackage(spec.package);
    if (schema == null) {
      log.warning('No pre-built type definition for ${spec.package}. '
          'Run the CLI to parse and generate definitions first.');
      continue;
    }

    // Run analyzer before generating
    final analysisResult = const ApiSurfaceAnalyzer().analyze(schema);
    for (final d in analysisResult.diagnostics) {
      if (d.isError) {
        log.severe('[${spec.package}] $d');
      } else {
        log.warning('[${spec.package}] $d');
      }
    }
    if (analysisResult.hasErrors) {
      log.severe('Skipping ${spec.package} due to analysis errors');
      continue;
    }

    final files = _dartGen.generate(schema);
    for (final entry in files.entries) {
      // Strip the header and imports from individual files; hoist imports
      var code = entry.value;
      code = code.replaceFirst(RegExp(r'// GENERATED CODE.*\n'), '');
      code = code.replaceFirst(RegExp(r'// Generated by.*\n'), '');
      // Extract and hoist all import lines
      final importPattern = RegExp(r"import '[^']+';[ ]*\n");
      for (final match in importPattern.allMatches(code)) {
        imports.add(match.group(0)!.trim());
      }
      code = code.replaceAll(importPattern, '');
      code = code.trim();
      codeSections.add('// --- ${spec.package} ---\n$code');
    }
  }

  // Assemble final output with all imports at the top
  final buffer = StringBuffer();
  buffer.writeln('// GENERATED CODE — DO NOT EDIT');
  buffer.writeln('// Generated by auto_interop_generator via build_runner');
  buffer.writeln();
  // Only emit imports when there is generated code to avoid unused_import
  final sortedImports = imports.toList()..sort();
  if (codeSections.isNotEmpty) {
    for (final imp in sortedImports) {
      buffer.writeln(imp);
    }
  }
  buffer.writeln();
  for (final section in codeSections) {
    buffer.writeln(section);
    buffer.writeln();
  }

  await buildStep.writeAsString(
    AssetId(inputId.package, 'lib/generated/auto_interop_bindings.dart'),
    buffer.toString(),
  );
}