From f44a988476bad8c65acc883ce1568c97be8a4a57 Mon Sep 17 00:00:00 2001 From: zvecr Date: Mon, 23 May 2022 20:02:14 +0100 Subject: [PATCH] Initial validation of xap.hjson --- data/schemas/xap.jsonschema | 254 +++++++++++++++++++++++++++++++++++ lib/python/qmk/xap/common.py | 14 +- 2 files changed, 266 insertions(+), 2 deletions(-) create mode 100644 data/schemas/xap.jsonschema diff --git a/data/schemas/xap.jsonschema b/data/schemas/xap.jsonschema new file mode 100644 index 00000000000..9994778d092 --- /dev/null +++ b/data/schemas/xap.jsonschema @@ -0,0 +1,254 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "qmk.xap.v1", + "title": "XAP Spec", + "definitions": { + "data_type": { + "oneOf": [ + { + "enum": [ + "bool", + "u8", + "u16", + "u32", + "u64", + "struct", + "string" + ] + }, + { + "type": "string", + "pattern": "^u\\d{1,2}\\[\\d{1,2}\\]*$" + } + ] + }, + "router_type": { + "enum": [ + "command", + "router" + ] + }, + "permission": { + "enum": [ + "secure", + "ignore" + ] + }, + "struct": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + } + } + } + }, + "route": { + "type": "object", + "propertyNames": { + "$ref": "qmk.definitions.v1#/hex_number_2d" + }, + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "$ref": "#/definitions/router_type" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "define": { + "type": "string" + }, + "permissions": { + "$ref": "#/definitions/permission" + }, + "enable_if_preprocessor": { + "type": "string" + }, + "request_type": { + "$ref": "#/definitions/data_type" + }, + "request_struct_length": { + "type": "number" + }, + "request_purpose": { + "type": "string" + }, + "return_type": { + "$ref": "#/definitions/data_type" + }, + "request_struct_members": { + "$ref": "#definitions/struct" + }, + "return_struct_length": { + "type": "number" + }, + "return_constant": { + "type": [ + "array", + "string" + ] + }, + "return_struct_members": { + "$ref": "#definitions/struct" + }, + "return_purpose": { + "type": "string" + }, + "return_execute": { + "type": "string" + }, + "routes": { + "$ref": "#/definitions/route" + } + } + } + } + }, + "type": "object", + "additionalProperties": false, + "required": [ + "version" + ], + "properties": { + "version": { + "$ref": "qmk.definitions.v1#/bcd_version" + }, + "define": { + "type": "string" + }, + "uses": { + "type": "object", + "additionalProperties": { + "$ref": "qmk.definitions.v1#/bcd_version" + } + }, + "documentation": { + "type": "object", + "properties": { + "order": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": { + "type": "string" + } + }, + "term_definitions": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "type_docs": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "type_definitions": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/data_type" + }, + "struct_length": { + "type": "number" + }, + "struct_members": { + "$ref": "#definitions/struct" + } + } + } + }, + "response_flags": { + "type": "object", + "additionalProperties": false, + "properties": { + "define_prefix": { + "type": "string" + }, + "bits": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "define": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + } + } + }, + "broadcast_messages": { + "type": "object", + "additionalProperties": false, + "properties": { + "define_prefix": { + "type": "string" + }, + "messages": { + "type": "object", + "propertyNames": { + "$ref": "qmk.definitions.v1#/hex_number_2d" + }, + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "define": { + "type": "string" + }, + "description": { + "type": "string" + }, + "return_type": { + "$ref": "#/definitions/data_type" + } + } + } + } + } + }, + "routes": { + "$ref": "#/definitions/route" + } + } +} \ No newline at end of file diff --git a/lib/python/qmk/xap/common.py b/lib/python/qmk/xap/common.py index f3f371cdd8e..64372db804e 100755 --- a/lib/python/qmk/xap/common.py +++ b/lib/python/qmk/xap/common.py @@ -2,12 +2,13 @@ """ import os import hjson +import jsonschema from pathlib import Path from typing import OrderedDict from jinja2 import Environment, FileSystemLoader, select_autoescape from qmk.constants import QMK_FIRMWARE -from qmk.json_schema import json_load +from qmk.json_schema import json_load, validate from qmk.decorators import lru_cache from qmk.keymap import locate_keymap from qmk.path import keyboard @@ -135,7 +136,16 @@ def merge_xap_defs(kb, km): if km_xap.exists(): definitions.append({'routes': {'0x03': hjson.load(km_xap.open(encoding='utf-8'))}}) - return _merge_ordered_dicts(definitions) + defs = _merge_ordered_dicts(definitions) + + try: + validate(defs, 'qmk.xap.v1') + + except jsonschema.ValidationError as e: + print(f'Invalid XAP spec: {e.message}') + exit(1) + + return defs @lru_cache(timeout=5)