@es-joy/jsoe 0.3.0 → 0.4.1

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 (189) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc.cjs +1 -0
  3. package/.ncurc.cjs +9 -0
  4. package/CHANGES.md +8 -0
  5. package/demo/index.html +8 -0
  6. package/demo/index.js +1 -1
  7. package/dist/formatAndTypeChoices.d.ts +56 -0
  8. package/dist/formatAndTypeChoices.d.ts.map +1 -0
  9. package/dist/formats/indexedDBKey.d.ts +4 -0
  10. package/dist/formats/indexedDBKey.d.ts.map +1 -0
  11. package/dist/formats/json.d.ts +4 -0
  12. package/dist/formats/json.d.ts.map +1 -0
  13. package/dist/formats/schemaAndArbitrary.d.ts +6 -0
  14. package/dist/formats/schemaAndArbitrary.d.ts.map +1 -0
  15. package/dist/formats/schemaOnly.d.ts +6 -0
  16. package/dist/formats/schemaOnly.d.ts.map +1 -0
  17. package/dist/formats/structuredCloning.d.ts +20 -0
  18. package/dist/formats/structuredCloning.d.ts.map +1 -0
  19. package/dist/formats.d.ts +26 -0
  20. package/dist/formats.d.ts.map +1 -0
  21. package/dist/fundamentalTypes/BooleanObjectType.d.ts +8 -0
  22. package/dist/fundamentalTypes/BooleanObjectType.d.ts.map +1 -0
  23. package/dist/fundamentalTypes/NumberObjectType.d.ts +6 -0
  24. package/dist/fundamentalTypes/NumberObjectType.d.ts.map +1 -0
  25. package/dist/fundamentalTypes/StringObjectType.d.ts +6 -0
  26. package/dist/fundamentalTypes/StringObjectType.d.ts.map +1 -0
  27. package/dist/fundamentalTypes/arrayReferenceType.d.ts +8 -0
  28. package/dist/fundamentalTypes/arrayReferenceType.d.ts.map +1 -0
  29. package/dist/fundamentalTypes/arrayType.d.ts +60 -0
  30. package/dist/fundamentalTypes/arrayType.d.ts.map +1 -0
  31. package/dist/fundamentalTypes/bigintType.d.ts +6 -0
  32. package/dist/fundamentalTypes/bigintType.d.ts.map +1 -0
  33. package/dist/fundamentalTypes/dateType.d.ts +26 -0
  34. package/dist/fundamentalTypes/dateType.d.ts.map +1 -0
  35. package/dist/fundamentalTypes/nullType.d.ts +6 -0
  36. package/dist/fundamentalTypes/nullType.d.ts.map +1 -0
  37. package/dist/fundamentalTypes/numberType.d.ts +6 -0
  38. package/dist/fundamentalTypes/numberType.d.ts.map +1 -0
  39. package/dist/fundamentalTypes/objectReferenceType.d.ts +8 -0
  40. package/dist/fundamentalTypes/objectReferenceType.d.ts.map +1 -0
  41. package/dist/fundamentalTypes/objectType.d.ts +6 -0
  42. package/dist/fundamentalTypes/objectType.d.ts.map +1 -0
  43. package/dist/fundamentalTypes/regexpType.d.ts +8 -0
  44. package/dist/fundamentalTypes/regexpType.d.ts.map +1 -0
  45. package/dist/fundamentalTypes/sparseUndefinedType.d.ts +6 -0
  46. package/dist/fundamentalTypes/sparseUndefinedType.d.ts.map +1 -0
  47. package/dist/fundamentalTypes/stringType.d.ts +6 -0
  48. package/dist/fundamentalTypes/stringType.d.ts.map +1 -0
  49. package/dist/fundamentalTypes/undefinedType.d.ts +6 -0
  50. package/dist/fundamentalTypes/undefinedType.d.ts.map +1 -0
  51. package/dist/index.d.ts +5 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/src/deepEqual.d.ts +3 -0
  54. package/dist/src/deepEqual.d.ts.map +1 -0
  55. package/dist/src/formatAndTypeChoices.d.ts +47 -0
  56. package/dist/src/formatAndTypeChoices.d.ts.map +1 -0
  57. package/dist/src/formats/indexedDBKey.d.ts +9 -0
  58. package/dist/src/formats/indexedDBKey.d.ts.map +1 -0
  59. package/dist/src/formats/json.d.ts +9 -0
  60. package/dist/src/formats/json.d.ts.map +1 -0
  61. package/dist/src/formats/schemaAndArbitrary.d.ts +6 -0
  62. package/dist/src/formats/schemaAndArbitrary.d.ts.map +1 -0
  63. package/dist/src/formats/schemaOnly.d.ts +6 -0
  64. package/dist/src/formats/schemaOnly.d.ts.map +1 -0
  65. package/dist/src/formats/structuredCloning.d.ts +15 -0
  66. package/dist/src/formats/structuredCloning.d.ts.map +1 -0
  67. package/dist/src/formats.d.ts +18 -0
  68. package/dist/src/formats.d.ts.map +1 -0
  69. package/dist/src/fundamentalTypes/BooleanObjectType.d.ts +6 -0
  70. package/dist/src/fundamentalTypes/BooleanObjectType.d.ts.map +1 -0
  71. package/dist/src/fundamentalTypes/NumberObjectType.d.ts +6 -0
  72. package/dist/src/fundamentalTypes/NumberObjectType.d.ts.map +1 -0
  73. package/dist/src/fundamentalTypes/StringObjectType.d.ts +6 -0
  74. package/dist/src/fundamentalTypes/StringObjectType.d.ts.map +1 -0
  75. package/dist/src/fundamentalTypes/arrayReferenceType.d.ts +6 -0
  76. package/dist/src/fundamentalTypes/arrayReferenceType.d.ts.map +1 -0
  77. package/dist/src/fundamentalTypes/arrayType.d.ts +6 -0
  78. package/dist/src/fundamentalTypes/arrayType.d.ts.map +1 -0
  79. package/dist/src/fundamentalTypes/bigintType.d.ts +6 -0
  80. package/dist/src/fundamentalTypes/bigintType.d.ts.map +1 -0
  81. package/dist/src/fundamentalTypes/dateType.d.ts +6 -0
  82. package/dist/src/fundamentalTypes/dateType.d.ts.map +1 -0
  83. package/dist/src/fundamentalTypes/nullType.d.ts +6 -0
  84. package/dist/src/fundamentalTypes/nullType.d.ts.map +1 -0
  85. package/dist/src/fundamentalTypes/numberType.d.ts +6 -0
  86. package/dist/src/fundamentalTypes/numberType.d.ts.map +1 -0
  87. package/dist/src/fundamentalTypes/objectReferenceType.d.ts +6 -0
  88. package/dist/src/fundamentalTypes/objectReferenceType.d.ts.map +1 -0
  89. package/dist/src/fundamentalTypes/objectType.d.ts +6 -0
  90. package/dist/src/fundamentalTypes/objectType.d.ts.map +1 -0
  91. package/dist/src/fundamentalTypes/regexpType.d.ts +6 -0
  92. package/dist/src/fundamentalTypes/regexpType.d.ts.map +1 -0
  93. package/dist/src/fundamentalTypes/sparseUndefinedType.d.ts +6 -0
  94. package/dist/src/fundamentalTypes/sparseUndefinedType.d.ts.map +1 -0
  95. package/dist/src/fundamentalTypes/stringType.d.ts +6 -0
  96. package/dist/src/fundamentalTypes/stringType.d.ts.map +1 -0
  97. package/dist/src/fundamentalTypes/undefinedType.d.ts +6 -0
  98. package/dist/src/fundamentalTypes/undefinedType.d.ts.map +1 -0
  99. package/dist/src/index.d.ts +5 -0
  100. package/dist/src/index.d.ts.map +1 -0
  101. package/dist/src/subTypes/blobHTMLType.d.ts +26 -0
  102. package/dist/src/subTypes/blobHTMLType.d.ts.map +1 -0
  103. package/dist/src/subTypes/falseType.d.ts +6 -0
  104. package/dist/src/subTypes/falseType.d.ts.map +1 -0
  105. package/dist/src/subTypes/trueType.d.ts +6 -0
  106. package/dist/src/subTypes/trueType.d.ts.map +1 -0
  107. package/dist/src/superTypes/SpecialNumberSuperType.d.ts +11 -0
  108. package/dist/src/superTypes/SpecialNumberSuperType.d.ts.map +1 -0
  109. package/dist/src/superTypes/SpecialRealNumberSuperType.d.ts +6 -0
  110. package/dist/src/superTypes/SpecialRealNumberSuperType.d.ts.map +1 -0
  111. package/dist/src/typeChoices.d.ts +30 -0
  112. package/dist/src/typeChoices.d.ts.map +1 -0
  113. package/dist/src/types.d.ts +333 -0
  114. package/dist/src/types.d.ts.map +1 -0
  115. package/dist/src/utils/dialogs.d.ts +29 -0
  116. package/dist/src/utils/dialogs.d.ts.map +1 -0
  117. package/dist/src/utils/jsonPointer.d.ts +42 -0
  118. package/dist/src/utils/jsonPointer.d.ts.map +1 -0
  119. package/dist/src/utils/templateUtils.d.ts +59 -0
  120. package/dist/src/utils/templateUtils.d.ts.map +1 -0
  121. package/dist/src/utils/types.d.ts +2 -0
  122. package/dist/src/utils/types.d.ts.map +1 -0
  123. package/dist/subTypes/blobHTMLType.d.ts +14 -0
  124. package/dist/subTypes/blobHTMLType.d.ts.map +1 -0
  125. package/dist/subTypes/falseType.d.ts +8 -0
  126. package/dist/subTypes/falseType.d.ts.map +1 -0
  127. package/dist/subTypes/trueType.d.ts +8 -0
  128. package/dist/subTypes/trueType.d.ts.map +1 -0
  129. package/dist/superTypes/SpecialNumberSuperType.d.ts +14 -0
  130. package/dist/superTypes/SpecialNumberSuperType.d.ts.map +1 -0
  131. package/dist/superTypes/SpecialRealNumberSuperType.d.ts +6 -0
  132. package/dist/superTypes/SpecialRealNumberSuperType.d.ts.map +1 -0
  133. package/dist/typeChoices.d.ts +103 -0
  134. package/dist/typeChoices.d.ts.map +1 -0
  135. package/dist/types.d.ts +523 -0
  136. package/dist/types.d.ts.map +1 -0
  137. package/dist/utils/dialogs.d.ts +109 -0
  138. package/dist/utils/dialogs.d.ts.map +1 -0
  139. package/dist/utils/jsonPointer.d.ts +46 -0
  140. package/dist/utils/jsonPointer.d.ts.map +1 -0
  141. package/dist/utils/templateUtils.d.ts +59 -0
  142. package/dist/utils/templateUtils.d.ts.map +1 -0
  143. package/dist/utils/types.d.ts +2 -0
  144. package/dist/utils/types.d.ts.map +1 -0
  145. package/dist/vendor/jamilih/dist/jml-es.d.ts +436 -0
  146. package/dist/vendor/jamilih/dist/jml-es.d.ts.map +1 -0
  147. package/dist/vendor/typeson-registry/dist/index.d.ts +400 -0
  148. package/dist/vendor/typeson-registry/dist/index.d.ts.map +1 -0
  149. package/dist/vendor-imports.d.ts +3 -0
  150. package/dist/vendor-imports.d.ts.map +1 -0
  151. package/package.json +17 -11
  152. package/postorder-traversal.js +58 -0
  153. package/src/formatAndTypeChoices.js +95 -50
  154. package/src/formats/indexedDBKey.js +49 -57
  155. package/src/formats/json.js +47 -56
  156. package/src/formats/schemaOnly.js +12 -2
  157. package/src/formats/structuredCloning.js +162 -105
  158. package/src/formats.js +38 -10
  159. package/src/fundamentalTypes/BooleanObjectType.js +6 -4
  160. package/src/fundamentalTypes/NumberObjectType.js +5 -3
  161. package/src/fundamentalTypes/StringObjectType.js +1 -1
  162. package/src/fundamentalTypes/arrayReferenceType.js +29 -14
  163. package/src/fundamentalTypes/arrayType.js +789 -278
  164. package/src/fundamentalTypes/bigintType.js +2 -2
  165. package/src/fundamentalTypes/dateType.js +42 -14
  166. package/src/fundamentalTypes/nullType.js +1 -1
  167. package/src/fundamentalTypes/numberType.js +2 -2
  168. package/src/fundamentalTypes/objectReferenceType.js +7 -5
  169. package/src/fundamentalTypes/regexpType.js +45 -24
  170. package/src/fundamentalTypes/sparseUndefinedType.js +7 -1
  171. package/src/fundamentalTypes/stringType.js +1 -1
  172. package/src/fundamentalTypes/undefinedType.js +2 -2
  173. package/src/subTypes/blobHTMLType.js +42 -22
  174. package/src/subTypes/falseType.js +2 -2
  175. package/src/subTypes/trueType.js +2 -2
  176. package/src/superTypes/SpecialNumberSuperType.js +13 -6
  177. package/src/superTypes/SpecialRealNumberSuperType.js +11 -5
  178. package/src/typeChoices.js +137 -55
  179. package/src/types.js +309 -146
  180. package/src/utils/dialogs.js +98 -29
  181. package/src/utils/jsonPointer.js +4 -0
  182. package/src/utils/templateUtils.js +27 -12
  183. package/src/vendor-imports.js +8 -0
  184. package/tsconfig.json +18 -0
  185. package/typings/sceditor.d.ts +20 -0
  186. package/vendor/jamilih/dist/jml-es.js +1019 -389
  187. package/vendor/jamilih/dist/jml.d.ts +436 -0
  188. package/vendor/jamilih/package.json +136 -0
  189. package/vendor/typeson-registry/dist/index.js +365 -83
package/src/types.js CHANGED
@@ -1,7 +1,9 @@
1
- import {jml} from '../vendor/jamilih/dist/jml-es.js';
2
1
  import {
2
+ // jamilih
3
+ jml,
4
+ // typeson-registry
3
5
  Typeson, getJSONType, structuredCloningThrowing
4
- } from '../vendor/typeson-registry/dist/index.js';
6
+ } from './vendor-imports.js';
5
7
 
6
8
  import Formats from './formats.js';
7
9
 
@@ -36,64 +38,118 @@ import SpecialNumberSuperType from './superTypes/SpecialNumberSuperType.js';
36
38
  */
37
39
  export const getPropertyValueFromLegend = (legend) => {
38
40
  const propElem = $e(legend, '*[data-prop="true"]');
39
- return propElem.nodeName.toLowerCase() === 'input'
40
- ? propElem.value
41
- : String(Number.parseInt(propElem.textContent) - 1); // 1-based to 0-based
41
+ if (!propElem) {
42
+ throw new Error(
43
+ 'No property on the supplied legend element'
44
+ );
45
+ }
46
+ if (propElem.nodeName.toLowerCase() === 'input') {
47
+ return /** @type {HTMLInputElement} */ (propElem).value;
48
+ }
49
+ if (!propElem.textContent) {
50
+ throw new Error(
51
+ 'No property with text present on the supplied legend element'
52
+ );
53
+ }
54
+ // 1-based to 0-based
55
+ return String(Number.parseInt(propElem.textContent) - 1);
42
56
  };
43
57
 
44
58
  const Types = {};
45
59
 
60
+ /**
61
+ * @typedef {import('./formats.js').StructuredCloneValue} StructuredCloneValue
62
+ */
63
+
64
+ /**
65
+ * @typedef {import('jamilih').JamilihArray} JamilihArray
66
+ */
67
+
68
+ /**
69
+ * @typedef {{
70
+ * format: import('./formats.js').AvailableFormat,
71
+ * endMatchTypeObjs: TypeObject[],
72
+ * remnant: string,
73
+ * rootHolder: [
74
+ * type: string, parent: object, parentPath: string|number, path: string
75
+ * ][],
76
+ * parent: object,
77
+ * parentPath: string|number
78
+ * }} RootInfo
79
+ */
80
+
46
81
  /**
47
82
  * @typedef {object} TypeObject
48
- * @property {JamilihArray} option Creates the option HTML. May set an option
49
- * `title` or `value`
83
+ * @property {[
84
+ * string, {value?: AvailableType, title?: string}?
85
+ * ]} option Creates the option HTML. May set an option `title` or `value`
50
86
  * @property {boolean} [array] Private context variable. Whether or not
51
87
  * it is an array. Do not use in other types.
52
88
  * @property {string[]} [regexEndings] Used for string parsing.
53
- * @property {RegExp} [stringRegex] Used for string parsing. If not
54
- * present, use `stringRegexBegin` and `stringRegexEnd`
89
+ * @property {RegExp|((nonGrouping?: boolean) => RegExp)} [stringRegex] Used
90
+ * for string parsing. If not present, use `stringRegexBegin` and
91
+ * `stringRegexEnd`.
55
92
  * @property {RegExp} [stringRegexBegin] Used for string parsing. If not
56
93
  * present, use `stringRegex`
57
94
  * @property {RegExp} [stringRegexEnd] Used for string parsing. If not
58
95
  * present, use `stringRegex`
59
- * @property {(ArbitraryValue) => boolean} [valueMatch] Function to
96
+ * @property {(v: StructuredCloneValue) => boolean} [valueMatch] Function to
60
97
  * check whether this subtype matches
61
98
  * @property {string} [superType] The greater fundamental type to which
62
99
  * the type belongs
63
- * @property {(s: string) => ArbitraryValue} toValue Converts from
64
- * string to value. May use `stringRegex` to find components.
65
- * @property {(info: {root?: HTMLDivElement}) =>
66
- * ArbitraryValue
100
+ * @property {(
101
+ * s: string, info?: RootInfo
102
+ * ) => StructuredCloneValue} toValue Converts from string to value. May use
103
+ * `stringRegex` to find components.
104
+ * @property {(info: {
105
+ * root: HTMLDivElement,
106
+ * stateObj?: StateObject,
107
+ * currentPath?: string
108
+ * }) =>
109
+ * StructuredCloneValue
67
110
  * } getValue Gets the value for the type
68
- * @property {(info: {root?: HTMLDivElement}) => void} [setValue] Should set
69
- * the value of the form's `getInput` element
111
+ * @property {(
112
+ * info: {
113
+ * root: HTMLDivElement,
114
+ * value: StructuredCloneValue
115
+ * }
116
+ * ) => void} [setValue] Should set the value of the form's `getInput` element
70
117
  * @property {(info: {
71
- * value?: ArbitraryValue,
118
+ * value?: StructuredCloneValue,
72
119
  * typeNamespace?: string,
73
- * type?: string,
120
+ * type?: AvailableType,
74
121
  * topRoot?: HTMLDivElement,
75
122
  * resultType?: "keys"|"values"|"both",
76
- * format?: string
123
+ * format: import('./formats.js').AvailableFormat
77
124
  * }) => JamilihArray} viewUI
78
125
  * @property {(info: {
79
- * value?: ArbitraryValue,
126
+ * value?: StructuredCloneValue,
80
127
  * typeNamespace?: string,
128
+ * bringIntoFocus?: boolean,
129
+ * format?: import('./formats.js').AvailableFormat,
130
+ * resultType?: "keys"|"values"|"both",
131
+ * type?: AvailableType,
132
+ * buildTypeChoices?: import('./typeChoices.js').BuildTypeChoices,
133
+ * topRoot?: HTMLDivElement
81
134
  * }) => JamilihArray} editUI
82
135
  * @property {(info: {root: HTMLDivElement}) =>
83
- * HTMLInputElement|HTMLTextareaElement|HTMLSelectElement} getInput Gets the
84
- * form control (with `value`)
85
- * @property {(path: string, value: ArbitraryValue) =>
86
- * ArbitraryValue} [resolveReference] Gets the reference. For array and object
87
- * references types only
136
+ * HTMLInputElement|HTMLTextAreaElement|HTMLSelectElement|
137
+ * HTMLButtonElement} getInput Gets the form control (with `value`)
138
+ * @property {(
139
+ * info: {root: HTMLDivElement}
140
+ * ) => HTMLSelectElement} [getSelect]
141
+ * @property {(path: string, value: StructuredCloneValue) =>
142
+ * StructuredCloneValue} [resolveReference] Gets the reference. For array
143
+ * and object references types only
88
144
  * @property {(info: {root: HTMLDivElement, topRoot?: HTMLDivElement}) => {
89
- * message: string,
145
+ * message?: string,
90
146
  * valid: boolean
91
147
  * }} [validate] Message will be used if validity is false.
92
148
  * @property {(info: {topRoot: HTMLDivElement}) => void} [validateAll] For
93
149
  * validation of array and object references only.
94
150
  * @property {{
95
151
  * structuredCloning: {
96
- * after: string,
152
+ * after: AvailableType,
97
153
  * contexts: string[]
98
154
  * }
99
155
  * }} [stateDependent] The type after which it should be placed and its
@@ -201,62 +257,97 @@ Types.availableTypes = {
201
257
  },
202
258
 
203
259
  // We're catching this instead of using this
204
- sparseUndefined: sparseUndefinedType
205
- };
206
- Types.availableTypes.ValidDate = {
207
- valid: true
208
- };
209
- /*
210
- Types.availableTypes.sparseArrays = {
260
+ sparseUndefined: sparseUndefinedType,
261
+
262
+ ValidDate: {
263
+ valid: true
264
+ },
265
+ /*
266
+ sparseArrays: {
267
+ sparse: true
268
+ },
269
+ */
270
+ arrayNonindexKeys: {
211
271
  sparse: true
272
+ }
212
273
  };
274
+
275
+ /**
276
+ * @typedef {"null"|"true"|"false"|"number"|"bigint"|"string"|"arrayReference"|
277
+ * "objectReference"|"array"|"object"|"date"|"userObject"|"undef"|
278
+ * "SpecialRealNumber"|"SpecialNumber"|"regexp"|"BooleanObject"|
279
+ * "NumberObject"|"StringObject"|"map"|"set"|"file"|"filelist"|"blobHTML"|
280
+ * "arraybuffer"|"arraybufferview"|"dataview"|"imagedata"|"imagebitmap"|
281
+ * "int8array"|"uint8array"|"uint8clampedarray"|"int16array"|"uint16array"|
282
+ * "int32array"|"uint32array"|"float32array"|"float64array"|"IntlCollator"|
283
+ * "IntlDateTimeFormat"|"IntlNumberFormat"|"sparseUndefined"|"ValidDate"|
284
+ * "arrayNonindexKeys"} AvailableType
213
285
  */
214
- Types.availableTypes.arrayNonindexKeys = {
215
- sparse: true
216
- };
217
286
 
218
287
  /**
219
- * @param {[copyTo: string, copyFrom: string]} replacements
288
+ * @param {[
289
+ * copyFrom: AvailableType, copyTo: AvailableType
290
+ * ][]} replacements
220
291
  * @returns {void}
221
292
  */
