summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--data/schemas/api_keyboard.jsonschema44
-rw-r--r--data/schemas/definitions.jsonschema107
-rw-r--r--data/schemas/keyboard.jsonschema263
-rw-r--r--keyboards/checkerboards/nop60/info.json138
-rw-r--r--keyboards/ramonimbao/chevron/info.json2
-rw-r--r--keyboards/sendyyeah/75pixels/info.json62
-rwxr-xr-xlib/python/qmk/cli/format/json.py5
-rw-r--r--lib/python/qmk/info.py6
-rw-r--r--lib/python/qmk/json_schema.py34
9 files changed, 351 insertions, 310 deletions
diff --git a/data/schemas/api_keyboard.jsonschema b/data/schemas/api_keyboard.jsonschema
index d570ee9990..d638658a1d 100644
--- a/data/schemas/api_keyboard.jsonschema
+++ b/data/schemas/api_keyboard.jsonschema
@@ -1,34 +1,22 @@
 {
+    "$id": "qmk.api.keyboard.v1",
     "allOf": [
-        { "$ref": "qmk.keyboard.v1" },
+        {"$ref": "qmk.keyboard.v1"},
         {
-            "$id": "qmk.api.keyboard.v1",
-            "keymaps": {
-                "type": "string"
-            },
-            "parse_errors": {
-                "type": "array",
-                "items": {
-                    "type": "string"
-                }
-            },
-            "parse_warnings": {
-                "type": "array",
-                "items": {
-                    "type": "string"
-                }
-            },
-            "processor_type": {
-                "type": "string"
-            },
-            "protocol": {
-                "type": "string"
-            },
-            "keyboard_folder": {
-                "type": "string"
-            },
-            "platform": {
-                "type": "string"
+            "properties": {
+                "keymaps": {
+                    "type": "object",
+                    "properties": {
+                        "url": {"type": "string"}
+                    }
+
+                },
+                "parse_errors": {"$ref": "qmk.definitions.v1#/string_array"},
+                "parse_warnings": {"$ref": "qmk.definitions.v1#/string_array"},
+                "processor_type": {"type": "string"},
+                "protocol": {"type": "string"},
+                "keyboard_folder": {"type": "string"},
+                "platform": {"type": "string"}
             }
         }
     ]
diff --git a/data/schemas/definitions.jsonschema b/data/schemas/definitions.jsonschema
new file mode 100644
index 0000000000..822f237073
--- /dev/null
+++ b/data/schemas/definitions.jsonschema
@@ -0,0 +1,107 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema#",
+    "$id": "qmk.definitions.v1",
+    "title": "Common definitions used across QMK's jsonschemas.",
+    "type": "object",
+    "boolean_array": {
+        "type": "object",
+        "additionalProperties": {"type": "boolean"}
+    },
+    "filename": {
+        "type": "string",
+        "minLength": 1,
+        "pattern": "^[0-9a-z_]*$"
+    },
+    "hex_number_2d": {
+        "type": "string",
+        "pattern": "^0x[0-9A-F]{2}$"
+    },
+    "hex_number_4d": {
+        "type": "string",
+        "pattern": "^0x[0-9A-F]{4}$"
+    },
+    "text_identifier": {
+        "type": "string",
+        "minLength": 1,
+        "maxLength": 250
+    },
+    "layout_macro": {
+        "oneOf": [
+            {
+                "type": "string",
+                "enum": ["LAYOUT", "LAYOUT_planck_1x2uC"]
+            },
+            {
+                "type": "string",
+                "pattern": "^LAYOUT_[0-9a-z_]*$"
+            }
+        ]
+    },
+    "key_unit": {
+        "type": "number",
+        "min": 0.25
+    },
+    "mcu_pin_array": {
+        "type": "array",
+        "items": {"$ref": "#/mcu_pin"}
+    },
+    "mcu_pin": {
+        "oneOf": [
+            {
+                "type": "string",
+                "pattern": "^[A-K]\\d{1,2}$"
+            },
+            {
+                "type": "string",
+                "pattern": "^LINE_PIN\\d{1,2}$"
+            },
+            {
+                "type": "number",
+                "multipleOf": 1
+            },
+            {
+                "type": "null"
+            }
+        ]
+    },
+    "signed_decimal": {
+        "type": "number"
+    },
+    "signed_int": {
+        "type": "number",
+        "multipleOf": 1
+    }
+    "signed_int_8": {
+        "type": "number",
+        "min": -127,
+        "max": 127,
+        "multipleOf": 1
+    }
+    "string_array": {
+        "type": "array",
+        "items": {
+            "type": "string"
+        }
+    },
+    "string_object": {
+        "type": "object",
+        "additionalProperties": {
+            "type": "string"
+        }
+    },
+    "unsigned_decimal": {
+        "type": "number",
+        "min": 0
+    },
+    "unsigned_int": {
+        "type": "number",
+        "min": 0,
+        "multipleOf": 1
+    }
+    "unsigned_int_8": {
+        "type": "number",
+        "min": 0,
+        "max": 255,
+        "multipleOf": 1
+    }
+}
diff --git a/data/schemas/keyboard.jsonschema b/data/schemas/keyboard.jsonschema
index 177bb0a961..d6d33ce4ec 100644
--- a/data/schemas/keyboard.jsonschema
+++ b/data/schemas/keyboard.jsonschema
@@ -1,24 +1,12 @@
 {
-    "$schema": "http://json-schema.org/schema#",
+    "$schema": "http://json-schema.org/draft-07/schema#",
     "$id": "qmk.keyboard.v1",
     "title": "Keyboard Information",
     "type": "object",
     "properties": {
-        "keyboard_name": {
-            "type": "string",
-            "minLength": 2,
-            "maxLength": 250
-        },
-        "maintainer": {
-            "type": "string",
-            "minLength": 2,
-            "maxLength": 250
-        },
-        "manufacturer": {
-            "type": "string",
-            "minLength": 2,
-            "maxLength": 250
-        },
+        "keyboard_name": {"$ref": "qmk.definitions.v1#/text_identifier"},
+        "maintainer": {"$ref": "qmk.definitions.v1#/text_identifier"},
+        "manufacturer": {"$ref": "qmk.definitions.v1#/text_identifier"},
         "url": {
             "type": "string",
             "format": "uri"
@@ -40,62 +28,25 @@
             "type": "string",
             "enum": ["COL2ROW", "ROW2COL"]
         },
-        "debounce": {
-            "type": "number",
-            "min": 0,
-            "multipleOf": 1
-        },
-        "height": {
-            "type": "number",
-            "min": 0.25
-        },
-        "width": {
-            "type": "number",
-            "min": 0.25
-        },
+        "debounce": {"$ref": "qmk.definitions.v1#/unsigned_int"},
+        "height": {"$ref": "qmk.definitions.v1#/key_unit"},
+        "width": {"$ref": "qmk.definitions.v1#/key_unit"},
         "community_layouts": {
             "type": "array",
-            "items": {
-                "type": "string",
-                "minLength": 2,
-                "pattern": "^[0-9a-z_]*$"
-            }
-        },
-        "features": {
-            "type": "object",
-            "additionalProperties": {"type": "boolean"}
+            "items": {"$ref": "qmk.definitions.v1#/filename"}
         },
+        "features": {"$ref": "qmk.definitions.v1#/boolean_array"},
         "indicators": {
             "type": "object",
             "properties": {
-                "caps_lock": {
-                    "type": "string",
-                    "pattern": "^[A-K]\\d{1,2}$"
-                },
-                "num_lock": {
-                    "type": "string",
-                    "pattern": "^[A-K]\\d{1,2}$"
-                },
-                "scroll_lock": {
-                    "type": "string",
-                    "pattern": "^[A-K]\\d{1,2}$"
-                }
+                "caps_lock": {"$ref": "qmk.definitions.v1#/mcu_pin"},
+                "num_lock": {"$ref": "qmk.definitions.v1#/mcu_pin"},
+                "scroll_lock": {"$ref": "qmk.definitions.v1#/mcu_pin"}
             }
         },
         "layout_aliases": {
             "type": "object",
-            "additionalProperties": {
-                "oneOf": [
-                    {
-                        "type": "string",
-                        "enum": ["LAYOUT", "LAYOUT_planck_1x2uC"]
-                    },
-                    {
-                        "type": "string",
-                        "pattern": "^LAYOUT_[0-9a-z_]*$"
-                    }
-                ]
-            }
+            "additionalProperties": {"$ref": "qmk.definitions.v1#/layout_macro"}
         },
         "layouts": {
             "type": "object",
@@ -109,11 +60,7 @@
                     "c_macro": {
                         "type": "boolean"
                     },
-                    "key_count": {
-                        "type": "number",
-                        "min": 0,
-                        "multipleOf": 1
-                    },
+                    "key_count": {"$ref": "qmk.definitions.v1#/key_unit"},
                     "layout": {
                         "type": "array",
                         "items": {
@@ -131,34 +78,14 @@
                                         "multipleOf": 1
                                     }
                                 },
-                                "h": {
-                                    "type": "number",
-                                    "min": 0.25
-                                },
-                                "r": {
-                                    "type": "number",
-                                    "min": 0
-                                },
-                                "rx": {
-                                    "type": "number",
-                                    "min": 0
-                                },
-                                "ry": {
-                                    "type": "number",
-                                    "min": 0
-                                },
-                                "w": {
-                                    "type": "number",
-                                    "min": 0.25
-                                },
-                                "x": {
-                                    "type": "number",
-                                    "min": 0
-                                },
-                                "y": {
-                                    "type": "number",
-                                    "min": 0
-                                }
+                                "key_count": {"$ref": "qmk.definitions.v1#/key_unit"},
+                                "r": {"$ref": "qmk.definitions.v1#/unsigned_decimal"},
+                                "rx": {"$ref": "qmk.definitions.v1#/unsigned_decimal"},
+                                "ry": {"$ref": "qmk.definitions.v1#/unsigned_decimal"},
+                                "h": {"$ref": "qmk.definitions.v1#/key_unit"},
+                                "w": {"$ref": "qmk.definitions.v1#/key_unit"},
+                                "x": {"$ref": "qmk.definitions.v1#/key_unit"},
+                                "y": {"$ref": "qmk.definitions.v1#/key_unit"}
                             }
                         }
                     }
@@ -171,73 +98,10 @@
             "properties": {
                 "direct": {
                     "type": "array",
-                    "items": {
-                        "type": "array",
-                        "items": {
-                            "oneOf": [
-                                {
-                                    "type": "string",
-                                    "pattern": "^[A-K]\\d{1,2}$"
-                                },
-                                {
-                                    "type": "string",
-                                    "pattern": "^LINE_PIN\\d{1,2}$"
-                                },
-                                {
-                                    "type": "number",
-                                    "multipleOf": 1
-                                },
-                                {
-                                    "type": "null"
-                                }
-                            ]
-                        }
-                    }
+                    "items": {$ref": "qmk.definitions.v1#/mcu_pin_array"}
                 },
-                "cols": {
-                    "type": "array",
-                    "items": {
-                        "oneOf": [
-                            {
-                                "type": "string",
-                                "pattern": "^[A-K]\\d{1,2}$"
-                            },
-                            {
-                                "type": "string",
-                                "pattern": "^LINE_PIN\\d{1,2}$"
-                            },
-                            {
-                                "type": "number",
-                                "multipleOf": 1
-                            },
-                            {
-                                "type": "null"
-                            }
-                        ]
-                    }
-                },
-                "rows": {
-                    "type": "array",
-                    "items": {
-                        "oneOf": [
-                            {
-                                "type": "string",
-                                "pattern": "^[A-K]\\d{1,2}$"
-                            },
-                            {
-                                "type": "string",
-                                "pattern": "^LINE_PIN\\d{1,2}$"
-                            },
-                            {
-                                "type": "number",
-                                "multipleOf": 1
-                            },
-                            {
-                                "type": "null"
-                            }
-                        ]
-                    }
-                }
+                "cols": {"$ref": "qmk.definitions.v1#/mcu_pin_array"},
+                "rows": {"$ref": "qmk.definitions.v1#/mcu_pin_array"}
             }
         },
         "rgblight": {
@@ -250,47 +114,19 @@
                         "type": "boolean"
                     }
                 },
