Module: Insika::Plugin::Loader::ConfigSchema
- Defined in:
- lib/insika/plugin/loader.rb
Overview
Subset JSON Schema validator (no gem; swappable). validate(schema, value) -> [String] (empty = valid). An invalid schema AND a config that fails validation land in the same list (fail-closed per plugin).
Constant Summary collapse
- KEYWORDS =
%w[type properties required additionalProperties enum].freeze
- TYPES =
{ "object" => [Hash], "array" => [Array], "string" => [String], "integer" => [Integer], "number" => [Numeric], "boolean" => [TrueClass, FalseClass], "null" => [NilClass] }.freeze
Class Method Summary collapse
- .check_enum(schema, value, path) ⇒ Object
- .check_object(schema, value, path) ⇒ Object
- .check_type(schema, value, path) ⇒ Object
- .validate(schema, value, path = "config") ⇒ Object
Class Method Details
.check_enum(schema, value, path) ⇒ Object
328 329 330 331 332 333 |
# File 'lib/insika/plugin/loader.rb', line 328 def self.check_enum(schema, value, path) return [] unless schema.key?("enum") return [] if Array(schema["enum"]).include?(value) ["#{path}: value #{value.inspect} not in enum"] end |
.check_object(schema, value, path) ⇒ Object
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 |
# File 'lib/insika/plugin/loader.rb', line 335 def self.check_object(schema, value, path) return [] unless schema.key?("properties") || schema.key?("required") || schema.key?("additionalProperties") props = schema["properties"] || {} return ["#{path}: properties must be a Hash"] unless props.is_a?(Hash) return [] unless value.is_a?(Hash) # object keywords only apply to a Hash errors = [] props.each { |k, sub| errors.concat(validate(sub, value[k], "#{path}.#{k}")) if value.key?(k) } Array(schema["required"]).each do |req| errors << "#{path}: missing required key: #{req}" unless value.key?(req) end if schema["additionalProperties"] == false && !(extra = value.keys - props.keys).empty? errors << "#{path}: keys not allowed: #{extra.join(', ')}" end errors end |
.check_type(schema, value, path) ⇒ Object
318 319 320 321 322 323 324 325 326 |
# File 'lib/insika/plugin/loader.rb', line 318 def self.check_type(schema, value, path) return [] unless schema.key?("type") klasses = TYPES[schema["type"]] return ["#{path}: unknown type: #{schema['type'].inspect}"] if klasses.nil? return [] if klasses.any? { |k| value.is_a?(k) } ["#{path}: expected #{schema['type']}, got #{value.class}"] end |
.validate(schema, value, path = "config") ⇒ Object
306 307 308 309 310 311 312 313 314 315 316 |
# File 'lib/insika/plugin/loader.rb', line 306 def self.validate(schema, value, path = "config") return ["#{path}: schema must be a Hash"] unless schema.is_a?(Hash) errors = [] unknown = schema.keys - KEYWORDS errors << "#{path}: unsupported keyword(s): #{unknown.join(', ')}" unless unknown.empty? errors.concat(check_type(schema, value, path)) errors.concat(check_enum(schema, value, path)) errors.concat(check_object(schema, value, path)) errors end |