@es-joy/jsoe 0.15.0 → 0.17.0

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 (207) hide show
  1. package/.ncurc.cjs +4 -5
  2. package/CHANGES.md +9 -0
  3. package/README.md +28 -4
  4. package/badges/licenses-badge.svg +1 -0
  5. package/dist/formatAndTypeChoices.d.ts +39 -19
  6. package/dist/formatAndTypeChoices.d.ts.map +1 -1
  7. package/dist/formats/indexedDBKey.d.ts +1 -1
  8. package/dist/formats/indexedDBKey.d.ts.map +1 -1
  9. package/dist/formats/json.d.ts +1 -1
  10. package/dist/formats/json.d.ts.map +1 -1
  11. package/dist/formats/schema.d.ts +11 -0
  12. package/dist/formats/schema.d.ts.map +1 -0
  13. package/dist/formats/structuredCloning.d.ts +11 -13
  14. package/dist/formats/structuredCloning.d.ts.map +1 -1
  15. package/dist/formats.d.ts +86 -25
  16. package/dist/formats.d.ts.map +1 -1
  17. package/dist/fundamentalTypes/BooleanObjectType.d.ts +1 -1
  18. package/dist/fundamentalTypes/BooleanObjectType.d.ts.map +1 -1
  19. package/dist/fundamentalTypes/NumberObjectType.d.ts +1 -1
  20. package/dist/fundamentalTypes/NumberObjectType.d.ts.map +1 -1
  21. package/dist/fundamentalTypes/StringObjectType.d.ts +1 -1
  22. package/dist/fundamentalTypes/StringObjectType.d.ts.map +1 -1
  23. package/dist/fundamentalTypes/arrayReferenceType.d.ts +1 -1
  24. package/dist/fundamentalTypes/arrayType.d.ts +3 -3
  25. package/dist/fundamentalTypes/arrayType.d.ts.map +1 -1
  26. package/dist/fundamentalTypes/bigintObjectType.d.ts +6 -0
  27. package/dist/fundamentalTypes/bigintObjectType.d.ts.map +1 -0
  28. package/dist/fundamentalTypes/bigintType.d.ts +1 -1
  29. package/dist/fundamentalTypes/bigintType.d.ts.map +1 -1
  30. package/dist/fundamentalTypes/blobType.d.ts +1 -1
  31. package/dist/fundamentalTypes/blobType.d.ts.map +1 -1
  32. package/dist/fundamentalTypes/booleanType.d.ts +8 -0
  33. package/dist/fundamentalTypes/booleanType.d.ts.map +1 -0
  34. package/dist/fundamentalTypes/catchType.d.ts +6 -0
  35. package/dist/fundamentalTypes/catchType.d.ts.map +1 -0
  36. package/dist/fundamentalTypes/dateType.d.ts +4 -4
  37. package/dist/fundamentalTypes/dateType.d.ts.map +1 -1
  38. package/dist/fundamentalTypes/domexceptionType.d.ts +1 -1
  39. package/dist/fundamentalTypes/domexceptionType.d.ts.map +1 -1
  40. package/dist/fundamentalTypes/enumType.d.ts +6 -0
  41. package/dist/fundamentalTypes/enumType.d.ts.map +1 -0
  42. package/dist/fundamentalTypes/errorType.d.ts +1 -1
  43. package/dist/fundamentalTypes/errorType.d.ts.map +1 -1
  44. package/dist/fundamentalTypes/fileType.d.ts +1 -1
  45. package/dist/fundamentalTypes/fileType.d.ts.map +1 -1
  46. package/dist/fundamentalTypes/filelistType.d.ts +1 -1
  47. package/dist/fundamentalTypes/filelistType.d.ts.map +1 -1
  48. package/dist/fundamentalTypes/functionType.d.ts +6 -0
  49. package/dist/fundamentalTypes/functionType.d.ts.map +1 -0
  50. package/dist/fundamentalTypes/literalType.d.ts +6 -0
  51. package/dist/fundamentalTypes/literalType.d.ts.map +1 -0
  52. package/dist/fundamentalTypes/mapType.d.ts +1 -1
  53. package/dist/fundamentalTypes/mapType.d.ts.map +1 -1
  54. package/dist/fundamentalTypes/nanType.d.ts +6 -0
  55. package/dist/fundamentalTypes/nanType.d.ts.map +1 -0
  56. package/dist/fundamentalTypes/nativeEnumType.d.ts +6 -0
  57. package/dist/fundamentalTypes/nativeEnumType.d.ts.map +1 -0
  58. package/dist/fundamentalTypes/neverType.d.ts +6 -0
  59. package/dist/fundamentalTypes/neverType.d.ts.map +1 -0
  60. package/dist/fundamentalTypes/noneditableType.d.ts +1 -1
  61. package/dist/fundamentalTypes/noneditableType.d.ts.map +1 -1
  62. package/dist/fundamentalTypes/nullType.d.ts +1 -1
  63. package/dist/fundamentalTypes/nullType.d.ts.map +1 -1
  64. package/dist/fundamentalTypes/numberType.d.ts +1 -1
  65. package/dist/fundamentalTypes/numberType.d.ts.map +1 -1
  66. package/dist/fundamentalTypes/objectReferenceType.d.ts +1 -1
  67. package/dist/fundamentalTypes/objectType.d.ts +1 -1
  68. package/dist/fundamentalTypes/objectType.d.ts.map +1 -1
  69. package/dist/fundamentalTypes/promiseType.d.ts +6 -0
  70. package/dist/fundamentalTypes/promiseType.d.ts.map +1 -0
  71. package/dist/fundamentalTypes/recordType.d.ts +6 -0
  72. package/dist/fundamentalTypes/recordType.d.ts.map +1 -0
  73. package/dist/fundamentalTypes/regexpType.d.ts +1 -1
  74. package/dist/fundamentalTypes/regexpType.d.ts.map +1 -1
  75. package/dist/fundamentalTypes/setType.d.ts +1 -1
  76. package/dist/fundamentalTypes/setType.d.ts.map +1 -1
  77. package/dist/fundamentalTypes/sparseUndefinedType.d.ts +1 -1
  78. package/dist/fundamentalTypes/sparseUndefinedType.d.ts.map +1 -1
  79. package/dist/fundamentalTypes/stringType.d.ts +1 -1
  80. package/dist/fundamentalTypes/stringType.d.ts.map +1 -1
  81. package/dist/fundamentalTypes/symbolType.d.ts +8 -0
  82. package/dist/fundamentalTypes/symbolType.d.ts.map +1 -0
  83. package/dist/fundamentalTypes/tupleType.d.ts +6 -0
  84. package/dist/fundamentalTypes/tupleType.d.ts.map +1 -0
  85. package/dist/fundamentalTypes/undefinedType.d.ts +1 -1
  86. package/dist/fundamentalTypes/undefinedType.d.ts.map +1 -1
  87. package/dist/fundamentalTypes/voidType.d.ts +6 -0
  88. package/dist/fundamentalTypes/voidType.d.ts.map +1 -0
  89. package/dist/index.d.ts +2 -2
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +9661 -1587
  92. package/dist/subTypes/blobHTMLType.d.ts.map +1 -1
  93. package/dist/subTypes/falseType.d.ts +1 -1
  94. package/dist/subTypes/trueType.d.ts +1 -1
  95. package/dist/superTypes/SpecialNumberType.d.ts +1 -1
  96. package/dist/superTypes/SpecialRealNumberType.d.ts +1 -1
  97. package/dist/superTypes/SpecialRealNumberType.d.ts.map +1 -1
  98. package/dist/superTypes/buffersourceType.d.ts +1 -1
  99. package/dist/superTypes/buffersourceType.d.ts.map +1 -1
  100. package/dist/superTypes/dommatrixType.d.ts +1 -1
  101. package/dist/superTypes/dommatrixType.d.ts.map +1 -1
  102. package/dist/superTypes/dompointType.d.ts +1 -1
  103. package/dist/superTypes/dompointType.d.ts.map +1 -1
  104. package/dist/superTypes/domrectType.d.ts +1 -1
  105. package/dist/superTypes/domrectType.d.ts.map +1 -1
  106. package/dist/superTypes/errorsSpecialType.d.ts +1 -1
  107. package/dist/superTypes/errorsSpecialType.d.ts.map +1 -1
  108. package/dist/typeChoices.d.ts +33 -16
  109. package/dist/typeChoices.d.ts.map +1 -1
  110. package/dist/types.d.ts +161 -157
  111. package/dist/types.d.ts.map +1 -1
  112. package/dist/utils/dialogs.d.ts +3 -3
  113. package/dist/utils/dialogs.d.ts.map +1 -1
  114. package/dist/utils/jsonPointer.d.ts.map +1 -1
  115. package/dist/utils/media.d.ts.map +1 -1
  116. package/dist/utils/objects.d.ts +16 -0
  117. package/dist/utils/objects.d.ts.map +1 -0
  118. package/dist/utils/types.d.ts +1 -1
  119. package/dist/utils/types.d.ts.map +1 -1
  120. package/dist/vendor-imports.d.ts +1 -1
  121. package/eslint.config.js +74 -0
  122. package/licenseInfo.json +4 -0
  123. package/package.json +59 -69
  124. package/rollup.config.js +16 -1
  125. package/src/formatAndTypeChoices.js +68 -54
  126. package/src/formats/indexedDBKey.js +9 -4
  127. package/src/formats/json.js +7 -4
  128. package/src/formats/schema.js +772 -0
  129. package/src/formats/structuredCloning.js +187 -86
  130. package/src/formats.js +61 -26
  131. package/src/fundamentalTypes/BooleanObjectType.js +18 -6
  132. package/src/fundamentalTypes/NumberObjectType.js +18 -5
  133. package/src/fundamentalTypes/StringObjectType.js +20 -8
  134. package/src/fundamentalTypes/arrayType.js +1241 -533
  135. package/src/fundamentalTypes/bigintObjectType.js +64 -0
  136. package/src/fundamentalTypes/bigintType.js +31 -5
  137. package/src/fundamentalTypes/blobType.js +201 -190
  138. package/src/fundamentalTypes/booleanType.js +63 -0
  139. package/src/fundamentalTypes/catchType.js +140 -0
  140. package/src/fundamentalTypes/dateType.js +57 -19
  141. package/src/fundamentalTypes/domexceptionType.js +61 -63
  142. package/src/fundamentalTypes/enumType.js +52 -0
  143. package/src/fundamentalTypes/errorType.js +20 -7
  144. package/src/fundamentalTypes/fileType.js +195 -189
  145. package/src/fundamentalTypes/filelistType.js +4 -0
  146. package/src/fundamentalTypes/functionType.js +150 -0
  147. package/src/fundamentalTypes/literalType.js +81 -0
  148. package/src/fundamentalTypes/mapType.js +4 -0
  149. package/src/fundamentalTypes/nanType.js +41 -0
  150. package/src/fundamentalTypes/nativeEnumType.js +155 -0
  151. package/src/fundamentalTypes/neverType.js +44 -0
  152. package/src/fundamentalTypes/noneditableType.js +19 -5
  153. package/src/fundamentalTypes/nullType.js +16 -6
  154. package/src/fundamentalTypes/numberType.js +49 -6
  155. package/src/fundamentalTypes/objectType.js +10 -2
  156. package/src/fundamentalTypes/promiseType.js +60 -0
  157. package/src/fundamentalTypes/recordType.js +42 -0
  158. package/src/fundamentalTypes/regexpType.js +52 -34
  159. package/src/fundamentalTypes/setType.js +4 -0
  160. package/src/fundamentalTypes/sparseUndefinedType.js +3 -0
  161. package/src/fundamentalTypes/stringType.js +254 -6
  162. package/src/fundamentalTypes/symbolType.js +81 -0
  163. package/src/fundamentalTypes/tupleType.js +39 -0
  164. package/src/fundamentalTypes/undefinedType.js +14 -4
  165. package/src/fundamentalTypes/voidType.js +48 -0
  166. package/src/jsoe.css +37 -3
  167. package/src/subTypes/blobHTMLType.js +33 -24
  168. package/src/superTypes/SpecialRealNumberType.js +22 -6
  169. package/src/superTypes/buffersourceType.js +86 -30
  170. package/src/superTypes/dommatrixType.js +24 -7
  171. package/src/superTypes/dompointType.js +27 -7
  172. package/src/superTypes/domrectType.js +33 -7
  173. package/src/superTypes/errorsSpecialType.js +30 -14
  174. package/src/typeChoices.js +115 -44
  175. package/src/types.js +129 -45
  176. package/src/utils/FileList.js +3 -3
  177. package/src/utils/dialogs.js +6 -8
  178. package/src/utils/objects.js +22 -0
  179. package/src/vendor-imports.js +1 -1
  180. package/tsconfig.json +2 -2
  181. package/vendor/jamilih/dist/jml-es.js +23 -6
  182. package/vendor/typeson-registry/dist/index.js +77 -47
  183. package/vendor/zod/lib/index.mjs +4236 -0
  184. package/vendor/zodex/dist/esm/dezerialize.d.ts +26 -0
  185. package/vendor/zodex/dist/esm/dezerialize.js +393 -0
  186. package/vendor/zodex/dist/esm/index.d.ts +9 -0
  187. package/vendor/zodex/dist/esm/index.js +4 -0
  188. package/vendor/zodex/dist/esm/infer.d.ts +29 -0
  189. package/vendor/zodex/dist/esm/infer.js +1 -0
  190. package/vendor/zodex/dist/esm/package.json +1 -0
  191. package/vendor/zodex/dist/esm/types.d.ts +201 -0
  192. package/vendor/zodex/dist/esm/types.js +13 -0
  193. package/vendor/zodex/dist/esm/ui.d.ts +23 -0
  194. package/vendor/zodex/dist/esm/ui.js +10 -0
  195. package/vendor/zodex/dist/esm/zerialize.d.ts +50 -0
  196. package/vendor/zodex/dist/esm/zerialize.js +417 -0
  197. package/vendor/zodex/dist/esm/zod-types.d.ts +11 -0
  198. package/vendor/zodex/dist/esm/zod-types.js +1 -0
  199. package/.eslintignore +0 -13
  200. package/.eslintrc.cjs +0 -145
  201. package/.nyc_output/out.json +0 -114984
  202. package/cypress.config.ts +0 -15
  203. package/demo/index-instrumented.html +0 -29
  204. package/demo/index.html +0 -29
  205. package/demo/index.js +0 -644
  206. package/src/formats/schemaAndArbitrary.js +0 -20
  207. package/src/formats/schemaOnly.js +0 -539
@@ -20,14 +20,17 @@ import json from './json.js';
20
20
  };
21
21
 
22
22
  /**
23
+ * Delegates data-based UI building to method for adding child elements (a
24
+ * method which is housed in the array type object).
23
25
  * @typedef {(info: {
24
26
  * propName: string,
25
27
  * type: import('../types.js').AvailableType,
26
28
  * value: import('../formats.js').StructuredCloneValue,
27
29
  * bringIntoFocus?: boolean,
28
30
  * setAValue?: boolean,
29
- * schemaContent?: object,
30
- * schemaState?: import('../types.js').GetPossibleSchemasForPathAndType
31
+ * schemaContent?: import('../formats/schema.js').ZodexSchema,
32
+ * mustBeOptional?: boolean,
33
+ * schemaIdx?: number
31
34
  * }) => HTMLElement|null} AddAndSetArrayElement
32
35
  */
33
36
 
@@ -36,6 +39,8 @@ import json from './json.js';
36
39
  */
37
40
 
38
41
  /**
42
+ * Obtains state-specific data and returns an observer that can build a UI based
43
+ * on data it receives.
39
44
  * @param {import('../types.js').StateObject} stateObj
40
45
  * @returns {EncapsulateObserver}
41
46
  */
@@ -43,19 +48,26 @@ const encapsulateObserver = (stateObj) => {
43
48
  const {
44
49
  typeNamespace, readonly, format: frmt, schemaContent,
45
50
  formats,
46
- types,
47
- getPossibleSchemasForPathAndType
51
+ types
48
52
  } = stateObj;
49
53
 
50
54
  const format = /** @type {import('../formats.js').AvailableFormat} */ (frmt);
51
55
 
52
56
  /**
57
+ * Matches keypaths to the HTML UI Element.
53
58
  * @type {{[key: string]: HTMLElement & {
54
59
  * $addAndSetArrayElement: AddAndSetArrayElement
55
60
  * }}}
56
61
  */
57
62
  const parents = {};
58
63
 
64
+ /**
65
+ * @type {{
66
+ * [key: string]: [import('zodex').SzType, number|undefined]|undefined
67
+ * }}
68
+ */
69
+ const schemaParents = {};
70
+
59
71
  /** @type {string[]} */
60
72
  const mapPaths = [];
61
73
 
@@ -110,17 +122,39 @@ const encapsulateObserver = (stateObj) => {
110
122
  ? 'arrayNonindexKeys'
111
123
  // ? 'sparseArrays'
112
124
  : 'array';
125
+
126
+ const li = keypath.lastIndexOf('.');
127
+ const arrayOrObjectPropertyName =
128
+ unescapeKeyPathComponent(keypath.slice(li + 1));
129
+ const parentPath = li === -1 ? '' : keypath.slice(0, li);
130
+
131
+ let schema, schemaIdx, mustBeOptional;
113
132
  if (typeof cyclicKeypath === 'string') {
114
133
  newValue = typesonPathToJSONPointer(cyclicKeypath);
115
134
  newType = type === 'array' ? 'arrayReference' : 'objectReference';
116
- newType = canonicalToAvailableType(
135
+ ({
136
+ newType, schema, schemaIdx, mustBeOptional
137
+ } = canonicalTypeToAvailableTypeAndSchema(
117
138
  /** @type {import('../types.js').default} */ (types),
118
139
  /** @type {import('../formats.js').default} */ (formats),
119
- format, state, newType, value
120
- ); // Todo (low): Add accurate state for second argument
140
+ format, state, newType, value,
141
+ arrayOrObjectPropertyName,
142
+ schemaParents[parentPath],
143
+ stateObj
144
+ )); // Todo (low): Add accurate state for second argument
121
145
  } else {
146
+ // console.log(
147
+ // // keypath
148
+ // 'schemaParents', keypath, parentPath, value,
149
+ // arrayOrObjectPropertyName, schemaParents[parentPath]
150
+ // );
122
151
  try {
123
- newType = canonicalToAvailableType(
152
+ // console.log(
153
+ // 'VVVV0', JSON.stringify(parentPath), schemaParents // , stateObj
154
+ // );
155
+ ({
156
+ newType, schema, schemaIdx, mustBeOptional
157
+ } = canonicalTypeToAvailableTypeAndSchema(
124
158
  /** @type {import('../types.js').default} */ (types),
125
159
  /** @type {import('../formats.js').default} */ (formats),
126
160
  format,
@@ -129,8 +163,14 @@ const encapsulateObserver = (stateObj) => {
129
163
  * @type {import('../types.js').AvailableType}
130
164
  */
131
165
  (type),
132
- value
133
- ); // Todo (low): Add state for second argument
166
+ value,
167
+ arrayOrObjectPropertyName,
168
+ schemaParents[parentPath],
169
+ stateObj
170
+ )); // Todo (low): Add state for second argument
171
+ // console.log('VVVV1', value, schema);
172
+ // console.log('VVVV2',
173
+ // JSON.stringify(stateObj.schemaContent, null, 2));
134
174
  } catch (err) {
135
175
  console.log('err', type, err);
136
176
  stateObj.error = /** @type {Error} */ (err);
@@ -138,13 +178,8 @@ const encapsulateObserver = (stateObj) => {
138
178
  }
139
179
  }
140
180
 
141
- const li = keypath.lastIndexOf('.');
142
- const arrayOrObjectPropertyName =
143
- unescapeKeyPathComponent(keypath.slice(li + 1));
144
- const parentPath = li === -1 ? '' : keypath.slice(0, li);
145
-
146
181
  const hasChildren = [
147
- 'array', 'object', 'set', 'map',
182
+ 'array', 'object', 'set', 'map', 'tuple', 'record', 'filelist',
148
183
  // 'sparseArrays',
149
184
  'arrayNonindexKeys'
150
185
  ].includes(newType);
@@ -157,6 +192,18 @@ const encapsulateObserver = (stateObj) => {
157
192
  mapPaths.push(keypath);
158
193
  }
159
194
 
195
+ if (schema) {
196
+ stateObj.specificSchema = schema;
197
+ if (!stateObj.specificSchemas) {
198
+ stateObj.specificSchemas = [];
199
+ }
200
+ stateObj.specificSchemas.push(schema);
201
+ }
202
+
203
+ // console.log('is', stateObj.schemaContent);
204
+ // console.log('but could set to', schema);
205
+ // console.log('arrayOrObjectPropertyName', arrayOrObjectPropertyName);
206
+
160
207
  if (!stateObj.rootUI) {
161
208
  // console.log('vvvv0', newType, newValue);
162
209
  stateObj.rootUI = types?.getUIForModeAndType({
@@ -166,16 +213,8 @@ const encapsulateObserver = (stateObj) => {
166
213
  bringIntoFocus: false,
167
214
  buildTypeChoices,
168
215
  format,
169
- schemaContent,
170
- schemaState: getPossibleSchemasForPathAndType,
171
- /* schema:
172
- &&
173
- getPossibleSchemasForPathAndType({
174
- keypath,
175
- parentPath: '',
176
- valueType: newType
177
- }),
178
- */
216
+ specificSchemaObject: schema,
217
+ schemaContent: schema ?? schemaContent,
179
218
  value: newValue,
180
219
  hasValue: true,
181
220
  // Not currently in use but may be convenient for a
@@ -187,6 +226,10 @@ const encapsulateObserver = (stateObj) => {
187
226
  * {$addAndSetArrayElement: AddAndSetArrayElement}}
188
227
  */ (stateObj.rootUI);
189
228
 
229
+ if (schema) {
230
+ schemaParents[''] = [schema, schemaIdx];
231
+ }
232
+
190
233
  // Since we're skipping the array elements, we need to add the
191
234
  // map element to the array index where the array children
192
235
  // will be found (which we do want)
@@ -201,6 +244,14 @@ const encapsulateObserver = (stateObj) => {
201
244
  return;
202
245
  }
203
246
 
247
+ if (schema) {
248
+ schemaParents[keypath] = [schema, schemaIdx];
249
+ }
250
+ // console.log(
251
+ // 'schemaParents', newValue, JSON.stringify(parentPath),
252
+ // schema, schemaParents
253
+ // );
254
+
204
255
  // Todo (low): If could be async, use async encapsulate method
205
256
  // Todo (low): Handle `awaitingTypesonPromise` with place-holder
206
257
  // Todo (low): Handle `resolvingTypesonPromise` to replace place-holder
@@ -235,20 +286,13 @@ const encapsulateObserver = (stateObj) => {
235
286
  // console.log('vvvv', newType, '::', newValue, '::', newValue?.cause);
236
287
 
237
288
  const root = ui.$addAndSetArrayElement({
289
+ mustBeOptional,
238
290
  propName: arrayOrObjectPropertyName,
239
291
  type: newType,
240
292
  value: newValue,
241
293
  bringIntoFocus: false,
242
- schemaContent,
243
- schemaState: getPossibleSchemasForPathAndType
244
- /* schema:
245
- && getPossibleSchemasForPathAndType({
246
- keypath,
247
- parentPath,
248
- arrayOrObjectPropertyName,
249
- valueType: newType
250
- })
251
- */
294
+ schemaIdx,
295
+ schemaContent: schema ?? schemaContent
252
296
  });
253
297
 
254
298
  /* istanbul ignore if -- Guard for `null` return */
@@ -267,7 +311,9 @@ const encapsulateObserver = (stateObj) => {
267
311
  type: newType,
268
312
  // eslint-disable-next-line object-shorthand -- TS
269
313
  root: /** @type {HTMLDivElement} */ (root),
270
- topRoot: /** @type {HTMLDivElement} */ (stateObj.rootUI)
314
+ topRoot: /** @type {HTMLDivElement} */ (stateObj.rootUI),
315
+ // We don't want focus when values auto-added
316
+ avoidReport: true
271
317
  });
272
318
  }
273
319
 
@@ -296,6 +342,7 @@ const encapsulateObserver = (stateObj) => {
296
342
  };
297
343
 
298
344
  /**
345
+ * Performs replacements on a list of types.
299
346
  * @param {string[]} originTypes
300
347
  * @param {[originType: string, replacementType: string][]} replacements
301
348
  * @returns {void}
@@ -307,21 +354,40 @@ const replaceTypes = (originTypes, replacements) => {
307
354
  };
308
355
 
309
356
  /**
310
- * @param {import('../types.js').default} types
311
- * @param {import('../formats.js').default} formats
312
- * @param {import('../formats.js').AvailableFormat} format
313
- * @param {string} state
314
- * @param {import('../types.js').AvailableType} valType
315
- * @param {import('../formats.js').StructuredCloneValue} v
316
- * @throws {Error}
317
- * @returns {import('../types.js').AvailableType}
357
+ * Converts a (typeson structured cloning) type to a type name relevant for the
358
+ * format, state, value, and schema content, and may supply a child type if
359
+ * there is a match. Also returns relevant schema for the type.
360
+ * @param {import('../types.js').default} types The Types object containing
361
+ * type-specific data.
362
+ * @param {import('../formats.js').default} formats The Formats object
363
+ * containing format-specific data.
364
+ * @param {import('../formats.js').AvailableFormat} format The current format.
365
+ * @param {string} state The current state.
366
+ * @param {import('../types.js').AvailableType} valType The value type being
367
+ * checked.
368
+ * @param {import('../formats.js').StructuredCloneValue} v The value being
369
+ * checked.
370
+ * @param {string} arrayOrObjectPropertyName
371
+ * @param {[import('zodex').SzType, number|undefined]|undefined} parentSchema
372
+ * @param {import('../types.js').StateObject} stateObj The schema content
373
+ * being checked.
374
+ * @throws {Error} May throw if data found to be invalid.
375
+ * @returns {{
376
+ * newType: import('../types.js').AvailableType,
377
+ * schema?: import('zodex').SzType|undefined,
378
+ * mustBeOptional?: boolean,
379
+ * schemaIdx?: number
380
+ * }} Schema and type info.
318
381
  */
319
- const canonicalToAvailableType = (
320
- types, formats, format, state, valType, v
382
+ const canonicalTypeToAvailableTypeAndSchema = (
383
+ types, formats, format, state, valType, v, arrayOrObjectPropertyName,
384
+ parentSchema, stateObj
321
385
  ) => {
322
386
  const frmt = formats.getAvailableFormat(format);
323
- const {getTypesForState, convertFromTypeson, testInvalid} = frmt;
324
- const allowableTypes = getTypesForState.call(frmt, types, state);
387
+ const {getTypesAndSchemasForState, convertFromTypeson, testInvalid} = frmt;
388
+ const allowableTypes = getTypesAndSchemasForState.call(
389
+ frmt, types, state, stateObj.schemaContent
390
+ )?.types;
325
391
  /* istanbul ignore if -- Guard */
326
392
  if (!allowableTypes) {
327
393
  throw new Error('Unexpected undefined type for state');
@@ -331,41 +397,60 @@ const canonicalToAvailableType = (
331
397
  * @type {import('../types.js').AvailableType|undefined}
332
398
  */
333
399
  let ret;
334
- // console.log('format, state, valType, v', format, state, valType, v);
335
400
 
336
401
  /**
337
- * @param {string} newValType
338
- * @throws {Error}
339
- * @returns {never}
402
+ * Throws an error with information about the new value type.
403
+ * @param {string} newValType The new value type being recorded.
404
+ * @throws {Error} The invalid Error being thrown.
405
+ * @returns {never} Always throws instead of returning.
340
406
  */
341
407
  const isInvalid = (newValType) => {
342
- console.log('newValType', newValType);
343
- const err = new Error('Invalid');
344
- /** @type {Error & {newValType: string}} */ (err).newValType = newValType;
408
+ const err = /** @type {Error & {newValType: string}} */ (
409
+ new Error('Invalid')
410
+ );
411
+ err.newValType = newValType;
345
412
  throw err;
346
413
  };
414
+ let schema;
347
415
  if (convertFromTypeson) {
348
- const newValType = convertFromTypeson(valType);
416
+ let newValType;
417
+ let mustBeOptional;
418
+ let schemaIdx;
419
+ ({
420
+ type: newValType,
421
+ schema,
422
+ schemaIdx,
423
+ mustBeOptional
424
+ } = convertFromTypeson(
425
+ valType, types, v, arrayOrObjectPropertyName, parentSchema, stateObj
426
+ ));
349
427
  if (typeof newValType === 'string') {
350
428
  if (testInvalid && testInvalid(newValType, v)) {
351
429
  return isInvalid(newValType);
352
430
  }
353
431
  valType = newValType;
432
+ if (schema) {
433
+ return {
434
+ newType: valType,
435
+ schema,
436
+ schemaIdx,
437
+ mustBeOptional
438
+ };
439
+ }
354
440
  }
355
441
  }
356
442
 
357
- // console.log('ret', ret);
358
443
  allowableTypes.some((allowableType) => {
359
- // eslint-disable-next-line @stylistic/max-len -- Long
360
- const typeObj = /** @type {import('../types.js').TypeObject & {childTypes: string[]}} */ (
361
- types.getTypeObject(allowableType)
362
- );
444
+ const typeObj =
445
+ /** @type {import('../types.js').TypeObject & {childTypes: string[]}} */ (
446
+ types.getTypeObject(allowableType)
447
+ );
363
448
  const {
364
449
  valueMatch, superType, childTypes
365
450
  } = typeObj;
366
451
  if (
367
452
  (superType && valueMatch &&
368
- // Currently using for `true` and `false`
453
+ // Using, e.g., for `true` and `false` subtypes
369
454
  superType === valType && valueMatch(v)) ||
370
455
  (childTypes && childTypes.includes(valType))
371
456
  ) {
@@ -375,7 +460,7 @@ const canonicalToAvailableType = (
375
460
 
376
461
  return false;
377
462
  });
378
- // console.log('ret2', ret);
463
+
379
464
  if (ret === undefined) {
380
465
  // We run this separately from the `childTypes` check above
381
466
  // to ensure `childTypes` have priority regardless of position
@@ -387,29 +472,25 @@ const canonicalToAvailableType = (
387
472
  return false;
388
473
  });
389
474
  if (ret === undefined) {
475
+ console.log('AALLLowableTypes', state, allowableTypes, '::', valType);
390
476
  return isInvalid(valType);
391
477
  }
392
478
  }
393
- return ret;
479
+ return {
480
+ newType: ret,
481
+ schema
482
+ };
394
483
  };
395
484
 
396
- /**
397
- * @callback FormatIterator
398
- * @param {import('../formats.js').StructuredCloneValue} records
399
- * @param {import('../types.js').StateObject} stateObj
400
- * @returns {Promise<Element>}
401
- */
402
-
403
485
  /** @type {import('../formats.js').Format} */
404
486
  const structuredCloning = {
405
487
  iterate (records, stateObj) {
406
- // console.log('records', records);
407
488
  /* istanbul ignore if -- Just a guard */
408
489
  if (!stateObj.format) {
409
490
  stateObj.format = 'structuredCloning';
410
491
  }
411
492
  // Todo: Replace this with async typeson?
412
- // eslint-disable-next-line promise/avoid-new
493
+ // eslint-disable-next-line promise/avoid-new -- Our own API for now
413
494
  return new Promise((resolve, reject) => {
414
495
  const structuredCloningFixed = structuredCloningThrowing.filter(
415
496
  (typeSpecSet) => {
@@ -441,13 +522,13 @@ const structuredCloning = {
441
522
  } else {
442
523
  resolve(/** @type {Required<import('../types.js').StateObject>} */ (
443
524
  stateObj
444
- ).rootUI);
525
+ ));
445
526
  }
446
527
  });
447
528
  },
448
- getTypesForState (types, state) {
529
+ getTypesAndSchemasForState (types, state) {
449
530
  if (state && types.getContextInfo('structuredCloning', state)) {
450
- const typesForFormat = this.getTypesForState(types) ||
531
+ const typesForFormat = this.getTypesAndSchemasForState(types)?.types ||
451
532
  /* istanbul ignore next -- types should be an array */
452
533
  [];
453
534
  const contextInfo = types.getContextInfo('structuredCloning', state);
@@ -455,22 +536,39 @@ const structuredCloning = {
455
536
  const precedingIdx = typesForFormat.indexOf(after);
456
537
  typesForFormat.splice(precedingIdx + 1, 0, type);
457
538
  });
458
- return typesForFormat;
539
+ return {
540
+ types: typesForFormat,
541
+ schemaObjects: []
542
+ };
459
543
  }
460
- // Todo: Could we implement schemas here by introducing new keys to
461
- // `Types.contexts` which could be used rather than manual
462
- // handling to determine a delimited group of children
544
+ // Todo: Introduce new keys (to `Types.contexts`?) which could be used to
545
+ // determine a delimited group of children (rather
546
+ // than manual exception handling as we do here)
463
547
  if (state === 'errorsArray') {
464
- return ['error', 'errors'];
548
+ return {
549
+ types: ['error', 'errors'],
550
+ schemaObjects: []
551
+ };
465
552
  }
466
553
  if (state === 'filelistArray') {
467
- return ['file'];
554
+ return {
555
+ types: ['file'],
556
+ schemaObjects: []
557
+ };
468
558
  }
469
- return this.types();
559
+ return {
560
+ types: this.types(),
561
+ schemaObjects: []
562
+ };
470
563
  /*
471
- // Todo (low): These need to specify their own inner contexts
564
+ // These have their children determined internally to array
472
565
  if (['map', 'set'].includes(state)) {return;}
473
- if ('int8array', 'uint8array', 'uint8clampedarray',
566
+ */
567
+
568
+ // These have their own internal numeric children instead
569
+ /*
570
+ if (
571
+ 'int8array', 'uint8array', 'uint8clampedarray',
474
572
  'int16array', 'uint16array', 'int32array',
475
573
  'uint32array', 'float32array', 'float64array'
476
574
  ).includes(state)) {return;}
@@ -481,6 +579,8 @@ const structuredCloning = {
481
579
  replaceTypes(jsonTypes, [
482
580
  [
483
581
  'array',
582
+ // We can rename to this instead of `arrayNonindexKeys` if we change
583
+ // typeson-registry name
484
584
  // 'sparseArrays',
485
585
  'arrayNonindexKeys'
486
586
  ]
@@ -493,6 +593,7 @@ const structuredCloning = {
493
593
  ...jsonTypes,
494
594
  'undef', // Explicit undefined only
495
595
  'bigint',
596
+ 'bigintObject',
496
597
  'SpecialNumber', // '`NaN`, `Infinity`, `-Infinity`, `-0`
497
598
  'date',
498
599
  'regexp',
package/src/formats.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import indexedDBKey from './formats/indexedDBKey.js';
2
2
  import json from './formats/json.js';
3
3
  import structuredCloning from './formats/structuredCloning.js';
4
+ import schema from './formats/schema.js';
4
5
 
5
6
  /**
6
7
  * An arbitrary Structured Clone, JSON, etc. value.
@@ -8,11 +9,15 @@ import structuredCloning from './formats/structuredCloning.js';
8
9
  */
9
10
 
10
11
  /**
11
- * @callback GetTypesForFormatAndState
12
+ * @callback GetTypesAndSchemasForFormatAndState
12
13
  * @param {import('./types.js').default} types
13
14
  * @param {AvailableFormat} format
14
15
  * @param {string} [state]
15
- * @returns {import('./types.js').AvailableType[]|undefined}
16
+ * @param {import('./formatAndTypeChoices.js').ZodexSchema|
17
+ * undefined} [schemaObject]
18
+ * @param {import('./formatAndTypeChoices.js').ZodexSchema|
19
+ * undefined} [schemaOriginal]
20
+ * @returns {TypesAndSchemaObjects|undefined}
16
21
  */
17
22
 
18
23
  /* schema:
@@ -25,25 +30,57 @@ export const getTypeForFormatStateAndValue = ({format, state, value}) => {
25
30
  */
26
31
 
27
32
  /**
28
- * @typedef {"indexedDBKey"|"json"|"structuredCloning"} AvailableFormat
33
+ * @typedef {"indexedDBKey"|"json"|"structuredCloning"|"schema"} AvailableFormat
29
34
  */
30
35
 
31
36
  /**
32
37
  * @typedef {{
33
- * types: () => (import('./types.js').AvailableType)[],
34
- * testInvalid?: (
38
+ * types: (import('./types.js').AvailableType)[],
39
+ * schemaObjects: import('./formats/schema.js').ZodexSchema[]
40
+ * }} TypesAndSchemaObjects
41
+ */
42
+
43
+ /**
44
+ * Responsible for traversing over data (along with state information) to build
45
+ * and return a relevant UI element.
46
+ * @callback FormatIterator
47
+ * @param {StructuredCloneValue} records
48
+ * @param {import('./types.js').StateObject} stateObj
49
+ * @returns {Promise<Required<import('./types.js').StateObject>>}
50
+ */
51
+
52
+ /**
53
+ * @typedef {object} Format
54
+ * @property {() => (import('./types.js').AvailableType)[]} types Returns list
55
+ * of types generally available to structured cloning. See
56
+ * {@link getTypesAndSchemasForState} for context-dependent method.
57
+ * @property {FormatIterator} iterate Traverses over data to build and return
58
+ * a relevant UI element.
59
+ * @property {(
60
+ * types: import('./types.js').default,
61
+ * state?: string,
62
+ * schemaObject?: import('./formatAndTypeChoices.js').ZodexSchema|
63
+ * undefined,
64
+ * schemaOriginal?: import('./formatAndTypeChoices.js').ZodexSchema|
65
+ * undefined
66
+ * ) => TypesAndSchemaObjects|undefined} getTypesAndSchemasForState Gets the
67
+ * specific types (and schemas) relevant to a given state.
68
+ * @property {(
35
69
  * newType: string, value: Date|Array<StructuredCloneValue>
36
- * ) => boolean|undefined,
37
- * convertFromTypeson?: (
38
- * typesonType: import('./types.js').AvailableType
39
- * ) => import('./types.js').AvailableType|undefined,
40
- * iterate: import('./formats/structuredCloning.js').FormatIterator,
41
- * getTypesForState: (
42
- * types: import('./types.js').default,
43
- * state?: string
44
- * ) => undefined|
45
- * (import('./types.js').AvailableType)[]
46
- * }} Format
70
+ * ) => boolean|undefined} [testInvalid]
71
+ * @property {(
72
+ * typesonType: import('./types.js').AvailableType,
73
+ * types: import('./types.js').default,
74
+ * v?: import('./formats.js').StructuredCloneValue,
75
+ * arrayOrObjectPropertyName?: string,
76
+ * parentSchema?: [import('zodex').SzType, number|undefined]|undefined,
77
+ * stateObj?: import('./types.js').StateObject,
78
+ * ) => {
79
+ * type: import('./types.js').AvailableType|undefined
80
+ * schema?: import('zodex').SzType|undefined,
81
+ * mustBeOptional?: boolean,
82
+ * schemaIdx?: number
83
+ * }} [convertFromTypeson]
47
84
  */
48
85
 
49
86
  /**
@@ -80,11 +117,7 @@ class Formats {
80
117
  this.availableFormats = /** @type {{[key: string]: Format}} */ ({
81
118
  indexedDBKey,
82
119
  json,
83
- // Todo (readme): these too? getTypesForState(types, state)
84
- /* schema:
85
- schemaAndArbitrary,
86
- schemaOnly,
87
- */
120
+ schema,
88
121
  structuredCloning
89
122
  });
90
123
  }
@@ -94,7 +127,7 @@ class Formats {
94
127
  * @param {AvailableFormat} format
95
128
  * @param {StructuredCloneValue} record
96
129
  * @param {import('./types.js').StateObject} stateObj
97
- * @returns {Promise<Element>}
130
+ * @returns {Promise<Required<import('./types.js').StateObject>>}
98
131
  */
99
132
  async getControlsForFormatAndValue (types, format, record, stateObj) {
100
133
  return await this.availableFormats[format].
@@ -109,12 +142,14 @@ class Formats {
109
142
  }
110
143
 
111
144
  /**
112
- * @type {GetTypesForFormatAndState}
145
+ * @type {GetTypesAndSchemasForFormatAndState}
113
146
  */
114
- getTypesForFormatAndState (
115
- types, format, state
147
+ getTypesAndSchemasForFormatAndState (
148
+ types, format, state, schemaObject, schemaOriginal
116
149
  ) {
117
- return this.availableFormats[format].getTypesForState(types, state);
150
+ return this.availableFormats[format].getTypesAndSchemasForState(
151
+ types, state, schemaObject, schemaOriginal
152
+ );
118
153
  }
119
154
 
120
155
  /**
@@ -1,3 +1,4 @@
1
+ import {toStringTag} from '../vendor-imports.js';
1
2
  import {$e, $$e} from '../utils/templateUtils.js';
2
3
 
3
4
  /**
@@ -6,9 +7,13 @@ import {$e, $$e} from '../utils/templateUtils.js';
6
7
  const BooleanObjectType = {
7
8
  option: ['BooleanObject'],
8
9
  stringRegex: /^Boolean\((.*)\)$/u,
10
+ valueMatch (x) {
11
+ return toStringTag(x) === 'Boolean' && typeof x === 'object';
12
+ },
9
13
  toValue (s) {
10
14
  return {
11
- // eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins
15
+ // eslint-disable-next-line @stylistic/max-len -- Long
16
+ // eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins -- Deliberate creation here
12
17
  value: new Boolean(s === 'true')
13
18
  };
14
19
  },
@@ -27,16 +32,23 @@ const BooleanObjectType = {
27
32
  const input = inputs[value.valueOf() ? 0 : 1];
28
33
  input.checked = true;
29
34
  },
30
- viewUI ({value}) {
31
- return ['i', {dataset: {type: 'BooleanObject'}}, [`Boolean(${value})`]];
35
+ viewUI ({value, specificSchemaObject}) {
36
+ return ['i', {
37
+ dataset: {type: 'BooleanObject'},
38
+ title: specificSchemaObject?.description ?? '(a Boolean Object)'
39
+ }, [specificSchemaObject ? `${value}` : `Boolean(${value})`]];
32
40
  },
33
41
  ct: 0,
34
42
  editUI ({
35
- // eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins
36
- typeNamespace, value = new Boolean(true)
43
+ // eslint-disable-next-line @stylistic/max-len -- Long
44
+ // eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins -- Deliberate creation here
45
+ typeNamespace, specificSchemaObject, value = new Boolean(true)
37
46
  }) {
38
47
  this.ct++;
39
- return ['div', {dataset: {type: 'BooleanObject'}}, [
48
+ return ['div', {
49
+ dataset: {type: 'BooleanObject'},
50
+ title: specificSchemaObject?.description ?? 'Boolean object'
51
+ }, [
40
52
  ['label', [
41
53
  'True',
42
54
  ['input', {