checkSource function
Run the full check pipeline (skip-directive scan + AST visitor) against a source string.
This is the library entry point: the check_js_invariants executable
calls it over file contents, and consumer test suites can call it
against synthetic inputs to pin the rules.
Implementation
CheckResult checkSource(String filePath, String source) {
// Skip-directive check: scan the first 10 lines for a valid marker. A
// malformed marker (present but no issue ref, empty reason, or
// whitespace-only reason after trim) fails the check.
final header = source.split('\n').take(10).toList();
String? skipReason;
int? skipIssue;
int? malformedMarkerLine;
for (var i = 0; i < header.length; i++) {
final line = header[i];
final m = _skipDirective.firstMatch(line);
if (m != null) {
final reason = m.group(1)!.trim();
if (reason.isNotEmpty) {
skipReason = reason;
skipIssue = int.parse(m.group(2)!);
break;
}
malformedMarkerLine = i + 1;
continue;
}
if (_skipDirectiveMarker.hasMatch(line)) {
malformedMarkerLine = i + 1;
}
}
if (skipReason == null && malformedMarkerLine != null) {
return CheckResult(
filePath: filePath,
violations: [
'❌ $filePath:$malformedMarkerLine — malformed skip directive\n'
' Required: // CHECK_JS_INVARIANTS_SKIP_FILE: <reason> #<issue>\n'
' Both <reason> (non-empty) and #<issue> are required.',
],
skipDirective: null,
);
}
if (skipReason != null) {
return CheckResult(
filePath: filePath,
violations: const [],
skipDirective: (reason: skipReason, issue: skipIssue!),
);
}
final parsed = parseString(content: source, throwIfDiagnostics: false);
final lineStarts = _computeLineStarts(source);
final visitor = _InvariantChecker(filePath, lineStarts);
parsed.unit.visitChildren(visitor);
return CheckResult(
filePath: filePath,
violations: List.unmodifiable(visitor.violations),
skipDirective: null,
);
}