aboutsummaryrefslogtreecommitdiffstats
path: root/teal-src/util/jsonschema.tl
diff options
context:
space:
mode:
Diffstat (limited to 'teal-src/util/jsonschema.tl')
-rw-r--r--teal-src/util/jsonschema.tl374
1 files changed, 0 insertions, 374 deletions
diff --git a/teal-src/util/jsonschema.tl b/teal-src/util/jsonschema.tl
deleted file mode 100644
index 160c164c..00000000
--- a/teal-src/util/jsonschema.tl
+++ /dev/null
@@ -1,374 +0,0 @@
--- Copyright (C) 2021 Kim Alvefur
---
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
--- Based on
--- https://json-schema.org/draft/2020-12/json-schema-core.html
--- https://json-schema.org/draft/2020-12/json-schema-validation.html
---
-
-local json = require"util.json"
-local null = json.null;
-
-local pointer = require "util.jsonpointer"
-
-local type json_type_name = json.json_type_name
-
--- json_type_name here is non-standard
-local type schema_t = boolean | 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 | { json_type_name }
- enum : { any }
- const : any
-
- allOf : { schema_t }
- anyOf : { schema_t }
- oneOf : { schema_t }
-
- ["not"] : schema_t
- ["if"] : schema_t
- ["then"] : schema_t
- ["else"] : schema_t
-
- ["$ref"] : string
-
- -- numbers
- multipleOf : number
- maximum : number
- exclusiveMaximum : number
- minimum : number
- exclusiveMinimum : number
-
- -- strings
- maxLength : integer
- minLength : integer
- pattern : string -- NYI
- format : string
-
- -- arrays
- prefixItems : { schema_t }
- items : schema_t
- contains : schema_t
- maxItems : integer
- minItems : integer
- uniqueItems : boolean
- maxContains : integer -- NYI
- minContains : integer -- NYI
-
- -- objects
- properties : { string : schema_t }
- maxProperties : integer -- NYI
- minProperties : integer -- NYI
- required : { string }
- dependentRequired : { string : { string } }
- additionalProperties: schema_t
- patternProperties: schema_t -- NYI
- propertyNames : schema_t
-
- -- xml
- record xml_t
- name : string
- namespace : string
- prefix : string
- attribute : boolean
- wrapped : boolean
-
- -- nonstantard, maybe in the future
- text : boolean
- x_name_is_value : boolean
- x_single_attribute : string
- end
-
- xml : xml_t
-
- -- descriptive
- title : string
- description : string
- deprecated : boolean
- readOnly : boolean
- writeOnly : boolean
-
- -- methods
- validate : function ( schema_t, any, json_schema_object ) : boolean
-end
-
--- TODO validator function per schema property
-
-local function simple_validate(schema : json_type_name | { json_type_name }, data : any) : boolean
- if schema == nil then
- return true
- elseif 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
- elseif schema is { json_type_name } then
- for _, one in ipairs(schema as { json_type_name }) do
- if simple_validate(one, data) then
- return true
- end
- end
- return false
- else
- return type(data) == schema
- end
-end
-
-local complex_validate : function ( json_schema_object, any, json_schema_object ) : boolean
-
-local function validate (schema : schema_t, data : any, root : json_schema_object) : boolean
- if schema is boolean then
- return schema
- else
- return complex_validate(schema, data, root)
- end
-end
-
-function complex_validate (schema : json_schema_object, data : any, root : json_schema_object) : boolean
-
- if root == nil then
- root = schema
- end
-
- if schema["$ref"] and schema["$ref"]:sub(1,1) == "#" then
- local referenced = pointer.resolve(root as table, schema["$ref"]:sub(2)) as schema_t
- if referenced ~= nil and referenced ~= root and referenced ~= schema then
- if not validate(referenced, data, root) then
- return false;
- end
- end
- end
-
- if not simple_validate(schema.type, data) then
- return false;
- end
-
- if schema.type == "object" then
- if data is table then
- -- just check that there the keys are all strings
- for k in pairs(data) do
- if not k is string then
- return false
- end
- end
- end
- end
-
- if schema.type == "array" then
- if data is table then
- -- just check that there the keys are all numbers
- for i in pairs(data) do
- if not i is integer then
- return false
- end
- end
- end
- end
-
- if schema["enum"] ~= nil then
- local match = false
- for _, v in ipairs(schema["enum"]) do
- if v == data then
- -- FIXME supposed to do deep-compare
- match = true
- break
- end
- end
- if not match then
- return false
- end
- end
-
- -- XXX this is measured in byte, while JSON measures in ... bork
- -- TODO use utf8.len?
- if data is string then
- if schema.maxLength and #data > schema.maxLength then
- return false
- end
- if schema.minLength and #data < schema.minLength then
- return false
- end
- end
-
- if data is number then
- if schema.multipleOf and (data == 0 or data % schema.multipleOf ~= 0) then
- return false
- end
-
- if schema.maximum and not ( data <= schema.maximum ) then
- return false
- end
-
- if schema.exclusiveMaximum and not ( data < schema.exclusiveMaximum ) then
- return false
- end
-
- if schema.minimum and not ( data >= schema.minimum ) then
- return false
- end
-
- if schema.exclusiveMinimum and not ( data > schema.exclusiveMinimum ) then
- return false
- end
- end
-
- if schema.allOf then
- for _, sub in ipairs(schema.allOf) do
- if not validate(sub, data, root) then
- return false
- end
- end
- end
-
- if schema.oneOf then
- local valid = 0
- for _, sub in ipairs(schema.oneOf) do
- if validate(sub, data, root) then
- valid = valid + 1
- end
- end
- if valid ~= 1 then
- return false
- end
- end
-
- if schema.anyOf then
- local match = false
- for _, sub in ipairs(schema.anyOf) do
- if validate(sub, data, root) then
- match = true
- break
- end
- end
- if not match then
- return false
- end
- end
-
- if schema["not"] then
- if validate(schema["not"], data, root) then
- return false
- end
- end
-
- if schema["if"] ~= nil then
- if validate(schema["if"], data, root) then
- if schema["then"] then
- return validate(schema["then"], data, root)
- end
- else
- if schema["else"] then
- return validate(schema["else"], data, root)
- end
- end
- end
-
- if schema.const ~= nil and schema.const ~= data then
- return false
- end
-
- if data is table then
-
- if schema.maxItems and #data > schema.maxItems then
- return false
- end
-
- if schema.minItems and #data < schema.minItems then
- return false
- end
-
- if schema.required then
- for _, k in ipairs(schema.required) do
- if data[k] == nil then
- return false
- end
- end
- end
-
- if schema.propertyNames ~= nil then
- for k in pairs(data) do
- if not validate(schema.propertyNames, k, root) then
- return false
- end
- end
- end
-
- if schema.properties then
- for k, sub in pairs(schema.properties) do
- if data[k] ~= nil and not validate(sub, data[k], root) then
- return false
- end
- end
- end
-
- if schema.additionalProperties ~= nil then
- for k, v in pairs(data) do
- if schema.properties == nil or schema.properties[k as string] == nil then
- if not validate(schema.additionalProperties, v, root) then
- return false
- end
- end
- end
- end
-
- if schema.uniqueItems then
- -- only works for scalars, would need to deep-compare for objects/arrays/tables
- local values : { any : boolean } = {}
- for _, v in pairs(data) do
- if values[v] then
- return false
- end
- values[v] = true
- end
- end
-
- local p = 0
- if schema.prefixItems ~= nil then
- for i, s in ipairs(schema.prefixItems) do
- if data[i] == nil then
- break
- elseif validate(s, data[i], root) then
- p = i
- else
- return false
- end
- end
- end
-
- if schema.items ~= nil then
- for i = p+1, #data do
- if not validate(schema.items, data[i], root) then
- return false
- end
- end
- end
-
- if schema.contains ~= nil then
- local found = false
- for i = 1, #data do
- if validate(schema.contains, data[i], root) then
- found = true
- break
- end
- end
- if not found then
- return false
- end
- end
- end
-
- return true;
-end
-
-
-json_schema_object.validate = validate;
-
-return json_schema_object;