Class: Plumb::JSONSchemaVisitor

Inherits:
Object
  • Object
show all
Includes:
VisitorHandlers
Defined in:
lib/plumb/json_schema_visitor.rb

Constant Summary collapse

InvalidJSONValueError =

Raised when a value that has no JSON-native representation would end up in the generated schema. Register a handler (via .on(...)) that converts the offending type to a JSON-native value to resolve it.

Class.new(StandardError)
TYPE =
'type'
PROPERTIES =
'properties'
REQUIRED =
'required'
DEFAULT =
'default'
ANY_OF =
'anyOf'
ALL_OF =
'allOf'
NOT =
'not'
ENUM =
'enum'
CONST =
'const'
REF =
'$ref'
DEFS =
'$defs'
ITEMS =
'items'
PATTERN =
'pattern'
MINIMUM =
'minimum'
MAXIMUM =
'maximum'
MIN_ITEMS =
'minItems'
MAX_ITEMS =
'maxItems'
MIN_LENGTH =
'minLength'
MAX_LENGTH =
'maxLength'
FORMAT =
'format'
EXCLUSIVE_MAXIMUM =
'exclusiveMaximum'
FORMAT_MINIMUM =
'formatMinimum'
FORMAT_MAXIMUM =
'formatMaximum'
FORMAT_EXCLUSIVE_MAXIMUM =
'formatExclusiveMaximum'
ENVELOPE =
{
  '$schema' => 'https://json-schema.org/draft-08/schema#'
}.freeze

Constants included from VisitorHandlers

VisitorHandlers::NODE_NAME_FALLBACKS

Class Method Summary collapse

Instance Method Summary collapse

Methods included from VisitorHandlers

included, #on_missing_handler, #visit, #visit_children, #visit_name

Class Method Details

.call(node, root: true) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
# File 'lib/plumb/json_schema_visitor.rb', line 43

def self.call(node, root: true)
  visitor = new
  data = visitor.visit(node)
  # Deferred types register named entries in a `$defs` table and reference
  # them by `$ref` (see the :deferred handler). Hoist that table to the top of
  # the document so the root-relative `#/$defs/...` pointers resolve.
  defs = visitor.defs
  data = data.merge(DEFS => defs) unless defs.empty?
  data = ENVELOPE.merge(data) if root
  normalize_json(data)
end

.normalize_json(value) ⇒ Object

Recursively normalize the generated schema into JSON-native values and fail loudly on anything that has no JSON representation. Symbols are coerced to strings; everything that isn't a JSON-native value raises, so the user knows they need to register a custom visitor handler.



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/plumb/json_schema_visitor.rb', line 59

def self.normalize_json(value)
  case value
  when ::Hash
    value.each_with_object({}) do |(key, val), hash|
      hash[normalize_json(key)] = normalize_json(val)
    end
  when ::Array
    value.map { |val| normalize_json(val) }
  when ::Symbol
    value.to_s
  when ::String, ::Numeric, true, false, nil
    value
  else
    raise InvalidJSONValueError,
          "#{value.class} value #{value.inspect} cannot be serialized to JSON Schema. " \
          'Register a Plumb::JSONSchemaVisitor.on(...) handler that converts it to a JSON-native value.'
  end
end

Instance Method Details

#defsObject

The $defs table of materialized Deferred schemas built during this visit, hoisted to the document root by .call. Empty unless a Deferred was visited.



89
# File 'lib/plumb/json_schema_visitor.rb', line 89

def defs = @defs || BLANK_HASH