1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
require "json"
require "yaml"
require_relative "../json_schema"
module Commands
class ValidateSchema
attr_accessor :detect
attr_accessor :fail_fast
attr_accessor :extra_schemas
attr_accessor :errors
attr_accessor :messages
def initialize
@detect = false
@fail_fast = false
@extra_schemas = []
@errors = []
@messages = []
end
def run(argv)
return false if !initialize_store
if !detect
return false if !(schema_file = argv.shift)
return false if !(schema = parse(schema_file))
end
# if there are no remaining files in arguments, also a problem
return false if argv.count < 1
argv.each do |data_file|
if !(data = read_file(data_file))
return false
end
if detect
if !(schema_uri = data["$schema"])
@errors = ["#{data_file}: No $schema tag for detection."]
return false
end
if !(schema = @store.lookup_schema(schema_uri))
@errors = ["#{data_file}: Unknown $schema, try specifying one with -s."]
return false
end
end
valid, errors = schema.validate(data, fail_fast: fail_fast)
if valid
@messages += ["#{data_file} is valid."]
else
@errors = map_schema_errors(data_file, errors)
end
end
@errors.empty?
end
private
def initialize_store
@store = JsonSchema::DocumentStore.new
extra_schemas.each do |extra_schema|
if !(extra_schema = parse(extra_schema))
return false
end
@store.add_schema(extra_schema)
end
true
end
# Builds a JSON Reference + message like "/path/to/file#/path/to/data".
def map_schema_errors(file, errors)
errors.map { |m| "#{file}#{m}" }
end
def parse(file)
if !(schema_data = read_file(file))
return nil
end
parser = JsonSchema::Parser.new
if !(schema = parser.parse(schema_data))
@errors = map_schema_errors(file, parser.errors)
return nil
end
expander = JsonSchema::ReferenceExpander.new
if !expander.expand(schema, store: @store)
@errors = map_schema_errors(file, expander.errors)
return nil
end
schema
end
def read_file(file)
contents = File.read(file)
# Perform an empty check because boath YAML and JSON's load will return
# `nil` in the case of an empty file, which will otherwise produce
# confusing results.
if contents.empty?
@errors = ["#{file}: File is empty."]
nil
else
if File.extname(file) == ".yaml"
YAML.load(contents)
else
JSON.load(contents)
end
end
rescue Errno::ENOENT
@errors = ["#{file}: No such file or directory."]
nil
rescue JSON::ParserError
# Ruby's parsing exceptions aren't too helpful, just point user to
# a better tool
@errors = ["#{file}: Invalid JSON. Try to validate using `jsonlint`."]
nil
rescue Psych::SyntaxError
@errors = ["#{file}: Invalid YAML."]
nil
end
end
end
|