@es-joy/jsoe 0.12.4 → 0.13.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.
- package/.nyc_output/out.json +11754 -11508
- package/CHANGES.md +8 -0
- package/demo/index.js +38 -29
- package/dist/formatAndTypeChoices.d.ts +11 -2
- package/dist/formatAndTypeChoices.d.ts.map +1 -1
- package/dist/formats/structuredCloning.d.ts.map +1 -1
- package/dist/formats.d.ts +52 -10
- package/dist/formats.d.ts.map +1 -1
- package/dist/fundamentalTypes/arrayType.d.ts.map +1 -1
- package/dist/fundamentalTypes/dateType.d.ts.map +1 -1
- package/dist/fundamentalTypes/errorType.d.ts.map +1 -1
- package/dist/fundamentalTypes/regexpType.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +795 -620
- package/dist/superTypes/errorsSpecialType.d.ts.map +1 -1
- package/dist/typeChoices.d.ts +4 -0
- package/dist/typeChoices.d.ts.map +1 -1
- package/dist/types.d.ts +308 -74
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/formatAndTypeChoices.js +20 -5
- package/src/formats/indexedDBKey.js +1 -1
- package/src/formats/json.js +1 -1
- package/src/formats/schemaAndArbitrary.js +1 -1
- package/src/formats/schemaOnly.js +1 -1
- package/src/formats/structuredCloning.js +22 -13
- package/src/formats.js +87 -26
- package/src/fundamentalTypes/arrayReferenceType.js +2 -2
- package/src/fundamentalTypes/arrayType.js +43 -23
- package/src/fundamentalTypes/dateType.js +2 -3
- package/src/fundamentalTypes/errorType.js +5 -3
- package/src/fundamentalTypes/regexpType.js +2 -3
- package/src/index.js +1 -1
- package/src/superTypes/errorsSpecialType.js +12 -5
- package/src/typeChoices.js +21 -10
- package/src/types.js +579 -527
package/dist/index.js
CHANGED
|
@@ -2680,6 +2680,8 @@ dialogs.setLocale();
|
|
|
2680
2680
|
* requireObject?: boolean,
|
|
2681
2681
|
* objectHasValue?: boolean,
|
|
2682
2682
|
* topRoot?: import('./types.js').RootElement,
|
|
2683
|
+
* formats?: import('./formats.js').default
|
|
2684
|
+
* types?: import('./types.js').default
|
|
2683
2685
|
* schema?: string,
|
|
2684
2686
|
* schemaContent?: object,
|
|
2685
2687
|
* }} cfg
|
|
@@ -2706,13 +2708,15 @@ const buildTypeChoices = ({
|
|
|
2706
2708
|
requireObject,
|
|
2707
2709
|
objectHasValue,
|
|
2708
2710
|
topRoot,
|
|
2711
|
+
formats = new Formats(),
|
|
2712
|
+
types = new Types(),
|
|
2709
2713
|
schema,
|
|
2710
2714
|
schemaContent
|
|
2711
2715
|
}) => {
|
|
2712
2716
|
// console.log('format', format, 'state', state, 'path', typeNamespace);
|
|
2713
2717
|
const typeOptions = requireObject
|
|
2714
|
-
? [
|
|
2715
|
-
:
|
|
2718
|
+
? [types.getOptionForType('object')]
|
|
2719
|
+
: types.getTypeOptionsForFormatAndState(format, state);
|
|
2716
2720
|
|
|
2717
2721
|
let editUI;
|
|
2718
2722
|
|
|
@@ -2721,11 +2725,13 @@ const buildTypeChoices = ({
|
|
|
2721
2725
|
const root = /** @type {HTMLDivElement} */ (
|
|
2722
2726
|
$e(typeContainer, 'div[data-type]')
|
|
2723
2727
|
);
|
|
2724
|
-
return
|
|
2728
|
+
return types.getValueForRoot(
|
|
2725
2729
|
root,
|
|
2726
2730
|
/** @type {import('./types.js').StateObject} */ ({
|
|
2727
2731
|
typeNamespace,
|
|
2732
|
+
formats,
|
|
2728
2733
|
format,
|
|
2734
|
+
types,
|
|
2729
2735
|
...stateObj
|
|
2730
2736
|
}),
|
|
2731
2737
|
currentPath
|
|
@@ -2788,7 +2794,7 @@ const buildTypeChoices = ({
|
|
|
2788
2794
|
// (needed by arrayNonindexKeys for setting an array
|
|
2789
2795
|
// length and avoiding errors); could set all
|
|
2790
2796
|
// values through here?
|
|
2791
|
-
editUI =
|
|
2797
|
+
editUI = types.getUIForModeAndType({
|
|
2792
2798
|
readonly: false,
|
|
2793
2799
|
typeNamespace,
|
|
2794
2800
|
type,
|
|
@@ -2803,7 +2809,7 @@ const buildTypeChoices = ({
|
|
|
2803
2809
|
this.$validate();
|
|
2804
2810
|
topRoot = this.$getTopRoot(); // May be existing now
|
|
2805
2811
|
// Needed; Array/object ref somewhere could now be valid or invalid
|
|
2806
|
-
|
|
2812
|
+
types.validateAllReferences({topRoot});
|
|
2807
2813
|
},
|
|
2808
2814
|
|
|
2809
2815
|
/** @type {AddTypeAndEditUI} */
|
|
@@ -2835,7 +2841,7 @@ const buildTypeChoices = ({
|
|
|
2835
2841
|
return false;
|
|
2836
2842
|
}
|
|
2837
2843
|
const editUI = container.firstElementChild;
|
|
2838
|
-
return
|
|
2844
|
+
return types.validate({
|
|
2839
2845
|
type, root: editUI, topRoot: this.$getTopRoot()
|
|
2840
2846
|
});
|
|
2841
2847
|
}
|
|
@@ -2872,17 +2878,21 @@ const buildTypeChoices = ({
|
|
|
2872
2878
|
value = {};
|
|
2873
2879
|
}
|
|
2874
2880
|
try {
|
|
2875
|
-
const rootEditUI = await
|
|
2881
|
+
const rootEditUI = await formats.getControlsForFormatAndValue(
|
|
2882
|
+
types,
|
|
2883
|
+
format,
|
|
2876
2884
|
value,
|
|
2877
2885
|
{
|
|
2878
2886
|
readonly: false,
|
|
2879
2887
|
typeNamespace,
|
|
2880
2888
|
schema,
|
|
2881
|
-
schemaContent
|
|
2889
|
+
schemaContent,
|
|
2890
|
+
formats,
|
|
2891
|
+
types
|
|
2882
2892
|
}
|
|
2883
2893
|
);
|
|
2884
2894
|
const type =
|
|
2885
|
-
Types
|
|
2895
|
+
Types.getTypeForRoot(/** @type {HTMLDivElement} */ (
|
|
2886
2896
|
rootEditUI
|
|
2887
2897
|
));
|
|
2888
2898
|
// eslint-disable-next-line @stylistic/max-len -- Long
|
|
@@ -2919,7 +2929,7 @@ const buildTypeChoices = ({
|
|
|
2919
2929
|
const root = /** @type {HTMLDivElement} */ (
|
|
2920
2930
|
$e(typeContainer, 'div[data-type]')
|
|
2921
2931
|
);
|
|
2922
|
-
return Types
|
|
2932
|
+
return Types.getTypeForRoot(root);
|
|
2923
2933
|
},
|
|
2924
2934
|
|
|
2925
2935
|
/** @type {ValidValuesSet} */
|
|
@@ -2928,17 +2938,18 @@ const buildTypeChoices = ({
|
|
|
2928
2938
|
$e(typeContainer, 'div[data-type]')
|
|
2929
2939
|
);
|
|
2930
2940
|
const form = /** @type {HTMLFormElement} */ (root.closest('form'));
|
|
2931
|
-
return Types
|
|
2941
|
+
return Types.validValuesSet({form, typeNamespace});
|
|
2932
2942
|
},
|
|
2933
2943
|
|
|
2934
2944
|
/** @type {SetValue} */
|
|
2935
2945
|
async setValue (value, stateObj) {
|
|
2936
2946
|
const rootEditUI = /** @type {HTMLDivElement} */ (
|
|
2937
|
-
await getControlsForFormatAndValue(
|
|
2947
|
+
await formats.getControlsForFormatAndValue(
|
|
2948
|
+
types,
|
|
2938
2949
|
format, value, stateObj
|
|
2939
2950
|
)
|
|
2940
2951
|
);
|
|
2941
|
-
const type = Types
|
|
2952
|
+
const type = Types.getTypeForRoot(rootEditUI);
|
|
2942
2953
|
/** @type {HTMLSelectElement & {$addTypeAndEditUI: AddTypeAndEditUI}} */ (
|
|
2943
2954
|
sel
|
|
2944
2955
|
).$addTypeAndEditUI({type, editUI: rootEditUI});
|
|
@@ -3061,7 +3072,7 @@ const json = {
|
|
|
3061
3072
|
return undefined; // Todo: Fix?
|
|
3062
3073
|
}
|
|
3063
3074
|
},
|
|
3064
|
-
getTypesForState (state) {
|
|
3075
|
+
getTypesForState (types, state) {
|
|
3065
3076
|
/* istanbul ignore else -- No other states apparently */
|
|
3066
3077
|
if (!state || ['array', 'object'].includes(state)) {
|
|
3067
3078
|
return this.types();
|
|
@@ -3094,6 +3105,8 @@ const json = {
|
|
|
3094
3105
|
const encapsulateObserver = (stateObj) => {
|
|
3095
3106
|
const {
|
|
3096
3107
|
typeNamespace, readonly, format: frmt, schemaContent,
|
|
3108
|
+
formats,
|
|
3109
|
+
types,
|
|
3097
3110
|
getPossibleSchemasForPathAndType
|
|
3098
3111
|
} = stateObj;
|
|
3099
3112
|
|
|
@@ -3166,11 +3179,13 @@ const encapsulateObserver = (stateObj) => {
|
|
|
3166
3179
|
newValue = typesonPathToJSONPointer(cyclicKeypath);
|
|
3167
3180
|
newType = type === 'array' ? 'arrayReference' : 'objectReference';
|
|
3168
3181
|
newType = canonicalToAvailableType(
|
|
3169
|
-
format, state, newType, value
|
|
3182
|
+
types, formats, format, state, newType, value
|
|
3170
3183
|
); // Todo (low): Add accurate state for second argument
|
|
3171
3184
|
} else {
|
|
3172
3185
|
try {
|
|
3173
3186
|
newType = canonicalToAvailableType(
|
|
3187
|
+
types,
|
|
3188
|
+
formats,
|
|
3174
3189
|
format,
|
|
3175
3190
|
state,
|
|
3176
3191
|
/**
|
|
@@ -3207,7 +3222,7 @@ const encapsulateObserver = (stateObj) => {
|
|
|
3207
3222
|
|
|
3208
3223
|
if (!stateObj.rootUI) {
|
|
3209
3224
|
// console.log('vvvv0', newType, newValue);
|
|
3210
|
-
stateObj.rootUI =
|
|
3225
|
+
stateObj.rootUI = types.getUIForModeAndType({
|
|
3211
3226
|
readonly,
|
|
3212
3227
|
typeNamespace,
|
|
3213
3228
|
type: newType,
|
|
@@ -3305,13 +3320,13 @@ const encapsulateObserver = (stateObj) => {
|
|
|
3305
3320
|
}
|
|
3306
3321
|
|
|
3307
3322
|
if (!readonly) {
|
|
3308
|
-
|
|
3323
|
+
types.setValue({
|
|
3309
3324
|
type: newType,
|
|
3310
3325
|
// eslint-disable-next-line object-shorthand -- TS
|
|
3311
3326
|
root: /** @type {HTMLDivElement} */ (root),
|
|
3312
3327
|
value: newValue
|
|
3313
3328
|
});
|
|
3314
|
-
|
|
3329
|
+
types.validate({
|
|
3315
3330
|
type: newType,
|
|
3316
3331
|
// eslint-disable-next-line object-shorthand -- TS
|
|
3317
3332
|
root: /** @type {HTMLDivElement} */ (root),
|
|
@@ -3355,6 +3370,8 @@ const replaceTypes = (originTypes, replacements) => {
|
|
|
3355
3370
|
};
|
|
3356
3371
|
|
|
3357
3372
|
/**
|
|
3373
|
+
* @param {import('../types.js').default} types
|
|
3374
|
+
* @param {import('../formats.js').default} formats
|
|
3358
3375
|
* @param {import('../formats.js').AvailableFormat} format
|
|
3359
3376
|
* @param {string} state
|
|
3360
3377
|
* @param {import('../types.js').AvailableType} valType
|
|
@@ -3362,10 +3379,12 @@ const replaceTypes = (originTypes, replacements) => {
|
|
|
3362
3379
|
* @throws {Error}
|
|
3363
3380
|
* @returns {import('../types.js').AvailableType}
|
|
3364
3381
|
*/
|
|
3365
|
-
const canonicalToAvailableType = (
|
|
3366
|
-
|
|
3382
|
+
const canonicalToAvailableType = (
|
|
3383
|
+
types, formats, format, state, valType, v
|
|
3384
|
+
) => {
|
|
3385
|
+
const frmt = formats.getAvailableFormat(format);
|
|
3367
3386
|
const {getTypesForState, convertFromTypeson, testInvalid} = frmt;
|
|
3368
|
-
const allowableTypes = getTypesForState.call(frmt, state);
|
|
3387
|
+
const allowableTypes = getTypesForState.call(frmt, types, state);
|
|
3369
3388
|
/* istanbul ignore if -- Guard */
|
|
3370
3389
|
if (!allowableTypes) {
|
|
3371
3390
|
throw new Error('Unexpected undefined type for state');
|
|
@@ -3402,7 +3421,7 @@ const canonicalToAvailableType = (format, state, valType, v) => {
|
|
|
3402
3421
|
allowableTypes.some((allowableType) => {
|
|
3403
3422
|
// eslint-disable-next-line @stylistic/max-len -- Long
|
|
3404
3423
|
const typeObj = /** @type {import('../types.js').TypeObject & {childTypes: string[]}} */ (
|
|
3405
|
-
|
|
3424
|
+
types.getTypeObject(allowableType)
|
|
3406
3425
|
);
|
|
3407
3426
|
const {
|
|
3408
3427
|
valueMatch, superType, childTypes
|
|
@@ -3469,12 +3488,13 @@ const structuredCloning = {
|
|
|
3469
3488
|
}
|
|
3470
3489
|
});
|
|
3471
3490
|
},
|
|
3472
|
-
getTypesForState (state) {
|
|
3473
|
-
if (state &&
|
|
3474
|
-
const typesForFormat = this.getTypesForState() ||
|
|
3491
|
+
getTypesForState (types, state) {
|
|
3492
|
+
if (state && types.getContextInfo('structuredCloning', state)) {
|
|
3493
|
+
const typesForFormat = this.getTypesForState(types) ||
|
|
3475
3494
|
/* istanbul ignore next -- types should be an array */
|
|
3476
3495
|
[];
|
|
3477
|
-
|
|
3496
|
+
const contextInfo = types.getContextInfo('structuredCloning', state);
|
|
3497
|
+
contextInfo.forEach(({type, after}) => {
|
|
3478
3498
|
const precedingIdx = typesForFormat.indexOf(after);
|
|
3479
3499
|
typesForFormat.splice(precedingIdx + 1, 0, type);
|
|
3480
3500
|
});
|
|
@@ -3588,7 +3608,7 @@ const indexedDBKey = {
|
|
|
3588
3608
|
stateObj.format = 'indexedDBKey';
|
|
3589
3609
|
return structuredCloning.iterate(records, stateObj);
|
|
3590
3610
|
},
|
|
3591
|
-
getTypesForState (state) {
|
|
3611
|
+
getTypesForState (types, state) {
|
|
3592
3612
|
if (!state || ['array'].includes(state)) {
|
|
3593
3613
|
return this.types();
|
|
3594
3614
|
}
|
|
@@ -3617,6 +3637,14 @@ const typesonToIndexedDBKey = new Map([
|
|
|
3617
3637
|
* @typedef {any} StructuredCloneValue
|
|
3618
3638
|
*/
|
|
3619
3639
|
|
|
3640
|
+
/**
|
|
3641
|
+
* @callback GetTypesForFormatAndState
|
|
3642
|
+
* @param {import('./types.js').default} types
|
|
3643
|
+
* @param {AvailableFormat} format
|
|
3644
|
+
* @param {string} [state]
|
|
3645
|
+
* @returns {import('./types.js').AvailableType[]|undefined}
|
|
3646
|
+
*/
|
|
3647
|
+
|
|
3620
3648
|
/* schema:
|
|
3621
3649
|
export const getTypeForFormatStateAndValue = ({format, state, value}) => {
|
|
3622
3650
|
const valType = new Typeson().register(
|
|
@@ -3640,39 +3668,92 @@ export const getTypeForFormatStateAndValue = ({format, state, value}) => {
|
|
|
3640
3668
|
* typesonType: import('./types.js').AvailableType
|
|
3641
3669
|
* ) => import('./types.js').AvailableType|undefined,
|
|
3642
3670
|
* iterate: import('./formats/structuredCloning.js').FormatIterator,
|
|
3643
|
-
* getTypesForState: (
|
|
3671
|
+
* getTypesForState: (
|
|
3672
|
+
* types: import('./types.js').default,
|
|
3673
|
+
* state?: string
|
|
3674
|
+
* ) => undefined|
|
|
3644
3675
|
* (import('./types.js').AvailableType)[]
|
|
3645
3676
|
* }} Format
|
|
3646
3677
|
*/
|
|
3647
3678
|
|
|
3648
|
-
// Using methods ensure we have fresh copies
|
|
3649
|
-
const Formats = {
|
|
3650
|
-
availableFormats: /** @type {{[key: string]: Format}} */ ({
|
|
3651
|
-
indexedDBKey,
|
|
3652
|
-
json,
|
|
3653
|
-
// Todo (readme): these too? getTypesForState(state)
|
|
3654
|
-
/* schema:
|
|
3655
|
-
schemaAndArbitrary,
|
|
3656
|
-
schemaOnly,
|
|
3657
|
-
*/
|
|
3658
|
-
structuredCloning
|
|
3659
|
-
})
|
|
3660
|
-
};
|
|
3661
|
-
|
|
3662
3679
|
/**
|
|
3663
|
-
*
|
|
3664
|
-
* @param {StructuredCloneValue} record
|
|
3665
|
-
* @param {import('./types.js').StateObject} stateObj
|
|
3666
|
-
* @returns {Promise<Element>}
|
|
3680
|
+
* Class for processing multiple formats.
|
|
3667
3681
|
*/
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3682
|
+
class Formats {
|
|
3683
|
+
/**
|
|
3684
|
+
*
|
|
3685
|
+
*/
|
|
3686
|
+
constructor () {
|
|
3687
|
+
// Can enable later (and add tests)
|
|
3688
|
+
// if (formats) {
|
|
3689
|
+
// this.availableFormats = {};
|
|
3690
|
+
// formats.forEach((format) => {
|
|
3691
|
+
// let formatValue;
|
|
3692
|
+
// switch (format) {
|
|
3693
|
+
// case 'indexedDBKey':
|
|
3694
|
+
// formatValue = indexedDBKey;
|
|
3695
|
+
// break;
|
|
3696
|
+
// case 'json':
|
|
3697
|
+
// formatValue = json;
|
|
3698
|
+
// break;
|
|
3699
|
+
// case 'structuredCloning':
|
|
3700
|
+
// formatValue = structuredCloning;
|
|
3701
|
+
// break;
|
|
3702
|
+
// default:
|
|
3703
|
+
// throw new Error('Unknown format');
|
|
3704
|
+
// }
|
|
3705
|
+
// this.availableFormats[format] = formatValue;
|
|
3706
|
+
// });
|
|
3707
|
+
// return;
|
|
3708
|
+
// }
|
|
3709
|
+
// Using methods ensure we have fresh copies
|
|
3710
|
+
this.availableFormats = /** @type {{[key: string]: Format}} */ ({
|
|
3711
|
+
indexedDBKey,
|
|
3712
|
+
json,
|
|
3713
|
+
// Todo (readme): these too? getTypesForState(types, state)
|
|
3714
|
+
/* schema:
|
|
3715
|
+
schemaAndArbitrary,
|
|
3716
|
+
schemaOnly,
|
|
3717
|
+
*/
|
|
3718
|
+
structuredCloning
|
|
3675
3719
|
});
|
|
3720
|
+
}
|
|
3721
|
+
|
|
3722
|
+
/**
|
|
3723
|
+
* @param {import('./types.js').default} types
|
|
3724
|
+
* @param {AvailableFormat} format
|
|
3725
|
+
* @param {StructuredCloneValue} record
|
|
3726
|
+
* @param {import('./types.js').StateObject} stateObj
|
|
3727
|
+
* @returns {Promise<Element>}
|
|
3728
|
+
*/
|
|
3729
|
+
async getControlsForFormatAndValue (types, format, record, stateObj) {
|
|
3730
|
+
return await this.availableFormats[format].
|
|
3731
|
+
iterate(record, {
|
|
3732
|
+
...stateObj,
|
|
3733
|
+
types,
|
|
3734
|
+
formats: this,
|
|
3735
|
+
// This had been before `stateObj` but should apparently have precedence
|
|
3736
|
+
// or just avoid passing `format` to this function
|
|
3737
|
+
format
|
|
3738
|
+
});
|
|
3739
|
+
}
|
|
3740
|
+
|
|
3741
|
+
/**
|
|
3742
|
+
* @type {GetTypesForFormatAndState}
|
|
3743
|
+
*/
|
|
3744
|
+
getTypesForFormatAndState (
|
|
3745
|
+
types, format, state
|
|
3746
|
+
) {
|
|
3747
|
+
return this.availableFormats[format].getTypesForState(types, state);
|
|
3748
|
+
}
|
|
3749
|
+
|
|
3750
|
+
/**
|
|
3751
|
+
* @param {AvailableFormat} format
|
|
3752
|
+
* @returns {Format}
|
|
3753
|
+
*/
|
|
3754
|
+
getAvailableFormat (format) {
|
|
3755
|
+
return this.availableFormats[format];
|
|
3756
|
+
}
|
|
3676
3757
|
}
|
|
3677
3758
|
|
|
3678
3759
|
/**
|
|
@@ -4191,7 +4272,7 @@ const arrayReferenceType = {
|
|
|
4191
4272
|
'arrayNonindexKeys'
|
|
4192
4273
|
// 'sparseArrays'
|
|
4193
4274
|
].includes(
|
|
4194
|
-
Types
|
|
4275
|
+
Types.getTypeForRoot(referent)
|
|
4195
4276
|
);
|
|
4196
4277
|
};
|
|
4197
4278
|
let message;
|
|
@@ -4248,7 +4329,7 @@ const arrayReferenceType = {
|
|
|
4248
4329
|
|
|
4249
4330
|
// Condition to confirm that referenced element is an array or
|
|
4250
4331
|
// object (or reference) with the designated `type`
|
|
4251
|
-
const referentType = Types
|
|
4332
|
+
const referentType = Types.getTypeForRoot(referent);
|
|
4252
4333
|
const referentBaseType = /** @type {(string|null|undefined)[]} */ ([
|
|
4253
4334
|
'array',
|
|
4254
4335
|
'arrayNonindexKeys'
|
|
@@ -4270,12 +4351,12 @@ const arrayReferenceType = {
|
|
|
4270
4351
|
valid: true
|
|
4271
4352
|
};
|
|
4272
4353
|
},
|
|
4273
|
-
validateAll ({topRoot}) {
|
|
4354
|
+
validateAll ({types, topRoot}) {
|
|
4274
4355
|
const type = /** @type {import('../types.js').AvailableType} */ (
|
|
4275
4356
|
`${this.type}Reference`
|
|
4276
4357
|
);
|
|
4277
4358
|
$$e(topRoot, `div[data-type="${type}"]`).forEach((root) => {
|
|
4278
|
-
|
|
4359
|
+
types.validate({
|
|
4279
4360
|
type,
|
|
4280
4361
|
// eslint-disable-next-line object-shorthand -- TS
|
|
4281
4362
|
root: /** @type {HTMLDivElement} */ (root),
|
|
@@ -4481,7 +4562,10 @@ const arrayType = {
|
|
|
4481
4562
|
} = /** @type {import('../types.js').RootInfo} */ (info);
|
|
4482
4563
|
// eslint-disable-next-line prefer-destructuring -- TS
|
|
4483
4564
|
const format = /** @type {import('../types.js').RootInfo} */ (info).format;
|
|
4484
|
-
|
|
4565
|
+
// eslint-disable-next-line prefer-destructuring -- TS
|
|
4566
|
+
const types = /** @type {import('../types.js').default} */ (
|
|
4567
|
+
/** @type {import('../types.js').RootInfo} */ (info).types
|
|
4568
|
+
);
|
|
4485
4569
|
const {sparse} = this;
|
|
4486
4570
|
const state = sparse
|
|
4487
4571
|
? 'arrayNonindexKeys'
|
|
@@ -4532,7 +4616,7 @@ const arrayType = {
|
|
|
4532
4616
|
}
|
|
4533
4617
|
let v, beginOnly, assign;
|
|
4534
4618
|
try {
|
|
4535
|
-
[v, stringVal, beginOnly, assign] =
|
|
4619
|
+
[v, stringVal, beginOnly, assign] = types.getValueForString(
|
|
4536
4620
|
stringVal,
|
|
4537
4621
|
{
|
|
4538
4622
|
firstRun: false,
|
|
@@ -4589,7 +4673,7 @@ const arrayType = {
|
|
|
4589
4673
|
stringVal = stringVal.slice(propAndColon[0].length);
|
|
4590
4674
|
let v, beginOnly, assign;
|
|
4591
4675
|
try {
|
|
4592
|
-
[v, stringVal, beginOnly, assign] =
|
|
4676
|
+
[v, stringVal, beginOnly, assign] = types.getValueForString(
|
|
4593
4677
|
stringVal,
|
|
4594
4678
|
{
|
|
4595
4679
|
firstRun: false, format, state,
|
|
@@ -4618,7 +4702,13 @@ const arrayType = {
|
|
|
4618
4702
|
parse();
|
|
4619
4703
|
return {value: retObj, remnant: stringVal};
|
|
4620
4704
|
},
|
|
4621
|
-
getValue ({root, stateObj
|
|
4705
|
+
getValue ({root, stateObj, currentPath = ''}) {
|
|
4706
|
+
/* istanbul ignore if */
|
|
4707
|
+
if (!stateObj) {
|
|
4708
|
+
throw new Error('TS guard'); // TS guard
|
|
4709
|
+
}
|
|
4710
|
+
// eslint-disable-next-line prefer-destructuring -- TS
|
|
4711
|
+
const types = /** @type {import('../types.js').default} */ (stateObj.types);
|
|
4622
4712
|
const top = currentPath === '';
|
|
4623
4713
|
const arrayItems =
|
|
4624
4714
|
/**
|
|
@@ -4651,10 +4741,10 @@ const arrayType = {
|
|
|
4651
4741
|
* @returns {[boolean, any?]}
|
|
4652
4742
|
*/
|
|
4653
4743
|
const getValOrRef = (root, currentPathPart) => {
|
|
4654
|
-
const value =
|
|
4744
|
+
const value = types.getValueForRoot(
|
|
4655
4745
|
root, stateObj, currentPath + '/' + currentPathPart
|
|
4656
4746
|
);
|
|
4657
|
-
if (stateObj.handlingReference) {
|
|
4747
|
+
if ('handlingReference' in stateObj && stateObj.handlingReference) {
|
|
4658
4748
|
// We deal with references later once object is fully constructed
|
|
4659
4749
|
stateObj.handlingReference = false;
|
|
4660
4750
|
return [false];
|
|
@@ -4730,7 +4820,7 @@ const arrayType = {
|
|
|
4730
4820
|
},
|
|
4731
4821
|
|
|
4732
4822
|
// Try to keep in sync with basic structure of `editUI`
|
|
4733
|
-
viewUI ({typeNamespace, type, value, topRoot, resultType, format}) {
|
|
4823
|
+
viewUI ({typeNamespace, type, types, value, topRoot, resultType, format}) {
|
|
4734
4824
|
// const {sparse} = this;
|
|
4735
4825
|
let itemIndex = -1;
|
|
4736
4826
|
|
|
@@ -4787,7 +4877,7 @@ const arrayType = {
|
|
|
4787
4877
|
schemaContent, schemaState
|
|
4788
4878
|
}) {
|
|
4789
4879
|
if (parentType === 'map') {
|
|
4790
|
-
const root =
|
|
4880
|
+
const root = types.getUIForModeAndType({
|
|
4791
4881
|
resultType,
|
|
4792
4882
|
readonly: true,
|
|
4793
4883
|
typeNamespace, type, topRoot,
|
|
@@ -4818,7 +4908,7 @@ const arrayType = {
|
|
|
4818
4908
|
}
|
|
4819
4909
|
|
|
4820
4910
|
const fieldset = this.$addArrayElement({propName});
|
|
4821
|
-
const root =
|
|
4911
|
+
const root = types.getUIForModeAndType({
|
|
4822
4912
|
resultType,
|
|
4823
4913
|
readonly: true,
|
|
4824
4914
|
typeNamespace, type, topRoot,
|
|
@@ -4928,6 +5018,7 @@ const arrayType = {
|
|
|
4928
5018
|
// population of the array in the callback
|
|
4929
5019
|
editUI ({
|
|
4930
5020
|
typeNamespace, buildTypeChoices, format, // resultType,
|
|
5021
|
+
formats, types,
|
|
4931
5022
|
type, arrayState, topRoot, value, bringIntoFocus = true
|
|
4932
5023
|
}) {
|
|
4933
5024
|
const {sparse} = this;
|
|
@@ -5018,7 +5109,7 @@ const arrayType = {
|
|
|
5018
5109
|
} else {
|
|
5019
5110
|
group.before(swapGroup);
|
|
5020
5111
|
}
|
|
5021
|
-
|
|
5112
|
+
types.validateAllReferences({
|
|
5022
5113
|
// eslint-disable-next-line object-shorthand -- TS
|
|
5023
5114
|
topRoot: /** @type {HTMLDivElement} */ (topRoot)
|
|
5024
5115
|
}); // Needed
|
|
@@ -5201,7 +5292,7 @@ const arrayType = {
|
|
|
5201
5292
|
(this).$validateMapKey();
|
|
5202
5293
|
|
|
5203
5294
|
// Needed?
|
|
5204
|
-
|
|
5295
|
+
types.validateAllReferences({
|
|
5205
5296
|
// eslint-disable-next-line object-shorthand -- TS
|
|
5206
5297
|
topRoot: /** @type {HTMLDivElement} */ (topRoot)
|
|
5207
5298
|
});
|
|
@@ -5286,7 +5377,7 @@ const arrayType = {
|
|
|
5286
5377
|
/* await */ this.$validateLegend();
|
|
5287
5378
|
// Todo (low): We could make this more efficient by waiting
|
|
5288
5379
|
// until all added (when pre-populating)
|
|
5289
|
-
|
|
5380
|
+
types.validateAllReferences({
|
|
5290
5381
|
// eslint-disable-next-line object-shorthand -- TS
|
|
5291
5382
|
topRoot: /** @type {HTMLDivElement} */ (topRoot)
|
|
5292
5383
|
}); // Needed
|
|
@@ -5541,7 +5632,17 @@ const arrayType = {
|
|
|
5541
5632
|
parentTypeObject.getValue.call({
|
|
5542
5633
|
...parentTypeObject,
|
|
5543
5634
|
set: false
|
|
5544
|
-
}, {
|
|
5635
|
+
}, {
|
|
5636
|
+
root,
|
|
5637
|
+
stateObj: {
|
|
5638
|
+
types,
|
|
5639
|
+
// eslint-disable-next-line object-shorthand -- TS
|
|
5640
|
+
formats:
|
|
5641
|
+
/** @type {import('../formats.js').default} */ (
|
|
5642
|
+
formats
|
|
5643
|
+
)
|
|
5644
|
+
}
|
|
5645
|
+
})
|
|
5545
5646
|
);
|
|
5546
5647
|
// console.log('values', values);
|
|
5547
5648
|
|
|
@@ -5563,7 +5664,7 @@ const arrayType = {
|
|
|
5563
5664
|
if (!root) {
|
|
5564
5665
|
return null;
|
|
5565
5666
|
}
|
|
5566
|
-
return
|
|
5667
|
+
return types.getFormControlForRoot(root);
|
|
5567
5668
|
});
|
|
5568
5669
|
|
|
5569
5670
|
const control = controls[dupeIndex];
|
|
@@ -5665,7 +5766,7 @@ const arrayType = {
|
|
|
5665
5766
|
}
|
|
5666
5767
|
// Maybe not needed as addition (without renumbering)
|
|
5667
5768
|
// wouldn't yet add type
|
|
5668
|
-
|
|
5769
|
+
types.validateAllReferences({
|
|
5669
5770
|
// eslint-disable-next-line object-shorthand -- TS
|
|
5670
5771
|
topRoot: /** @type {HTMLDivElement} */ (topRoot)
|
|
5671
5772
|
});
|
|
@@ -5691,7 +5792,7 @@ const arrayType = {
|
|
|
5691
5792
|
});
|
|
5692
5793
|
}
|
|
5693
5794
|
// Maybe not needed as removal would remove circular
|
|
5694
|
-
|
|
5795
|
+
types.validateAllReferences({
|
|
5695
5796
|
// eslint-disable-next-line object-shorthand -- TS
|
|
5696
5797
|
topRoot: /** @type {HTMLDivElement} */ (topRoot)
|
|
5697
5798
|
});
|
|
@@ -5803,7 +5904,7 @@ const arrayType = {
|
|
|
5803
5904
|
(this).$addArrayElement({alwaysFocus: true});
|
|
5804
5905
|
// Maybe not needed as addition (without renumbering)
|
|
5805
5906
|
// wouldn't yet add type
|
|
5806
|
-
|
|
5907
|
+
types.validateAllReferences({
|
|
5807
5908
|
// eslint-disable-next-line object-shorthand -- TS
|
|
5808
5909
|
topRoot: /** @type {HTMLDivElement} */ (topRoot)
|
|
5809
5910
|
});
|
|
@@ -5855,7 +5956,7 @@ const arrayType = {
|
|
|
5855
5956
|
fieldset.remove();
|
|
5856
5957
|
});
|
|
5857
5958
|
// Maybe not needed as removal would remove circular
|
|
5858
|
-
|
|
5959
|
+
types.validateAllReferences({
|
|
5859
5960
|
// eslint-disable-next-line object-shorthand -- TS
|
|
5860
5961
|
topRoot: /** @type {HTMLDivElement} */ (topRoot)
|
|
5861
5962
|
});
|
|
@@ -5949,7 +6050,7 @@ const arrayType = {
|
|
|
5949
6050
|
).$redrawMoveArrows();
|
|
5950
6051
|
}
|
|
5951
6052
|
// Maybe not needed as removal would remove circular
|
|
5952
|
-
|
|
6053
|
+
types.validateAllReferences({
|
|
5953
6054
|
// eslint-disable-next-line object-shorthand -- TS
|
|
5954
6055
|
topRoot: /** @type {HTMLDivElement} */ (topRoot)
|
|
5955
6056
|
});
|
|
@@ -5971,7 +6072,7 @@ const arrayType = {
|
|
|
5971
6072
|
itemIndex = -1;
|
|
5972
6073
|
}
|
|
5973
6074
|
// Maybe not needed as removal would remove circular
|
|
5974
|
-
|
|
6075
|
+
types.validateAllReferences({
|
|
5975
6076
|
// eslint-disable-next-line object-shorthand -- TS
|
|
5976
6077
|
topRoot: /** @type {HTMLDivElement} */ (topRoot)
|
|
5977
6078
|
});
|
|
@@ -6026,13 +6127,13 @@ const arrayType = {
|
|
|
6026
6127
|
// from `errorsSpecialType` (and `filelistType`)
|
|
6027
6128
|
if (setAValue) {
|
|
6028
6129
|
const typeObj = /** @type {import('../types.js').TypeObject} */ (
|
|
6029
|
-
|
|
6130
|
+
types.getTypeObject(type)
|
|
6030
6131
|
);
|
|
6031
6132
|
if (typeObj.setValue) {
|
|
6032
6133
|
typeObj.setValue({root, value});
|
|
6033
6134
|
}
|
|
6034
6135
|
}
|
|
6035
|
-
|
|
6136
|
+
types.validate({type, root, topRoot});
|
|
6036
6137
|
return root;
|
|
6037
6138
|
},
|
|
6038
6139
|
|
|
@@ -6255,7 +6356,7 @@ const dateType = {
|
|
|
6255
6356
|
},
|
|
6256
6357
|
// Change to default to `new Date()` when can't be `NaN`
|
|
6257
6358
|
// value (keys)?
|
|
6258
|
-
editUI ({typeNamespace, value = ''}) {
|
|
6359
|
+
editUI ({typeNamespace, types, value = ''}) {
|
|
6259
6360
|
const notANum = this.isValueInvalid(value);
|
|
6260
6361
|
const invalid = this.valid
|
|
6261
6362
|
? ''
|
|
@@ -6285,7 +6386,7 @@ const dateType = {
|
|
|
6285
6386
|
const root = /** @type {HTMLDivElement} */ (
|
|
6286
6387
|
label.parentElement
|
|
6287
6388
|
);
|
|
6288
|
-
|
|
6389
|
+
types.validate({type: 'date', root});
|
|
6289
6390
|
}
|
|
6290
6391
|
},
|
|
6291
6392
|
$on: {
|
|
@@ -6473,7 +6574,7 @@ const regexpType = {
|
|
|
6473
6574
|
viewUI ({value}) {
|
|
6474
6575
|
return ['i', {dataset: {type: 'regexp'}}, [String(value)]];
|
|
6475
6576
|
},
|
|
6476
|
-
editUI ({typeNamespace, value = {source: '', flags: ''}}) {
|
|
6577
|
+
editUI ({typeNamespace, types, value = {source: '', flags: ''}}) {
|
|
6477
6578
|
// Todo (low): Add RegExp syntax highlighter
|
|
6478
6579
|
const select = /** @type {HTMLSelectElement} */ (jml(
|
|
6479
6580
|
'select',
|
|
@@ -6515,7 +6616,7 @@ const regexpType = {
|
|
|
6515
6616
|
// Could be disallowed flags; we might instead try in
|
|
6516
6617
|
// advance which will work
|
|
6517
6618
|
select.addEventListener('change', () => {
|
|
6518
|
-
|
|
6619
|
+
types.validate({type: 'regexp', root});
|
|
6519
6620
|
});
|
|
6520
6621
|
return [root];
|
|
6521
6622
|
}
|
|
@@ -6948,7 +7049,7 @@ const errorType = {
|
|
|
6948
7049
|
return errObj;
|
|
6949
7050
|
},
|
|
6950
7051
|
viewUI (
|
|
6951
|
-
{value: o, format}
|
|
7052
|
+
{value: o, types, format}
|
|
6952
7053
|
) {
|
|
6953
7054
|
return /** @type {import('jamilih').JamilihArray} */ ([
|
|
6954
7055
|
'div', {dataset: {type: 'error'}}, [
|
|
@@ -6987,7 +7088,8 @@ const errorType = {
|
|
|
6987
7088
|
o.cause
|
|
6988
7089
|
? this.viewUI({
|
|
6989
7090
|
format,
|
|
6990
|
-
value: o.cause
|
|
7091
|
+
value: o.cause,
|
|
7092
|
+
types
|
|
6991
7093
|
})
|
|
6992
7094
|
: ''
|
|
6993
7095
|
]]
|
|
@@ -6995,7 +7097,7 @@ const errorType = {
|
|
|
6995
7097
|
]
|
|
6996
7098
|
]);
|
|
6997
7099
|
},
|
|
6998
|
-
editUI ({typeNamespace, value = {
|
|
7100
|
+
editUI ({typeNamespace, types, value = {
|
|
6999
7101
|
message: '',
|
|
7000
7102
|
name: '',
|
|
7001
7103
|
fileName: '',
|
|
@@ -7161,6 +7263,7 @@ const errorType = {
|
|
|
7161
7263
|
if (!causeContents?.children.length) {
|
|
7162
7264
|
const editui = component.editUI({
|
|
7163
7265
|
typeNamespace,
|
|
7266
|
+
types,
|
|
7164
7267
|
value: value.cause
|
|
7165
7268
|
});
|
|
7166
7269
|
jml(...editui, causeContents);
|
|
@@ -7360,7 +7463,7 @@ const errorsSpecialType = {
|
|
|
7360
7463
|
}
|
|
7361
7464
|
});
|
|
7362
7465
|
},
|
|
7363
|
-
getValue ({root}) {
|
|
7466
|
+
getValue ({root, stateObj}) {
|
|
7364
7467
|
const UserErrorType = specialErrorsMap.get(
|
|
7365
7468
|
/** @type {HTMLSelectElement} */ (
|
|
7366
7469
|
$e(root, '.errorType')
|
|
@@ -7397,6 +7500,7 @@ const errorsSpecialType = {
|
|
|
7397
7500
|
)).firstElementChild;
|
|
7398
7501
|
|
|
7399
7502
|
const errors = arrayType.getValue({
|
|
7503
|
+
stateObj,
|
|
7400
7504
|
root: /** @type {HTMLDivElement} */ (errorRoot)
|
|
7401
7505
|
});
|
|
7402
7506
|
errObj = new UET(errors, message);
|
|
@@ -7412,6 +7516,7 @@ const errorsSpecialType = {
|
|
|
7412
7516
|
root, '.aggregateErrorsContents'
|
|
7413
7517
|
)).firstElementChild;
|
|
7414
7518
|
const errors = arrayType.getValue({
|
|
7519
|
+
stateObj,
|
|
7415
7520
|
root: /** @type {HTMLDivElement} */ (errorRoot)
|
|
7416
7521
|
});
|
|
7417
7522
|
errObj = new UET(errors);
|
|
@@ -7469,6 +7574,7 @@ const errorsSpecialType = {
|
|
|
7469
7574
|
);
|
|
7470
7575
|
if (causeContents.children.length) {
|
|
7471
7576
|
errObj.cause = this.getValue({
|
|
7577
|
+
stateObj,
|
|
7472
7578
|
root: causeContents
|
|
7473
7579
|
});
|
|
7474
7580
|
}
|
|
@@ -7476,7 +7582,7 @@ const errorsSpecialType = {
|
|
|
7476
7582
|
return errObj;
|
|
7477
7583
|
},
|
|
7478
7584
|
viewUI (
|
|
7479
|
-
{value: o, format, typeNamespace, resultType}
|
|
7585
|
+
{value: o, types, format, typeNamespace, resultType}
|
|
7480
7586
|
) {
|
|
7481
7587
|
const constructor = getConstructor(o.constructor);
|
|
7482
7588
|
return /** @type {import('jamilih').JamilihArray} */ ([
|
|
@@ -7518,7 +7624,8 @@ const errorsSpecialType = {
|
|
|
7518
7624
|
o.cause
|
|
7519
7625
|
? this.viewUI({
|
|
7520
7626
|
format,
|
|
7521
|
-
value: o.cause
|
|
7627
|
+
value: o.cause,
|
|
7628
|
+
types
|
|
7522
7629
|
})
|
|
7523
7630
|
: ''
|
|
7524
7631
|
]]
|
|
@@ -7545,7 +7652,8 @@ const errorsSpecialType = {
|
|
|
7545
7652
|
const [div] = arrayType.viewUI({
|
|
7546
7653
|
typeNamespace, resultType, format,
|
|
7547
7654
|
type: 'arrayNonindexKeys',
|
|
7548
|
-
value: []
|
|
7655
|
+
value: [],
|
|
7656
|
+
types
|
|
7549
7657
|
});
|
|
7550
7658
|
|
|
7551
7659
|
/** @type {Error[]} */
|
|
@@ -7580,6 +7688,7 @@ const errorsSpecialType = {
|
|
|
7580
7688
|
},
|
|
7581
7689
|
editUI ({
|
|
7582
7690
|
typeNamespace,
|
|
7691
|
+
types,
|
|
7583
7692
|
|
|
7584
7693
|
// Pass these to `errors` array
|
|
7585
7694
|
buildTypeChoices,
|
|
@@ -7808,6 +7917,7 @@ const errorsSpecialType = {
|
|
|
7808
7917
|
if (!causeContents?.children.length) {
|
|
7809
7918
|
const editui = component.editUI({
|
|
7810
7919
|
typeNamespace,
|
|
7920
|
+
types,
|
|
7811
7921
|
value: value.cause
|
|
7812
7922
|
});
|
|
7813
7923
|
jml(...editui, causeContents);
|
|
@@ -7874,7 +7984,7 @@ const errorsSpecialType = {
|
|
|
7874
7984
|
);
|
|
7875
7985
|
if (!aggregateErrorsContents?.children.length) {
|
|
7876
7986
|
const [editui] = arrayType.editUI({
|
|
7877
|
-
typeNamespace, buildTypeChoices, format,
|
|
7987
|
+
typeNamespace, types, buildTypeChoices, format,
|
|
7878
7988
|
type: 'array',
|
|
7879
7989
|
topRoot, bringIntoFocus,
|
|
7880
7990
|
arrayState: 'errorsArray',
|
|
@@ -10889,6 +10999,11 @@ const getPropertyValueFromLegend = (legend) => {
|
|
|
10889
10999
|
return String(Number.parseInt(propElem.textContent) - 1);
|
|
10890
11000
|
};
|
|
10891
11001
|
|
|
11002
|
+
/**
|
|
11003
|
+
* Any other possibilities than `div`?
|
|
11004
|
+
* @typedef {HTMLDivElement} RootElement
|
|
11005
|
+
*/
|
|
11006
|
+
|
|
10892
11007
|
/**
|
|
10893
11008
|
* Utility to retrieve the type out of a type root element.
|
|
10894
11009
|
* @callback GetTypeForRoot
|
|
@@ -10901,7 +11016,7 @@ const getPropertyValueFromLegend = (legend) => {
|
|
|
10901
11016
|
* state and path.
|
|
10902
11017
|
* @callback GetValueForRoot
|
|
10903
11018
|
* @param {RootElement} root
|
|
10904
|
-
* @param {StateObject}
|
|
11019
|
+
* @param {StateObject} stateObj
|
|
10905
11020
|
* @param {string} [currentPath]
|
|
10906
11021
|
* @returns {StructuredCloneValue}
|
|
10907
11022
|
*/
|
|
@@ -10918,7 +11033,7 @@ const getPropertyValueFromLegend = (legend) => {
|
|
|
10918
11033
|
* Utility to get the value for a root using its ancestor and state.
|
|
10919
11034
|
* @callback GetValueFromRootAncestor
|
|
10920
11035
|
* @param {string|HTMLElement} selOrEl
|
|
10921
|
-
* @param {StateObject}
|
|
11036
|
+
* @param {StateObject} stateObj
|
|
10922
11037
|
* @returns {StructuredCloneValue}
|
|
10923
11038
|
*/
|
|
10924
11039
|
|
|
@@ -10929,13 +11044,6 @@ const getPropertyValueFromLegend = (legend) => {
|
|
|
10929
11044
|
* HTMLButtonElement}
|
|
10930
11045
|
*/
|
|
10931
11046
|
|
|
10932
|
-
/**
|
|
10933
|
-
* @callback GetTypesForFormatAndState
|
|
10934
|
-
* @param {string} format
|
|
10935
|
-
* @param {string} [state]
|
|
10936
|
-
* @returns {AvailableType[]|undefined}
|
|
10937
|
-
*/
|
|
10938
|
-
|
|
10939
11047
|
/**
|
|
10940
11048
|
* @callback GetOptionForType
|
|
10941
11049
|
* @param {AvailableType} type
|
|
@@ -10944,11 +11052,40 @@ const getPropertyValueFromLegend = (legend) => {
|
|
|
10944
11052
|
|
|
10945
11053
|
/**
|
|
10946
11054
|
* @callback GetTypeOptionsForFormatAndState
|
|
10947
|
-
* @param {
|
|
11055
|
+
* @param {import('./formats.js').AvailableFormat} format
|
|
10948
11056
|
* @param {string} [parserState]
|
|
10949
11057
|
* @returns {[string, {value: AvailableType, title?: string}][]}
|
|
10950
11058
|
*/
|
|
10951
11059
|
|
|
11060
|
+
/**
|
|
11061
|
+
* @typedef {(
|
|
11062
|
+
* keypath: string,
|
|
11063
|
+
* parentPath: string,
|
|
11064
|
+
* arrayOrObjectPropertyName: string,
|
|
11065
|
+
* valueType: string
|
|
11066
|
+
* ) => StateObject} GetPossibleSchemasForPathAndType
|
|
11067
|
+
*/
|
|
11068
|
+
|
|
11069
|
+
/**
|
|
11070
|
+
* @typedef {{
|
|
11071
|
+
* typeNamespace?: string,
|
|
11072
|
+
* "readonly"?: boolean,
|
|
11073
|
+
* format?: import('./formats.js').AvailableFormat,
|
|
11074
|
+
* formats: import('./formats.js').default,
|
|
11075
|
+
* types: Types,
|
|
11076
|
+
* error?: Error,
|
|
11077
|
+
* rootUI?: Element,
|
|
11078
|
+
* schema?: string,
|
|
11079
|
+
* schemaContent?: object,
|
|
11080
|
+
* getPossibleSchemasForPathAndType?: GetPossibleSchemasForPathAndType,
|
|
11081
|
+
* paths?: {[currentPath: string]: {
|
|
11082
|
+
* referentPath: string,
|
|
11083
|
+
* expectArrayReferent: boolean
|
|
11084
|
+
* }},
|
|
11085
|
+
* handlingReference?: boolean
|
|
11086
|
+
* }} StateObject
|
|
11087
|
+
*/
|
|
11088
|
+
|
|
10952
11089
|
/* eslint-disable jsdoc/valid-types -- readonly reserved */
|
|
10953
11090
|
/**
|
|
10954
11091
|
* @typedef {(cfg: {
|
|
@@ -11027,35 +11164,6 @@ const getPropertyValueFromLegend = (legend) => {
|
|
|
11027
11164
|
* ) => void} CustomValidateAllReferences
|
|
11028
11165
|
*/
|
|
11029
11166
|
|
|
11030
|
-
/**
|
|
11031
|
-
* @type {{
|
|
11032
|
-
* availableTypes: {
|
|
11033
|
-
* [key in AvailableType]: Partial<TypeObject>|string[]
|
|
11034
|
-
* },
|
|
11035
|
-
* getTypeForRoot: GetTypeForRoot,
|
|
11036
|
-
* getValueForRoot: GetValueForRoot,
|
|
11037
|
-
* getFormControlForRoot: GetFormControlForRoot,
|
|
11038
|
-
* getValueFromRootAncestor: GetValueFromRootAncestor,
|
|
11039
|
-
* getFormControlFromRootAncestor: GetFormControlFromRootAncestor,
|
|
11040
|
-
* getTypesForFormatAndState: GetTypesForFormatAndState,
|
|
11041
|
-
* getOptionForType: GetOptionForType,
|
|
11042
|
-
* getTypeOptionsForFormatAndState: GetTypeOptionsForFormatAndState,
|
|
11043
|
-
* getUIForModeAndType: GetUIForModeAndType,
|
|
11044
|
-
* contexts: {
|
|
11045
|
-
* [key: string]: {
|
|
11046
|
-
* [key: string]: {type: AvailableType, after: AvailableType}[]
|
|
11047
|
-
* }
|
|
11048
|
-
* },
|
|
11049
|
-
* validValuesSet: ValidValuesSet,
|
|
11050
|
-
* validateAllReferences: ValidateAllReferences,
|
|
11051
|
-
* validate: Validate,
|
|
11052
|
-
* setValue: SetValue,
|
|
11053
|
-
* getValueForString: GetValueForString,
|
|
11054
|
-
* customValidateAllReferences?: CustomValidateAllReferences
|
|
11055
|
-
* }}
|
|
11056
|
-
*/
|
|
11057
|
-
const Types = {};
|
|
11058
|
-
|
|
11059
11167
|
/**
|
|
11060
11168
|
* @typedef {import('./formats.js').StructuredCloneValue} StructuredCloneValue
|
|
11061
11169
|
*/
|
|
@@ -11077,7 +11185,8 @@ const Types = {};
|
|
|
11077
11185
|
* path: string
|
|
11078
11186
|
* ][],
|
|
11079
11187
|
* parent?: object,
|
|
11080
|
-
* parentPath?: string|number
|
|
11188
|
+
* parentPath?: string|number,
|
|
11189
|
+
* types?: Types
|
|
11081
11190
|
* }} RootInfo
|
|
11082
11191
|
*/
|
|
11083
11192
|
|
|
@@ -11142,13 +11251,16 @@ const Types = {};
|
|
|
11142
11251
|
* type?: AvailableType,
|
|
11143
11252
|
* topRoot?: HTMLDivElement,
|
|
11144
11253
|
* resultType?: "keys"|"values"|"both",
|
|
11145
|
-
* format: import('./formats.js').AvailableFormat
|
|
11254
|
+
* format: import('./formats.js').AvailableFormat,
|
|
11255
|
+
* types: Types
|
|
11146
11256
|
* }) => JamilihArray} viewUI
|
|
11147
11257
|
* @property {(info: {
|
|
11148
11258
|
* value?: StructuredCloneValue,
|
|
11149
11259
|
* typeNamespace?: string,
|
|
11150
11260
|
* bringIntoFocus?: boolean,
|
|
11151
11261
|
* format?: import('./formats.js').AvailableFormat,
|
|
11262
|
+
* formats?: import('./formats.js').default,
|
|
11263
|
+
* types: Types,
|
|
11152
11264
|
* resultType?: "keys"|"values"|"both",
|
|
11153
11265
|
* type?: AvailableType,
|
|
11154
11266
|
* arrayState?: string,
|
|
@@ -11168,7 +11280,10 @@ const Types = {};
|
|
|
11168
11280
|
* message?: string,
|
|
11169
11281
|
* valid: boolean
|
|
11170
11282
|
* }} [validate] Message will be used if validity is false.
|
|
11171
|
-
* @property {(info: {
|
|
11283
|
+
* @property {(info: {
|
|
11284
|
+
* topRoot: HTMLDivElement,
|
|
11285
|
+
* types: Types
|
|
11286
|
+
* }) => void} [validateAll] For
|
|
11172
11287
|
* validation of array and object references only.
|
|
11173
11288
|
* @property {{
|
|
11174
11289
|
* structuredCloning: {
|
|
@@ -11179,308 +11294,566 @@ const Types = {};
|
|
|
11179
11294
|
* context types
|
|
11180
11295
|
*/
|
|
11181
11296
|
|
|
11182
|
-
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
|
|
11186
|
-
|
|
11187
|
-
|
|
11188
|
-
|
|
11189
|
-
|
|
11190
|
-
|
|
11191
|
-
|
|
11192
|
-
|
|
11193
|
-
// regexp, as added properties on them are not being cloned (in Chrome
|
|
11194
|
-
// at least)
|
|
11195
|
-
object: objectType,
|
|
11196
|
-
date: dateType,
|
|
11297
|
+
/**
|
|
11298
|
+
* @typedef {"null"|"true"|"false"|"number"|"bigint"|"string"|"arrayReference"|
|
|
11299
|
+
* "objectReference"|"array"|"object"|"date"|"userObject"|"undef"|
|
|
11300
|
+
* "SpecialRealNumber"|"SpecialNumber"|"regexp"|"BooleanObject"|
|
|
11301
|
+
* "NumberObject"|"StringObject"|"map"|"set"|"file"|"filelist"|"blobHTML"|
|
|
11302
|
+
* "arraybuffer"|"arraybufferview"|"dataview"|"imagedata"|"imagebitmap"|
|
|
11303
|
+
* "int8array"|"uint8array"|"uint8clampedarray"|"int16array"|"uint16array"|
|
|
11304
|
+
* "int32array"|"uint32array"|"float32array"|"float64array"|"ValidDate"|
|
|
11305
|
+
* "arrayNonindexKeys"|"error"|"errors"|"blob"|"domexception"|"domrect"|
|
|
11306
|
+
* "dompoint"|"dommatrix"} AvailableType
|
|
11307
|
+
*/
|
|
11197
11308
|
|
|
11198
|
-
|
|
11199
|
-
|
|
11200
|
-
|
|
11201
|
-
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
|
|
11309
|
+
/**
|
|
11310
|
+
*
|
|
11311
|
+
*/
|
|
11312
|
+
class Types {
|
|
11313
|
+
/**
|
|
11314
|
+
*
|
|
11315
|
+
*/
|
|
11316
|
+
constructor () {
|
|
11317
|
+
this.formats = new Formats(); // Todo: Make customizable and test
|
|
11206
11318
|
|
|
11207
|
-
|
|
11208
|
-
|
|
11319
|
+
/** @type {CustomValidateAllReferences|undefined} */
|
|
11320
|
+
this.customValidateAllReferences = undefined;
|
|
11321
|
+
/**
|
|
11322
|
+
* @type {{
|
|
11323
|
+
* [key in AvailableType]: Partial<TypeObject>|string[]
|
|
11324
|
+
* }}
|
|
11325
|
+
*/
|
|
11326
|
+
this.availableTypes = {
|
|
11327
|
+
null: nullType,
|
|
11328
|
+
true: trueType,
|
|
11329
|
+
false: falseType,
|
|
11330
|
+
number: numberType,
|
|
11331
|
+
bigint: bigintType,
|
|
11332
|
+
string: stringType,
|
|
11333
|
+
arrayReference: arrayReferenceType,
|
|
11334
|
+
objectReference: objectReferenceType,
|
|
11335
|
+
array: arrayType,
|
|
11336
|
+
// Note: We don't do for BooleanObject/NumberObject/StringObject, date,
|
|
11337
|
+
// regexp, as added properties on them are not being cloned (in Chrome
|
|
11338
|
+
// at least)
|
|
11339
|
+
object: objectType,
|
|
11340
|
+
date: dateType,
|
|
11209
11341
|
|
|
11210
|
-
|
|
11211
|
-
|
|
11212
|
-
|
|
11213
|
-
|
|
11342
|
+
// This type is only for throwing upon cloning errors:
|
|
11343
|
+
// 'checkDataCloneException'
|
|
11344
|
+
// This type might be supported by evaluable JS or config
|
|
11345
|
+
// passed in:
|
|
11346
|
+
userObject: ['User objects'],
|
|
11347
|
+
undef: undefinedType,
|
|
11348
|
+
SpecialRealNumber: SpecialRealNumberSuperType,
|
|
11349
|
+
SpecialNumber: SpecialNumberSuperType,
|
|
11350
|
+
|
|
11351
|
+
error: errorType,
|
|
11352
|
+
errors: errorsSpecialType,
|
|
11353
|
+
|
|
11354
|
+
regexp: regexpType,
|
|
11355
|
+
BooleanObject: BooleanObjectType,
|
|
11356
|
+
NumberObject: NumberObjectType,
|
|
11357
|
+
StringObject: StringObjectType,
|
|
11358
|
+
|
|
11359
|
+
map: mapType,
|
|
11360
|
+
set: setType,
|
|
11361
|
+
|
|
11362
|
+
file: fileType,
|
|
11363
|
+
filelist: filelistType,
|
|
11364
|
+
blob: blobType,
|
|
11365
|
+
blobHTML: blobHTMLType,
|
|
11366
|
+
|
|
11367
|
+
domexception: domexceptionType,
|
|
11368
|
+
domrect: domrectType,
|
|
11369
|
+
dompoint: dompointType,
|
|
11370
|
+
dommatrix: dommatrixType,
|
|
11371
|
+
|
|
11372
|
+
arraybuffer: {
|
|
11373
|
+
option: ['ArrayBuffer']
|
|
11374
|
+
},
|
|
11375
|
+
arraybufferview: {
|
|
11376
|
+
option: ['ArrayBufferView']
|
|
11377
|
+
},
|
|
11378
|
+
dataview: {
|
|
11379
|
+
option: ['DataView']
|
|
11380
|
+
},
|
|
11381
|
+
imagedata: {
|
|
11382
|
+
option: ['ImageData']
|
|
11383
|
+
},
|
|
11384
|
+
imagebitmap: {
|
|
11385
|
+
option: ['ImageBitmap']
|
|
11386
|
+
},
|
|
11214
11387
|
|
|
11215
|
-
|
|
11216
|
-
|
|
11388
|
+
// Typed Arrays
|
|
11389
|
+
int8array: {
|
|
11390
|
+
option: ['Int8Array']
|
|
11391
|
+
},
|
|
11392
|
+
uint8array: {
|
|
11393
|
+
option: ['Uint8Array']
|
|
11394
|
+
},
|
|
11395
|
+
uint8clampedarray: {
|
|
11396
|
+
option: ['Uint8ClampedArray']
|
|
11397
|
+
},
|
|
11398
|
+
int16array: {
|
|
11399
|
+
option: ['Int16Array']
|
|
11400
|
+
},
|
|
11401
|
+
uint16array: {
|
|
11402
|
+
option: ['Uint16Array']
|
|
11403
|
+
},
|
|
11404
|
+
int32array: {
|
|
11405
|
+
option: ['Int32Array']
|
|
11406
|
+
},
|
|
11407
|
+
uint32array: {
|
|
11408
|
+
option: ['Uint32Array']
|
|
11409
|
+
},
|
|
11410
|
+
float32array: {
|
|
11411
|
+
option: ['Float32Array']
|
|
11412
|
+
},
|
|
11413
|
+
float64array: {
|
|
11414
|
+
option: ['Float64Array']
|
|
11415
|
+
},
|
|
11217
11416
|
|
|
11218
|
-
|
|
11219
|
-
|
|
11220
|
-
blob: blobType,
|
|
11221
|
-
blobHTML: blobHTMLType,
|
|
11417
|
+
// We're catching this instead of using this
|
|
11418
|
+
// sparseUndefined: sparseUndefinedType,
|
|
11222
11419
|
|
|
11223
|
-
|
|
11224
|
-
|
|
11225
|
-
|
|
11226
|
-
|
|
11420
|
+
ValidDate: {
|
|
11421
|
+
valid: true
|
|
11422
|
+
},
|
|
11423
|
+
/*
|
|
11424
|
+
sparseArrays: {
|
|
11425
|
+
sparse: true
|
|
11426
|
+
},
|
|
11427
|
+
*/
|
|
11428
|
+
arrayNonindexKeys: {
|
|
11429
|
+
sparse: true
|
|
11430
|
+
}
|
|
11431
|
+
};
|
|
11227
11432
|
|
|
11228
|
-
|
|
11229
|
-
|
|
11230
|
-
|
|
11231
|
-
|
|
11232
|
-
|
|
11233
|
-
|
|
11234
|
-
|
|
11235
|
-
|
|
11236
|
-
|
|
11237
|
-
|
|
11238
|
-
|
|
11239
|
-
|
|
11240
|
-
|
|
11241
|
-
|
|
11242
|
-
|
|
11433
|
+
/**
|
|
11434
|
+
* @param {[
|
|
11435
|
+
* copyFrom: AvailableType, copyTo: AvailableType
|
|
11436
|
+
* ][]} replacements
|
|
11437
|
+
* @returns {void}
|
|
11438
|
+
*/
|
|
11439
|
+
const copyTypeObjs = (replacements) => {
|
|
11440
|
+
replacements.forEach(([copyFrom, copyTo]) => {
|
|
11441
|
+
Object.assign(this.availableTypes[
|
|
11442
|
+
/** @type {AvailableType} */
|
|
11443
|
+
(copyTo)
|
|
11444
|
+
], this.availableTypes[
|
|
11445
|
+
/** @type {AvailableType} */
|
|
11446
|
+
(copyFrom)
|
|
11447
|
+
]);
|
|
11448
|
+
});
|
|
11449
|
+
};
|
|
11243
11450
|
|
|
11244
|
-
|
|
11245
|
-
|
|
11246
|
-
|
|
11247
|
-
|
|
11248
|
-
|
|
11249
|
-
|
|
11250
|
-
|
|
11251
|
-
|
|
11252
|
-
|
|
11253
|
-
|
|
11254
|
-
|
|
11255
|
-
option: ['Int16Array']
|
|
11256
|
-
},
|
|
11257
|
-
uint16array: {
|
|
11258
|
-
option: ['Uint16Array']
|
|
11259
|
-
},
|
|
11260
|
-
int32array: {
|
|
11261
|
-
option: ['Int32Array']
|
|
11262
|
-
},
|
|
11263
|
-
uint32array: {
|
|
11264
|
-
option: ['Uint32Array']
|
|
11265
|
-
},
|
|
11266
|
-
float32array: {
|
|
11267
|
-
option: ['Float32Array']
|
|
11268
|
-
},
|
|
11269
|
-
float64array: {
|
|
11270
|
-
option: ['Float64Array']
|
|
11271
|
-
},
|
|
11451
|
+
copyTypeObjs(
|
|
11452
|
+
[
|
|
11453
|
+
/** @type {[AvailableType, AvailableType]} */ (
|
|
11454
|
+
['date', 'ValidDate']
|
|
11455
|
+
),
|
|
11456
|
+
// 'sparseArrays'
|
|
11457
|
+
/** @type {[AvailableType, AvailableType]} */ (
|
|
11458
|
+
['array', 'arrayNonindexKeys']
|
|
11459
|
+
)
|
|
11460
|
+
]
|
|
11461
|
+
);
|
|
11272
11462
|
|
|
11273
|
-
|
|
11274
|
-
|
|
11463
|
+
/**
|
|
11464
|
+
* @type {{
|
|
11465
|
+
* [key: string]: {
|
|
11466
|
+
* [key: string]: {type: AvailableType, after: AvailableType}[]
|
|
11467
|
+
* }
|
|
11468
|
+
* }}
|
|
11469
|
+
*/
|
|
11470
|
+
this.contexts = {};
|
|
11471
|
+
Object.entries(this.availableTypes).forEach(([typ, typeObj]) => {
|
|
11472
|
+
const type = /** @type {AvailableType} */ (typ);
|
|
11473
|
+
const {stateDependent} = /** @type {TypeObject} */ (typeObj);
|
|
11474
|
+
if (stateDependent) {
|
|
11475
|
+
Object.entries(stateDependent).forEach(([
|
|
11476
|
+
format, formatStateDependent
|
|
11477
|
+
]) => {
|
|
11478
|
+
if (!this.contexts[format]) {
|
|
11479
|
+
this.contexts[format] = {};
|
|
11480
|
+
}
|
|
11481
|
+
const {contexts, after} = formatStateDependent;
|
|
11482
|
+
contexts.forEach((context) => {
|
|
11483
|
+
if (!this.contexts[format][context]) {
|
|
11484
|
+
this.contexts[format][context] = [];
|
|
11485
|
+
}
|
|
11486
|
+
this.contexts[format][context].push({type, after});
|
|
11487
|
+
});
|
|
11488
|
+
});
|
|
11489
|
+
}
|
|
11490
|
+
});
|
|
11491
|
+
}
|
|
11275
11492
|
|
|
11276
|
-
|
|
11277
|
-
|
|
11278
|
-
|
|
11279
|
-
|
|
11280
|
-
|
|
11281
|
-
|
|
11282
|
-
|
|
11283
|
-
|
|
11284
|
-
|
|
11285
|
-
|
|
11493
|
+
/**
|
|
11494
|
+
* @param {import('./formats.js').AvailableFormat} format
|
|
11495
|
+
* @param {StructuredCloneValue} record
|
|
11496
|
+
* @param {StateObject} stateObj
|
|
11497
|
+
* @returns {Promise<Element>}
|
|
11498
|
+
*/
|
|
11499
|
+
async getControlsForFormatAndValue (
|
|
11500
|
+
format, record, stateObj
|
|
11501
|
+
) {
|
|
11502
|
+
return await this.formats.getControlsForFormatAndValue(
|
|
11503
|
+
this, format, record, stateObj
|
|
11504
|
+
);
|
|
11286
11505
|
}
|
|
11287
|
-
};
|
|
11288
11506
|
|
|
11289
|
-
/**
|
|
11290
|
-
|
|
11291
|
-
*
|
|
11292
|
-
*
|
|
11293
|
-
*
|
|
11294
|
-
*
|
|
11295
|
-
*
|
|
11296
|
-
|
|
11297
|
-
|
|
11298
|
-
|
|
11299
|
-
|
|
11507
|
+
/**
|
|
11508
|
+
* @param {import('./formats.js').AvailableFormat} format
|
|
11509
|
+
* @param {string} context
|
|
11510
|
+
* @returns {{
|
|
11511
|
+
* type: AvailableType
|
|
11512
|
+
* after: AvailableType
|
|
11513
|
+
* }[]}
|
|
11514
|
+
*/
|
|
11515
|
+
getContextInfo (format, context) {
|
|
11516
|
+
return this.contexts[format][context];
|
|
11517
|
+
}
|
|
11300
11518
|
|
|
11301
|
-
/**
|
|
11302
|
-
|
|
11303
|
-
|
|
11304
|
-
|
|
11305
|
-
|
|
11306
|
-
|
|
11307
|
-
|
|
11308
|
-
|
|
11309
|
-
|
|
11310
|
-
|
|
11311
|
-
|
|
11312
|
-
|
|
11519
|
+
/** @type {GetValueForRoot} */
|
|
11520
|
+
getValueForRoot (root, stateObj, currentPath) {
|
|
11521
|
+
const typeObject = /** @type {TypeObject} */ (
|
|
11522
|
+
this.availableTypes[
|
|
11523
|
+
/** @type {AvailableType} */
|
|
11524
|
+
(Types.getTypeForRoot(root))
|
|
11525
|
+
]
|
|
11526
|
+
);
|
|
11527
|
+
return typeObject.getValue({
|
|
11528
|
+
root, stateObj, currentPath
|
|
11529
|
+
});
|
|
11530
|
+
}
|
|
11531
|
+
|
|
11532
|
+
/** @type {GetFormControlForRoot} */
|
|
11533
|
+
getFormControlForRoot (root) {
|
|
11534
|
+
const typeObj = /** @type {TypeObject} */ (this.availableTypes[
|
|
11313
11535
|
/** @type {AvailableType} */
|
|
11314
|
-
(
|
|
11536
|
+
(Types.getTypeForRoot(root))
|
|
11315
11537
|
]);
|
|
11316
|
-
|
|
11317
|
-
|
|
11538
|
+
/* istanbul ignore if -- All have except aliases */
|
|
11539
|
+
if (!typeObj.getInput) {
|
|
11540
|
+
return null;
|
|
11541
|
+
}
|
|
11542
|
+
return typeObj.getInput({root});
|
|
11543
|
+
}
|
|
11318
11544
|
|
|
11319
|
-
|
|
11320
|
-
|
|
11321
|
-
|
|
11322
|
-
|
|
11323
|
-
|
|
11324
|
-
|
|
11325
|
-
|
|
11326
|
-
|
|
11327
|
-
|
|
11328
|
-
|
|
11329
|
-
|
|
11545
|
+
/** @type {GetValueFromRootAncestor} */
|
|
11546
|
+
getValueFromRootAncestor (selOrEl, stateObj) {
|
|
11547
|
+
return this.getValueForRoot(
|
|
11548
|
+
/** @type {RootElement} */
|
|
11549
|
+
($e(selOrEl, 'div[data-type]')),
|
|
11550
|
+
{
|
|
11551
|
+
...stateObj,
|
|
11552
|
+
formats: this.formats
|
|
11553
|
+
}
|
|
11554
|
+
);
|
|
11555
|
+
}
|
|
11330
11556
|
|
|
11331
|
-
|
|
11332
|
-
|
|
11333
|
-
};
|
|
11557
|
+
/** @type {GetFormControlFromRootAncestor} */
|
|
11558
|
+
getFormControlFromRootAncestor (selOrEl) {
|
|
11559
|
+
const root = /** @type {RootElement} */ ($e(selOrEl, 'div[data-type]'));
|
|
11560
|
+
if (!root) {
|
|
11561
|
+
return null;
|
|
11562
|
+
}
|
|
11563
|
+
return this.getFormControlForRoot(root);
|
|
11564
|
+
}
|
|
11334
11565
|
|
|
11335
|
-
/**
|
|
11336
|
-
|
|
11337
|
-
|
|
11338
|
-
|
|
11339
|
-
|
|
11340
|
-
|
|
11341
|
-
|
|
11342
|
-
|
|
11566
|
+
/** @type {GetOptionForType} */
|
|
11567
|
+
getOptionForType (type) {
|
|
11568
|
+
/** @type {[string, {value?: AvailableType, title?: string}?]} */
|
|
11569
|
+
const optInfo = [
|
|
11570
|
+
...(/** @type {TypeObject} */ (
|
|
11571
|
+
this.availableTypes[type]
|
|
11572
|
+
)).option
|
|
11573
|
+
];
|
|
11574
|
+
optInfo[1] = {value: type, ...(optInfo[1])};
|
|
11575
|
+
return /** @type {[string, {value: AvailableType, title?: string}]} */ (
|
|
11576
|
+
optInfo
|
|
11577
|
+
);
|
|
11578
|
+
}
|
|
11343
11579
|
|
|
11344
|
-
/**
|
|
11345
|
-
|
|
11346
|
-
|
|
11347
|
-
|
|
11348
|
-
|
|
11349
|
-
|
|
11350
|
-
|
|
11351
|
-
|
|
11352
|
-
|
|
11353
|
-
|
|
11354
|
-
|
|
11355
|
-
|
|
11356
|
-
* expectArrayReferent: boolean
|
|
11357
|
-
* }},
|
|
11358
|
-
* handlingReference?: boolean
|
|
11359
|
-
* }} StateObject
|
|
11360
|
-
*/
|
|
11361
|
-
|
|
11362
|
-
Types.getValueForRoot = (root, stateObj, currentPath) => {
|
|
11363
|
-
const typeObject = /** @type {TypeObject} */ (
|
|
11364
|
-
Types.availableTypes[
|
|
11365
|
-
/** @type {AvailableType} */
|
|
11366
|
-
(Types.getTypeForRoot(root))
|
|
11367
|
-
]
|
|
11368
|
-
);
|
|
11369
|
-
return typeObject.getValue({
|
|
11370
|
-
root, stateObj, currentPath
|
|
11371
|
-
});
|
|
11372
|
-
};
|
|
11580
|
+
/** @type {GetTypeOptionsForFormatAndState} */
|
|
11581
|
+
getTypeOptionsForFormatAndState (format, parserState) {
|
|
11582
|
+
const typesForFormatAndState = this.formats.getTypesForFormatAndState(
|
|
11583
|
+
this, format, parserState
|
|
11584
|
+
);
|
|
11585
|
+
if (!typesForFormatAndState) {
|
|
11586
|
+
throw new Error('Unexpected type for format and state');
|
|
11587
|
+
}
|
|
11588
|
+
return typesForFormatAndState.map((type) => {
|
|
11589
|
+
return this.getOptionForType(type);
|
|
11590
|
+
});
|
|
11591
|
+
}
|
|
11373
11592
|
|
|
11374
|
-
|
|
11375
|
-
|
|
11376
|
-
|
|
11377
|
-
|
|
11378
|
-
|
|
11379
|
-
|
|
11380
|
-
|
|
11381
|
-
|
|
11593
|
+
/** @type {GetUIForModeAndType} */
|
|
11594
|
+
getUIForModeAndType ({
|
|
11595
|
+
readonly, resultType, typeNamespace, type, topRoot, bringIntoFocus,
|
|
11596
|
+
buildTypeChoices, format, schemaContent, schemaState, value, hasValue,
|
|
11597
|
+
replaced
|
|
11598
|
+
}) {
|
|
11599
|
+
const typeObj = /** @type {TypeObject} */ (this.availableTypes[type]);
|
|
11600
|
+
const arg = hasValue
|
|
11601
|
+
? {
|
|
11602
|
+
typeNamespace, type, buildTypeChoices,
|
|
11603
|
+
format, schemaContent, schemaState,
|
|
11604
|
+
resultType, topRoot, bringIntoFocus, value,
|
|
11605
|
+
replaced,
|
|
11606
|
+
types: this
|
|
11607
|
+
}
|
|
11608
|
+
: {
|
|
11609
|
+
typeNamespace, type, buildTypeChoices,
|
|
11610
|
+
format, schemaContent, schemaState,
|
|
11611
|
+
resultType, topRoot, bringIntoFocus,
|
|
11612
|
+
replaced,
|
|
11613
|
+
types: this
|
|
11614
|
+
};
|
|
11615
|
+
const root = /** @type {HTMLDivElement} */ (jml(
|
|
11616
|
+
...(readonly
|
|
11617
|
+
? typeObj.viewUI(arg)
|
|
11618
|
+
: typeObj.editUI(arg))
|
|
11619
|
+
));
|
|
11620
|
+
if (!readonly && typeObj.validate) {
|
|
11621
|
+
const formControl = typeObj.getInput({root});
|
|
11622
|
+
formControl.addEventListener('input', () => {
|
|
11623
|
+
this.validate({type, root, topRoot});
|
|
11624
|
+
});
|
|
11625
|
+
}
|
|
11626
|
+
return root;
|
|
11382
11627
|
}
|
|
11383
|
-
return typeObj.getInput({root});
|
|
11384
|
-
};
|
|
11385
11628
|
|
|
11386
|
-
|
|
11387
|
-
|
|
11388
|
-
|
|
11389
|
-
(
|
|
11390
|
-
|
|
11391
|
-
|
|
11392
|
-
}
|
|
11629
|
+
/** @type {ValidateAllReferences} */
|
|
11630
|
+
validateAllReferences ({topRoot}) {
|
|
11631
|
+
/* istanbul ignore if -- Unreachable? */
|
|
11632
|
+
if (!topRoot) {
|
|
11633
|
+
console.log('No references present');
|
|
11634
|
+
return;
|
|
11635
|
+
}
|
|
11393
11636
|
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
|
|
11397
|
-
|
|
11637
|
+
// Could just hard-code arrayReference and objectReference,
|
|
11638
|
+
// but we'll try to avoid depending on specific types
|
|
11639
|
+
Object.values(this.availableTypes).forEach((typeObj) => {
|
|
11640
|
+
const typeObject = /** @type {TypeObject} */ (typeObj);
|
|
11641
|
+
if (typeObject.validateAll) {
|
|
11642
|
+
typeObject.validateAll({topRoot, types: this});
|
|
11643
|
+
}
|
|
11644
|
+
});
|
|
11645
|
+
|
|
11646
|
+
if (this.customValidateAllReferences) {
|
|
11647
|
+
this.customValidateAllReferences({topRoot});
|
|
11648
|
+
}
|
|
11398
11649
|
}
|
|
11399
|
-
return Types.getFormControlForRoot(root);
|
|
11400
|
-
};
|
|
11401
11650
|
|
|
11402
|
-
|
|
11403
|
-
|
|
11404
|
-
|
|
11405
|
-
|
|
11406
|
-
|
|
11407
|
-
|
|
11408
|
-
|
|
11409
|
-
|
|
11410
|
-
|
|
11411
|
-
|
|
11412
|
-
|
|
11413
|
-
|
|
11414
|
-
|
|
11415
|
-
|
|
11416
|
-
|
|
11417
|
-
}
|
|
11651
|
+
/** @type {Validate} */
|
|
11652
|
+
validate ({type, root, topRoot}) {
|
|
11653
|
+
const typeObj = /** @type {TypeObject} */ (this.availableTypes[type]);
|
|
11654
|
+
// Todo (low): We limit for now to input boxes which have `validate`
|
|
11655
|
+
if (typeObj.validate) {
|
|
11656
|
+
const {valid, message} = typeObj.validate({root, topRoot});
|
|
11657
|
+
const formControl = typeObj.getInput({root});
|
|
11658
|
+
formControl.setCustomValidity(
|
|
11659
|
+
valid
|
|
11660
|
+
? ''
|
|
11661
|
+
/* istanbul ignore next -- Should always have a message */
|
|
11662
|
+
: message || 'Invalid'
|
|
11663
|
+
);
|
|
11664
|
+
formControl.reportValidity();
|
|
11665
|
+
return valid;
|
|
11666
|
+
}
|
|
11667
|
+
return true;
|
|
11668
|
+
}
|
|
11418
11669
|
|
|
11419
|
-
|
|
11420
|
-
|
|
11421
|
-
|
|
11422
|
-
|
|
11423
|
-
|
|
11424
|
-
|
|
11670
|
+
/** @type {SetValue} */
|
|
11671
|
+
setValue ({type, root, value}) {
|
|
11672
|
+
const typeObj = /** @type {TypeObject} */ (this.availableTypes[type]);
|
|
11673
|
+
if (typeObj.setValue) {
|
|
11674
|
+
typeObj.setValue({root, value});
|
|
11675
|
+
}
|
|
11425
11676
|
}
|
|
11426
|
-
return typesForFormatAndState.map((type) => {
|
|
11427
|
-
return Types.getOptionForType(type);
|
|
11428
|
-
});
|
|
11429
|
-
};
|
|
11430
11677
|
|
|
11431
|
-
|
|
11432
|
-
|
|
11433
|
-
|
|
11434
|
-
|
|
11435
|
-
|
|
11436
|
-
|
|
11437
|
-
|
|
11438
|
-
|
|
11439
|
-
|
|
11440
|
-
|
|
11441
|
-
|
|
11442
|
-
|
|
11678
|
+
// Todo (low): Should really add real parser
|
|
11679
|
+
// Todo (low): Implement `getStringForValue` (e.g., to expose feature for
|
|
11680
|
+
// bookmarking object value currently in view); would not be
|
|
11681
|
+
// enough to iterate DOM to get string URL as we'd also like
|
|
11682
|
+
// the ability to have arbitrary JSON/structuredCloning sent to this
|
|
11683
|
+
// URL from other sites/programs (can currently pass in JSON
|
|
11684
|
+
// format to the URL, but that is still expecting our Router
|
|
11685
|
+
// string syntax)
|
|
11686
|
+
|
|
11687
|
+
/** @type {GetValueForString} */
|
|
11688
|
+
getValueForString (s, {
|
|
11689
|
+
format, state, endMatchTypeObjs = [], firstRun = true,
|
|
11690
|
+
rootHolder = [], parent, parentPath
|
|
11691
|
+
}) {
|
|
11692
|
+
const allowedTypes = this.formats.getTypesForFormatAndState(
|
|
11693
|
+
this, format, state
|
|
11694
|
+
);
|
|
11695
|
+
if (!allowedTypes) {
|
|
11696
|
+
throw new Error('Could not get types for format and state');
|
|
11443
11697
|
}
|
|
11444
|
-
|
|
11445
|
-
|
|
11446
|
-
|
|
11447
|
-
|
|
11448
|
-
replaced
|
|
11449
|
-
};
|
|
11450
|
-
const root = /** @type {HTMLDivElement} */ (jml(
|
|
11451
|
-
...(readonly
|
|
11452
|
-
? typeObj.viewUI(arg)
|
|
11453
|
-
: typeObj.editUI(arg))
|
|
11454
|
-
));
|
|
11455
|
-
if (!readonly && typeObj.validate) {
|
|
11456
|
-
const formControl = typeObj.getInput({root});
|
|
11457
|
-
formControl.addEventListener('input', () => {
|
|
11458
|
-
Types.validate({type, root, topRoot});
|
|
11698
|
+
const allowedTypeObjs = Object.entries(
|
|
11699
|
+
this.availableTypes
|
|
11700
|
+
).filter(([type]) => {
|
|
11701
|
+
return allowedTypes.includes(/** @type {AvailableType} */ (type));
|
|
11459
11702
|
});
|
|
11460
|
-
|
|
11461
|
-
return root;
|
|
11462
|
-
};
|
|
11703
|
+
const allowedTypeObjsVals = allowedTypeObjs.map(([, arr]) => arr);
|
|
11463
11704
|
|
|
11464
|
-
|
|
11465
|
-
|
|
11466
|
-
|
|
11467
|
-
|
|
11468
|
-
|
|
11469
|
-
|
|
11470
|
-
if (!Types.contexts[format]) {
|
|
11471
|
-
Types.contexts[format] = {};
|
|
11705
|
+
const reduced = allowedTypeObjsVals.reduce((array, typObj) => {
|
|
11706
|
+
const typeObj = /** @type {TypeObject} */ (typObj);
|
|
11707
|
+
let arr = /** @type {string[]} */ (array);
|
|
11708
|
+
if (typeObj.regexEndings) {
|
|
11709
|
+
arr.push(...typeObj.regexEndings);
|
|
11710
|
+
arr = [...new Set(arr)];
|
|
11472
11711
|
}
|
|
11473
|
-
|
|
11474
|
-
|
|
11475
|
-
|
|
11476
|
-
|
|
11712
|
+
return arr;
|
|
11713
|
+
}, []);
|
|
11714
|
+
const endings = '|' + /** @type {string[]} */ (
|
|
11715
|
+
reduced
|
|
11716
|
+
).map((str) => escapeRegex(str)).join('|');
|
|
11717
|
+
|
|
11718
|
+
/**
|
|
11719
|
+
* @type {RegExpMatchArray|boolean|null}
|
|
11720
|
+
*/
|
|
11721
|
+
let match = null;
|
|
11722
|
+
let found = allowedTypeObjs.find(([/* _type */, typObj]) => {
|
|
11723
|
+
const typeObj = /** @type {TypeObject} */ (typObj);
|
|
11724
|
+
let {stringRegex} = typeObj;
|
|
11725
|
+
if (typeof typeObj.stringRegex === 'function') {
|
|
11726
|
+
stringRegex = typeObj.stringRegex(true);
|
|
11727
|
+
}
|
|
11728
|
+
stringRegex = stringRegex
|
|
11729
|
+
// Strip off terminal (dollar sign) when matching substrings
|
|
11730
|
+
? new RegExp(
|
|
11731
|
+
/** @type {RegExp} */ (
|
|
11732
|
+
stringRegex
|
|
11733
|
+
).source.slice(0, -1) + '(?=$' + endings + ')',
|
|
11734
|
+
'u'
|
|
11735
|
+
)
|
|
11736
|
+
: stringRegex;
|
|
11737
|
+
match = Boolean(stringRegex && s) && s.match(
|
|
11738
|
+
/** @type {RegExp} */ (stringRegex)
|
|
11739
|
+
);
|
|
11740
|
+
return match;
|
|
11741
|
+
});
|
|
11742
|
+
|
|
11743
|
+
let beginOnly = false;
|
|
11744
|
+
if (found === undefined) {
|
|
11745
|
+
found = allowedTypeObjs.find(([/* _type */, typObj]) => {
|
|
11746
|
+
const typeObj = /** @type {TypeObject} */ (typObj);
|
|
11747
|
+
const {stringRegexBegin} = typeObj;
|
|
11748
|
+
match = Boolean(stringRegexBegin && s) && s.match(
|
|
11749
|
+
/** @type {RegExp} */ (stringRegexBegin)
|
|
11750
|
+
);
|
|
11751
|
+
if (match) {
|
|
11752
|
+
beginOnly = true;
|
|
11753
|
+
endMatchTypeObjs.push(typeObj);
|
|
11477
11754
|
}
|
|
11478
|
-
|
|
11755
|
+
return match;
|
|
11479
11756
|
});
|
|
11480
|
-
}
|
|
11757
|
+
}
|
|
11758
|
+
let assign = true;
|
|
11759
|
+
if (found !== undefined) {
|
|
11760
|
+
// The `found` is evaluated again, so sets `match` to non-null
|
|
11761
|
+
const mtch = /** @type {RegExpMatchArray} */ (
|
|
11762
|
+
/** @type {unknown} */ (match)
|
|
11763
|
+
);
|
|
11764
|
+
const [content, innerContent] = mtch;
|
|
11765
|
+
let remnant = s.slice(content.length);
|
|
11766
|
+
s = s.slice(0, content.length);
|
|
11767
|
+
// console.log('s0', s, '::', remnant, match);
|
|
11768
|
+
let valObj;
|
|
11769
|
+
try {
|
|
11770
|
+
valObj = /** @type {TypeObject} */ (found[1]).toValue(
|
|
11771
|
+
mtch.groups?.innerContent || innerContent || s, {
|
|
11772
|
+
types: this,
|
|
11773
|
+
format,
|
|
11774
|
+
match,
|
|
11775
|
+
endMatchTypeObjs,
|
|
11776
|
+
remnant,
|
|
11777
|
+
rootHolder,
|
|
11778
|
+
parent,
|
|
11779
|
+
parentPath
|
|
11780
|
+
}
|
|
11781
|
+
);
|
|
11782
|
+
/* istanbul ignore next -- Good regexes should prevent */
|
|
11783
|
+
} catch (e) {
|
|
11784
|
+
/* istanbul ignore next -- Good regexes should prevent */
|
|
11785
|
+
console.log('eee', e);
|
|
11786
|
+
/* istanbul ignore next -- Good regexes should prevent */
|
|
11787
|
+
throw e;
|
|
11788
|
+
}
|
|
11789
|
+
if (valObj.assign === false) {
|
|
11790
|
+
assign = false;
|
|
11791
|
+
}
|
|
11792
|
+
const {value} = valObj;
|
|
11793
|
+
if (valObj.remnant !== undefined) {
|
|
11794
|
+
({remnant} = valObj);
|
|
11795
|
+
}
|
|
11796
|
+
|
|
11797
|
+
if (beginOnly && endMatchTypeObjs.length) {
|
|
11798
|
+
const endMatch = remnant.match(
|
|
11799
|
+
/** @type {RegExp} */ (/** @type {TypeObject} */ (
|
|
11800
|
+
endMatchTypeObjs.at(-1)
|
|
11801
|
+
).stringRegexEnd)
|
|
11802
|
+
);
|
|
11803
|
+
if (endMatch) {
|
|
11804
|
+
endMatchTypeObjs.pop(); // Safe now to extract
|
|
11805
|
+
remnant = remnant.slice(endMatch[0].length);
|
|
11806
|
+
}
|
|
11807
|
+
}
|
|
11808
|
+
if (firstRun) {
|
|
11809
|
+
const typeson = new c().register(
|
|
11810
|
+
ae
|
|
11811
|
+
);
|
|
11812
|
+
try {
|
|
11813
|
+
const topRoot = typeson.revive(value);
|
|
11814
|
+
rootHolder.forEach(([type, parent, parentPath, path]) => {
|
|
11815
|
+
const typeObject = this.availableTypes[
|
|
11816
|
+
/** @type {AvailableType} */ (type + 'Reference')
|
|
11817
|
+
];
|
|
11818
|
+
|
|
11819
|
+
// @ts-expect-error Reference method exists
|
|
11820
|
+
const val = typeObject.resolveReference(path, topRoot);
|
|
11821
|
+
const basicType = getJSONType(val);
|
|
11822
|
+
// eslint-disable-next-line @stylistic/max-len -- Long
|
|
11823
|
+
/* istanbul ignore else -- Successful reference always an object/array? */
|
|
11824
|
+
if (
|
|
11825
|
+
['array', 'object'].includes(type) && basicType === type
|
|
11826
|
+
) {
|
|
11827
|
+
/** @type {{[key: string]: any}} */ (
|
|
11828
|
+
parent
|
|
11829
|
+
)[/** @type {string|number} */ (parentPath)] = val;
|
|
11830
|
+
}
|
|
11831
|
+
});
|
|
11832
|
+
return [topRoot, remnant, beginOnly, assign];
|
|
11833
|
+
} catch (err) {
|
|
11834
|
+
console.log('failed Typeson revival', err);
|
|
11835
|
+
}
|
|
11836
|
+
}
|
|
11837
|
+
return [value, remnant, beginOnly, assign];
|
|
11838
|
+
}
|
|
11839
|
+
throw new Error('Bad parsing data');
|
|
11481
11840
|
}
|
|
11482
|
-
});
|
|
11483
11841
|
|
|
11842
|
+
/**
|
|
11843
|
+
* @param {AvailableType} type
|
|
11844
|
+
* @returns {Partial<TypeObject>|string[]}
|
|
11845
|
+
*/
|
|
11846
|
+
getTypeObject (type) {
|
|
11847
|
+
return this.availableTypes[type];
|
|
11848
|
+
}
|
|
11849
|
+
}
|
|
11850
|
+
|
|
11851
|
+
/** @type {GetTypeForRoot} */
|
|
11852
|
+
Types.getTypeForRoot = (root) => {
|
|
11853
|
+
return String(root ? root.dataset.type : root);
|
|
11854
|
+
};
|
|
11855
|
+
|
|
11856
|
+
/** @type {ValidValuesSet} */
|
|
11484
11857
|
Types.validValuesSet = ({form, typeNamespace, keySelectClass}) => {
|
|
11485
11858
|
// If form is hidden, don't list errors by default
|
|
11486
11859
|
if (!form.offsetParent ||
|
|
@@ -11514,57 +11887,6 @@ Types.validValuesSet = ({form, typeNamespace, keySelectClass}) => {
|
|
|
11514
11887
|
);
|
|
11515
11888
|
};
|
|
11516
11889
|
|
|
11517
|
-
/**
|
|
11518
|
-
* Any other possibilities than `div`?
|
|
11519
|
-
* @typedef {HTMLDivElement} RootElement
|
|
11520
|
-
*/
|
|
11521
|
-
|
|
11522
|
-
Types.validateAllReferences = ({topRoot}) => {
|
|
11523
|
-
/* istanbul ignore if -- Unreachable? */
|
|
11524
|
-
if (!topRoot) {
|
|
11525
|
-
console.log('No references present');
|
|
11526
|
-
return;
|
|
11527
|
-
}
|
|
11528
|
-
|
|
11529
|
-
// Could just hard-code arrayReference and objectReference,
|
|
11530
|
-
// but we'll try to avoid depending on specific types
|
|
11531
|
-
Object.values(Types.availableTypes).forEach((typeObj) => {
|
|
11532
|
-
const typeObject = /** @type {TypeObject} */ (typeObj);
|
|
11533
|
-
if (typeObject.validateAll) {
|
|
11534
|
-
typeObject.validateAll({topRoot});
|
|
11535
|
-
}
|
|
11536
|
-
});
|
|
11537
|
-
|
|
11538
|
-
if (Types.customValidateAllReferences) {
|
|
11539
|
-
Types.customValidateAllReferences({topRoot});
|
|
11540
|
-
}
|
|
11541
|
-
};
|
|
11542
|
-
|
|
11543
|
-
Types.validate = ({type, root, topRoot}) => {
|
|
11544
|
-
const typeObj = /** @type {TypeObject} */ (Types.availableTypes[type]);
|
|
11545
|
-
// Todo (low): We limit for now to input boxes which have `validate`
|
|
11546
|
-
if (typeObj.validate) {
|
|
11547
|
-
const {valid, message} = typeObj.validate({root, topRoot});
|
|
11548
|
-
const formControl = typeObj.getInput({root});
|
|
11549
|
-
formControl.setCustomValidity(
|
|
11550
|
-
valid
|
|
11551
|
-
? ''
|
|
11552
|
-
/* istanbul ignore next -- Should always have a message */
|
|
11553
|
-
: message || 'Invalid'
|
|
11554
|
-
);
|
|
11555
|
-
formControl.reportValidity();
|
|
11556
|
-
return valid;
|
|
11557
|
-
}
|
|
11558
|
-
return true;
|
|
11559
|
-
};
|
|
11560
|
-
|
|
11561
|
-
Types.setValue = ({type, root, value}) => {
|
|
11562
|
-
const typeObj = /** @type {TypeObject} */ (Types.availableTypes[type]);
|
|
11563
|
-
if (typeObj.setValue) {
|
|
11564
|
-
typeObj.setValue({root, value});
|
|
11565
|
-
}
|
|
11566
|
-
};
|
|
11567
|
-
|
|
11568
11890
|
/**
|
|
11569
11891
|
*
|
|
11570
11892
|
* @param {string} str
|
|
@@ -11575,168 +11897,6 @@ function escapeRegex (str) {
|
|
|
11575
11897
|
replaceAll(/[.\\+*?^[\]$(){}=!<>|:-]/gu, '\\$&');
|
|
11576
11898
|
}
|
|
11577
11899
|
|
|
11578
|
-
// Todo (low): Should really add real parser
|
|
11579
|
-
// Todo (low): Implement `getStringForValue` (e.g., to expose feature for
|
|
11580
|
-
// bookmarking object value currently in view); would not be
|
|
11581
|
-
// enough to iterate DOM to get string URL as we'd also like
|
|
11582
|
-
// the ability to have arbitrary JSON/structuredCloning sent to this
|
|
11583
|
-
// URL from other sites/programs (can currently pass in JSON
|
|
11584
|
-
// format to the URL, but that is still expecting our Router
|
|
11585
|
-
// string syntax)
|
|
11586
|
-
|
|
11587
|
-
Types.getValueForString = (s, {
|
|
11588
|
-
format, state, endMatchTypeObjs = [], firstRun = true,
|
|
11589
|
-
rootHolder = [], parent, parentPath
|
|
11590
|
-
}) => {
|
|
11591
|
-
const allowedTypes = Types.getTypesForFormatAndState(format, state);
|
|
11592
|
-
if (!allowedTypes) {
|
|
11593
|
-
throw new Error('Could not get types for format and state');
|
|
11594
|
-
}
|
|
11595
|
-
const allowedTypeObjs = Object.entries(
|
|
11596
|
-
Types.availableTypes
|
|
11597
|
-
).filter(([type]) => {
|
|
11598
|
-
return allowedTypes.includes(/** @type {AvailableType} */ (type));
|
|
11599
|
-
});
|
|
11600
|
-
const allowedTypeObjsVals = allowedTypeObjs.map(([, arr]) => arr);
|
|
11601
|
-
|
|
11602
|
-
const reduced = allowedTypeObjsVals.reduce((array, typObj) => {
|
|
11603
|
-
const typeObj = /** @type {TypeObject} */ (typObj);
|
|
11604
|
-
let arr = /** @type {string[]} */ (array);
|
|
11605
|
-
if (typeObj.regexEndings) {
|
|
11606
|
-
arr.push(...typeObj.regexEndings);
|
|
11607
|
-
arr = [...new Set(arr)];
|
|
11608
|
-
}
|
|
11609
|
-
return arr;
|
|
11610
|
-
}, []);
|
|
11611
|
-
const endings = '|' + /** @type {string[]} */ (
|
|
11612
|
-
reduced
|
|
11613
|
-
).map((str) => escapeRegex(str)).join('|');
|
|
11614
|
-
|
|
11615
|
-
/**
|
|
11616
|
-
* @type {RegExpMatchArray|boolean|null}
|
|
11617
|
-
*/
|
|
11618
|
-
let match = null;
|
|
11619
|
-
let found = allowedTypeObjs.find(([/* _type */, typObj]) => {
|
|
11620
|
-
const typeObj = /** @type {TypeObject} */ (typObj);
|
|
11621
|
-
let {stringRegex} = typeObj;
|
|
11622
|
-
if (typeof typeObj.stringRegex === 'function') {
|
|
11623
|
-
stringRegex = typeObj.stringRegex(true);
|
|
11624
|
-
}
|
|
11625
|
-
stringRegex = stringRegex
|
|
11626
|
-
// Strip off terminal (dollar sign) when matching substrings
|
|
11627
|
-
? new RegExp(
|
|
11628
|
-
/** @type {RegExp} */ (
|
|
11629
|
-
stringRegex
|
|
11630
|
-
).source.slice(0, -1) + '(?=$' + endings + ')',
|
|
11631
|
-
'u'
|
|
11632
|
-
)
|
|
11633
|
-
: stringRegex;
|
|
11634
|
-
match = Boolean(stringRegex && s) && s.match(
|
|
11635
|
-
/** @type {RegExp} */ (stringRegex)
|
|
11636
|
-
);
|
|
11637
|
-
return match;
|
|
11638
|
-
});
|
|
11639
|
-
|
|
11640
|
-
let beginOnly = false;
|
|
11641
|
-
if (found === undefined) {
|
|
11642
|
-
found = allowedTypeObjs.find(([/* _type */, typObj]) => {
|
|
11643
|
-
const typeObj = /** @type {TypeObject} */ (typObj);
|
|
11644
|
-
const {stringRegexBegin} = typeObj;
|
|
11645
|
-
match = Boolean(stringRegexBegin && s) && s.match(
|
|
11646
|
-
/** @type {RegExp} */ (stringRegexBegin)
|
|
11647
|
-
);
|
|
11648
|
-
if (match) {
|
|
11649
|
-
beginOnly = true;
|
|
11650
|
-
endMatchTypeObjs.push(typeObj);
|
|
11651
|
-
}
|
|
11652
|
-
return match;
|
|
11653
|
-
});
|
|
11654
|
-
}
|
|
11655
|
-
let assign = true;
|
|
11656
|
-
if (found !== undefined) {
|
|
11657
|
-
// The `found` is evaluated again, so sets `match` to non-null
|
|
11658
|
-
const mtch = /** @type {RegExpMatchArray} */ (
|
|
11659
|
-
/** @type {unknown} */ (match)
|
|
11660
|
-
);
|
|
11661
|
-
const [content, innerContent] = mtch;
|
|
11662
|
-
let remnant = s.slice(content.length);
|
|
11663
|
-
s = s.slice(0, content.length);
|
|
11664
|
-
// console.log('s0', s, '::', remnant, match);
|
|
11665
|
-
let valObj;
|
|
11666
|
-
try {
|
|
11667
|
-
valObj = /** @type {TypeObject} */ (found[1]).toValue(
|
|
11668
|
-
mtch.groups?.innerContent || innerContent || s, {
|
|
11669
|
-
format,
|
|
11670
|
-
match,
|
|
11671
|
-
endMatchTypeObjs,
|
|
11672
|
-
remnant,
|
|
11673
|
-
rootHolder,
|
|
11674
|
-
parent,
|
|
11675
|
-
parentPath
|
|
11676
|
-
}
|
|
11677
|
-
);
|
|
11678
|
-
/* istanbul ignore next -- Good regexes should prevent */
|
|
11679
|
-
} catch (e) {
|
|
11680
|
-
/* istanbul ignore next -- Good regexes should prevent */
|
|
11681
|
-
console.log('eee', e);
|
|
11682
|
-
/* istanbul ignore next -- Good regexes should prevent */
|
|
11683
|
-
throw e;
|
|
11684
|
-
}
|
|
11685
|
-
if (valObj.assign === false) {
|
|
11686
|
-
assign = false;
|
|
11687
|
-
}
|
|
11688
|
-
const {value} = valObj;
|
|
11689
|
-
if (valObj.remnant !== undefined) {
|
|
11690
|
-
({remnant} = valObj);
|
|
11691
|
-
}
|
|
11692
|
-
|
|
11693
|
-
if (beginOnly && endMatchTypeObjs.length) {
|
|
11694
|
-
const endMatch = remnant.match(
|
|
11695
|
-
/** @type {RegExp} */ (/** @type {TypeObject} */ (
|
|
11696
|
-
endMatchTypeObjs.at(-1)
|
|
11697
|
-
).stringRegexEnd)
|
|
11698
|
-
);
|
|
11699
|
-
if (endMatch) {
|
|
11700
|
-
endMatchTypeObjs.pop(); // Safe now to extract
|
|
11701
|
-
remnant = remnant.slice(endMatch[0].length);
|
|
11702
|
-
}
|
|
11703
|
-
}
|
|
11704
|
-
if (firstRun) {
|
|
11705
|
-
const typeson = new c().register(
|
|
11706
|
-
ae
|
|
11707
|
-
);
|
|
11708
|
-
try {
|
|
11709
|
-
const topRoot = typeson.revive(value);
|
|
11710
|
-
rootHolder.forEach(([type, parent, parentPath, path]) => {
|
|
11711
|
-
const typeObject = Types.availableTypes[
|
|
11712
|
-
/** @type {AvailableType} */ (type + 'Reference')
|
|
11713
|
-
];
|
|
11714
|
-
|
|
11715
|
-
// @ts-expect-error Reference method exists
|
|
11716
|
-
const val = typeObject.resolveReference(path, topRoot);
|
|
11717
|
-
const basicType = getJSONType(val);
|
|
11718
|
-
// eslint-disable-next-line @stylistic/max-len -- Long
|
|
11719
|
-
/* istanbul ignore else -- Successful reference always an object/array? */
|
|
11720
|
-
if (
|
|
11721
|
-
['array', 'object'].includes(type) && basicType === type
|
|
11722
|
-
) {
|
|
11723
|
-
/** @type {{[key: string]: any}} */ (
|
|
11724
|
-
parent
|
|
11725
|
-
)[/** @type {string|number} */ (parentPath)] = val;
|
|
11726
|
-
}
|
|
11727
|
-
});
|
|
11728
|
-
return [topRoot, remnant, beginOnly, assign];
|
|
11729
|
-
} catch (err) {
|
|
11730
|
-
console.log('failed Typeson revival', err);
|
|
11731
|
-
}
|
|
11732
|
-
}
|
|
11733
|
-
return [value, remnant, beginOnly, assign];
|
|
11734
|
-
}
|
|
11735
|
-
throw new Error('Bad parsing data');
|
|
11736
|
-
};
|
|
11737
|
-
|
|
11738
|
-
var Types$1 = Types;
|
|
11739
|
-
|
|
11740
11900
|
/**
|
|
11741
11901
|
* @callback TypeRootGetter
|
|
11742
11902
|
* @returns {HTMLDivElement|null}
|
|
@@ -11823,6 +11983,8 @@ const getFormatAndSchemaChoices = ({schema, hasKeyPath} = {}) => {
|
|
|
11823
11983
|
* plain object).
|
|
11824
11984
|
* @param {string} [cfg.typeNamespace] Used to prevent conflicts with other
|
|
11825
11985
|
* instances of typeChoices on the page
|
|
11986
|
+
* @param {import('./formats.js').default} cfg.formats
|
|
11987
|
+
* @param {import('./types.js').default} [cfg.types]
|
|
11826
11988
|
* @returns {{
|
|
11827
11989
|
* formatChoices: FormatChoices,
|
|
11828
11990
|
* typesHolder: TypesHolder,
|
|
@@ -11831,7 +11993,9 @@ const getFormatAndSchemaChoices = ({schema, hasKeyPath} = {}) => {
|
|
|
11831
11993
|
* currentPath: string) => import('./formats.js').StructuredCloneValue,
|
|
11832
11994
|
* getType: () => string,
|
|
11833
11995
|
* validValuesSet: () => boolean,
|
|
11834
|
-
* setValue: SetValue
|
|
11996
|
+
* setValue: SetValue,
|
|
11997
|
+
* formats: import('./formats.js').default,
|
|
11998
|
+
* types: import('./types.js').default
|
|
11835
11999
|
* }} The selector for types and the container for them. Both should be
|
|
11836
12000
|
* added to the page.
|
|
11837
12001
|
*/
|
|
@@ -11841,7 +12005,9 @@ function formatAndTypeChoices ({
|
|
|
11841
12005
|
hasValue,
|
|
11842
12006
|
singleValue,
|
|
11843
12007
|
hasKeyPath,
|
|
11844
|
-
typeNamespace
|
|
12008
|
+
typeNamespace,
|
|
12009
|
+
formats = new Formats(),
|
|
12010
|
+
types = new Types()
|
|
11845
12011
|
}) {
|
|
11846
12012
|
const format = 'structuredCloning';
|
|
11847
12013
|
const formatChoices = /** @type {FormatChoices} */ (jml('select', {
|
|
@@ -11888,6 +12054,8 @@ function formatAndTypeChoices ({
|
|
|
11888
12054
|
),
|
|
11889
12055
|
// resultType: 'both',
|
|
11890
12056
|
format: this.value,
|
|
12057
|
+
formats,
|
|
12058
|
+
types,
|
|
11891
12059
|
typeNamespace,
|
|
11892
12060
|
requireObject: hasKeyPath,
|
|
11893
12061
|
objectHasValue: hasValue,
|
|
@@ -11939,6 +12107,8 @@ function formatAndTypeChoices ({
|
|
|
11939
12107
|
// resultType: 'both',
|
|
11940
12108
|
topRoot: /** @type {HTMLDivElement} */ ($e(typesHolder, 'div[data-type]')),
|
|
11941
12109
|
format,
|
|
12110
|
+
formats,
|
|
12111
|
+
types,
|
|
11942
12112
|
typeNamespace,
|
|
11943
12113
|
requireObject: hasKeyPath,
|
|
11944
12114
|
objectHasValue: hasValue,
|
|
@@ -11947,6 +12117,8 @@ function formatAndTypeChoices ({
|
|
|
11947
12117
|
}).domArray}, typesHolder);
|
|
11948
12118
|
|
|
11949
12119
|
return {
|
|
12120
|
+
formats,
|
|
12121
|
+
types,
|
|
11950
12122
|
formatChoices,
|
|
11951
12123
|
typesHolder,
|
|
11952
12124
|
// Easier for Jamilih
|
|
@@ -11965,11 +12137,13 @@ function formatAndTypeChoices ({
|
|
|
11965
12137
|
const root = /** @type {HTMLDivElement & {$getTypeRoot: TypeRootGetter}} */ (
|
|
11966
12138
|
typesHolder
|
|
11967
12139
|
).$getTypeRoot();
|
|
11968
|
-
return
|
|
12140
|
+
return types.getValueForRoot(/** @type {HTMLDivElement} */ (root), {
|
|
11969
12141
|
typeNamespace,
|
|
11970
12142
|
format: /** @type {import('./formats.js').AvailableFormat} */ (
|
|
11971
12143
|
formatChoices.value
|
|
11972
12144
|
),
|
|
12145
|
+
formats,
|
|
12146
|
+
types,
|
|
11973
12147
|
...stateObj
|
|
11974
12148
|
}, currentPath);
|
|
11975
12149
|
},
|
|
@@ -11982,7 +12156,7 @@ function formatAndTypeChoices ({
|
|
|
11982
12156
|
const root = /** @type {HTMLDivElement & {$getTypeRoot: TypeRootGetter}} */ (
|
|
11983
12157
|
typesHolder
|
|
11984
12158
|
).$getTypeRoot();
|
|
11985
|
-
return Types
|
|
12159
|
+
return Types.getTypeForRoot(/** @type {HTMLDivElement} */ (root));
|
|
11986
12160
|
},
|
|
11987
12161
|
|
|
11988
12162
|
/**
|
|
@@ -11996,13 +12170,14 @@ function formatAndTypeChoices ({
|
|
|
11996
12170
|
const form = /** @type {HTMLFormElement} */ (
|
|
11997
12171
|
/** @type {Element} */ (root).closest('form')
|
|
11998
12172
|
);
|
|
11999
|
-
return Types
|
|
12173
|
+
return Types.validValuesSet({form, typeNamespace});
|
|
12000
12174
|
},
|
|
12001
12175
|
|
|
12002
12176
|
/** @type {SetValue} */
|
|
12003
12177
|
async setValue (value, stateObj) {
|
|
12004
12178
|
const rootEditUI = /** @type {HTMLDivElement} */ (
|
|
12005
|
-
await getControlsForFormatAndValue(
|
|
12179
|
+
await formats.getControlsForFormatAndValue(
|
|
12180
|
+
types,
|
|
12006
12181
|
/** @type {import('./formats.js').AvailableFormat} */ (
|
|
12007
12182
|
formatChoices.value
|
|
12008
12183
|
),
|
|
@@ -12010,7 +12185,7 @@ function formatAndTypeChoices ({
|
|
|
12010
12185
|
stateObj
|
|
12011
12186
|
)
|
|
12012
12187
|
);
|
|
12013
|
-
const type = Types
|
|
12188
|
+
const type = Types.getTypeForRoot(rootEditUI);
|
|
12014
12189
|
// eslint-disable-next-line @stylistic/max-len -- Long
|
|
12015
12190
|
const sel = /** @type {HTMLDivElement & {$getTypeSelect: TypeSelectGetter}} */ (
|
|
12016
12191
|
typesHolder
|
|
@@ -12023,4 +12198,4 @@ function formatAndTypeChoices ({
|
|
|
12023
12198
|
};
|
|
12024
12199
|
}
|
|
12025
12200
|
|
|
12026
|
-
export { Formats, Types
|
|
12201
|
+
export { Formats, Types, formatAndTypeChoices, getFormatAndSchemaChoices, buildTypeChoices as typeChoices };
|