validateHooksJson function
Validate a plugin's hooks.json file.
Implementation
Future<ValidationResult> validateHooksJson(String filePath) async {
String content;
try {
content = await File(filePath).readAsString();
} on FileSystemException catch (e) {
if (e.osError?.errorCode == 2) {
// ENOENT is fine -- hooks are optional
return ValidationResult(
success: true,
errors: const [],
warnings: const [],
filePath: filePath,
fileType: PluginFileType.hooks,
);
}
return ValidationResult(
success: false,
errors: [
ValidationError(
path: 'file',
message: 'Failed to read file: ${e.message}',
),
],
warnings: const [],
filePath: filePath,
fileType: PluginFileType.hooks,
);
}
try {
final parsed = _jsonDecode(content);
if (parsed is! Map<String, dynamic>) {
return ValidationResult(
success: false,
errors: [
const ValidationError(
path: 'json',
message: 'hooks.json root must be a JSON object',
),
],
warnings: const [],
filePath: filePath,
fileType: PluginFileType.hooks,
);
}
// Validate hooks field presence
if (!parsed.containsKey('hooks')) {
return ValidationResult(
success: false,
errors: [
const ValidationError(
path: 'hooks',
message: 'hooks.json must contain a "hooks" field',
),
],
warnings: const [],
filePath: filePath,
fileType: PluginFileType.hooks,
);
}
} catch (e) {
return ValidationResult(
success: false,
errors: [
ValidationError(
path: 'json',
message:
'Invalid JSON syntax: $e. '
'At runtime this breaks the entire plugin load.',
),
],
warnings: const [],
filePath: filePath,
fileType: PluginFileType.hooks,
);
}
return ValidationResult(
success: true,
errors: const [],
warnings: const [],
filePath: filePath,
fileType: PluginFileType.hooks,
);
}