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.addInstanceCreationExpression((InstanceCreationExpression node) {
    final String typeName = node.constructorName.type.name.lexeme;

    // Check for WebView widgets
    if (typeName != 'WebView' &&
        typeName != 'WebViewWidget' &&
        typeName != 'InAppWebView') {
      return;
    }

    final String nodeSource = node.toSource();

    // Check for data URL with HTML content
    if (!nodeSource.contains('data:text/html') &&
        !nodeSource.contains('loadHtml') &&
        !nodeSource.contains('loadData')) {
      return;
    }

    // Check if content has interpolation (user content)
    if (nodeSource.contains(r'$')) {
      // Check for escaping/sanitization
      if (nodeSource.contains('htmlEscape') ||
          nodeSource.contains('sanitize') ||
          nodeSource.contains('escape') ||
          nodeSource.contains('HtmlUnescape')) {
        return; // Has escaping
      }

      reporter.atNode(node);
    }
  });

  // Also check for direct loadHtml calls
  context.addMethodInvocation((MethodInvocation node) {
    final String methodName = node.methodName.name;

    if (methodName != 'loadHtml' &&
        methodName != 'loadHtmlString' &&
        methodName != 'loadData') {
      return;
    }

    final String nodeSource = node.toSource();

    // Check for interpolation without escaping
    if (nodeSource.contains(r'$') &&
        !nodeSource.contains('htmlEscape') &&
        !nodeSource.contains('sanitize') &&
        !nodeSource.contains('escape')) {
      reporter.atNode(node);
    }
  });
}