@es-joy/jsoe 0.5.1 → 0.6.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 (80) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc.cjs +2 -0
  3. package/.nyc_output/out.json +121296 -0
  4. package/CHANGES.md +10 -0
  5. package/README.md +47 -21
  6. package/cypress.config.ts +13 -0
  7. package/demo/index-instrumented.html +29 -0
  8. package/demo/index.html +10 -1
  9. package/demo/index.js +482 -126
  10. package/dist/formatAndTypeChoices.d.ts +2 -2
  11. package/dist/formatAndTypeChoices.d.ts.map +1 -1
  12. package/dist/formats/json.d.ts.map +1 -1
  13. package/dist/formats/structuredCloning.d.ts +2 -1
  14. package/dist/formats/structuredCloning.d.ts.map +1 -1
  15. package/dist/fundamentalTypes/arrayType.d.ts +6 -37
  16. package/dist/fundamentalTypes/arrayType.d.ts.map +1 -1
  17. package/dist/fundamentalTypes/dateType.d.ts.map +1 -1
  18. package/dist/fundamentalTypes/errorType.d.ts +6 -0
  19. package/dist/fundamentalTypes/errorType.d.ts.map +1 -0
  20. package/dist/fundamentalTypes/mapType.d.ts +6 -0
  21. package/dist/fundamentalTypes/mapType.d.ts.map +1 -0
  22. package/dist/fundamentalTypes/nullType.d.ts.map +1 -1
  23. package/dist/fundamentalTypes/objectReferenceType.d.ts.map +1 -1
  24. package/dist/fundamentalTypes/setType.d.ts +6 -0
  25. package/dist/fundamentalTypes/setType.d.ts.map +1 -0
  26. package/dist/fundamentalTypes/sparseUndefinedType.d.ts.map +1 -1
  27. package/dist/fundamentalTypes/undefinedType.d.ts.map +1 -1
  28. package/dist/subTypes/blobHTMLType.d.ts +12 -6
  29. package/dist/subTypes/blobHTMLType.d.ts.map +1 -1
  30. package/dist/superTypes/SpecialNumberType.d.ts +14 -0
  31. package/dist/superTypes/SpecialNumberType.d.ts.map +1 -0
  32. package/dist/superTypes/SpecialRealNumberType.d.ts +6 -0
  33. package/dist/superTypes/SpecialRealNumberType.d.ts.map +1 -0
  34. package/dist/superTypes/errorsSpecialType.d.ts +8 -0
  35. package/dist/superTypes/errorsSpecialType.d.ts.map +1 -0
  36. package/dist/typeChoices.d.ts +4 -2
  37. package/dist/typeChoices.d.ts.map +1 -1
  38. package/dist/types.d.ts +83 -231
  39. package/dist/types.d.ts.map +1 -1
  40. package/dist/utils/dialogs.d.ts +22 -22
  41. package/dist/utils/dialogs.d.ts.map +1 -1
  42. package/dist/utils/templateUtils.d.ts +6 -6
  43. package/dist/utils/templateUtils.d.ts.map +1 -1
  44. package/dist/vendor-imports.d.ts +1 -1
  45. package/package.json +39 -34
  46. package/rollup.config.js +14 -2
  47. package/server.js +1 -1
  48. package/src/formatAndTypeChoices.js +9 -9
  49. package/src/formats/indexedDBKey.js +2 -2
  50. package/src/formats/json.js +1 -2
  51. package/src/formats/structuredCloning.js +101 -29
  52. package/src/formats.js +2 -2
  53. package/src/fundamentalTypes/arrayReferenceType.js +3 -3
  54. package/src/fundamentalTypes/arrayType.js +390 -87
  55. package/src/fundamentalTypes/dateType.js +4 -6
  56. package/src/fundamentalTypes/errorType.js +416 -0
  57. package/src/fundamentalTypes/mapType.js +34 -0
  58. package/src/fundamentalTypes/nullType.js +1 -2
  59. package/src/fundamentalTypes/objectReferenceType.js +2 -1
  60. package/src/fundamentalTypes/regexpType.js +2 -2
  61. package/src/fundamentalTypes/setType.js +34 -0
  62. package/src/fundamentalTypes/sparseUndefinedType.js +2 -3
  63. package/src/fundamentalTypes/undefinedType.js +2 -3
  64. package/src/jsoe.css +3 -0
  65. package/src/subTypes/blobHTMLType.js +37 -33
  66. package/src/subTypes/falseType.js +2 -2
  67. package/src/subTypes/trueType.js +2 -2
  68. package/src/superTypes/{SpecialNumberSuperType.js → SpecialNumberType.js} +1 -1
  69. package/src/superTypes/{SpecialRealNumberSuperType.js → SpecialRealNumberType.js} +3 -2
  70. package/src/superTypes/errorsSpecialType.js +768 -0
  71. package/src/typeChoices.js +27 -20
  72. package/src/types.js +71 -39
  73. package/src/utils/dialogs.js +11 -12
  74. package/src/utils/jsonPointer.js +3 -3
  75. package/src/utils/templateUtils.js +4 -4
  76. package/src/vendor-imports.js +2 -2
  77. package/tsconfig.json +1 -1
  78. package/typings/CypressPlugins.d.ts +10 -0
  79. package/vendor/jamilih/dist/jml-es.js +126 -106
  80. package/vendor/typeson-registry/dist/index.js +188 -44
