You are given a set of custom descriptor objects that define the expected schema of a configuration object. Implement a validator that checks whether an input configuration matches the descriptor.
A descriptor may describe:
-
A primitive value, such as
string
,
number
,
boolean
, or
null
.
-
An object with named fields, where each field has its own descriptor.
-
A list, where every element must match the list element descriptor.
For this problem, assume all fields defined in an object descriptor are required unless stated otherwise, and fields not present in the descriptor should be reported as unexpected.
Example descriptor:
PersonDescriptor:
name: string
email: string
address: AddressDescriptor
AddressDescriptor:
street: string
city: string
Example input:
{
"name": "John Adams",
"email": "johnadams@gmail.com",
"address": "111 street"
}
The input is invalid because address is expected to be an object matching AddressDescriptor, but the provided value is a string.
Implement:
validate(config, descriptor) -> list of validation errors
The validator should recursively check nested object descriptors and list descriptors. Each validation error should include enough information to identify where the problem occurred, such as the field path and the expected versus actual type.
Your implementation should handle at least the following cases:
-
Missing required fields.
-
Unexpected extra fields.
-
Primitive type mismatches.
-
Nested object validation.
-
List validation, including invalid element types.
-
Clear error reporting for multiple errors in the same config.
Do not use an external schema validation library.