mirror of
https://github.com/tristanpenman/valijson.git
synced 2025-03-03 12:58:03 +01:00
Cosmetic improvements for schema_parser.hpp and validation_results.hpp
This commit is contained in:
parent
71f4cdaa84
commit
217b990b00
@ -41,16 +41,13 @@ public:
|
||||
kDraft7
|
||||
};
|
||||
|
||||
/// Version of JSON Schema that should be expected when parsing
|
||||
const Version version;
|
||||
|
||||
/**
|
||||
* @brief Construct a new SchemaParser for a given version of JSON Schema
|
||||
*
|
||||
* @param version Version of JSON Schema that will be expected
|
||||
*/
|
||||
explicit SchemaParser(const Version version = kDraft7)
|
||||
: version(version) { }
|
||||
: m_version(version) { }
|
||||
|
||||
/**
|
||||
* @brief Release memory associated with custom ConstraintBuilders
|
||||
@ -68,14 +65,13 @@ public:
|
||||
template<typename AdapterType>
|
||||
struct FunctionPtrs
|
||||
{
|
||||
typedef typename adapters::AdapterTraits<AdapterType>::DocumentType
|
||||
DocumentType;
|
||||
typedef typename adapters::AdapterTraits<AdapterType>::DocumentType DocumentType;
|
||||
|
||||
/// Templated function pointer type for fetching remote documents
|
||||
typedef std::function< const DocumentType* (const std::string &uri) > FetchDoc ;
|
||||
typedef std::function<const DocumentType* (const std::string &uri)> FetchDoc;
|
||||
|
||||
/// Templated function pointer type for freeing fetched documents
|
||||
typedef std::function< void (const DocumentType *)> FreeDoc ;
|
||||
typedef std::function<void (const DocumentType *)> FreeDoc;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -96,8 +92,7 @@ public:
|
||||
* @todo Add additional checks for key conflicts, empty keys, and
|
||||
* potential restrictions relating to case sensitivity
|
||||
*/
|
||||
void addConstraintBuilder(const std::string &key,
|
||||
const ConstraintBuilder *builder)
|
||||
void addConstraintBuilder(const std::string &key, const ConstraintBuilder *builder)
|
||||
{
|
||||
constraintBuilders.push_back(std::make_pair(key, builder));
|
||||
}
|
||||
@ -122,17 +117,14 @@ public:
|
||||
typename FunctionPtrs<AdapterType>::FreeDoc freeDoc = nullptr )
|
||||
{
|
||||
if ((fetchDoc == nullptr ) ^ (freeDoc == nullptr)) {
|
||||
throw std::runtime_error(
|
||||
"Remote document fetching cannot be enabled without both "
|
||||
"fetch and free functions");
|
||||
throw std::runtime_error("Remote document fetching can't be enabled without both fetch and free functions");
|
||||
}
|
||||
|
||||
typename DocumentCache<AdapterType>::Type docCache;
|
||||
SchemaCache schemaCache;
|
||||
try {
|
||||
resolveThenPopulateSchema(schema, node, node, schema,
|
||||
opt::optional<std::string>(), "",
|
||||
fetchDoc, nullptr, nullptr, docCache, schemaCache);
|
||||
resolveThenPopulateSchema(schema, node, node, schema, opt::optional<std::string>(), "", fetchDoc, nullptr,
|
||||
nullptr, docCache, schemaCache);
|
||||
} catch (...) {
|
||||
freeDocumentCache<AdapterType>(docCache, freeDoc);
|
||||
throw;
|
||||
@ -151,8 +143,7 @@ private:
|
||||
template<typename AdapterType>
|
||||
struct DocumentCache
|
||||
{
|
||||
typedef typename adapters::AdapterTraits<AdapterType>::DocumentType
|
||||
DocumentType;
|
||||
typedef typename adapters::AdapterTraits<AdapterType>::DocumentType DocumentType;
|
||||
|
||||
typedef std::map<std::string, const DocumentType*> Type;
|
||||
};
|
||||
@ -204,16 +195,15 @@ private:
|
||||
* portions of URI provided by the resolution scope.
|
||||
*/
|
||||
virtual opt::optional<std::string> findAbsoluteDocumentUri(
|
||||
const opt::optional<std::string> resolutionScope,
|
||||
const opt::optional<std::string> documentUri)
|
||||
const opt::optional<std::string>& resolutionScope,
|
||||
const opt::optional<std::string>& documentUri)
|
||||
{
|
||||
if (resolutionScope) {
|
||||
if (documentUri) {
|
||||
if (internal::uri::isUriAbsolute(*documentUri)) {
|
||||
return *documentUri;
|
||||
} else {
|
||||
return internal::uri::resolveRelativeUri(
|
||||
*resolutionScope, *documentUri);
|
||||
return internal::uri::resolveRelativeUri(*resolutionScope, *documentUri);
|
||||
}
|
||||
} else {
|
||||
return *resolutionScope;
|
||||
@ -248,8 +238,7 @@ private:
|
||||
if (itr == o.end()) {
|
||||
return false;
|
||||
} else if (!itr->second.asString(result)) {
|
||||
throw std::invalid_argument(
|
||||
"$ref property expected to contain string value.");
|
||||
throw std::invalid_argument("$ref property expected to contain string value.");
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -258,7 +247,7 @@ private:
|
||||
/**
|
||||
* Sanitise an optional JSON Pointer, trimming trailing slashes
|
||||
*/
|
||||
std::string sanitiseJsonPointer(const opt::optional<std::string> input)
|
||||
static std::string sanitiseJsonPointer(const opt::optional<std::string>& input)
|
||||
{
|
||||
if (input) {
|
||||
// Trim trailing slash(es)
|
||||
@ -310,15 +299,14 @@ private:
|
||||
* usage of the schema cache during development, and is not expected
|
||||
* to occur otherwise, even for malformed schemas.
|
||||
*/
|
||||
void updateSchemaCache(SchemaCache &schemaCache,
|
||||
static void updateSchemaCache(SchemaCache &schemaCache,
|
||||
const std::vector<std::string> &keysToCreate,
|
||||
const Subschema *schema)
|
||||
{
|
||||
for (const std::string &keyToCreate : keysToCreate) {
|
||||
const SchemaCache::value_type value(keyToCreate, schema);
|
||||
if (!schemaCache.insert(value).second) {
|
||||
throw std::logic_error(
|
||||
"Key '" + keyToCreate + "' already in schema cache.");
|
||||
throw std::logic_error("Key '" + keyToCreate + "' already in schema cache.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -375,16 +363,13 @@ private:
|
||||
|
||||
// Construct a key that we can use to search the schema cache for
|
||||
// a schema corresponding to the current node
|
||||
const std::string schemaCacheKey =
|
||||
currentScope ? (*currentScope + nodePath) : nodePath;
|
||||
const std::string schemaCacheKey = currentScope ? (*currentScope + nodePath) : nodePath;
|
||||
|
||||
// Retrieve an existing schema from the cache if possible
|
||||
const Subschema *cachedPtr =
|
||||
querySchemaCache(schemaCache, schemaCacheKey);
|
||||
const Subschema *cachedPtr = querySchemaCache(schemaCache, schemaCacheKey);
|
||||
|
||||
// Create a new schema otherwise
|
||||
const Subschema *subschema = cachedPtr ? cachedPtr :
|
||||
rootSchema.createSubschema();
|
||||
const Subschema *subschema = cachedPtr ? cachedPtr : rootSchema.createSubschema();
|
||||
|
||||
// Add cache entries for keys belonging to any $ref nodes that were
|
||||
// visited before arriving at the current node
|
||||
@ -404,8 +389,7 @@ private:
|
||||
|
||||
// Returns a document URI if the reference points somewhere
|
||||
// other than the current document
|
||||
const opt::optional<std::string> documentUri =
|
||||
internal::json_reference::getJsonReferenceUri(jsonRef);
|
||||
const opt::optional<std::string> documentUri = internal::json_reference::getJsonReferenceUri(jsonRef);
|
||||
|
||||
// Extract JSON Pointer from JSON Reference, with any trailing
|
||||
// slashes removed so that keys in the schema cache end
|
||||
@ -417,12 +401,10 @@ private:
|
||||
// scope. An absolute document URI will take precedence when
|
||||
// present, otherwise we need to resolve the URI relative to
|
||||
// the current resolution scope
|
||||
const opt::optional<std::string> actualDocumentUri =
|
||||
findAbsoluteDocumentUri(currentScope, documentUri);
|
||||
const opt::optional<std::string> actualDocumentUri = findAbsoluteDocumentUri(currentScope, documentUri);
|
||||
|
||||
// Construct a key to search the schema cache for an existing schema
|
||||
const std::string queryKey = actualDocumentUri ?
|
||||
(*actualDocumentUri + actualJsonPointer) : actualJsonPointer;
|
||||
const std::string queryKey = actualDocumentUri ? (*actualDocumentUri + actualJsonPointer) : actualJsonPointer;
|
||||
|
||||
// Check for the second termination condition (found a $ref node that
|
||||
// already has an entry in the schema cache)
|
||||
@ -441,8 +423,7 @@ private:
|
||||
if (docCacheItr == docCache.end()) {
|
||||
// Resolve reference against remote document
|
||||
if (!fetchDoc) {
|
||||
throw std::runtime_error(
|
||||
"Fetching of remote JSON References not enabled.");
|
||||
throw std::runtime_error("Fetching of remote JSON References not enabled.");
|
||||
}
|
||||
|
||||
// Returns a pointer to the remote document that was
|
||||
@ -453,9 +434,7 @@ private:
|
||||
|
||||
// Can't proceed without the remote document
|
||||
if (!newDoc) {
|
||||
throw std::runtime_error(
|
||||
"Failed to fetch referenced schema document: " +
|
||||
*actualDocumentUri);
|
||||
throw std::runtime_error("Failed to fetch referenced schema document: " + *actualDocumentUri);
|
||||
}
|
||||
|
||||
typedef typename DocumentCache<AdapterType>::Type::value_type
|
||||
@ -579,7 +558,7 @@ private:
|
||||
const AdapterType &rootNode,
|
||||
const AdapterType &node,
|
||||
const Subschema &subschema,
|
||||
const opt::optional<std::string> currentScope,
|
||||
const opt::optional<std::string>& currentScope,
|
||||
const std::string &nodePath,
|
||||
const typename FunctionPtrs<AdapterType>::FetchDoc fetchDoc,
|
||||
const Subschema *parentSubschema,
|
||||
@ -593,7 +572,7 @@ private:
|
||||
"appropriate Adapter implementation");
|
||||
|
||||
if (!node.isObject()) {
|
||||
if (version == kDraft7 && node.maybeBool()) {
|
||||
if (m_version == kDraft7 && node.maybeBool()) {
|
||||
// Boolean schema
|
||||
if (!node.asBool()) {
|
||||
rootSchema.setAlwaysInvalid(&subschema, true);
|
||||
@ -603,7 +582,7 @@ private:
|
||||
std::string s;
|
||||
s += "Expected node at ";
|
||||
s += nodePath;
|
||||
if (version == kDraft7) {
|
||||
if (m_version == kDraft7) {
|
||||
s += " to contain schema object or boolean value; actual node type is: ";
|
||||
} else {
|
||||
s += " to contain schema object; actual node type is: ";
|
||||
@ -618,15 +597,13 @@ private:
|
||||
|
||||
// Check for 'id' attribute and update current scope
|
||||
opt::optional<std::string> updatedScope;
|
||||
if ((itr = object.find("id")) != object.end() &&
|
||||
itr->second.maybeString()) {
|
||||
if ((itr = object.find("id")) != object.end() && itr->second.maybeString()) {
|
||||
const std::string id = itr->second.asString();
|
||||
rootSchema.setSubschemaId(&subschema, itr->second.asString());
|
||||
if (!currentScope || internal::uri::isUriAbsolute(id)) {
|
||||
updatedScope = id;
|
||||
} else {
|
||||
updatedScope = internal::uri::resolveRelativeUri(
|
||||
*currentScope, id);
|
||||
updatedScope = internal::uri::resolveRelativeUri(*currentScope, id);
|
||||
}
|
||||
} else {
|
||||
updatedScope = currentScope;
|
||||
@ -679,7 +656,7 @@ private:
|
||||
}
|
||||
|
||||
if ((itr = object.find("divisibleBy")) != object.end()) {
|
||||
if (version == kDraft3) {
|
||||
if (m_version == kDraft3) {
|
||||
if (itr->second.maybeInteger()) {
|
||||
rootSchema.addConstraintToSubschema(
|
||||
makeMultipleOfIntConstraint(itr->second),
|
||||
@ -720,10 +697,8 @@ private:
|
||||
additionalItemsItr = object.find("additionalItems");
|
||||
rootSchema.addConstraintToSubschema(
|
||||
makeLinearItemsConstraint(rootSchema, rootNode,
|
||||
itemsItr != object.end() ?
|
||||
&itemsItr->second : nullptr,
|
||||
additionalItemsItr != object.end() ?
|
||||
&additionalItemsItr->second : nullptr,
|
||||
itemsItr != object.end() ? &itemsItr->second : nullptr,
|
||||
additionalItemsItr != object.end() ? &additionalItemsItr->second : nullptr,
|
||||
updatedScope, nodePath + "/items",
|
||||
nodePath + "/additionalItems", fetchDoc,
|
||||
docCache, schemaCache),
|
||||
@ -738,7 +713,7 @@ private:
|
||||
const typename AdapterType::Object::const_iterator elseItr = object.find("else");
|
||||
|
||||
if (object.end() != ifItr) {
|
||||
if (version == kDraft7) {
|
||||
if (m_version == kDraft7) {
|
||||
rootSchema.addConstraintToSubschema(
|
||||
makeConditionalConstraint(rootSchema, rootNode,
|
||||
ifItr->second,
|
||||
@ -752,7 +727,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
if (version == kDraft7) {
|
||||
if (m_version == kDraft7) {
|
||||
if ((itr = object.find("exclusiveMaximum")) != object.end()) {
|
||||
rootSchema.addConstraintToSubschema(
|
||||
makeMaximumConstraintExclusive(itr->second),
|
||||
@ -773,13 +748,11 @@ private:
|
||||
&subschema);
|
||||
} else {
|
||||
rootSchema.addConstraintToSubschema(
|
||||
makeMaximumConstraint(itr->second,
|
||||
&exclusiveMaximumItr->second),
|
||||
makeMaximumConstraint(itr->second, &exclusiveMaximumItr->second),
|
||||
&subschema);
|
||||
}
|
||||
} else if (object.find("exclusiveMaximum") != object.end()) {
|
||||
throw std::runtime_error(
|
||||
"'exclusiveMaximum' constraint only valid if a 'maximum' "
|
||||
throw std::runtime_error("'exclusiveMaximum' constraint only valid if a 'maximum' "
|
||||
"constraint is also present");
|
||||
}
|
||||
|
||||
@ -798,11 +771,10 @@ private:
|
||||
makeMaxPropertiesConstraint(itr->second), &subschema);
|
||||
}
|
||||
|
||||
if (version == kDraft7) {
|
||||
if (m_version == kDraft7) {
|
||||
if ((itr = object.find("exclusiveMinimum")) != object.end()) {
|
||||
rootSchema.addConstraintToSubschema(
|
||||
makeMinimumConstraintExclusive(itr->second),
|
||||
&subschema);
|
||||
makeMinimumConstraintExclusive(itr->second), &subschema);
|
||||
}
|
||||
|
||||
if ((itr = object.find("minimum")) != object.end()) {
|
||||
@ -811,22 +783,18 @@ private:
|
||||
&subschema);
|
||||
}
|
||||
} else if ((itr = object.find("minimum")) != object.end()) {
|
||||
typename AdapterType::Object::const_iterator exclusiveMinimumItr =
|
||||
object.find("exclusiveMinimum");
|
||||
typename AdapterType::Object::const_iterator exclusiveMinimumItr = object.find("exclusiveMinimum");
|
||||
if (exclusiveMinimumItr == object.end()) {
|
||||
rootSchema.addConstraintToSubschema(
|
||||
makeMinimumConstraint<AdapterType>(itr->second, nullptr),
|
||||
&subschema);
|
||||
} else {
|
||||
rootSchema.addConstraintToSubschema(
|
||||
makeMinimumConstraint<AdapterType>(
|
||||
itr->second,
|
||||
&exclusiveMinimumItr->second),
|
||||
makeMinimumConstraint<AdapterType>(itr->second, &exclusiveMinimumItr->second),
|
||||
&subschema);
|
||||
}
|
||||
} else if (object.find("exclusiveMinimum") != object.end()) {
|
||||
throw std::runtime_error(
|
||||
"'exclusiveMinimum' constraint only valid if a 'minimum' "
|
||||
throw std::runtime_error("'exclusiveMinimum' constraint only valid if a 'minimum' "
|
||||
"constraint is also present");
|
||||
}
|
||||
|
||||
@ -846,9 +814,8 @@ private:
|
||||
}
|
||||
|
||||
if ((itr = object.find("multipleOf")) != object.end()) {
|
||||
if (version == kDraft3) {
|
||||
throw std::runtime_error(
|
||||
"'multipleOf' constraint not available in draft 3");
|
||||
if (m_version == kDraft3) {
|
||||
throw std::runtime_error("'multipleOf' constraint not available in draft 3");
|
||||
} else if (itr->second.maybeInteger()) {
|
||||
rootSchema.addConstraintToSubschema(
|
||||
makeMultipleOfIntConstraint(itr->second),
|
||||
@ -858,23 +825,20 @@ private:
|
||||
makeMultipleOfDoubleConstraint(itr->second),
|
||||
&subschema);
|
||||
} else {
|
||||
throw std::runtime_error("Expected an numeric value for "
|
||||
" 'divisibleBy' constraint.");
|
||||
throw std::runtime_error("Expected an numeric value for 'divisibleBy' constraint.");
|
||||
}
|
||||
}
|
||||
|
||||
if ((itr = object.find("not")) != object.end()) {
|
||||
rootSchema.addConstraintToSubschema(
|
||||
makeNotConstraint(rootSchema, rootNode, itr->second,
|
||||
updatedScope, nodePath + "/not", fetchDoc, docCache,
|
||||
schemaCache),
|
||||
makeNotConstraint(rootSchema, rootNode, itr->second, updatedScope, nodePath + "/not", fetchDoc,
|
||||
docCache, schemaCache),
|
||||
&subschema);
|
||||
}
|
||||
|
||||
if ((itr = object.find("oneOf")) != object.end()) {
|
||||
rootSchema.addConstraintToSubschema(
|
||||
makeOneOfConstraint(rootSchema, rootNode, itr->second,
|
||||
updatedScope, nodePath + "/oneOf", fetchDoc,
|
||||
makeOneOfConstraint(rootSchema, rootNode, itr->second, updatedScope, nodePath + "/oneOf", fetchDoc,
|
||||
docCache, schemaCache),
|
||||
&subschema);
|
||||
}
|
||||
@ -896,12 +860,9 @@ private:
|
||||
object.end() != additionalPropertiesItr) {
|
||||
rootSchema.addConstraintToSubschema(
|
||||
makePropertiesConstraint(rootSchema, rootNode,
|
||||
propertiesItr != object.end() ?
|
||||
&propertiesItr->second : nullptr,
|
||||
patternPropertiesItr != object.end() ?
|
||||
&patternPropertiesItr->second : nullptr,
|
||||
additionalPropertiesItr != object.end() ?
|
||||
&additionalPropertiesItr->second : nullptr,
|
||||
propertiesItr != object.end() ? &propertiesItr->second : nullptr,
|
||||
patternPropertiesItr != object.end() ? &patternPropertiesItr->second : nullptr,
|
||||
additionalPropertiesItr != object.end() ? &additionalPropertiesItr->second : nullptr,
|
||||
updatedScope, nodePath + "/properties",
|
||||
nodePath + "/patternProperties",
|
||||
nodePath + "/additionalProperties",
|
||||
@ -911,7 +872,7 @@ private:
|
||||
}
|
||||
|
||||
if ((itr = object.find("propertyNames")) != object.end()) {
|
||||
if (version == kDraft7) {
|
||||
if (m_version == kDraft7) {
|
||||
rootSchema.addConstraintToSubschema(
|
||||
makePropertyNamesConstraint(rootSchema, rootNode, itr->second, updatedScope,
|
||||
nodePath, fetchDoc, docCache, schemaCache),
|
||||
@ -922,60 +883,49 @@ private:
|
||||
}
|
||||
|
||||
if ((itr = object.find("required")) != object.end()) {
|
||||
if (version == kDraft3) {
|
||||
if (m_version == kDraft3) {
|
||||
if (parentSubschema && ownName) {
|
||||
opt::optional<constraints::RequiredConstraint>
|
||||
constraint = makeRequiredConstraintForSelf(
|
||||
itr->second, *ownName);
|
||||
opt::optional<constraints::RequiredConstraint> constraint =
|
||||
makeRequiredConstraintForSelf(itr->second, *ownName);
|
||||
if (constraint) {
|
||||
rootSchema.addConstraintToSubschema(*constraint,
|
||||
parentSubschema);
|
||||
rootSchema.addConstraintToSubschema(*constraint, parentSubschema);
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"'required' constraint not valid here");
|
||||
throw std::runtime_error("'required' constraint not valid here");
|
||||
}
|
||||
} else {
|
||||
rootSchema.addConstraintToSubschema(
|
||||
makeRequiredConstraint(itr->second), &subschema);
|
||||
rootSchema.addConstraintToSubschema(makeRequiredConstraint(itr->second), &subschema);
|
||||
}
|
||||
}
|
||||
|
||||
if ((itr = object.find("title")) != object.end()) {
|
||||
if (itr->second.maybeString()) {
|
||||
rootSchema.setSubschemaTitle(&subschema,
|
||||
itr->second.asString());
|
||||
rootSchema.setSubschemaTitle(&subschema, itr->second.asString());
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"'title' attribute should have a string value");
|
||||
throw std::runtime_error("'title' attribute should have a string value");
|
||||
}
|
||||
}
|
||||
|
||||
if ((itr = object.find("type")) != object.end()) {
|
||||
rootSchema.addConstraintToSubschema(
|
||||
makeTypeConstraint(rootSchema, rootNode, itr->second,
|
||||
updatedScope, nodePath + "/type", fetchDoc,
|
||||
makeTypeConstraint(rootSchema, rootNode, itr->second, updatedScope, nodePath + "/type", fetchDoc,
|
||||
docCache, schemaCache),
|
||||
&subschema);
|
||||
}
|
||||
|
||||
if ((itr = object.find("uniqueItems")) != object.end()) {
|
||||
opt::optional<constraints::UniqueItemsConstraint> constraint =
|
||||
makeUniqueItemsConstraint(itr->second);
|
||||
opt::optional<constraints::UniqueItemsConstraint> constraint = makeUniqueItemsConstraint(itr->second);
|
||||
if (constraint) {
|
||||
rootSchema.addConstraintToSubschema(*constraint, &subschema);
|
||||
}
|
||||
}
|
||||
|
||||
for (ConstraintBuilders::const_iterator
|
||||
builderItr = constraintBuilders.begin();
|
||||
builderItr != constraintBuilders.end(); ++builderItr) {
|
||||
if ((itr = object.find(builderItr->first)) != object.end()) {
|
||||
for (const auto & constraintBuilder : constraintBuilders) {
|
||||
if ((itr = object.find(constraintBuilder.first)) != object.end()) {
|
||||
constraints::Constraint *constraint = nullptr;
|
||||
try {
|
||||
constraint = builderItr->second->make(itr->second);
|
||||
rootSchema.addConstraintToSubschema(*constraint,
|
||||
&subschema);
|
||||
constraint = constraintBuilder.second->make(itr->second);
|
||||
rootSchema.addConstraintToSubschema(*constraint, &subschema);
|
||||
delete constraint;
|
||||
} catch (...) {
|
||||
delete constraint;
|
||||
@ -1026,16 +976,14 @@ private:
|
||||
{
|
||||
std::string jsonRef;
|
||||
if (!extractJsonReference(node, jsonRef)) {
|
||||
populateSchema(rootSchema, rootNode, node, subschema, currentScope,
|
||||
nodePath, fetchDoc, parentSchema, ownName, docCache,
|
||||
schemaCache);
|
||||
populateSchema(rootSchema, rootNode, node, subschema, currentScope, nodePath, fetchDoc, parentSchema,
|
||||
ownName, docCache, schemaCache);
|
||||
return;
|
||||
}
|
||||
|
||||
// Returns a document URI if the reference points somewhere
|
||||
// other than the current document
|
||||
const opt::optional<std::string> documentUri =
|
||||
internal::json_reference::getJsonReferenceUri(jsonRef);
|
||||
const opt::optional<std::string> documentUri = internal::json_reference::getJsonReferenceUri(jsonRef);
|
||||
|
||||
// Extract JSON Pointer from JSON Reference
|
||||
const std::string actualJsonPointer = sanitiseJsonPointer(
|
||||
@ -1044,48 +992,37 @@ private:
|
||||
if (documentUri && internal::uri::isUriAbsolute(*documentUri)) {
|
||||
// Resolve reference against remote document
|
||||
if (!fetchDoc) {
|
||||
throw std::runtime_error(
|
||||
"Fetching of remote JSON References not enabled.");
|
||||
throw std::runtime_error("Fetching of remote JSON References not enabled.");
|
||||
}
|
||||
|
||||
const typename DocumentCache<AdapterType>::DocumentType *newDoc =
|
||||
fetchDoc(*documentUri);
|
||||
const typename DocumentCache<AdapterType>::DocumentType *newDoc = fetchDoc(*documentUri);
|
||||
|
||||
// Can't proceed without the remote document
|
||||
if (!newDoc) {
|
||||
throw std::runtime_error(
|
||||
"Failed to fetch referenced schema document: " +
|
||||
*documentUri);
|
||||
throw std::runtime_error("Failed to fetch referenced schema document: " + *documentUri);
|
||||
}
|
||||
|
||||
// Add to document cache
|
||||
typedef typename DocumentCache<AdapterType>::Type::value_type
|
||||
DocCacheValueType;
|
||||
typedef typename DocumentCache<AdapterType>::Type::value_type DocCacheValueType;
|
||||
|
||||
docCache.insert(DocCacheValueType(*documentUri, newDoc));
|
||||
|
||||
const AdapterType newRootNode(*newDoc);
|
||||
|
||||
const AdapterType &referencedAdapter =
|
||||
internal::json_pointer::resolveJsonPointer(
|
||||
newRootNode, actualJsonPointer);
|
||||
internal::json_pointer::resolveJsonPointer(newRootNode, actualJsonPointer);
|
||||
|
||||
// TODO: Need to detect degenerate circular references
|
||||
resolveThenPopulateSchema(rootSchema, newRootNode,
|
||||
referencedAdapter, subschema, opt::optional<std::string>(),
|
||||
actualJsonPointer, fetchDoc, parentSchema, ownName,
|
||||
docCache, schemaCache);
|
||||
resolveThenPopulateSchema(rootSchema, newRootNode, referencedAdapter, subschema, {}, actualJsonPointer,
|
||||
fetchDoc, parentSchema, ownName, docCache, schemaCache);
|
||||
|
||||
} else {
|
||||
const AdapterType &referencedAdapter =
|
||||
internal::json_pointer::resolveJsonPointer(
|
||||
rootNode, actualJsonPointer);
|
||||
internal::json_pointer::resolveJsonPointer(rootNode, actualJsonPointer);
|
||||
|
||||
// TODO: Need to detect degenerate circular references
|
||||
resolveThenPopulateSchema(rootSchema, rootNode, referencedAdapter,
|
||||
subschema, opt::optional<std::string>(),
|
||||
actualJsonPointer, fetchDoc,
|
||||
parentSchema, ownName, docCache, schemaCache);
|
||||
resolveThenPopulateSchema(rootSchema, rootNode, referencedAdapter, subschema, {}, actualJsonPointer,
|
||||
fetchDoc, parentSchema, ownName, docCache, schemaCache);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1119,15 +1056,14 @@ private:
|
||||
SchemaCache &schemaCache)
|
||||
{
|
||||
if (!node.maybeArray()) {
|
||||
throw std::runtime_error(
|
||||
"Expected array value for 'allOf' constraint.");
|
||||
throw std::runtime_error("Expected array value for 'allOf' constraint.");
|
||||
}
|
||||
|
||||
constraints::AllOfConstraint constraint;
|
||||
|
||||
int index = 0;
|
||||
for (const AdapterType schemaNode : node.asArray()) {
|
||||
if (schemaNode.maybeObject() || (version == kDraft7 && schemaNode.isBool())) {
|
||||
if (schemaNode.maybeObject() || (m_version == kDraft7 && schemaNode.isBool())) {
|
||||
const std::string childPath = nodePath + "/" + std::to_string(index);
|
||||
const Subschema *subschema = makeOrReuseSchema<AdapterType>(
|
||||
rootSchema, rootNode, schemaNode, currentScope,
|
||||
@ -1135,8 +1071,7 @@ private:
|
||||
constraint.addSubschema(subschema);
|
||||
index++;
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"Expected element to be a valid schema in 'allOf' constraint.");
|
||||
throw std::runtime_error("Expected element to be a valid schema in 'allOf' constraint.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1173,15 +1108,14 @@ private:
|
||||
SchemaCache &schemaCache)
|
||||
{
|
||||
if (!node.maybeArray()) {
|
||||
throw std::runtime_error(
|
||||
"Expected array value for 'anyOf' constraint.");
|
||||
throw std::runtime_error("Expected array value for 'anyOf' constraint.");
|
||||
}
|
||||
|
||||
constraints::AnyOfConstraint constraint;
|
||||
|
||||
int index = 0;
|
||||
for (const AdapterType schemaNode : node.asArray()) {
|
||||
if (schemaNode.maybeObject() || (version == kDraft7 && schemaNode.isBool())) {
|
||||
if (schemaNode.maybeObject() || (m_version == kDraft7 && schemaNode.isBool())) {
|
||||
const std::string childPath = nodePath + "/" + std::to_string(index);
|
||||
const Subschema *subschema = makeOrReuseSchema<AdapterType>(
|
||||
rootSchema, rootNode, schemaNode, currentScope,
|
||||
@ -1189,8 +1123,7 @@ private:
|
||||
constraint.addSubschema(subschema);
|
||||
index++;
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"Expected array element to be a valid schema in 'anyOf' constraint.");
|
||||
throw std::runtime_error("Expected array element to be a valid schema in 'anyOf' constraint.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1316,7 +1249,7 @@ private:
|
||||
{
|
||||
constraints::ContainsConstraint constraint;
|
||||
|
||||
if (contains.isObject() || (version == kDraft7 && contains.maybeBool())) {
|
||||
if (contains.isObject() || (m_version == kDraft7 && contains.maybeBool())) {
|
||||
const Subschema *subschema = makeOrReuseSchema<AdapterType>(
|
||||
rootSchema, rootNode, contains, currentScope, containsPath,
|
||||
fetchDoc, nullptr, nullptr, docCache, schemaCache);
|
||||
@ -1329,8 +1262,7 @@ private:
|
||||
|
||||
} else {
|
||||
// All other formats will result in an exception being thrown.
|
||||
throw std::runtime_error(
|
||||
"Expected valid schema for 'contains' constraint.");
|
||||
throw std::runtime_error("Expected valid schema for 'contains' constraint.");
|
||||
}
|
||||
|
||||
return constraint;
|
||||
@ -1420,7 +1352,7 @@ private:
|
||||
// exercised the flexibility by loosely-typed Adapter types. If the
|
||||
// value of the dependency mapping is an object, then we'll try to
|
||||
// process it as a dependent schema.
|
||||
} else if (member.second.isObject() || (version == kDraft7 && member.second.maybeBool())) {
|
||||
} else if (member.second.isObject() || (m_version == kDraft7 && member.second.maybeBool())) {
|
||||
// Parse dependent subschema
|
||||
const Subschema *childSubschema =
|
||||
makeOrReuseSchema<AdapterType>(rootSchema, rootNode,
|
||||
@ -1432,7 +1364,7 @@ private:
|
||||
// If we're supposed to be parsing a Draft3 schema, then the value
|
||||
// of the dependency mapping can also be a string containing the
|
||||
// name of a single dependency.
|
||||
} else if (version == kDraft3 && member.second.isString()) {
|
||||
} else if (m_version == kDraft3 && member.second.isString()) {
|
||||
dependenciesConstraint.addPropertyDependency(member.first,
|
||||
member.second.getString());
|
||||
|
||||
@ -1522,8 +1454,7 @@ private:
|
||||
// and is set to true, then additional array items do not need
|
||||
// to satisfy any constraints.
|
||||
if (additionalItems->asBool()) {
|
||||
constraint.setAdditionalItemsSubschema(
|
||||
rootSchema.emptySubschema());
|
||||
constraint.setAdditionalItemsSubschema(rootSchema.emptySubschema());
|
||||
}
|
||||
} else if (additionalItems->maybeObject()) {
|
||||
// If the value of the additionalItems property is an object,
|
||||
@ -1537,8 +1468,7 @@ private:
|
||||
} else {
|
||||
// Any other format for the additionalItems property will result
|
||||
// in an exception being thrown.
|
||||
throw std::runtime_error(
|
||||
"Expected bool or object value for 'additionalItems'");
|
||||
throw std::runtime_error("Expected bool or object value for 'additionalItems'");
|
||||
}
|
||||
} else {
|
||||
// The default value for the additionalItems property is an empty
|
||||
@ -1567,9 +1497,7 @@ private:
|
||||
index++;
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"Expected array value for non-singular 'items' "
|
||||
"constraint.");
|
||||
throw std::runtime_error("Expected array value for non-singular 'items' constraint.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1622,7 +1550,7 @@ private:
|
||||
// array is provided, or a single Schema object, in an object value is
|
||||
// provided. If the items constraint is not provided, then array items
|
||||
// will be validated against the additionalItems schema.
|
||||
if (items.isObject() || (version == kDraft7 && items.maybeBool())) {
|
||||
if (items.isObject() || (m_version == kDraft7 && items.maybeBool())) {
|
||||
// If the items constraint contains an object value, then it
|
||||
// should contain a Schema that will be used to validate all
|
||||
// items in a target array. Any schema defined by the
|
||||
@ -1639,8 +1567,7 @@ private:
|
||||
|
||||
} else {
|
||||
// All other formats will result in an exception being thrown.
|
||||
throw std::runtime_error(
|
||||
"Expected valid schema for singular 'items' constraint.");
|
||||
throw std::runtime_error("Expected valid schema for singular 'items' constraint.");
|
||||
}
|
||||
|
||||
return constraint;
|
||||
@ -1669,8 +1596,7 @@ private:
|
||||
const AdapterType *exclusiveMaximum)
|
||||
{
|
||||
if (!node.maybeDouble()) {
|
||||
throw std::runtime_error(
|
||||
"Expected numeric value for maximum constraint.");
|
||||
throw std::runtime_error("Expected numeric value for maximum constraint.");
|
||||
}
|
||||
|
||||
constraints::MaximumConstraint constraint;
|
||||
@ -1678,9 +1604,7 @@ private:
|
||||
|
||||
if (exclusiveMaximum) {
|
||||
if (!exclusiveMaximum->maybeBool()) {
|
||||
throw std::runtime_error(
|
||||
"Expected boolean value for exclusiveMaximum "
|
||||
"constraint.");
|
||||
throw std::runtime_error("Expected boolean value for exclusiveMaximum constraint.");
|
||||
}
|
||||
|
||||
constraint.setExclusiveMaximum(exclusiveMaximum->asBool());
|
||||
@ -1733,9 +1657,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error(
|
||||
"Expected non-negative integer value for 'maxItems' "
|
||||
"constraint.");
|
||||
throw std::runtime_error("Expected non-negative integer value for 'maxItems' constraint.");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1759,9 +1681,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error(
|
||||
"Expected a non-negative integer value for 'maxLength' "
|
||||
"constraint.");
|
||||
throw std::runtime_error("Expected a non-negative integer value for 'maxLength' constraint.");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1787,9 +1707,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error(
|
||||
"Expected a non-negative integer for 'maxProperties' "
|
||||
"constraint.");
|
||||
throw std::runtime_error("Expected a non-negative integer for 'maxProperties' constraint.");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1810,8 +1728,7 @@ private:
|
||||
const AdapterType *exclusiveMinimum)
|
||||
{
|
||||
if (!node.maybeDouble()) {
|
||||
throw std::runtime_error(
|
||||
"Expected numeric value for minimum constraint.");
|
||||
throw std::runtime_error("Expected numeric value for minimum constraint.");
|
||||
}
|
||||
|
||||
constraints::MinimumConstraint constraint;
|
||||
@ -1819,9 +1736,7 @@ private:
|
||||
|
||||
if (exclusiveMinimum) {
|
||||
if (!exclusiveMinimum->maybeBool()) {
|
||||
throw std::runtime_error(
|
||||
"Expected boolean value for 'exclusiveMinimum' "
|
||||
"constraint.");
|
||||
throw std::runtime_error("Expected boolean value for 'exclusiveMinimum' constraint.");
|
||||
}
|
||||
|
||||
constraint.setExclusiveMinimum(exclusiveMinimum->asBool());
|
||||
@ -1862,8 +1777,7 @@ private:
|
||||
* @return pointer to a new MinItemsConstraint that belongs to the caller
|
||||
*/
|
||||
template<typename AdapterType>
|
||||
constraints::MinItemsConstraint makeMinItemsConstraint(
|
||||
const AdapterType &node)
|
||||
constraints::MinItemsConstraint makeMinItemsConstraint(const AdapterType &node)
|
||||
{
|
||||
if (node.maybeInteger()) {
|
||||
const int64_t value = node.asInteger();
|
||||
@ -1874,9 +1788,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error(
|
||||
"Expected a non-negative integer value for 'minItems' "
|
||||
"constraint.");
|
||||
throw std::runtime_error("Expected a non-negative integer value for 'minItems' constraint.");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1888,8 +1800,7 @@ private:
|
||||
* @return pointer to a new MinLengthConstraint that belongs to the caller
|
||||
*/
|
||||
template<typename AdapterType>
|
||||
constraints::MinLengthConstraint makeMinLengthConstraint(
|
||||
const AdapterType &node)
|
||||
constraints::MinLengthConstraint makeMinLengthConstraint(const AdapterType &node)
|
||||
{
|
||||
if (node.maybeInteger()) {
|
||||
const int64_t value = node.asInteger();
|
||||
@ -1900,9 +1811,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error(
|
||||
"Expected a non-negative integer value for 'minLength' "
|
||||
"constraint.");
|
||||
throw std::runtime_error("Expected a non-negative integer value for 'minLength' constraint.");
|
||||
}
|
||||
|
||||
|
||||
@ -1917,8 +1826,7 @@ private:
|
||||
* caller
|
||||
*/
|
||||
template<typename AdapterType>
|
||||
constraints::MinPropertiesConstraint makeMinPropertiesConstraint(
|
||||
const AdapterType &node)
|
||||
constraints::MinPropertiesConstraint makeMinPropertiesConstraint(const AdapterType &node)
|
||||
{
|
||||
if (node.maybeInteger()) {
|
||||
int64_t value = node.asInteger();
|
||||
@ -1929,9 +1837,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error(
|
||||
"Expected a non-negative integer for 'minProperties' "
|
||||
"constraint.");
|
||||
throw std::runtime_error("Expected a non-negative integer for 'minProperties' constraint.");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1943,8 +1849,7 @@ private:
|
||||
* @return a MultipleOfConstraint
|
||||
*/
|
||||
template<typename AdapterType>
|
||||
constraints::MultipleOfDoubleConstraint makeMultipleOfDoubleConstraint(
|
||||
const AdapterType &node)
|
||||
constraints::MultipleOfDoubleConstraint makeMultipleOfDoubleConstraint(const AdapterType &node)
|
||||
{
|
||||
constraints::MultipleOfDoubleConstraint constraint;
|
||||
constraint.setDivisor(node.asDouble());
|
||||
@ -1960,8 +1865,7 @@ private:
|
||||
* @return a MultipleOfIntConstraint
|
||||
*/
|
||||
template<typename AdapterType>
|
||||
constraints::MultipleOfIntConstraint makeMultipleOfIntConstraint(
|
||||
const AdapterType &node)
|
||||
constraints::MultipleOfIntConstraint makeMultipleOfIntConstraint(const AdapterType &node)
|
||||
{
|
||||
constraints::MultipleOfIntConstraint constraint;
|
||||
constraint.setDivisor(node.asInteger());
|
||||
@ -1996,7 +1900,7 @@ private:
|
||||
typename DocumentCache<AdapterType>::Type &docCache,
|
||||
SchemaCache &schemaCache)
|
||||
{
|
||||
if (node.maybeObject() || (version == kDraft7 && node.maybeBool())) {
|
||||
if (node.maybeObject() || (m_version == kDraft7 && node.maybeBool())) {
|
||||
const Subschema *subschema = makeOrReuseSchema<AdapterType>(
|
||||
rootSchema, rootNode, node, currentScope, nodePath,
|
||||
fetchDoc, nullptr, nullptr, docCache, schemaCache);
|
||||
@ -2040,8 +1944,7 @@ private:
|
||||
|
||||
int index = 0;
|
||||
for (const AdapterType schemaNode : node.getArray()) {
|
||||
const std::string childPath = nodePath + "/" +
|
||||
std::to_string(index);
|
||||
const std::string childPath = nodePath + "/" + std::to_string(index);
|
||||
const Subschema *subschema = makeOrReuseSchema<AdapterType>(
|
||||
rootSchema, rootNode, schemaNode, currentScope, childPath,
|
||||
fetchDoc, nullptr, nullptr, docCache, schemaCache);
|
||||
@ -2166,8 +2069,7 @@ private:
|
||||
// If it has a boolean value that is 'true', then an empty
|
||||
// schema should be used.
|
||||
if (additionalProperties->asBool()) {
|
||||
constraint.setAdditionalPropertiesSubschema(
|
||||
rootSchema.emptySubschema());
|
||||
constraint.setAdditionalPropertiesSubschema(rootSchema.emptySubschema());
|
||||
}
|
||||
} else if (additionalProperties->isObject()) {
|
||||
// If additionalProperties is an object, it should be used as
|
||||
@ -2179,14 +2081,12 @@ private:
|
||||
constraint.setAdditionalPropertiesSubschema(subschema);
|
||||
} else {
|
||||
// All other types are invalid
|
||||
throw std::runtime_error(
|
||||
"Invalid type for 'additionalProperties' constraint.");
|
||||
throw std::runtime_error("Invalid type for 'additionalProperties' constraint.");
|
||||
}
|
||||
} else {
|
||||
// If an additionalProperties constraint is not provided, then the
|
||||
// default value is an empty schema.
|
||||
constraint.setAdditionalPropertiesSubschema(
|
||||
rootSchema.emptySubschema());
|
||||
constraint.setAdditionalPropertiesSubschema(rootSchema.emptySubschema());
|
||||
}
|
||||
|
||||
return constraint;
|
||||
@ -2203,10 +2103,8 @@ private:
|
||||
typename DocumentCache<AdapterType>::Type &docCache,
|
||||
SchemaCache &schemaCache)
|
||||
{
|
||||
const Subschema *subschema = makeOrReuseSchema<AdapterType>(rootSchema, rootNode,
|
||||
currentNode, currentScope, nodePath, fetchDoc, nullptr, nullptr, docCache,
|
||||
schemaCache);
|
||||
|
||||
const Subschema *subschema = makeOrReuseSchema<AdapterType>(rootSchema, rootNode, currentNode, currentScope,
|
||||
nodePath, fetchDoc, nullptr, nullptr, docCache, schemaCache);
|
||||
constraints::PropertyNamesConstraint constraint;
|
||||
constraint.setSubschema(subschema);
|
||||
return constraint;
|
||||
@ -2261,8 +2159,7 @@ private:
|
||||
|
||||
for (const AdapterType v : node.getArray()) {
|
||||
if (!v.maybeString()) {
|
||||
throw std::runtime_error("Expected required property name to "
|
||||
"be a string value");
|
||||
throw std::runtime_error("Expected required property name to be a string value");
|
||||
}
|
||||
|
||||
constraint.addRequiredProperty(v.getString());
|
||||
@ -2305,9 +2202,8 @@ private:
|
||||
|
||||
if (node.maybeString()) {
|
||||
const TypeConstraint::JsonType type = TypeConstraint::jsonTypeFromString(node.getString());
|
||||
if (type == TypeConstraint::kAny && version == kDraft4) {
|
||||
throw std::runtime_error(
|
||||
"'any' type is not supported in version 4 schemas.");
|
||||
if (type == TypeConstraint::kAny && m_version == kDraft4) {
|
||||
throw std::runtime_error("'any' type is not supported in version 4 schemas.");
|
||||
}
|
||||
|
||||
constraint.addNamedType(type);
|
||||
@ -2316,22 +2212,17 @@ private:
|
||||
int index = 0;
|
||||
for (const AdapterType v : node.getArray()) {
|
||||
if (v.maybeString()) {
|
||||
const TypeConstraint::JsonType type =
|
||||
TypeConstraint::jsonTypeFromString(v.getString());
|
||||
|
||||
if (type == TypeConstraint::kAny && version == kDraft4) {
|
||||
throw std::runtime_error(
|
||||
"'any' type is not supported in version 4 "
|
||||
"schemas.");
|
||||
const TypeConstraint::JsonType type = TypeConstraint::jsonTypeFromString(v.getString());
|
||||
if (type == TypeConstraint::kAny && m_version == kDraft4) {
|
||||
throw std::runtime_error("'any' type is not supported in version 4 schemas.");
|
||||
}
|
||||
|
||||
constraint.addNamedType(type);
|
||||
|
||||
} else if (v.maybeObject() && version == kDraft3) {
|
||||
} else if (v.maybeObject() && m_version == kDraft3) {
|
||||
const std::string childPath = nodePath + "/" + std::to_string(index);
|
||||
const Subschema *subschema = makeOrReuseSchema<AdapterType>(
|
||||
rootSchema, rootNode, v, currentScope, childPath,
|
||||
fetchDoc, nullptr, nullptr, docCache, schemaCache);
|
||||
const Subschema *subschema = makeOrReuseSchema<AdapterType>(rootSchema, rootNode, v, currentScope,
|
||||
childPath, fetchDoc, nullptr, nullptr, docCache, schemaCache);
|
||||
constraint.addSchemaType(subschema);
|
||||
|
||||
} else {
|
||||
@ -2341,10 +2232,9 @@ private:
|
||||
index++;
|
||||
}
|
||||
|
||||
} else if (node.maybeObject() && version == kDraft3) {
|
||||
const Subschema *subschema = makeOrReuseSchema<AdapterType>(
|
||||
rootSchema, rootNode, node, currentScope, nodePath,
|
||||
fetchDoc, nullptr, nullptr, docCache, schemaCache);
|
||||
} else if (node.maybeObject() && m_version == kDraft3) {
|
||||
const Subschema *subschema = makeOrReuseSchema<AdapterType>(rootSchema, rootNode, node, currentScope,
|
||||
nodePath, fetchDoc, nullptr, nullptr, docCache, schemaCache);
|
||||
constraint.addSchemaType(subschema);
|
||||
|
||||
} else {
|
||||
@ -2376,10 +2266,13 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error(
|
||||
"Expected boolean value for 'uniqueItems' constraint.");
|
||||
throw std::runtime_error("Expected boolean value for 'uniqueItems' constraint.");
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// Version of JSON Schema that should be expected when parsing
|
||||
const Version m_version;
|
||||
};
|
||||
|
||||
} // namespace valijson
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace valijson {
|
||||
@ -25,21 +26,6 @@ public:
|
||||
*/
|
||||
struct Error
|
||||
{
|
||||
/**
|
||||
* @brief Construct an Error object with no context or description.
|
||||
*/
|
||||
Error() { }
|
||||
|
||||
/**
|
||||
* @brief Construct an Error object using a context and description.
|
||||
*
|
||||
* @param context Context string to use
|
||||
* @param description Description string to use
|
||||
*/
|
||||
Error(const std::vector<std::string> &context, const std::string &description)
|
||||
: context(context),
|
||||
description(description) { }
|
||||
|
||||
/// Path to the node that failed validation.
|
||||
std::vector<std::string> context;
|
||||
|
||||
@ -52,7 +38,7 @@ public:
|
||||
*/
|
||||
std::deque<Error>::const_iterator begin() const
|
||||
{
|
||||
return errors.begin();
|
||||
return m_errors.begin();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,7 +46,7 @@ public:
|
||||
*/
|
||||
std::deque<Error>::const_iterator end() const
|
||||
{
|
||||
return errors.end();
|
||||
return m_errors.end();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,7 +54,7 @@ public:
|
||||
*/
|
||||
size_t numErrors() const
|
||||
{
|
||||
return errors.size();
|
||||
return m_errors.size();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,7 +64,7 @@ public:
|
||||
*/
|
||||
void pushError(const Error &error)
|
||||
{
|
||||
errors.push_back(error);
|
||||
m_errors.push_back(error);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,7 +76,7 @@ public:
|
||||
void
|
||||
pushError(const std::vector<std::string> &context, const std::string &description)
|
||||
{
|
||||
errors.push_back(Error(context, description));
|
||||
m_errors.push_back({context, description});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,20 +89,19 @@ public:
|
||||
bool
|
||||
popError(Error &error)
|
||||
{
|
||||
if (errors.empty()) {
|
||||
if (m_errors.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
error = errors.front();
|
||||
errors.pop_front();
|
||||
error = m_errors.front();
|
||||
m_errors.pop_front();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// FIFO queue of validation errors that have been reported
|
||||
std::deque<Error> errors;
|
||||
|
||||
std::deque<Error> m_errors;
|
||||
};
|
||||
|
||||
} // namespace valijson
|
||||
|
Loading…
x
Reference in New Issue
Block a user