teal-src/util/jsonschema.tl
changeset 11464 a8b4e04bc044
parent 11463 86904555bffc
child 12136 4ff0d33dfb2b
--- a/teal-src/util/jsonschema.tl	Thu Mar 18 23:16:41 2021 +0100
+++ b/teal-src/util/jsonschema.tl	Thu Mar 18 23:57:03 2021 +0100
@@ -8,18 +8,19 @@
 -- https://json-schema.org/draft/2020-12/json-schema-validation.html
 --
 
-local record schema_t
-	enum type_e
-		"null"
-		"boolean"
-		"object"
-		"array"
-		"number"
-		"string"
-		"integer"
-	end
+local json = require"util.json"
+local null = json.null;
+
+local type json_type_name = json.json_type_name
 
-	type : type_e
+-- json_type_name here is non-standard
+local type schema_t = boolean | json_type_name | json_schema_object
+
+local record json_schema_object
+	type json_type_name = json.json_type_name
+	type schema_object = json_schema_object
+
+	type : json_type_name
 	enum : { any }
 	const : any
 
@@ -56,7 +57,7 @@
 	minContains : integer
 
 	-- objects
-	properties : { string : schema_t | type_e }
+	properties : { string : schema_t }
 	maxProperties : integer
 	minProperties : integer
 	required : { string }
@@ -87,26 +88,30 @@
 	deprecated : boolean
 	readOnly : boolean
 	writeOnly : boolean
+
+	-- methods
+	validate : function ( schema_t, any) : boolean
 end
-local type_e = schema_t.type_e
 
 -- TODO validator function per schema property
 
-local type_validators : { type_e : function (schema_t, any) : boolean } = {}
+local type_validators : { json_type_name : function (schema_t, any) : boolean } = {}
 
-local function simple_validate(schema : type_e, data : any) : boolean
+local function simple_validate(schema : json_type_name, data : any) : boolean
 	if schema == "object" and data is table then
 		return type(data) == "table" and (next(data)==nil or type((next(data, nil))) == "string")
 	elseif schema == "array" and data is table then
 		return type(data) == "table" and (next(data)==nil or type((next(data, nil))) == "number")
 	elseif schema == "integer" then
 		return math.type(data) == schema
+	elseif schema == "null" then
+		return data == null
 	else
 		return type(data) == schema
 	end
 end
 
-type_validators.string = function (schema : schema_t, data : any) : boolean
+type_validators.string = function (schema : json_schema_object, data : any) : boolean
 	-- XXX this is measured in byte, while JSON measures in ... bork
 	-- TODO use utf8.len?
 	if data is string then
@@ -121,7 +126,7 @@
 	return false
 end
 
-type_validators.number = function (schema : schema_t, data : number) : boolean
+type_validators.number = function (schema : json_schema_object, data : number) : boolean
 	if schema.multipleOf and data % schema.multipleOf ~= 0 then
 		return false
 	end
@@ -147,14 +152,14 @@
 
 type_validators.integer = type_validators.number
 
-local function validate(schema : schema_t | type_e | boolean, data : any) : boolean
+local function validate(schema : schema_t, data : any) : boolean
 	if schema is boolean then
 		return schema
 	end
-	if schema is type_e then
+	if schema is json_type_name then
 		return simple_validate(schema, data)
 	end
-	if schema is schema_t then
+	if schema is json_schema_object then
 		if schema.allOf then
 			for _, sub in ipairs(schema.allOf) do
 				if not validate(sub, data) then
@@ -228,7 +233,7 @@
 	end
 end
 
-type_validators.table = function (schema : schema_t, data : any) : boolean
+type_validators.table = function (schema : json_schema_object, data : any) : boolean
 	if data is table then
 
 		if schema.maxItems and #data > schema.maxItems then
@@ -248,12 +253,12 @@
 		end
 
 		if schema.properties then
-			local additional : schema_t | boolean = schema.additionalProperties or true
+			local additional : schema_t = schema.additionalProperties or true
 			for k, v in pairs(data) do
 				if schema.propertyNames and not validate(schema.propertyNames, k) then
 					return false
 				end
-				local s = schema.properties[k as string] or additional as schema_t
+				local s = schema.properties[k as string] or additional
 				if not validate(s, v) then
 					return false
 				end
@@ -345,7 +350,6 @@
 	return false
 end
 
-return {
-	validate = validate;
-	schema_t = schema_t;
-}
+json_schema_object.validate = validate;
+
+return json_schema_object;