Module: JSONSchemer

Defined in:
lib/json_schemer/errors.rb,
lib/json_schemer.rb,
lib/json_schemer/format.rb,
lib/json_schemer/output.rb,
lib/json_schemer/result.rb,
lib/json_schemer/schema.rb,
lib/json_schemer/keyword.rb,
lib/json_schemer/openapi.rb,
lib/json_schemer/version.rb,
lib/json_schemer/location.rb,
lib/json_schemer/draft4/meta.rb,
lib/json_schemer/draft6/meta.rb,
lib/json_schemer/draft7/meta.rb,
lib/json_schemer/ecma_regexp.rb,
lib/json_schemer/draft4/vocab.rb,
lib/json_schemer/draft6/vocab.rb,
lib/json_schemer/draft7/vocab.rb,
lib/json_schemer/format/email.rb,
lib/json_schemer/openapi30/meta.rb,
lib/json_schemer/openapi31/meta.rb,
lib/json_schemer/cached_resolver.rb,
lib/json_schemer/format/duration.rb,
lib/json_schemer/format/hostname.rb,
lib/json_schemer/openapi30/vocab.rb,
lib/json_schemer/openapi31/vocab.rb,
lib/json_schemer/draft201909/meta.rb,
lib/json_schemer/draft202012/meta.rb,
lib/json_schemer/draft201909/vocab.rb,
lib/json_schemer/draft202012/vocab.rb,
lib/json_schemer/openapi30/document.rb,
lib/json_schemer/openapi31/document.rb,
lib/json_schemer/format/json_pointer.rb,
lib/json_schemer/format/uri_template.rb,
lib/json_schemer/openapi30/vocab/base.rb,
lib/json_schemer/openapi31/vocab/base.rb,
lib/json_schemer/draft201909/vocab/core.rb,
lib/json_schemer/draft202012/vocab/core.rb,
lib/json_schemer/draft4/vocab/validation.rb,
lib/json_schemer/draft7/vocab/validation.rb,
lib/json_schemer/draft202012/vocab/content.rb,
lib/json_schemer/draft202012/vocab/meta_data.rb,
lib/json_schemer/draft201909/vocab/applicator.rb,
lib/json_schemer/draft202012/vocab/applicator.rb,
lib/json_schemer/draft202012/vocab/validation.rb,
lib/json_schemer/draft202012/vocab/unevaluated.rb,
lib/json_schemer/draft202012/vocab/format_assertion.rb,
lib/json_schemer/draft202012/vocab/format_annotation.rb

Overview

Based on code from @robacarp found in issue 48: github.com/davishmcclurg/json_schemer/issues/48

Defined Under Namespace

Modules: Draft201909, Draft202012, Draft4, Draft6, Draft7, Errors, Format, Location, OpenAPI30, OpenAPI31, Output Classes: CachedRefResolver, CachedResolver, EcmaRegexp, InvalidEcmaRegexp, InvalidFileURI, InvalidRefPointer, InvalidRefResolution, InvalidRegexpResolution, Keyword, OpenAPI, Result, Schema, UnknownContentEncoding, UnknownContentMediaType, UnknownFormat, UnknownOutputFormat, UnknownRef, UnknownVocabulary, UnsupportedMetaSchema, UnsupportedOpenAPIVersion

Constant Summary collapse

