check method
Validates both config files with the real section parsers. Missing files are fine (defaults apply); syntax errors, strict-section schema errors and bad scalar types are errors; unknown top-level keys are warnings (the runtime silently ignores them — the check does not).
Implementation
Future<ConfigCheckReport> check() async {
final report = ConfigCheckReport();
final globalPath = globalConfigPath;
if (globalPath == null) {
report.notes.add(
'global scope unavailable on this host (no home directory)',
);
} else {
final text = await _readTextOrNull(globalPath);
if (text == null) {
report.notes.add('global config absent (defaults apply): $globalPath');
} else {
_collectDiagnostics(text, globalPath, report.errors, report.warnings);
_collectHostWarnings(_tryParse(text), globalPath, report.warnings);
}
}
final projectPath = projectConfigPath;
if (globalPath != null &&
_normalizePath(projectPath) == _normalizePath(globalPath)) {
// cwd == home resolves the project scope to the user file itself; a
// second pass would validate the same bytes twice and flag every
// user-only key as dead config (gh-1573). One file, one pass.
report.notes.add(
'project config resolves to the global file — skipped: $projectPath',
);
return report;
}
final projectText = await _readTextOrNull(projectPath);
if (projectText == null) {
report.notes.add('project config absent (defaults apply): $projectPath');
} else {
final projectWarnings = <ConfigDiagnostic>[];
_collectDiagnostics(
projectText,
projectPath,
report.errors,
projectWarnings,
);
report.warnings.addAll(projectWarnings);
// Dead config: sections the project file is never read for.
final doc = _tryParse(projectText);
if (doc != null) {
for (final key in doc.keys) {
if (!_projectSections.contains('$key')) {
report.warnings.add(
ConfigDiagnostic(
projectPath,
'"$key" in the project file is dead config — only '
'${_projectSections.join('/')} are read from here',
),
);
}
}
}
_collectHostWarnings(doc, projectPath, report.warnings);
}
return report;
}