diff --git a/package.json b/package.json index 42c3eee..1af5808 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@the-via/reader", - "version": "1.5.10", + "version": "1.6.0", "repository": { "type": "git", "url": "git+ssh://git@github.com/the-via/reader.git" diff --git a/src/common-menus/index.ts b/src/common-menus/index.ts new file mode 100644 index 0000000..2966195 --- /dev/null +++ b/src/common-menus/index.ts @@ -0,0 +1,13 @@ +import {qmk_audio} from './qmk_audio'; +import {qmk_backlight} from './qmk_backlight'; +import {qmk_backlight_rgblight} from './qmk_backlight_rgblight'; +import {qmk_rgblight} from './qmk_rgblight'; +import {qmk_rgb_matrix} from './qmk_rgb_matrix'; + +export const commonMenus = { + qmk_audio, + qmk_backlight_rgblight, + qmk_backlight, + qmk_rgb_matrix, + qmk_rgblight, +}; diff --git a/src/common-menus/qmk_audio.ts b/src/common-menus/qmk_audio.ts new file mode 100644 index 0000000..78f4613 --- /dev/null +++ b/src/common-menus/qmk_audio.ts @@ -0,0 +1,24 @@ +import {VIAMenu} from '../menu-types'; + +export const qmk_audio: VIAMenu[] = [ + { + label: 'Audio', + content: [ + { + label: 'General', + content: [ + { + label: 'Audio Enable', + type: 'toggle', + content: ['id_qmk_audio_enable', 4, 1], + }, + { + label: 'Audio Clicky Enable', + type: 'toggle', + content: ['id_qmk_audio_clicky_enable', 4, 2], + }, + ], + }, + ], + }, +]; diff --git a/src/common-menus/qmk_backlight.ts b/src/common-menus/qmk_backlight.ts new file mode 100644 index 0000000..ee649b5 --- /dev/null +++ b/src/common-menus/qmk_backlight.ts @@ -0,0 +1,29 @@ +import {VIAMenu} from '../menu-types'; + +export const qmk_backlight: VIAMenu[] = [ + { + label: 'Lighting', + content: [ + { + label: 'Backlight', + content: [ + { + label: 'Backlight Brightness', + type: 'range', + options: [0, 255], + content: ['id_qmk_backlight_brightness', 1, 1], + }, + { + label: 'Backlight Effect', + type: 'dropdown', + content: ['id_qmk_backlight_effect', 1, 2], + options: [ + ['Off', 0], + ['Breathing', 1], + ], + }, + ], + }, + ], + }, +]; diff --git a/src/common-menus/qmk_backlight_rgblight.ts b/src/common-menus/qmk_backlight_rgblight.ts new file mode 100644 index 0000000..263652e --- /dev/null +++ b/src/common-menus/qmk_backlight_rgblight.ts @@ -0,0 +1,104 @@ +import {VIAMenu} from '../menu-types'; + +export const qmk_backlight_rgblight: VIAMenu[] = [ + { + label: 'Lighting', + content: [ + { + label: 'Backlight', + content: [ + { + label: 'Backlight Brightness', + type: 'range', + options: [0, 255], + content: ['id_qmk_backlight_brightness', 1, 1], + }, + { + label: 'Backlight Effect', + type: 'dropdown', + content: ['id_qmk_backlight_effect', 1, 2], + options: [ + ['Off', 0], + ['Breathing', 1], + ], + }, + ], + }, + { + label: 'Underglow', + content: [ + { + label: 'Brightness', + type: 'range', + options: [0, 255], + content: ['id_qmk_rgblight_brightness', 2, 1], + }, + { + label: 'Effect', + type: 'dropdown', + content: ['id_qmk_rgblight_effect', 2, 2], + options: [ + 'All Off', + 'Solid Color', + 'Breathing 1', + 'Breathing 2', + 'Breathing 3', + 'Breathing 4', + 'Rainbow Mood 1', + 'Rainbow Mood 2', + 'Rainbow Mood 3', + 'Rainbow Swirl 1', + 'Rainbow Swirl 2', + 'Rainbow Swirl 3', + 'Rainbow Swirl 4', + 'Rainbow Swirl 5', + 'Rainbow Swirl 6', + 'Snake 1', + 'Snake 2', + 'Snake 3', + 'Snake 4', + 'Snake 5', + 'Snake 6', + 'Knight 1', + 'Knight 2', + 'Knight 3', + 'Christmas', + 'Gradient 1', + 'Gradient 2', + 'Gradient 3', + 'Gradient 4', + 'Gradient 5', + 'Gradient 6', + 'Gradient 7', + 'Gradient 8', + 'Gradient 9', + 'Gradient 10', + 'RGB Test', + 'Alternating', + 'Twinkle 1', + 'Twinkle 2', + 'Twinkle 3', + 'Twinkle 4', + 'Twinkle 5', + 'Twinkle 6', + ], + }, + { + showIf: '{id_qmk_rgblight_effect} != 0', + label: 'Effect Speed', + type: 'range', + options: [0, 255], + content: ['id_qmk_rgblight_effect_speed', 2, 3], + }, + { + showIf: + '{id_qmk_rgblight_effect} != 0 && {id_qmk_rgblight_effect} != 35', + label: 'Color', + type: 'color', + content: ['id_qmk_rgblight_color', 2, 4], + }, + ], + }, + ], + }, +]; diff --git a/src/common-menus/qmk_rgb_matrix.ts b/src/common-menus/qmk_rgb_matrix.ts new file mode 100644 index 0000000..db3b5e6 --- /dev/null +++ b/src/common-menus/qmk_rgb_matrix.ts @@ -0,0 +1,86 @@ +import {VIAMenu} from '../menu-types'; + +export const qmk_rgb_matrix: VIAMenu[] = [ + { + label: 'Lighting', + content: [ + { + label: 'Backlight', + content: [ + { + label: 'Brightness', + type: 'range', + options: [0, 255], + content: ['id_qmk_rgb_matrix_brightness', 3, 1], + }, + { + label: 'Effect', + type: 'dropdown', + content: ['id_qmk_rgb_matrix_effect', 3, 2], + options: [ + 'All Off', + 'Solid Color', + 'Alphas Mods', + 'Gradient Up/Down', + 'Gradient Left/Right', + 'Breathing', + 'Band Sat.', + 'Band Val.', + 'Pinwheel Sat.', + 'Pinwheel Val.', + 'Spiral Sat.', + 'Spiral Val.', + 'Cycle All', + 'Cycle Left/Right', + 'Cycle Up/Down', + 'Rainbow Moving Chevron', + 'Cycle Out/In', + 'Cycle Out/In Dual', + 'Cycle Pinwheel', + 'Cycle Spiral', + 'Dual Beacon', + 'Rainbow Beacon', + 'Rainbow Pinwheels', + 'Raindrops', + 'Jellybean Raindrops', + 'Hue Breathing', + 'Hue Pendulum', + 'Hue Wave', + 'Pixel Rain', + 'Pixel Flow', + 'Pixel Fractal', + 'Typing Heatmap', + 'Digital Rain', + 'Solid Reactive Simple', + 'Solid Reactive', + 'Solid Reactive Wide', + 'Solid Reactive Multi Wide', + 'Solid Reactive Cross', + 'Solid Reactive Multi Cross', + 'Solid Reactive Nexus', + 'Solid Reactive Multi Nexus', + 'Spash', + 'Multi Splash', + 'Solid Splash', + 'Solid Multi Splash', + ], + }, + { + showIf: '{id_qmk_rgb_matrix_effect} != 0', + label: 'Effect Speed', + type: 'range', + options: [0, 255], + content: ['id_qmk_rgb_matrix_effect_speed', 3, 3], + }, + { + showIf: + '{id_qmk_rgb_matrix_effect} != 0 && {id_qmk_rgb_matrix_effect} != 24 && {id_qmk_rgb_matrix_effect} != 28 && {id_qmk_rgb_matrix_effect} != 29 && {id_qmk_rgb_matrix_effect} != 32', + label: 'Color', + type: 'color', + content: ['id_qmk_rgb_matrix_color', 3, 4], + }, + ], + }, + ], + }, +]; diff --git a/src/common-menus/qmk_rgblight.ts b/src/common-menus/qmk_rgblight.ts new file mode 100644 index 0000000..6f3aa00 --- /dev/null +++ b/src/common-menus/qmk_rgblight.ts @@ -0,0 +1,84 @@ +import {VIAMenu} from '../menu-types'; + +export const qmk_rgblight: VIAMenu[] = [ + { + label: 'Lighting', + content: [ + { + label: 'Underglow', + content: [ + { + label: 'Brightness', + type: 'range', + options: [0, 255], + content: ['id_qmk_rgblight_brightness', 2, 1], + }, + { + label: 'Effect', + type: 'dropdown', + content: ['id_qmk_rgblight_effect', 2, 2], + options: [ + 'All Off', + 'Solid Color', + 'Breathing 1', + 'Breathing 2', + 'Breathing 3', + 'Breathing 4', + 'Rainbow Mood 1', + 'Rainbow Mood 2', + 'Rainbow Mood 3', + 'Rainbow Swirl 1', + 'Rainbow Swirl 2', + 'Rainbow Swirl 3', + 'Rainbow Swirl 4', + 'Rainbow Swirl 5', + 'Rainbow Swirl 6', + 'Snake 1', + 'Snake 2', + 'Snake 3', + 'Snake 4', + 'Snake 5', + 'Snake 6', + 'Knight 1', + 'Knight 2', + 'Knight 3', + 'Christmas', + 'Gradient 1', + 'Gradient 2', + 'Gradient 3', + 'Gradient 4', + 'Gradient 5', + 'Gradient 6', + 'Gradient 7', + 'Gradient 8', + 'Gradient 9', + 'Gradient 10', + 'RGB Test', + 'Alternating', + 'Twinkle 1', + 'Twinkle 2', + 'Twinkle 3', + 'Twinkle 4', + 'Twinkle 5', + 'Twinkle 6', + ], + }, + { + showIf: '{id_qmk_rgblight_effect} != 0', + label: 'Effect Speed', + type: 'range', + options: [0, 255], + content: ['id_qmk_rgblight_effect_speed', 2, 3], + }, + { + showIf: + '{id_qmk_rgblight_effect} != 0 && {id_qmk_rgblight_effect} != 35', + label: 'Color', + type: 'color', + content: ['id_qmk_rgblight_color', 2, 4], + }, + ], + }, + ], + }, +]; diff --git a/src/index.ts b/src/index.ts index aab0dc3..ec1c137 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,3 +14,4 @@ export * from './menu-types'; export * from './themes'; export * from './types.guards'; export * from './validate'; +export * from './common-menus'; diff --git a/src/transform.ts b/src/transform.ts index 14ece2f..a21e21d 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -8,7 +8,11 @@ import { VIALightingTypeDefinition, } from './types.v2'; import {LightingPreset} from './lighting-presets'; -import {validateKeyBounds, validateLayouts} from './validate'; +import { + validateCommonMenus, + validateKeyBounds, + validateLayouts, +} from './validate'; export {VIADefinitionV3, KeyboardDefinitionV3}; @@ -65,6 +69,8 @@ export const keyboardDefinitionV3ToVIADefinitionV3 = ( ...viaLayout, }; validateKeyBounds(matrix, viaLayouts); + validateCommonMenus(menus ?? []); + return { name, vendorProductId: getVendorProductId(definition), diff --git a/src/validate.ts b/src/validate.ts index 1b1d0b5..88380ff 100644 --- a/src/validate.ts +++ b/src/validate.ts @@ -1,3 +1,4 @@ +import {commonMenus} from './common-menus'; import {kleLayoutToVIALayout} from './kle-parser'; import {VIALayout} from './types.common'; import {KeyboardDefinitionV3, VIADefinitionV3} from './types.v3'; @@ -39,3 +40,17 @@ export const validateKeyBounds = ( ); } }; + +export const validateCommonMenus = (menus: VIADefinitionV3['menus']) => { + const lookupFailedKeys = (menus || []).filter((menu) => { + if (typeof menu === 'string') { + return !Object.keys(commonMenus).includes(menu); + } + return false; + }); + if (lookupFailedKeys.length) { + throw Error( + `Common menus not for found for: ${lookupFailedKeys.join(', ')}` + ); + } +}; diff --git a/test/data/v3_invalid_common_menu.json b/test/data/v3_invalid_common_menu.json new file mode 100644 index 0000000..3e08b18 --- /dev/null +++ b/test/data/v3_invalid_common_menu.json @@ -0,0 +1,201 @@ +{ + "name": "wilba.tech WT60-KH1", + "vendorId": "0x6582", + "productId": "0x0034", + "keycodes": ["wt_lighting"], + "menus": ["wt_rgb_backlight"], + "matrix": {"rows": 5, "cols": 14}, + "layouts": { + "labels": [["Bottom Row", "7U", "HHKB", "WKL"]], + "keymap": [ + [ + { + "c": "#777777" + }, + "0,0", + { + "c": "#cccccc" + }, + "0,1", + "0,2", + "0,3", + "0,4", + "0,5", + "0,6", + "0,7", + "0,8", + "0,9", + "0,10", + "0,11", + "0,12", + "0,13", + "2,13" + ], + [ + { + "c": "#aaaaaa", + "w": 1.5 + }, + "1,0", + { + "c": "#cccccc" + }, + "1,1", + "1,2", + "1,3", + "1,4", + "1,5", + "1,6", + "1,7", + "1,8", + "1,9", + "1,10", + "1,11", + "1,12", + { + "c": "#aaaaaa", + "w": 1.5 + }, + "1,13" + ], + [ + { + "w": 1.75 + }, + "2,0", + { + "c": "#cccccc" + }, + "2,1", + "2,2", + "2,3", + "2,4", + "2,5", + "2,6", + "2,7", + "2,8", + "2,9", + "2,10", + "2,11", + { + "c": "#777777", + "w": 2.25 + }, + "2,12" + ], + [ + { + "c": "#aaaaaa", + "w": 2.25 + }, + "3,0", + { + "c": "#cccccc" + }, + "3,2", + "3,3", + "3,4", + "3,5", + "3,6", + "3,7", + "3,8", + "3,9", + "3,10", + "3,11", + { + "c": "#aaaaaa", + "w": 1.75 + }, + "3,12", + "3,13" + ], + [ + { + "w": 1.5 + }, + "4,0\n\n\n0,0", + "4,1\n\n\n0,0", + { + "w": 1.5 + }, + "4,2\n\n\n0,0", + { + "c": "#cccccc", + "w": 7 + }, + "4,6\n\n\n0,0", + { + "c": "#aaaaaa", + "w": 1.5 + }, + "4,11\n\n\n0,0", + "4,12\n\n\n0,0", + { + "w": 1.5 + }, + "4,13\n\n\n0,0" + ], + [ + { + "y": 0.25, + "w": 1.5, + "d": true + }, + "4,0\n\n\n0,1", + "4,1\n\n\n0,1", + { + "w": 1.5 + }, + "4,2\n\n\n0,1", + { + "c": "#cccccc", + "w": 7 + }, + "4,6\n\n\n0,1", + { + "c": "#aaaaaa", + "w": 1.5 + }, + "4,11\n\n\n0,1", + "4,12\n\n\n0,1", + { + "w": 1.5, + "d": true + }, + "4,13\n\n\n0,1" + ], + [ + { + "w": 1.5 + }, + "4,0\n\n\n0,2", + { + "d": true + }, + "4,1\n\n\n0,2", + { + "w": 1.5 + }, + "4,2\n\n\n0,2", + { + "c": "#cccccc", + "w": 7 + }, + "4,6\n\n\n0,2", + { + "c": "#aaaaaa", + "w": 1.5 + }, + "4,11\n\n\n0,2", + { + "d": true + }, + "4,12\n\n\n0,2", + { + "w": 1.5 + }, + "4,13\n\n\n0,2" + ] + ] + } +} diff --git a/test/transform.v3.test.ts b/test/transform.v3.test.ts index c4af2c8..6785dc2 100644 --- a/test/transform.v3.test.ts +++ b/test/transform.v3.test.ts @@ -56,3 +56,18 @@ test(`Vendor ID of '0xFEED' should fail`, () => { getVendorProductId({productId: '0xFEED', vendorId: '0x1234'}) ).not.toThrow(); }); + +test('invalid common menu fails', async () => { + const invalidCommonMenuDefinitionJson = await fs.promises.readFile( + './test/data/v3_invalid_common_menu.json', + 'utf-8' + ); + + const invalidCommonMenuDefinition = JSON.parse( + invalidCommonMenuDefinitionJson + ); + + expect(() => + keyboardDefinitionV3ToVIADefinitionV3(invalidCommonMenuDefinition) + ).toThrowErrorMatchingInlineSnapshot('"Common menus not for found for: wt_rgb_backlight"'); +});