222
293
  const copyTypeObjs = (replacements) => {
223
294
  replacements.forEach(([copyFrom, copyTo]) => {
224
- Object.assign(Types.availableTypes[copyTo], Types.availableTypes[copyFrom]);
295
+ Object.assign(Types.availableTypes[
296
+ /** @type {AvailableType} */
297
+ (copyTo)
298
+ ], Types.availableTypes[
299
+ /** @type {AvailableType} */
300
+ (copyFrom)
301
+ ]);
225
302
  });
226
303
  };
227
- copyTypeObjs([
228
- ['date', 'ValidDate'],
304
+
305
+ copyTypeObjs(
229
306
  [
230
- 'array',
231
- 'arrayNonindexKeys'
307
+ /** @type {[AvailableType, AvailableType]} */ (
308
+ ['date', 'ValidDate']
309
+ ),
232
310
  // 'sparseArrays'
311
+ /** @type {[AvailableType, AvailableType]} */ (
312
+ ['array', 'arrayNonindexKeys']
313
+ )
233
314
  ]
234
- ]);
315
+ );
235
316
 
236
317
  /**
237
318
  * Utility to retrieve the type out of a type root element.
238
319
  * @public
239
320
  * @param {?RootElement} root
240
- * @returns {string|undefined} Why would it not exist?
321
+ * @returns {string|undefined|null} Why would it not exist?
241
322
  */
242
323
  Types.getTypeForRoot = (root) => {
243
324
  return root && root.dataset.type;
244
325
  };
245
326
 
246
327
  /**
247
- * @typedef {{
248
- * typeNamespace: string,
249
- * "readonly": boolean,
250
- * format: string,
251
- * error: Error,
252
- * rootUI: Element,
253
- * schemaContent: string,
254
- * getPossibleSchemasForPathAndType: (
328
+ * @typedef {(
255
329
  * keypath: string,
256
- * parentPath: string,
257
- * arrayOrObjectPropertyName: string,
258
- * valueType: string
259
- * ) => StateObject
330
+ * parentPath: string,
331
+ * arrayOrObjectPropertyName: string,
332
+ * valueType: string
333
+ * ) => StateObject} GetPossibleSchemasForPathAndType
334
+ */
335
+
336
+ /**
337
+ * @typedef {{
338
+ * typeNamespace?: string,
339
+ * "readonly"?: boolean,
340
+ * format?: import('./formats.js').AvailableFormat,
341
+ * error?: Error,
342
+ * rootUI?: Element,
343
+ * schema?: string,
344
+ * schemaContent?: object,
345
+ * getPossibleSchemasForPathAndType?: GetPossibleSchemasForPathAndType,
346
+ * paths?: {[currentPath: string]: {
347
+ * referentPath: string,
348
+ * expectArrayReferent: boolean
349
+ * }},
350
+ * handlingReference?: boolean
260
351
  * }} StateObject
261
352
  */
262
353
 
