mirror of
https://github.com/JHDev2006/Super-Mario-Bros.-Remastered-Public.git
synced 2025-10-22 15:38:14 +00:00
added the game
This commit is contained in:
516
addons/JSON_Schema_Validator/json_schema_validator.gd
Normal file
516
addons/JSON_Schema_Validator/json_schema_validator.gd
Normal file
@@ -0,0 +1,516 @@
|
||||
class_name JSONSchema
|
||||
extends RefCounted
|
||||
|
||||
|
||||
# JSON Schema main script
|
||||
# Inherits from Reference for easy use
|
||||
|
||||
const SMALL_FLOAT_THRESHOLD = 0.001
|
||||
const MAX_DECIMAL_PLACES = 3
|
||||
|
||||
const DEF_KEY_NAME = "schema root"
|
||||
const DEF_ERROR_STRING = "##error##"
|
||||
|
||||
const JST_ARRAY = "array"
|
||||
const JST_BOOLEAN = "boolean"
|
||||
const JST_INTEGER = "integer"
|
||||
const JST_NULL = "null"
|
||||
const JST_NUMBER = "number"
|
||||
const JST_OBJECT = "object"
|
||||
const JST_STRING = "string"
|
||||
|
||||
const JSKW_TYPE = "type"
|
||||
const JSKW_PROP = "properties"
|
||||
const JSKW_REQ = "required"
|
||||
const JSKW_TITLE = "title"
|
||||
const JSKW_DESCR = "description"
|
||||
const JSKW_DEFAULT = "default"
|
||||
const JSKW_EXAMPLES = "examples"
|
||||
const JSKW_COMMENT = "$comment"
|
||||
const JSKW_ENUM = "enum"
|
||||
const JSKW_CONST = "const"
|
||||
const JSKW_PREFIX_ITEMS = "prefixItems"
|
||||
const JSKW_ITEMS = "items"
|
||||
const JSKW_MIN_ITEMS = "minItems"
|
||||
const JSKW_MAX_ITEMS = "maxItems"
|
||||
const JSKW_CONTAINS = "contains"
|
||||
const JSKW_ADD_ITEMS = "additionalItems"
|
||||
const JSKW_UNIQUE_ITEMS = "uniqueItems"
|
||||
const JSKW_MULT_OF = "multipleOf"
|
||||
const JSKW_MINIMUM = "minimum"
|
||||
const JSKW_MIN_EX = "exclusiveMinimum"
|
||||
const JSKW_MAXIMUM = "maximum"
|
||||
const JSKW_MAX_EX = "exclusiveMaximum"
|
||||
const JSKW_PROP_ADD = "additionalProperties"
|
||||
const JSKW_PROP_PATTERN = "patternProperties"
|
||||
const JSKW_PROP_NAMES = "propertyNames"
|
||||
const JSKW_PROP_MIN = "minProperties"
|
||||
const JSKW_PROP_MAX = "maxProperties"
|
||||
const JSKW_DEPEND = "dependencies"
|
||||
const JSKW_LENGTH_MIN = "minLength"
|
||||
const JSKW_LENGTH_MAX = "maxLength"
|
||||
const JSKW_PATTERN = "pattern"
|
||||
const JSKW_FORMAT = "format"
|
||||
const JSKW_COLOR = "color"
|
||||
|
||||
const JSM_GREATER = "greater"
|
||||
const JSM_GREATER_EQ = "greater or equal"
|
||||
const JSM_LESS = "less"
|
||||
const JSM_LESS_EQ = "less or equal"
|
||||
const JSM_OBJ_DICT = "object (dictionary)"
|
||||
|
||||
const JSL_AND = "%s and %s"
|
||||
const JSL_OR = "%s or %s"
|
||||
|
||||
const ERR_SCHEMA_FALSE = "Schema declared as deny all"
|
||||
const ERR_WRONG_SCHEMA_GEN = "Schema error: "
|
||||
const ERR_WRONG_SCHEMA_TYPE = "Schema error: schema must be empty object or object with 'type' keyword or boolean value"
|
||||
const ERR_WRONG_SHEMA_NOTA = "Schema error: expected that all elements of '%s.%s' must be '%s'"
|
||||
const ERR_WRONG_PROP_TYPE = "Schema error: any schema item must be object with 'type' keyword"
|
||||
const ERR_REQ_PROP_GEN = "Schema error: expected array of required properties for '%s'"
|
||||
const ERR_REQ_PROP_MISSING = "Missing required property: '%s' for '%s'"
|
||||
const ERR_NO_PROP_ADD = "Additional properties are not required: found '%s'"
|
||||
const ERR_FEW_PROP = "%d propertie(s) are not enough properties, at least %d are required"
|
||||
const ERR_MORE_PROP = "%d propertie(s) are too many properties, at most %d are allowed"
|
||||
const ERR_FEW_ITEMS = "%s item(s) are not enough items, at least %s are required"
|
||||
const ERR_MORE_ITEMS = "%s item(s) are too many items, at most %s are allowed"
|
||||
const ERR_INVALID_JSON_GEN = "Validation fails with message: %s"
|
||||
const ERR_INVALID_JSON_EXT = "Invalid JSON data passed with message: %s"
|
||||
const ERR_TYPE_MISMATCH_GEN = "Type mismatch: expected %s for '%s'"
|
||||
const ERR_INVALID_NUMBER = "The %s key that equals %s should have a maximum of %s decimal places"
|
||||
const ERR_INVALID_MULT = "Multiplier in key %s that equals %s must be greater or equal to %s"
|
||||
const ERR_MULT_D = "Key %s that equal %d must be multiple of %d"
|
||||
const ERR_MULT_F = "Key %s that equal %f must be multiple of %f"
|
||||
const ERR_RANGE_D = "Key %s that equal %d must be %s than %d"
|
||||
const ERR_RANGE_F = "Key %s that equal %f must be %s than %f"
|
||||
const ERR_RANGE_S = "Length of '%s' (%d) %s than declared (%d)"
|
||||
const ERR_WRONG_PATTERN = "String '%s' does not match its corresponding pattern"
|
||||
const ERR_FORMAT = "String '%s' does not match its corresponding format '%s'"
|
||||
|
||||
# This is one and only function that need you to call outside
|
||||
# If all validation checks passes, this OK
|
||||
func validate(json_data : String, schema: String) -> String:
|
||||
var error: int
|
||||
|
||||
var json = JSON.new()
|
||||
# General validation input data as JSON file
|
||||
error = json.parse(json_data)
|
||||
if error: return ERR_INVALID_JSON_EXT % error_string(error)
|
||||
|
||||
# General validation input schema as JSONSchema file
|
||||
error = json.parse(schema)
|
||||
if not error == OK : return ERR_WRONG_SCHEMA_GEN + error_string(error)
|
||||
var test_json_conv = JSON.new()
|
||||
test_json_conv.parse(schema)
|
||||
var parsed_schema = test_json_conv.get_data()
|
||||
match typeof(parsed_schema):
|
||||
TYPE_BOOL:
|
||||
if !parsed_schema:
|
||||
return ERR_INVALID_JSON_GEN % ERR_SCHEMA_FALSE
|
||||
else:
|
||||
return ""
|
||||
TYPE_DICTIONARY:
|
||||
if parsed_schema.is_empty():
|
||||
return ""
|
||||
elif parsed_schema.keys().size() > 0 && !parsed_schema.has(JSKW_TYPE):
|
||||
return ERR_WRONG_SCHEMA_TYPE
|
||||
_: return ERR_WRONG_SCHEMA_TYPE
|
||||
|
||||
# All inputs seems valid. Begin type validation
|
||||
# Normal return empty string, meaning OK
|
||||
return _type_selection(json_data, parsed_schema)
|
||||
|
||||
func _to_string():
|
||||
return "[JSONSchema:%d]" % get_instance_id()
|
||||
|
||||
# TODO: title, description, default, examples, $comment, enum, const
|
||||
func _type_selection(json_data: String, schema: Dictionary, key: String = DEF_KEY_NAME) -> String:
|
||||
# If the schema is an empty object it always passes validation
|
||||
if schema.is_empty():
|
||||
return ""
|
||||
|
||||
if typeof(schema) == TYPE_BOOL:
|
||||
# If the schema is true it always passes validation
|
||||
if schema:
|
||||
return ""
|
||||
# If the schema is false it always vales validation
|
||||
else:
|
||||
return ERR_INVALID_JSON_GEN + "false is always invalid"
|
||||
|
||||
var typearr: Array = _var_to_array(schema.type)
|
||||
var test_json_conv = JSON.new()
|
||||
test_json_conv.parse(json_data)
|
||||
var parsed_data = test_json_conv.get_data()
|
||||
var error: String = ERR_TYPE_MISMATCH_GEN % [typearr, key]
|
||||
for type in typearr:
|
||||
match type:
|
||||
JST_ARRAY:
|
||||
if typeof(parsed_data) == TYPE_ARRAY:
|
||||
error = _validate_array(parsed_data, schema, key)
|
||||
else:
|
||||
error = ERR_TYPE_MISMATCH_GEN % [[JST_ARRAY], key]
|
||||
JST_BOOLEAN:
|
||||
if typeof(parsed_data) != TYPE_BOOL:
|
||||
return ERR_TYPE_MISMATCH_GEN % [[JST_BOOLEAN], key]
|
||||
else:
|
||||
error = ""
|
||||
JST_INTEGER:
|
||||
if typeof(parsed_data) == TYPE_INT:
|
||||
error = _validate_integer(parsed_data, schema, key)
|
||||
if typeof(parsed_data) == TYPE_FLOAT && parsed_data == int(parsed_data):
|
||||
error = _validate_integer(int(parsed_data), schema, key)
|
||||
JST_NULL:
|
||||
if typeof(parsed_data) != TYPE_NIL:
|
||||
return ERR_TYPE_MISMATCH_GEN % [[JST_NULL], key]
|
||||
else:
|
||||
error = ""
|
||||
JST_NUMBER:
|
||||
if typeof(parsed_data) == TYPE_FLOAT:
|
||||
error = _validate_number(parsed_data, schema, key)
|
||||
else:
|
||||
error = ERR_TYPE_MISMATCH_GEN % [[JST_NUMBER], key]
|
||||
JST_OBJECT:
|
||||
if typeof(parsed_data) == TYPE_DICTIONARY:
|
||||
error = _validate_object(parsed_data, schema, key)
|
||||
else:
|
||||
error = ERR_TYPE_MISMATCH_GEN % [[JST_OBJECT], key]
|
||||
JST_STRING:
|
||||
if typeof(parsed_data) == TYPE_STRING:
|
||||
error = _validate_string(parsed_data, schema, key)
|
||||
else:
|
||||
error = ERR_TYPE_MISMATCH_GEN % [[JST_STRING], key]
|
||||
return error
|
||||
|
||||
|
||||
func _var_to_array(variant) -> Array:
|
||||
var result : Array = []
|
||||
if typeof(variant) == TYPE_ARRAY:
|
||||
result = variant
|
||||
else:
|
||||
result.append(variant)
|
||||
return result
|
||||
|
||||
func _validate_array(input_data: Array, input_schema: Dictionary, property_name: String = DEF_KEY_NAME) -> String:
|
||||
# TODO: contains minContains maxContains uniqueItems
|
||||
|
||||
# Initialize variables
|
||||
var error : String = "" # Variable to store any error messages
|
||||
var items_array : Array # Array of items in the schema
|
||||
var suberror : Array = [] # Array of suberrors in each item
|
||||
var additional_items_schema: Dictionary # Schema for additional items in the input data
|
||||
var is_additional_item_allowed: bool # Flag to check if additional items are allowed
|
||||
|
||||
# Check if minItems key exists in the schema
|
||||
if input_schema.has(JSKW_MIN_ITEMS):
|
||||
# Check if non negative number
|
||||
if input_schema.minItems < 0:
|
||||
return ERR_WRONG_SCHEMA_GEN + "minItems must be a non-negative number."
|
||||
|
||||
if input_data.size() < input_schema.minItems:
|
||||
return ERR_FEW_ITEMS % [input_data.size(), input_schema.minItems]
|
||||
|
||||
# Check if maxItems key exists in the schema
|
||||
if input_schema.has(JSKW_MAX_ITEMS):
|
||||
# Check if non negative number
|
||||
if input_schema.maxItems < 0:
|
||||
return ERR_WRONG_SCHEMA_GEN + "minItems must be a non-negative number."
|
||||
|
||||
if input_data.size() > input_schema.maxItems:
|
||||
return ERR_MORE_ITEMS % [input_data.size(), input_schema.maxItems]
|
||||
|
||||
# Check if prefixItems key exists in the schema
|
||||
if input_schema.has(JSKW_PREFIX_ITEMS):
|
||||
# Check if items key exists in the schema
|
||||
if not input_schema.has(JSKW_ITEMS):
|
||||
return ERR_REQ_PROP_MISSING % [JSKW_ITEMS, JSKW_PREFIX_ITEMS]
|
||||
|
||||
# Return error if items key is not a bool or a dictionary
|
||||
if not typeof(input_schema.items) == TYPE_DICTIONARY and not typeof(input_schema.items) == TYPE_BOOL:
|
||||
return ERR_WRONG_SCHEMA_TYPE
|
||||
|
||||
if typeof(input_schema.items) == TYPE_BOOL:
|
||||
# Check if additional items in the input data are allowed
|
||||
if input_schema.items == false:
|
||||
# Check if there are more items in the input data than specified in prefixItems
|
||||
if input_data.size() > input_schema.prefixItems.size():
|
||||
# Create an error message if there are more items than allowed
|
||||
var substr := "Array '%s' is of size %s but no addition items allowed." % [input_data, input_data.size()]
|
||||
return ERR_INVALID_JSON_GEN % substr
|
||||
# If the 'items' key is set to true all types are allowed for addition items.
|
||||
else:
|
||||
additional_items_schema = {}
|
||||
|
||||
# Check if items key is a dictionary
|
||||
if typeof(input_schema.items) == TYPE_DICTIONARY:
|
||||
# Any items after the specified ones in prefixItems have to be validated with this schema
|
||||
# Set the schema for additional array items
|
||||
additional_items_schema = input_schema.items
|
||||
|
||||
# Check if all entries in prefixItems are a dictionary
|
||||
for schema in input_schema.prefixItems:
|
||||
if typeof(schema) != TYPE_DICTIONARY:
|
||||
return ERR_WRONG_SHEMA_NOTA % [property_name, JSKW_ITEMS, JST_OBJECT]
|
||||
|
||||
# Check every item in the input data
|
||||
for index in input_data.size():
|
||||
var item = input_data[index]
|
||||
var current_schema: Dictionary
|
||||
var key_substr: String
|
||||
|
||||
if index <= input_schema.prefixItems.size() - 1:
|
||||
# As long as there are prefixItems in the array work with those
|
||||
current_schema = input_schema.prefixItems[index]
|
||||
key_substr = ".prefixItems"
|
||||
else:
|
||||
# After that use the items schema
|
||||
current_schema = additional_items_schema
|
||||
key_substr = ".items"
|
||||
|
||||
var sub_error_message := _type_selection(JSON.stringify(item), current_schema, property_name + key_substr + "[" + str(index) + "]")
|
||||
if not sub_error_message == "":
|
||||
suberror.append(sub_error_message)
|
||||
|
||||
if suberror.size() > 0:
|
||||
return ERR_INVALID_JSON_GEN % str(suberror)
|
||||
|
||||
# Return inside this if block, because we don't want to validate the items key twice.
|
||||
return error
|
||||
|
||||
# Check if items key exists in the schema
|
||||
if input_schema.has(JSKW_ITEMS):
|
||||
#'items' must be an object
|
||||
if not typeof(input_schema.items) == TYPE_DICTIONARY:
|
||||
return ERR_WRONG_SHEMA_NOTA % [property_name, JSKW_ITEMS, JST_OBJECT]
|
||||
|
||||
# Check every item of input Array on
|
||||
for index in input_data.size():
|
||||
index = index - 1
|
||||
|
||||
# Validate the array item with the schema defined by the 'items' key
|
||||
var sub_error_message := _type_selection(JSON.stringify(input_data[index]), input_schema.items, property_name + "[" + str(index) + "]")
|
||||
if not sub_error_message == "":
|
||||
suberror.append(sub_error_message)
|
||||
|
||||
if suberror.size() > 0:
|
||||
return ERR_INVALID_JSON_GEN % str(suberror)
|
||||
|
||||
return error
|
||||
|
||||
func _validate_boolean(input_data: bool, input_schema: Dictionary, property_name: String = DEF_KEY_NAME) -> String:
|
||||
# nothing to check
|
||||
return ""
|
||||
|
||||
func _validate_integer(input_data: int, input_schema: Dictionary, property_name: String = DEF_KEY_NAME) -> String:
|
||||
# all processing is performed in
|
||||
return _validate_number(input_data, input_schema, property_name)
|
||||
|
||||
func _validate_null(input_data, input_schema: Dictionary, property_name: String = DEF_KEY_NAME) -> String:
|
||||
# nothing to check
|
||||
return ""
|
||||
|
||||
func _validate_number(input_data: float, input_schema: Dictionary, property_name: String = DEF_KEY_NAME) -> String:
|
||||
var types: Array = _var_to_array(input_schema.type)
|
||||
# integer mode turns on only if types has integer and has not number
|
||||
var integer_mode: bool = types.has(JST_INTEGER) && !types.has(JST_NUMBER)
|
||||
|
||||
# Processing multiple check
|
||||
if input_schema.has(JSKW_MULT_OF):
|
||||
var mult: float
|
||||
var mod: float
|
||||
var is_zero: bool
|
||||
|
||||
# Get the multipleOf value from the schema and convert to float
|
||||
mult = float(input_schema[JSKW_MULT_OF])
|
||||
# Convert to integer if integer_mode is enabled
|
||||
mult = int(mult) if integer_mode else mult
|
||||
|
||||
# Check if the number has more decimal places then allowed
|
||||
var decimal_places := str(input_data).get_slice('.', 1)
|
||||
if not decimal_places.is_empty() and decimal_places.length() > MAX_DECIMAL_PLACES:
|
||||
return ERR_INVALID_NUMBER % [property_name, input_data, str(MAX_DECIMAL_PLACES)]
|
||||
|
||||
# Check if multipleOf is smaller than SMALL_FLOAT_THRESHOLD
|
||||
if not mult >= SMALL_FLOAT_THRESHOLD:
|
||||
return ERR_INVALID_MULT % [property_name, mult, str(SMALL_FLOAT_THRESHOLD)]
|
||||
|
||||
# Multiply by a big number if input is smaller than 1 to prevent float issues
|
||||
if input_data < 1.0 or mult < 1.0:
|
||||
mod = fmod(input_data * 1000, mult * 1000)
|
||||
else:
|
||||
mod = fmod(input_data, mult)
|
||||
|
||||
# Check if the remainder is close to zero
|
||||
is_zero = is_zero_approx(mod)
|
||||
|
||||
# Return error message if remainder is not close to zero
|
||||
if not is_zero:
|
||||
if integer_mode:
|
||||
return ERR_MULT_D % [property_name, input_data, mult]
|
||||
else:
|
||||
return ERR_MULT_F % [property_name, input_data, mult]
|
||||
|
||||
# processing minimum check
|
||||
if input_schema.has(JSKW_MINIMUM):
|
||||
var minimum = float(input_schema[JSKW_MINIMUM])
|
||||
minimum = int(minimum) if integer_mode else minimum
|
||||
if input_data < minimum:
|
||||
if integer_mode:
|
||||
return ERR_RANGE_D % [property_name, input_data, JSM_GREATER_EQ, minimum]
|
||||
else:
|
||||
return ERR_RANGE_F % [property_name, input_data, JSM_GREATER_EQ, minimum]
|
||||
|
||||
# processing exclusive minimum check
|
||||
if input_schema.has(JSKW_MIN_EX):
|
||||
var minimum = float(input_schema[JSKW_MIN_EX])
|
||||
minimum = int(minimum) if integer_mode else minimum
|
||||
if input_data <= minimum:
|
||||
if integer_mode:
|
||||
return ERR_RANGE_D % [property_name, input_data, JSM_GREATER, minimum]
|
||||
else:
|
||||
return ERR_RANGE_F % [property_name, input_data, JSM_GREATER, minimum]
|
||||
|
||||
# processing maximum check
|
||||
if input_schema.has(JSKW_MAXIMUM):
|
||||
var maximum = float(input_schema[JSKW_MAXIMUM])
|
||||
maximum = int(maximum) if integer_mode else maximum
|
||||
if input_data > maximum:
|
||||
if integer_mode:
|
||||
return ERR_RANGE_D % [property_name, input_data, JSM_LESS_EQ, maximum]
|
||||
else:
|
||||
return ERR_RANGE_F % [property_name, input_data, JSM_LESS_EQ, maximum]
|
||||
|
||||
# processing exclusive minimum check
|
||||
if input_schema.has(JSKW_MAX_EX):
|
||||
var maximum = float(input_schema[JSKW_MAX_EX])
|
||||
maximum = int(maximum) if integer_mode else maximum
|
||||
if input_data >= maximum:
|
||||
if integer_mode:
|
||||
return ERR_RANGE_D % [property_name, input_data, JSM_LESS, maximum]
|
||||
else:
|
||||
return ERR_RANGE_F % [property_name, input_data, JSM_LESS, maximum]
|
||||
|
||||
return ""
|
||||
|
||||
func _validate_object(input_data: Dictionary, input_schema: Dictionary, property_name: String = DEF_KEY_NAME) -> String:
|
||||
# TODO: patternProperties
|
||||
var error : String = ""
|
||||
|
||||
# Process dependencies
|
||||
if input_schema.has(JSKW_DEPEND):
|
||||
for dependency in input_schema.dependencies.keys():
|
||||
if input_data.has(dependency):
|
||||
match typeof(input_schema.dependencies[dependency]):
|
||||
TYPE_ARRAY:
|
||||
if input_schema.has(JSKW_REQ):
|
||||
for property in input_schema.dependencies[dependency]:
|
||||
input_schema.required.append(property)
|
||||
else:
|
||||
input_schema.required = input_schema.dependencies[dependency]
|
||||
TYPE_DICTIONARY:
|
||||
for key in input_schema.dependencies[dependency].keys():
|
||||
if input_schema.has(key):
|
||||
match typeof(input_schema[key]):
|
||||
TYPE_ARRAY:
|
||||
for element in input_schema.dependencies[dependency][key]:
|
||||
input_schema[key].append(element)
|
||||
TYPE_DICTIONARY:
|
||||
for element in input_schema.dependencies[dependency][key].keys():
|
||||
input_schema[key][element] = input_schema.dependencies[dependency][key][element]
|
||||
_:
|
||||
input_schema[key] = input_schema.dependencies[dependency][key]
|
||||
else:
|
||||
input_schema[key] = input_schema.dependencies[dependency][key]
|
||||
_:
|
||||
return ERR_WRONG_SCHEMA_GEN + ERR_TYPE_MISMATCH_GEN % [JSL_OR % [JST_ARRAY, JSM_OBJ_DICT], property_name]
|
||||
|
||||
# Process properties
|
||||
if input_schema.has(JSKW_PROP):
|
||||
|
||||
# Process required
|
||||
if input_schema.has(JSKW_REQ):
|
||||
if typeof(input_schema.required) != TYPE_ARRAY: return ERR_REQ_PROP_GEN % property_name
|
||||
for i in input_schema.required:
|
||||
if !input_data.has(i): return ERR_REQ_PROP_MISSING % [i, property_name]
|
||||
|
||||
# Continue validating schema subelements
|
||||
if typeof(input_schema.properties) != TYPE_DICTIONARY:
|
||||
return ERR_WRONG_SCHEMA_GEN + ERR_TYPE_MISMATCH_GEN % [JSM_OBJ_DICT, property_name]
|
||||
|
||||
# Process property items
|
||||
for key in input_schema.properties:
|
||||
if !input_schema.properties[key].has(JSKW_TYPE):
|
||||
return ERR_WRONG_PROP_TYPE
|
||||
if input_data.has(key):
|
||||
error = _type_selection(JSON.stringify(input_data[key]), input_schema.properties[key], key)
|
||||
else:
|
||||
pass
|
||||
if error: return error
|
||||
|
||||
# Process additional properties
|
||||
if input_schema.has(JSKW_PROP_ADD):
|
||||
match typeof(input_schema.additionalProperties):
|
||||
TYPE_BOOL:
|
||||
if not input_schema.additionalProperties:
|
||||
for key in input_data:
|
||||
if not input_schema.properties.has(key):
|
||||
return ERR_NO_PROP_ADD % key
|
||||
TYPE_DICTIONARY:
|
||||
for key in input_data:
|
||||
if not input_schema.properties.has(key):
|
||||
return _type_selection(JSON.stringify(input_data[key]), input_schema.additionalProperties, key)
|
||||
_:
|
||||
return ERR_WRONG_SCHEMA_GEN + ERR_TYPE_MISMATCH_GEN % [JSL_OR % [JST_BOOLEAN, JSM_OBJ_DICT], property_name]
|
||||
|
||||
# Process properties names
|
||||
if input_schema.has(JSKW_PROP_NAMES):
|
||||
if typeof(input_schema.propertyNames) != TYPE_DICTIONARY:
|
||||
return ERR_WRONG_SCHEMA_GEN + ERR_TYPE_MISMATCH_GEN % [JSM_OBJ_DICT, property_name]
|
||||
for key in input_data:
|
||||
error = _validate_string(key, input_schema.propertyNames, key)
|
||||
if error: return error
|
||||
|
||||
# Process minProperties maxProperties
|
||||
if input_schema.has(JSKW_PROP_MIN):
|
||||
if typeof(input_schema[JSKW_PROP_MIN]) != TYPE_FLOAT:
|
||||
return ERR_WRONG_SCHEMA_GEN + ERR_TYPE_MISMATCH_GEN % [JST_INTEGER, property_name]
|
||||
if input_data.keys().size() < input_schema[JSKW_PROP_MIN]:
|
||||
return ERR_FEW_PROP % [input_data.keys().size(), input_schema[JSKW_PROP_MIN]]
|
||||
|
||||
if input_schema.has(JSKW_PROP_MAX):
|
||||
if typeof(input_schema[JSKW_PROP_MAX]) != TYPE_FLOAT:
|
||||
return ERR_WRONG_SCHEMA_GEN + ERR_TYPE_MISMATCH_GEN % [JST_INTEGER, property_name]
|
||||
if input_data.keys().size() > input_schema[JSKW_PROP_MAX]:
|
||||
return ERR_MORE_PROP % [input_data.keys().size(), input_schema[JSKW_PROP_MAX]]
|
||||
|
||||
return error
|
||||
|
||||
func _validate_string(input_data: String, input_schema: Dictionary, property_name: String = DEF_KEY_NAME) -> String:
|
||||
# TODO: format
|
||||
var error : String = ""
|
||||
if input_schema.has(JSKW_LENGTH_MIN):
|
||||
if not (typeof(input_schema[JSKW_LENGTH_MIN]) == TYPE_INT || typeof(input_schema[JSKW_LENGTH_MIN]) == TYPE_FLOAT):
|
||||
return ERR_TYPE_MISMATCH_GEN % [JST_INTEGER, property_name+"."+JSKW_LENGTH_MIN]
|
||||
if input_data.length() < input_schema[JSKW_LENGTH_MIN]:
|
||||
return ERR_INVALID_JSON_GEN % ERR_RANGE_S % [property_name, input_data.length(), JSM_LESS ,input_schema[JSKW_LENGTH_MIN]]
|
||||
|
||||
if input_schema.has(JSKW_LENGTH_MAX):
|
||||
if not (typeof(input_schema[JSKW_LENGTH_MAX]) == TYPE_INT || typeof(input_schema[JSKW_LENGTH_MAX]) == TYPE_FLOAT):
|
||||
return ERR_TYPE_MISMATCH_GEN % [JST_INTEGER, property_name+"."+JSKW_LENGTH_MAX]
|
||||
if input_data.length() > input_schema[JSKW_LENGTH_MAX]:
|
||||
return ERR_INVALID_JSON_GEN % ERR_RANGE_S % [property_name, input_data.length(), JSM_GREATER, input_schema[JSKW_LENGTH_MAX]]
|
||||
|
||||
if input_schema.has(JSKW_PATTERN):
|
||||
if not (typeof(input_schema[JSKW_PATTERN]) == TYPE_STRING):
|
||||
return ERR_TYPE_MISMATCH_GEN % [JST_STRING, property_name+"."+JSKW_PATTERN]
|
||||
var regex = RegEx.new()
|
||||
regex.compile(input_schema[JSKW_PATTERN])
|
||||
if regex.search(input_data) == null:
|
||||
return ERR_INVALID_JSON_GEN % ERR_WRONG_PATTERN % property_name
|
||||
|
||||
if input_schema.has(JSKW_FORMAT):
|
||||
# validate "color" format
|
||||
if input_schema.format.to_lower() == JSKW_COLOR:
|
||||
if not input_data.is_valid_html_color():
|
||||
return ERR_INVALID_JSON_GEN % ERR_FORMAT % [property_name, JSKW_COLOR]
|
||||
|
||||
return error
|
Reference in New Issue
Block a user