committed by
Seth Hillbrand
12 changed files with 2430 additions and 0 deletions
-
1LICENSE.README
-
1thirdparty/CMakeLists.txt
-
17thirdparty/json_schema_validator/CMakeLists.txt
-
22thirdparty/json_schema_validator/LICENSE.MIT
-
7thirdparty/json_schema_validator/README.txt
-
115thirdparty/json_schema_validator/json-patch.cpp
-
38thirdparty/json_schema_validator/json-patch.hpp
-
185thirdparty/json_schema_validator/json-schema-draft7.json.cpp
-
159thirdparty/json_schema_validator/json-uri.cpp
-
1376thirdparty/json_schema_validator/json-validator.cpp
-
198thirdparty/json_schema_validator/nlohmann/json-schema.hpp
-
311thirdparty/json_schema_validator/string-format-check.cpp
@ -0,0 +1,17 @@ |
|||||
|
add_library( nlohmann_json_schema_validator |
||||
|
json-schema-draft7.json.cpp |
||||
|
json-uri.cpp |
||||
|
json-validator.cpp |
||||
|
json-patch.cpp |
||||
|
string-format-check.cpp |
||||
|
) |
||||
|
|
||||
|
target_include_directories( nlohmann_json_schema_validator |
||||
|
PUBLIC |
||||
|
$<INSTALL_INTERFACE:include> |
||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> |
||||
|
) |
||||
|
|
||||
|
target_link_libraries( nlohmann_json_schema_validator |
||||
|
PUBLIC nlohmann_json |
||||
|
) |
@ -0,0 +1,22 @@ |
|||||
|
Modern C++ JSON schema validator is licensed under the MIT License |
||||
|
<http://opensource.org/licenses/MIT>: |
||||
|
|
||||
|
Copyright (c) 2016 Patrick Boettcher |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of |
||||
|
this software and associated documentation files (the "Software"), to deal in |
||||
|
the Software without restriction, including without limitation the rights to |
||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
||||
|
of the Software, and to permit persons to whom the Software is furnished to do |
||||
|
so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included in all |
||||
|
copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
|
SOFTWARE. |
@ -0,0 +1,7 @@ |
|||||
|
This directory contains the pboettch/json-schema-validator project |
||||
|
from https://github.com/pboettch/json-schema-validator |
||||
|
with a patch to allow validating objects against specific sub definitions |
||||
|
in a schema from |
||||
|
https://github.com/pboettch/json-schema-validator/pull/154 |
||||
|
|
||||
|
The project is licensed under MIT, with the license text in this directory. |
@ -0,0 +1,115 @@ |
|||||
|
#include "json-patch.hpp"
|
||||
|
|
||||
|
#include <nlohmann/json-schema.hpp>
|
||||
|
|
||||
|
namespace |
||||
|
{ |
||||
|
|
||||
|
// originally from http://jsonpatch.com/, http://json.schemastore.org/json-patch
|
||||
|
// with fixes
|
||||
|
const nlohmann::json patch_schema = R"patch({ |
||||
|
"title": "JSON schema for JSONPatch files", |
||||
|
"$schema": "http://json-schema.org/draft-04/schema#", |
||||
|
"type": "array", |
||||
|
|
||||
|
"items": { |
||||
|
"oneOf": [ |
||||
|
{ |
||||
|
"additionalProperties": false, |
||||
|
"required": [ "value", "op", "path"], |
||||
|
"properties": { |
||||
|
"path" : { "$ref": "#/definitions/path" }, |
||||
|
"op": { |
||||
|
"description": "The operation to perform.", |
||||
|
"type": "string", |
||||
|
"enum": [ "add", "replace", "test" ] |
||||
|
}, |
||||
|
"value": { |
||||
|
"description": "The value to add, replace or test." |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"additionalProperties": false, |
||||
|
"required": [ "op", "path"], |
||||
|
"properties": { |
||||
|
"path" : { "$ref": "#/definitions/path" }, |
||||
|
"op": { |
||||
|
"description": "The operation to perform.", |
||||
|
"type": "string", |
||||
|
"enum": [ "remove" ] |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"additionalProperties": false, |
||||
|
"required": [ "from", "op", "path" ], |
||||
|
"properties": { |
||||
|
"path" : { "$ref": "#/definitions/path" }, |
||||
|
"op": { |
||||
|
"description": "The operation to perform.", |
||||
|
"type": "string", |
||||
|
"enum": [ "move", "copy" ] |
||||
|
}, |
||||
|
"from": { |
||||
|
"$ref": "#/definitions/path", |
||||
|
"description": "A JSON Pointer path pointing to the location to move/copy from." |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
"definitions": { |
||||
|
"path": { |
||||
|
"description": "A JSON Pointer path.", |
||||
|
"type": "string" |
||||
|
} |
||||
|
} |
||||
|
})patch"_json; |
||||
|
} // namespace
|
||||
|
|
||||
|
namespace nlohmann |
||||
|
{ |
||||
|
|
||||
|
json_patch::json_patch(json &&patch) |
||||
|
: j_(std::move(patch)) |
||||
|
{ |
||||
|
validateJsonPatch(j_); |
||||
|
} |
||||
|
|
||||
|
json_patch::json_patch(const json &patch) |
||||
|
: j_(std::move(patch)) |
||||
|
{ |
||||
|
validateJsonPatch(j_); |
||||
|
} |
||||
|
|
||||
|
json_patch &json_patch::add(const json::json_pointer &ptr, json value) |
||||
|
{ |
||||
|
j_.push_back(json{{"op", "add"}, {"path", ptr}, {"value", std::move(value)}}); |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
json_patch &json_patch::replace(const json::json_pointer &ptr, json value) |
||||
|
{ |
||||
|
j_.push_back(json{{"op", "replace"}, {"path", ptr}, {"value", std::move(value)}}); |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
json_patch &json_patch::remove(const json::json_pointer &ptr) |
||||
|
{ |
||||
|
j_.push_back(json{{"op", "remove"}, {"path", ptr}}); |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
void json_patch::validateJsonPatch(json const &patch) |
||||
|
{ |
||||
|
// static put here to have it created at the first usage of validateJsonPatch
|
||||
|
static nlohmann::json_schema::json_validator patch_validator(patch_schema); |
||||
|
|
||||
|
patch_validator.validate(patch); |
||||
|
|
||||
|
for (auto const &op : patch) |
||||
|
json::json_pointer(op["path"].get<std::string>()); |
||||
|
} |
||||
|
|
||||
|
} // namespace nlohmann
|
@ -0,0 +1,38 @@ |
|||||
|
#pragma once
|
||||
|
|
||||
|
#include <nlohmann/json.hpp>
|
||||
|
#include <string>
|
||||
|
|
||||
|
namespace nlohmann |
||||
|
{ |
||||
|
class JsonPatchFormatException : public std::exception |
||||
|
{ |
||||
|
public: |
||||
|
explicit JsonPatchFormatException(std::string msg) |
||||
|
: ex_{std::move(msg)} {} |
||||
|
|
||||
|
inline const char *what() const noexcept override final { return ex_.c_str(); } |
||||
|
|
||||
|
private: |
||||
|
std::string ex_; |
||||
|
}; |
||||
|
|
||||
|
class json_patch |
||||
|
{ |
||||
|
public: |
||||
|
json_patch() = default; |
||||
|
json_patch(json &&patch); |
||||
|
json_patch(const json &patch); |
||||
|
|
||||
|
json_patch &add(const json::json_pointer &, json value); |
||||
|
json_patch &replace(const json::json_pointer &, json value); |
||||
|
json_patch &remove(const json::json_pointer &); |
||||
|
|
||||
|
operator json() const { return j_; } |
||||
|
|
||||
|
private: |
||||
|
json j_; |
||||
|
|
||||
|
static void validateJsonPatch(json const &patch); |
||||
|
}; |
||||
|
} // namespace nlohmann
|
@ -0,0 +1,185 @@ |
|||||
|
/*
|
||||
|
* JSON schema validator for JSON for modern C++ |
||||
|
* |
||||
|
* Copyright (c) 2016-2019 Patrick Boettcher <p@yai.se>. |
||||
|
* |
||||
|
* SPDX-License-Identifier: MIT |
||||
|
* |
||||
|
*/ |
||||
|
#include <nlohmann/json.hpp>
|
||||
|
|
||||
|
namespace nlohmann |
||||
|
{ |
||||
|
namespace json_schema |
||||
|
{ |
||||
|
|
||||
|
json draft7_schema_builtin = R"( { |
||||
|
"$schema": "http://json-schema.org/draft-07/schema#", |
||||
|
"$id": "http://json-schema.org/draft-07/schema#", |
||||
|
"title": "Core schema meta-schema", |
||||
|
"definitions": { |
||||
|
"schemaArray": { |
||||
|
"type": "array", |
||||
|
"minItems": 1, |
||||
|
"items": { "$ref": "#" } |
||||
|
}, |
||||
|
"nonNegativeInteger": { |
||||
|
"type": "integer", |
||||
|
"minimum": 0 |
||||
|
}, |
||||
|
"nonNegativeIntegerDefault0": { |
||||
|
"allOf": [ |
||||
|
{ "$ref": "#/definitions/nonNegativeInteger" }, |
||||
|
{ "default": 0 } |
||||
|
] |
||||
|
}, |
||||
|
"simpleTypes": { |
||||
|
"enum": [ |
||||
|
"array", |
||||
|
"boolean", |
||||
|
"integer", |
||||
|
"null", |
||||
|
"number", |
||||
|
"object", |
||||
|
"string" |
||||
|
] |
||||
|
}, |
||||
|
"stringArray": { |
||||
|
"type": "array", |
||||
|
"items": { "type": "string" }, |
||||
|
"uniqueItems": true, |
||||
|
"default": [] |
||||
|
} |
||||
|
}, |
||||
|
"type": ["object", "boolean"], |
||||
|
"properties": { |
||||
|
"$id": { |
||||
|
"type": "string", |
||||
|
"format": "uri-reference" |
||||
|
}, |
||||
|
"$schema": { |
||||
|
"type": "string", |
||||
|
"format": "uri" |
||||
|
}, |
||||
|
"$ref": { |
||||
|
"type": "string", |
||||
|
"format": "uri-reference" |
||||
|
}, |
||||
|
"$comment": { |
||||
|
"type": "string" |
||||
|
}, |
||||
|
"title": { |
||||
|
"type": "string" |
||||
|
}, |
||||
|
"description": { |
||||
|
"type": "string" |
||||
|
}, |
||||
|
"default": true, |
||||
|
"readOnly": { |
||||
|
"type": "boolean", |
||||
|
"default": false |
||||
|
}, |
||||
|
"examples": { |
||||
|
"type": "array", |
||||
|
"items": true |
||||
|
}, |
||||
|
"multipleOf": { |
||||
|
"type": "number", |
||||
|
"exclusiveMinimum": 0 |
||||
|
}, |
||||
|
"maximum": { |
||||
|
"type": "number" |
||||
|
}, |
||||
|
"exclusiveMaximum": { |
||||
|
"type": "number" |
||||
|
}, |
||||
|
"minimum": { |
||||
|
"type": "number" |
||||
|
}, |
||||
|
"exclusiveMinimum": { |
||||
|
"type": "number" |
||||
|
}, |
||||
|
"maxLength": { "$ref": "#/definitions/nonNegativeInteger" }, |
||||
|
"minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, |
||||
|
"pattern": { |
||||
|
"type": "string", |
||||
|
"format": "regex" |
||||
|
}, |
||||
|
"additionalItems": { "$ref": "#" }, |
||||
|
"items": { |
||||
|
"anyOf": [ |
||||
|
{ "$ref": "#" }, |
||||
|
{ "$ref": "#/definitions/schemaArray" } |
||||
|
], |
||||
|
"default": true |
||||
|
}, |
||||
|
"maxItems": { "$ref": "#/definitions/nonNegativeInteger" }, |
||||
|
"minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, |
||||
|
"uniqueItems": { |
||||
|
"type": "boolean", |
||||
|
"default": false |
||||
|
}, |
||||
|
"contains": { "$ref": "#" }, |
||||
|
"maxProperties": { "$ref": "#/definitions/nonNegativeInteger" }, |
||||
|
"minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, |
||||
|
"required": { "$ref": "#/definitions/stringArray" }, |
||||
|
"additionalProperties": { "$ref": "#" }, |
||||
|
"definitions": { |
||||
|
"type": "object", |
||||
|
"additionalProperties": { "$ref": "#" }, |
||||
|
"default": {} |
||||
|
}, |
||||
|
"properties": { |
||||
|
"type": "object", |
||||
|
"additionalProperties": { "$ref": "#" }, |
||||
|
"default": {} |
||||
|
}, |
||||
|
"patternProperties": { |
||||
|
"type": "object", |
||||
|
"additionalProperties": { "$ref": "#" }, |
||||
|
"propertyNames": { "format": "regex" }, |
||||
|
"default": {} |
||||
|
}, |
||||
|
"dependencies": { |
||||
|
"type": "object", |
||||
|
"additionalProperties": { |
||||
|
"anyOf": [ |
||||
|
{ "$ref": "#" }, |
||||
|
{ "$ref": "#/definitions/stringArray" } |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
"propertyNames": { "$ref": "#" }, |
||||
|
"const": true, |
||||
|
"enum": { |
||||
|
"type": "array", |
||||
|
"items": true, |
||||
|
"minItems": 1, |
||||
|
"uniqueItems": true |
||||
|
}, |
||||
|
"type": { |
||||
|
"anyOf": [ |
||||
|
{ "$ref": "#/definitions/simpleTypes" }, |
||||
|
{ |
||||
|
"type": "array", |
||||
|
"items": { "$ref": "#/definitions/simpleTypes" }, |
||||
|
"minItems": 1, |
||||
|
"uniqueItems": true |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
"format": { "type": "string" }, |
||||
|
"contentMediaType": { "type": "string" }, |
||||
|
"contentEncoding": { "type": "string" }, |
||||
|
"if": { "$ref": "#" }, |
||||
|
"then": { "$ref": "#" }, |
||||
|
"else": { "$ref": "#" }, |
||||
|
"allOf": { "$ref": "#/definitions/schemaArray" }, |
||||
|
"anyOf": { "$ref": "#/definitions/schemaArray" }, |
||||
|
"oneOf": { "$ref": "#/definitions/schemaArray" }, |
||||
|
"not": { "$ref": "#" } |
||||
|
}, |
||||
|
"default": true |
||||
|
} )"_json; |
||||
|
} |
||||
|
} // namespace nlohmann
|
@ -0,0 +1,159 @@ |
|||||
|
/*
|
||||
|
* JSON schema validator for JSON for modern C++ |
||||
|
* |
||||
|
* Copyright (c) 2016-2019 Patrick Boettcher <p@yai.se>. |
||||
|
* |
||||
|
* SPDX-License-Identifier: MIT |
||||
|
* |
||||
|
*/ |
||||
|
#include <nlohmann/json-schema.hpp>
|
||||
|
|
||||
|
#include <sstream>
|
||||
|
|
||||
|
namespace nlohmann |
||||
|
{ |
||||
|
|
||||
|
void json_uri::update(const std::string &uri) |
||||
|
{ |
||||
|
std::string pointer = ""; // default pointer is document-root
|
||||
|
|
||||
|
// first split the URI into location and pointer
|
||||
|
auto pointer_separator = uri.find('#'); |
||||
|
if (pointer_separator != std::string::npos) { // and extract the pointer-string if found
|
||||
|
pointer = uri.substr(pointer_separator + 1); // remove #
|
||||
|
|
||||
|
// unescape %-values IOW, decode JSON-URI-formatted JSON-pointer
|
||||
|
std::size_t pos = pointer.size() - 1; |
||||
|
do { |
||||
|
pos = pointer.rfind('%', pos); |
||||
|
if (pos == std::string::npos) |
||||
|
break; |
||||
|
|
||||
|
if (pos >= pointer.size() - 2) { |
||||
|
pos--; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
std::string hex = pointer.substr(pos + 1, 2); |
||||
|
char ascii = (char) std::strtoul(hex.c_str(), nullptr, 16); |
||||
|
pointer.replace(pos, 3, 1, ascii); |
||||
|
|
||||
|
pos--; |
||||
|
} while (1); |
||||
|
} |
||||
|
|
||||
|
auto location = uri.substr(0, pointer_separator); |
||||
|
|
||||
|
if (location.size()) { // a location part has been found
|
||||
|
|
||||
|
// if it is an URN take it as it is
|
||||
|
if (location.find("urn:") == 0) { |
||||
|
urn_ = location; |
||||
|
|
||||
|
// and clear URL members
|
||||
|
scheme_ = ""; |
||||
|
authority_ = ""; |
||||
|
path_ = ""; |
||||
|
|
||||
|
} else { // it is an URL
|
||||
|
|
||||
|
// split URL in protocol, hostname and path
|
||||
|
std::size_t pos = 0; |
||||
|
auto proto = location.find("://", pos); |
||||
|
if (proto != std::string::npos) { // extract the protocol
|
||||
|
|
||||
|
urn_ = ""; // clear URN-member if URL is parsed
|
||||
|
|
||||
|
scheme_ = location.substr(pos, proto - pos); |
||||
|
pos = 3 + proto; // 3 == "://"
|
||||
|
|
||||
|
auto authority = location.find("/", pos); |
||||
|
if (authority != std::string::npos) { // and the hostname (no proto without hostname)
|
||||
|
authority_ = location.substr(pos, authority - pos); |
||||
|
pos = authority; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
auto path = location.substr(pos); |
||||
|
|
||||
|
// URNs cannot of have paths
|
||||
|
if (urn_.size() && path.size()) |
||||
|
throw std::invalid_argument("Cannot add a path (" + path + ") to an URN URI (" + urn_ + ")"); |
||||
|
|
||||
|
if (path[0] == '/') // if it starts with a / it is root-path
|
||||
|
path_ = path; |
||||
|
else if (pos == 0) { // the URL contained only a path and the current path has no / at the end, strip last element until / and append
|
||||
|
auto last_slash = path_.rfind('/'); |
||||
|
path_ = path_.substr(0, last_slash) + '/' + path; |
||||
|
} else // otherwise it is a subfolder
|
||||
|
path_.append(path); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
pointer_ = ""_json_pointer; |
||||
|
identifier_ = ""; |
||||
|
|
||||
|
if (pointer[0] == '/') |
||||
|
pointer_ = json::json_pointer(pointer); |
||||
|
else |
||||
|
identifier_ = pointer; |
||||
|
} |
||||
|
|
||||
|
std::string json_uri::location() const |
||||
|
{ |
||||
|
if (urn_.size()) |
||||
|
return urn_; |
||||
|
|
||||
|
std::stringstream s; |
||||
|
|
||||
|
if (scheme_.size() > 0) |
||||
|
s << scheme_ << "://"; |
||||
|
|
||||
|
s << authority_ |
||||
|
<< path_; |
||||
|
|
||||
|
return s.str(); |
||||
|
} |
||||
|
|
||||
|
std::string json_uri::to_string() const |
||||
|
{ |
||||
|
std::stringstream s; |
||||
|
|
||||
|
s << location() << " # "; |
||||
|
|
||||
|
if (identifier_ == "") |
||||
|
s << pointer_.to_string(); |
||||
|
else |
||||
|
s << identifier_; |
||||
|
|
||||
|
return s.str(); |
||||
|
} |
||||
|
|
||||
|
std::ostream &operator<<(std::ostream &os, const json_uri &u) |
||||
|
{ |
||||
|
return os << u.to_string(); |
||||
|
} |
||||
|
|
||||
|
std::string json_uri::escape(const std::string &src) |
||||
|
{ |
||||
|
std::vector<std::pair<std::string, std::string>> chars = { |
||||
|
{"~", "~0"}, |
||||
|
{"/", "~1"}}; |
||||
|
|
||||
|
std::string l = src; |
||||
|
|
||||
|
for (const auto &c : chars) { |
||||
|
std::size_t pos = 0; |
||||
|
do { |
||||
|
pos = l.find(c.first, pos); |
||||
|
if (pos == std::string::npos) |
||||
|
break; |
||||
|
l.replace(pos, 1, c.second); |
||||
|
pos += c.second.size(); |
||||
|
} while (1); |
||||
|
} |
||||
|
|
||||
|
return l; |
||||
|
} |
||||
|
|
||||
|
} // namespace nlohmann
|
1376
thirdparty/json_schema_validator/json-validator.cpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,198 @@ |
|||||
|
/*
|
||||
|
* JSON schema validator for JSON for modern C++ |
||||
|
* |
||||
|
* Copyright (c) 2016-2019 Patrick Boettcher <p@yai.se>. |
||||
|
* |
||||
|
* SPDX-License-Identifier: MIT |
||||
|
* |
||||
|
*/ |
||||
|
#ifndef NLOHMANN_JSON_SCHEMA_HPP__
|
||||
|
#define NLOHMANN_JSON_SCHEMA_HPP__
|
||||
|
|
||||
|
#ifdef _WIN32
|
||||
|
# if defined(JSON_SCHEMA_VALIDATOR_EXPORTS)
|
||||
|
# define JSON_SCHEMA_VALIDATOR_API __declspec(dllexport)
|
||||
|
# elif defined(JSON_SCHEMA_VALIDATOR_IMPORTS)
|
||||
|
# define JSON_SCHEMA_VALIDATOR_API __declspec(dllimport)
|
||||
|
# else
|
||||
|
# define JSON_SCHEMA_VALIDATOR_API
|
||||
|
# endif
|
||||
|
#else
|
||||
|
# define JSON_SCHEMA_VALIDATOR_API
|
||||
|
#endif
|
||||
|
|
||||
|
#include <nlohmann/json.hpp>
|
||||
|
|
||||
|
#ifdef NLOHMANN_JSON_VERSION_MAJOR
|
||||
|
# if (NLOHMANN_JSON_VERSION_MAJOR * 10000 + NLOHMANN_JSON_VERSION_MINOR * 100 + NLOHMANN_JSON_VERSION_PATCH) < 30800
|
||||
|
# error "Please use this library with NLohmann's JSON version 3.8.0 or higher"
|
||||
|
# endif
|
||||
|
#else
|
||||
|
# error "expected existing NLOHMANN_JSON_VERSION_MAJOR preproc variable, please update to NLohmann's JSON 3.8.0"
|
||||
|
#endif
|
||||
|
|
||||
|
// make yourself a home - welcome to nlohmann's namespace
|
||||
|
namespace nlohmann |
||||
|
{ |
||||
|
|
||||
|
// A class representing a JSON-URI for schemas derived from
|
||||
|
// section 8 of JSON Schema: A Media Type for Describing JSON Documents
|
||||
|
// draft-wright-json-schema-00
|
||||
|
//
|
||||
|
// New URIs can be derived from it using the derive()-method.
|
||||
|
// This is useful for resolving refs or subschema-IDs in json-schemas.
|
||||
|
//
|
||||
|
// This is done implement the requirements described in section 8.2.
|
||||
|
//
|
||||
|
class JSON_SCHEMA_VALIDATOR_API json_uri |
||||
|
{ |
||||
|
std::string urn_; |
||||
|
|
||||
|
std::string scheme_; |
||||
|
std::string authority_; |
||||
|
std::string path_; |
||||
|
|
||||
|
json::json_pointer pointer_; // fragment part if JSON-Pointer
|
||||
|
std::string identifier_; // fragment part if Locatation Independent ID
|
||||
|
|
||||
|
protected: |
||||
|
// decodes a JSON uri and replaces all or part of the currently stored values
|
||||
|
void update(const std::string &uri); |
||||
|
|
||||
|
std::tuple<std::string, std::string, std::string, std::string, std::string> as_tuple() const |
||||
|
{ |
||||
|
return std::make_tuple(urn_, scheme_, authority_, path_, identifier_ != "" ? identifier_ : pointer_); |
||||
|
} |
||||
|
|
||||
|
public: |
||||
|
json_uri(const std::string &uri) |
||||
|
{ |
||||
|
update(uri); |
||||
|
} |
||||
|
|
||||
|
const std::string &scheme() const { return scheme_; } |
||||
|
const std::string &authority() const { return authority_; } |
||||
|
const std::string &path() const { return path_; } |
||||
|
|
||||
|
const json::json_pointer &pointer() const { return pointer_; } |
||||
|
const std::string &identifier() const { return identifier_; } |
||||
|
|
||||
|
std::string fragment() const |
||||
|
{ |
||||
|
if (identifier_ == "") |
||||
|
return pointer_; |
||||
|
else |
||||
|
return identifier_; |
||||
|
} |
||||
|
|
||||
|
std::string url() const { return location(); } |
||||
|
std::string location() const; |
||||
|
|
||||
|
static std::string escape(const std::string &); |
||||
|
|
||||
|
// create a new json_uri based in this one and the given uri
|
||||
|
// resolves relative changes (pathes or pointers) and resets part if proto or hostname changes
|
||||
|
json_uri derive(const std::string &uri) const |
||||
|
{ |
||||
|
json_uri u = *this; |
||||
|
u.update(uri); |
||||
|
return u; |
||||
|
} |
||||
|
|
||||
|
// append a pointer-field to the pointer-part of this uri
|
||||
|
json_uri append(const std::string &field) const |
||||
|
{ |
||||
|
if (identifier_ != "") |
||||
|
return *this; |
||||
|
|
||||
|
json_uri u = *this; |
||||
|
u.pointer_ /= field; |
||||
|
return u; |
||||
|
} |
||||
|
|
||||
|
std::string to_string() const; |
||||
|
|
||||
|
friend bool operator<(const json_uri &l, const json_uri &r) |
||||
|
{ |
||||
|
return l.as_tuple() < r.as_tuple(); |
||||
|
} |
||||
|
|
||||
|
friend bool operator==(const json_uri &l, const json_uri &r) |
||||
|
{ |
||||
|
return l.as_tuple() == r.as_tuple(); |
||||
|
} |
||||
|
|
||||
|
friend std::ostream &operator<<(std::ostream &os, const json_uri &u); |
||||
|
}; |
||||
|
|
||||
|
namespace json_schema |
||||
|
{ |
||||
|
|
||||
|
extern json draft7_schema_builtin; |
||||
|
|
||||
|
typedef std::function<void(const json_uri & /*id*/, json & /*value*/)> schema_loader; |
||||
|
typedef std::function<void(const std::string & /*format*/, const std::string & /*value*/)> format_checker; |
||||
|
typedef std::function<void(const std::string & /*contentEncoding*/, const std::string & /*contentMediaType*/, const json & /*instance*/)> content_checker; |
||||
|
|
||||
|
// Interface for validation error handlers
|
||||
|
class JSON_SCHEMA_VALIDATOR_API error_handler |
||||
|
{ |
||||
|
public: |
||||
|
virtual ~error_handler() {} |
||||
|
virtual void error(const json::json_pointer & /*ptr*/, const json & /*instance*/, const std::string & /*message*/) = 0; |
||||
|
}; |
||||
|
|
||||
|
class JSON_SCHEMA_VALIDATOR_API basic_error_handler : public error_handler |
||||
|
{ |
||||
|
bool error_{false}; |
||||
|
|
||||
|
public: |
||||
|
void error(const json::json_pointer & /*ptr*/, const json & /*instance*/, const std::string & /*message*/) override |
||||
|
{ |
||||
|
error_ = true; |
||||
|
} |
||||
|
|
||||
|
virtual void reset() { error_ = false; } |
||||
|
operator bool() const { return error_; } |
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
* Checks validity of JSON schema built-in string format specifiers like 'date-time', 'ipv4', ... |
||||
|
*/ |
||||
|
void default_string_format_check(const std::string &format, const std::string &value); |
||||
|
|
||||
|
class root_schema; |
||||
|
|
||||
|
class JSON_SCHEMA_VALIDATOR_API json_validator |
||||
|
{ |
||||
|
std::unique_ptr<root_schema> root_; |
||||
|
|
||||
|
public: |
||||
|
json_validator(schema_loader = nullptr, format_checker = nullptr, content_checker = nullptr); |
||||
|
|
||||
|
json_validator(const json &, schema_loader = nullptr, format_checker = nullptr, content_checker = nullptr); |
||||
|
json_validator(json &&, schema_loader = nullptr, format_checker = nullptr, content_checker = nullptr); |
||||
|
|
||||
|
json_validator(json_validator &&); |
||||
|
json_validator &operator=(json_validator &&); |
||||
|
|
||||
|
json_validator(json_validator const &) = delete; |
||||
|
json_validator &operator=(json_validator const &) = delete; |
||||
|
|
||||
|
~json_validator(); |
||||
|
|
||||
|
// insert and set the root-schema
|
||||
|
void set_root_schema(const json &); |
||||
|
void set_root_schema(json &&); |
||||
|
|
||||
|
// validate a json-document based on the root-schema
|
||||
|
json validate(const json &) const; |
||||
|
|
||||
|
// validate a json-document based on the root-schema with a custom error-handler
|
||||
|
json validate(const json &, error_handler &, const json_uri &initial_uri = json_uri("#")) const; |
||||
|
}; |
||||
|
|
||||
|
} // namespace json_schema
|
||||
|
} // namespace nlohmann
|
||||
|
|
||||
|
#endif /* NLOHMANN_JSON_SCHEMA_HPP__ */
|
@ -0,0 +1,311 @@ |
|||||
|
#include <nlohmann/json-schema.hpp>
|
||||
|
|
||||
|
#include <algorithm>
|
||||
|
#include <exception>
|
||||
|
#include <iostream>
|
||||
|
#include <regex>
|
||||
|
#include <sstream>
|
||||
|
#include <string>
|
||||
|
#include <utility>
|
||||
|
#include <vector>
|
||||
|
|
||||
|
/**
|
||||
|
* Many of the RegExes are from @see http://jmrware.com/articles/2009/uri_regexp/URI_regex.html
|
||||
|
*/ |
||||
|
|
||||
|
namespace |
||||
|
{ |
||||
|
template <typename T> |
||||
|
void range_check(const T value, const T min, const T max) |
||||
|
{ |
||||
|
if (!((value >= min) && (value <= max))) { |
||||
|
std::stringstream out; |
||||
|
out << "Value " << value << " should be in interval [" << min << "," << max << "] but is not!"; |
||||
|
throw std::invalid_argument(out.str()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** @see date_time_check */ |
||||
|
void rfc3339_date_check(const std::string &value) |
||||
|
{ |
||||
|
const static std::regex dateRegex{R"(^([0-9]{4})\-([0-9]{2})\-([0-9]{2})$)"}; |
||||
|
|
||||
|
std::smatch matches; |
||||
|
if (!std::regex_match(value, matches, dateRegex)) { |
||||
|
throw std::invalid_argument(value + " is not a date string according to RFC 3339."); |
||||
|
} |
||||
|
|
||||
|
const auto year = std::stoi(matches[1].str()); |
||||
|
const auto month = std::stoi(matches[2].str()); |
||||
|
const auto mday = std::stoi(matches[3].str()); |
||||
|
|
||||
|
const auto isLeapYear = (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)); |
||||
|
|
||||
|
range_check(month, 1, 12); |
||||
|
if (month == 2) { |
||||
|
range_check(mday, 1, isLeapYear ? 29 : 28); |
||||
|
} else if (month <= 7) { |
||||
|
range_check(mday, 1, month % 2 == 0 ? 30 : 31); |
||||
|
} else { |
||||
|
range_check(mday, 1, month % 2 == 0 ? 31 : 30); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** @see date_time_check */ |
||||
|
void rfc3339_time_check(const std::string &value) |
||||
|
{ |
||||
|
const static std::regex timeRegex{R"(^([0-9]{2})\:([0-9]{2})\:([0-9]{2})(\.[0-9]+)?(?:[Zz]|((?:\+|\-)[0-9]{2})\:([0-9]{2}))$)"}; |
||||
|
|
||||
|
std::smatch matches; |
||||
|
if (!std::regex_match(value, matches, timeRegex)) { |
||||
|
throw std::invalid_argument(value + " is not a time string according to RFC 3339."); |
||||
|
} |
||||
|
|
||||
|
const auto hour = std::stoi(matches[1].str()); |
||||
|
const auto minute = std::stoi(matches[2].str()); |
||||
|
const auto second = std::stoi(matches[3].str()); |
||||
|
// const auto secfrac = std::stof( matches[4].str() );
|
||||
|
|
||||
|
range_check(hour, 0, 23); |
||||
|
range_check(minute, 0, 59); |
||||
|
/**
|
||||
|
* @todo Could be made more exact by querying a leap second database and choosing the |
||||
|
* correct maximum in {58,59,60}. This current solution might match some invalid dates |
||||
|
* but it won't lead to false negatives. This only works if we know the full date, however |
||||
|
*/ |
||||
|
range_check(second, 0, 60); |
||||
|
|
||||
|
/* don't check the numerical offset if time zone is specified as 'Z' */ |
||||
|
if (!matches[5].str().empty()) { |
||||
|
const auto offsetHour = std::stoi(matches[5].str()); |
||||
|
const auto offsetMinute = std::stoi(matches[6].str()); |
||||
|
|
||||
|
range_check(offsetHour, -23, 23); |
||||
|
range_check(offsetMinute, 0, 59); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* @see https://tools.ietf.org/html/rfc3339#section-5.6
|
||||
|
* |
||||
|
* @verbatim |
||||
|
* date-fullyear = 4DIGIT |
||||
|
* date-month = 2DIGIT ; 01-12 |
||||
|
* date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on |
||||
|
* ; month/year |
||||
|
* time-hour = 2DIGIT ; 00-23 |
||||
|
* time-minute = 2DIGIT ; 00-59 |
||||
|
* time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second |
||||
|
* ; rules |
||||
|
* time-secfrac = "." 1*DIGIT |
||||
|
* time-numoffset = ("+" / "-") time-hour ":" time-minute |
||||
|
* time-offset = "Z" / time-numoffset |
||||
|
* |
||||
|
* partial-time = time-hour ":" time-minute ":" time-second |
||||
|
* [time-secfrac] |
||||
|
* full-date = date-fullyear "-" date-month "-" date-mday |
||||
|
* full-time = partial-time time-offset |
||||
|
* |
||||
|
* date-time = full-date "T" full-time |
||||
|
* @endverbatim |
||||
|
* NOTE: Per [ABNF] and ISO8601, the "T" and "Z" characters in this |
||||
|
* syntax may alternatively be lower case "t" or "z" respectively. |
||||
|
*/ |
||||
|
void rfc3339_date_time_check(const std::string &value) |
||||
|
{ |
||||
|
const static std::regex dateTimeRegex{R"(^([0-9]{4}\-[0-9]{2}\-[0-9]{2})[Tt]([0-9]{2}\:[0-9]{2}\:[0-9]{2}(?:\.[0-9]+)?(?:[Zz]|(?:\+|\-)[0-9]{2}\:[0-9]{2}))$)"}; |
||||
|
|
||||
|
std::smatch matches; |
||||
|
if (!std::regex_match(value, matches, dateTimeRegex)) { |
||||
|
throw std::invalid_argument(value + " is not a date-time string according to RFC 3339."); |
||||
|
} |
||||
|
|
||||
|
rfc3339_date_check(matches[1].str()); |
||||
|
rfc3339_time_check(matches[2].str()); |
||||
|
} |
||||
|
|
||||
|
const std::string decOctet{R"((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))"}; // matches numbers 0-255
|
||||
|
const std::string ipv4Address{"(?:" + decOctet + R"(\.){3})" + decOctet}; |
||||
|
const std::string h16{R"([0-9A-Fa-f]{1,4})"}; |
||||
|
const std::string h16Left{"(?:" + h16 + ":)"}; |
||||
|
const std::string ipv6Address{ |
||||
|
"(?:" |
||||
|
"(?:" + |
||||
|
h16Left + "{6}" |
||||
|
"|::" + |
||||
|
h16Left + "{5}" |
||||
|
"|(?:" + |
||||
|
h16 + ")?::" + h16Left + "{4}" |
||||
|
"|(?:" + |
||||
|
h16Left + "{0,1}" + h16 + ")?::" + h16Left + "{3}" |
||||
|
"|(?:" + |
||||
|
h16Left + "{0,2}" + h16 + ")?::" + h16Left + "{2}" |
||||
|
"|(?:" + |
||||
|
h16Left + "{0,3}" + h16 + ")?::" + h16Left + |
||||
|
"|(?:" + h16Left + "{0,4}" + h16 + ")?::" |
||||
|
")(?:" + |
||||
|
h16Left + h16 + "|" + ipv4Address + ")" |
||||
|
"|(?:" + |
||||
|
h16Left + "{0,5}" + h16 + ")?::" + h16 + |
||||
|
"|(?:" + h16Left + "{0,6}" + h16 + ")?::" |
||||
|
")"}; |
||||
|
const std::string ipvFuture{R"([Vv][0-9A-Fa-f]+\.[A-Za-z0-9\-._~!$&'()*+,;=:]+)"}; |
||||
|
const std::string regName{R"((?:[A-Za-z0-9\-._~!$&'()*+,;=]|%[0-9A-Fa-f]{2})*)"}; |
||||
|
const std::string host{ |
||||
|
"(?:" |
||||
|
R"(\[(?:)" + |
||||
|
ipv6Address + "|" + ipvFuture + R"()\])" + |
||||
|
"|" + ipv4Address + |
||||
|
"|" + regName + |
||||
|
")"}; |
||||
|
|
||||
|
// from http://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address
|
||||
|
const std::string hostname{R"(^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$)"}; |
||||
|
|
||||
|
/**
|
||||
|
* @see https://tools.ietf.org/html/rfc5322#section-4.1
|
||||
|
* |
||||
|
* @verbatim |
||||
|
* atom = [CFWS] 1*atext [CFWS] |
||||
|
* word = atom / quoted-string |
||||
|
* phrase = 1*word / obs-phrase |
||||
|
* obs-FWS = 1*WSP *(CRLF 1*WSP) |
||||
|
* FWS = ([*WSP CRLF] 1*WSP) / obs-FWS |
||||
|
* ; Folding white space |
||||
|
* ctext = %d33-39 / ; Printable US-ASCII |
||||
|
* %d42-91 / ; characters not including |
||||
|
* %d93-126 / ; "(", ")", or "\" |
||||
|
* obs-ctext |
||||
|
* ccontent = ctext / quoted-pair / comment |
||||
|
* comment = "(" *([FWS] ccontent) [FWS] ")" |
||||
|
* CFWS = (1*([FWS] comment) [FWS]) / FWS |
||||
|
* obs-local-part = word *("." word) |
||||
|
* obs-domain = atom *("." atom) |
||||
|
* obs-dtext = obs-NO-WS-CTL / quoted-pair |
||||
|
* quoted-pair = ("\" (VCHAR / WSP)) / obs-qp |
||||
|
* obs-NO-WS-CTL = %d1-8 / ; US-ASCII control |
||||
|
* %d11 / ; characters that do not |
||||
|
* %d12 / ; include the carriage |
||||
|
* %d14-31 / ; return, line feed, and |
||||
|
* %d127 ; white space characters |
||||
|
* obs-ctext = obs-NO-WS-CTL |
||||
|
* obs-qtext = obs-NO-WS-CTL |
||||
|
* obs-utext = %d0 / obs-NO-WS-CTL / VCHAR |
||||
|
* obs-qp = "\" (%d0 / obs-NO-WS-CTL / LF / CR) |
||||
|
* obs-body = *((*LF *CR *((%d0 / text) *LF *CR)) / CRLF) |
||||
|
* obs-unstruct = *((*LF *CR *(obs-utext *LF *CR)) / FWS) |
||||
|
* obs-phrase = word *(word / "." / CFWS) |
||||
|
* obs-phrase-list = [phrase / CFWS] *("," [phrase / CFWS]) |
||||
|
* qtext = %d33 / ; Printable US-ASCII |
||||
|
* %d35-91 / ; characters not including |
||||
|
* %d93-126 / ; "\" or the quote character |
||||
|
* obs-qtext |
||||
|
* qcontent = qtext / quoted-pair |
||||
|
* quoted-string = [CFWS] |
||||
|
* DQUOTE *([FWS] qcontent) [FWS] DQUOTE |
||||
|
* [CFWS] |
||||
|
* atext = ALPHA / DIGIT / ; Printable US-ASCII |
||||
|
* "!" / "#" / ; characters not including |
||||
|
* "$" / "%" / ; specials. Used for atoms. |
||||
|
* "&" / "'" / |
||||
|
* "*" / "+" / |
||||
|
* "-" / "/" / |
||||
|
* "=" / "?" / |
||||
|
* "^" / "_" / |
||||
|
* "`" / "{" / |
||||
|
* "|" / "}" / |
||||
|
* "~" |
||||
|
* dot-atom-text = 1*atext *("." 1*atext) |
||||
|
* dot-atom = [CFWS] dot-atom-text [CFWS] |
||||
|
* addr-spec = local-part "@" domain |
||||
|
* local-part = dot-atom / quoted-string / obs-local-part |
||||
|
* domain = dot-atom / domain-literal / obs-domain |
||||
|
* domain-literal = [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS] |
||||
|
* dtext = %d33-90 / ; Printable US-ASCII |
||||
|
* %d94-126 / ; characters not including |
||||
|
* obs-dtext ; "[", "]", or "\" |
||||
|
* @endverbatim |
||||
|
* @todo Currently don't have a working tool for this larger ABNF to generate a regex. |
||||
|
* Other options: |
||||
|
* - https://github.com/ldthomas/apg-6.3
|
||||
|
* - https://github.com/akr/abnf
|
||||
|
* |
||||
|
* The problematic thing are the allowed whitespaces (even newlines) in the email. |
||||
|
* Ignoring those and starting with |
||||
|
* @see https://stackoverflow.com/questions/13992403/regex-validation-of-email-addresses-according-to-rfc5321-rfc5322
|
||||
|
* and trying to divide up the complicated regex into understandable ABNF definitions from rfc5322 yields: |
||||
|
*/ |
||||
|
const std::string obsnowsctl{R"([\x01-\x08\x0b\x0c\x0e-\x1f\x7f])"}; |
||||
|
const std::string obsqp{R"(\\[\x01-\x09\x0b\x0c\x0e-\x7f])"}; |
||||
|
const std::string qtext{R"((?:[\x21\x23-\x5b\x5d-\x7e]|)" + obsnowsctl + ")"}; |
||||
|
const std::string dtext{R"([\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f])"}; |
||||
|
const std::string quotedString{R"("(?:)" + qtext + "|" + obsqp + R"()*")"}; |
||||
|
const std::string atext{R"([A-Za-z0-9!#$%&'*+/=?^_`{|}~-])"}; |
||||
|
const std::string domainLiteral{R"(\[(?:(?:)" + decOctet + R"()\.){3}(?:)" + decOctet + R"(|[A-Za-z0-9-]*[A-Za-z0-9]:(?:)" + dtext + "|" + obsqp + R"()+)\])"}; |
||||
|
|
||||
|
const std::string dotAtom{"(?:" + atext + R"(+(?:\.)" + atext + "+)*)"}; |
||||
|
const std::string stackoverflowMagicPart{R"((?:[[:alnum:]](?:[[:alnum:]-]*[[:alnum:]])?\.)+)" |
||||
|
R"([[:alnum:]](?:[[:alnum:]-]*[[:alnum:]])?)"}; |
||||
|
const std::string email{"(?:" + dotAtom + "|" + quotedString + ")@(?:" + stackoverflowMagicPart + "|" + domainLiteral + ")"}; |
||||
|
} // namespace
|
||||
|
|
||||
|
namespace nlohmann |
||||
|
{ |
||||
|
namespace json_schema |
||||
|
{ |
||||
|
/**
|
||||
|
* Checks validity for built-ins by converting the definitions given as ABNF in the linked RFC from |
||||
|
* @see https://json-schema.org/understanding-json-schema/reference/string.html#built-in-formats
|
||||
|
* into regular expressions using @see https://www.msweet.org/abnf/ and some manual editing.
|
||||
|
* |
||||
|
* @see https://json-schema.org/latest/json-schema-validation.html
|
||||
|
*/ |
||||
|
void default_string_format_check(const std::string &format, const std::string &value) |
||||
|
{ |
||||
|
if (format == "date-time") { |
||||
|
rfc3339_date_time_check(value); |
||||
|
} else if (format == "date") { |
||||
|
rfc3339_date_check(value); |
||||
|
} else if (format == "time") { |
||||
|
rfc3339_time_check(value); |
||||
|
} else if (format == "email") { |
||||
|
static const std::regex emailRegex{email}; |
||||
|
if (!std::regex_match(value, emailRegex)) { |
||||
|
throw std::invalid_argument(value + " is not a valid email according to RFC 5322."); |
||||
|
} |
||||
|
} else if (format == "hostname") { |
||||
|
static const std::regex hostRegex{hostname}; |
||||
|
if (!std::regex_match(value, hostRegex)) { |
||||
|
throw std::invalid_argument(value + " is not a valid hostname according to RFC 3986 Appendix A."); |
||||
|
} |
||||
|
} else if (format == "ipv4") { |
||||
|
const static std::regex ipv4Regex{"^" + ipv4Address + "$"}; |
||||
|
if (!std::regex_match(value, ipv4Regex)) { |
||||
|
throw std::invalid_argument(value + " is not an IPv4 string according to RFC 2673."); |
||||
|
} |
||||
|
} else if (format == "ipv6") { |
||||
|
static const std::regex ipv6Regex{ipv6Address}; |
||||
|
if (!std::regex_match(value, ipv6Regex)) { |
||||
|
throw std::invalid_argument(value + " is not an IPv6 string according to RFC 5954."); |
||||
|
} |
||||
|
} else if (format == "regex") { |
||||
|
try { |
||||
|
std::regex re(value, std::regex::ECMAScript); |
||||
|
} catch (std::exception &exception) { |
||||
|
throw exception; |
||||
|
} |
||||
|
} else { |
||||
|
/* yet unsupported JSON schema draft 7 built-ins */ |
||||
|
static const std::vector<std::string> jsonSchemaStringFormatBuiltIns{ |
||||
|
"date-time", "time", "date", "email", "idn-email", "hostname", "idn-hostname", "ipv4", "ipv6", "uri", |
||||
|
"uri-reference", "iri", "iri-reference", "uri-template", "json-pointer", "relative-json-pointer", "regex"}; |
||||
|
if (std::find(jsonSchemaStringFormatBuiltIns.begin(), jsonSchemaStringFormatBuiltIns.end(), format) != jsonSchemaStringFormatBuiltIns.end()) { |
||||
|
throw std::logic_error("JSON schema string format built-in " + format + " not yet supported. " + |
||||
|
"Please open an issue or use a custom format checker."); |
||||
|
} |
||||
|
|
||||
|
throw std::logic_error("Don't know how to validate " + format); |
||||
|
} |
||||
|
} |
||||
|
} // namespace json_schema
|
||||
|
} // namespace nlohmann
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue