@es-joy/jsoe 0.14.0 → 0.15.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.
@@ -0,0 +1,1455 @@
1
+ import {$e, $$e} from '../utils/templateUtils.js';
2
+ import {jml, toStringTag} from '../vendor-imports.js';
3
+ import dialogs from '../utils/dialogs.js';
4
+
5
+ const dataViewMethods = /** @type {const} */ ([
6
+ 'setInt8',
7
+ 'setUint8',
8
+ 'setInt16',
9
+ 'setUint16',
10
+ 'setInt32',
11
+ 'setUint32',
12
+ 'setFloat32',
13
+ 'setFloat64',
14
+ 'setBigInt64',
15
+ 'setBigUint64'
16
+ ]);
17
+
18
+ const typedArrays = /** @type {const} */ ([
19
+ 'Int8Array', 'Uint8Array', 'Uint8ClampedArray', 'Int16Array',
20
+ 'Uint16Array', 'Int32Array', 'Uint32Array', 'Float32Array',
21
+ 'Float64Array', 'BigInt64Array', 'BigUint64Array'
22
+ ]);
23
+
24
+ /**
25
+ * @param {TypedArray} typedArray
26
+ * @returns {{min: number, max: number}}
27
+ */
28
+ const getMinMaxForTypedArray = (typedArray) => {
29
+ switch (typedArray) {
30
+ case 'Int8Array':
31
+ return {min: -128, max: 127};
32
+ case 'Uint8Array':
33
+ return {min: 0, max: 255};
34
+ case 'Uint8ClampedArray':
35
+ return {min: 0, max: 255};
36
+ case 'Int16Array':
37
+ return {min: -32768, max: 32767};
38
+ case 'Uint16Array':
39
+ return {min: 0, max: 65535};
40
+ case 'Int32Array':
41
+ return {min: -2147483648, max: 2147483647};
42
+ case 'Uint32Array':
43
+ return {min: 0, max: 4294967295};
44
+ case 'Float32Array':
45
+ return {min: -3.4e38, max: 3.4e38};
46
+ case 'Float64Array':
47
+ // eslint-disable-next-line no-loss-of-precision -- Inevitable?
48
+ return {min: -1.8e308, max: 1.8e308};
49
+ case 'BigInt64Array':
50
+ return {min: -(2 ** 63), max: (2 ** 63) - 1};
51
+ case 'BigUint64Array':
52
+ return {min: 0, max: (2 ** 64) - 1};
53
+ /* istanbul ignore next -- Guard */
54
+ default:
55
+ /* istanbul ignore next -- Guard */
56
+ throw new Error('Unexpected typed array type');
57
+ }
58
+ };
59
+
60
+ /**
61
+ * @typedef {"Int8Array"|"Uint8Array"|"Uint8ClampedArray"|
62
+ * "Int16Array"|"Uint16Array"|"Int32Array"|"Uint32Array"|
63
+ * "Float32Array"|"Float64Array"|"BigInt64Array"|
64
+ * "BigUint64Array"} TypedArray
65
+ */
66
+
67
+ /**
68
+ * @typedef {Int8Array|Uint8Array|Uint8ClampedArray|
69
+ * Int16Array|Uint16Array|Int32Array|Uint32Array|
70
+ * Float32Array|Float64Array|BigInt64Array|
71
+ * BigUint64Array} TypedArrayInstance
72
+ */
73
+
74
+ /**
75
+ * @param {TypedArray} prop
76
+ * @returns {Int8ArrayConstructor|Uint8ArrayConstructor|
77
+ * Uint8ClampedArrayConstructor|Int16ArrayConstructor|
78
+ * Uint16ArrayConstructor|Int32ArrayConstructor|Uint32ArrayConstructor|
79
+ * Float32ArrayConstructor|Float64ArrayConstructor|
80
+ * BigInt64ArrayConstructor|BigUint64ArrayConstructor}
81
+ */
82
+ const getTypedArray = (prop) => {
83
+ switch (prop) {
84
+ case 'Int8Array':
85
+ return Int8Array;
86
+ case 'Uint8Array':
87
+ return Uint8Array;
88
+ case 'Uint8ClampedArray':
89
+ return Uint8ClampedArray;
90
+ case 'Int16Array':
91
+ return Int16Array;
92
+ case 'Uint16Array':
93
+ return Uint16Array;
94
+ case 'Int32Array':
95
+ return Int32Array;
96
+ case 'Uint32Array':
97
+ return Uint32Array;
98
+ case 'Float32Array':
99
+ return Float32Array;
100
+ case 'Float64Array':
101
+ return Float64Array;
102
+ case 'BigInt64Array':
103
+ return BigInt64Array;
104
+ case 'BigUint64Array':
105
+ return BigUint64Array;
106
+ /* istanbul ignore next -- Guard */
107
+ default:
108
+ /* istanbul ignore next -- Guard */
109
+ throw new Error('Unexpected type');
110
+ }
111
+ };
112
+
113
+ let idx = 0;
114
+
115
+ /**
116
+ * @type {import('../types.js').SuperTypeObject}
117
+ */
118
+ const buffersourceType = {
119
+ option: ['Buffer source (ArrayBuffer, DataView, TypedArrays)'],
120
+ childTypes: [
121
+ 'arraybuffer',
122
+ 'dataview',
123
+ 'int8array', 'uint8array', 'uint8clampedarray', 'int16array',
124
+ 'uint16array', 'int32array', 'uint32array', 'float32array',
125
+ 'float64array', 'bigint64array', 'biguint64array'
126
+ ],
127
+ stringRegex: /^(?<bufferSourceClass>ArrayBuffer|DataView|(?:Int8|Uint8|Uint8Clamped|Int16|Uint16|Int32|Uint32|Float32|Float64|BigInt64|BigUint64)Array)\((?<innerContent>.*)\)$/u,
128
+ toValue (s, rootInfo) {
129
+ const {groups: {
130
+ bufferSourceClass
131
+ /* istanbul ignore next -- Should always be found */
132
+ } = {}} = /** @type {RegExpMatchArray} */ (
133
+ /** @type {import('../types.js').RootInfo} */ (rootInfo).match
134
+ );
135
+
136
+ const o = JSON.parse(s);
137
+ const {
138
+ byteLength, maxByteLength, byteOffset,
139
+ dataViewByteOffset,
140
+ dataViewByteLength, length
141
+ } = o;
142
+ // @ts-expect-error Ok
143
+ const buffer = new ArrayBuffer(byteLength, {maxByteLength});
144
+
145
+ let typedArray, TypedArray;
146
+ if (bufferSourceClass.endsWith('Array') || 'typedArray' in o) {
147
+ TypedArray = getTypedArray(
148
+ /** @type {TypedArray} */ (o.typedArray ?? bufferSourceClass)
149
+ );
150
+
151
+ typedArray = new TypedArray(buffer, byteOffset, length);
152
+
153
+ if ('set' in o) {
154
+ o.set[0].forEach(
155
+ /**
156
+ * @param {string} s
157
+ * @param {number} i
158
+ * @returns {void}
159
+ */
160
+ (s, i) => {
161
+ if (typeof s === 'string') {
162
+ o.set[0][i] = BigInt(s);
163
+ }
164
+ }
165
+ );
166
+ typedArray.set(...(
167
+ /**
168
+ * @type {[
169
+ * array: Array<bigint> & Array<number>,
170
+ * offset?: number | undefined
171
+ * ]}
172
+ */ (o.set)));
173
+ }
174
+ }
175
+
176
+ /** @type {DataView|undefined} */
177
+ let view;
178
+ if (bufferSourceClass === 'DataView' || dataViewMethods.some((method) => {
179
+ return method in o;
180
+ })) {
181
+ view = new DataView(buffer, dataViewByteOffset, dataViewByteLength);
182
+ dataViewMethods.forEach((prop) => {
183
+ o[prop]?.forEach(
184
+ /**
185
+ * @type {(info: [
186
+ * byteOffset: number,
187
+ * value: bigint|number,
188
+ * littleEndian?: boolean|undefined
189
+ * ]) => void}
190
+ */
191
+ (vals) => {
192
+ if (typeof vals[1] === 'string') {
193
+ vals[1] = BigInt(vals[1]);
194
+ }
195
+ // @ts-expect-error It's ok
196
+ view[prop](...vals);
197
+ }
198
+ );
199
+ });
200
+ }
201
+ return {
202
+ value: bufferSourceClass === 'ArrayBuffer'
203
+ ? buffer
204
+ : bufferSourceClass === 'DataView'
205
+ ? view
206
+ : typedArray
207
+ };
208
+ },
209
+ getInput ({root}) {
210
+ const byteLength =
211
+ /**
212
+ * @type {HTMLInputElement & {
213
+ * $value: BufferSource
214
+ * }}
215
+ */ ($e(root, '.byteLength'));
216
+ return byteLength;
217
+ },
218
+ setValue ({root, value}) {
219
+ const stringTag = toStringTag(value);
220
+ if (stringTag === 'ArrayBuffer' || stringTag === 'DataView') {
221
+ $e(root, `[value=${stringTag}].buffersource-returnType`)?.click();
222
+ } else {
223
+ $e(root, `[value=TypedArray].buffersource-returnType`)?.click();
224
+ const typedArrays = /** @type {HTMLSelectElement} */ (
225
+ $e(root, '.buffersource-typedArrays')
226
+ );
227
+ typedArrays.value = stringTag;
228
+ typedArrays.dispatchEvent(new Event('change'));
229
+ }
230
+
231
+ const byteLength =
232
+ /**
233
+ * @type {HTMLInputElement & {
234
+ * $value: BufferSource
235
+ * }}
236
+ */ ($e(root, '.byteLength'));
237
+
238
+ byteLength.$value = value;
239
+
240
+ const buffer = stringTag === 'ArrayBuffer' ? value : value.buffer;
241
+ byteLength.value = buffer.byteLength;
242
+ byteLength.dispatchEvent(new Event('change'));
243
+
244
+ const maxByteLength = /** @type {HTMLInputElement} */ (
245
+ $e(root, '.maxByteLength')
246
+ );
247
+ maxByteLength.value = buffer.maxByteLength;
248
+ maxByteLength.dispatchEvent(new Event('change'));
249
+
250
+ if (stringTag === 'DataView') {
251
+ const dataViewByteLength = /** @type {HTMLInputElement} */ (
252
+ $e(root, '.dataViewByteLength')
253
+ );
254
+ dataViewByteLength.value = value.byteLength;
255
+ dataViewByteLength.dispatchEvent(new Event('change'));
256
+
257
+ const dataViewByteOffset = /** @type {HTMLInputElement} */ (
258
+ $e(root, '.dataViewByteOffset')
259
+ );
260
+ dataViewByteOffset.value = value.byteOffset;
261
+ dataViewByteOffset.dispatchEvent(new Event('change'));
262
+ } else if (stringTag !== 'ArrayBuffer') { // TypedArray
263
+ const typedArrayByteOffset = /** @type {HTMLInputElement} */ (
264
+ $e(root, '.typedArrayByteOffset')
265
+ );
266
+ typedArrayByteOffset.value = value.byteOffset;
267
+ typedArrayByteOffset.dispatchEvent(new Event('change'));
268
+
269
+ const typedArrayLength = /** @type {HTMLInputElement} */ (
270
+ $e(root, '.typedArrayLength')
271
+ );
272
+ typedArrayLength.value = value.length;
273
+ typedArrayLength.dispatchEvent(new Event('change'));
274
+ }
275
+ },
276
+ getValue ({root}) {
277
+ return /** @type {HTMLInputElement & {$value: BufferSource}} */ (
278
+ this.getInput({root})
279
+ ).$value;
280
+ },
281
+ viewUI ({value}) {
282
+ const stringTag = toStringTag(value);
283
+ const buffer = stringTag === 'ArrayBuffer' ? value : value.buffer;
284
+
285
+ return ['div', {dataset: {type: 'buffersource'}}, [
286
+ ['b', {class: 'emphasis'}, [stringTag]],
287
+ ['br'],
288
+ ['b', ['Buffer byte length: ']],
289
+ buffer.byteLength,
290
+ ['br'],
291
+ ['b', ['Buffer max byte length: ']],
292
+ buffer.maxByteLength,
293
+
294
+ ...stringTag === 'DataView'
295
+ ? [
296
+ ['br'],
297
+ ['b', ['Data View byte length: ']],
298
+ value.byteLength,
299
+ ['br'],
300
+ ['b', ['Data View byte offset: ']],
301
+ value.byteOffset
302
+ ]
303
+ : [''],
304
+ ...(stringTag !== 'DataView' && stringTag !== 'ArrayBuffer') // TypedArray
305
+ ? [
306
+ ['br'],
307
+ ['b', ['Typed Array byte offset: ']],
308
+ value.byteOffset,
309
+ ['br'],
310
+ ['b', ['Typed Array length: ']],
311
+ value.length
312
+ ]
313
+ : [''],
314
+ ['br'],
315
+ ['button', {
316
+ class: 'buffersource-viewData',
317
+ $on: {
318
+ async click (e) {
319
+ e.preventDefault();
320
+ const dialog = await dialogs.makeCancelDialog({
321
+ // @ts-expect-error TS bug
322
+ children: /** @type {import('jamilih').JamilihChildren} */ ([
323
+ ['select', {
324
+ class: 'buffersource-typedArrays-view',
325
+ 'aria-label': 'Typed Arrays',
326
+ $on: {
327
+ change () {
328
+ const typedArrayVal = /** @type {HTMLSelectElement} */ (
329
+ this
330
+ ).value;
331
+ const TypedArray = getTypedArray(
332
+ /** @type {TypedArray} */ (typedArrayVal)
333
+ );
334
+ const typedArray = new TypedArray(buffer);
335
+ const typedArrayArea = /** @type {HTMLElement} */ ($e(
336
+ /** @type {HTMLElement} */
337
+ (this.parentElement),
338
+ '.typedArrayArea'
339
+ ));
340
+ typedArrayArea.textContent = '';
341
+ typedArrayArea.append(
342
+ ...Array.from({
343
+ length: typedArray.length
344
+ }, (_v, key) => {
345
+ return jml('span', [
346
+ ['b', [key]],
347
+ ' ',
348
+ ['span', [
349
+ typedArray[key]
350
+ ? String(typedArray[key])
351
+ : '0'
352
+ ]],
353
+ ' '
354
+ ]);
355
+ })
356
+ );
357
+ }
358
+ }
359
+ }, typedArrays.map((typedArray) => {
360
+ return ['option', {
361
+ selected: stringTag === typedArray
362
+ ? true
363
+ : undefined
364
+ }, [typedArray]];
365
+ })],
366
+ ['div', {
367
+ class: 'typedArrayArea'
368
+ }]
369
+ ])
370
+ });
371
+
372
+ /** @type {HTMLSelectElement} */ (
373
+ $e(dialog, '.buffersource-typedArrays-view')
374
+ ).dispatchEvent(
375
+ new Event('change')
376
+ );
377
+ // Todo: We could also add `DataView` get methods here
378
+ // (and length/byte offset for the typed array) if
379
+ // there is a demand
380
+ }
381
+ }
382
+ }, ['View data']]
383
+ ]];
384
+ },
385
+ editUI ({typeNamespace, value}) {
386
+ idx++;
387
+
388
+ /**
389
+ * @typedef {() => void} BuildInstances
390
+ */
391
+
392
+ const div = /** @type {HTMLDivElement} */ (jml('div', {
393
+ dataset: {type: 'buffersource'}
394
+ }, [
395
+ ['fieldset', {
396
+ class: 'returnType',
397
+ $on: {
398
+ change () {
399
+ /**
400
+ * @type {HTMLFieldSetElement & {
401
+ * $buildInstances: BuildInstances
402
+ * }}
403
+ */ (this).$buildInstances();
404
+ }
405
+ },
406
+ $custom: {
407
+ /** @type {BuildInstances} */
408
+ $buildInstances () {
409
+ const that = /** @type {HTMLFieldSetElement} */ (this);
410
+ const ancestor = /** @type {HTMLDivElement} */ (that.parentElement);
411
+ const {value} = /** @type {HTMLInputElement} */ ($e(
412
+ that, `[name=${typeNamespace}-buffersource-returnType-${idx}]` +
413
+ `:checked`
414
+ ));
415
+
416
+ const byteLength =
417
+ /**
418
+ * @type {HTMLInputElement & {
419
+ * $value: BufferSource,
420
+ * $dataView: DataView,
421
+ * $typedArray: TypedArrayInstance
422
+ * }}
423
+ */ (
424
+ $e(ancestor, '.byteLength')
425
+ );
426
+ const byteLengthVal = Number.parseInt(byteLength.value);
427
+ const maxByteLength = Number.parseInt(
428
+ /** @type {HTMLInputElement} */ (
429
+ $e(ancestor, '.maxByteLength')
430
+ ).value
431
+ );
432
+
433
+ const buffer = new ArrayBuffer(
434
+ // @ts-expect-error New ArrayBuffer argument
435
+ byteLengthVal, maxByteLength ? {maxByteLength} : undefined
436
+ );
437
+
438
+ const dataViewByteOffsetVal = /** @type {HTMLInputElement} */ ($e(
439
+ ancestor,
440
+ '.dataViewByteOffset'
441
+ )).value;
442
+ const dataViewByteOffset = dataViewByteOffsetVal
443
+ ? Number.parseInt(dataViewByteOffsetVal)
444
+ : 0;
445
+
446
+ const dataViewByteLengthVal = /** @type {HTMLInputElement} */ ($e(
447
+ ancestor,
448
+ '.dataViewByteLength'
449
+ )).value;
450
+ const dataViewByteLength = dataViewByteLengthVal
451
+ ? Number.parseInt(dataViewByteLengthVal)
452
+ : undefined;
453
+
454
+ const dataView = new DataView(
455
+ buffer, dataViewByteOffset, dataViewByteLength
456
+ );
457
+
458
+ const {value: typedArrayValue} = /** @type {HTMLSelectElement} */ (
459
+ $e(ancestor, '.buffersource-typedArrays-init')
460
+ );
461
+
462
+ const TypedArray = getTypedArray(
463
+ /** @type {TypedArray} */ (typedArrayValue)
464
+ );
465
+ const typedArrayByteOffsetVal =
466
+ /** @type {HTMLInputElement} */ ($e(
467
+ ancestor,
468
+ '.typedArrayByteOffset'
469
+ )).value;
470
+ const typedArrayByteOffset = typedArrayByteOffsetVal
471
+ ? Number.parseInt(typedArrayByteOffsetVal)
472
+ : 0;
473
+
474
+ const typedArrayLengthVal =
475
+ /** @type {HTMLInputElement} */ ($e(
476
+ ancestor,
477
+ '.typedArrayLength'
478
+ )).value;
479
+ const typedArrayLength = typedArrayLengthVal
480
+ ? Number.parseInt(typedArrayLengthVal)
481
+ : byteLengthVal;
482
+
483
+ const typedArray = new TypedArray(
484
+ buffer, typedArrayByteOffset, typedArrayLength
485
+ );
486
+
487
+ byteLength.$dataView = dataView;
488
+ byteLength.$typedArray = typedArray;
489
+
490
+ const typedArrayValues = $$e(
491
+ ancestor, '.typedArrayArea .typedArrayValue'
492
+ ).map((input) => {
493
+ // Don't check dataset, as may be changing to BigInt now
494
+ return TypedArray.name.startsWith('Big')
495
+ ? BigInt(
496
+ /** @type {HTMLInputElement} */ (input).value
497
+ )
498
+ : Number(
499
+ /** @type {HTMLInputElement} */ (input).value
500
+ );
501
+ });
502
+
503
+ // @ts-expect-error Ok
504
+ byteLength.$typedArray.set(typedArrayValues, 0);
505
+
506
+ switch (value) {
507
+ case 'ArrayBuffer':
508
+ byteLength.$value = buffer;
509
+ break;
510
+ case 'DataView': {
511
+ byteLength.$value = dataView;
512
+ break;
513
+ } default: // 'TypedArray'
514
+ byteLength.$value = typedArray;
515
+ break;
516
+ }
517
+ }
518
+ }
519
+ }, [
520
+ ['legend', ['Return type']],
521
+ ['label', {
522
+ $on: {
523
+ click () {
524
+ /** @type {HTMLElement} */ ($e(
525
+ /** @type {HTMLElement} */ (this.parentElement),
526
+ '.buffersource-typedArrays'
527
+ )).hidden = true;
528
+ /** @type {HTMLElement} */ ($e(
529
+ /** @type {HTMLElement} */ (this?.parentElement?.parentElement),
530
+ '.buffersource-typedArrays-init'
531
+ )).hidden = false;
532
+ }
533
+ }
534
+ }, [
535
+ ['input', {
536
+ type: 'radio',
537
+ class: 'buffersource-returnType ' +
538
+ 'buffersource-returnType-arraybuffer',
539
+ name: `${typeNamespace}-buffersource-returnType-${idx}`,
540
+ checked: true,
541
+ value: 'ArrayBuffer'
542
+ // checked: toStringTag(value) !== ''
543
+ }],
544
+ 'ArrayBuffer'
545
+ ]],
546
+ ' ',
547
+ ['label', {
548
+ $on: {
549
+ click () {
550
+ /** @type {HTMLElement} */ ($e(
551
+ /** @type {HTMLElement} */ (this.parentElement),
552
+ '.buffersource-typedArrays'
553
+ )).hidden = true;
554
+ /** @type {HTMLElement} */ ($e(
555
+ /** @type {HTMLElement} */ (this?.parentElement?.parentElement),
556
+ '.buffersource-typedArrays-init'
557
+ )).hidden = false;
558
+ }
559
+ }
560
+ }, [
561
+ ['input', {
562
+ type: 'radio',
563
+ class: 'buffersource-returnType buffersource-returnType-dataview',
564
+ name: `${typeNamespace}-buffersource-returnType-${idx}`,
565
+ value: 'DataView'
566
+ // checked: toStringTag(value) !== ''
567
+ }],
568
+ 'DataView'
569
+ ]],
570
+ ' ',
571
+ ['label', {
572
+ $on: {
573
+ click () {
574
+ /** @type {HTMLElement} */ ($e(
575
+ /** @type {HTMLElement} */ (this.parentElement),
576
+ '.buffersource-typedArrays'
577
+ )).hidden = false;
578
+ /** @type {HTMLElement} */ ($e(
579
+ /** @type {HTMLElement} */ (this?.parentElement?.parentElement),
580
+ '.buffersource-typedArrays-init'
581
+ )).hidden = true;
582
+ }
583
+ }
584
+ }, [
585
+ ['input', {
586
+ type: 'radio',
587
+ class: 'buffersource-returnType buffersource-returnType-typedarray',
588
+ name: `${typeNamespace}-buffersource-returnType-${idx}`,
589
+ value: 'TypedArray'
590
+ // checked: toStringTag(value) !== ''
591
+ }],
592
+ 'Typed Array'
593
+ ]],
594
+ ' ',
595
+ ['select', {
596
+ hidden: true, class: 'buffersource-typedArrays',
597
+ 'aria-label': 'Typed Arrays',
598
+ $on: {
599
+ change (e) {
600
+ const that = /** @type {HTMLSelectElement} */ (this);
601
+ const ancestor = /** @type {HTMLElement} */ (
602
+ that.parentElement?.parentElement
603
+ );
604
+
605
+ const select =
606
+ /**
607
+ * @type {HTMLSelectElement & {
608
+ * $setMinsAndMaxes: SetMinsAndMaxes,
609
+ * $checkTypedArrayByteLength: CheckTypedArrayByteLength
610
+ * }}
611
+ */
612
+ ($e(
613
+ ancestor,
614
+ '.buffersource-typedArrays-init'
615
+ ));
616
+
617
+ // Update to reflect current state changes if later revealing
618
+ select.value = /** @type {HTMLSelectElement} */ (this).value;
619
+
620
+ const typedArrayLength =
621
+ /**
622
+ * @type {HTMLInputElement & {
623
+ * $checkBufferBounds: CheckBufferBounds
624
+ * }}
625
+ */ (
626
+ $e(ancestor, '.typedArrayLength')
627
+ );
628
+ if (!typedArrayLength.$checkBufferBounds(e)) {
629
+ return;
630
+ }
631
+
632
+ select.$setMinsAndMaxes(
633
+ /** @type {TypedArray} */
634
+ (/** @type {HTMLSelectElement} */ (this).value)
635
+ );
636
+
637
+ select.$checkTypedArrayByteLength(e);
638
+
639
+ const typedArrayByteOffset = $e(
640
+ /** @type {HTMLElement} */
641
+ (this?.parentElement?.parentElement),
642
+ '.typedArrayByteOffset'
643
+ );
644
+ /**
645
+ * @type {HTMLInputElement & {
646
+ * $checkByteOffsetMultiple: CheckByteOffsetMultiple
647
+ * }}
648
+ */ (typedArrayByteOffset).$checkByteOffsetMultiple(e);
649
+ }
650
+ }
651
+ }, typedArrays.map((typedArray) => {
652
+ return ['option', [typedArray]];
653
+ })]
654
+ ]],
655
+ ['fieldset', {
656
+ $on: {
657
+ change () {
658
+ /**
659
+ * @type {HTMLFieldSetElement & {
660
+ * $buildInstances: BuildInstances
661
+ * }}
662
+ */ (this.previousElementSibling).$buildInstances();
663
+ }
664
+ }
665
+ }, [
666
+ ['legend', ['Construction options']],
667
+ ['fieldset', [
668
+ ['legend', ['ArrayBuffer']],
669
+ ['label', [
670
+ 'Byte length ',
671
+ ['input', {
672
+ class: 'byteLength',
673
+ type: 'number', step: '1', size: '4', pattern: '\\d+',
674
+ min: 0,
675
+ $custom: {
676
+ $value: value ?? new ArrayBuffer(0)
677
+ },
678
+ $on: {
679
+ change (e) {
680
+ const that = /** @type {HTMLInputElement} */ (
681
+ this
682
+ );
683
+
684
+ const ancestor = /** @type {HTMLElement} */ (
685
+ that.
686
+ parentElement?.parentElement?.parentElement?.parentElement
687
+ );
688
+ const typedArrayLength =
689
+ /**
690
+ * @type {HTMLInputElement & {
691
+ * $checkBufferBounds: CheckBufferBounds
692
+ * }}
693
+ */ (
694
+ $e(ancestor, '.typedArrayLength')
695
+ );
696
+ if (!typedArrayLength.$checkBufferBounds(e)) {
697
+ return;
698
+ }
699
+
700
+ const maxByteLength = /** @type {HTMLInputElement} */ ($e(
701
+ /** @type {HTMLElement} */ (
702
+ that.parentElement?.parentElement
703
+ ), '.maxByteLength'
704
+ ));
705
+ const val = that.value;
706
+
707
+ if (Number.parseInt(val) > Number.MAX_SAFE_INTEGER) {
708
+ that.setCustomValidity(
709
+ 'The ArrayBuffer length exceeds the maximum ' +
710
+ 'allowable size'
711
+ );
712
+ e.stopPropagation();
713
+ that.reportValidity();
714
+ return;
715
+ }
716
+ that.setCustomValidity('');
717
+ that.reportValidity();
718
+
719
+ if (
720
+ Number.parseInt(val) > Number.parseInt(maxByteLength.value)
721
+ ) {
722
+ maxByteLength.value = val;
723
+ }
724
+
725
+ const greatGrandparent = /** @type {HTMLElement} */
726
+ (that.parentElement?.parentElement?.parentElement);
727
+
728
+ /**
729
+ * @type {HTMLInputElement & {
730
+ * $checkDataViewByteLength: CheckDataViewByteLength
731
+ * }}
732
+ */ ($e(
733
+ greatGrandparent,
734
+ '.dataViewByteLength'
735
+ )).$checkDataViewByteLength(e);
736
+
737
+ /**
738
+ * @type {HTMLSelectElement & {
739
+ * $checkTypedArrayByteLength: CheckTypedArrayByteLength
740
+ * }}
741
+ */ ($e(
742
+ /** @type {HTMLElement} */
743
+ (greatGrandparent.parentElement),
744
+ '.buffersource-typedArrays-init'
745
+ )).$checkTypedArrayByteLength(e);
746
+ }
747
+ }
748
+ }]
749
+ ]],
750
+ ' ',
751
+ ['label', [
752
+ 'Max byte length ',
753
+ ['input', {
754
+ class: 'maxByteLength',
755
+ type: 'number', step: '1', size: '4', pattern: '\\d+',
756
+ min: 0,
757
+ $on: {
758
+ change (e) {
759
+ const that = /** @type {HTMLInputElement} */ (this);
760
+ const byteLength = /** @type {HTMLInputElement} */ ($e(
761
+ /** @type {HTMLElement} */ (
762
+ that.parentElement?.parentElement
763
+ ), '.byteLength'
764
+ ));
765
+ const val = that.value;
766
+ if (
767
+ Number.parseInt(val) < Number.parseInt(byteLength.value)
768
+ ) {
769
+ // byteLength.value = val;
770
+ that.setCustomValidity(
771
+ 'The max value cannot be less than the byte length'
772
+ );
773
+ e.stopPropagation();
774
+ } else {
775
+ that.setCustomValidity('');
776
+ }
777
+ that.reportValidity();
778
+ }
779
+ }
780
+ }]
781
+ ]]
782
+ ]],
783
+ ['fieldset', [
784
+ ['legend', ['DataView']],
785
+ ['label', [
786
+ 'Byte length ',
787
+ ['input', {
788
+ class: 'dataViewByteLength',
789
+ type: 'number', step: '1', size: '4', pattern: '\\d+',
790
+ min: 0,
791
+ $custom: {
792
+ /**
793
+ * @typedef {(e: Event) => void} CheckDataViewByteLength
794
+ */
795
+
796
+ /** @type {CheckDataViewByteLength} */
797
+ $checkDataViewByteLength (e) {
798
+ const that = /** @type {HTMLInputElement} */ (
799
+ this
800
+ );
801
+ const greatGrandparent = /** @type {HTMLElement} */
802
+ (that.parentElement?.parentElement?.parentElement);
803
+
804
+ const byteOffset = Number.parseInt(
805
+ /** @type {HTMLInputElement} */ ($e(
806
+ greatGrandparent,
807
+ '.dataViewByteOffset'
808
+ )).value
809
+ ) || 0;
810
+
811
+ const bufferByteLengthVal = /** @type {HTMLInputElement} */ (
812
+ $e(
813
+ greatGrandparent,
814
+ '.byteLength'
815
+ )).value;
816
+ const bufferByteLength = bufferByteLengthVal
817
+ ? Number.parseInt(
818
+ bufferByteLengthVal
819
+ )
820
+ : 0;
821
+
822
+ const byteLength = that.value
823
+ ? Number.parseInt(
824
+ that.value
825
+ )
826
+ : bufferByteLength;
827
+
828
+ if (byteOffset + byteLength > bufferByteLength) {
829
+ that.setCustomValidity(
830
+ 'The DataView byte length and offset exceed ' +
831
+ 'the buffer\'s byte length'
832
+ );
833
+ e.stopPropagation();
834
+ } else {
835
+ that.setCustomValidity('');
836
+ }
837
+ that.reportValidity();
838
+ }
839
+ },
840
+ $on: {
841
+ change (e) {
842
+ /**
843
+ * @type {HTMLInputElement & {
844
+ * $checkDataViewByteLength: CheckDataViewByteLength
845
+ * }}
846
+ */ (
847
+ this
848
+ ).$checkDataViewByteLength(e);
849
+ }
850
+ }
851
+ }]
852
+ ]],
853
+ ' ',
854
+ ['label', [
855
+ 'Byte offset ',
856
+ ['input', {
857
+ class: 'dataViewByteOffset',
858
+ type: 'number', step: '1', size: '4', pattern: '\\d+',
859
+ min: 0,
860
+ $on: {
861
+ change (e) {
862
+ const that = /** @type {HTMLInputElement} */ (
863
+ this
864
+ );
865
+ const greatGrandparent = /** @type {HTMLElement} */
866
+ (that.parentElement?.parentElement?.parentElement);
867
+
868
+ /**
869
+ * @type {HTMLInputElement & {
870
+ * $checkDataViewByteLength: CheckDataViewByteLength
871
+ * }}
872
+ */ ($e(
873
+ greatGrandparent,
874
+ '.dataViewByteLength'
875
+ )).$checkDataViewByteLength(e);
876
+ }
877
+ }
878
+ }]
879
+ ]]
880
+ ]],
881
+ ['fieldset', [
882
+ ['legend', ['Typed array']],
883
+ ['label', [
884
+ 'Byte offset ',
885
+ ['input', {
886
+ class: 'typedArrayByteOffset',
887
+ type: 'number', step: '1', size: '4', pattern: '\\d+',
888
+ min: 0,
889
+ max: (2 ** 53) - 1,
890
+ $custom: {
891
+ /**
892
+ * @typedef {(e: Event) => void} CheckByteOffsetMultiple
893
+ */
894
+
895
+ /** @type {CheckByteOffsetMultiple} */
896
+ $checkByteOffsetMultiple (e) {
897
+ const that = /** @type {HTMLInputElement} */ (this);
898
+ const ancestor = /** @type {HTMLElement} */ (
899
+ that.
900
+ parentElement?.parentElement?.parentElement?.parentElement
901
+ );
902
+
903
+ const {value} = /** @type {HTMLSelectElement} */ (
904
+ $e(ancestor, '.buffersource-typedArrays-init')
905
+ );
906
+
907
+ const TypedArray = getTypedArray(
908
+ /** @type {TypedArray} */ (value)
909
+ );
910
+ if (
911
+ Number.parseInt(that.value) % TypedArray.BYTES_PER_ELEMENT
912
+ ) {
913
+ that.setCustomValidity(
914
+ 'Byte offset must be a multiple of the typed ' +
915
+ `array's bytes-per-element size (${
916
+ TypedArray.BYTES_PER_ELEMENT
917
+ })`
918
+ );
919
+ e.stopPropagation();
920
+ } else {
921
+ that.setCustomValidity('');
922
+ }
923
+ that.reportValidity();
924
+ }
925
+ },
926
+ $on: {
927
+ change (e) {
928
+ const that = /** @type {HTMLInputElement} */ (this);
929
+ const ancestor = /** @type {HTMLElement} */ (
930
+ that.
931
+ parentElement?.parentElement?.parentElement?.parentElement
932
+ );
933
+ const typedArrayLength =
934
+ /**
935
+ * @type {HTMLInputElement & {
936
+ * $checkBufferBounds: CheckBufferBounds
937
+ * }}
938
+ */ (
939
+ $e(ancestor, '.typedArrayLength')
940
+ );
941
+ if (!typedArrayLength.$checkBufferBounds(e)) {
942
+ return;
943
+ }
944
+ /**
945
+ * @type {HTMLInputElement & {
946
+ * $checkByteOffsetMultiple: CheckByteOffsetMultiple
947
+ * }}
948
+ */ (this).$checkByteOffsetMultiple(e);
949
+ }
950
+ }
951
+ }]
952
+ ]]
953
+ // ' ',
954
+ // ['label', [
955
+ // 'Length ',
956
+ // ['input', {
957
+ // class: 'typedArrayLength',
958
+ // type: 'number', step: '1', size: '4', pattern: '\\d+',
959
+ // min: 0
960
+ // }]
961
+ // ]]
962
+ ]]
963
+ ]],
964
+ ['fieldset', [
965
+ ['legend', ['Typed Array initialization (optional)']],
966
+ ['select', {
967
+ class: 'buffersource-typedArrays-init',
968
+ 'aria-label': 'Typed Arrays',
969
+ $custom: {
970
+ /**
971
+ * @callback SetMinsAndMaxes
972
+ * @param {TypedArray} typedArray
973
+ * @returns {void}
974
+ */
975
+
976
+ /** @type {SetMinsAndMaxes} */
977
+ $setMinsAndMaxes (typedArray) {
978
+ const {min, max} = getMinMaxForTypedArray(typedArray);
979
+
980
+ /** @type {HTMLInputElement[]} */ (
981
+ $$e(/** @type {HTMLElement} */ (
982
+ /** @type {HTMLSelectElement} */ (this).parentElement
983
+ ), '.typedArrayValue')
984
+ ).forEach((typedArrayValue) => {
985
+ typedArrayValue.className =
986
+ 'typedArrayValue typedArray-' + typedArray;
987
+ typedArrayValue.min = String(min);
988
+ typedArrayValue.max = String(max);
989
+ });
990
+ },
991
+
992
+ /**
993
+ * @typedef {(e: Event) => void} CheckTypedArrayByteLength
994
+ */
995
+
996
+ /** @type {CheckTypedArrayByteLength} */
997
+ $checkTypedArrayByteLength (e) {
998
+ const that = /** @type {HTMLSelectElement} */ (this);
999
+ const TypedArray = getTypedArray(
1000
+ /** @type {TypedArray} */ (that.value)
1001
+ );
1002
+
1003
+ const byteLength = /** @type {HTMLInputElement} */ ($e(
1004
+ /** @type {HTMLElement} */
1005
+ (that.parentElement?.parentElement),
1006
+ '.byteLength'
1007
+ ));
1008
+ const arrayBufferLength = byteLength.value
1009
+ ? Number.parseInt(
1010
+ byteLength.value
1011
+ )
1012
+ : 0;
1013
+ if (arrayBufferLength % TypedArray.BYTES_PER_ELEMENT) {
1014
+ byteLength.setCustomValidity(
1015
+ 'Array buffer must be a multiple of the typed array\'s ' +
1016
+ `bytes-per-element size (${TypedArray.BYTES_PER_ELEMENT})`
1017
+ );
1018
+ e.stopPropagation();
1019
+ } else {
1020
+ byteLength.setCustomValidity('');
1021
+ }
1022
+ byteLength.reportValidity();
1023
+ }
1024
+ },
1025
+ $on: {
1026
+ change (e) {
1027
+ const that =
1028
+ /**
1029
+ * @type {HTMLSelectElement & {
1030
+ * $setMinsAndMaxes: SetMinsAndMaxes,
1031
+ * $checkTypedArrayByteLength: CheckTypedArrayByteLength
1032
+ * }}
1033
+ */ (
1034
+ this
1035
+ );
1036
+
1037
+ const ancestor = /** @type {HTMLElement} */ (
1038
+ that.
1039
+ parentElement?.parentElement?.parentElement
1040
+ );
1041
+
1042
+ // Update to reflect current state changes if later revealing
1043
+ /** @type {HTMLSelectElement} */ ($e(
1044
+ /** @type {HTMLElement} */
1045
+ (this.parentElement?.parentElement),
1046
+ '.buffersource-typedArrays'
1047
+ )).value = that.value;
1048
+
1049
+ const typedArrayLength =
1050
+ /**
1051
+ * @type {HTMLInputElement & {
1052
+ * $checkBufferBounds: CheckBufferBounds
1053
+ * }}
1054
+ */ (
1055
+ $e(ancestor, '.typedArrayLength')
1056
+ );
1057
+ if (!typedArrayLength.$checkBufferBounds(e)) {
1058
+ return;
1059
+ }
1060
+
1061
+ that.$checkTypedArrayByteLength(e);
1062
+
1063
+ that.$setMinsAndMaxes(/** @type {TypedArray} */ (that.value));
1064
+
1065
+ const typedArrayByteOffset = $e(
1066
+ /** @type {HTMLElement} */
1067
+ (that?.parentElement?.parentElement),
1068
+ '.typedArrayByteOffset'
1069
+ );
1070
+ /**
1071
+ * @type {HTMLInputElement & {
1072
+ * $checkByteOffsetMultiple: CheckByteOffsetMultiple
1073
+ * }}
1074
+ */ (typedArrayByteOffset).$checkByteOffsetMultiple(e);
1075
+
1076
+ /**
1077
+ * @type {HTMLFieldSetElement & {
1078
+ * $buildInstances: BuildInstances
1079
+ * }}
1080
+ */ ($e(
1081
+ /** @type {HTMLElement} */
1082
+ (this.parentElement?.parentElement),
1083
+ '.returnType'
1084
+ )).$buildInstances();
1085
+ }
1086
+ }
1087
+ }, typedArrays.map((typedArray) => {
1088
+ return ['option', [typedArray]];
1089
+ })],
1090
+ ' ',
1091
+ ['label', [
1092
+ 'Array length: ',
1093
+ ['input', {
1094
+ class: 'typedArrayLength',
1095
+ type: 'number', step: '1', size: '4', pattern: '\\d+',
1096
+ min: 0,
1097
+ $custom: {
1098
+ /**
1099
+ * When creating a view from a buffer, the bounds are outside
1100
+ * the buffer. In other words, `byteOffset + length *
1101
+ * TypedArray.BYTES_PER_ELEMENT > buffer.byteLength`.
1102
+ * @typedef {(e: Event) => boolean} CheckBufferBounds
1103
+ */
1104
+
1105
+ /** @type {CheckBufferBounds} */
1106
+ $checkBufferBounds (e) {
1107
+ const that = /** @type {HTMLInputElement} */ (this);
1108
+
1109
+ const ancestor = /** @type {HTMLElement} */ (
1110
+ that.parentElement?.parentElement?.parentElement
1111
+ );
1112
+ const bufferByteLengthVal = /** @type {HTMLInputElement} */ (
1113
+ $e(
1114
+ ancestor,
1115
+ '.byteLength'
1116
+ )).value;
1117
+ const bufferByteLength = bufferByteLengthVal
1118
+ ? Number.parseInt(
1119
+ bufferByteLengthVal
1120
+ )
1121
+ : 0;
1122
+
1123
+ const length = that.value
1124
+ ? Number.parseInt(that.value)
1125
+ : bufferByteLength;
1126
+
1127
+ const {value} = /** @type {HTMLSelectElement} */ (
1128
+ $e(ancestor, '.buffersource-typedArrays-init')
1129
+ );
1130
+
1131
+ const TypedArray = getTypedArray(
1132
+ /** @type {TypedArray} */ (value)
1133
+ );
1134
+
1135
+ const typedArrayByteOffsetVal =
1136
+ /** @type {HTMLInputElement} */ ($e(
1137
+ ancestor,
1138
+ '.typedArrayByteOffset'
1139
+ )).value;
1140
+ const typedArrayByteOffset = typedArrayByteOffsetVal
1141
+ ? Number.parseInt(typedArrayByteOffsetVal)
1142
+ : 0;
1143
+
1144
+ console.log('1111', typedArrayByteOffset,
1145
+ length, TypedArray.BYTES_PER_ELEMENT,
1146
+ bufferByteLength);
1147
+
1148
+ if (
1149
+ (typedArrayByteOffset +
1150
+ (length * TypedArray.BYTES_PER_ELEMENT)) >
1151
+ bufferByteLength
1152
+ ) {
1153
+ that.setCustomValidity(
1154
+ 'The byte offset and the length times bytes per element ' +
1155
+ 'is greater than the buffer length'
1156
+ );
1157
+ e.stopPropagation();
1158
+ that.reportValidity();
1159
+ return false;
1160
+ }
1161
+
1162
+ that.setCustomValidity('');
1163
+ that.reportValidity();
1164
+ return true;
1165
+ },
1166
+
1167
+ /**
1168
+ * @typedef {() => void} BuildTypedArray
1169
+ */
1170
+
1171
+ /** @type {BuildTypedArray} */
1172
+ $buildTypedArray () {
1173
+ const that = /** @type {HTMLInputElement} */ (this);
1174
+ const length = Number.parseInt(that.value);
1175
+ const grandparent = /** @type {HTMLElement} */ (
1176
+ that.parentElement?.parentElement
1177
+ );
1178
+
1179
+ const ancestor = /** @type {HTMLElement} */ (
1180
+ that.parentElement?.parentElement?.parentElement
1181
+ );
1182
+ const bufferByteLength =
1183
+ /**
1184
+ * @type {HTMLInputElement & {
1185
+ * $typedArray: TypedArrayInstance
1186
+ * }}
1187
+ */ ($e(
1188
+ ancestor,
1189
+ '.byteLength'
1190
+ ));
1191
+
1192
+ const typedArrayArea = /** @type {HTMLElement} */ ($e(
1193
+ grandparent, '.typedArrayArea'
1194
+ ));
1195
+
1196
+ typedArrayArea.addEventListener('change', (e) => {
1197
+ const input = /** @type {HTMLInputElement} */ (e.target);
1198
+ bufferByteLength.$typedArray.set([
1199
+ // @ts-expect-error Ok
1200
+ input.dataset.bigint === 'true'
1201
+ ? BigInt(input.value)
1202
+ : Number(input.value)
1203
+ ], Number.parseInt(
1204
+ /** @type {string} */ (input.dataset.key)
1205
+ ));
1206
+ });
1207
+ const {value} = /** @type {HTMLSelectElement} */ (
1208
+ $e(grandparent, '.buffersource-typedArrays-init')
1209
+ );
1210
+ const {min, max} = getMinMaxForTypedArray(
1211
+ /** @type {TypedArray} */ (value)
1212
+ );
1213
+
1214
+ typedArrayArea.textContent = '';
1215
+ typedArrayArea.append(
1216
+ ...Array.from({length}, (_v, key) => {
1217
+ return jml('label', [
1218
+ key,
1219
+ ' ',
1220
+ ['input', {
1221
+ class: 'typedArrayValue typedArray-' + value,
1222
+ dataset: {
1223
+ key, bigint: String(value.startsWith('BigInt'))
1224
+ },
1225
+ type: 'number', step: '1',
1226
+ pattern: value.startsWith('Float')
1227
+ ? '\\d+(?:\\.\\d+)?'
1228
+ : '\\d+',
1229
+ value: bufferByteLength.$typedArray[key]
1230
+ ? String(bufferByteLength.$typedArray[key])
1231
+ : '0',
1232
+ min, max
1233
+ }],
1234
+ ' '
1235
+ // !key || key % 9 ? ' ' : ['br']
1236
+ ]);
1237
+ })
1238
+ );
1239
+ }
1240
+ },
1241
+ $on: {
1242
+ change (e) {
1243
+ const that =
1244
+ /**
1245
+ * @type {HTMLInputElement & {
1246
+ * $checkBufferBounds: CheckBufferBounds,
1247
+ * $buildTypedArray: BuildTypedArray
1248
+ * }}
1249
+ */ (
1250
+ this
1251
+ );
1252
+ const grandparent = /** @type {HTMLElement} */ (
1253
+ this.parentElement?.parentElement
1254
+ );
1255
+
1256
+ if (!that.$checkBufferBounds(e)) {
1257
+ return;
1258
+ }
1259
+
1260
+ const {value} = /** @type {HTMLSelectElement} */ (
1261
+ $e(grandparent, '.buffersource-typedArrays-init')
1262
+ );
1263
+
1264
+ const length = Number.parseInt(that.value);
1265
+ try {
1266
+ const TypedArray = getTypedArray(
1267
+ /** @type {TypedArray} */ (value)
1268
+ );
1269
+ // eslint-disable-next-line no-new -- Testing
1270
+ new TypedArray(length);
1271
+ } catch (err) {
1272
+ that.setCustomValidity('Typed Array length is too long');
1273
+ e.stopPropagation();
1274
+ that.reportValidity();
1275
+ return;
1276
+ }
1277
+ that.setCustomValidity('');
1278
+ that.reportValidity();
1279
+
1280
+ /**
1281
+ * @type {HTMLFieldSetElement & {
1282
+ * $buildInstances: BuildInstances
1283
+ * }}
1284
+ */ ($e(
1285
+ /** @type {HTMLElement} */
1286
+ (this.parentElement?.parentElement?.parentElement),
1287
+ '.returnType'
1288
+ )).$buildInstances();
1289
+
1290
+ that.$buildTypedArray();
1291
+ }
1292
+ }
1293
+ }],
1294
+ ['div', {
1295
+ class: 'typedArrayArea'
1296
+ }]
1297
+ ]]
1298
+ ]],
1299
+ ['fieldset', [
1300
+ ['legend', ['DataView initialization (optional)']],
1301
+ ['select', {
1302
+ class: 'dataViewMethod',
1303
+ 'aria-label': 'Data View methods',
1304
+ $on: {
1305
+ change () {
1306
+ const dataViewArea = /** @type {HTMLDivElement} */ ($e(
1307
+ /** @type {HTMLElement} */ (this.parentElement), '.dataViewArea'
1308
+ ));
1309
+
1310
+ const val = /** @type {HTMLSelectElement} */ (this).value;
1311
+ const typedArray = /** @type {TypedArray} */ (
1312
+ val.slice(3) + 'Array'
1313
+ );
1314
+
1315
+ dataViewArea.textContent = '';
1316
+ dataViewArea.append(
1317
+ jml(
1318
+ 'label', [
1319
+ 'Byte offset ',
1320
+ ['input', {
1321
+ type: 'number',
1322
+ class: 'dataViewSetByteOffset',
1323
+ step: '1', size: '4', pattern: '\\d+'
1324
+ }]
1325
+ ]
1326
+ ),
1327
+ ' ',
1328
+ jml(
1329
+ 'label', [
1330
+ 'Value ',
1331
+ ['input', {
1332
+ type: 'number',
1333
+ step: '1', size: '4', pattern: '\\d+',
1334
+ class: 'typedArrayValue typedArray-' + typedArray,
1335
+ ...getMinMaxForTypedArray(typedArray)
1336
+ }]
1337
+ ]
1338
+ ),
1339
+ val === 'setInt8' || val === 'setUint8'
1340
+ ? ''
1341
+ : jml('label', [
1342
+ ['input', {
1343
+ class: 'littleEndian',
1344
+ type: 'checkbox'
1345
+ }],
1346
+ 'Little endian'
1347
+ ]),
1348
+ ' ',
1349
+ jml('button', {
1350
+ $on: {
1351
+ click (e) {
1352
+ e.preventDefault();
1353
+ const ancestor = /** @type {HTMLElement} */ (
1354
+ this.parentElement
1355
+ );
1356
+ const dataViewMethod =
1357
+ /** @type {dataViewMethods[number]} */ (
1358
+ /** @type {HTMLSelectElement} */ (
1359
+ ancestor.previousElementSibling
1360
+ )?.value
1361
+ );
1362
+
1363
+ const dataViewSetByteOffset =
1364
+ Number.parseInt(/** @type {HTMLInputElement} */ ($e(
1365
+ ancestor,
1366
+ '.dataViewSetByteOffset'
1367
+ )).value);
1368
+ const typedArrayValue =
1369
+ /** @type {HTMLInputElement} */ ($e(
1370
+ ancestor,
1371
+ '.typedArrayValue'
1372
+ )).value;
1373
+ const littleEndian =
1374
+ /** @type {HTMLInputElement|null} */ ($e(
1375
+ ancestor,
1376
+ '.littleEndian'
1377
+ ))?.checked;
1378
+
1379
+ const byteLength =
1380
+ /**
1381
+ * @type {HTMLInputElement & {
1382
+ * $dataView: DataView,
1383
+ * }}
1384
+ */ (
1385
+ $e(
1386
+ /** @type {HTMLElement} */
1387
+ (ancestor?.parentElement?.parentElement),
1388
+ '.byteLength'
1389
+ )
1390
+ );
1391
+
1392
+ if (
1393
+ dataViewMethod === 'setBigInt64' ||
1394
+ dataViewMethod === 'setBigUint64'
1395
+ ) {
1396
+ byteLength.$dataView[dataViewMethod](
1397
+ dataViewSetByteOffset,
1398
+ BigInt(typedArrayValue),
1399
+ littleEndian
1400
+ );
1401
+ } else {
1402
+ byteLength.$dataView[dataViewMethod](
1403
+ dataViewSetByteOffset,
1404
+ Number(typedArrayValue),
1405
+ littleEndian
1406
+ );
1407
+ }
1408
+
1409
+ const typedArrayLength =
1410
+ /**
1411
+ * @type {HTMLInputElement & {
1412
+ * $buildTypedArray: BuildTypedArray
1413
+ * }}
1414
+ */ ($e(
1415
+ /** @type {HTMLElement} */
1416
+ (ancestor.parentElement?.parentElement),
1417
+ '.typedArrayLength'
1418
+ ));
1419
+ typedArrayLength.$buildTypedArray();
1420
+ }
1421
+ }
1422
+ }, ['Set'])
1423
+ );
1424
+ }
1425
+ }
1426
+ }, [
1427
+ ['option', {value: ''}, ['(Select a data view method)']],
1428
+ ...dataViewMethods.map((dataViewMethod) => {
1429
+ return /** @type {import('jamilih').JamilihArray} */ (
1430
+ ['option', [dataViewMethod]]
1431
+ );
1432
+ })
1433
+ ]],
1434
+ ' ',
1435
+ ['div', {class: 'dataViewArea'}]
1436
+ ]]
1437
+ ]));
1438
+
1439
+ if (this.setValue && value) {
1440
+ this.setValue({root: div, value});
1441
+ } else {
1442
+ const byteLength =
1443
+ /**
1444
+ * @type {HTMLInputElement & {
1445
+ * $value: BufferSource
1446
+ * }}
1447
+ */ ($e(div, '.byteLength'));
1448
+ byteLength.$value = new ArrayBuffer(0);
1449
+ }
1450
+
1451
+ return [div];
1452
+ }
1453
+ };
1454
+
1455
+ export default buffersourceType;