@keymanapp/common-types 17.0.85-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/build/src/consts/virtual-key-constants.d.ts +131 -0
  2. package/build/src/consts/virtual-key-constants.d.ts.map +1 -0
  3. package/build/src/consts/virtual-key-constants.js +245 -0
  4. package/build/src/consts/virtual-key-constants.js.map +1 -0
  5. package/build/src/import/techpreview/cldr_info.json +5 -0
  6. package/build/src/import/techpreview/keys-Latn-implied.xml +80 -0
  7. package/build/src/import/techpreview/keys-Zyyy-currency.xml +22 -0
  8. package/build/src/import/techpreview/keys-Zyyy-punctuation.xml +46 -0
  9. package/build/src/keyman-touch-layout/keyman-touch-layout-file-reader.d.ts +7 -0
  10. package/build/src/keyman-touch-layout/keyman-touch-layout-file-reader.d.ts.map +1 -0
  11. package/build/src/keyman-touch-layout/keyman-touch-layout-file-reader.js +74 -0
  12. package/build/src/keyman-touch-layout/keyman-touch-layout-file-reader.js.map +1 -0
  13. package/build/src/keyman-touch-layout/keyman-touch-layout-file-writer.d.ts +24 -0
  14. package/build/src/keyman-touch-layout/keyman-touch-layout-file-writer.d.ts.map +1 -0
  15. package/build/src/keyman-touch-layout/keyman-touch-layout-file-writer.js +75 -0
  16. package/build/src/keyman-touch-layout/keyman-touch-layout-file-writer.js.map +1 -0
  17. package/build/src/keyman-touch-layout/keyman-touch-layout-file.d.ts +76 -0
  18. package/build/src/keyman-touch-layout/keyman-touch-layout-file.d.ts.map +1 -0
  19. package/build/src/keyman-touch-layout/keyman-touch-layout-file.js +26 -0
  20. package/build/src/keyman-touch-layout/keyman-touch-layout-file.js.map +1 -0
  21. package/build/src/keyman-touch-layout.clean.spec.json +170 -0
  22. package/build/src/kmx/element-string.d.ts +19 -0
  23. package/build/src/kmx/element-string.d.ts.map +1 -0
  24. package/build/src/kmx/element-string.js +72 -0
  25. package/build/src/kmx/element-string.js.map +1 -0
  26. package/build/src/kmx/kmx-builder.d.ts +77 -0
  27. package/build/src/kmx/kmx-builder.d.ts.map +1 -0
  28. package/build/src/kmx/kmx-builder.js +193 -0
  29. package/build/src/kmx/kmx-builder.js.map +1 -0
  30. package/build/src/kmx/kmx-plus-builder/build-disp.d.ts +18 -0
  31. package/build/src/kmx/kmx-plus-builder/build-disp.d.ts.map +1 -0
  32. package/build/src/kmx/kmx-plus-builder/build-disp.js +25 -0
  33. package/build/src/kmx/kmx-plus-builder/build-disp.js.map +1 -0
  34. package/build/src/kmx/kmx-plus-builder/build-elem.d.ts +26 -0
  35. package/build/src/kmx/kmx-plus-builder/build-elem.d.ts.map +1 -0
  36. package/build/src/kmx/kmx-plus-builder/build-elem.js +78 -0
  37. package/build/src/kmx/kmx-plus-builder/build-elem.js.map +1 -0
  38. package/build/src/kmx/kmx-plus-builder/build-keys.d.ts +60 -0
  39. package/build/src/kmx/kmx-plus-builder/build-keys.d.ts.map +1 -0
  40. package/build/src/kmx/kmx-plus-builder/build-keys.js +107 -0
  41. package/build/src/kmx/kmx-plus-builder/build-keys.js.map +1 -0
  42. package/build/src/kmx/kmx-plus-builder/build-layr.d.ts +54 -0
  43. package/build/src/kmx/kmx-plus-builder/build-layr.d.ts.map +1 -0
  44. package/build/src/kmx/kmx-plus-builder/build-layr.js +99 -0
  45. package/build/src/kmx/kmx-plus-builder/build-layr.js.map +1 -0
  46. package/build/src/kmx/kmx-plus-builder/build-list.d.ts +34 -0
  47. package/build/src/kmx/kmx-plus-builder/build-list.d.ts.map +1 -0
  48. package/build/src/kmx/kmx-plus-builder/build-list.js +62 -0
  49. package/build/src/kmx/kmx-plus-builder/build-list.js.map +1 -0
  50. package/build/src/kmx/kmx-plus-builder/build-loca.d.ts +12 -0
  51. package/build/src/kmx/kmx-plus-builder/build-loca.d.ts.map +1 -0
  52. package/build/src/kmx/kmx-plus-builder/build-loca.js +20 -0
  53. package/build/src/kmx/kmx-plus-builder/build-loca.js.map +1 -0
  54. package/build/src/kmx/kmx-plus-builder/build-meta.d.ts +17 -0
  55. package/build/src/kmx/kmx-plus-builder/build-meta.d.ts.map +1 -0
  56. package/build/src/kmx/kmx-plus-builder/build-meta.js +21 -0
  57. package/build/src/kmx/kmx-plus-builder/build-meta.js.map +1 -0
  58. package/build/src/kmx/kmx-plus-builder/build-name.d.ts +12 -0
  59. package/build/src/kmx/kmx-plus-builder/build-name.d.ts.map +1 -0
  60. package/build/src/kmx/kmx-plus-builder/build-name.js +23 -0
  61. package/build/src/kmx/kmx-plus-builder/build-name.js.map +1 -0
  62. package/build/src/kmx/kmx-plus-builder/build-ordr.d.ts +18 -0
  63. package/build/src/kmx/kmx-plus-builder/build-ordr.d.ts.map +1 -0
  64. package/build/src/kmx/kmx-plus-builder/build-ordr.js +27 -0
  65. package/build/src/kmx/kmx-plus-builder/build-ordr.js.map +1 -0
  66. package/build/src/kmx/kmx-plus-builder/build-sect.d.ts +16 -0
  67. package/build/src/kmx/kmx-plus-builder/build-sect.d.ts.map +1 -0
  68. package/build/src/kmx/kmx-plus-builder/build-sect.js +14 -0
  69. package/build/src/kmx/kmx-plus-builder/build-sect.js.map +1 -0
  70. package/build/src/kmx/kmx-plus-builder/build-strs.d.ts +18 -0
  71. package/build/src/kmx/kmx-plus-builder/build-strs.d.ts.map +1 -0
  72. package/build/src/kmx/kmx-plus-builder/build-strs.js +34 -0
  73. package/build/src/kmx/kmx-plus-builder/build-strs.js.map +1 -0
  74. package/build/src/kmx/kmx-plus-builder/build-tran.d.ts +20 -0
  75. package/build/src/kmx/kmx-plus-builder/build-tran.d.ts.map +1 -0
  76. package/build/src/kmx/kmx-plus-builder/build-tran.js +30 -0
  77. package/build/src/kmx/kmx-plus-builder/build-tran.js.map +1 -0
  78. package/build/src/kmx/kmx-plus-builder/build-vkey.d.ts +16 -0
  79. package/build/src/kmx/kmx-plus-builder/build-vkey.d.ts.map +1 -0
  80. package/build/src/kmx/kmx-plus-builder/build-vkey.js +23 -0
  81. package/build/src/kmx/kmx-plus-builder/build-vkey.js.map +1 -0
  82. package/build/src/kmx/kmx-plus-builder/builder-section.d.ts +6 -0
  83. package/build/src/kmx/kmx-plus-builder/builder-section.d.ts.map +1 -0
  84. package/build/src/kmx/kmx-plus-builder/builder-section.js +3 -0
  85. package/build/src/kmx/kmx-plus-builder/builder-section.js.map +1 -0
  86. package/build/src/kmx/kmx-plus-builder/kmx-plus-builder.d.ts +47 -0
  87. package/build/src/kmx/kmx-plus-builder/kmx-plus-builder.d.ts.map +1 -0
  88. package/build/src/kmx/kmx-plus-builder/kmx-plus-builder.js +143 -0
  89. package/build/src/kmx/kmx-plus-builder/kmx-plus-builder.js.map +1 -0
  90. package/build/src/kmx/kmx-plus.d.ts +259 -0
  91. package/build/src/kmx/kmx-plus.d.ts.map +1 -0
  92. package/build/src/kmx/kmx-plus.js +594 -0
  93. package/build/src/kmx/kmx-plus.js.map +1 -0
  94. package/build/src/kmx/kmx.d.ts +166 -0
  95. package/build/src/kmx/kmx.d.ts.map +1 -0
  96. package/build/src/kmx/kmx.js +271 -0
  97. package/build/src/kmx/kmx.js.map +1 -0
  98. package/build/src/kmx/string-list.d.ts +29 -0
  99. package/build/src/kmx/string-list.d.ts.map +1 -0
  100. package/build/src/kmx/string-list.js +75 -0
  101. package/build/src/kmx/string-list.js.map +1 -0
  102. package/build/src/kpj/keyman-developer-project.d.ts +58 -0
  103. package/build/src/kpj/keyman-developer-project.d.ts.map +1 -0
  104. package/build/src/kpj/keyman-developer-project.js +141 -0
  105. package/build/src/kpj/keyman-developer-project.js.map +1 -0
  106. package/build/src/kpj/kpj-file-reader.d.ts +17 -0
  107. package/build/src/kpj/kpj-file-reader.d.ts.map +1 -0
  108. package/build/src/kpj/kpj-file-reader.js +92 -0
  109. package/build/src/kpj/kpj-file-reader.js.map +1 -0
  110. package/build/src/kpj/kpj-file.d.ts +39 -0
  111. package/build/src/kpj/kpj-file.d.ts.map +1 -0
  112. package/build/src/kpj/kpj-file.js +11 -0
  113. package/build/src/kpj/kpj-file.js.map +1 -0
  114. package/build/src/kpj.schema.json +127 -0
  115. package/build/src/kvk/kvk-file-reader.d.ts +5 -0
  116. package/build/src/kvk/kvk-file-reader.d.ts.map +1 -0
  117. package/build/src/kvk/kvk-file-reader.js +35 -0
  118. package/build/src/kvk/kvk-file-reader.js.map +1 -0
  119. package/build/src/kvk/kvk-file-writer.d.ts +20 -0
  120. package/build/src/kvk/kvk-file-writer.d.ts.map +1 -0
  121. package/build/src/kvk/kvk-file-writer.js +67 -0
  122. package/build/src/kvk/kvk-file-writer.js.map +1 -0
  123. package/build/src/kvk/kvk-file.d.ts +64 -0
  124. package/build/src/kvk/kvk-file.d.ts.map +1 -0
  125. package/build/src/kvk/kvk-file.js +63 -0
  126. package/build/src/kvk/kvk-file.js.map +1 -0
  127. package/build/src/kvk/kvks-file-reader.d.ts +30 -0
  128. package/build/src/kvk/kvks-file-reader.d.ts.map +1 -0
  129. package/build/src/kvk/kvks-file-reader.js +154 -0
  130. package/build/src/kvk/kvks-file-reader.js.map +1 -0
  131. package/build/src/kvk/kvks-file-writer.d.ts +6 -0
  132. package/build/src/kvk/kvks-file-writer.d.ts.map +1 -0
  133. package/build/src/kvk/kvks-file-writer.js +99 -0
  134. package/build/src/kvk/kvks-file-writer.js.map +1 -0
  135. package/build/src/kvk/kvks-file.d.ts +44 -0
  136. package/build/src/kvk/kvks-file.d.ts.map +1 -0
  137. package/build/src/kvk/kvks-file.js +10 -0
  138. package/build/src/kvk/kvks-file.js.map +1 -0
  139. package/build/src/kvk/visual-keyboard.d.ts +35 -0
  140. package/build/src/kvk/visual-keyboard.d.ts.map +1 -0
  141. package/build/src/kvk/visual-keyboard.js +61 -0
  142. package/build/src/kvk/visual-keyboard.js.map +1 -0
  143. package/build/src/kvks.schema.json +182 -0
  144. package/build/src/ldml-keyboard/ldml-keyboard-testdata-xml.d.ts +56 -0
  145. package/build/src/ldml-keyboard/ldml-keyboard-testdata-xml.d.ts.map +1 -0
  146. package/build/src/ldml-keyboard/ldml-keyboard-testdata-xml.js +20 -0
  147. package/build/src/ldml-keyboard/ldml-keyboard-testdata-xml.js.map +1 -0
  148. package/build/src/ldml-keyboard/ldml-keyboard-xml-reader.d.ts +91 -0
  149. package/build/src/ldml-keyboard/ldml-keyboard-xml-reader.d.ts.map +1 -0
  150. package/build/src/ldml-keyboard/ldml-keyboard-xml-reader.js +370 -0
  151. package/build/src/ldml-keyboard/ldml-keyboard-xml-reader.js.map +1 -0
  152. package/build/src/ldml-keyboard/ldml-keyboard-xml.d.ts +143 -0
  153. package/build/src/ldml-keyboard/ldml-keyboard-xml.d.ts.map +1 -0
  154. package/build/src/ldml-keyboard/ldml-keyboard-xml.js +34 -0
  155. package/build/src/ldml-keyboard/ldml-keyboard-xml.js.map +1 -0
  156. package/build/src/ldml-keyboard.schema.json +634 -0
  157. package/build/src/ldml-keyboardtest.schema.json +221 -0
  158. package/build/src/main.d.ts +21 -0
  159. package/build/src/main.d.ts.map +1 -0
  160. package/build/src/main.js +20 -0
  161. package/build/src/main.js.map +1 -0
  162. package/build/src/util/common-events.d.ts +49 -0
  163. package/build/src/util/common-events.d.ts.map +1 -0
  164. package/build/src/util/common-events.js +29 -0
  165. package/build/src/util/common-events.js.map +1 -0
  166. package/build/src/util/compiler-interfaces.d.ts +51 -0
  167. package/build/src/util/compiler-interfaces.d.ts.map +1 -0
  168. package/build/src/util/compiler-interfaces.js +33 -0
  169. package/build/src/util/compiler-interfaces.js.map +1 -0
  170. package/build/src/util/util.d.ts +17 -0
  171. package/build/src/util/util.d.ts.map +1 -0
  172. package/build/src/util/util.js +67 -0
  173. package/build/src/util/util.js.map +1 -0
  174. package/build/tsconfig.tsbuildinfo +1 -0
  175. package/build.sh +86 -0
  176. package/package.json +58 -0
  177. package/src/consts/virtual-key-constants.ts +257 -0
  178. package/src/keyman-touch-layout/keyman-touch-layout-file-reader.ts +81 -0
  179. package/src/keyman-touch-layout/keyman-touch-layout-file-writer.ts +84 -0
  180. package/src/keyman-touch-layout/keyman-touch-layout-file.ts +87 -0
  181. package/src/kmx/element-string.ts +79 -0
  182. package/src/kmx/kmx-builder.ts +287 -0
  183. package/src/kmx/kmx-plus-builder/build-disp.ts +46 -0
  184. package/src/kmx/kmx-plus-builder/build-elem.ts +103 -0
  185. package/src/kmx/kmx-plus-builder/build-keys.ts +175 -0
  186. package/src/kmx/kmx-plus-builder/build-layr.ts +154 -0
  187. package/src/kmx/kmx-plus-builder/build-list.ts +95 -0
  188. package/src/kmx/kmx-plus-builder/build-loca.ts +34 -0
  189. package/src/kmx/kmx-plus-builder/build-meta.ts +37 -0
  190. package/src/kmx/kmx-plus-builder/build-name.ts +37 -0
  191. package/src/kmx/kmx-plus-builder/build-ordr.ts +45 -0
  192. package/src/kmx/kmx-plus-builder/build-sect.ts +31 -0
  193. package/src/kmx/kmx-plus-builder/build-strs.ts +58 -0
  194. package/src/kmx/kmx-plus-builder/build-tran.ts +50 -0
  195. package/src/kmx/kmx-plus-builder/build-vkey.ts +43 -0
  196. package/src/kmx/kmx-plus-builder/builder-section.ts +6 -0
  197. package/src/kmx/kmx-plus-builder/kmx-plus-builder.ts +190 -0
  198. package/src/kmx/kmx-plus.ts +692 -0
  199. package/src/kmx/kmx.ts +360 -0
  200. package/src/kmx/string-list.ts +74 -0
  201. package/src/kpj/keyman-developer-project.ts +155 -0
  202. package/src/kpj/kpj-file-reader.ts +103 -0
  203. package/src/kpj/kpj-file.ts +52 -0
  204. package/src/kvk/kvk-file-reader.ts +34 -0
  205. package/src/kvk/kvk-file-writer.ts +72 -0
  206. package/src/kvk/kvk-file.ts +122 -0
  207. package/src/kvk/kvks-file-reader.ts +164 -0
  208. package/src/kvk/kvks-file-writer.ts +113 -0
  209. package/src/kvk/kvks-file.ts +53 -0
  210. package/src/kvk/visual-keyboard.ts +80 -0
  211. package/src/ldml-keyboard/ldml-keyboard-testdata-xml.ts +74 -0
  212. package/src/ldml-keyboard/ldml-keyboard-xml-reader.ts +387 -0
  213. package/src/ldml-keyboard/ldml-keyboard-xml.ts +177 -0
  214. package/src/main.ts +27 -0
  215. package/src/restructure.d.ts +2 -0
  216. package/src/util/common-events.ts +50 -0
  217. package/src/util/compiler-interfaces.ts +54 -0
  218. package/src/util/util.ts +68 -0
  219. package/test/fixtures/import-minimal.xml +8 -0
  220. package/test/fixtures/import-minimal1.xml +11 -0
  221. package/test/fixtures/import-minimal2.xml +11 -0
  222. package/test/fixtures/import-symbols.xml +13 -0
  223. package/test/fixtures/invalid-conforms-to.xml +19 -0
  224. package/test/fixtures/invalid-import-base.xml +16 -0
  225. package/test/fixtures/invalid-import-path.xml +16 -0
  226. package/test/fixtures/invalid-import-readfail.xml +16 -0
  227. package/test/fixtures/invalid-import-wrongroot.xml +16 -0
  228. package/test/fixtures/invalid-structure-per-dtd.xml +8 -0
  229. package/test/fixtures/keyman-touch-layout/khmer_angkor.keyman-touch-layout +1950 -0
  230. package/test/fixtures/keyman-touch-layout/legacy.keyman-touch-layout +36 -0
  231. package/test/fixtures/kpj/khmer_angkor.kpj +187 -0
  232. package/test/fixtures/kvk/khmer_angkor.kvk +0 -0
  233. package/test/fixtures/kvk/khmer_angkor.kvks +206 -0
  234. package/test/fixtures/test-fr.xml +22 -0
  235. package/test/helpers/index.ts +39 -0
  236. package/test/helpers/reader-callback-test.ts +199 -0
  237. package/test/keyman-touch-layout/test-keyman-touch-layout-file-reader.ts +71 -0
  238. package/test/keyman-touch-layout/test-keyman-touch-layout-round-trip.ts +35 -0
  239. package/test/kpj/test-kpj-file-reader.ts +123 -0
  240. package/test/kvk/test-kvk-file.ts +15 -0
  241. package/test/kvk/test-kvk-round-trip.ts +87 -0
  242. package/test/kvk/test-kvk-utils.ts +24 -0
  243. package/test/kvk/test-kvks-file.ts +45 -0
  244. package/test/ldml-keyboard/test-ldml-keyboard-testdata-reader.ts +51 -0
  245. package/test/ldml-keyboard/test-ldml-keyboard-xml-reader.ts +131 -0
  246. package/test/tsconfig.json +21 -0
  247. package/test/util/test-unescape.ts +38 -0
  248. package/tsconfig.json +17 -0
