Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revise JSON Schema public interface namespaces #1501

Merged
merged 1 commit into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion src/core/jsonschema/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ include(./official_resolver.cmake)
sourcemeta_library(NAMESPACE sourcemeta PROJECT core NAME jsonschema
FOLDER "Core/JSON Schema"
PRIVATE_HEADERS bundle.h resolver.h
walker.h reference.h frame.h error.h unevaluated.h
walker.h frame.h error.h unevaluated.h
keywords.h transform.h
SOURCES jsonschema.cc default_walker.cc frame.cc
resolver.cc walker.cc bundle.cc
Expand Down
4 changes: 2 additions & 2 deletions src/core/jsonschema/bundle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ auto is_official_metaschema_reference(const sourcemeta::core::Pointer &pointer,

auto bundle_schema(sourcemeta::core::JSON &root, const std::string &container,
const sourcemeta::core::JSON &subschema,
sourcemeta::core::Frame &frame,
sourcemeta::core::SchemaFrame &frame,
const sourcemeta::core::SchemaWalker &walker,
const sourcemeta::core::SchemaResolver &resolver,
const std::optional<std::string> &default_dialect) -> void {
Expand Down Expand Up @@ -137,7 +137,7 @@ auto bundle(sourcemeta::core::JSON &schema, const SchemaWalker &walker,
const std::optional<std::string> &default_dialect) -> void {
const auto vocabularies{
sourcemeta::core::vocabularies(schema, resolver, default_dialect)};
sourcemeta::core::Frame frame;
sourcemeta::core::SchemaFrame frame;
bundle_schema(schema, definitions_keyword(vocabularies), schema, frame,
walker, resolver, default_dialect);
}
Expand Down
18 changes: 12 additions & 6 deletions src/core/jsonschema/default_walker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ auto sourcemeta::core::default_schema_walker(
-> sourcemeta::core::SchemaWalkerResult {
#define WALK(vocabulary, _keyword, strategy, ...) \
if (vocabularies.contains(vocabulary) && keyword == _keyword) \
return {sourcemeta::core::KeywordType::strategy, vocabulary, {__VA_ARGS__}};
return {sourcemeta::core::SchemaKeywordType::strategy, \
vocabulary, \
{__VA_ARGS__}};

#define WALK_ANY(vocabulary_1, vocabulary_2, _keyword, strategy, ...) \
WALK(vocabulary_1, _keyword, strategy, __VA_ARGS__) \
Expand Down Expand Up @@ -306,7 +308,8 @@ auto sourcemeta::core::default_schema_walker(
if ((vocabularies.contains(HTTP_BASE "draft-07/schema#") ||
vocabularies.contains(HTTP_BASE "draft-07/hyper-schema#")) &&
keyword != "$ref") {
return {sourcemeta::core::KeywordType::Unknown, std::nullopt, {"$ref"}};
return {
sourcemeta::core::SchemaKeywordType::Unknown, std::nullopt, {"$ref"}};
}

// Draft6
Expand Down Expand Up @@ -410,7 +413,8 @@ auto sourcemeta::core::default_schema_walker(
if ((vocabularies.contains(HTTP_BASE "draft-06/schema#") ||
vocabularies.contains(HTTP_BASE "draft-06/hyper-schema#")) &&
keyword != "$ref") {
return {sourcemeta::core::KeywordType::Unknown, std::nullopt, {"$ref"}};
return {
sourcemeta::core::SchemaKeywordType::Unknown, std::nullopt, {"$ref"}};
}

// Draft4
Expand Down Expand Up @@ -494,7 +498,8 @@ auto sourcemeta::core::default_schema_walker(
if ((vocabularies.contains(HTTP_BASE "draft-04/schema#") ||
vocabularies.contains(HTTP_BASE "draft-04/hyper-schema#")) &&
keyword != "$ref") {
return {sourcemeta::core::KeywordType::Unknown, std::nullopt, {"$ref"}};
return {
sourcemeta::core::SchemaKeywordType::Unknown, std::nullopt, {"$ref"}};
}

// Draft3
Expand Down Expand Up @@ -538,7 +543,8 @@ auto sourcemeta::core::default_schema_walker(
// $ref also takes precedence over any unknown keyword
if (vocabularies.contains(HTTP_BASE "draft-03/schema#") &&
keyword != "$ref") {
return {sourcemeta::core::KeywordType::Unknown, std::nullopt, {"$ref"}};
return {
sourcemeta::core::SchemaKeywordType::Unknown, std::nullopt, {"$ref"}};
}

// Draft2
Expand Down Expand Up @@ -662,5 +668,5 @@ auto sourcemeta::core::default_schema_walker(
#undef WALK
#undef WALK_ANY
#undef WALK_MAYBE_DEPENDENT
return {sourcemeta::core::KeywordType::Unknown, std::nullopt, {}};
return {sourcemeta::core::SchemaKeywordType::Unknown, std::nullopt, {}};
}
202 changes: 108 additions & 94 deletions src/core/jsonschema/frame.cc

Large diffs are not rendered by default.

13 changes: 6 additions & 7 deletions src/core/jsonschema/include/sourcemeta/core/jsonschema.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include <sourcemeta/core/jsonschema_error.h>
#include <sourcemeta/core/jsonschema_frame.h>
#include <sourcemeta/core/jsonschema_keywords.h>
#include <sourcemeta/core/jsonschema_reference.h>
#include <sourcemeta/core/jsonschema_resolver.h>
#include <sourcemeta/core/jsonschema_transform.h>
#include <sourcemeta/core/jsonschema_unevaluated.h>
Expand Down Expand Up @@ -49,7 +48,7 @@ auto is_schema(const JSON &schema) -> bool;

/// @ingroup jsonschema
/// The strategy to follow when attempting to identify a schema
enum class IdentificationStrategy : std::uint8_t {
enum class SchemaIdentificationStrategy : std::uint8_t {
/// Only proceed if we can guarantee the identifier is valid
Strict,

Expand Down Expand Up @@ -83,11 +82,11 @@ enum class IdentificationStrategy : std::uint8_t {
/// guessing game. Often useful if you have a schema without a dialect and you
/// want to at least try to get something.
SOURCEMETA_CORE_JSONSCHEMA_EXPORT
auto identify(
const JSON &schema, const SchemaResolver &resolver,
const IdentificationStrategy strategy = IdentificationStrategy::Strict,
const std::optional<std::string> &default_dialect = std::nullopt,
const std::optional<std::string> &default_id = std::nullopt)
auto identify(const JSON &schema, const SchemaResolver &resolver,
const SchemaIdentificationStrategy strategy =
SchemaIdentificationStrategy::Strict,
const std::optional<std::string> &default_dialect = std::nullopt,
const std::optional<std::string> &default_id = std::nullopt)
-> std::optional<std::string>;

/// @ingroup jsonschema
Expand Down
48 changes: 24 additions & 24 deletions src/core/jsonschema/include/sourcemeta/core/jsonschema_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#endif

#include <sourcemeta/core/jsonpointer.h>
#include <sourcemeta/core/jsonschema_reference.h>
#include <sourcemeta/core/jsonschema_keywords.h>
#include <sourcemeta/core/jsonschema_resolver.h>
#include <sourcemeta/core/jsonschema_walker.h>

Expand Down Expand Up @@ -44,59 +44,59 @@ namespace sourcemeta::core {
/// }
/// })JSON");
///
/// sourcemeta::core::Frame frame;
/// sourcemeta::core::SchemaSchemaFrame frame;
/// frame.analyse(document,
/// sourcemeta::core::default_schema_walker,
/// sourcemeta::core::official_resolver);
///
/// // IDs
/// assert(frame.locations().contains({sourcemeta::core::ReferenceType::Static,
/// assert(frame.locations().contains({sourcemeta::core::SchemaReferenceType::Static,
/// "https://www.example.com/schema"}));
/// assert(frame.locations().contains({sourcemeta::core::ReferenceType::Static,
/// assert(frame.locations().contains({sourcemeta::core::SchemaReferenceType::Static,
/// "https://www.example.com/foo"}));
///
/// // Anchors
/// assert(frame.locations().contains({sourcemeta::core::ReferenceType::Static,
/// assert(frame.locations().contains({sourcemeta::core::SchemaReferenceType::Static,
/// "https://www.example.com/schema#test"}));
///
/// // Root Pointers
/// assert(frame.locations().contains({sourcemeta::core::ReferenceType::Static,
/// assert(frame.locations().contains({sourcemeta::core::SchemaReferenceType::Static,
/// "https://www.example.com/schema#/$id"}));
/// assert(frame.locations().contains({sourcemeta::core::ReferenceType::Static,
/// assert(frame.locations().contains({sourcemeta::core::SchemaReferenceType::Static,
/// "https://www.example.com/schema#/$schema"}));
/// assert(frame.locations().contains({sourcemeta::core::ReferenceType::Static,
/// assert(frame.locations().contains({sourcemeta::core::SchemaReferenceType::Static,
/// "https://www.example.com/schema#/items"}));
/// assert(frame.locations().contains({sourcemeta::core::ReferenceType::Static,
/// assert(frame.locations().contains({sourcemeta::core::SchemaReferenceType::Static,
/// "https://www.example.com/schema#/items/$id"}));
/// assert(frame.locations().contains({sourcemeta::core::ReferenceType::Static,
/// assert(frame.locations().contains({sourcemeta::core::SchemaReferenceType::Static,
/// "https://www.example.com/schema#/items/type"}));
/// assert(frame.locations().contains({sourcemeta::core::ReferenceType::Static,
/// assert(frame.locations().contains({sourcemeta::core::SchemaReferenceType::Static,
/// "https://www.example.com/schema#/properties"}));
/// assert(frame.locations().contains({sourcemeta::core::ReferenceType::Static,
/// assert(frame.locations().contains({sourcemeta::core::SchemaReferenceType::Static,
/// "https://www.example.com/schema#/properties/foo"}));
/// assert(frame.locations().contains({sourcemeta::core::ReferenceType::Static,
/// assert(frame.locations().contains({sourcemeta::core::SchemaReferenceType::Static,
/// "https://www.example.com/schema#/properties/foo/$anchor"}));
/// assert(frame.locations().contains({sourcemeta::core::ReferenceType::Static,
/// assert(frame.locations().contains({sourcemeta::core::SchemaReferenceType::Static,
/// "https://www.example.com/schema#/properties/foo/type"}));
/// assert(frame.locations().contains({sourcemeta::core::ReferenceType::Static,
/// assert(frame.locations().contains({sourcemeta::core::SchemaReferenceType::Static,
/// "https://www.example.com/schema#/properties/bar"}));
/// assert(frame.locations().contains({sourcemeta::core::ReferenceType::Static,
/// assert(frame.locations().contains({sourcemeta::core::SchemaReferenceType::Static,
/// "https://www.example.com/schema#/properties/bar/$ref"}));
///
/// // Subpointers
/// assert(frame.locations().contains({sourcemeta::core::ReferenceType::Static,
/// assert(frame.locations().contains({sourcemeta::core::SchemaReferenceType::Static,
/// "https://www.example.com/foo#/$id"}));
/// assert(frame.locations().contains({sourcemeta::core::ReferenceType::Static,
/// assert(frame.locations().contains({sourcemeta::core::SchemaReferenceType::Static,
/// "https://www.example.com/foo#/type"}));
///
/// // References
/// assert(frame.references().contains({sourcemeta::core::ReferenceType::Static,
/// assert(frame.references().contains({sourcemeta::core::SchemaReferenceType::Static,
/// { "properties", "bar", "$ref" }}));
/// assert(frame.references().at({sourcemeta::core::ReferenceType::Static,
/// assert(frame.references().at({sourcemeta::core::SchemaReferenceType::Static,
/// { "properties", "bar", "$ref" }}).destination ==
/// "https://www.example.com/schema#/properties/foo");
/// ```
class SOURCEMETA_CORE_JSONSCHEMA_EXPORT Frame {
class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaFrame {
public:
/// A single entry in a JSON Schema reference map
struct ReferencesEntry {
Expand All @@ -113,7 +113,7 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT Frame {
/// have a static and a dynamic reference to the same location
/// on the same schema object.
using References =
std::map<std::pair<ReferenceType, Pointer>, ReferencesEntry>;
std::map<std::pair<SchemaReferenceType, Pointer>, ReferencesEntry>;

#if defined(__GNUC__)
#pragma GCC diagnostic push
Expand Down Expand Up @@ -150,7 +150,7 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT Frame {
/// JSON Pointers within the schema, and subschemas dialects. We call it
/// reference frame as this mapping is essential for resolving references.
using Locations =
std::map<std::pair<ReferenceType, std::string>, LocationsEntry>;
std::map<std::pair<SchemaReferenceType, std::string>, LocationsEntry>;

/// Analyse a given schema
auto analyse(const JSON &schema, const SchemaWalker &walker,
Expand Down Expand Up @@ -188,7 +188,7 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT Frame {
auto
dereference(const LocationsEntry &location,
const Pointer &relative_schema_location = empty_pointer) const
-> std::pair<ReferenceType,
-> std::pair<SchemaReferenceType,
std::optional<std::reference_wrapper<const LocationsEntry>>>;

private:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@

namespace sourcemeta::core {

/// @ingroup jsonschema
/// The reference type
enum class SchemaReferenceType : std::uint8_t { Static, Dynamic };

#if defined(__GNUC__)
#pragma GCC diagnostic push
// For some strange reason, GCC on Debian 11 believes that a member of
Expand All @@ -14,7 +18,7 @@ namespace sourcemeta::core {
#endif
/// @ingroup jsonschema
/// Determines the type of a JSON Schema keyword
enum class KeywordType : std::uint8_t {
enum class SchemaKeywordType : std::uint8_t {
/// The JSON Schema keyword is unknown
Unknown,
/// The JSON Schema keyword is a non-applicator assertion
Expand Down
14 changes: 0 additions & 14 deletions src/core/jsonschema/include/sourcemeta/core/jsonschema_reference.h

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ auto official_resolver(std::string_view identifier)
/// #include <cassert>
///
/// // (1) Create a map resolver that falls back to the official resolver
/// sourcemeta::core::MapSchemaResolver
/// sourcemeta::core::SchemaMapResolver
/// resolver{sourcemeta::core::official_resolver};
///
/// const sourcemeta::core::JSON schema =
Expand All @@ -62,14 +62,14 @@ auto official_resolver(std::string_view identifier)
///
/// assert(resolver("https://www.example.com").has_value());
/// ```
class SOURCEMETA_CORE_JSONSCHEMA_EXPORT MapSchemaResolver {
class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaMapResolver {
public:
/// Construct an empty resolver. If you don't add schemas to it, it will
/// always resolve to nothing
MapSchemaResolver();
SchemaMapResolver();

/// Construct an empty resolver that has another schema resolver as a fallback
MapSchemaResolver(const SchemaResolver &resolver);
SchemaMapResolver(const SchemaResolver &resolver);

/// Register a schema to the map resolver
auto add(const JSON &schema,
Expand Down Expand Up @@ -104,22 +104,22 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT MapSchemaResolver {
/// #include <cassert>
///
/// // (1) Create a flat file resolver that falls back to the official resolver
/// sourcemeta::core::FlatFileSchemaResolver
/// sourcemeta::core::SchemaFlatFileResolver
/// resolver{sourcemeta::core::official_resolver};
///
/// // (2) Register a schema by path
/// resolver.add("path/to/example.schema.json");
///
/// assert(resolver("https://www.example.com").has_value());
/// ```
class SOURCEMETA_CORE_JSONSCHEMA_EXPORT FlatFileSchemaResolver {
class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaFlatFileResolver {
public:
/// Construct an empty resolver. If you don't add schemas to it, it will
/// always resolve to nothing
FlatFileSchemaResolver();
SchemaFlatFileResolver();

/// Construct an empty resolver that has another schema resolver as a fallback
FlatFileSchemaResolver(const SchemaResolver &resolver);
SchemaFlatFileResolver(const SchemaResolver &resolver);

/// Determines how to access the registered file entry, letting you hook
/// into how schemas are read to support other file formats, like YAML
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
namespace sourcemeta::core {

/// @ingroup jsonschema
struct UnevaluatedEntry {
struct SchemaUnevaluatedEntry {
/// The absolute pointers of the static keyword dependencies
std::set<Pointer> static_dependencies;
/// The absolute pointers of the static keyword dependencies
Expand All @@ -31,7 +31,7 @@ struct UnevaluatedEntry {

/// @ingroup jsonschema
/// The flattened set of unevaluated cases in the schema by absolute URI
using UnevaluatedEntries = std::map<std::string, UnevaluatedEntry>;
using SchemaUnevaluatedEntries = std::map<std::string, SchemaUnevaluatedEntry>;

// TODO: Eventually generalize this to list every cross-dependency between
// keywords, supporting extensibility of custom vocabularies too
Expand All @@ -54,7 +54,7 @@ using UnevaluatedEntries = std::map<std::string, UnevaluatedEntry>;
/// "unevaluatedProperties": false
/// })JSON");
///
/// sourcemeta::core::Frame frame;
/// sourcemeta::core::SchemaSchemaFrame frame;
/// frame.analyse(document,
/// sourcemeta::core::default_schema_walker,
/// sourcemeta::core::official_resolver);
Expand All @@ -67,9 +67,9 @@ using UnevaluatedEntries = std::map<std::string, UnevaluatedEntry>;
/// assert(!result.at("#/unevaluatedProperties").dynamic);
/// assert(result.at("#/unevaluatedProperties").dependencies.empty());
/// ```
auto SOURCEMETA_CORE_JSONSCHEMA_EXPORT
unevaluated(const JSON &schema, const Frame &frame, const SchemaWalker &walker,
const SchemaResolver &resolver) -> UnevaluatedEntries;
auto SOURCEMETA_CORE_JSONSCHEMA_EXPORT unevaluated(
const JSON &schema, const SchemaFrame &frame, const SchemaWalker &walker,
const SchemaResolver &resolver) -> SchemaUnevaluatedEntries;

} // namespace sourcemeta::core

Expand Down
Loading