VOCABULARIES =
{
  'https://json-schema.org/draft/2020-12/vocab/core' => Draft202012::Vocab::CORE,
  'https://json-schema.org/draft/2020-12/vocab/applicator' => Draft202012::Vocab::APPLICATOR,
  'https://json-schema.org/draft/2020-12/vocab/unevaluated' => Draft202012::Vocab::UNEVALUATED,
  'https://json-schema.org/draft/2020-12/vocab/validation' => Draft202012::Vocab::VALIDATION,
  'https://json-schema.org/draft/2020-12/vocab/format-annotation' => Draft202012::Vocab::FORMAT_ANNOTATION,
  'https://json-schema.org/draft/2020-12/vocab/format-assertion' => Draft202012::Vocab::FORMAT_ASSERTION,
  'https://json-schema.org/draft/2020-12/vocab/content' => Draft202012::Vocab::CONTENT,
  'https://json-schema.org/draft/2020-12/vocab/meta-data' => Draft202012::Vocab::META_DATA,

  'https://json-schema.org/draft/2019-09/vocab/core' => Draft201909::Vocab::CORE,
  'https://json-schema.org/draft/2019-09/vocab/applicator' => Draft201909::Vocab::APPLICATOR,
  'https://json-schema.org/draft/2019-09/vocab/validation' => Draft201909::Vocab::VALIDATION,
  'https://json-schema.org/draft/2019-09/vocab/format' => Draft201909::Vocab::FORMAT,
  'https://json-schema.org/draft/2019-09/vocab/content' => Draft201909::Vocab::CONTENT,
  'https://json-schema.org/draft/2019-09/vocab/meta-data' => Draft201909::Vocab::META_DATA,

  'json-schemer://draft7' => Draft7::Vocab::ALL,
  'json-schemer://draft6' => Draft6::Vocab::ALL,
  'json-schemer://draft4' => Draft4::Vocab::ALL,

  'https://spec.openapis.org/oas/3.1/vocab/base' => OpenAPI31::Vocab::BASE,
  'json-schemer://openapi30' => OpenAPI30::Vocab::BASE
}
VOCABULARY_ORDER =
VOCABULARIES.transform_values.with_index { |_vocabulary, index| index }
WINDOWS_URI_PATH_REGEX =
/\A\/[a-z]:/i
FILE_URI_REF_RESOLVER =
proc do |uri|
  raise InvalidFileURI, 'must use `file` scheme' unless uri.scheme == 'file'
  raise InvalidFileURI, 'cannot have a host (use `file:///`)' if uri.host && !uri.host.empty?
  path = uri.path
  path = path[1..-1] if path.match?(WINDOWS_URI_PATH_REGEX)
  JSON.parse(File.read(URI::DEFAULT_PARSER.unescape(path)))
end
META_SCHEMA_CALLABLES_BY_BASE_URI_STR =
{
  Draft202012::BASE_URI.to_s => method(:draft202012),
  Draft201909::BASE_URI.to_s => method(:draft201909),
  Draft7::BASE_URI.to_s => method(:draft7),
  Draft6::BASE_URI.to_s => method(:draft6),
  Draft4::BASE_URI.to_s => method(:draft4),
  # version-less $schema deprecated after Draft 4
  'http://json-schema.org/schema#' => method(:draft4),
  OpenAPI31::BASE_URI.to_s => method(:openapi31),
  OpenAPI30::BASE_URI.to_s => method(:openapi30)
}.freeze
META_SCHEMAS_BY_BASE_URI_STR =
Hash.new do |hash, base_uri_str|
  next unless META_SCHEMA_CALLABLES_BY_BASE_URI_STR.key?(base_uri_str)
  hash[base_uri_str] = META_SCHEMA_CALLABLES_BY_BASE_URI_STR.fetch(base_uri_str).call
end
VERSION =
'2.0.0'

Class Method Summary collapse

Class Method Details

.draft201909Object



153
154
155
156
157
158
159
160
# File 'lib/json_schemer.rb', line 153

def draft201909
  @draft201909 ||= Schema.new(
    Draft201909::SCHEMA,
    :base_uri => Draft201909::BASE_URI,
    :ref_resolver => Draft201909::Meta::SCHEMAS.to_proc,
    :regexp_resolver => 'ecma'
  )
end

.draft202012Object



144
145
146
147
148
149
150
151
# File 'lib/json_schemer.rb', line 144

def draft202012
  @draft202012 ||= Schema.new(
    Draft202012::SCHEMA,
    :base_uri => Draft202012::BASE_URI,
    :ref_resolver => Draft202012::Meta::SCHEMAS.to_proc,
    :regexp_resolver => 'ecma'
  )
end

.draft4Object



180
181
182
183
184
185
186
187
# File 'lib/json_schemer.rb', line 180

def draft4
  @draft4 ||= Schema.new(
    Draft4::SCHEMA,
    :vocabulary => { 'json-schemer://draft4' => true },
    :base_uri => Draft4::BASE_URI,
    :regexp_resolver => 'ecma'
  )
end

.draft6Object



171
172
173
174
175
176
177
178
# File 'lib/json_schemer.rb', line 171

def draft6
  @draft6 ||= Schema.new(
    Draft6::SCHEMA,
    :vocabulary => { 'json-schemer://draft6' => true },
    :base_uri => Draft6::BASE_URI,
    :regexp_resolver => 'ecma'
  )
end

.draft7Object



162
163
164
165
166
167
168
169
# File 'lib/json_schemer.rb', line 162

