freshnessIssues method

List<ZukeIndexFreshnessIssue> freshnessIssues({
  1. required String root,
})

Implementation

List<ZukeIndexFreshnessIssue> freshnessIssues({required String root}) {
  final issues = <ZukeIndexFreshnessIssue>[];
  final generatedManifest = File(_join(root, generatedManifestPath));
  if (!generatedManifest.existsSync()) {
    return [
      ZukeIndexFreshnessIssue(
        kind: ZukeIndexFreshnessIssueKind.generatedManifestMissing,
        path: generatedManifestPath,
        message: 'Generated manifest is missing: $generatedManifestPath',
      ),
    ];
  }
  if (_sha256(generatedManifest.readAsBytesSync()) !=
      generatedManifestDigest) {
    return [
      ZukeIndexFreshnessIssue(
        kind: ZukeIndexFreshnessIssueKind.generatedManifestDigestMismatch,
        path: generatedManifestPath,
        message: 'Generated manifest content changed: $generatedManifestPath',
      ),
    ];
  }
  issues.addAll(_generatedOutputIssues(root, generatedManifest));
  final rootPath = Directory(root).absolute.path;
  final currentPatternInputs = _matchedPatternInputs(rootPath, inputPatterns);
  if (!_sameSet(currentPatternInputs, patternInputs)) {
    final changed =
        <String>{...currentPatternInputs, ...patternInputs}
            .where(
              (path) =>
                  !currentPatternInputs.contains(path) ||
                  !patternInputs.contains(path),
            )
            .toList()
          ..sort();
    issues.add(
      ZukeIndexFreshnessIssue(
        kind: ZukeIndexFreshnessIssueKind.inputInventoryMismatch,
        path: changed.isEmpty ? '.zuke/analyzer-index.json' : changed.first,
        message:
            'Configured specification inputs changed: '
            '${changed.isEmpty ? '.zuke/analyzer-index.json' : changed.join(', ')}',
      ),
    );
  }
  final current = <ZukeIndexInput>[];
  for (final input in inputs) {
    final file = File(_join(rootPath, input.path));
    if (!file.existsSync()) {
      issues.add(
        ZukeIndexFreshnessIssue(
          kind: ZukeIndexFreshnessIssueKind.inputMissing,
          path: input.path,
          message: 'Indexed input is missing: ${input.path}',
        ),
      );
      continue;
    }
    final currentInput = ZukeIndexInput(
      path: input.path,
      digest: _sha256(file.readAsBytesSync()),
    );
    current.add(currentInput);
    if (currentInput.digest != input.digest) {
      issues.add(
        ZukeIndexFreshnessIssue(
          kind: ZukeIndexFreshnessIssueKind.inputDigestMismatch,
          path: input.path,
          message: 'Indexed input content changed: ${input.path}',
        ),
      );
    }
  }
  final hasInputIssue = issues.any(
    (issue) =>
        issue.kind == ZukeIndexFreshnessIssueKind.inputMissing ||
        issue.kind == ZukeIndexFreshnessIssueKind.inputDigestMismatch ||
        issue.kind == ZukeIndexFreshnessIssueKind.inputInventoryMismatch,
  );
  if (!hasInputIssue &&
      _inputDigest(
            current,
            requirementIds,
            controlIds,
            bindingIds,
            inputPatterns,
            patternInputs,
          ) !=
          inputDigest) {
    issues.add(
      const ZukeIndexFreshnessIssue(
        kind: ZukeIndexFreshnessIssueKind.inputSetDigestMismatch,
        path: '.zuke/analyzer-index.json',
        message:
            'Analyzer index digest does not match its indexed inputs and IDs',
      ),
    );
  }
  return List.unmodifiable(issues);
}