-                "brightness_steps": {
-                    "type": "number",
-                    "min": 0,
-                    "multipleOf": 1
-                },
-                "hue_steps": {
-                    "type": "number",
-                    "min": 0,
-                    "multipleOf": 1
-                },
-                "led_count": {
-                    "type": "number",
-                    "min": 0,
-                    "multipleOf": 1
-                },
-                "max_brightness": {
-                    "type": "number",
-                    "min": 0,
-                    "max": 255,
-                    "multipleOf": 1
-                },
-                "pin": {
-                    "type": "string",
-                    "pattern": "^([A-K]\\d{1,2}|LINE_PIN\\d{1,2})$"
-                },
-                "saturation_steps": {
-                    "type": "number",
-                    "min": 0,
-                    "multipleOf": 1
-                },
+                "brightness_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"},
+                "hue_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"},
+                "led_count": {"$ref": "qmk.definitions.v1#/unsigned_int"},
+                "max_brightness": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
+                "pin": {"$ref": "qmk.definitions.v1#/mcu_pin"},
+                "saturation_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"},
                 "sleep": {"type": "boolean"},
                 "split": {"type": "boolean"},
                 "split_count": {
                     "type": "array",
                     "minLength": 2,
                     "maxLength": 2,
-                    "items": {
-                        "type": "number",
-                        "min": 0,
-                        "multipleOf": 1
-                    }
+                    "items": {"$ref": "qmk.definitions.v1#/unsigned_int"}
                 }
             }
         },
