aboutsummaryrefslogtreecommitdiff
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 d570ee999..d638658a1 100644
--- a/data/schemas/api_keyboard.jsonschema
+++ b/data/schemas/api_keyboard.jsonschema
@@ -1,34 +1,22 @@
1{ 1{
2 "$id": "qmk.api.keyboard.v1",
2 "allOf": [ 3 "allOf": [
3 { "$ref": "qmk.keyboard.v1" }, 4 {"$ref": "qmk.keyboard.v1"},
4 { 5 {
5 "$id": "qmk.api.keyboard.v1", 6 "properties": {
6 "keymaps": { 7 "keymaps": {
7 "type": "string" 8 "type": "object",
8 }, 9 "properties": {
9 "parse_errors": { 10 "url": {"type": "string"}
10 "type": "array", 11 }
11 "items": { 12
12 "type": "string" 13 },
13 } 14 "parse_errors": {"$ref": "qmk.definitions.v1#/string_array"},
14 }, 15 "parse_warnings": {"$ref": "qmk.definitions.v1#/string_array"},
15 "parse_warnings": { 16 "processor_type": {"type": "string"},
16 "type": "array", 17 "protocol": {"type": "string"},
17 "items": { 18 "keyboard_folder": {"type": "string"},
18 "type": "string" 19 "platform": {"type": "string"}
19 }
20 },
21 "processor_type": {
22 "type": "string"
23 },
24 "protocol": {
25 "type": "string"
26 },
27 "keyboard_folder": {
28 "type": "string"
29 },
30 "platform": {
31 "type": "string"
32 } 20 }
33 } 21 }
34 ] 22 ]
diff --git a/data/schemas/definitions.jsonschema b/data/schemas/definitions.jsonschema
new file mode 100644
index 000000000..822f23707
--- /dev/null
+++ b/data/schemas/definitions.jsonschema
@@ -0,0 +1,107 @@
1{
2 "$schema": "http://json-schema.org/draft-07/schema#",
3 "$id": "qmk.definitions.v1",
4 "title": "Common definitions used across QMK's jsonschemas.",
5 "type": "object",
6 "boolean_array": {
7 "type": "object",
8 "additionalProperties": {"type": "boolean"}
9 },
10 "filename": {
11 "type": "string",
12 "minLength": 1,
13 "pattern": "^[0-9a-z_]*$"
14 },
15 "hex_number_2d": {
16 "type": "string",
17 "pattern": "^0x[0-9A-F]{2}$"
18 },
19 "hex_number_4d": {
20 "type": "string",
21 "pattern": "^0x[0-9A-F]{4}$"
22 },
23 "text_identifier": {
24 "type": "string",
25 "minLength": 1,
26 "maxLength": 250
27 },
28 "layout_macro": {
29 "oneOf": [
30 {
31 "type": "string",
32 "enum": ["LAYOUT", "LAYOUT_planck_1x2uC"]
33 },
34 {
35 "type": "string",
36 "pattern": "^LAYOUT_[0-9a-z_]*$"
37 }
38 ]
39 },
40 "key_unit": {
41 "type": "number",
42 "min": 0.25
43 },
44 "mcu_pin_array": {
45 "type": "array",
46 "items": {"$ref": "#/mcu_pin"}
47 },
48 "mcu_pin": {
49 "oneOf": [
50 {
51 "type": "string",
52 "pattern": "^[A-K]\\d{1,2}$"
53 },
54 {
55 "type": "string",
56 "pattern": "^LINE_PIN\\d{1,2}$"
57 },
58 {
59 "type": "number",
60 "multipleOf": 1
61 },
62 {
63 "type": "null"
64 }
65 ]
66 },
67 "signed_decimal": {
68 "type": "number"
69 },
70 "signed_int": {
71 "type": "number",
72 "multipleOf": 1
73 }
74 "signed_int_8": {
75 "type": "number",
76 "min": -127,
77 "max": 127,
78 "multipleOf": 1
79 }
80 "string_array": {
81 "type": "array",
82 "items": {
83 "type": "string"
84 }
85 },
86 "string_object": {
87 "type": "object",
88 "additionalProperties": {
89 "type": "string"
90 }
91 },
92 "unsigned_decimal": {
93 "type": "number",
94 "min": 0
95 },
96 "unsigned_int": {
97 "type": "number",
98 "min": 0,
99 "multipleOf": 1
100 }
101 "unsigned_int_8": {
102 "type": "number",
103 "min": 0,
104 "max": 255,
105 "multipleOf": 1
106 }
107}
diff --git a/data/schemas/keyboard.jsonschema b/data/schemas/keyboard.jsonschema
index 177bb0a96..d6d33ce4e 100644
--- a/data/schemas/keyboard.jsonschema
+++ b/data/schemas/keyboard.jsonschema
@@ -1,24 +1,12 @@
1{ 1{
2 "$schema": "http://json-schema.org/schema#", 2 "$schema": "http://json-schema.org/draft-07/schema#",
3 "$id": "qmk.keyboard.v1", 3 "$id": "qmk.keyboard.v1",
4 "title": "Keyboard Information", 4 "title": "Keyboard Information",
5 "type": "object", 5 "type": "object",
6 "properties": { 6 "properties": {
7 "keyboard_name": { 7 "keyboard_name": {"$ref": "qmk.definitions.v1#/text_identifier"},
8 "type": "string", 8 "maintainer": {"$ref": "qmk.definitions.v1#/text_identifier"},
9 "minLength": 2, 9 "manufacturer": {"$ref": "qmk.definitions.v1#/text_identifier"},
10 "maxLength": 250
11 },
12 "maintainer": {
13 "type": "string",
14 "minLength": 2,
15 "maxLength": 250
16 },
17 "manufacturer": {
18 "type": "string",
19 "minLength": 2,
20 "maxLength": 250
21 },
22 "url": { 10 "url": {
23 "type": "string", 11 "type": "string",
24 "format": "uri" 12 "format": "uri"
@@ -40,62 +28,25 @@
40 "type": "string", 28 "type": "string",
41 "enum": ["COL2ROW", "ROW2COL"] 29 "enum": ["COL2ROW", "ROW2COL"]
42 }, 30 },
43 "debounce": { 31 "debounce": {"$ref": "qmk.definitions.v1#/unsigned_int"},
44 "type": "number", 32 "height": {"$ref": "qmk.definitions.v1#/key_unit"},
45 "min": 0, 33 "width": {"$ref": "qmk.definitions.v1#/key_unit"},
46 "multipleOf": 1
47 },
48 "height": {
49 "type": "number",
50 "min": 0.25
51 },
52 "width": {
53 "type": "number",
54 "min": 0.25
55 },
56 "community_layouts": { 34 "community_layouts": {
57 "type": "array", 35 "type": "array",
58 "items": { 36 "items": {"$ref": "qmk.definitions.v1#/filename"}
59 "type": "string",
60 "minLength": 2,
61 "pattern": "^[0-9a-z_]*$"
62 }
63 },
64 "features": {
65 "type": "object",
66 "additionalProperties": {"type": "boolean"}
67 }, 37 },
38 "features": {"$ref": "qmk.definitions.v1#/boolean_array"},
68 "indicators": { 39 "indicators": {
69 "type": "object", 40 "type": "object",
70 "properties": { 41 "properties": {
71 "caps_lock": { 42 "caps_lock": {"$ref": "qmk.definitions.v1#/mcu_pin"},
72 "type": "string", 43 "num_lock": {"$ref": "qmk.definitions.v1#/mcu_pin"},
73 "pattern": "^[A-K]\\d{1,2}$" 44 "scroll_lock": {"$ref": "qmk.definitions.v1#/mcu_pin"}
74 },
75 "num_lock": {
76 "type": "string",
77 "pattern": "^[A-K]\\d{1,2}$"
78 },
79 "scroll_lock": {
80 "type": "string",
81 "pattern": "^[A-K]\\d{1,2}$"
82 }
83 } 45 }
84 }, 46 },
85 "layout_aliases": { 47 "layout_aliases": {
86 "type": "object", 48 "type": "object",
87 "additionalProperties": { 49 "additionalProperties": {"$ref": "qmk.definitions.v1#/layout_macro"}
88 "oneOf": [
89 {
90 "type": "string",
91 "enum": ["LAYOUT", "LAYOUT_planck_1x2uC"]
92 },
93 {
94 "type": "string",
95 "pattern": "^LAYOUT_[0-9a-z_]*$"
96 }
97 ]
98 }
99 }, 50 },
100 "layouts": { 51 "layouts": {
101 "type": "object", 52 "type": "object",
@@ -109,11 +60,7 @@
109 "c_macro": { 60 "c_macro": {
110 "type": "boolean" 61 "type": "boolean"
111 }, 62 },
112 "key_count": { 63 "key_count": {"$ref": "qmk.definitions.v1#/key_unit"},
113 "type": "number",
114 "min": 0,
115 "multipleOf": 1
116 },
117 "layout": { 64 "layout": {
118 "type": "array", 65 "type": "array",
119 "items": { 66 "items": {
@@ -131,34 +78,14 @@
131 "multipleOf": 1 78 "multipleOf": 1
132 } 79 }
133 }, 80 },
134 "h": { 81 "key_count": {"$ref": "qmk.definitions.v1#/key_unit"},
135 "type": "number", 82 "r": {"$ref": "qmk.definitions.v1#/unsigned_decimal"},
136 "min": 0.25 83 "rx": {"$ref": "qmk.definitions.v1#/unsigned_decimal"},
137 }, 84 "ry": {"$ref": "qmk.definitions.v1#/unsigned_decimal"},
138 "r": { 85 "h": {"$ref": "qmk.definitions.v1#/key_unit"},
139 "type": "number", 86 "w": {"$ref": "qmk.definitions.v1#/key_unit"},
140 "min": 0 87 "x": {"$ref": "qmk.definitions.v1#/key_unit"},
141 }, 88 "y": {"$ref": "qmk.definitions.v1#/key_unit"}
142 "rx": {
143 "type": "number",
144 "min": 0
145 },
146 "ry": {
147 "type": "number",
148 "min": 0
149 },
150 "w": {
151 "type": "number",
152 "min": 0.25
153 },
154 "x": {
155 "type": "number",
156 "min": 0
157 },
158 "y": {
159 "type": "number",
160 "min": 0
161 }
162 } 89 }
163 } 90 }
164 } 91 }
@@ -171,73 +98,10 @@
171 "properties": { 98 "properties": {
172 "direct": { 99 "direct": {
173 "type": "array", 100 "type": "array",
174 "items": { 101 "items": {$ref": "qmk.definitions.v1#/mcu_pin_array"}
175 "type": "array",
176 "items": {
177 "oneOf": [
178 {
179 "type": "string",
180 "pattern": "^[A-K]\\d{1,2}$"
181 },
182 {
183 "type": "string",
184 "pattern": "^LINE_PIN\\d{1,2}$"
185 },
186 {
187 "type": "number",
188 "multipleOf": 1
189 },
190 {
191 "type": "null"
192 }
193 ]
194 }
195 }
196 }, 102 },
197 "cols": { 103 "cols": {"$ref": "qmk.definitions.v1#/mcu_pin_array"},
198 "type": "array", 104 "rows": {"$ref": "qmk.definitions.v1#/mcu_pin_array"}
199 "items": {
200 "oneOf": [
201 {
202 "type": "string",
203 "pattern": "^[A-K]\\d{1,2}$"
204 },
205 {
206 "type": "string",
207 "pattern": "^LINE_PIN\\d{1,2}$"
208 },
209 {
210 "type": "number",
211 "multipleOf": 1
212 },
213 {
214 "type": "null"
215 }
216 ]
217 }
218 },
219 "rows": {
220 "type": "array",
221 "items": {
222 "oneOf": [
223 {
224 "type": "string",
225 "pattern": "^[A-K]\\d{1,2}$"
226 },
227 {
228 "type": "string",
229 "pattern": "^LINE_PIN\\d{1,2}$"
230 },
231 {
232 "type": "number",
233 "multipleOf": 1
234 },
235 {
236 "type": "null"
237 }
238 ]
239 }
240 }
241 } 105 }
242 }, 106 },
243 "rgblight": { 107 "rgblight": {
@@ -250,47 +114,19 @@
250 "type": "boolean" 114 "type": "boolean"
251 } 115 }
252 }, 116 },
253 "brightness_steps": { 117 "brightness_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"},
254 "type": "number", 118 "hue_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"},
255 "min": 0, 119 "led_count": {"$ref": "qmk.definitions.v1#/unsigned_int"},
256 "multipleOf": 1 120 "max_brightness": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
257 }, 121 "pin": {"$ref": "qmk.definitions.v1#/mcu_pin"},
258 "hue_steps": { 122 "saturation_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"},
259 "type": "number",
260 "min": 0,
261 "multipleOf": 1
262 },
263 "led_count": {
264 "type": "number",
265 "min": 0,
266 "multipleOf": 1
267 },
268 "max_brightness": {
269 "type": "number",
270 "min": 0,
271 "max": 255,
272 "multipleOf": 1
273 },
274 "pin": {
275 "type": "string",
276 "pattern": "^([A-K]\\d{1,2}|LINE_PIN\\d{1,2})$"
277 },
278 "saturation_steps": {
279 "type": "number",
280 "min": 0,
281 "multipleOf": 1
282 },
283 "sleep": {"type": "boolean"}, 123 "sleep": {"type": "boolean"},
284 "split": {"type": "boolean"}, 124 "split": {"type": "boolean"},
285 "split_count": { 125 "split_count": {
286 "type": "array", 126 "type": "array",
287 "minLength": 2, 127 "minLength": 2,
288 "maxLength": 2, 128 "maxLength": 2,
289 "items": { 129 "items": {"$ref": "qmk.definitions.v1#/unsigned_int"}
290 "type": "number",
291 "min": 0,
292 "multipleOf": 1
293 }
294 } 130 }
295 } 131 }
296 }, 132 },
@@ -298,40 +134,19 @@
298 "type": "object", 134 "type": "object",
299 "additionalProperties": false, 135 "additionalProperties": false,
300 "properties": { 136 "properties": {
301 "device_ver": { 137 "device_ver": {"$ref": "qmk.definitions.v1#/hex_number_4d"},
302 "type": "string", 138 "pid": {"$ref": "qmk.definitions.v1#/hex_number_4d"},
303 "pattern": "^[0-9A-F]x[0-9A-F][0-9A-F][0-9A-F][0-9A-F]" 139 "vid": {"$ref": "qmk.definitions.v1#/hex_number_4d"}
304 },
305 "pid": {
306 "type": "string",
307 "pattern": "^[0-9A-F]x[0-9A-F][0-9A-F][0-9A-F][0-9A-F]"
308 },
309 "vid": {
310 "type": "string",
311 "pattern": "^[0-9A-F]x[0-9A-F][0-9A-F][0-9A-F][0-9A-F]"
312 }
313 } 140 }
314 }, 141 },
315 "qmk_lufa_bootloader": { 142 "qmk_lufa_bootloader": {
316 "type": "object", 143 "type": "object",
317 "additionalProperties": false, 144 "additionalProperties": false,
318 "properties": { 145 "properties": {
319 "esc_output": { 146 "esc_output": {"$ref": "qmk.definitions.v1#/mcu_pin"},
320 "type": "string", 147 "esc_input": {"$ref": "qmk.definitions.v1#/mcu_pin"},
321 "pattern": "^[A-K]\\d{1,2}$" 148 "led": {"$ref": "qmk.definitions.v1#/mcu_pin"},
322 }, 149 "speaker": {"$ref": "qmk.definitions.v1#/mcu_pin"}
323 "esc_input": {
324 "type": "string",
325 "pattern": "^[A-K]\\d{1,2}$"
326 },
327 "led": {
328 "type": "string",
329 "pattern": "^[A-K]\\d{1,2}$"
330 },
331 "speaker": {
332 "type": "string",
333 "pattern": "^[A-K]\\d{1,2}$"
334 }
335 } 150 }
336 } 151 }
337 } 152 }
diff --git a/keyboards/checkerboards/nop60/info.json b/keyboards/checkerboards/nop60/info.json
index 82ff7229f..66e770634 100644
--- a/keyboards/checkerboards/nop60/info.json
+++ b/keyboards/checkerboards/nop60/info.json
@@ -1,15 +1,143 @@
1{ 1{
2 "keyboard_name": "nop60", 2 "keyboard_name": "nop60",
3 "url": "",
4 "maintainer": "nasp", 3 "maintainer": "nasp",
5 "width": 15,
6 "height": 5, 4 "height": 5,
5 "width": 15,
6 "url": "",
7 "layouts": { 7 "layouts": {
8 "LAYOUT": { 8 "LAYOUT": {
9 "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}] 9 "layout": [
10 { "label": "Esc", "x": 0, "y": 0 },
11 { "label": "!", "x": 1, "y": 0 },
12 { "label": "@", "x": 2, "y": 0 },
13 { "label": "#", "x": 3, "y": 0 },
14 { "label": "$", "x": 4, "y": 0 },
15 { "label": "%", "x": 5, "y": 0 },
16 { "label": "^", "x": 6, "y": 0 },
17 { "label": "&", "x": 7, "y": 0 },
18 { "label": "*", "x": 8, "y": 0 },
19 { "label": "(", "x": 9, "y": 0 },
20 { "label": ")", "x": 10, "y": 0 },
21 { "label": "_", "x": 11, "y": 0 },
22 { "label": "+", "x": 12, "y": 0 },
23 { "label": "~", "x": 13, "y": 0 },
24 { "label": "Bksp", "x": 14, "y": 0 },
25 { "label": "Tab", "w": 1.5, "x": 0, "y": 1 },
26 { "label": "Q", "x": 1.5, "y": 1 },
27 { "label": "W", "x": 2.5, "y": 1 },
28 { "label": "E", "x": 3.5, "y": 1 },
29 { "label": "R", "x": 4.5, "y": 1 },
30 { "label": "T", "x": 5.5, "y": 1 },
31 { "label": "Y", "x": 6.5, "y": 1 },
32 { "label": "U", "x": 7.5, "y": 1 },
33 { "label": "I", "x": 8.5, "y": 1 },
34 { "label": "O", "x": 9.5, "y": 1 },
35 { "label": "P", "x": 10.5, "y": 1 },
36 { "label": "{", "x": 11.5, "y": 1 },
37 { "label": "}", "x": 12.5, "y": 1 },
38 { "label": "|", "w": 1.5, "x": 13.5, "y": 1 },
39 { "label": "Caps Lock", "w": 1.75, "x": 0, "y": 2 },
40 { "label": "A", "x": 1.75, "y": 2 },
41 { "label": "S", "x": 2.75, "y": 2 },
42 { "label": "D", "x": 3.75, "y": 2 },
43 { "label": "F", "x": 4.75, "y": 2 },
44 { "label": "G", "x": 5.75, "y": 2 },
45 { "label": "H", "x": 6.75, "y": 2 },
46 { "label": "J", "x": 7.75, "y": 2 },
47 { "label": "K", "x": 8.75, "y": 2 },
48 { "label": "L", "x": 9.75, "y": 2 },
49 { "label": ":", "x": 10.75, "y": 2 },
50 { "label": "\"", "x": 11.75, "y": 2 },
51 { "label": "Enter", "w": 2.25, "x": 12.75, "y": 2 },
52 { "label": "Shift", "w": 2.25, "x": 0, "y": 3 },
53 { "label": "Z", "x": 2.25, "y": 3 },
54 { "label": "X", "x": 3.25, "y": 3 },
55 { "label": "C", "x": 4.25, "y": 3 },
56 { "label": "V", "x": 5.25, "y": 3 },
57 { "label": "B", "x": 6.25, "y": 3 },
58 { "label": "N", "x": 7.25, "y": 3 },
59 { "label": "M", "x": 8.25, "y": 3 },
60 { "label": "<", "x": 9.25, "y": 3 },
61 { "label": ">", "x": 10.25, "y": 3 },
62 { "label": "?", "x": 11.25, "y": 3 },
63 { "label": "Shift", "w": 1.75, "x": 12.25, "y": 3 },
64 { "label": "Fn", "x": 14, "y": 3 },
65 { "label": "Ctrl", "w": 1.5, "x": 0, "y": 4 },
66 { "label": "Win", "x": 1.5, "y": 4 },
67 { "label": "Alt", "w": 1.5, "x": 2.5, "y": 4 },
68 { "w": 7, "x": 4, "y": 4 },
69 { "label": "Alt", "w": 1.5, "x": 11, "y": 4 },
70 { "label": "Win", "x": 12.5, "y": 4 },
71 { "label": "Ctrl", "w": 1.5, "x": 13.5, "y": 4 }
72 ]
10 }, 73 },
11 "LAYOUT": { 74 "LAYOUT_2x3u": {
12 "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}] 75 "layout": [
76 { "label": "Esc", "x": 0, "y": 0 },
77 { "label": "!", "x": 1, "y": 0 },
78 { "label": "@", "x": 2, "y": 0 },
79 { "label": "#", "x": 3, "y": 0 },
80 { "label": "$", "x": 4, "y": 0 },
81 { "label": "%", "x": 5, "y": 0 },
82 { "label": "^", "x": 6, "y": 0 },
83 { "label": "&", "x": 7, "y": 0 },
84 { "label": "*", "x": 8, "y": 0 },
85 { "label": "(", "x": 9, "y": 0 },
86 { "label": ")", "x": 10, "y": 0 },
87 { "label": "_", "x": 11, "y": 0 },
88 { "label": "+", "x": 12, "y": 0 },
89 { "label": "~", "x": 13, "y": 0 },
90 { "label": "Bksp", "x": 14, "y": 0 },
91 { "label": "Tab", "w": 1.5, "x": 0, "y": 1 },
92 { "label": "Q", "x": 1.5, "y": 1 },
93 { "label": "W", "x": 2.5, "y": 1 },
94 { "label": "E", "x": 3.5, "y": 1 },
95 { "label": "R", "x": 4.5, "y": 1 },
96 { "label": "T", "x": 5.5, "y": 1 },
97 { "label": "Y", "x": 6.5, "y": 1 },
98 { "label": "U", "x": 7.5, "y": 1 },
99 { "label": "I", "x": 8.5, "y": 1 },
100 { "label": "O", "x": 9.5, "y": 1 },
101 { "label": "P", "x": 10.5, "y": 1 },
102 { "label": "{", "x": 11.5, "y": 1 },
103 { "label": "}", "x": 12.5, "y": 1 },
104 { "label": "|", "w": 1.5, "x": 13.5, "y": 1 },
105 { "label": "Caps Lock", "w": 1.75, "x": 0, "y": 2 },
106 { "label": "A", "x": 1.75, "y": 2 },
107 { "label": "S", "x": 2.75, "y": 2 },
108 { "label": "D", "x": 3.75, "y": 2 },
109 { "label": "F", "x": 4.75, "y": 2 },
110 { "label": "G", "x": 5.75, "y": 2 },
111 { "label": "H", "x": 6.75, "y": 2 },
112 { "label": "J", "x": 7.75, "y": 2 },
113 { "label": "K", "x": 8.75, "y": 2 },
114 { "label": "L", "x": 9.75, "y": 2 },
115 { "label": ":", "x": 10.75, "y": 2 },
116 { "label": "\"", "x": 11.75, "y": 2 },
117 { "label": "Enter", "w": 2.25, "x": 12.75, "y": 2 },
118 { "label": "Shift", "w": 2.25, "x": 0, "y": 3 },
119 { "label": "Z", "x": 2.25, "y": 3 },
120 { "label": "X", "x": 3.25, "y": 3 },
121 { "label": "C", "x": 4.25, "y": 3 },
122 { "label": "V", "x": 5.25, "y": 3 },
123 { "label": "B", "x": 6.25, "y": 3 },
124 { "label": "N", "x": 7.25, "y": 3 },
125 { "label": "M", "x": 8.25, "y": 3 },
126 { "label": "<", "x": 9.25, "y": 3 },
127 { "label": ">", "x": 10.25, "y": 3 },
128 { "label": "?", "x": 11.25, "y": 3 },
129 { "label": "Shift", "w": 1.75, "x": 12.25, "y": 3 },
130 { "label": "Fn", "x": 14, "y": 3 },
131 { "label": "Ctrl", "w": 1.5, "x": 0, "y": 4 },
132 { "label": "Win", "x": 1.5, "y": 4 },
133 { "label": "Alt", "w": 1.5, "x": 2.5, "y": 4 },
134 { "w": 3, "x": 4, "y": 4 },
135 { "x": 7, "y": 4 },
136 { "w": 3, "x": 8, "y": 4 },
137 { "label": "Alt", "w": 1.5, "x": 11, "y": 4 },
138 { "label": "Win", "x": 12.5, "y": 4 },
139 { "label": "Ctrl", "w": 1.5, "x": 13.5, "y": 4 }
140 ]
13 } 141 }
14 } 142 }
15} 143}
diff --git a/keyboards/ramonimbao/chevron/info.json b/keyboards/ramonimbao/chevron/info.json
index 11ed02e53..2a88fedb1 100644
--- a/keyboards/ramonimbao/chevron/info.json
+++ b/keyboards/ramonimbao/chevron/info.json
@@ -1,7 +1,5 @@
1{ 1{
2 "keyboard_name": "Chevron", 2 "keyboard_name": "Chevron",
3 "url": "",
4 "maintainer": "",
5 "width": 14.5, 3 "width": 14.5,
6 "height": 5, 4 "height": 5,
7 "layouts": { 5 "layouts": {
diff --git a/keyboards/sendyyeah/75pixels/info.json b/keyboards/sendyyeah/75pixels/info.json
index 20d158cf7..d952cac13 100644
--- a/keyboards/sendyyeah/75pixels/info.json
+++ b/keyboards/sendyyeah/75pixels/info.json
@@ -7,7 +7,7 @@
7 "layouts": { 7 "layouts": {
8 "LAYOUT_ortho_5x15": { 8 "LAYOUT_ortho_5x15": {
9 "layout": [ 9 "layout": [
10 {"label": "Esc", "X": 0, "y": 0}, 10 {"label": "Esc", "x": 0, "y": 0},
11 {"label": "1", "x": 1, "y": 0}, 11 {"label": "1", "x": 1, "y": 0},
12 {"label": "2", "x": 2, "y": 0}, 12 {"label": "2", "x": 2, "y": 0},
13 {"label": "3", "x": 3, "y": 0}, 13 {"label": "3", "x": 3, "y": 0},
@@ -22,21 +22,21 @@
22 {"label": "NumLock", "x": 12, "y": 0}, 22 {"label": "NumLock", "x": 12, "y": 0},
23 {"label": "/", "x": 13, "y": 0}, 23 {"label": "/", "x": 13, "y": 0},
24 {"label": "*", "x": 14, "y": 0}, 24 {"label": "*", "x": 14, "y": 0},
25 {"label": "Tab", "X": 0, "y": 1}, 25 {"label": "Tab", "x": 0, "y": 1},
26 {"label": "Q", "X": 1, "y": 1}, 26 {"label": "Q", "x": 1, "y": 1},
27 {"label": "W", "X": 2, "y": 1}, 27 {"label": "W", "x": 2, "y": 1},
28 {"label": "E", "X": 3, "y": 1}, 28 {"label": "E", "x": 3, "y": 1},
29 {"label": "R", "X": 4, "y": 1}, 29 {"label": "R", "x": 4, "y": 1},
30 {"label": "T", "X": 5, "y": 1}, 30 {"label": "T", "x": 5, "y": 1},
31 {"label": "Y", "X": 6, "y": 1}, 31 {"label": "Y", "x": 6, "y": 1},
32 {"label": "U", "X": 7, "y": 1}, 32 {"label": "U", "x": 7, "y": 1},
33 {"label": "I", "X": 8, "y": 1}, 33 {"label": "I", "x": 8, "y": 1},
34 {"label": "O", "X": 9, "y": 1}, 34 {"label": "O", "x": 9, "y": 1},
35 {"label": "P", "X": 10, "y": 1}, 35 {"label": "P", "x": 10, "y": 1},
36 {"label": "|\n\\", "X": 11, "y": 1}, 36 {"label": "|\n\\", "x": 11, "y": 1},
37 {"label": "7\nHome", "X": 12, "y": 1}, 37 {"label": "7\nHome", "x": 12, "y": 1},
38 {"label": "8\nUp", "X": 13, "y": 1}, 38 {"label": "8\nUp", "x": 13, "y": 1},
39 {"label": "9\nPgUp", "X": 14, "y": 1}, 39 {"label": "9\nPgUp", "x": 14, "y": 1},
40 {"label": "Caps", "x": 0, "y": 2}, 40 {"label": "Caps", "x": 0, "y": 2},
41 {"label": "A", "x": 1, "y": 2}, 41 {"label": "A", "x": 1, "y": 2},
42 {"label": "S", "x": 2, "y": 2}, 42 {"label": "S", "x": 2, "y": 2},
@@ -67,21 +67,21 @@
67 {"label": "1\nEnd", "x": 12, "y": 3}, 67 {"label": "1\nEnd", "x": 12, "y": 3},
68 {"label": "2\nDown", "x": 13, "y": 3}, 68 {"label": "2\nDown", "x": 13, "y": 3},
69 {"label": "3\nPgDn", "x": 14, "y": 3}, 69 {"label": "3\nPgDn", "x": 14, "y": 3},
70 {"label": "Ctrl", "X": 0, "y": 4}, 70 {"label": "Ctrl", "x": 0, "y": 4},
71 {"label": "Win", "X": 1, "y": 4}, 71 {"label": "Win", "x": 1, "y": 4},
72 {"label": "Alt", "X": 2, "y": 4}, 72 {"label": "Alt", "x": 2, "y": 4},
73 {"label": "Fn", "X": 3, "y": 4}, 73 {"label": "Fn", "x": 3, "y": 4},
74 {"label": "Lower", "X": 4, "y": 4}, 74 {"label": "Lower", "x": 4, "y": 4},
75 {"label": "Space", "X": 5, "y": 4}, 75 {"label": "Space", "x": 5, "y": 4},
76 {"label": "Space", "X": 6, "y": 4}, 76 {"label": "Space", "x": 6, "y": 4},
77 {"label": "Raise", "X": 7, "y": 4}, 77 {"label": "Raise", "x": 7, "y": 4},
78 {"label": "Alt", "X": 8, "y": 4}, 78 {"label": "Alt", "x": 8, "y": 4},
79 {"label": "Win", "X": 9, "y": 4}, 79 {"label": "Win", "x": 9, "y": 4},
80 {"label": "Menu", "X": 10, "y": 4}, 80 {"label": "Menu", "x": 10, "y": 4},
81 {"label": "Ctrl", "X": 11, "y": 4}, 81 {"label": "Ctrl", "x": 11, "y": 4},
82 {"label": "0\nIns", "X": 12, "y": 4}, 82 {"label": "0\nIns", "x": 12, "y": 4},
83 {"label": ".\nDel", "X": 13, "y": 4}, 83 {"label": ".\nDel", "x": 13, "y": 4},
84 {"label": "Enter", "X": 14, "y": 4} 84 {"label": "Enter", "x": 14, "y": 4}
85 ] 85 ]
86 } 86 }
87 } 87 }
diff --git a/lib/python/qmk/cli/format/json.py b/lib/python/qmk/cli/format/json.py
index 1358c70e7..19d504491 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
8from milc import cli 8from milc import cli
9 9
10from qmk.info import info_json 10from qmk.info import info_json
11from qmk.json_schema import json_load, keyboard_validate 11from qmk.json_schema import json_load, validate
12from qmk.json_encoders import InfoJSONEncoder, KeymapJSONEncoder 12from qmk.json_encoders import InfoJSONEncoder, KeymapJSONEncoder
13from qmk.path import normpath 13from qmk.path import normpath
14 14
@@ -23,14 +23,13 @@ def format_json(cli):
23 23
24 if cli.args.format == 'auto': 24 if cli.args.format == 'auto':
25 try: 25 try:
26 keyboard_validate(json_file) 26 validate(json_file, 'qmk.keyboard.v1')
27 json_encoder = InfoJSONEncoder 27 json_encoder = InfoJSONEncoder
28 28
29 except ValidationError as e: 29 except ValidationError as e:
30 cli.log.warning('File %s did not validate as a keyboard:\n\t%s', cli.args.json_file, e) 30 cli.log.warning('File %s did not validate as a keyboard:\n\t%s', cli.args.json_file, e)
31 cli.log.info('Treating %s as a keymap file.', cli.args.json_file) 31 cli.log.info('Treating %s as a keymap file.', cli.args.json_file)
32 json_encoder = KeymapJSONEncoder 32 json_encoder = KeymapJSONEncoder
33
34 elif cli.args.format == 'keyboard': 33 elif cli.args.format == 'keyboard':
35 json_encoder = InfoJSONEncoder 34 json_encoder = InfoJSONEncoder
36 elif cli.args.format == 'keymap': 35 elif cli.args.format == 'keymap':
diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py
index a70bd4c31..5525f0fe6 100644
--- a/lib/python/qmk/info.py
+++ b/lib/python/qmk/info.py
@@ -9,7 +9,7 @@ from milc import cli
9 9
10from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS 10from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS
11from qmk.c_parse import find_layouts 11from qmk.c_parse import find_layouts
12from qmk.json_schema import deep_update, json_load, keyboard_validate, keyboard_api_validate 12from qmk.json_schema import deep_update, json_load, validate
13from qmk.keyboard import config_h, rules_mk 13from qmk.keyboard import config_h, rules_mk
14from qmk.keymap import list_keymaps 14from qmk.keymap import list_keymaps
15from qmk.makefile import parse_rules_mk_file 15from qmk.makefile import parse_rules_mk_file
@@ -66,7 +66,7 @@ def info_json(keyboard):
66 66
67 # Validate against the jsonschema 67 # Validate against the jsonschema
68 try: 68 try:
69 keyboard_api_validate(info_data) 69 validate(info_data, 'qmk.api.keyboard.v1')
70 70
71 except jsonschema.ValidationError as e: 71 except jsonschema.ValidationError as e:
72 json_path = '.'.join([str(p) for p in e.absolute_path]) 72 json_path = '.'.join([str(p) for p in e.absolute_path])
@@ -490,7 +490,7 @@ def merge_info_jsons(keyboard, info_data):
490 continue 490 continue
491 491
492 try: 492 try:
493 keyboard_validate(new_info_data) 493 validate(new_info_data, 'qmk.keyboard.v1')
494 except jsonschema.ValidationError as e: 494 except jsonschema.ValidationError as e:
495 json_path = '.'.join([str(p) for p in e.absolute_path]) 495 json_path = '.'.join([str(p) for p in e.absolute_path])
496 cli.log.error('Not including data from file: %s', info_file) 496 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 077dfcaa9..3e5663a29 100644
--- a/lib/python/qmk/json_schema.py
+++ b/lib/python/qmk/json_schema.py
@@ -24,9 +24,10 @@ def json_load(json_file):
24 24
25def load_jsonschema(schema_name): 25def load_jsonschema(schema_name):
26 """Read a jsonschema file from disk. 26 """Read a jsonschema file from disk.
27
28 FIXME(skullydazed/anyone): Refactor to make this a public function.
29 """ 27 """
28 if Path(schema_name).exists():
29 return json_load(schema_name)
30
30 schema_path = Path(f'data/schemas/{schema_name}.jsonschema') 31 schema_path = Path(f'data/schemas/{schema_name}.jsonschema')
31 32
32 if not schema_path.exists(): 33 if not schema_path.exists():
@@ -35,28 +36,33 @@ def load_jsonschema(schema_name):
35 return json_load(schema_path) 36 return json_load(schema_path)
36 37
37 38
38def keyboard_validate(data): 39def create_validator(schema):
39 """Validates data against the keyboard jsonschema. 40 """Creates a validator for the given schema id.
40 """ 41 """
41 schema = load_jsonschema('keyboard') 42 schema_store = {}
42 validator = jsonschema.Draft7Validator(schema).validate
43 43
44 return validator(data) 44 for schema_file in Path('data/schemas').glob('*.jsonschema'):
45 schema_data = load_jsonschema(schema_file)
46 if not isinstance(schema_data, dict):
47 cli.log.debug('Skipping schema file %s', schema_file)
48 continue
49 schema_store[schema_data['$id']] = schema_data
50
51 resolver = jsonschema.RefResolver.from_schema(schema_store['qmk.keyboard.v1'], store=schema_store)
52
53 return jsonschema.Draft7Validator(schema_store[schema], resolver=resolver).validate
45 54
46 55
47def keyboard_api_validate(data): 56def validate(data, schema):
48 """Validates data against the api_keyboard jsonschema. 57 """Validates data against a schema.
49 """ 58 """
50 base = load_jsonschema('keyboard') 59 validator = create_validator(schema)
51 relative = load_jsonschema('api_keyboard')
52 resolver = jsonschema.RefResolver.from_schema(base)
53 validator = jsonschema.Draft7Validator(relative, resolver=resolver).validate
54 60
55 return validator(data) 61 return validator(data)
56 62
57 63
58def deep_update(origdict, newdict): 64def deep_update(origdict, newdict):
59 """Update a dictionary in place, recursing to do a deep copy. 65 """Update a dictionary in place, recursing to do a depth-first deep copy.
60 """ 66 """
61 for key, value in newdict.items(): 67 for key, value in newdict.items():
62 if isinstance(value, Mapping): 68 if isinstance(value, Mapping):