runWithReporter method

  1. @override
void runWithReporter(
  1. SaropaDiagnosticReporter reporter,
  2. SaropaContext context
)
override

Override this method to implement your lint rule.

Use context to register callbacks for AST node types:

context.addMethodInvocation((node) {
  if (condition) {
    reporter.atNode(node);
  }
});

Implementation

@override
void runWithReporter(
  SaropaDiagnosticReporter reporter,
  SaropaContext context,
) {
  context.addMethodDeclaration((MethodDeclaration node) {
    final body = node.body;
    // Check if async method
    if (body is! BlockFunctionBody) return;
    if (body.keyword?.lexeme != 'async') return;

    // Check if in Bloc class
    final parent = node.parent;
    if (parent is! ClassDeclaration) return;
    final extendsClause = parent.extendsClause;
    if (extendsClause == null) return;
    final superName = extendsClause.superclass.name.lexeme;
    if (superName != 'Bloc' && superName != 'Cubit') return;

    // Check if method has Emitter parameter (Bloc handler)
    bool hasEmitter = false;
    for (final param in node.parameters?.parameters ?? <FormalParameter>[]) {
      final paramSource = param.toSource();
      if (paramSource.contains('Emitter')) {
        hasEmitter = true;
        break;
      }
    }

    if (!hasEmitter) return;

    // Check if emit is called before await
    final methodSource = body.toSource();
    final awaitIndex = methodSource.indexOf('await ');
    if (awaitIndex == -1) return;

    final beforeAwait = methodSource.substring(0, awaitIndex);

    // cspell:ignore inprogress
    final hasLoadingEmit =
        beforeAwait.contains('emit(') &&
        (beforeAwait.toLowerCase().contains('loading') ||
            beforeAwait.toLowerCase().contains('inprogress'));

    if (!hasLoadingEmit) {
      reporter.atNode(node);
    }
  });
}