generateScreenBindings function

Future<void> generateScreenBindings(
  1. List<String> args, {
  2. List<String> defaultTemplates = const ['https://raw.githubusercontent.com/dev-cetera/df_generate_screen/main/templates/v2/_bindings.g.dart.md'],
})

Implementation

Future<void> generateScreenBindings(
  List<String> args, {
  List<String> defaultTemplates = const [
    'https://raw.githubusercontent.com/dev-cetera/df_generate_screen/main/templates/v2/_bindings.g.dart.md',
  ],
}) async {
  Log.enableReleaseAsserts = true;
  final parser = CliParser(
    title: 'dev-cetera.com',
    description:
        'A tool for generating screen bindings for classes annotated @GenerateScreenBindings.',
    example: 'df_generate_screen_bindings -i .',
    additional:
        'For contributions, error reports and information, visit: https://github.com/dev-cetera.',
    params: [
      DefaultFlags.HELP.flag,
      DefaultOptionParams.INPUT_PATH.option.copyWith(
        defaultsTo: FileSystemUtility.i.currentDir,
      ),
      DefaultMultiOptions.TEMPLATES.multiOption.copyWith(
        defaultsTo: defaultTemplates,
      ),
      DefaultOptionParams.DART_SDK.option,
    ],
  );

  // ---------------------------------------------------------------------------

  final (argResults, argParser) = parser.parse(args);

  // ---------------------------------------------------------------------------

  final help = argResults.flag(DefaultFlags.HELP.name);
  if (help) {
    Log.printCyan(parser.getInfo(argParser));
    exit(ExitCodes.SUCCESS.code);
  }

  // ---------------------------------------------------------------------------

  late final String inputPath;
  late final List<String> templates;
  late final String? dartSdk;
  try {
    inputPath = argResults.option(DefaultOptionParams.INPUT_PATH.name)!;
    templates = argResults.multiOption(DefaultMultiOptions.TEMPLATES.name);
    dartSdk = argResults.option(DefaultOptionParams.DART_SDK.name);
  } catch (_) {
    Log.printRed(
      'Missing required args! Use --help flag for more information.',
    );

    exit(ExitCodes.FAILURE.code);
  }

  // ---------------------------------------------------------------------------

  final analysisContextCollection = createDartAnalysisContextCollection(
    {inputPath},
    dartSdk, //
  );

  // ---------------------------------------------------------------------------

  Log.printWhite('Looking for Dart files..');
  final filePathStream0 = PathExplorer(inputPath).exploreFiles();
  final filePathStream1 = filePathStream0.where(
    (e) => _isAllowedFileName(e.path),
  );
  List<FilePathExplorerFinding> findings;
  try {
    findings = await filePathStream1.toList();
  } catch (e) {
    Log.printRed('Failed to read file tree!');
    exit(ExitCodes.FAILURE.code);
  }
  if (findings.isEmpty) {
    Log.printYellow('No files found in $inputPath!');
    exit(ExitCodes.SUCCESS.code);
  }

  // ---------------------------------------------------------------------------

  final templateData = <String, String>{};
  for (final template in templates) {
    Log.printWhite('Reading template at: $template...');
    final result =
        await MdTemplateUtility.i.readTemplateFromPathOrUrl(template).value;

    if (result.isErr()) {
      Log.printRed(' Failed to read template!');
      exit(ExitCodes.FAILURE.code);
    }
    templateData[template] = result.unwrap();
  }

  // ---------------------------------------------------------------------------

  Log.printWhite('Generating...');

  for (final entry in templateData.entries) {
    final fileName = p.basename(entry.key).replaceAll('.md', '');
    final template = entry.value;
    // Tracks which output paths have already been written this run so we can
    // refuse to silently overwrite when two annotated classes in the same
    // directory would map to the same generated file — the previous code
    // would drop all but the last insight's output without warning.
    final writtenOutputPaths = <String>{};
    try {
      for (final finding in findings) {
        final inputFilePath = finding.path;
        final insights = await extractInsightsFromFile(
          inputFilePath,
          analysisContextCollection,
        );
        for (final insight in insights) {
          final output = _interpolator.interpolate(template, insight);
          final outputFilePath = p.join(
            PathUtility.i.localDirName(inputFilePath),
            fileName,
          );
          if (!writtenOutputPaths.add(outputFilePath)) {
            Log.printRed(
              '✘ Collision: `${insight.className}` would overwrite '
              '$outputFilePath produced earlier in this run. Move '
              '`${insight.className}` to its own directory or use a '
              'distinct template per class. Skipping this insight.',
            );
            continue;
          }
          await FileSystemUtility.i.writeLocalFile(outputFilePath, output);
          Log.printWhite('✔ Generated $fileName');
        }
      }
    } catch (e) {
      Log.printRed('✘ One or more files failed to generate: $e');
      exit(ExitCodes.FAILURE.code);
    }
  }

  // ---------------------------------------------------------------------------

  Log.printWhite('Fixing generated files..');
  await fixDartFile(inputPath);

  Log.printWhite('Formatting generated files..');
  await fmtDartFile(inputPath);

  // ---------------------------------------------------------------------------

  Log.printGreen('Done!');
}