run method

  1. @override
Future<int> run()
override

Runs this command.

The return value is wrapped in a Future if necessary and returned by CommandRunner.runCommand.

Implementation

@override
Future<int> run() async {
  final all = argResults?['all'] as bool? ?? false;
  var componentsToAdd = argResults?.rest ?? [];

  if (componentsToAdd.isEmpty && !all) {
    throw UsageException('Especifique ao menos um componente ou use --all.', usage);
  }

  final variant = argResults?['variant'] as String?;
  final overwrite = argResults?['overwrite'] as bool? ?? false;
  final projectRoot = Directory.current.path;

  try {
    // 1. Setup Infra
    final templatesPath = await resolveTemplatesPath();
    final loader = TemplateLoader(templatesPath);
    final stateService = BuildStateService(projectRoot);

    // 2. Setup Pipeline (Fyarn v4 Formal Build System)
    final engine = PipelineEngine();
    engine.addStage(EnvironmentStage());
    engine.addStage(GraphBuilderStage(loader));

    engine.addStage(GraphValidationStage());
    engine.addStage(DeltaComputationStage(stateService));
    engine.addStage(IncrementalBuildEngineStage());
    engine.addStage(ConsistencyCheckStage(loader));
    engine.addStage(TestStage());

    engine.addStage(VerificationStage());
    engine.addStage(ResolutionStage());
    engine.addStage(RenderingStage(loader));
    engine.addStage(PersistenceStage());
    engine.addStage(FormatStage());

    // 3. Resolver componentes a serem adicionados
    if (all) {
      final uiPath = p.join(templatesPath, 'ui');
      final uiDir = Directory(uiPath);
      if (await uiDir.exists()) {
        final List<String> validComponents = [];
        final entities = await uiDir.list().where((e) => e is Directory).toList();

        for (final entity in entities) {
          final name = p.basename(entity.path);
          if (name == 'auth') continue;

          final mainTemplatePath = p.join(entity.path, 'fyarn_$name.dart.tpl');
          if (await File(mainTemplatePath).exists()) {
            validComponents.add(name);
          }
        }

        componentsToAdd = validComponents;
        Logger.info('🧶 Adicionando ${componentsToAdd.length} componentes válidos (v1.1.0)...\n');
      }
    }

    // 4. Execute para cada componente
    for (final component in componentsToAdd) {
      final context = PipelineContext(
        componentName: component.toLowerCase(),
        variant: variant,
        overwrite: overwrite,
        projectRoot: projectRoot,
      );

      await engine.run(context);

      // 4. Salva a prova de build (Persistence of Truth)
      // Construímos o índice reverso: para cada dependência do IR, este componente é um dependente
      final Map<String, List<String>> reverseDeps = {};
      for (final dep in context.ir.dependencies) {
        reverseDeps[dep] = [context.componentName];
      }

      final buildProofIR = BuildProofIR(
        componentName: context.componentName,
        buildProofHash: context.ir.irHash,
        contentHashes: context.ir.resolvedFiles.map(
          (k, v) => MapEntry(k, v.contentHash),
        ),
        dependencyIndex: reverseDeps,
        proof: context.proof,
      );

      await stateService.saveBuild(buildProofIR);

    }


    Logger.success('\nProcess completed successfully! 🧶');
    return 0;
  } catch (e, s) {
    Logger.error(e.toString());
    Logger.debug(s.toString());
    return 1;
  }
}