Comparison

util/jsonschema.lua @ 12132:4ff0d33dfb2b

util.jsonschema: Add support for $ref pointers
author Kim Alvefur <zash@zash.se>
date Wed, 29 Dec 2021 16:57:35 +0100
parent 11460:a8b4e04bc044
child 12500:88e1b94105ae
comparison
equal deleted inserted replaced
12131:b4c0efff8dd3 12132:4ff0d33dfb2b
1 local json = require("util.json") 1 local json = require("util.json")
2 local null = json.null; 2 local null = json.null;
3
4 local pointer = require("util.jsonpointer")
3 5
4 local json_type_name = json.json_type_name 6 local json_type_name = json.json_type_name
5 7
6 local schema_t = {} 8 local schema_t = {}
7 9
61 return true 63 return true
62 end 64 end
63 65
64 type_validators.integer = type_validators.number 66 type_validators.integer = type_validators.number
65 67
66 local function validate(schema, data) 68 local function validate(schema, data, root)
67 if type(schema) == "boolean" then 69 if type(schema) == "boolean" then
68 return schema 70 return schema
69 end 71 end
70 if type(schema) == "string" then 72 if type(schema) == "string" then
71 return simple_validate(schema, data) 73 return simple_validate(schema, data)
72 end 74 end
73 if type(schema) == "table" then 75 if type(schema) == "table" then
76 if root == nil then
77 root = schema
78 end
79 if schema["$ref"] and schema["$ref"]:sub(1, 1) == "#" then
80 local referenced = pointer.resolve(root, schema["$ref"]:sub(2))
81 if referenced ~= nil then
82 return validate(referenced, data, root)
83 end
84 end
85
74 if schema.allOf then 86 if schema.allOf then
75 for _, sub in ipairs(schema.allOf) do 87 for _, sub in ipairs(schema.allOf) do
76 if not validate(sub, data) then 88 if not validate(sub, data, root) then
77 return false 89 return false
78 end 90 end
79 end 91 end
80 return true 92 return true
81 end 93 end
82 94
83 if schema.oneOf then 95 if schema.oneOf then
84 local valid = 0 96 local valid = 0
85 for _, sub in ipairs(schema.oneOf) do 97 for _, sub in ipairs(schema.oneOf) do
86 if validate(sub, data) then 98 if validate(sub, data, root) then
87 valid = valid + 1 99 valid = valid + 1
88 end 100 end
89 end 101 end
90 return valid == 1 102 return valid == 1
91 end 103 end
92 104
93 if schema.anyOf then 105 if schema.anyOf then
94 for _, sub in ipairs(schema.anyOf) do 106 for _, sub in ipairs(schema.anyOf) do
95 if validate(sub, data) then 107 if validate(sub, data, root) then
96 return true 108 return true
97 end 109 end
98 end 110 end
99 return false 111 return false
100 end 112 end
101 113
102 if schema["not"] then 114 if schema["not"] then
103 if validate(schema["not"], data) then 115 if validate(schema["not"], data, root) then
104 return false 116 return false
105 end 117 end
106 end 118 end
107 119
108 if schema["if"] then 120 if schema["if"] then
109 if validate(schema["if"], data) then 121 if validate(schema["if"], data, root) then
110 if schema["then"] then 122 if schema["then"] then
111 return validate(schema["then"], data) 123 return validate(schema["then"], data, root)
112 end 124 end
113 else 125 else
114 if schema["else"] then 126 if schema["else"] then
115 return validate(schema["else"], data) 127 return validate(schema["else"], data, root)
116 end 128 end
117 end 129 end
118 end 130 end
119 131
120 if schema.const ~= nil and schema.const ~= data then 132 if schema.const ~= nil and schema.const ~= data then
135 return false 147 return false
136 end 148 end
137 149
138 local validator = type_validators[schema.type] 150 local validator = type_validators[schema.type]
139 if validator then 151 if validator then
140 return validator(schema, data) 152 return validator(schema, data, root)
141 end 153 end
142 end 154 end
143 return true 155 return true
144 end 156 end
145 end 157 end
146 158
147 type_validators.table = function(schema, data) 159 type_validators.table = function(schema, data, root)
148 if type(data) == "table" then 160 if type(data) == "table" then
149 161
150 if schema.maxItems and #data > schema.maxItems then 162 if schema.maxItems and #data > schema.maxItems then
151 return false 163 return false
152 end 164 end
164 end 176 end
165 177
166 if schema.properties then 178 if schema.properties then
167 local additional = schema.additionalProperties or true 179 local additional = schema.additionalProperties or true
168 for k, v in pairs(data) do 180 for k, v in pairs(data) do
169 if schema.propertyNames and not validate(schema.propertyNames, k) then 181 if schema.propertyNames and not validate(schema.propertyNames, k, root) then
170 return false 182 return false
171 end 183 end
172 local s = schema.properties[k] or additional 184 local s = schema.properties[k] or additional
173 if not validate(s, v) then 185 if not validate(s, v, root) then
174 return false 186 return false
175 end 187 end
176 end 188 end
177 elseif schema.additionalProperties then 189 elseif schema.additionalProperties then
178 for k, v in pairs(data) do 190 for k, v in pairs(data) do
179 if schema.propertyNames and not validate(schema.propertyNames, k) then 191 if schema.propertyNames and not validate(schema.propertyNames, k, root) then
180 return false 192 return false
181 end 193 end
182 if not validate(schema.additionalProperties, v) then 194 if not validate(schema.additionalProperties, v, root) then
183 return false 195 return false
184 end 196 end
185 end 197 end
186 end 198 end
187 199
197 end 209 end
198 210
199 local p = 0 211 local p = 0
200 if schema.prefixItems then 212 if schema.prefixItems then
201 for i, s in ipairs(schema.prefixItems) do 213 for i, s in ipairs(schema.prefixItems) do
202 if validate(s, data[i]) then 214 if validate(s, data[i], root) then
203 p = i 215 p = i
204 else 216 else
205 return false 217 return false
206 end 218 end
207 end 219 end
208 end 220 end
209 221
210 if schema.items then 222 if schema.items then
211 for i = p + 1, #data do 223 for i = p + 1, #data do
212 if not validate(schema.items, data[i]) then 224 if not validate(schema.items, data[i], root) then
213 return false 225 return false
214 end 226 end
215 end 227 end
216 end 228 end
217 229
218 if schema.contains then 230 if schema.contains then
219 local found = false 231 local found = false
220 for i = 1, #data do 232 for i = 1, #data do
221 if validate(schema.contains, data[i]) then 233 if validate(schema.contains, data[i], root) then
222 found = true 234 found = true
223 break 235 break
224 end 236 end
225 end 237 end
226 if not found then 238 if not found then
231 return true 243 return true
232 end 244 end
233 return false 245 return false
234 end 246 end
235 247
236 type_validators.object = function(schema, data) 248 type_validators.object = function(schema, data, root)
237 if type(data) == "table" then 249 if type(data) == "table" then
238 for k in pairs(data) do 250 for k in pairs(data) do
239 if not (type(k) == "string") then 251 if not (type(k) == "string") then
240 return false 252 return false
241 end 253 end
242 end 254 end
243 255
244 return type_validators.table(schema, data) 256 return type_validators.table(schema, data, root)
245 end 257 end
246 return false 258 return false
247 end 259 end
248 260
249 type_validators.array = function(schema, data) 261 type_validators.array = function(schema, data, root)
250 if type(data) == "table" then 262 if type(data) == "table" then
251 263
252 for i in pairs(data) do 264 for i in pairs(data) do
253 if not (type(i) == "number") then 265 if not (type(i) == "number") then
254 return false 266 return false
255 end 267 end
256 end 268 end
257 269
258 return type_validators.table(schema, data) 270 return type_validators.table(schema, data, root)
259 end 271 end
260 return false 272 return false
261 end 273 end
262 274
263 json_schema_object.validate = validate; 275 json_schema_object.validate = validate;