@@ -298,40 +134,19 @@
             "type": "object",
             "additionalProperties": false,
             "properties": {
-                "device_ver": {
-                    "type": "string",
-                    "pattern": "^[0-9A-F]x[0-9A-F][0-9A-F][0-9A-F][0-9A-F]"
-                },
-                "pid": {
-                    "type": "string",
-                    "pattern": "^[0-9A-F]x[0-9A-F][0-9A-F][0-9A-F][0-9A-F]"
-                },
-                "vid": {
-                    "type": "string",
-                    "pattern": "^[0-9A-F]x[0-9A-F][0-9A-F][0-9A-F][0-9A-F]"
-                }
+                "device_ver": {"$ref": "qmk.definitions.v1#/hex_number_4d"},
+                "pid": {"$ref": "qmk.definitions.v1#/hex_number_4d"},
+                "vid": {"$ref": "qmk.definitions.v1#/hex_number_4d"}
             }
         },
         "qmk_lufa_bootloader": {
             "type": "object",
             "additionalProperties": false,
             "properties": {
-                "esc_output": {
-                    "type": "string",
-                    "pattern": "^[A-K]\\d{1,2}$"
-                },
-                "esc_input": {
-                    "type": "string",
-                    "pattern": "^[A-K]\\d{1,2}$"
-                },
-                "led": {
-                    "type": "string",
-                    "pattern": "^[A-K]\\d{1,2}$"
-                },
-                "speaker": {
-                    "type": "string",
-                    "pattern": "^[A-K]\\d{1,2}$"
-                }
+                "esc_output": {"$ref": "qmk.definitions.v1#/mcu_pin"},
+                "esc_input": {"$ref": "qmk.definitions.v1#/mcu_pin"},
+                "led": {"$ref": "qmk.definitions.v1#/mcu_pin"},
+                "speaker": {"$ref": "qmk.definitions.v1#/mcu_pin"}
             }
         }
     }