@@ -0,0 +1,768 @@
1
+ /* globals InternalError */
2
+ import {errors as errorsTypesonRegistry} from 'typeson-registry';
3
+ import {$e} from '../utils/templateUtils.js';
4
+ import {jml} from '../vendor-imports.js';
5
+ import arrayType from '../fundamentalTypes/arrayType.js';
6
+
7
+ /**
8
+ * @typedef {number} Integer
9
+ */
10
+
11
+ /**
12
+ * @param {object} obj
13
+ * @returns {string}
14
+ */
15
+ function getConstructor (obj) {
16
+ const str = Function.prototype.toString.call(obj);
17
+ return str.slice(9, str.indexOf('('));
18
+ }
19
+
20
+ /**
21
+ * @typedef {ErrorConstructor|AggregateErrorConstructor} SpecialErrorType
22
+ */
23
+
24
+ /** @type {Map<string, SpecialErrorType>} */
25
+ const specialErrorsMap = new Map([
26
+ ['TypeError', TypeError],
27
+ ['RangeError', RangeError],
28
+ ['SyntaxError', SyntaxError],
29
+ ['ReferenceError', ReferenceError],
30
+ ['EvalError', EvalError],
31
+ ['URIError', URIError]
32
+ ]);
33
+ if (typeof AggregateError !== 'undefined') {
34
+ specialErrorsMap.set('AggregateError', AggregateError);
35
+ }
36
+
37
+ /* istanbul ignore next 5 */
38
+ // @ts-expect-error Only use if available
39
+ if (typeof InternalError !== 'undefined') {
40
+ // @ts-expect-error Only use if available
41
+ specialErrorsMap.set('InternalError', InternalError);
42
+ }
43
+
44
+ const specialErrors = [...specialErrorsMap.keys()];
45
+
46
+ /**
47
+ * @type {import('./SpecialNumberType.js').SuperTypeObject}
48
+ */
49
+ const errorsSpecialType = {
50
+ option: ['Special errors'],
51
+ childTypes: specialErrors.map((err) => {
52
+ return err.toLowerCase();
53
+ }),
54
+ stringRegex: new RegExp(
55
+ '^(?<errorClass>' + specialErrors.join('|') +
56
+ ')\\((?<innerContent>.*)\\)$', 'u'
57
+ ),
58
+ toValue (s, rootInfo) {
59
+ const {groups: {
60
+ errorClass
61
+ /* istanbul ignore next -- Should always be found */
62
+ } = {}} = /** @type {RegExpMatchArray} */ (
63
+ /** @type {import('../types.js').RootInfo} */ (rootInfo).match
64
+ );
65
+
66
+ const obj = JSON.parse(s);
67
+ const errObj = /** @type {{revive: import('typeson-registry').Reviver}} */ (
68
+ errorsTypesonRegistry[errorClass.toLowerCase()]
69
+ ).revive(obj, {});
70
+ return {value: errObj};
71
+ },
72
+ getInput ({root}) { // Which one to get here?
73
+ return /** @type {HTMLInputElement} */ ($e(root, 'input:not([type])'));
74
+ },
75
+ setValue ({root, value}) {
76
+ const errorType =
77
+ /**
78
+ * @type {HTMLSelectElement & {
79
+ * $hideAggregateErrorsLabel: () => void
80
+ * }}
81
+ */ (
82
+ $e(root, '.errorType')
83
+ );
84
+ errorType.value = getConstructor(value.constructor);
85
+ errorType.$hideAggregateErrorsLabel();
86
+
87
+ if (typeof value.message === 'string') {
88
+ /** @type {HTMLInputElement} */ (
89
+ $e(root, 'input.message:not([type])')
90
+ ).value = value.message;
91
+ } else {
92
+ /** @type {HTMLInputElement} */ (
93
+ $e(root, 'input.message[type=checkbox]')
94
+ ).click();
95
+ }
96
+ if (typeof value.name === 'string') {
97
+ /** @type {HTMLInputElement} */ (
98
+ $e(root, 'input.name:not([type])')
99
+ ).value = value.name;
100
+ } else {
101
+ /** @type {HTMLInputElement} */ (
102
+ $e(root, 'input.name[type=checkbox]')
103
+ ).click();
104
+ }
105
+ if (typeof value.fileName === 'string') {
106
+ /** @type {HTMLInputElement} */ (
107
+ $e(root, 'input.fileName:not([type])')
108
+ ).value = value.fileName;
109
+ } else {
110
+ /** @type {HTMLInputElement} */ (
111
+ $e(root, 'input.fileName[type=checkbox]')
112
+ ).click();
113
+ }
114
+
115
+ if (typeof value.lineNumber === 'number') {
116
+ /** @type {HTMLInputElement} */ (
117
+ $e(root, 'input.lineNumber[type=number]')
118
+ ).value = value.lineNumber;
119
+ } else {
120
+ /** @type {HTMLInputElement} */ (
121
+ $e(root, 'input.lineNumber[type=number]')
122
+ ).value = '';
123
+ }
124
+
125
+ if (typeof value.columnNumber === 'number') {
126
+ /** @type {HTMLInputElement} */ (
127
+ $e(root, 'input.columnNumber[type=number]')
128
+ ).value = value.columnNumber;
129
+ } else {
130
+ /** @type {HTMLInputElement} */ (
131
+ $e(root, 'input.columnNumber[type=number]')
132
+ ).value = '';
133
+ }
134
+
135
+ if (typeof value.stack === 'string') {
136
+ /** @type {HTMLTextAreaElement} */ (
137
+ $e(root, 'textarea.stack:not([type])')
138
+ ).value = value.stack;
139
+ } else {
140
+ /** @type {HTMLInputElement} */ (
141
+ $e(root, 'input.stack[type=checkbox]')
142
+ ).click();
143
+ }
144
+
145
+ setTimeout(() => {
146
+ if (typeof value.cause === 'object') {
147
+ /** @type {HTMLElement} */ ($e(root, '.cause')).click();
148
+ /** @type {import('../types.js').TypeObjectSetValue} */ (
149
+ this.setValue
150
+ )({
151
+ root: /** @type {HTMLDivElement} */ ($e(root, '.causeContents')),
152
+ value: value.cause
153
+ });
154
+ }
155
+
156
+ if (Array.isArray(value.errors)) {
157
+ const aggregateErrors =
158
+ /**
159
+ * @type {HTMLElement & {
160
+ * $emptyAggregateErrorsContents: () => void,
161
+ * $populateContents: (errs: unknown[]) => void
162
+ * }}
163
+ */ (
164
+ $e(root, 'input.aggregateErrors')
165
+ );
166
+ aggregateErrors.click();
167
+ aggregateErrors.$emptyAggregateErrorsContents();
168
+ aggregateErrors.$populateContents(value.errors);
169
+ }
170
+ });
171
+ },
172
+ getValue ({root}) {
173
+ const UserErrorType = specialErrorsMap.get(
174
+ /** @type {HTMLSelectElement} */ (
175
+ $e(root, '.errorType')
176
+ ).value
177
+ );
178
+ if (!UserErrorType) {
179
+ throw new Error('Bad error type');
180
+ }
181
+
182
+ /**
183
+ * @type {{
184
+ * message?: string|undefined
185
+ * name?: string|undefined
186
+ * fileName?: string|undefined
187
+ * stack?: string|undefined,
188
+ * lineNumber?: number|undefined
189
+ * columnNumber?: number|undefined
190
+ * cause?: unknown|undefined
191
+ * }}
192
+ */
193
+ let errObj;
194
+ if (/** @type {HTMLInputElement} */ (
195
+ $e(root, 'input.message[type=checkbox]')
196
+ ).checked) {
197
+ const message = /** @type {HTMLInputElement} */ (
198
+ $e(root, 'input.message:not([type])')
199
+ ).value;
200
+
201
+ if (getConstructor(UserErrorType) === 'AggregateError') {
202
+ const UET = /** @type {AggregateErrorConstructor} */ (UserErrorType);
203
+ const errorRoot =
204
+ /** @type {HTMLElement} */ ($e(
205
+ root, '.aggregateErrorsContents'
206
+ )).firstElementChild;
207
+
208
+ const errors = arrayType.getValue({
209
+ root: /** @type {HTMLDivElement} */ (errorRoot)
210
+ });
211
+ errObj = new UET(errors, message);
212
+ } else {
213
+ const UET = /** @type {TypeErrorConstructor} */ (UserErrorType);
214
+ errObj = new UET(message);
215
+ }
216
+ } else {
217
+ if (getConstructor(UserErrorType) === 'AggregateError') {
218
+ const UET = /** @type {AggregateErrorConstructor} */ (UserErrorType);
219
+ const errorRoot =
220
+ /** @type {HTMLElement} */ ($e(
221
+ root, '.aggregateErrorsContents'
222
+ )).firstElementChild;
223
+ const errors = arrayType.getValue({
224
+ root: /** @type {HTMLDivElement} */ (errorRoot)
225
+ });
226
+ errObj = new UET(errors);
227
+ } else {
228
+ const UET = /** @type {TypeErrorConstructor} */ (UserErrorType);
229
+ errObj = new UET();
230
+ }
231
+ errObj.message = undefined; // Force (at least needed for Chrome)
232
+ }
233
+ if (/** @type {HTMLInputElement} */ (
234
+ $e(root, 'input.name[type=checkbox]')
235
+ ).checked) {
236
+ const name = /** @type {HTMLInputElement} */ (
237
+ $e(root, 'input.name:not([type])')
238
+ ).value;
239
+ errObj.name = name;
240
+ } else {
241
+ errObj.name = undefined;
242
+ }
243
+ if (/** @type {HTMLInputElement} */ (
244
+ $e(root, 'input.fileName[type=checkbox]')
245
+ ).checked) {
246
+ const fileName = /** @type {HTMLInputElement} */ (
247
+ $e(root, 'input.fileName:not([type])')
248
+ ).value;
249
+ errObj.fileName = fileName;
250
+ } else {
251
+ errObj.fileName = undefined;
252
+ }
253
+ if (/** @type {HTMLInputElement} */ (
254
+ $e(root, 'input.stack[type=checkbox]')
255
+ ).checked) {
256
+ const stack = /** @type {HTMLTextAreaElement} */ (
257
+ $e(root, 'textarea.stack:not([type])')
258
+ ).value;
259
+ errObj.stack = stack;
260
+ } else {
261
+ errObj.stack = undefined;
262
+ }
263
+
264
+ const lineNumber = /** @type {HTMLInputElement} */ (
265
+ $e(root, 'input.lineNumber[type=number]')
266
+ ).value;
267
+ errObj.lineNumber = lineNumber === '' ? undefined : Number(lineNumber);
268
+
269
+ const columnNumber = /** @type {HTMLInputElement} */ (
270
+ $e(root, 'input.columnNumber[type=number]')
271
+ ).value;
272
+ errObj.columnNumber = columnNumber === ''
273
+ ? undefined
274
+ : Number(columnNumber);
275
+
276
+ const causeContents = /** @type {HTMLDivElement} */ (
277
+ $e(root, '.causeContents')
278
+ );
279
+ if (causeContents.children.length) {
280
+ errObj.cause = this.getValue({
281
+ root: causeContents
282
+ });
283
+ }
284
+
285
+ return errObj;
286
+ },
287
+ viewUI (
288
+ {value: o, format, typeNamespace, resultType}
289
+ ) {
290
+ const constructor = getConstructor(o.constructor);
291
+ return /** @type {import('jamilih').JamilihArray} */ ([
292
+ 'div', {dataset: {type: 'errors'}}, [
293
+ ['div', [['b', ['Error type: ']], ['span', [
294
+ constructor
295
+ ]]]],
296
+ typeof o.message === 'string'
297
+ ? ['div', [['b', ['Message: ']], ['span', [o.message]]]]
298
+ : [],
299
+ typeof o.name === 'string'
300
+ ? ['div', [['b', ['Name: ']], ['span', [o.name]]]]
301
+ : [],
302
+ typeof o.fileName === 'string'
303
+ ? ['div', [['b', ['File name: ']], ['span', [o.fileName]]]]
304
+ : [],
305
+ typeof o.lineNumber === 'number'
306
+ ? ['div', [['b', ['Line number: ']], ['span', [o.lineNumber]]]]
307
+ : [],
308
+ typeof o.columnNumber === 'number'
309
+ ? ['div', [['b', ['Column number: ']], ['span', [o.columnNumber]]]]
310
+ : [],
311
+ typeof o.stack === 'string'
312
+ ? ['div', [['b', ['Stack: ']], ['span', [o.stack]]]]
313
+ : [],
314
+ ['b', ['Cause: ']], ['div', {class: 'causeHolder'}, [
315
+ ['button', {$on: {click (/** @type {Event} */ e) {
316
+ e.preventDefault();
317
+ const {target} = e;
318
+ const causeContents = /** @type {HTMLDivElement} */ (
319
+ /** @type {HTMLElement} */ (target).nextElementSibling
320
+ );
321
+ causeContents.hidden = !causeContents.hidden;
322
+ /** @type {HTMLElement} */ (
323
+ target
324
+ ).textContent = causeContents.hidden ? '+' : '-';
325
+ }}}, ['-']],
326
+ ['div', {class: 'causeContents'}, [
327
+ o.cause
328
+ ? this.viewUI({
329
+ format,
330
+ value: o.cause
331
+ })
332
+ : ''
333
+ ]]
334
+ ]],
335
+ constructor === 'AggregateError'
336
+ ? ['div', [
337
+ ['b', ['Errors ']],
338
+ ['div', {class: 'aggregateErrorsHolder'}, [
339
+ ['button', {$on: {click (/** @type {Event} */ e) {
340
+ e.preventDefault();
341
+ const {target} = e;
342
+ const aggregateErrorsContents = /** @type {HTMLDivElement} */ (
343
+ /** @type {HTMLElement} */ (target).nextElementSibling
344
+ );
345
+ aggregateErrorsContents.hidden =
346
+ !aggregateErrorsContents.hidden;
347
+ /** @type {HTMLElement} */ (
348
+ target
349
+ ).textContent = aggregateErrorsContents.hidden ? '+' : '-';
350
+ }}}, ['-']],
351
+ ['div', {class: 'aggregateErrorsContents'}, [
352
+ (o.errors
353
+ ? (() => {
354
+ const [div] = arrayType.viewUI({
355
+ typeNamespace, resultType, format,
356
+ type: 'arrayNonindexKeys',
357
+ value: []
358
+ });
359
+
360
+ /** @type {Error[]} */
361
+ (o.errors).forEach((error, idx) => {
362
+ /**
363
+ * @type {HTMLDivElement & {
364
+ * $addAndSetArrayElement:
365
+ * import('../formats/structuredCloning.js').
366
+ * AddAndSetArrayElement
367
+ * }}
368
+ */
369
+ (div).$addAndSetArrayElement({
370
+ propName: String(idx),
371
+ type: getConstructor(error.constructor) === 'Error'
372
+ ? 'error'
373
+ : 'errors',
374
+ value: error,
375
+ bringIntoFocus: false
376
+ // schemaContent, schemaState
377
+ });
378
+ });
379
+ return div;
380
+ })()
381
+ /* istanbul ignore next -- Just a guard */
382
+ : '')
383
+ ]]
384
+ ]]
385
+ ]]
386
+ : ''
387
+ ]
388
+ ]);
389
+ },
390
+ editUI ({
391
+ typeNamespace,
392
+
393
+ // Pass these to `errors` array
394
+ buildTypeChoices,
395
+ format,
396
+ topRoot,
397
+ bringIntoFocus,
398
+
399
+ value = {
400
+ message: '',
401
+ name: '',
402
+ fileName: '',
403
+ lineNumber: '',
404
+ columnNumber: '',
405
+ stack: '',
406
+ cause: undefined,
407
+ errors: undefined
408
+ }
409
+ }) {
410
+ /**
411
+ * @param {Event} e
412
+ * @this {HTMLInputElement}
413
+ * @returns {void}
414
+ */
415
+ const click = function (e) {
416
+ /** @type {HTMLElement} */ (
417
+ /** @type {HTMLElement} */ (
418
+ this.parentNode
419
+ ).nextElementSibling
420
+ // eslint-disable-next-line @stylistic/space-unary-ops -- TS
421
+ ).hidden = !
422
+ /** @type {HTMLInputElement} */
423
+ (e.target).checked;
424
+ };
425
+ // eslint-disable-next-line consistent-this -- Clearer
426
+ const component = this;
427
+
428
+ if (typeof value.cause === 'object') {
429
+ setTimeout(() => {
430
+ /** @type {HTMLElement} */ ($e(
431
+ div, '.cause'
432
+ )).click();
433
+ });
434
+ }
435
+
436
+ if (Array.isArray(value.errors)) {
437
+ setTimeout(() => {
438
+ /** @type {HTMLElement} */ ($e(
439
+ div, 'input.aggregateErrors'
440
+ )).click();
441
+ });
442
+ }
443
+
444
+ const div = /** @type {HTMLDivElement} */ (jml(
445
+ 'div',
446
+ {dataset: {type: 'errors'}},
447
+ /** @type {import('jamilih').JamilihChildren} */ ([
448
+ ['div', [
449
+ ['label', [
450
+ 'Special error type ',
451
+ ['select', {
452
+ class: 'errorType',
453
+ $custom: {
454
+ /**
455
+ * @this {HTMLSelectElement}
456
+ */
457
+ $hideAggregateErrorsLabel () {
458
+ const aggregateErrorsLabel =
459
+ /** @type {HTMLLabelElement} */ ($e(
460
+ /** @type {Element} */
461
+ (this.parentElement?.closest('div[data-type=errors]')),
462
+ 'label.aggregateErrors'
463
+ ));
464
+ aggregateErrorsLabel.hidden =
465
+ /** @type {HTMLSelectElement} */ (
466
+ this
467
+ ).value !== 'AggregateError';
468
+ }
469
+ },
470
+ $on: {
471
+ /**
472
+ * @this {HTMLSelectElement & {
473
+ * $hideAggregateErrorsLabel: () => void
474
+ * }}
475
+ */
476
+ change () {
477
+ this.$hideAggregateErrorsLabel();
478
+ }
479
+ }
480
+ }, [
481
+ ['option', {value: ''}, ['Select an error type']],
482
+ ...specialErrors.map((errorType) => {
483
+ return ['option', {
484
+ selected: errorType === getConstructor(value.constructor)
485
+ ? 'selected'
486
+ : undefined
487
+ }, [
488
+ errorType
489
+ ]];
490
+ })
491
+ ]]
492
+ ]],
493
+ ['br'],
494
+ ['label', [
495
+ 'Message? ',
496
+ ['input', {
497
+ class: 'message',
498
+ type: 'checkbox', checked: typeof value.message === 'string',
499
+ $on: {
500
+ click
501
+ }
502
+ }]
503
+ ]],
504
+ ' ',
505
+ ['label', {
506
+ hidden: typeof value.message !== 'string'
507
+ }, [
508
+ 'Message ',
509
+ ['input', {
510
+ class: 'message',
511
+ name: `${typeNamespace}-errors-message`,
512
+ value: value.message
513
+ }]
514
+ ]]
515
+ ]],
516
+ ['div', [
517
+ ['label', [
518
+ 'Name? ',
519
+ ['input', {
520
+ class: 'name',
521
+ type: 'checkbox', checked: typeof value.name === 'string',
522
+ $on: {
523
+ click
524
+ }
525
+ }]
526
+ ]],
527
+ ' ',
528
+ ['label', {
529
+ hidden: typeof value.name !== 'string'
530
+ }, [
531
+ 'Name ',
532
+ ['input', {
533
+ class: 'name',
534
+ name: `${typeNamespace}-errors-name`,
535
+ value: value.name
536
+ }]
537
+ ]]
538
+ ]],
539
+ ['br'],
540
+ ['div', [
541
+ ['label', [
542
+ 'File name? ',
543
+ ['input', {
544
+ class: 'fileName',
545
+ type: 'checkbox', checked: typeof value.fileName === 'string',
546
+ $on: {
547
+ click
548
+ }
549
+ }]
550
+ ]],
551
+ ' ',
552
+ ['label', {
553
+ hidden: typeof value.fileName !== 'string'
554
+ }, [
555
+ 'File name ',
556
+ ['input', {
557
+ class: 'fileName',
558
+ name: `${typeNamespace}-errors-fileName`,
559
+ value: value.fileName
560
+ }]
561
+ ]]
562
+ ]],
563
+ ['label', [
564
+ 'Line number ',
565
+ ['input', {
566
+ class: 'lineNumber',
567
+ name: `${typeNamespace}-errors-lineNumber`,
568
+ type: 'number', step: 'any', value: value.lineNumber
569
+ }]
570
+ ]],
571
+ ['br'],
572
+ ['label', [
573
+ 'Column number ',
574
+ ['input', {
575
+ class: 'columnNumber',
576
+ name: `${typeNamespace}-errors-columnNumber`,
577
+ type: 'number', step: 'any', value: value.columnNumber
578
+ }]
579
+ ]],
580
+ ['div', [
581
+ ['label', [
582
+ 'Stack? ',
583
+ ['input', {
584
+ class: 'stack',
585
+ type: 'checkbox', checked: typeof value.stack === 'string',
586
+ $on: {
587
+ click
588
+ }
589
+ }]
590
+ ]],
591
+ ['label', {
592
+ hidden: typeof value.stack !== 'string'
593
+ }, [
594
+ 'Stack ',
595
+ ['textarea', {
596
+ class: 'stack',
597
+ name: `${typeNamespace}-errors-stack`
598
+ }, [
599
+ value.stack ?? ''
600
+ ]]
601
+ ]]
602
+ ]],
603
+ ['label', [
604
+ 'Cause? ',
605
+ ['input', {
606
+ class: 'cause',
607
+ type: 'checkbox',
608
+ $on: {
609
+ click (e) {
610
+ click.call(/** @type {HTMLInputElement} */ (this), e);
611
+ const causeHolder = /** @type {Element} */ (
612
+ /** @type {Element} */ (
613
+ this.parentElement
614
+ ).nextElementSibling
615
+ );
616
+ const causeContents = $e(causeHolder, '.causeContents');
617
+ if (!causeContents?.children.length) {
618
+ const editui = component.editUI({
619
+ typeNamespace,
620
+ value: value.cause
621
+ });
622
+ jml(...editui, causeContents);
623
+ }
624
+ }
625
+ }
626
+ }]
627
+ ]],
628
+ ['div', {class: 'causeHolder', hidden: true}, [
629
+ ['label', ['Cause ']],
630
+ ['button', {$on: {click (/** @type {Event} */ e) {
631
+ e.preventDefault();
632
+ const {target} = e;
633
+ const causeContents = /** @type {HTMLDivElement} */ ($e(
634
+ /** @type {HTMLElement} */
635
+ (/** @type {HTMLElement} */ (target).closest('.causeHolder')),
636
+ '.causeContents'
637
+ ));
638
+ causeContents.hidden = !causeContents.hidden;
639
+ /** @type {HTMLElement} */ (
640
+ target
641
+ ).textContent = causeContents.hidden ? '+' : '-';
642
+ }}}, ['-']],
643
+ ['div', {class: 'causeContents'}]
644
+ ]],
645
+ ['br'],
646
+ ['label', {class: 'aggregateErrors'}, {
647
+ hidden: !value.errors
648
+ }, [
649
+ 'Aggregate errors? ',
650
+ ['input', {
651
+ class: 'aggregateErrors',
652
+ type: 'checkbox',
653
+ $custom: {
654
+ /**
655
+ * @this {HTMLInputElement}
656
+ */
657
+ $emptyAggregateErrorsContents () {
658
+ const aggregateErrorsHolder = /** @type {Element} */ (
659
+ /** @type {Element} */ (
660
+ this.parentElement
661
+ ).nextElementSibling
662
+ );
663
+ const aggregateErrorsContents = $e(
664
+ aggregateErrorsHolder, '.aggregateErrorsContents'
665
+ );
666
+ while (aggregateErrorsContents?.firstChild) {
667
+ aggregateErrorsContents?.firstChild.remove();
668
+ }
669
+ },
670
+
671
+ /**
672
+ * @param {Error[]} errors
673
+ * @this {HTMLInputElement}
674
+ */
675
+ $populateContents (errors) {
676
+ const aggregateErrorsHolder = /** @type {Element} */ (
677
+ /** @type {Element} */ (
678
+ this.parentElement
679
+ ).nextElementSibling
680
+ );
681
+ const aggregateErrorsContents = $e(
682
+ aggregateErrorsHolder, '.aggregateErrorsContents'
683
+ );
684
+ if (!aggregateErrorsContents?.children.length) {
685
+ const [editui] = arrayType.editUI({
686
+ typeNamespace, buildTypeChoices, format,
687
+ type: 'array',
688
+ topRoot, bringIntoFocus,
689
+ arrayState: 'errorsArray',
690
+ value: []
691
+ });
692
+
693
+ errors.forEach((error, idx) => {
694
+ /**
695
+ * @type {HTMLDivElement & {
696
+ * $addAndSetArrayElement:
697
+ * import('../formats/structuredCloning.js').
698
+ * AddAndSetArrayElement
699
+ * }}
700
+ */
701
+ (editui).$addAndSetArrayElement({
702
+ propName: String(idx),
703
+ type: getConstructor(error.constructor) === 'Error'
704
+ ? 'error'
705
+ : 'errors',
706
+ value: error,
707
+ bringIntoFocus: false,
708
+ setAValue: true
709
+ // schemaContent, schemaState
710
+ });
711
+ });
712
+
713
+ jml(editui, aggregateErrorsContents);
714
+ }
715
+ }
716
+ },
717
+ $on: {
718
+ click (e) {
719
+ click.call(/** @type {HTMLInputElement} */ (this), e);
720
+ const that =
721
+ /**
722
+ * @type {HTMLInputElement & {
723
+ * $populateContents: (errs: unknown[]) => void
724
+ * }}
725
+ */
726
+ (this);
727
+ if (value.errors) {
728
+ (that).$populateContents(value.errors);
729
+ } else {
730
+ (that).$populateContents([
731
+ {
732
+ message: '',
733
+ name: '',
734
+ stack: ''
735
+ }
736
+ ]);
737
+ }
738
+ }
739
+ }
740
+ }]
741
+ ]],
742
+ ['div', {class: 'aggregateErrorsHolder', hidden: true}, [
743
+ ['label', ['Aggregate errors ']],
744
+ ['button', {$on: {click (/** @type {Event} */ e) {
745
+ e.preventDefault();
746
+ const {target} = e;
747
+ const aggregateErrorsContents = /** @type {HTMLDivElement} */ ($e(
748
+ /** @type {HTMLElement} */
749
+ (/** @type {HTMLElement} */ (
750
+ target
751
+ ).closest('.aggregateErrorsHolder')),
752
+ '.aggregateErrorsContents'
753
+ ));
754
+ aggregateErrorsContents.hidden = !aggregateErrorsContents.hidden;
755
+ /** @type {HTMLElement} */ (
756
+ target
757
+ ).textContent = aggregateErrorsContents.hidden ? '+' : '-';
758
+ }}}, ['-']],
759
+ ['div', {class: 'aggregateErrorsContents'}]
760
+ ]]
761
+ ])
762
+ ));
763
+
764
+ return [div];
765
+ }
766
+ };
767
+
768
+ export default errorsSpecialType;