Class: JekyllOpenAPI::Schema

Inherits:
Object
  • Object
show all
Defined in:
lib/jekyll_openapi/schema.rb

Overview

Normalized, ref-aware view over a JSON-Schema node, shared by every schema renderer.

It centralises the two things that used to be copy-pasted (and drift) across the TypeScript and XML renderers: the type inference that fills in an omitted type, and the $ref following with cycle detection. A new renderer (JSON example, HTML, …) implements formatting only — it never walks raw hashes or re-infers types.

Schemas are immutable and carry the set of $ref pointers already followed on the current path (seen), so following a self-referential schema stops instead of looping, while genuine reuse (the same schema in two branches) is never mistaken for a cycle.

Constant Summary collapse

CYCLE =

Sentinel returned by #follow when a $ref points back onto the path.

:cycle

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(node, seen = []) ⇒ Schema

Returns a new instance of Schema.



29
30
31
32
# File 'lib/jekyll_openapi/schema.rb', line 29

def initialize(node, seen = [])
  @node = node
  @seen = seen
end

Instance Attribute Details

#seenObject (readonly)

Returns the value of attribute seen.



27
28
29
# File 'lib/jekyll_openapi/schema.rb', line 27

def seen
  @seen
end

Class Method Details

.wrap(node, seen = []) ⇒ Object



23
24
25
# File 'lib/jekyll_openapi/schema.rb', line 23

def self.wrap(node, seen = [])
  node.is_a?(Schema) ? node : new(node, seen)
end

Instance Method Details

#[](key) ⇒ Object

Raw read, delegating through a Reference transparently.



101
102
103
# File 'lib/jekyll_openapi/schema.rb', line 101

def [](key)
  mapping? ? @node[key] : nil
end

#additional_propertiesSchema?

Returns the additionalProperties schema, only when it is a schema object (the boolean true/false forms carry no shape to render).

Returns:

  • (Schema, nil)

    the additionalProperties schema, only when it is a schema object (the boolean true/false forms carry no shape to render)



160
161
162
163
# File 'lib/jekyll_openapi/schema.rb', line 160

def additional_properties
  value = self["additionalProperties"]
  value.is_a?(Hash) || value.is_a?(Reference) ? child(value) : nil
end

#compositionArray(String, Array<Schema>)?

Returns e.g. ["oneOf", [Schema, ...]].

Returns:

  • (Array(String, Array<Schema>), nil)

    e.g. ["oneOf", [Schema, ...]]



112
113
114
115
116
117
118
# File 'lib/jekyll_openapi/schema.rb', line 112

def composition
  %w[oneOf anyOf allOf].each do |keyword|
    members = self[keyword]
    return [keyword, members.map { |m| child(m) }] if members.is_a?(Array)
  end
  nil
end

#declared_typeObject

--- type ----------------------------------------------------------------



122
123
124
# File 'lib/jekyll_openapi/schema.rb', line 122

def declared_type
  self["type"]
end

#descriptionObject



177
# File 'lib/jekyll_openapi/schema.rb', line 177

def description = self["description"]

#dig(*keys) ⇒ Object



105
106
107
# File 'lib/jekyll_openapi/schema.rb', line 105

def dig(*keys)
  mapping? ? @node.dig(*keys) : nil
end

#enumObject

--- leaf metadata -------------------------------------------------------



173
# File 'lib/jekyll_openapi/schema.rb', line 173

def enum = self["enum"]

#exampleObject



178
# File 'lib/jekyll_openapi/schema.rb', line 178

def example = self["example"]

#examplesObject



179
# File 'lib/jekyll_openapi/schema.rb', line 179

def examples = self["examples"]

#followSchema

Follow a $ref one hop.

Returns:

  • (Schema)

    the target when resolvable, CYCLE when the ref is already on the current path, nil when external, unresolvable, or a raw (never-dereferenced) ref that carries no root to resolve against (a warning is emitted by Reference).



92
93
94
95
96
97
98
# File 'lib/jekyll_openapi/schema.rb', line 92

def follow
  return self unless reference?
  pointer = ref
  return CYCLE if @seen.include?(pointer)
  target = @node.is_a?(Reference) ? @node.resolve : nil
  target.nil? ? nil : Schema.new(target, @seen + [pointer])
end

#formatObject



174
# File 'lib/jekyll_openapi/schema.rb', line 174

def format = self["format"]

#itemsObject

--- array ---------------------------------------------------------------



167
168
169
# File 'lib/jekyll_openapi/schema.rb', line 167