diff --git a/keyboards/checkerboards/nop60/info.json b/keyboards/checkerboards/nop60/info.json
index 82ff7229fa..66e7706349 100644
--- a/keyboards/checkerboards/nop60/info.json
+++ b/keyboards/checkerboards/nop60/info.json
@@ -1,15 +1,143 @@
 {
     "keyboard_name": "nop60",
-    "url": "",
     "maintainer": "nasp",
-    "width": 15,
     "height": 5,
+    "width": 15,
+    "url": "",
     "layouts": {
         "LAYOUT": {
-            "2x3u": [{"label":"Esc", "x":0, "y":0}, {"label":"!", "x":1, "y":0}, {"label":"@", "x":2, "y":0}, {"label":"#", "x":3, "y":0}, {"label":"$", "x":4, "y":0}, {"label":"%", "x":5, "y":0}, {"label":"^", "x":6, "y":0}, {"label":"&", "x":7, "y":0}, {"label":"*", "x":8, "y":0}, {"label":"(", "x":9, "y":0}, {"label":")", "x":10, "y":0}, {"label":"_", "x":11, "y":0}, {"label":"+", "x":12, "y":0}, {"label":"~", "x":13, "y":0}, {"label":"Bksp", "x":14, "y":0}, {"label":"Tab", "x":0, "y":1, "w":1.5}, {"label":"Q", "x":1.5, "y":1}, {"label":"W", "x":2.5, "y":1}, {"label":"E", "x":3.5, "y":1}, {"label":"R", "x":4.5, "y":1}, {"label":"T", "x":5.5, "y":1}, {"label":"Y", "x":6.5, "y":1}, {"label":"U", "x":7.5, "y":1}, {"label":"I", "x":8.5, "y":1}, {"label":"O", "x":9.5, "y":1}, {"label":"P", "x":10.5, "y":1}, {"label":"{", "x":11.5, "y":1}, {"label":"}", "x":12.5, "y":1}, {"label":"|", "x":13.5, "y":1, "w":1.5}, {"label":"Caps Lock", "x":0, "y":2, "w":1.75}, {"label":"A", "x":1.75, "y":2}, {"label":"S", "x":2.75, "y":2}, {"label":"D", "x":3.75, "y":2}, {"label":"F", "x":4.75, "y":2}, {"label":"G", "x":5.75, "y":2}, {"label":"H", "x":6.75, "y":2}, {"label":"J", "x":7.75, "y":2}, {"label":"K", "x":8.75, "y":2}, {"label":"L", "x":9.75, "y":2}, {"label":":", "x":10.75, "y":2}, {"label":"\"", "x":11.75, "y":2}, {"label":"Enter", "x":12.75, "y":2, "w":2.25}, {"label":"Shift", "x":0, "y":3, "w":2.25}, {"label":"Z", "x":2.25, "y":3}, {"label":"X", "x":3.25, "y":3}, {"label":"C", "x":4.25, "y":3}, {"label":"V", "x":5.25, "y":3}, {"label":"B", "x":6.25, "y":3}, {"label":"N", "x":7.25, "y":3}, {"label":"M", "x":8.25, "y":3}, {"label":"<", "x":9.25, "y":3}, {"label":">", "x":10.25, "y":3}, {"label":"?", "x":11.25, "y":3}, {"label":"Shift", "x":12.25, "y":3, "w":1.75}, {"label":"Fn", "x":14, "y":3}, {"label":"Ctrl", "x":0, "y":4, "w":1.5}, {"label":"Win", "x":1.5, "y":4}, {"label":"Alt", "x":2.5, "y":4, "w":1.5}, {"x":4, "y":4, "w":3}, {"x":7, "y":4}, {"x":8, "y":4, "w":3}, {"label":"Alt", "x":11, "y":4, "w":1.5}, {"label":"Win", "x":12.5, "y":4}, {"label":"Ctrl", "x":13.5, "y":4, "w":1.5}]
+            "layout": [
+                { "label": "Esc", "x": 0, "y": 0 },
+                { "label": "!", "x": 1, "y": 0 },
+                { "label": "@", "x": 2, "y": 0 },
+                { "label": "#", "x": 3, "y": 0 },
+                { "label": "$", "x": 4, "y": 0 },
+                { "label": "%", "x": 5, "y": 0 },
+                { "label": "^", "x": 6, "y": 0 },
+                { "label": "&", "x": 7, "y": 0 },
+                { "label": "*", "x": 8, "y": 0 },
+                { "label": "(", "x": 9, "y": 0 },
+                { "label": ")", "x": 10, "y": 0 },
+                { "label": "_", "x": 11, "y": 0 },
+                { "label": "+", "x": 12, "y": 0 },
+                { "label": "~", "x": 13, "y": 0 },
+                { "label": "Bksp", "x": 14, "y": 0 },
+                { "label": "Tab", "w": 1.5, "x": 0, "y": 1 },
+                { "label": "Q", "x": 1.5, "y": 1 },
+                { "label": "W", "x": 2.5, "y": 1 },
+                { "label": "E", "x": 3.5, "y": 1 },
+                { "label": "R", "x": 4.5, "y": 1 },
+                { "label": "T", "x": 5.5, "y": 1 },
+                { "label": "Y", "x": 6.5, "y": 1 },
+                { "label": "U", "x": 7.5, "y": 1 },
+                { "label": "I", "x": 8.5, "y": 1 },
+                { "label": "O", "x": 9.5, "y": 1 },
+                { "label": "P", "x": 10.5, "y": 1 },
+                { "label": "{", "x": 11.5, "y": 1 },
+                { "label": "}", "x": 12.5, "y": 1 },
+                { "label": "|", "w": 1.5, "x": 13.5, "y": 1 },
+                { "label": "Caps Lock", "w": 1.75, "x": 0, "y": 2 },
+                { "label": "A", "x": 1.75, "y": 2 },
+                { "label": "S", "x": 2.75, "y": 2 },
+                { "label": "D", "x": 3.75, "y": 2 },
+                { "label": "F", "x": 4.75, "y": 2 },
+                { "label": "G", "x": 5.75, "y": 2 },
+                { "label": "H", "x": 6.75, "y": 2 },
+                { "label": "J", "x": 7.75, "y": 2 },
+                { "label": "K", "x": 8.75, "y": 2 },
+                { "label": "L", "x": 9.75, "y": 2 },
+                { "label": ":", "x": 10.75, "y": 2 },
+                { "label": "\"", "x": 11.75, "y": 2 },
+                { "label": "Enter", "w": 2.25, "x": 12.75, "y": 2 },
+                { "label": "Shift", "w": 2.25, "x": 0, "y": 3 },
+                { "label": "Z", "x": 2.25, "y": 3 },
+                { "label": "X", "x": 3.25, "y": 3 },
+                { "label": "C", "x": 4.25, "y": 3 },
+                { "label": "V", "x": 5.25, "y": 3 },
+                { "label": "B", "x": 6.25, "y": 3 },
+                { "label": "N", "x": 7.25, "y": 3 },
+                { "label": "M", "x": 8.25, "y": 3 },
+                { "label": "<", "x": 9.25, "y": 3 },
+                { "label": ">", "x": 10.25, "y": 3 },
+                { "label": "?", "x": 11.25, "y": 3 },
+                { "label": "Shift", "w": 1.75, "x": 12.25, "y": 3 },
+                { "label": "Fn", "x": 14, "y": 3 },
+                { "label": "Ctrl", "w": 1.5, "x": 0, "y": 4 },
+                { "label": "Win", "x": 1.5, "y": 4 },
+                { "label": "Alt", "w": 1.5, "x": 2.5, "y": 4 },
+                { "w": 7, "x": 4, "y": 4 },
+                { "label": "Alt", "w": 1.5, "x": 11, "y": 4 },
+                { "label": "Win", "x": 12.5, "y": 4 },
+                { "label": "Ctrl", "w": 1.5, "x": 13.5, "y": 4 }
+            ]
         },
-	    "LAYOUT": {
-            "7u": [{"label":"Esc", "x":0, "y":0}, {"label":"!", "x":1, "y":0}, {"label":"@", "x":2, "y":0}, {"label":"#", "x":3, "y":0}, {"label":"$", "x":4, "y":0}, {"label":"%", "x":5, "y":0}, {"label":"^", "x":6, "y":0}, {"label":"&", "x":7, "y":0}, {"label":"*", "x":8, "y":0}, {"label":"(", "x":9, "y":0}, {"label":")", "x":10, "y":0}, {"label":"_", "x":11, "y":0}, {"label":"+", "x":12, "y":0}, {"label":"~", "x":13, "y":0}, {"label":"Bksp", "x":14, "y":0}, {"label":"Tab", "x":0, "y":1, "w":1.5}, {"label":"Q", "x":1.5, "y":1}, {"label":"W", "x":2.5, "y":1}, {"label":"E", "x":3.5, "y":1}, {"label":"R", "x":4.5, "y":1}, {"label":"T", "x":5.5, "y":1}, {"label":"Y", "x":6.5, "y":1}, {"label":"U", "x":7.5, "y":1}, {"label":"I", "x":8.5, "y":1}, {"label":"O", "x":9.5, "y":1}, {"label":"P", "x":10.5, "y":1}, {"label":"{", "x":11.5, "y":1}, {"label":"}", "x":12.5, "y":1}, {"label":"|", "x":13.5, "y":1, "w":1.5}, {"label":"Caps Lock", "x":0, "y":2, "w":1.75}, {"label":"A", "x":1.75, "y":2}, {"label":"S", "x":2.75, "y":2}, {"label":"D", "x":3.75, "y":2}, {"label":"F", "x":4.75, "y":2}, {"label":"G", "x":5.75, "y":2}, {"label":"H", "x":6.75, "y":2}, {"label":"J", "x":7.75, "y":2}, {"label":"K", "x":8.75, "y":2}, {"label":"L", "x":9.75, "y":2}, {"label":":", "x":10.75, "y":2}, {"label":"\"", "x":11.75, "y":2}, {"label":"Enter", "x":12.75, "y":2, "w":2.25}, {"label":"Shift", "x":0, "y":3, "w":2.25}, {"label":"Z", "x":2.25, "y":3}, {"label":"X", "x":3.25, "y":3}, {"label":"C", "x":4.25, "y":3}, {"label":"V", "x":5.25, "y":3}, {"label":"B", "x":6.25, "y":3}, {"label":"N", "x":7.25, "y":3}, {"label":"M", "x":8.25, "y":3}, {"label":"<", "x":9.25, "y":3}, {"label":">", "x":10.25, "y":3}, {"label":"?", "x":11.25, "y":3}, {"label":"Shift", "x":12.25, "y":3, "w":1.75}, {"label":"Fn", "x":14, "y":3}, {"label":"Ctrl", "x":0, "y":4, "w":1.5}, {"label":"Win", "x":1.5, "y":4}, {"label":"Alt", "x":2.5, "y":4, "w":1.5}, {"x":4, "y":4, "w":7}, {"label":"Alt", "x":11, "y":4, "w":1.5}, {"label":"Win", "x":12.5, "y":4}, {"label":"Ctrl", "x":13.5, "y":4, "w":1.5}]
+        "LAYOUT_2x3u": {
+            "layout": [
+                { "label": "Esc", "x": 0, "y": 0 },
+                { "label": "!", "x": 1, "y": 0 },
+                { "label": "@", "x": 2, "y": 0 },
+                { "label": "#", "x": 3, "y": 0 },
+                { "label": "$", "x": 4, "y": 0 },
+                { "label": "%", "x": 5, "y": 0 },
+                { "label": "^", "x": 6, "y": 0 },
+                { "label": "&", "x": 7, "y": 0 },
+                { "label": "*", "x": 8, "y": 0 },
+                { "label": "(", "x": 9, "y": 0 },
+                { "label": ")", "x": 10, "y": 0 },
+                { "label": "_", "x": 11, "y": 0 },
+                { "label": "+", "x": 12, "y": 0 },
+                { "label": "~", "x": 13, "y": 0 },
+                { "label": "Bksp", "x": 14, "y": 0 },
+                { "label": "Tab", "w": 1.5, "x": 0, "y": 1 },
+                { "label": "Q", "x": 1.5, "y": 1 },
+                { "label": "W", "x": 2.5, "y": 1 },
+                { "label": "E", "x": 3.5, "y": 1 },
+                { "label": "R", "x": 4.5, "y": 1 },
+                { "label": "T", "x": 5.5, "y": 1 },
+                { "label": "Y", "x": 6.5, "y": 1 },
+                { "label": "U", "x": 7.5, "y": 1 },
+                { "label": "I", "x": 8.5, "y": 1 },
+                { "label": "O", "x": 9.5, "y": 1 },
+                { "label": "P", "x": 10.5, "y": 1 },
+                { "label": "{", "x": 11.5, "y": 1 },
+                { "label": "}", "x": 12.5, "y": 1 },
+                { "label": "|", "w": 1.5, "x": 13.5, "y": 1 },
+                { "label": "Caps Lock", "w": 1.75, "x": 0, "y": 2 },
+                { "label": "A", "x": 1.75, "y": 2 },
+                { "label": "S", "x": 2.75, "y": 2 },
+                { "label": "D", "x": 3.75, "y": 2 },
+                { "label": "F", "x": 4.75, "y": 2 },
+                { "label": "G", "x": 5.75, "y": 2 },
+                { "label": "H", "x": 6.75, "y": 2 },
+                { "label": "J", "x": 7.75, "y": 2 },
+                { "label": "K", "x": 8.75, "y": 2 },
+                { "label": "L", "x": 9.75, "y": 2 },
+                { "label": ":", "x": 10.75, "y": 2 },
+                { "label": "\"", "x": 11.75, "y": 2 },
+                { "label": "Enter", "w": 2.25, "x": 12.75, "y": 2 },
+                { "label": "Shift", "w": 2.25, "x": 0, "y": 3 },
+                { "label": "Z", "x": 2.25, "y": 3 },
+                { "label": "X", "x": 3.25, "y": 3 },
+                { "label": "C", "x": 4.25, "y": 3 },
+                { "label": "V", "x": 5.25, "y": 3 },
+                { "label": "B", "x": 6.25, "y": 3 },
+                { "label": "N", "x": 7.25, "y": 3 },
+                { "label": "M", "x": 8.25, "y": 3 },
+                { "label": "<", "x": 9.25, "y": 3 },
+                { "label": ">", "x": 10.25, "y": 3 },
+                { "label": "?", "x": 11.25, "y": 3 },
+                { "label": "Shift", "w": 1.75, "x": 12.25, "y": 3 },
+                { "label": "Fn", "x": 14, "y": 3 },
+                { "label": "Ctrl", "w": 1.5, "x": 0, "y": 4 },
+                { "label": "Win", "x": 1.5, "y": 4 },
+                { "label": "Alt", "w": 1.5, "x": 2.5, "y": 4 },
+                { "w": 3, "x": 4, "y": 4 },
+                { "x": 7, "y": 4 },
+                { "w": 3, "x": 8, "y": 4 },
+                { "label": "Alt", "w": 1.5, "x": 11, "y": 4 },
+                { "label": "Win", "x": 12.5, "y": 4 },
+                { "label": "Ctrl", "w": 1.5, "x": 13.5, "y": 4 }
+            ]
         }
     }
 }
diff --git a/keyboards/ramonimbao/chevron/info.json b/keyboards/ramonimbao/chevron/info.json
index 11ed02e53b..2a88fedb16 100644
--- a/keyboards/ramonimbao/chevron/info.json
+++ b/keyboards/ramonimbao/chevron/info.json
@@ -1,7 +1,5 @@
 {
     "keyboard_name": "Chevron",
-    "url": "",
-    "maintainer": "",
     "width": 14.5,
     "height": 5,
     "layouts": {
diff --git a/keyboards/sendyyeah/75pixels/info.json b/keyboards/sendyyeah/75pixels/info.json
index 20d158cf74..d952cac134 100644
--- a/keyboards/sendyyeah/75pixels/info.json
+++ b/keyboards/sendyyeah/75pixels/info.json
@@ -7,7 +7,7 @@
     "layouts": {
         "LAYOUT_ortho_5x15": {
             "layout": [
-                {"label": "Esc", "X": 0, "y": 0},
+                {"label": "Esc", "x": 0, "y": 0},
                 {"label": "1", "x": 1, "y": 0},
                 {"label": "2", "x": 2, "y": 0},
                 {"label": "3", "x": 3, "y": 0},
@@ -22,21 +22,21 @@
                 {"label": "NumLock", "x": 12, "y": 0},
                 {"label": "/", "x": 13, "y": 0},
                 {"label": "*", "x": 14, "y": 0},
-                {"label": "Tab", "X": 0, "y": 1},
-                {"label": "Q", "X": 1, "y": 1},
-                {"label": "W", "X": 2, "y": 1},
-                {"label": "E", "X": 3, "y": 1},
-                {"label": "R", "X": 4, "y": 1},
-                {"label": "T", "X": 5, "y": 1},
-                {"label": "Y", "X": 6, "y": 1},
-                {"label": "U", "X": 7, "y": 1},
-                {"label": "I", "X": 8, "y": 1},
-                {"label": "O", "X": 9, "y": 1},
-                {"label": "P", "X": 10, "y": 1},
-                {"label": "|\n\\", "X": 11, "y": 1},
-                {"label": "7\nHome", "X": 12, "y": 1},
-                {"label": "8\nUp", "X": 13, "y": 1},
-                {"label": "9\nPgUp", "X": 14, "y": 1},
+                {"label": "Tab", "x": 0, "y": 1},
+                {"label": "Q", "x": 1, "y": 1},
+                {"label": "W", "x": 2, "y": 1},
+                {"label": "E", "x": 3, "y": 1},
+                {"label": "R", "x": 4, "y": 1},
+                {"label": "T", "x": 5, "y": 1},
+                {"label": "Y", "x": 6, "y": 1},
+                {"label": "U", "x": 7, "y": 1},
+                {"label": "I", "x": 8, "y": 1},
+                {"label": "O", "x": 9, "y": 1},
+                {"label": "P", "x": 10, "y": 1},
+                {"label": "|\n\\", "x": 11, "y": 1},
+                {"label": "7\nHome", "x": 12, "y": 1},
+                {"label": "8\nUp", "x": 13, "y": 1},
+                {"label": "9\nPgUp", "x": 14, "y": 1},
                 {"label": "Caps", "x": 0, "y": 2},
                 {"label": "A", "x": 1, "y": 2},
                 {"label": "S", "x": 2, "y": 2},
@@ -67,21 +67,21 @@
                 {"label": "1\nEnd", "x": 12, "y": 3},
                 {"label": "2\nDown", "x": 13, "y": 3},
                 {"label": "3\nPgDn", "x": 14, "y": 3},
-                {"label": "Ctrl", "X": 0, "y": 4},
-                {"label": "Win", "X": 1, "y": 4},
-                {"label": "Alt", "X": 2, "y": 4},
-                {"label": "Fn", "X": 3, "y": 4},
-                {"label": "Lower", "X": 4, "y": 4},
-                {"label": "Space", "X": 5, "y": 4},
-                {"label": "Space", "X": 6, "y": 4},
-                {"label": "Raise", "X": 7, "y": 4},
-                {"label": "Alt", "X": 8, "y": 4},
-                {"label": "Win", "X": 9, "y": 4},
-                {"label": "Menu", "X": 10, "y": 4},
-                {"label": "Ctrl", "X": 11, "y": 4},
-                {"label": "0\nIns", "X": 12, "y": 4},
-                {"label": ".\nDel", "X": 13, "y": 4},
-                {"label": "Enter", "X": 14, "y": 4}
+                {"label": "Ctrl", "x": 0, "y": 4},
+                {"label": "Win", "x": 1, "y": 4},
+                {"label": "Alt", "x": 2, "y": 4},
+                {"label": "Fn", "x": 3, "y": 4},
+                {"label": "Lower", "x": 4, "y": 4},
+                {"label": "Space", "x": 5, "y": 4},
+                {"label": "Space", "x": 6, "y": 4},
+                {"label": "Raise", "x": 7, "y": 4},
+                {"label": "Alt", "x": 8, "y": 4},
+                {"label": "Win", "x": 9, "y": 4},
+                {"label": "Menu", "x": 10, "y": 4},
+                {"label": "Ctrl", "x": 11, "y": 4},
+                {"label": "0\nIns", "x": 12, "y": 4},
+                {"label": ".\nDel", "x": 13, "y": 4},
+                {"label": "Enter", "x": 14, "y": 4}
             ]
         }
     }
diff --git a/lib/python/qmk/cli/format/json.py b/lib/python/qmk/cli/format/json.py
index 1358c70e7a..19d504491f 100755
--- a/lib/python/qmk/cli/format/json.py
+++ b/lib/python/qmk/cli/format/json.py
@@ -8,7 +8,7 @@ from jsonschema import ValidationError
 from milc import cli
 
 from qmk.info import info_json
-from qmk.json_schema import json_load, keyboard_validate
+from qmk.json_schema import json_load, validate
 from qmk.json_encoders import InfoJSONEncoder, KeymapJSONEncoder
 from qmk.path import normpath
 
@@ -23,14 +23,13 @@ def format_json(cli):
 
     if cli.args.format == 'auto':
         try:
-            keyboard_validate(json_file)
+            validate(json_file, 'qmk.keyboard.v1')
             json_encoder = InfoJSONEncoder
 
         except ValidationError as e:
             cli.log.warning('File %s did not validate as a keyboard:\n\t%s', cli.args.json_file, e)
             cli.log.info('Treating %s as a keymap file.', cli.args.json_file)
             json_encoder = KeymapJSONEncoder
-
     elif cli.args.format == 'keyboard':
         json_encoder = InfoJSONEncoder
     elif cli.args.format == 'keymap':
diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py
index a70bd4c31c..5525f0fe6b 100644
--- a/lib/python/qmk/info.py
+++ b/lib/python/qmk/info.py
@@ -9,7 +9,7 @@ from milc import cli
 
 from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS
 from qmk.c_parse import find_layouts
-from qmk.json_schema import deep_update, json_load, keyboard_validate, keyboard_api_validate
+from qmk.json_schema import deep_update, json_load, validate
 from qmk.keyboard import config_h, rules_mk
 from qmk.keymap import list_keymaps
 from qmk.makefile import parse_rules_mk_file
@@ -66,7 +66,7 @@ def info_json(keyboard):
 
     # Validate against the jsonschema
     try:
-        keyboard_api_validate(info_data)
+        validate(info_data, 'qmk.api.keyboard.v1')
 
     except jsonschema.ValidationError as e:
         json_path = '.'.join([str(p) for p in e.absolute_path])
@@ -490,7 +490,7 @@ def merge_info_jsons(keyboard, info_data):
             continue
 
         try:
-            keyboard_validate(new_info_data)
+            validate(new_info_data, 'qmk.keyboard.v1')
         except jsonschema.ValidationError as e:
             json_path = '.'.join([str(p) for p in e.absolute_path])
             cli.log.error('Not including data from file: %s', info_file)
diff --git a/lib/python/qmk/json_schema.py b/lib/python/qmk/json_schema.py
index 077dfcaa93..3e5663a291 100644
--- a/lib/python/qmk/json_schema.py
+++ b/lib/python/qmk/json_schema.py
@@ -24,9 +24,10 @@ def json_load(json_file):
 
 def load_jsonschema(schema_name):
     """Read a jsonschema file from disk.
-
-    FIXME(skullydazed/anyone): Refactor to make this a public function.
     """
+    if Path(schema_name).exists():
+        return json_load(schema_name)
+
     schema_path = Path(f'data/schemas/{schema_name}.jsonschema')
 
     if not schema_path.exists():
@@ -35,28 +36,33 @@ def load_jsonschema(schema_name):
     return json_load(schema_path)
 
 
-def keyboard_validate(data):
-    """Validates data against the keyboard jsonschema.
+def create_validator(schema):
+    """Creates a validator for the given schema id.
     """
-    schema = load_jsonschema('keyboard')
-    validator = jsonschema.Draft7Validator(schema).validate
+    schema_store = {}
 
-    return validator(data)
+    for schema_file in Path('data/schemas').glob('*.jsonschema'):
+        schema_data = load_jsonschema(schema_file)
+        if not isinstance(schema_data, dict):
+            cli.log.debug('Skipping schema file %s', schema_file)
+            continue
+        schema_store[schema_data['$id']] = schema_data
+
+    resolver = jsonschema.RefResolver.from_schema(schema_store['qmk.keyboard.v1'], store=schema_store)
+
+    return jsonschema.Draft7Validator(schema_store[schema], resolver=resolver).validate
 
 
-def keyboard_api_validate(data):
-    """Validates data against the api_keyboard jsonschema.
+def validate(data, schema):
+    """Validates data against a schema.
     """
-    base = load_jsonschema('keyboard')
-    relative = load_jsonschema('api_keyboard')
-    resolver = jsonschema.RefResolver.from_schema(base)
-    validator = jsonschema.Draft7Validator(relative, resolver=resolver).validate
+    validator = create_validator(schema)
 
     return validator(data)
 
 
 def deep_update(origdict, newdict):
-    """Update a dictionary in place, recursing to do a deep copy.
+    """Update a dictionary in place, recursing to do a depth-first deep copy.
     """
     for key, value in newdict.items():
         if isinstance(value, Mapping):