Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
99b7e39
Upgrade to ajv 8.5.0
r-ash Jun 21, 2021
488dcf4
Update error message and output parsing to work with ajv 8.5
r-ash Jun 21, 2021
2b67e44
Fix draft-04 handling
richfitz Jun 21, 2021
487419f
Add ajv formats package and tests
r-ash Jun 22, 2021
0ce312e
Merge branch 'master' into mrc-2476
r-ash Jun 22, 2021
998090f
Run with strict mode off by default and expose as an argument
r-ash Jun 22, 2021
706763c
Bump version no and add news item
r-ash Jun 22, 2021
cbe3e08
Use ajv as default validator
r-ash Jun 22, 2021
e527d8c
Update NEWS.md
r-ash Jun 22, 2021
253b8b5
Add formats to draft-04 and add test
r-ash Jun 22, 2021
5c3ada2
Merge branch 'mrc-2476' of github.com:ropensci/jsonvalidate into mrc-…
r-ash Jun 22, 2021
08f78f4
Update NEWS
r-ash Jun 22, 2021
f39c34d
Update R/validate.R
r-ash Jun 22, 2021
632fe88
Code tidy
r-ash Jun 22, 2021
688233d
Merge branch 'mrc-2476' of github.com:ropensci/jsonvalidate into mrc-…
r-ash Jun 22, 2021
700f8bb
Regenerate docs
r-ash Jun 22, 2021
1870d98
Switch back to imjv default, fallback on ajv if schema version > draf…
r-ash Jun 22, 2021
8d77aff
Add dataPath property for backward compatibility
r-ash Jun 22, 2021
f511066
Add support for using 2019-09 and 2020-12 json schema
r-ash Jun 22, 2021
a4e6267
New approach to backward compatibility
richfitz Jul 5, 2021
e02ff96
Add rob
richfitz Jul 5, 2021
eb0f147
Enable GHA for this branch
richfitz Jul 5, 2021
8ca69c2
Fix news
richfitz Jul 5, 2021
132269c
Merge pull request #45 from ropensci/mrc-2476-compat
r-ash Jul 6, 2021
ad90324
Update .github/workflows/R-CMD-check.yaml
r-ash Jul 6, 2021
5a938e5
Update .github/workflows/test-coverage.yaml
r-ash Jul 6, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
Package: jsonvalidate
Title: Validate 'JSON' Schema
Version: 1.2.3
Version: 1.3.0
Authors@R: c(person("Rich", "FitzJohn", role = c("aut", "cre"),
email = "rich.fitzjohn@gmail.com"),
person("Rob", "Ashton", role = "aut"),
person("Alicia", "Schep", role = "ctb"),
person("Ian", "Lyttle", role = "ctb"),
person("Kara", "Woo", role = "ctb"),
Expand All @@ -23,7 +24,8 @@ Suggests:
knitr,
jsonlite,
rmarkdown,
testthat
testthat,
withr
RoxygenNote: 7.1.1
VignetteBuilder: knitr
Encoding: UTF-8
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## jsonvalidate 1.3.0

* Upgrade to ajv version 8.5.0
* Add arg `strict` to `json_validate` and `json_validator` to allow evaluating schema in strict mode for ajv only. This is off (`FALSE`) by default to use permissive behaviour detailed in JSON schema

## jsonvalidate 1.2.3

* Schemas can use references to other files with JSON pointers i.e. schemas can reference parts of other files e.g. `definitions.json#/definitions/hello`
Expand Down
8 changes: 2 additions & 6 deletions R/read.R
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,10 @@ read_meta_schema_version <- function(schema, v8) {
return(NULL)
}

regex <- "^http://json-schema.org/(draft-\\d{2})/schema#$"
regex <- paste0("^https*://json-schema.org/",
"(draft-\\d{2}|draft/\\d{4}-\\d{2})/schema#*$")
version <- gsub(regex, "\\1", meta_schema)

versions_legal <- c("draft-04", "draft-06", "draft-07")
if (!(version %in% versions_legal)) {
stop(sprintf("Unknown meta schema version '%s'", version))
}

version
}