@@ -0,0 +1,74 @@
1
+ //
2
+ // Conforms to techpreview
3
+ //
4
+ // The interfaces in this file are designed with reference to the mapped
5
+ // structures produced by xml2js when passed a LDML keyboard test data .xml file.
6
+ //
7
+ // Using prefix LKT for LDML Keyboard Test
8
+ //
9
+
10
+ export interface LDMLKeyboardTestDataXMLSourceFile {
11
+ /**
12
+ * <keyboardTest> -- the root element.
13
+ */
14
+ keyboardTest: LKTKeyboardTest;
15
+ }
16
+
17
+ export interface LKTKeyboardTest {
18
+ conformsTo?: string;
19
+ info?: LKTInfo;
20
+ repertoire?: LKTRepertoire[];
21
+ tests?: LKTTests[];
22
+ };
23
+
24
+ export interface LKTInfo {
25
+ author?: string;
26
+ keyboard?: string;
27
+ name?: string;
28
+ };
29
+
30
+ export interface LKTRepertoire {
31
+ name?: string;
32
+ chars?: string;
33
+ type?: string;
34
+ };
35
+
36
+ export interface LKTTests {
37
+ name?: string;
38
+ test?: LKTTest[];
39
+ };
40
+
41
+ export interface LKTTest {
42
+ name?: string;
43
+ startContext?: LKTStartContext;
44
+ actions?: LKTAction[]; // differs from XML, to represent order of actions
45
+ };
46
+
47
+ export interface LKTStartContext {
48
+ to?: string;
49
+ };
50
+
51
+ export interface LKTCheck {
52
+ result?: string;
53
+ };
54
+
55
+ export interface LKTEmit {
56
+ to?: string;
57
+ };
58
+
59
+ export interface LKTKeystroke {
60
+ key?: string;
61
+ flick?: string;
62
+ longPress?: string;
63
+ tapCount?: string;
64
+ };
65
+
66
+ /**
67
+ * Test Actions.
68
+ * The expectation is that each LKTAction object will have exactly one non-falsy field.
69
+ */
70
+ export interface LKTAction {
71
+ check?: LKTCheck;
72
+ emit?: LKTEmit;
73
+ keystroke?: LKTKeystroke;
74
+ };
@@ -0,0 +1,387 @@
1
+ import * as xml2js from 'xml2js';
2
+ import { LDMLKeyboardXMLSourceFile, LKImport } from './ldml-keyboard-xml.js';
3
+ import { default as AjvModule } from 'ajv';
4
+ const Ajv = AjvModule.default; // The actual expected Ajv type.
5
+ import { boxXmlArray } from '../util/util.js';
6
+ import { CompilerCallbacks } from '../util/compiler-interfaces.js';
7
+ import { constants } from '@keymanapp/ldml-keyboard-constants';
8
+ import { CommonTypesMessages } from '../util/common-events.js';
9
+ import { LDMLKeyboardTestDataXMLSourceFile, LKTTest, LKTTests } from './ldml-keyboard-testdata-xml.js';
10
+
11
+ interface NameAndProps {
12
+ '$'?: any; // content
13
+ '#name'?: string; // element name
14
+ '$$'?: any; // children
15
+ };
16
+
17
+ export default class LDMLKeyboardXMLSourceFileReader {
18
+ callbacks: CompilerCallbacks;
19
+
20
+ constructor(callbacks : CompilerCallbacks) {
21
+ this.callbacks = callbacks;
22
+ }
23
+
24
+ readImportFile(version: string, subpath: string): Buffer {
25
+ // TODO-LDML: sanitize input string
26
+ let importPath = new URL(`../import/${version}/${subpath}`, import.meta.url);
27
+ // TODO-LDML: support baseFileName?
28
+ return this.callbacks.loadFile(importPath.pathname, importPath);
29
+ }
30
+
31
+ /**
32
+ * xml2js will not place single-entry objects into arrays.
33
+ * Easiest way to fix this is to box them ourselves as needed
34
+ * @param source any
35
+ * @returns true on success, false on failure
36
+ */
37
+ private boxArrays(source: any) : boolean {
38
+ if (source?.keyboard) {
39
+ if (!source.keyboard.keys) {
40
+ source.keyboard.keys = {
41
+ key: [],
42
+ flicks: [],
43
+ };
44
+ }
45
+ if (!source.keyboard.keys.import) {
46
+ source.keyboard.keys.import = [];
47
+ }
48
+ }
49
+ boxXmlArray(source?.keyboard, 'layers');
50
+ boxXmlArray(source?.keyboard?.displays, 'display');
51
+ boxXmlArray(source?.keyboard?.names, 'name');
52
+ boxXmlArray(source?.keyboard?.vkeys, 'vkey');
53
+ boxXmlArray(source?.keyboard?.keys, 'key');
54
+ boxXmlArray(source?.keyboard?.keys, 'flicks');
55
+ boxXmlArray(source?.keyboard?.locales, 'locale');
56
+ boxXmlArray(source?.keyboard, 'transforms');
57
+ if(source?.keyboard?.layers) {
58
+ for(let layers of source?.keyboard?.layers) {
59
+ boxXmlArray(layers, 'layer');
60
+ if(layers?.layer) {
61
+ for(let layer of layers?.layer) {
62
+ boxXmlArray(layer, 'row');
63
+ }
64
+ }
65
+ }
66
+ }
67
+ if(source?.keyboard?.keys?.flicks) {
68
+ for(let flicks of source?.keyboard?.keys?.flicks) {
69
+ boxXmlArray(flicks, 'flick');
70
+ }
71
+ }
72
+ if(source?.keyboard?.transforms) {
73
+ for(let transform of source.keyboard.transforms) {
74
+ boxXmlArray(transform, 'transform');
75
+ }
76
+ }
77
+ boxXmlArray(source?.keyboard?.reorders, 'reorder');
78
+ return this.boxImportsAndSpecials(source, 'keyboard');
79
+ }
80
+
81
+ /**
82
+ * Recurse over object, boxing up any specials or imports
83
+ * @param obj any object to be traversed
84
+ * @param subtag the leafmost enclosing tag such as 'keyboard'
85
+ * @returns true on success, false on failure
86
+ */
87
+ private boxImportsAndSpecials(obj: any, subtag: string) : boolean {
88
+ if (!obj) return true;
89
+ if (Array.isArray(obj)) {
90
+ for (const sub of obj) {
91
+ // retain the same subtag
92
+ if (!this.boxImportsAndSpecials(sub, subtag)) {
93
+ return false;
94
+ }
95
+ }
96
+ } else if(typeof obj === 'object') {
97
+ for (const key of Object.keys(obj)) {
98
+ if (key === 'special') {
99
+ boxXmlArray(obj, key);
100
+ } else if(key === 'import') {
101
+ // Need to 'box it up' first for processing
102
+ boxXmlArray(obj, key);
103
+ // Now, resolve the import
104
+ if (!this.resolveImports(obj, subtag)) {
105
+ return false;
106
+ }
107
+ // now delete the import array we so carefully constructed, the caller does not
108
+ // want to see it.
109
+ delete obj['import'];
110
+ } else {
111
+ if (!this.boxImportsAndSpecials(obj[key], key)) {
112
+ return false;
113
+ }
114
+ }
115
+ }
116
+ }
117
+ return true;
118
+ }
119
+
120
+ /**
121
+ *
122
+ * @param obj object to be imported into
123
+ * @param subtag obj's element tag, e.g. `keys`
124
+ * @returns true on success, false on failure
125
+ */
126
+ private resolveImports(obj: any, subtag: string) : boolean {
127
+ // These are in reverse order, because the imports insert at the beginning of the array.
128
+ // first, the explicit imports
129
+ for (const asImport of ([...obj['import'] as LKImport[]].reverse())) {
130
+ if (!this.resolveOneImport(obj, subtag, asImport)) {
131
+ return false;
132
+ }
133
+ }
134
+ // then, the implied imports
135
+ if (subtag === 'keys') {
136
+ // <import base="cldr" path="techpreview/keys-Latn-implied.xml"/>
137
+ if (!this.resolveOneImport(obj, subtag, {
138
+ base: constants.cldr_import_base,
139
+ path: constants.cldr_implied_keys_import
140
+ })) {
141
+ return false;
142
+ }
143
+ }
144
+ return true;
145
+ }
146
+
147
+ /**
148
+ * @param obj the object being imported into
149
+ * @param subtag obj's element tag, e.g. `keys`
150
+ * @param asImport the import structure
151
+ * @returns true on success, false on failure
152
+ */
153
+ private resolveOneImport(obj: any, subtag: string, asImport: LKImport) : boolean {
154
+ const { base, path } = asImport;
155
+ if (base !== constants.cldr_import_base) {
156
+ this.callbacks.reportMessage(CommonTypesMessages.Error_ImportInvalidBase({base, path, subtag}));
157
+ return false;
158
+ }
159
+ const paths = path.split('/');
160
+ if (paths[0] == '' || paths[1] == '' || paths.length !== 2) {
161
+ this.callbacks.reportMessage(CommonTypesMessages.Error_ImportInvalidPath({base, path, subtag}));
162
+ return false;
163
+ }
164
+ const importData: Uint8Array = this.readImportFile(paths[0], paths[1]);
165
+ if (!importData || !importData.length) {
166
+ this.callbacks.reportMessage(CommonTypesMessages.Error_ImportReadFail({base, path, subtag}));
167
+ return false;
168
+ }
169
+ const importXml: any = this.loadUnboxed(importData); // TODO-LDML: have to load as any because it is an arbitrary part
170
+ const importRootNode = importXml[subtag]; // e.g. <keys/>
171
+
172
+ // importXml will have one property: the root element.
173
+ if (!importRootNode) {
174
+ this.callbacks.reportMessage(CommonTypesMessages.Error_ImportWrongRoot({base, path, subtag}));
175
+ return false;
176
+ }
177
+ // pull all children of importXml[subtag] into obj
178
+ for (const subsubtag of Object.keys(importRootNode).reverse()) { // e.g. <key/>
179
+ const subsubval = importRootNode[subsubtag];
180
+ if (!Array.isArray(subsubval)) {
181
+ // This is somewhat of an internal error, indicating that a non-mergeable XML file was imported
182
+ // Not exercisable with the standard LDML imports.
183
+ this.callbacks.reportMessage(CommonTypesMessages.Error_ImportMergeFail({base, path, subtag, subsubtag}));
184
+ return false;
185
+ }
186
+ if (!obj[subsubtag]) {
187
+ obj[subsubtag] = []; // start with empty array
188
+ }
189
+ obj[subsubtag] = [...subsubval, ...obj[subsubtag]];
190
+ }
191
+ return true;
192
+ }
193
+
194
+ /**
195
+ * @returns true if valid, false if invalid
196
+ */
197
+ public validate(source: LDMLKeyboardXMLSourceFile | LDMLKeyboardTestDataXMLSourceFile, schemaSource: Buffer): boolean {
198
+ const schema = JSON.parse(schemaSource.toString('utf8'));
199
+ const ajv = new Ajv();
200
+ if(!ajv.validate(schema, source)) {
201
+ for (let err of ajv.errors) {
202
+ this.callbacks.reportMessage(CommonTypesMessages.Error_SchemaValidationError({
203
+ instancePath: err.instancePath,
204
+ keyword: err.keyword,
205
+ message: err.message || 'Unknown AJV Error', // docs say 'message' is optional if 'messages:false' in options
206
+ params: Object.entries(err.params || {}).sort().map(([k,v])=>`${k}="${v}"`).join(' '),
207
+ }));
208
+ }
209
+ return false;
210
+ }
211
+ return true;
212
+ }
213
+
214
+ loadUnboxed(file: Uint8Array): LDMLKeyboardXMLSourceFile {
215
+ let source = (() => {
216
+ let a: LDMLKeyboardXMLSourceFile;
217
+ let parser = new xml2js.Parser({
218
+ explicitArray: false,
219
+ mergeAttrs: true,
220
+ includeWhiteChars: false,
221
+ emptyTag: {} as any
222
+ // Why "as any"? xml2js is broken:
223
+ // https://github.com/Leonidas-from-XIV/node-xml2js/issues/648 means
224
+ // that an old version of `emptyTag` is used which doesn't support
225
+ // functions, but DefinitelyTyped is requiring use of function or a
226
+ // string. See also notes at
227
+ // https://github.com/DefinitelyTyped/DefinitelyTyped/pull/59259#issuecomment-1254405470
228
+ // An alternative fix would be to pull xml2js directly from github
229
+ // rather than using the version tagged on npmjs.com.
230
+ });
231
+ parser.parseString(file, (e: unknown, r: unknown) => { a = r as LDMLKeyboardXMLSourceFile }); // TODO-LDML: isn't 'e' the error?
232
+ return a;
233
+ })();
234
+ return source;
235
+ }
236
+
237
+ /**
238
+ * @param file
239
+ * @returns source on success, otherwise null
240
+ */
241
+ public load(file: Uint8Array): LDMLKeyboardXMLSourceFile | null {
242
+ if (!file) {
243
+ return null;
244
+ }
245
+ const source = this.loadUnboxed(file);
246
+ if(this.boxArrays(source)) {
247
+ return source;
248
+ } else {
249
+ return null;
250
+ }
251
+ }
252
+
253
+ loadTestDataUnboxed(file: Uint8Array): any {
254
+ let source = (() => {
255
+ let a: any;
256
+ let parser = new xml2js.Parser({
257
+ // explicitArray: false,
258
+ preserveChildrenOrder:true, // needed for test data
259
+ explicitChildren: true, // needed for test data
260
+ // mergeAttrs: true,
261
+ // includeWhiteChars: false,
262
+ // emptyTag: {} as any
263
+ // Why "as any"? xml2js is broken:
264
+ // https://github.com/Leonidas-from-XIV/node-xml2js/issues/648 means
265
+ // that an old version of `emptyTag` is used which doesn't support
266
+ // functions, but DefinitelyTyped is requiring use of function or a
267
+ // string. See also notes at
268
+ // https://github.com/DefinitelyTyped/DefinitelyTyped/pull/59259#issuecomment-1254405470
269
+ // An alternative fix would be to pull xml2js directly from github
270
+ // rather than using the version tagged on npmjs.com.
271
+ });
272
+ parser.parseString(file, (e: unknown, r: unknown) => { a = r as any }); // TODO-LDML: isn't 'e' the error?
273
+ return a; // Why 'any'? Because we need to box up the $'s into proper properties.
274
+ })();
275
+ return source;
276
+ }
277
+
278
+ /**
279
+ * Filter the obj array for a subtag
280
+ * @param source array of source objs
281
+ * @param subtag subtag to filter on
282
+ * @returns
283
+ */
284
+ findSubtagArray(source: NameAndProps[], subtag: string): NameAndProps[] {
285
+ return source?.filter(o => o['#name'] === subtag);
286
+ }
287
+
288
+ /**
289
+ * Get exactly one element
290
+ * @param source
291
+ * @param subtag
292
+ * @returns
293
+ */
294
+ findSubtag(source: NameAndProps[], subtag: string): NameAndProps | null {
295
+ const r = this.findSubtagArray(source, subtag);
296
+ if (!r || r.length === 0) {
297
+ return null;
298
+ } else if (r.length === 1) {
299
+ return r[0];
300
+ } else {
301
+ this.callbacks.reportMessage(CommonTypesMessages.Error_TestDataUnexpectedArray({subtag}));
302
+ return null; // ERROR
303
+ }
304
+ }
305
+
306
+ /**
307
+ * The default test data stuffer.
308
+ * Just gets $ (the attrs) as the body.
309
+ * Override to use something more complex, such as including child nodes.
310
+ * @param o object to map
311
+ * @param r back ref to reader
312
+ */
313
+ static readonly defaultMapper = ((o : NameAndProps, r: LDMLKeyboardXMLSourceFileReader) => o?.$);
314
+
315
+ /**
316
+ *
317
+ * @param obj target object
318
+ * @param source array of $/#name strings
319
+ * @param subtag name to extract
320
+ * @param mapper custom mapper function
321
+ */
322
+ stuffBoxes(obj: any, source: NameAndProps[], subtag: string, asArray?: boolean, mapper?: (v: NameAndProps, r: LDMLKeyboardXMLSourceFileReader) => any) {
323
+ if (!mapper) {
324
+ mapper = LDMLKeyboardXMLSourceFileReader.defaultMapper;
325
+ }
326
+ if (asArray) {
327
+ const r = this;
328
+ obj[subtag] = this.findSubtagArray(source, subtag)?.map((v) => mapper(v, r)); // extract contents only
329
+ } else {
330
+ obj[subtag] = mapper(this.findSubtag(source, subtag), this); // run the mapper once
331
+ }
332
+ }
333
+
334
+ boxTestDataArrays(raw: any) : LDMLKeyboardTestDataXMLSourceFile | null {
335
+ if (!raw) return null;
336
+ const a : LDMLKeyboardTestDataXMLSourceFile = {
337
+ keyboardTest: {
338
+ conformsTo: raw?.keyboardTest?.$?.conformsTo,
339
+ }
340
+ };
341
+
342
+ const $$ : NameAndProps[] = raw?.keyboardTest?.$$;
343
+
344
+ this.stuffBoxes(a.keyboardTest, $$, 'info');
345
+ this.stuffBoxes(a.keyboardTest, $$, 'repertoire', true);
346
+ this.stuffBoxes(a.keyboardTest, $$, 'tests', true, (o, r) => {
347
+ // start with basic unpack
348
+ const tests : LKTTests = LDMLKeyboardXMLSourceFileReader.defaultMapper(o, r);
349
+ // add ingredients
350
+ r.stuffBoxes(tests, o.$$, 'test', true, (o, r) => {
351
+ // start with basic unpack
352
+ const test : LKTTest = LDMLKeyboardXMLSourceFileReader.defaultMapper(o, r);
353
+ // add ingredients
354
+ const $$ : NameAndProps[] = o.$$;
355
+ r.stuffBoxes(test, $$, 'startContext'); // singleton
356
+ // now the actions
357
+ test.actions = $$.map(v => {
358
+ const subtag = v['#name'];
359
+ const subv = LDMLKeyboardXMLSourceFileReader.defaultMapper(v, r);
360
+ switch(subtag) {
361
+ case 'keystroke': return { keystroke: subv };
362
+ case 'check': return { check: subv };
363
+ case 'emit': return { emit: subv };
364
+ case 'startContext': return null; // handled above
365
+ default: this.callbacks.reportMessage(CommonTypesMessages.Error_TestDataUnexpectedAction({ subtag })); return null;
366
+ }
367
+ }).filter(v => v !== null);
368
+ return test;
369
+ });
370
+ return tests;
371
+ });
372
+
373
+ return a;
374
+ }
375
+
376
+ /**
377
+ * @param file test file
378
+ * @returns source on success, otherwise null
379
+ */
380
+ public loadTestData(file: Uint8Array): LDMLKeyboardTestDataXMLSourceFile | null {
381
+ if (!file) {
382
+ return null;
383
+ }
384
+ const source = this.loadTestDataUnboxed(file);
385
+ return this.boxTestDataArrays(source);
386
+ }
387
+ }
@@ -0,0 +1,177 @@
1
+ //
2
+ // Conforms to techpreview
3
+ //
4
+ // The interfaces in this file are designed with reference to the mapped
5
+ // structures produced by xml2js when passed a LDML keyboard .xml file.
6
+ //
7
+ // Using prefix LK for LDML Keyboard
8
+ //
9
+
10
+ export interface LDMLKeyboardXMLSourceFile {
11
+ /**
12
+ * <keyboard> -- the root element.
13
+ */
14
+ keyboard: LKKeyboard;
15
+ }
16
+
17
+ export interface LKKeyboard {
18
+ locale?: string;
19
+ conformsTo?: string;
20
+
21
+ locales?: LKLocales;
22
+ version?: LKVersion;
23
+ info?: LKInfo;
24
+ names?: LKNames;
25
+ settings?: LKSettings;
26
+ keys?: LKKeys;
27
+ displays?: LKDisplays;
28
+ layers?: LKLayers[];
29
+ vkeys?: LKVkeys;
30
+ transforms?: LKTransforms[];
31
+ reorders?: LKReorders;
32
+ };
33
+
34
+ /**
35
+ * This is defined as an interface, but actually is resolved during the reading phase
36
+ */
37
+ export interface LKImport {
38
+ /**
39
+ * import base, currently `cldr` is supported
40
+ */
41
+ base: string;
42
+ /**
43
+ * path to imported resource, of the form `techpreview/*.xml`
44
+ */
45
+ path: string;
46
+ };
47
+
48
+ export interface LKLocales {
49
+ locale: LKLocale[];
50
+ };
51
+
52
+ export interface LKLocale {
53
+ id?: string;
54
+ };
55
+
56
+ export interface LKVersion {
57
+ number: string; // semver string
58
+ }
59
+
60
+ export interface LKInfo {
61
+ author?: string;
62
+ indicator?: string;
63
+ layout?: string;
64
+ normalization?: string;
65
+ };
66
+
67
+ export interface LKNames {
68
+ name: LKName[];
69
+ };
70
+
71
+ export interface LKName {
72
+ value?: string;
73
+ };
74
+
75
+ export interface LKSettings {
76
+ fallback: "omit";
77
+ transformFailure: "omit";
78
+ transformPartial: "hide";
79
+ };
80
+
81
+ export interface LKKeys {
82
+ key: LKKey[];
83
+ flicks: LKFlicks[];
84
+ };
85
+
86
+ export interface LKKey {
87
+ id?: string;
88
+ flicks?: string;
89
+ to?: string;
90
+ gap?: boolean;
91
+ switch?: string;
92
+ longPress?: string;
93
+ longPressDefault?: string;
94
+ multiTap?: string;
95
+ transform?: "no";
96
+ width?: number;
97
+ };
98
+
99
+ export interface LKFlicks {
100
+ id?: string;
101
+ flick?: LKFlick[];
102
+ };
103
+
104
+ export interface LKFlick {
105
+ directions?: string;
106
+ to?: string;
107
+ };
108
+
109
+ export interface LKLayers {
110
+ /**
111
+ * `touch`, or hardware `us`, `iso`, `jis`, `abnt2`
112
+ */
113
+ form?: string;
114
+ /**
115
+ * Minimum width in millimeters
116
+ */
117
+ minDeviceWidth?: number;
118
+ layer?: LKLayer[];
119
+ };
120
+
121
+ export interface LKLayer {
122
+ id?: string;
123
+ modifier?: string;
124
+ row?: LKRow[];
125
+ };
126
+
127
+ export interface LKRow {
128
+ keys?: string;
129
+ };
130
+
131
+ export interface LKVkeys {
132
+ vkey?: LKVkey[];
133
+ };
134
+
135
+ export interface LKVkey {
136
+ from?: string;
137
+ to?: string;
138
+ };
139
+
140
+ export interface LKTransforms {
141
+ type?: "simple" | "final";
142
+ transform: LKTransform[];
143
+ };
144
+
145
+ export interface LKTransform {
146
+ from?: string;
147
+ to?: string;
148
+ before?: string;
149
+ error?: "fail";
150
+ };
151
+
152
+ export interface LKReorders {
153
+ reorder: LKReorder[];
154
+ };
155
+
156
+ export interface LKReorder {
157
+ from?: string;
158
+ before?: string;
159
+ order?: string;
160
+ tertiary?: string;
161
+ tertiary_base?: string;
162
+ prebase?: string;
163
+ };
164
+
165
+ export interface LKDisplayOptions {
166
+ baseCharacter?: string;
167
+ };
168
+
169
+ export interface LKDisplay {
170
+ to?: string;
171
+ display?: string;
172
+ };
173
+
174
+ export interface LKDisplays {
175
+ display?: LKDisplay[];
176
+ displayOptions?: LKDisplayOptions;
177
+ };
package/src/main.ts ADDED
@@ -0,0 +1,27 @@
1
+
2
+ export * as KMX from './kmx/kmx.js';
3
+ export * as KMXPlus from './kmx/kmx-plus.js';
4
+ export { default as KMXBuilder } from './kmx/kmx-builder.js';
5
+
6
+ export * as VisualKeyboard from './kvk/visual-keyboard.js';
7
+ export { default as KMXPlusBuilder} from './kmx/kmx-plus-builder/kmx-plus-builder.js';
8
+ export { default as KvkFileReader } from './kvk/kvk-file-reader.js';
9
+ export { default as KvksFileReader } from './kvk/kvks-file-reader.js';
10
+ export { default as KvkFileWriter } from './kvk/kvk-file-writer.js';
11
+
12
+ export * as LDMLKeyboard from './ldml-keyboard/ldml-keyboard-xml.js';
13
+ export { LDMLKeyboardTestDataXMLSourceFile } from './ldml-keyboard/ldml-keyboard-testdata-xml.js';
14
+ export { default as LDMLKeyboardXMLSourceFileReader } from './ldml-keyboard/ldml-keyboard-xml-reader.js';
15
+
16
+ export * as Constants from './consts/virtual-key-constants.js';
17
+
18
+ export { CompilerCallbacks, CompilerEvent, CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageSpec } from './util/compiler-interfaces.js';
19
+ export { CommonTypesMessages } from './util/common-events.js';
20
+
21
+ export * as TouchLayout from './keyman-touch-layout/keyman-touch-layout-file.js';
22
+ export { TouchLayoutFileReader } from './keyman-touch-layout/keyman-touch-layout-file-reader.js';
23
+ export { TouchLayoutFileWriter, TouchLayoutFileWriterOptions } from './keyman-touch-layout/keyman-touch-layout-file-writer.js';
24
+
25
+ export * as KPJ from './kpj/kpj-file.js';
26
+ export { KPJFileReader } from './kpj/kpj-file-reader.js';
27
+ export { KeymanDeveloperProject } from './kpj/keyman-developer-project.js';
@@ -0,0 +1,2 @@
1
+ // TODO: consider defining more types?
2
+ declare module 'restructure';