compute static method

List<String> compute({
  1. required String exceptionType,
  2. required String message,
  3. String? stackTrace,
  4. List<String>? customFingerprint,
})

Computes a deterministic list of fingerprint tokens and SHA-256 hash.

Extracts top non-framework stack frames and combines them with the exceptionType.

Implementation

static List<String> compute({
  required String exceptionType,
  required String message,
  String? stackTrace,
  List<String>? customFingerprint,
}) {
  if (customFingerprint != null && customFingerprint.isNotEmpty) {
    return List<String>.from(customFingerprint);
  }

  final tokens = <String>[exceptionType];

  if (stackTrace != null && stackTrace.isNotEmpty) {
    final lines = stackTrace.split('\n');
    for (final line in lines) {
      final trimmed = line.trim();
      if (trimmed.isEmpty) continue;

      // Skip internal SDK / dart runtime frames to group by user code
      if (trimmed.contains('package:flutter/') ||
          trimmed.contains('dart:async') ||
          trimmed.contains('dart:isolate') ||
          trimmed.contains('dart:core') ||
          trimmed.contains('dart_sdk.js') ||
          trimmed.contains('package:bloom_framework/src/observability')) {
        continue;
      }

      // Match frame symbol (e.g. #0 CartController.addItem or at CartController.addItem)
      final vmMatch = _vmFramePattern.firstMatch(trimmed);
      if (vmMatch != null) {
        tokens.add(vmMatch.group(1)!);
      } else {
        final webMatch = _webFramePattern.firstMatch(trimmed);
        if (webMatch != null) {
          tokens.add(webMatch.group(1)!);
        }
      }
      if (tokens.length >= 4) break; // Take up to top 3 user frames
    }
  }

  if (tokens.length == 1 && message.isNotEmpty) {
    // If no stack frames could be parsed, use sanitized message prefix
    tokens.add(sanitizeMessage(message));
  }

  return tokens;
}