def draft7
  @draft7 ||= Schema.new(
    Draft7::SCHEMA,
    :vocabulary => { 'json-schemer://draft7' => true },
    :base_uri => Draft7::BASE_URI,
    :regexp_resolver => 'ecma'
  )
end

.openapi(document, **options) ⇒ Object



244
245
246
# File 'lib/json_schemer.rb', line 244

def openapi(document, **options)
  OpenAPI.new(document, **options)
end

.openapi30Object



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/json_schemer.rb', line 206

def openapi30
  @openapi30 ||= Schema.new(
    OpenAPI30::SCHEMA,
    :vocabulary => {
      'json-schemer://draft4' => true,
      'json-schemer://openapi30' => true
    },
    :base_uri => OpenAPI30::BASE_URI,
    :ref_resolver => OpenAPI30::Meta::SCHEMAS.to_proc,
    :regexp_resolver => 'ecma',
    :formats => {
      'int32' => proc { |instance, _value| instance.is_a?(Integer) && instance.bit_length <= 32 },
      'int64' => proc { |instance, _value| instance.is_a?(Integer) && instance.bit_length <= 64 },
      'float' => proc { |instance, _value| instance.is_a?(Float) },
      'double' => proc { |instance, _value| instance.is_a?(Float) },
      'byte' => proc { |instance, _value| Format.decode_content_encoding(instance, 'base64').first },
      'binary' => proc { |instance, _value| instance.is_a?(String) && instance.encoding == Encoding::ASCII_8BIT },
      'password' => proc { |_instance, _value| true }
    }
  )
end

.openapi30_documentObject



236
237
238
239
240
241
242
# File 'lib/json_schemer.rb', line 236

def openapi30_document
  @openapi30_document ||= Schema.new(
    OpenAPI30::Document::SCHEMA,
    :ref_resolver => OpenAPI30::Document::SCHEMAS.to_proc,
    :regexp_resolver => 'ecma'
  )
end

.openapi31Object



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/json_schemer.rb', line 189

def openapi31
  @openapi31 ||= Schema.new(
    OpenAPI31::SCHEMA,
    :base_uri => OpenAPI31::BASE_URI,
    :ref_resolver => OpenAPI31::Meta::SCHEMAS.to_proc,
    :regexp_resolver => 'ecma',
    # https://spec.openapis.org/oas/latest.html#data-types
    :formats => {
      'int32' => proc { |instance, _value| instance.is_a?(Integer) && instance.bit_length <= 32 },
      'int64' => proc { |instance, _value| instance.is_a?(Integer) && instance.bit_length <= 64 },
      'float' => proc { |instance, _value| instance.is_a?(Float) },
      'double' => proc { |instance, _value| instance.is_a?(Float) },
      'password' => proc { |_instance, _value| true }
    }
  )
end

.openapi31_documentObject



228
229
230
231
232
233
234
# File 'lib/json_schemer.rb', line 228

def openapi31_document
  @openapi31_document ||= Schema.new(
    OpenAPI31::Document::SCHEMA_BASE,
    :ref_resolver => OpenAPI31::Document::SCHEMAS.to_proc,
    :regexp_resolver => 'ecma'
  )
end

.schema(schema, meta_schema: draft202012, **options) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/json_schemer.rb', line 115

def schema(schema, meta_schema: draft202012, **options)
  case schema
  when String
    schema = JSON.parse(schema)
  when Pathname
    base_uri = URI.parse(File.join('file:', URI::DEFAULT_PARSER.escape(schema.realpath.to_s)))
    options[:base_uri] = base_uri
    schema = if options.key?(:ref_resolver)
      FILE_URI_REF_RESOLVER.call(base_uri)
    else
      ref_resolver = CachedResolver.new(&FILE_URI_REF_RESOLVER)
      options[:ref_resolver] = ref_resolver
      ref_resolver.call(base_uri)
    end
  end
  unless meta_schema.is_a?(Schema)
    meta_schema = META_SCHEMAS_BY_BASE_URI_STR[meta_schema] || raise(UnsupportedMetaSchema, meta_schema)
  end
  Schema.new(schema, :meta_schema => meta_schema, **options)
end

.valid_schema?(schema, **options) ⇒ Boolean

Returns:

  • (Boolean)


136
137
138
# File 'lib/json_schemer.rb', line 136

def valid_schema?(schema, **options)
  schema(schema, **options).valid_schema?
end

.validate_schema(schema, **options) ⇒ Object



140
141
142
# File 'lib/json_schemer.rb', line 140

def validate_schema(schema, **options)
  schema(schema, **options).validate_schema
end