def items
  child(self["items"])
end

#mapping?Boolean

Whether this wraps something readable as a schema object.

Returns:

  • (Boolean)


39
40
41
# File 'lib/jekyll_openapi/schema.rb', line 39

def mapping?
  @node.is_a?(Hash) || @node.is_a?(Reference)
end

#nameObject

Component name of a local ref, e.g. "Pet" for "#/components/schemas/Pet"; nil for external refs or non-refs. Derived from the pointer alone, so it needs no dereferencing.



67
68
69
70
71
# File 'lib/jekyll_openapi/schema.rb', line 67

def name
  pointer = ref
  return nil unless pointer.is_a?(String) && pointer.start_with?("#")
  JSONPointer.unescape(pointer.delete_prefix("#").split("/").last)
end

#named_reference?Boolean

A local $ref to a named component — the kind an HTML renderer links to rather than inlines. External refs (no local name) return false.

Returns:

  • (Boolean)


75
76
77
# File 'lib/jekyll_openapi/schema.rb', line 75

def named_reference?
  reference? && !name.nil?
end

#override_descriptionObject

The use-site description sitting beside a $ref (a 3.1 sibling override), if any. Lets a renderer annotate a link without expanding its target.



81
82
83
84
85
# File 'lib/jekyll_openapi/schema.rb', line 81

def override_description
  return @node.overrides["description"] if @node.is_a?(Reference)
  return @node["description"] if raw_reference?
  nil
end

#patternObject



175
# File 'lib/jekyll_openapi/schema.rb', line 175

def pattern = self["pattern"]

#propertiesObject

--- object --------------------------------------------------------------



150
151
152
# File 'lib/jekyll_openapi/schema.rb', line 150

def properties
  (self["properties"] || {}).map { |key, node| [key, child(node)] }
end

#rawObject



34
35
36
# File 'lib/jekyll_openapi/schema.rb', line 34

def raw
  @node
end

#raw_reference?Boolean

A plain {"$ref" => "..."} hash that never went through the Dereferencer.

Returns:

  • (Boolean)


53
54
55
# File 'lib/jekyll_openapi/schema.rb', line 53

def raw_reference?
  @node.is_a?(Hash) && @node["$ref"].is_a?(String)
end

#refObject

The raw pointer string, e.g. "#/components/schemas/Pet"; nil when not a ref.



58
59
60
61
62
# File 'lib/jekyll_openapi/schema.rb', line 58

def ref
  return @node.ref if @node.is_a?(Reference)
  return @node["$ref"] if raw_reference?
  nil
end

#reference?Boolean

A $ref node — either a linked Reference (produced by the Dereferencer) or a raw, un-dereferenced {"$ref" => "..."} hash. Link-mode rendering only needs the pointer string, so it works on either form (see #ref/#name); following a ref to inline its target still requires a linked Reference (a raw ref carries no root to resolve against — see #follow).

Returns:

  • (Boolean)


48
49
50
# File 'lib/jekyll_openapi/schema.rb', line 48

def reference?
  @node.is_a?(Reference) || raw_reference?
end

#required?(key) ⇒ Boolean

Returns:

  • (Boolean)


154
155
156
# File 'lib/jekyll_openapi/schema.rb', line 154

def required?(key)
  Array(self["required"]).include?(key)
end

#summaryObject



176
# File 'lib/jekyll_openapi/schema.rb', line 176

def summary = self["summary"]

#typeObject

Single inferred type, mirroring what most tooling assumes when type is omitted. Returns nil for a type union (see #type_union?) or the unknown.



132
133
134
135
136
137
138
139
140
# File 'lib/jekyll_openapi/schema.rb', line 132

def type
  declared = declared_type
  return declared if declared.is_a?(String)
  return nil if declared.is_a?(Array)
  return "object" if self["properties"] || self["additionalProperties"]
  return "array" if self["items"]
  return "string" if self["enum"]
  nil
end

#type_union?Boolean

Returns:

  • (Boolean)


126
127
128
# File 'lib/jekyll_openapi/schema.rb', line 126

def type_union?
  declared_type.is_a?(Array)
end

#with_type(single) ⇒ Object

A copy of this schema with type pinned to one member of a type union.



143
144
145
146
# File 'lib/jekyll_openapi/schema.rb', line 143

def with_type(single)
  node = @node.is_a?(Hash) ? @node.merge("type" => single) : @node
  Schema.new(node, @seen)
end

#xmlObject



180
# File 'lib/jekyll_openapi/schema.rb', line 180

def xml = self["xml"] || {}