@@ -271,7 +362,10 @@ Types.getTypeForRoot = (root) => {
271
362
  */
272
363
  Types.getValueForRoot = (root, stateObj, currentPath) => {
273
364
  const typeObject = /** @type {TypeObject} */ (
274
- Types.availableTypes[Types.getTypeForRoot(root)]
365
+ Types.availableTypes[
366
+ /** @type {AvailableType} */
367
+ (Types.getTypeForRoot(root))
368
+ ]
275
369
  );
276
370
  return typeObject.getValue({
277
371
  root, stateObj, currentPath
@@ -282,10 +376,14 @@ Types.getValueForRoot = (root, stateObj, currentPath) => {
282
376
  * Utility to get the form control (e.g., input element) for a root.
283
377
  * @public
284
378
  * @param {RootElement} root
285
- * @returns {null|HTMLInputElement}
379
+ * @returns {null|
380
+ * HTMLInputElement|HTMLTextAreaElement|HTMLSelectElement|HTMLButtonElement}
286
381
  */
287
382
  Types.getFormControlForRoot = (root) => {
288
- const typeObj = Types.availableTypes[Types.getTypeForRoot(root)];
383
+ const typeObj = /** @type {TypeObject} */ (Types.availableTypes[
384
+ /** @type {AvailableType} */
385
+ (Types.getTypeForRoot(root))
386
+ ]);
289
387
  /* istanbul ignore if -- All have except aliases */
290
388
  if (!typeObj.getInput) {
291
389
  return null;
@@ -301,16 +399,21 @@ Types.getFormControlForRoot = (root) => {
301
399
  * @returns {StructuredCloneValue}
302
400
  */
303
401
  Types.getValueFromRootAncestor = (selOrEl, stateObj) => {
304
- return Types.getValueForRoot($e(selOrEl, 'div[data-type]'), stateObj);
402
+ return Types.getValueForRoot(
403
+ /** @type {RootElement} */
404
+ ($e(selOrEl, 'div[data-type]')),
405
+ stateObj
406
+ );
305
407
  };
306
408
 
307
409
  /**
308
410
  * @public
309
411
  * @param {string|Element} selOrEl
310
- * @returns {null|HTMLInputElement}
412
+ * @returns {null|HTMLInputElement|HTMLTextAreaElement|HTMLSelectElement|
413
+ * HTMLButtonElement}
311
414
  */
312
415
  Types.getFormControlFromRootAncestor = (selOrEl) => {
313
- const root = $e(selOrEl, 'div[data-type]');
416
+ const root = /** @type {RootElement} */ ($e(selOrEl, 'div[data-type]'));
314
417
  if (!root) {
315
418
  return null;
316
419
  }
@@ -319,8 +422,8 @@ Types.getFormControlFromRootAncestor = (selOrEl) => {
319
422
 
320
423
  /**
321
424
  * @param {string} format
322
- * @param {string} state
323
- * @returns {string[]}
425
+ * @param {string} [state]
426
+ * @returns {AvailableType[]|undefined}
324
427
  */
325
428
  Types.getTypesForFormatAndState = (
326
429
  format, state
@@ -328,68 +431,85 @@ Types.getTypesForFormatAndState = (
328
431
 
329
432
  /**
330
433
  * @public
331
- * @param {string} type
332
- * @returns {JamilihArray}
434
+ * @param {AvailableType} type
435
+ * @returns {[string, {value: AvailableType, title?: string}]}
333
436
  */
334
437
  Types.getOptionForType = (type) => {
335
- const optInfo = [...Types.availableTypes[type].option];
336
- optInfo[1] = {value: type, ...optInfo[1]};
337
- return optInfo;
438
+ /** @type {[string, {value?: AvailableType, title?: string}?]} */
439
+ const optInfo = [
440
+ ...(/** @type {TypeObject} */ (
441
+ Types.availableTypes[type]
442
+ )).option
443
+ ];
444
+ optInfo[1] = {value: type, ...(optInfo[1])};
445
+ return /** @type {[string, {value: AvailableType, title?: string}]} */ (
446
+ optInfo
447
+ );
338
448
  };
339
449
 
340
450
  /**
341
451
  * @public
342
452
  * @param {string} format
343
- * @param {string} parserState
344
- * @returns {JamilihArray[]}
453
+ * @param {string} [parserState]
454
+ * @returns {[string, {value: AvailableType, title?: string}][]}
345
455
  */
346
456
  Types.getTypeOptionsForFormatAndState = (format, parserState) => {
347
457
  const typesForFormatAndState = Types.getTypesForFormatAndState(
348
458
  format, parserState
349
459
  );
460
+ if (!typesForFormatAndState) {
461
+ throw new Error('Unexpected type for format and state');
462
+ }
350
463
  return typesForFormatAndState.map((type) => {
351
464
  return Types.getOptionForType(type);
352
465
  });
353
466
  };
354
467
 
468
+ /* eslint-disable jsdoc/valid-types -- readonly reserved */
355
469
  /**
356
470
  * @public
357
471
  * @param {object} cfg
358
- * @param {boolean} cfg."readonly"
359
- * @param {"both"|"keys"|"values"} cfg.resultType
360
- * @param {string} cfg.typeNamespace
361
- * @param {string} cfg.type
362
- * @param {RootElement} cfg.topRoot
363
- * @param {boolean} cfg.bringIntoFocus
364
- * @param {BuildTypeChoices} cfg.buildTypeChoices
365
- * @param {string} cfg.format
366
- * @param {string} cfg.schemaContent
367
- * @param {StateObject} cfg.schemaState Not currently in use and may
368
- * need to change the type
472
+ * @param {boolean} [cfg.readonly]
473
+ * @param {"both"|"keys"|"values"} [cfg.resultType]
474
+ * @param {string} [cfg.typeNamespace]
475
+ * @param {AvailableType} cfg.type
476
+ * @param {RootElement} [cfg.topRoot]
477
+ * @param {boolean|undefined} cfg.bringIntoFocus
478
+ * @param {import('./typeChoices.js').BuildTypeChoices} [cfg.buildTypeChoices]
479
+ * @param {import('./formats.js').AvailableFormat} cfg.format
480
+ * @param {object} [cfg.schemaContent]
481
+ * @param {GetPossibleSchemasForPathAndType} [cfg.schemaState] Not currently
482
+ * in use
369
483
  * @param {StructuredCloneValue} cfg.value
370
484
  * @param {boolean} cfg.hasValue
485
+ * @param {StructuredCloneValue} [cfg.replaced]
371
486
  * @returns {Element}
372
487
  */
373
488
  Types.getUIForModeAndType = ({
374
489
  readonly, resultType, typeNamespace, type, topRoot, bringIntoFocus,
375
- buildTypeChoices, format, schemaContent, schemaState, value, hasValue
490
+ buildTypeChoices, format, schemaContent, schemaState, value, hasValue,
491
+ replaced
376
492
  }) => {
377
- const typeObj = Types.availableTypes[type];
378
- const root = jml(
379
- ...typeObj[readonly ? 'viewUI' : 'editUI'](
380
- hasValue
381
- ? {
382
- typeNamespace, type, buildTypeChoices,
383
- format, schemaContent, schemaState,
384
- resultType, topRoot, bringIntoFocus, value
385
- }
386
- : {
387
- typeNamespace, type, buildTypeChoices,
388
- format, schemaContent, schemaState,
389
- resultType, topRoot, bringIntoFocus
390
- }
391
- )
392
- );
493
+ /* eslint-enable jsdoc/valid-types -- readonly reserved */
494
+ const typeObj = /** @type {TypeObject} */ (Types.availableTypes[type]);
495
+ const arg = hasValue
496
+ ? {
497
+ typeNamespace, type, buildTypeChoices,
498
+ format, schemaContent, schemaState,
499
+ resultType, topRoot, bringIntoFocus, value,
500
+ replaced
501
+ }
502
+ : {
503
+ typeNamespace, type, buildTypeChoices,
504
+ format, schemaContent, schemaState,
505
+ resultType, topRoot, bringIntoFocus,
506
+ replaced
507
+ };
508
+ const root = /** @type {HTMLDivElement} */ (jml(
509
+ ...(readonly
510
+ ? typeObj.viewUI(arg)
511
+ : typeObj.editUI(arg))
512
+ ));
393
513
  if (!readonly && typeObj.validate) {
394
514
  const formControl = typeObj.getInput({root});
395
515
  formControl.addEventListener('input', () => {
@@ -399,8 +519,17 @@ Types.getUIForModeAndType = ({
399
519
  return root;
400
520
  };
401
521
 
522
+ /**
523
+ * @type {{
524
+ * [key: string]: {
525
+ * [key: string]: {type: AvailableType, after: AvailableType}[]
526
+ * }
527
+ * }}
528
+ */
402
529
  Types.contexts = {};
403
- Object.entries(Types.availableTypes).forEach(([type, {stateDependent}]) => {
530
+ Object.entries(Types.availableTypes).forEach(([typ, typeObj]) => {
531
+ const type = /** @type {AvailableType} */ (typ);
532
+ const {stateDependent} = /** @type {TypeObject} */ (typeObj);
404
533
  if (stateDependent) {
405
534
  Object.entries(stateDependent).forEach(([format, formatStateDependent]) => {
406
535
  if (!Types.contexts[format]) {
@@ -421,8 +550,8 @@ Object.entries(Types.availableTypes).forEach(([type, {stateDependent}]) => {
421
550
  * @public
422
551
  * @param {object} cfg
423
552
  * @param {HTMLFormElement} cfg.form
424
- * @param {string} cfg.typeNamespace
425
- * @param {string} cfg.keySelectClass
553
+ * @param {string} [cfg.typeNamespace]
554
+ * @param {string} [cfg.keySelectClass]
426
555
  * @returns {boolean}
427
556
  */
428
557
  Types.validValuesSet = ({form, typeNamespace, keySelectClass}) => {
@@ -435,10 +564,13 @@ Types.validValuesSet = ({form, typeNamespace, keySelectClass}) => {
435
564
  return false;
436
565
  }
437
566
 
438
- const typeChoices = $$e(
439
- form,
440
- keySelectClass ? `.${keySelectClass}` : `.typeChoices-${typeNamespace}`
441
- );
567
+ const typeChoices =
568
+ /** @type {(HTMLSelectElement & {$validate: () => boolean})[]} */ (
569
+ $$e(
570
+ form,
571
+ keySelectClass ? `.${keySelectClass}` : `.typeChoices-${typeNamespace}`
572
+ )
573
+ );
442
574
  return (
443
575
  // Specific value type set if present (any descendant, not
444
576
  // only the first) chosen
@@ -475,7 +607,8 @@ Types.validateAllReferences = ({topRoot}) => {
475
607
 
476
608
  // Could just hard-code arrayReference and objectReference,
477
609
  // but we'll try to avoid depending on specific types
478
- Object.values(Types.availableTypes).forEach((typeObject) => {
610
+ Object.values(Types.availableTypes).forEach((typeObj) => {
611
+ const typeObject = /** @type {TypeObject} */ (typeObj);
479
612
  if (typeObject.validateAll) {
480
613
  typeObject.validateAll({topRoot});
481
614
  }
@@ -486,16 +619,21 @@ Types.validateAllReferences = ({topRoot}) => {
486
619
  }
487
620
  };
488
621
 
622
+ /**
623
+ * @type {null|((info: {topRoot: HTMLDivElement}) => void)}
624
+ */
625
+ Types.customValidateAllReferences = null;
626
+
489
627
  /**
490
628
  * @public
491
629
  * @param {object} cfg
492
- * @param {string} cfg.type
630
+ * @param {AvailableType} cfg.type
493
631
  * @param {RootElement} cfg.root
494
- * @param {RootElement} cfg.topRoot
632
+ * @param {RootElement} [cfg.topRoot]
495
633
  * @returns {boolean}
496
634
  */
497
635
  Types.validate = ({type, root, topRoot}) => {
498
- const typeObj = Types.availableTypes[type];
636
+ const typeObj = /** @type {TypeObject} */ (Types.availableTypes[type]);
499
637
  // Todo (low): We limit for now to input boxes which have `validate`
500
638
  if (typeObj.validate) {
501
639
  const {valid, message} = typeObj.validate({root, topRoot});
@@ -514,13 +652,13 @@ Types.validate = ({type, root, topRoot}) => {
514
652
 
515
653
  /**
516
654
  * @param {object} cfg
517
- * @param {string} cfg.type
655
+ * @param {AvailableType} cfg.type
518
656
  * @param {RootElement} cfg.root
519
657
  * @param {StructuredCloneValue} cfg.value
520
658
  * @returns {void}
521
659
  */
522
660
  Types.setValue = ({type, root, value}) => {
523
- const typeObj = Types.availableTypes[type];
661
+ const typeObj = /** @type {TypeObject} */ (Types.availableTypes[type]);
524
662
  if (typeObj.setValue) {
525
663
  typeObj.setValue({root, value});
526
664
  }
@@ -549,68 +687,86 @@ function escapeRegex (str) {
549
687
  * @public
550
688
  * @param {string} s
551
689
  * @param {object} cfg
552
- * @param {string} cfg.format
690
+ * @param {import('./formats.js').AvailableFormat} cfg.format
553
691
  * @param {string} cfg.state
554
692
  * @param {TypeObject[]} [cfg.endMatchTypeObjs=[]]
555
693
  * @param {boolean} [cfg.firstRun=true]
556
- * @param {
557
- * [
558
- * type: string,
559
- * parent: array|object,
560
- * parentPath: string,
561
- * path: string
562
- * ]
563
- * } [cfg.rootHolder=[]]
564
- * @param {ArbitraryArray|ArbitraryObject} cfg.parent
565
- * @param {string} cfg.parentPath
566
- * @returns {{
567
- * value: ArbitraryValue,
694
+ * @param {[
695
+ * type: string,
696
+ * parent: {[key: string]: any},
697
+ * parentPath: string|number,
698
+ * path: string
699
+ * ][]} [cfg.rootHolder=[]]
700
+ * @param {{[key: string]: any}} cfg.parent
701
+ * @param {string|number} cfg.parentPath
702
+ * @returns {[
703
+ * value: StructuredCloneValue,
568
704
  * remnant: string,
569
705
  * beginOnly: boolean,
570
706
  * assign: boolean
571
- * }}
707
+ * ]}
572
708
  */
573
709
  Types.getValueForString = (s, {
574
710
  format, state, endMatchTypeObjs = [], firstRun = true,
575
711
  rootHolder = [], parent, parentPath
576
712
  }) => {
577
- let assign = true;
578
- let match;
579
713
  const allowedTypes = Types.getTypesForFormatAndState(format, state);
714
+ if (!allowedTypes) {
715
+ throw new Error('Could not get types for format and state');
716
+ }
580
717
  const allowedTypeObjs = Object.entries(
581
718
  Types.availableTypes
582
- ).filter(([type]) => allowedTypes.includes(type));
719
+ ).filter(([type]) => {
720
+ return allowedTypes.includes(/** @type {AvailableType} */ (type));
721
+ });
583
722
  const allowedTypeObjsVals = allowedTypeObjs.map(([, arr]) => arr);
584
723
 
585
- const endings = '|' + allowedTypeObjsVals.reduce((arr, typeObj) => {
724
+ const reduced = allowedTypeObjsVals.reduce((array, typObj) => {
725
+ const typeObj = /** @type {TypeObject} */ (typObj);
726
+ let arr = /** @type {string[]} */ (array);
586
727
  if (typeObj.regexEndings) {
587
728
  arr.push(...typeObj.regexEndings);
588
729
  arr = [...new Set(arr)];
589
730
  }
590
731
  return arr;
591
- }, []).map((str) => escapeRegex(str)).join('|');
592
-
593
- let found = allowedTypeObjs.find(([_type, typeObj]) => {
732
+ }, []);
733
+ const endings = '|' + /** @type {string[]} */ (
734
+ reduced
735
+ ).map((str) => escapeRegex(str)).join('|');
736
+
737
+ /**
738
+ * @type {RegExpMatchArray|boolean|null}
739
+ */
740
+ let match = null;
741
+ let found = allowedTypeObjs.find(([_type, typObj]) => {
742
+ const typeObj = /** @type {TypeObject} */ (typObj);
594
743
  let {stringRegex} = typeObj;
595
- if (typeof stringRegex === 'function') {
744
+ if (typeof typeObj.stringRegex === 'function') {
596
745
  stringRegex = typeObj.stringRegex(true);
597
746
  }
598
747
  stringRegex = stringRegex
599
748
  // Strip off terminal (dollar sign) when matching substrings
600
749
  ? new RegExp(
601
- stringRegex.source.slice(0, -1) + '(?=$' + endings + ')',
750
+ /** @type {RegExp} */ (
751
+ stringRegex
752
+ ).source.slice(0, -1) + '(?=$' + endings + ')',
602
753
  'u'
603
754
  )
604
755
  : stringRegex;
605
- match = stringRegex && s && s.match(stringRegex);
756
+ match = Boolean(stringRegex && s) && s.match(
757
+ /** @type {RegExp} */ (stringRegex)
758
+ );
606
759
  return match;
607
760
  });
608
761
 
609
- let beginOnly;
762
+ let beginOnly = false;
610
763
  if (found === undefined) {
611
- found = allowedTypeObjs.find(([_type, typeObj]) => {
764
+ found = allowedTypeObjs.find(([_type, typObj]) => {
765
+ const typeObj = /** @type {TypeObject} */ (typObj);
612
766
  const {stringRegexBegin} = typeObj;
613
- match = stringRegexBegin && s && s.match(stringRegexBegin);
767
+ match = Boolean(stringRegexBegin && s) && s.match(
768
+ /** @type {RegExp} */ (stringRegexBegin)
769
+ );
614
770
  if (match) {
615
771
  beginOnly = true;
616
772
  endMatchTypeObjs.push(typeObj);
@@ -618,13 +774,16 @@ Types.getValueForString = (s, {
618
774
  return match;
619
775
  });
620
776
  }
777
+ let assign = true;
621
778
  if (found !== undefined) {
622
- let remnant = s.slice(match[0].length);
623
- s = s.slice(0, match[0].length);
779
+ // @ts-ignore The `found` is evaluated again, so sets `match` to non-null
780
+ const [content, innerContent] = /** @type {RegExpMatchArray} */ (match);
781
+ let remnant = s.slice(content.length);
782
+ s = s.slice(0, content.length);
624
783
  // console.log('s0', s, '::', remnant, match);
625
784
  let valObj;
626
785
  try {
627
- valObj = found[1].toValue(match[1] || s, {
786
+ valObj = /** @type {TypeObject} */ (found[1]).toValue(innerContent || s, {
628
787
  format,
629
788
  endMatchTypeObjs,
630
789
  remnant,
@@ -646,7 +805,7 @@ Types.getValueForString = (s, {
646
805
 
647
806
  if (beginOnly && endMatchTypeObjs.length) {
648
807
  const endMatch = remnant.match(
649
- endMatchTypeObjs.slice(-1)[0].stringRegexEnd
808
+ /** @type {RegExp} */ (endMatchTypeObjs.slice(-1)[0].stringRegexEnd)
650
809
  );
651
810
  if (endMatch) {
652
811
  endMatchTypeObjs.pop(); // Safe now to extract
@@ -660,8 +819,12 @@ Types.getValueForString = (s, {
660
819
  try {
661
820
  const topRoot = typeson.revive(value);
662
821
  rootHolder.forEach(([type, parent, parentPath, path]) => {
663
- const val = Types.availableTypes[type + 'Reference']
664
- .resolveReference(path, topRoot);
822
+ const typeObject = Types.availableTypes[
823
+ /** @type {AvailableType} */ (type + 'Reference')
824
+ ];
825
+
826
+ // @ts-expect-error Reference method exists
827
+ const val = typeObject.resolveReference(path, topRoot);
665
828
  const basicType = getJSONType(val);
666
829
  // eslint-disable-next-line max-len -- Long
667
830
  /* istanbul ignore else -- Successful reference always an object/array? */