fingerprint library

Issue fingerprinting for the Flutter accessibility scanner.

Mirrors the rule-engine fingerprint builder (FNV-1a hash + fluent builder), ported from the React integration and adapted for the analyzer/AST world.

Because the reporter (bin/reporter.dart) runs the lint rules as a subprocess (dart run custom_lint --format json) and only sees their JSON output, a custom fingerprint set inside a rule cannot reach the reporter in-process the way it does under ESLint. Instead, the report helper records overrides to a side-channel file in .dart_tool/; the reporter reads them back (see readOverrides/takeOverride) and otherwise falls back to generateDefaultFingerprint.

Overriding looks like this inside a rule's run, replacing reporter.atNode(node, code):

report(
  resolver,
  reporter,
  node,
  code,
  fingerprint: createFingerprint(resolver, node, ruleId: code.name)
      .includeRuleId()
      .includeElementName()
      .includeAttributeHash()
      .build(),
);

Classes

FingerprintBuilder
Part-composition + hashing engine. Reads from a plain field bag so the same builder backs both the rule-facing createFingerprint and the reporter-facing generateDefaultFingerprint.

Constants

overridesEnvVar → const String
Environment variable the reporter sets on the custom_lint subprocess to pin the absolute path of the side-channel file. Consulted by _overridesFileFor on both the write and read sides.

Functions

clearOverrides({String? rootPath}) → void
Delete the side-channel file. The reporter calls this before a run (so a previous run's entries can't leak in) and after consuming overrides. rootPath defaults to the reporter's cwd.
createFingerprint(CustomLintResolver resolver, AstNode node, {required String ruleId}) FingerprintBuilder
Fluent builder for custom fingerprints, used inside rules. Extracts the fields from the resolver + AST node, then delegates to the shared FingerprintBuilder. ruleId is passed explicitly because it lives on the rule's LintCode, not the node.
defaultOverridesFilePath([String? rootPath]) String
Absolute path of the side-channel file under rootPath (defaults to cwd). The reporter calls this to compute the value it exports as overridesEnvVar to the subprocess.
fingerprintKey({required String ruleId, required String filePath, required int line, required int column}) String
Stable key joining a diagnostic's identity. Both the rule side (write) and the reporter side (read) reconstruct the same key from the rule id, absolute file path and 1-based line/column.
fnv1a(String str) String
FNV-1a hash → 8-char zero-padded hex string. Matches the rule-engine / React implementation.
generateDefaultFingerprint({required String ruleId, required String relativePath, required String snippet}) String
Default fingerprint computed by the reporter from a custom_lint diagnostic + its source snippet.
normalizeText(String? str) String
Collapse runs of whitespace and trim, so cosmetic formatting changes don't alter fingerprints.
readOverrides({String? rootPath}) Map<String, String>
Read the override file into a key → fingerprint map (last entry wins per key). Returns an empty map when no overrides were recorded. rootPath defaults to the reporter's cwd.
recordOverride({required String rootPath, required String ruleId, required String filePath, required int line, required int column, required String fingerprint}) → void
Append one override entry to the side-channel file. Best-effort: a failed write just means the reporter falls back to the default fingerprint for that diagnostic.
report(CustomLintResolver resolver, DiagnosticReporter reporter, AstNode node, LintCode code, {String? fingerprint}) → void
Opt-in replacement for reporter.atNode. Reports the diagnostic as usual; if fingerprint is supplied, records it under the key the reporter will reconstruct from the same location.
takeOverride(Map<String, String> overrides, String key) String?
Read and remove an override, so a stale entry can't be reused within the same report.
toRelativePath(String filePath) String
Forward-slashed path relative to the current working directory, falling back to the raw path when the file lives outside it. Mirrors the reporter's makeRelativePath.