Expand Down
7 changes: 7 additions & 0 deletions R/util.R
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,10 @@ set_names <- function(x, nms) {
names(x) <- nms
x
}


note_imjv <- function(msg) {
if (!isTRUE(getOption("jsonvalidate.no_note_imjv", FALSE))) {
message(msg)
}
}
95 changes: 82 additions & 13 deletions R/validate.R
Original file line number Diff line number Diff line change
@@ -1,5 +1,46 @@
##' Create a validator that can validate multiple json files.
##'
##' @section Validation Engines:
##'
##' We support two different json validation engines, \code{imjv}
##' ("is-my-json-valid") and \code{ajv} ("Another JSON
##' Validator"). \code{imjv} was the original validator included in
##' the package and remains the default for reasons of backward
##' compatibility. However, users are encouraged to migrate to
##' \code{ajv} as with it we support many more features, including
##' nested schemas that span multiple files, meta schema versions
##' later than draft-04, validating using a subschema, and
##' validating a subset of an input data object.
##'
##' If your schema uses these features we will print a message to
##' screen indicating that you should update. We do not use a
##' warning here as this will be disruptive to users. You can
##' disable the message by setting the option
##' \code{jsonvalidate.no_note_imjv} to \code{TRUE}. Consider
##' using \code{withr::with_options} (or simply
##' \code{suppressMessages}) to scope this option if you want to
##' quieten it within code you do not control.
##'
##' Updating the engine should be simply a case of adding \code{engine
##' = "ajv"} to your \code{json_validator} or \code{json_validate}
##' calls, but you may see some issues when doing so.
##'
##' \itemize{
##' \item Your json now fails validation: We've seen this where
##' schemas spanned several files and are silently ignored. By
##' including these, your data may now fail validation and you will
##' need to either fix the data or the schema.
##'
##' \item Your code depended on the exact payload returned by
##' \code{imjv}: If you are inspecting the error result and checking
##' numbers of errors, or even the columns used to describe the
##' errors, you will likely need to update your code to accommodate
##' the slightly different format of \code{ajv}
##'
##' \item Your schema is simply invalid: If you reference an invalid
##' metaschema for example, jsonvalidate will fail
##' }
##'
##' @title Create a json validator
##'
##' @param schema Contents of the json schema, or a filename
Expand All @@ -17,6 +58,13 @@
##' would check that the json is a valid "Hello" object. Only available if
##' \code{engine = 'ajv'}.
##'
##' @param strict Set whether the schema should be parsed strictly or not.
##' If in strict mode schemas will error to "prevent any unexpected
##' behaviours or silently ignored mistakes in user schema". For example
##' it will error if encounters unknown formats or unknown keywords. See
##' https://ajv.js.org/strict-mode.html for details. Only available in
##' \code{engine = 'ajv'}.
##'
##' @section Using multiple files:
##'
##' Multiple files are supported. You can have a schema that
Expand All @@ -33,12 +81,14 @@
##'
##' @export
##' @example man-roxygen/example-json_validator.R
json_validator <- function(schema, engine = "imjv", reference = NULL) {
json_validator <- function(schema, engine = "imjv", reference = NULL,
strict = FALSE) {
v8 <- env$ct
schema <- read_schema(schema, v8)

switch(engine,
imjv = json_validator_imjv(schema, v8, reference),
ajv = json_validator_ajv(schema, v8, reference),
ajv = json_validator_ajv(schema, v8, reference, strict),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if we try and use imjv with a meta schema version of draft-6/7? Still throws an error? We should probably document that. Also the docstring for engine needs updating to reflect the new default

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It still throws an error yeah - this referenced issue from the code mafintosh/is-my-json-valid#160 still a problem

stop(sprintf("Unknown engine '%s'", engine)))
}

Expand Down Expand Up @@ -74,9 +124,10 @@ json_validator <- function(schema, engine = "imjv", reference = NULL) {
##' @example man-roxygen/example-json_validate.R
json_validate <- function(json, schema, verbose = FALSE, greedy = FALSE,
error = FALSE, engine = "imjv", reference = NULL,
query = NULL) {
tmp <- json_validator(schema, engine, reference = reference)
tmp(json, verbose, greedy, error, query)
query = NULL, strict = FALSE) {
validator <- json_validator(schema, engine, reference = reference,
strict = strict)
validator(json, verbose, greedy, error, query)
}


Expand All @@ -85,17 +136,25 @@ json_validator_imjv <- function(schema, v8, reference) {
meta_schema_version <- schema$meta_schema_version %||% "draft-04"

if (!is.null(reference)) {
## This one has to be an error; it has never worked and makes no
## sense.
stop("subschema validation only supported with engine 'ajv'")
}

if (meta_schema_version != "draft-04") {
stop(sprintf(
"meta schema version '%s' is only supported with engine 'ajv'",
meta_schema_version))
## We detect the version, so let the user know they are not really
## getting what they're asking for
note_imjv(paste(
"meta schema version other than 'draft-04' is only supported with",
sprintf("engine 'ajv' (requested: '%s')", meta_schema_version),
"- falling back to use 'draft-04'"))
meta_schema_version <- "draft-04"
}

if (length(schema$dependencies) > 0L) {
stop("Schema references are only supported with engine 'ajv'")
## We've found references, but can't support them. Let the user
## know.
note_imjv("Schema references are only supported with engine 'ajv'")
}

v8$call("imjv_create", name, meta_schema_version, V8::JS(schema$schema))
Expand All @@ -119,19 +178,25 @@ json_validator_imjv <- function(schema, v8, reference) {
}


json_validator_ajv <- function(schema, v8, reference) {
json_validator_ajv <- function(schema, v8, reference, strict) {
name <- random_id()
meta_schema_version <- schema$meta_schema_version %||% "draft-07"

versions_legal <- c("draft-04", "draft-06", "draft-07", "draft/2019-09",
"draft/2020-12")
if (!(meta_schema_version %in% versions_legal)) {
stop(sprintf("Unknown meta schema version '%s'", meta_schema_version))
}

if (is.null(reference)) {
reference <- V8::JS("null")
}
if (is.null(schema$filename)) {
schema$filename <- V8::JS("null")
}
dependencies <- V8::JS(schema$dependencies %||% "null")
v8$call("ajv_create", name, meta_schema_version, V8::JS(schema$schema),
schema$filename, dependencies, reference)
v8$call("ajv_create", name, meta_schema_version, strict,
V8::JS(schema$schema), schema$filename, dependencies, reference)

ret <- function(json, verbose = FALSE, greedy = FALSE, error = FALSE,
query = NULL) {
Expand Down Expand Up @@ -164,6 +229,10 @@ validation_result <- function(res, error, verbose) {
stop(validation_error(res))
}
if (verbose) {
## In ajv version < 8 errors had dataPath property. This has
## been renamed to instancePath in v8 +. Keep dataPath for
## backwards compatibility to support dccvalidator
res$errors$dataPath <- res$errors$instancePath
attr(success, "errors") <- res$errors
}
}
Expand All @@ -177,7 +246,7 @@ validation_error <- function(res) {
n <- nrow(errors)
if (res$engine == "ajv") {
detail <- paste(sprintf("\t- %s (%s): %s",
errors$dataPath,
errors$instancePath,
errors$schemaPath,
errors$message),
collapse = "\n")
Expand Down
2 changes: 1 addition & 1 deletion inst/LICENSE.ajv
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2015-2017 Evgeny Poberezkin
Copyright (c) 2015-2021 Evgeny Poberezkin

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
Loading