1from six.moves import urllib_parse as urlparse
2
3import jsonpointer
4
5from flex.exceptions import (
6    ValidationError,
7)
8from flex.datastructures import (
9    ValidationDict,
10)
11from flex.error_messages import MESSAGES
12from flex.constants import (
13    OBJECT,
14    STRING,
15)
16from flex.decorators import (
17    skip_if_not_of_type,
18)
19from flex.validation.common import (
20    generate_object_validator,
21)
22
23reference_object_schema = {
24    'type': OBJECT,
25    'additionalProperties': False,
26    'required': [
27        '$ref',
28    ],
29    'properties': {
30        '$ref': {
31            'type': STRING,
32        },
33    },
34}
35
36
37@skip_if_not_of_type(STRING)
38def validate_reference_pointer(reference, context, **kwargs):
39    parts = urlparse.urlparse(reference)
40    if any((parts.scheme, parts.netloc, parts.path, parts.params, parts.query)):
41        raise ValidationError(
42            MESSAGES['reference']['unsupported'].format(reference),
43        )
44
45    try:
46        jsonpointer.resolve_pointer(context, parts.fragment)
47    except jsonpointer.JsonPointerException:
48        raise ValidationError(
49            MESSAGES['reference']['undefined'].format(reference),
50        )
51
52
53non_field_validators = ValidationDict()
54non_field_validators.add_property_validator('$ref', validate_reference_pointer)
55
56reference_object_validator = generate_object_validator(
57    schema=reference_object_schema,
58    non_field_validators=non_field_validators,
59)
60