JSON-Structure

 view release on metacpan or  search on metacpan

lib/JSON/Structure/SchemaValidator.pm  view on Meta::CPAN

            $self->_validate_schema( $obj->{else}, 0, "$path/else", undef );
        }
    }
}

sub _validate_composition_array {
    my ( $self, $arr, $keyword, $path ) = @_;

    if ( ref($arr) ne 'ARRAY' ) {
        $self->_add_error( SCHEMA_COMPOSITION_NOT_ARRAY,
            "$keyword must be an array", $path );
        return;
    }

    if ( @$arr == 0 ) {
        $self->_add_error( SCHEMA_COMPOSITION_EMPTY,
            "$keyword array cannot be empty", $path );
        return;
    }

    for my $i ( 0 .. $#$arr ) {
        my $schema = $arr->[$i];
        if ( ref($schema) ne 'HASH' ) {
            $self->_add_error(
                SCHEMA_KEYWORD_INVALID_TYPE,
                "$keyword\[$i] must be a schema object",
                "$path\[$i]"
            );
        }
        else {
            $self->_validate_schema( $schema, 0, "$path\[$i]", undef );
        }
    }
}

sub _check_json_pointer {
    my ( $self, $pointer, $doc, $path ) = @_;

    if ( !defined $pointer || ref($pointer) ) {
        $self->_add_error( SCHEMA_KEYWORD_INVALID_TYPE,
            '$root must be a string', $path );
        return;
    }

    # Validate the pointer resolves
    my $target = $self->_resolve_json_pointer( $pointer, $doc );
    if ( !defined $target ) {
        $self->_add_error( SCHEMA_REF_NOT_FOUND,
            "\$root target does not exist: $pointer", $path );
    }
}

sub _resolve_json_pointer {
    my ( $self, $pointer, $doc ) = @_;

    # Handle # prefix
    $pointer =~ s/^#//;

    return $doc if $pointer eq '' || $pointer eq '/';

    my @segments = split m{/}, $pointer;
    shift @segments if @segments && $segments[0] eq '';

    my $current = $doc;

    for my $segment (@segments) {

        # Unescape JSON Pointer tokens
        $segment =~ s/~1/\//g;
        $segment =~ s/~0/~/g;

        if ( ref($current) eq 'HASH' ) {
            return undef unless exists $current->{$segment};
            $current = $current->{$segment};
        }
        elsif ( ref($current) eq 'ARRAY' ) {
            return undef unless $segment =~ /^\d+$/;
            my $idx = int($segment);
            return undef if $idx >= @$current;
            $current = $current->[$idx];
        }
        else {
            return undef;
        }
    }

    return $current;
}

sub _validate_namespace {
    my ( $self, $definitions, $path ) = @_;

    for my $name ( keys %$definitions ) {
        my $def      = $definitions->{$name};
        my $def_path = "$path/$name";

        # Validate identifier
        my $id_regex =
          $self->{allow_dollar} ? $IDENTIFIER_DOLLAR_REGEX : $IDENTIFIER_REGEX;
        if ( $name !~ $id_regex ) {
            $self->_add_error( SCHEMA_NAME_INVALID,
                "Definition name '$name' must be a valid identifier",
                $def_path );
        }

        if ( ref($def) ne 'HASH' ) {
            $self->_add_error( SCHEMA_INVALID_TYPE,
                'Definition must be an object', $def_path );
            next;
        }

        # Check for nested definitions (namespace)
        if (   !exists $def->{type}
            && !exists $def->{'$ref'}
            && !$self->_has_composition_keywords($def) )
        {
            # Could be a namespace with nested definitions
            my $has_nested = 0;
            for my $key ( keys %$def ) {
                if (
                    ref( $def->{$key} ) eq 'HASH'



( run in 0.531 second using v1.01-cache-2.11-cpan-71847e10f99 )