diff options
Diffstat (limited to 'api/services/zmk/keymap.js')
-rw-r--r-- | api/services/zmk/keymap.js | 50 |
1 files changed, 49 insertions, 1 deletions
diff --git a/api/services/zmk/keymap.js b/api/services/zmk/keymap.js index a8837ea..4eafb88 100644 --- a/api/services/zmk/keymap.js +++ b/api/services/zmk/keymap.js @@ -9,6 +9,14 @@ const uniq = require('lodash/uniq') const { renderTable } = require('./layout') +class KeymapValidationError extends Error { + constructor (errors) { + super() + this.name = 'KeymapValidationError' + this.errors = errors + } +} + const behaviours = JSON.parse(fs.readFileSync(path.join(__dirname, 'data/zmk-behaviors.json'))) const behavioursByBind = keyBy(behaviours, 'code') @@ -145,8 +153,48 @@ function generateKeymapJSON (layout, keymap, encoded) { return base.replace('"layers": null', `"layers": [\n ${layers.join(', ')}\n ]`) } +function validateKeymapJson(keymap) { + const errors = [] + + if (typeof keymap !== 'object' || keymap === null) { + errors.push('keymap.json root must be an object') + } else if (!Array.isArray(keymap.layers)) { + errors.push('keymap must include "layers" array') + } else { + for (let i in keymap.layers) { + const layer = keymap.layers[i] + + if (!Array.isArray(layer)) { + errors.push(`Layer at layers[${i}] must be an array`) + } else { + for (let j in layer) { + const key = layer[j] + const keyPath = `layers[${i}][${j}]` + + if (typeof key !== 'string') { + errors.push(`Value at "${keyPath}" must be a string`) + } else { + const bind = key.match(/^&.+?\b/) + if (!(bind && bind[0] in behavioursByBind)) { + errors.push(`Key bind at "${keyPath}" has invalid behaviour`) + } + } + + // TODO: validate remaining bind parameters + } + } + } + } + + if (errors.length) { + throw new KeymapValidationError(errors) + } +} + module.exports = { + KeymapValidationError, encodeKeymap, parseKeymap, - generateKeymap + generateKeymap, + validateKeymapJson } |