@es-joy/jsoe 0.28.2 → 0.30.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.
- package/.claude/scheduled_tasks.lock +1 -0
- package/CHANGES.md +25 -0
- package/README.md +4 -0
- package/dist/formatAndTypeChoices.d.ts +6 -6
- package/dist/formatAndTypeChoices.d.ts.map +1 -1
- package/dist/formats/schema.d.ts +5 -0
- package/dist/formats/schema.d.ts.map +1 -1
- package/dist/formats.d.ts +2 -2
- package/dist/formats.d.ts.map +1 -1
- package/dist/fundamentalTypes/dateType.d.ts +26 -2
- package/dist/fundamentalTypes/dateType.d.ts.map +1 -1
- package/dist/fundamentalTypes/domexceptionType.d.ts +7 -0
- package/dist/fundamentalTypes/domexceptionType.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/jtltExtensions.d.ts +112 -0
- package/dist/jtltExtensions.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/arraySearchType.d.ts +22 -0
- package/dist/search/fundamentalTypes/arraySearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/bigintSearchType.d.ts +10 -0
- package/dist/search/fundamentalTypes/bigintSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/blobSearchType.d.ts +19 -0
- package/dist/search/fundamentalTypes/blobSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/booleanSearchType.d.ts +11 -0
- package/dist/search/fundamentalTypes/booleanSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/catchSearchType.d.ts +18 -0
- package/dist/search/fundamentalTypes/catchSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/dateSearchType.d.ts +15 -0
- package/dist/search/fundamentalTypes/dateSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/domexceptionSearchType.d.ts +16 -0
- package/dist/search/fundamentalTypes/domexceptionSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/enumSearchType.d.ts +26 -0
- package/dist/search/fundamentalTypes/enumSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/errorSearchType.d.ts +9 -0
- package/dist/search/fundamentalTypes/errorSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/fileSearchType.d.ts +28 -0
- package/dist/search/fundamentalTypes/fileSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/filelistSearchType.d.ts +24 -0
- package/dist/search/fundamentalTypes/filelistSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/functionSearchType.d.ts +18 -0
- package/dist/search/fundamentalTypes/functionSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/mapSearchType.d.ts +22 -0
- package/dist/search/fundamentalTypes/mapSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/nanSearchType.d.ts +7 -0
- package/dist/search/fundamentalTypes/nanSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/nullSearchType.d.ts +7 -0
- package/dist/search/fundamentalTypes/nullSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/numberSearchType.d.ts +11 -0
- package/dist/search/fundamentalTypes/numberSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/objectSearchType.d.ts +21 -0
- package/dist/search/fundamentalTypes/objectSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/promiseSearchType.d.ts +20 -0
- package/dist/search/fundamentalTypes/promiseSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/regexpSearchType.d.ts +20 -0
- package/dist/search/fundamentalTypes/regexpSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/setSearchType.d.ts +15 -0
- package/dist/search/fundamentalTypes/setSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/stringSearchType.d.ts +21 -0
- package/dist/search/fundamentalTypes/stringSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/symbolSearchType.d.ts +16 -0
- package/dist/search/fundamentalTypes/symbolSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/undefinedSearchType.d.ts +7 -0
- package/dist/search/fundamentalTypes/undefinedSearchType.d.ts.map +1 -0
- package/dist/search/index.d.ts +70 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/queryTree.d.ts +12 -1
- package/dist/search/queryTree.d.ts.map +1 -1
- package/dist/search/queryTreeBuilders.d.ts +18 -0
- package/dist/search/queryTreeBuilders.d.ts.map +1 -1
- package/dist/search/searchDispatch.d.ts +44 -0
- package/dist/search/searchDispatch.d.ts.map +1 -1
- package/dist/search/searchElementUtils.d.ts +106 -0
- package/dist/search/searchElementUtils.d.ts.map +1 -0
- package/dist/search/searchUtils.d.ts +550 -0
- package/dist/search/searchUtils.d.ts.map +1 -0
- package/dist/search/subTypes/blobHTMLSearchType.d.ts +36 -0
- package/dist/search/subTypes/blobHTMLSearchType.d.ts.map +1 -0
- package/dist/search/subTypes/recordSearchType.d.ts +18 -0
- package/dist/search/subTypes/recordSearchType.d.ts.map +1 -0
- package/dist/search/subTypes/tupleSearchType.d.ts +21 -0
- package/dist/search/subTypes/tupleSearchType.d.ts.map +1 -0
- package/dist/search/superTypes/SpecialRealNumberSearchType.d.ts +14 -0
- package/dist/search/superTypes/SpecialRealNumberSearchType.d.ts.map +1 -0
- package/dist/search/superTypes/buffersourceSearchType.d.ts +17 -0
- package/dist/search/superTypes/buffersourceSearchType.d.ts.map +1 -0
- package/dist/search/superTypes/dommatrixSearchType.d.ts +11 -0
- package/dist/search/superTypes/dommatrixSearchType.d.ts.map +1 -0
- package/dist/search/superTypes/dompointSearchType.d.ts +9 -0
- package/dist/search/superTypes/dompointSearchType.d.ts.map +1 -0
- package/dist/search/superTypes/domrectSearchType.d.ts +9 -0
- package/dist/search/superTypes/domrectSearchType.d.ts.map +1 -0
- package/dist/search/superTypes/errorsSpecialSearchType.d.ts +11 -0
- package/dist/search/superTypes/errorsSpecialSearchType.d.ts.map +1 -0
- package/dist/search/unions/discriminatedUnionSearchType.d.ts +12 -0
- package/dist/search/unions/discriminatedUnionSearchType.d.ts.map +1 -0
- package/dist/search/unions/unionFamilySearchType.d.ts +36 -0
- package/dist/search/unions/unionFamilySearchType.d.ts.map +1 -0
- package/dist/search/unions/unionSearchType.d.ts +8 -0
- package/dist/search/unions/unionSearchType.d.ts.map +1 -0
- package/dist/search/unions/xorSearchType.d.ts +12 -0
- package/dist/search/unions/xorSearchType.d.ts.map +1 -0
- package/dist/superTypes/buffersourceType.d.ts.map +1 -1
- package/dist/typeChoices.d.ts +3 -3
- package/dist/typeChoices.d.ts.map +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -4
- package/pnpm-workspace.yaml +1 -1
- package/rollup.config.js +12 -0
- package/src/formatAndTypeChoices.js +4 -4
- package/src/formats/schema.js +1 -1
- package/src/formats.js +1 -1
- package/src/fundamentalTypes/dateType.js +40 -14
- package/src/fundamentalTypes/domexceptionType.js +41 -33
- package/src/fundamentalTypes/regexpType.js +1 -1
- package/src/index.js +6 -0
- package/src/jsoe.css +204 -0
- package/src/jtltExtensions.js +103 -0
- package/src/search/fundamentalTypes/arraySearchType.js +101 -0
- package/src/search/fundamentalTypes/bigintSearchType.js +68 -0
- package/src/search/fundamentalTypes/blobSearchType.js +42 -0
- package/src/search/fundamentalTypes/booleanSearchType.js +40 -0
- package/src/search/fundamentalTypes/catchSearchType.js +59 -0
- package/src/search/fundamentalTypes/dateSearchType.js +166 -0
- package/src/search/fundamentalTypes/domexceptionSearchType.js +84 -0
- package/src/search/fundamentalTypes/enumSearchType.js +62 -0
- package/src/search/fundamentalTypes/errorSearchType.js +11 -0
- package/src/search/fundamentalTypes/fileSearchType.js +94 -0
- package/src/search/fundamentalTypes/filelistSearchType.js +103 -0
- package/src/search/fundamentalTypes/functionSearchType.js +102 -0
- package/src/search/fundamentalTypes/mapSearchType.js +117 -0
- package/src/search/fundamentalTypes/nanSearchType.js +11 -0
- package/src/search/fundamentalTypes/nullSearchType.js +11 -0
- package/src/search/fundamentalTypes/numberSearchType.js +59 -0
- package/src/search/fundamentalTypes/objectSearchType.js +367 -0
- package/src/search/fundamentalTypes/promiseSearchType.js +61 -0
- package/src/search/fundamentalTypes/regexpSearchType.js +72 -0
- package/src/search/fundamentalTypes/setSearchType.js +91 -0
- package/src/search/fundamentalTypes/stringSearchType.js +44 -0
- package/src/search/fundamentalTypes/symbolSearchType.js +39 -0
- package/src/search/fundamentalTypes/undefinedSearchType.js +11 -0
- package/src/search/index.js +96 -0
- package/src/search/queryTree.js +244 -0
- package/src/search/queryTreeBuilders.js +233 -0
- package/src/search/searchDispatch.js +291 -0
- package/src/search/searchElementUtils.js +373 -0
- package/src/search/searchUtils.js +847 -0
- package/src/search/subTypes/blobHTMLSearchType.js +122 -0
- package/src/search/subTypes/recordSearchType.js +105 -0
- package/src/search/subTypes/tupleSearchType.js +152 -0
- package/src/search/superTypes/SpecialRealNumberSearchType.js +42 -0
- package/src/search/superTypes/buffersourceSearchType.js +53 -0
- package/src/search/superTypes/dommatrixSearchType.js +24 -0
- package/src/search/superTypes/dompointSearchType.js +15 -0
- package/src/search/superTypes/domrectSearchType.js +15 -0
- package/src/search/superTypes/errorsSpecialSearchType.js +15 -0
- package/src/search/unions/discriminatedUnionSearchType.js +16 -0
- package/src/search/unions/unionFamilySearchType.js +168 -0
- package/src/search/unions/unionSearchType.js +12 -0
- package/src/search/unions/xorSearchType.js +16 -0
- package/src/superTypes/buffersourceType.js +13 -15
- package/src/typeChoices.js +2 -2
- package/src/types.js +2 -2
- package/tsconfig-prod.json +12 -0
- package/tsconfig.json +5 -10
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, buildCheckbox, readCheckbox, buildLengthSizeControls,
|
|
3
|
+
readLengthSizeQuery, buildOptInFieldset, readOptInChecked, wireOptInFieldset,
|
|
4
|
+
buildAtLeastOneSentinel, syncAtLeastOneCheck
|
|
5
|
+
} from '../searchUtils.js';
|
|
6
|
+
import {makeMapRecordJointLeaf, combineAnd} from '../queryTreeBuilders.js';
|
|
7
|
+
import {findSearchElement, getQueryViaElement, hasGetQuery} from '../searchElementUtils.js';
|
|
8
|
+
import {buildSearchWidget} from '../searchDispatch.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {Element} root - a `jsoe-search-map` element
|
|
16
|
+
* @returns {void}
|
|
17
|
+
*/
|
|
18
|
+
function syncMapValidity (root) {
|
|
19
|
+
syncAtLeastOneCheck(
|
|
20
|
+
root, () => readOptInChecked(root, 'key') || readOptInChecked(root, 'value') ||
|
|
21
|
+
readLengthSizeQuery(root, '') !== undefined
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Map, Record: string-type searches of keys, values; ideally would allow
|
|
27
|
+
* search to insist on match of key and value (README) - structurally the
|
|
28
|
+
* same as `recordSearchType.js` (`key`/`value` recursion at `*key`/`*value`
|
|
29
|
+
* segments, a "require same entry" toggle producing one `mapRecordJoint`
|
|
30
|
+
* leaf), plus a `lengthSize` control for `min`/`max` (a `Map`, unlike a
|
|
31
|
+
* `Record`, carries its own size bounds in the schema - the same
|
|
32
|
+
* affordance `setSearchType.js` gets for the analogous reason), combined
|
|
33
|
+
* with the joint leaf via `$and`. Key and value are each wrapped in their
|
|
34
|
+
* own `buildOptInFieldset` (so leaving either at "no constraint" doesn't
|
|
35
|
+
* force it via a `required` control inside), but *leaving all three*
|
|
36
|
+
* (key, value, and size) unconfigured is itself invalid via
|
|
37
|
+
* `buildAtLeastOneSentinel` - unlike `recordSearchType.js` (which has no
|
|
38
|
+
* size control of its own and so needs key or value specifically), a
|
|
39
|
+
* length/size-only search is already meaningful here, the same as
|
|
40
|
+
* `arraySearchType.js`/`setSearchType.js`.
|
|
41
|
+
* @type {SearchTypeObject}
|
|
42
|
+
*/
|
|
43
|
+
const mapSearchType = {
|
|
44
|
+
buildUI ({schemaObject, path, typeNamespace, topRoot, types, originalJSON}) {
|
|
45
|
+
const label = buildPathLabel(schemaObject, path);
|
|
46
|
+
const name = `${typeNamespace}-map`;
|
|
47
|
+
const mapSchemaObject = /** @type {import('zodexy').SzMap<any, any>} */ (
|
|
48
|
+
schemaObject
|
|
49
|
+
);
|
|
50
|
+
const keyPath = `${path}/*key`;
|
|
51
|
+
const valuePath = `${path}/*value`;
|
|
52
|
+
const keyArr = buildSearchWidget({
|
|
53
|
+
schemaObject: mapSchemaObject.key,
|
|
54
|
+
path: keyPath,
|
|
55
|
+
typeNamespace,
|
|
56
|
+
topRoot,
|
|
57
|
+
types,
|
|
58
|
+
originalJSON
|
|
59
|
+
});
|
|
60
|
+
const valueArr = buildSearchWidget({
|
|
61
|
+
schemaObject: mapSchemaObject.value,
|
|
62
|
+
path: valuePath,
|
|
63
|
+
typeNamespace,
|
|
64
|
+
topRoot,
|
|
65
|
+
types,
|
|
66
|
+
originalJSON
|
|
67
|
+
});
|
|
68
|
+
return ['jsoe-search-map', {
|
|
69
|
+
dataset: {searchPath: path, searchKind: 'map'},
|
|
70
|
+
title: label,
|
|
71
|
+
$define: {
|
|
72
|
+
/** @this {HTMLElement} */
|
|
73
|
+
connectedCallback () {
|
|
74
|
+
wireOptInFieldset(this, 'key', () => syncMapValidity(this));
|
|
75
|
+
wireOptInFieldset(this, 'value', () => syncMapValidity(this));
|
|
76
|
+
this.querySelector('input.jsoeSearchSize')?.addEventListener(
|
|
77
|
+
'input', () => syncMapValidity(this)
|
|
78
|
+
);
|
|
79
|
+
syncMapValidity(this);
|
|
80
|
+
},
|
|
81
|
+
/** @this {HTMLElement} */
|
|
82
|
+
getQuery () {
|
|
83
|
+
const searchPath = this.dataset.searchPath ?? '';
|
|
84
|
+
const lengthLeaf = readLengthSizeQuery(this, searchPath);
|
|
85
|
+
const keyEl = findSearchElement(this, `${searchPath}/*key`);
|
|
86
|
+
const valueEl = findSearchElement(this, `${searchPath}/*value`);
|
|
87
|
+
const keyQuery = keyEl && hasGetQuery(keyEl) && readOptInChecked(this, 'key')
|
|
88
|
+
? keyEl.getQuery()
|
|
89
|
+
: undefined;
|
|
90
|
+
const valueQuery = valueEl && hasGetQuery(valueEl) && readOptInChecked(this, 'value')
|
|
91
|
+
? valueEl.getQuery()
|
|
92
|
+
: undefined;
|
|
93
|
+
const jointLeaf = keyQuery || valueQuery
|
|
94
|
+
? makeMapRecordJointLeaf(searchPath, readCheckbox(this), keyQuery, valueQuery)
|
|
95
|
+
: undefined;
|
|
96
|
+
return combineAnd([lengthLeaf, jointLeaf]);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}, [
|
|
100
|
+
['span', {class: 'searchLabel'}, [label]],
|
|
101
|
+
...buildLengthSizeControls({
|
|
102
|
+
name, min: mapSchemaObject.min, max: mapSchemaObject.max, includeSparse: false
|
|
103
|
+
}),
|
|
104
|
+
...buildOptInFieldset({
|
|
105
|
+
name: `${name}-key`, key: 'key', label: 'Key matches', children: [keyArr]
|
|
106
|
+
}),
|
|
107
|
+
...buildOptInFieldset({
|
|
108
|
+
name: `${name}-value`, key: 'value', label: 'Value matches', children: [valueArr]
|
|
109
|
+
}),
|
|
110
|
+
buildCheckbox({name: `${name}-joint`, label: 'Require same entry'}),
|
|
111
|
+
buildAtLeastOneSentinel()
|
|
112
|
+
]];
|
|
113
|
+
},
|
|
114
|
+
getQuery: getQueryViaElement
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export default mapSearchType;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {makePresenceOnlySearchType} from '../searchElementUtils.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `NaN`: "no variants to allow for distinct search" (README).
|
|
5
|
+
* @type {import('../searchDispatch.js').SearchTypeObject}
|
|
6
|
+
*/
|
|
7
|
+
const nanSearchType = makePresenceOnlySearchType({
|
|
8
|
+
tagName: 'jsoe-search-nan'
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export default nanSearchType;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {makePresenceOnlySearchType} from '../searchElementUtils.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `null`: "no variants to allow for distinct search" (README).
|
|
5
|
+
* @type {import('../searchDispatch.js').SearchTypeObject}
|
|
6
|
+
*/
|
|
7
|
+
const nullSearchType = makePresenceOnlySearchType({
|
|
8
|
+
tagName: 'jsoe-search-null'
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export default nullSearchType;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, buildRangeInputsPair, readRangeInputsPair, buildTriStateSelect,
|
|
3
|
+
readTriStateSelect, syncRangeValidity
|
|
4
|
+
} from '../searchUtils.js';
|
|
5
|
+
import {makeRangeLeaf, makeIntegerCheckLeaf, combineAnd} from '../queryTreeBuilders.js';
|
|
6
|
+
import {getQueryViaElement} from '../searchElementUtils.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* OR Ranges/Is Not Range, Is/Is Not Integer (README).
|
|
14
|
+
* @type {SearchTypeObject}
|
|
15
|
+
*/
|
|
16
|
+
const numberSearchType = {
|
|
17
|
+
buildUI ({schemaObject, path, typeNamespace}) {
|
|
18
|
+
const label = buildPathLabel(schemaObject, path);
|
|
19
|
+
const name = `${typeNamespace}-number`;
|
|
20
|
+
return ['jsoe-search-number', {
|
|
21
|
+
dataset: {searchPath: path, searchKind: 'number'},
|
|
22
|
+
title: label,
|
|
23
|
+
$define: {
|
|
24
|
+
/** @this {HTMLElement} */
|
|
25
|
+
connectedCallback () {
|
|
26
|
+
syncRangeValidity(this);
|
|
27
|
+
},
|
|
28
|
+
/** @this {HTMLElement} */
|
|
29
|
+
getQuery () {
|
|
30
|
+
const searchPath = this.dataset.searchPath ?? '';
|
|
31
|
+
const {gte, lte} = readRangeInputsPair(this);
|
|
32
|
+
const rangeLeaf = gte === '' && lte === ''
|
|
33
|
+
? undefined
|
|
34
|
+
: makeRangeLeaf(searchPath, 'number', {
|
|
35
|
+
...(gte === '' ? {} : {$gte: Number(gte)}),
|
|
36
|
+
...(lte === '' ? {} : {$lte: Number(lte)})
|
|
37
|
+
});
|
|
38
|
+
const isInteger = readTriStateSelect(this);
|
|
39
|
+
const integerLeaf = isInteger === undefined
|
|
40
|
+
? undefined
|
|
41
|
+
: makeIntegerCheckLeaf(searchPath, isInteger);
|
|
42
|
+
return combineAnd([rangeLeaf, integerLeaf]);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}, [
|
|
46
|
+
['span', {class: 'searchLabel'}, [label]],
|
|
47
|
+
...buildRangeInputsPair({name}),
|
|
48
|
+
['label', [
|
|
49
|
+
'Integer: ',
|
|
50
|
+
buildTriStateSelect({
|
|
51
|
+
name: `${name}-integer`, trueLabel: 'Integer', falseLabel: 'Not integer'
|
|
52
|
+
})
|
|
53
|
+
]]
|
|
54
|
+
]];
|
|
55
|
+
},
|
|
56
|
+
getQuery: getQueryViaElement
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export default numberSearchType;
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import {jml} from '../../vendor-imports.js';
|
|
2
|
+
import {escapeJSONPointer} from '../../utils/jsonPointer.js';
|
|
3
|
+
import {
|
|
4
|
+
buildPathLabel, buildHasPropertyToggle, readTriStateSelect, findOwnControl,
|
|
5
|
+
buildCheckbox, readCheckbox, buildAtLeastOneSentinel, syncAtLeastOneCheck,
|
|
6
|
+
setDescendantsRequired, revalidateDescendants, resyncAtLeastOne
|
|
7
|
+
} from '../searchUtils.js';
|
|
8
|
+
import {combineAnd, makeHasPropertyLeaf} from '../queryTreeBuilders.js';
|
|
9
|
+
import {
|
|
10
|
+
findSearchElement, getQueryViaElement, hasGetQuery
|
|
11
|
+
} from '../searchElementUtils.js';
|
|
12
|
+
import {buildSearchWidget} from '../searchDispatch.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* An object with zero active rows (nothing added from the pull-down, and no
|
|
20
|
+
* required property opted into) expresses no constraint at all - the same
|
|
21
|
+
* "no absent values" reasoning as every other leaf's own required control,
|
|
22
|
+
* just with nothing native to hang a `required` attribute directly off of,
|
|
23
|
+
* since what counts as "active" is a dynamically-changing count of child
|
|
24
|
+
* rows rather than one fixed input. `searchUtils.js`'s
|
|
25
|
+
* `buildAtLeastOneSentinel`/`syncAtLeastOneCheck` stand in for that.
|
|
26
|
+
* @param {Element} root - a `jsoe-search-object` element
|
|
27
|
+
* @returns {void}
|
|
28
|
+
*/
|
|
29
|
+
function syncObjectValidity (root) {
|
|
30
|
+
const addedRowCount = root.querySelectorAll(':scope > jsoe-search-has-property').length;
|
|
31
|
+
const checkedRequiredCount = [
|
|
32
|
+
...root.querySelectorAll(
|
|
33
|
+
':scope > jsoe-search-required-property > label > input.jsoeSearchCheckbox'
|
|
34
|
+
)
|
|
35
|
+
].filter((checkbox) => /** @type {HTMLInputElement} */ (checkbox).checked).length;
|
|
36
|
+
syncAtLeastOneCheck(root, () => addedRowCount + checkedRequiredCount > 0);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* One added property's row: the fixed "has property" tri-state toggle
|
|
41
|
+
* (`buildHasPropertyToggle`) plus, immediately recursing (search plan §6
|
|
42
|
+
* build order: "Object / Array / Set - first types recursing into child
|
|
43
|
+
* schemas via `getSearchTypeObject`"), that property's own full search
|
|
44
|
+
* widget - so a user can combine "has property X" with "X matches Y" in
|
|
45
|
+
* one row rather than only being able to ask about existence.
|
|
46
|
+
* @param {{
|
|
47
|
+
* propertyName: string,
|
|
48
|
+
* propSchema: import('../../formats/schema.js').ZodexSchema,
|
|
49
|
+
* path: string,
|
|
50
|
+
* typeNamespace: string|undefined,
|
|
51
|
+
* topRoot: import('../../types.js').RootElement|undefined,
|
|
52
|
+
* types: import('../../types.js').default|undefined,
|
|
53
|
+
* originalJSON: import('../../formats/schema.js').ZodexSchema|undefined,
|
|
54
|
+
* addPropertySelect: HTMLSelectElement
|
|
55
|
+
* }} cfg
|
|
56
|
+
* @returns {HTMLElement}
|
|
57
|
+
*/
|
|
58
|
+
function buildHasPropertyRow ({
|
|
59
|
+
propertyName, propSchema, path, typeNamespace, topRoot, types, originalJSON,
|
|
60
|
+
addPropertySelect
|
|
61
|
+
}) {
|
|
62
|
+
const childPath = `${path}/${escapeJSONPointer(propertyName)}`;
|
|
63
|
+
const name = `${typeNamespace}-hasProperty-${propertyName}`;
|
|
64
|
+
const childArr = buildSearchWidget({
|
|
65
|
+
schemaObject: propSchema, path: childPath, typeNamespace, topRoot, types,
|
|
66
|
+
originalJSON
|
|
67
|
+
});
|
|
68
|
+
const row = /** @type {HTMLElement} */ (jml('jsoe-search-has-property', {
|
|
69
|
+
dataset: {searchPath: childPath, searchKind: 'hasProperty', propertyName},
|
|
70
|
+
$define: {
|
|
71
|
+
// Reads `childPath` off `this.dataset` rather than closing over the
|
|
72
|
+
// outer `path`/`propertyName`: `$define`'s mixin is installed once
|
|
73
|
+
// on the shared prototype the first time this tag is defined, so
|
|
74
|
+
// every later `<jsoe-search-has-property>` instance must read its
|
|
75
|
+
// own per-row state off `this`. `readTriStateSelect`/
|
|
76
|
+
// `findSearchElement` are themselves closure-free (class- and
|
|
77
|
+
// `dataset`-driven; see `searchUtils.js`'s `findOwnControl`), so no
|
|
78
|
+
// further per-instance state needs storing here.
|
|
79
|
+
/** @this {HTMLElement} */
|
|
80
|
+
getQuery () {
|
|
81
|
+
const searchPath = this.dataset.searchPath ?? '';
|
|
82
|
+
const existsCheck = readTriStateSelect(this);
|
|
83
|
+
const existsLeaf = existsCheck === undefined
|
|
84
|
+
? undefined
|
|
85
|
+
: makeHasPropertyLeaf(searchPath, existsCheck);
|
|
86
|
+
// "Doesn't have" already hides the child (its own `syncChildState`),
|
|
87
|
+
// since a value/presence constraint on an asserted-absent property
|
|
88
|
+
// is meaningless - skip its query outright rather than combining a
|
|
89
|
+
// stale/leftover constraint with a contradictory `$exists: false`.
|
|
90
|
+
// This matters most for `makePresenceOnlySearchType`'s leaves
|
|
91
|
+
// (undef/null/NaN), whose checkbox is permanently checked
|
|
92
|
+
// (`buildCheckbox`'s doc) and so would otherwise always contribute
|
|
93
|
+
// its `presence` leaf regardless of this row's own answer.
|
|
94
|
+
const childEl = existsCheck === false
|
|
95
|
+
? undefined
|
|
96
|
+
: findSearchElement(this, searchPath);
|
|
97
|
+
const childLeaf = childEl && hasGetQuery(childEl)
|
|
98
|
+
? childEl.getQuery()
|
|
99
|
+
: undefined;
|
|
100
|
+
return combineAnd([existsLeaf, childLeaf]);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}, [
|
|
104
|
+
buildHasPropertyToggle({name, propertyName}),
|
|
105
|
+
['button', {
|
|
106
|
+
type: 'button',
|
|
107
|
+
class: 'removePropertyButton',
|
|
108
|
+
$on: {
|
|
109
|
+
// `row`/`addPropertySelect`/`propertyName` are all closed over
|
|
110
|
+
// directly - safe since `buildHasPropertyRow` (unlike `$define`)
|
|
111
|
+
// runs fresh per row, so nothing here is shared across instances.
|
|
112
|
+
click () {
|
|
113
|
+
const option = /** @type {HTMLOptionElement|null} */ (
|
|
114
|
+
addPropertySelect.querySelector(
|
|
115
|
+
`option[value="${CSS.escape(propertyName)}"]`
|
|
116
|
+
)
|
|
117
|
+
);
|
|
118
|
+
if (option) {
|
|
119
|
+
option.disabled = false;
|
|
120
|
+
}
|
|
121
|
+
const objectRoot = row.closest('jsoe-search-object');
|
|
122
|
+
row.remove();
|
|
123
|
+
if (objectRoot) {
|
|
124
|
+
syncObjectValidity(/** @type {HTMLElement} */ (objectRoot));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}, ['Remove']],
|
|
129
|
+
childArr
|
|
130
|
+
]));
|
|
131
|
+
|
|
132
|
+
// Asserting the property is absent ("Doesn't have") makes a value
|
|
133
|
+
// constraint on it meaningless, so hide the recursed child widget while
|
|
134
|
+
// that's selected rather than leaving it showing (and usable) alongside a
|
|
135
|
+
// contradictory "doesn't have" answer - `buildUI` runs fresh per row, so
|
|
136
|
+
// (unlike `$define`) it's safe for this listener to close over `select`/
|
|
137
|
+
// `childRoot` directly.
|
|
138
|
+
const select = /** @type {HTMLSelectElement|undefined} */ (
|
|
139
|
+
findOwnControl(row, 'select.jsoeSearchTriState--')
|
|
140
|
+
);
|
|
141
|
+
const childRoot = findSearchElement(row, childPath);
|
|
142
|
+
// "Doesn't have" hides the child entirely (a value constraint on an
|
|
143
|
+
// asserted-absent property is meaningless) - a hidden control is already
|
|
144
|
+
// exempt from constraint validation on its own. "Has" keeps the child
|
|
145
|
+
// visible and interactive (so "Has property X" AND "X matches Y" can
|
|
146
|
+
// still be combined), but that existence assertion is *already* a
|
|
147
|
+
// complete constraint by itself, so its own required inputs (whatever
|
|
148
|
+
// type the child turns out to be) are relaxed via `setDescendantsRequired`
|
|
149
|
+
// rather than disabled - only "(any)" (no existence assertion) leaves
|
|
150
|
+
// them actually required, since the child's own value is then the row's
|
|
151
|
+
// only possible contribution. `revalidateDescendants` covers anything
|
|
152
|
+
// that (unlike a plain `required` attribute) re-asserts its own
|
|
153
|
+
// constraint imperatively on every keystroke regardless of this row's
|
|
154
|
+
// state - a range pair's `isExemptedByAncestorHasProperty` check
|
|
155
|
+
// (`searchUtils.js`) only takes effect once something re-runs it, which
|
|
156
|
+
// otherwise wouldn't happen until the user next touches that field.
|
|
157
|
+
// `resyncAtLeastOne` covers the same gap for a child that's itself an
|
|
158
|
+
// `object`/`array`/`map`/etc. with its own "at least one facet" sentinel
|
|
159
|
+
// (`buildAtLeastOneSentinel`) - `revalidateDescendants`' event-redispatch
|
|
160
|
+
// reaches `array`/`map`/etc. fine (their own answer changes via a plain
|
|
161
|
+
// `input`/`change` on a real control), but not `objectSearchType.js`
|
|
162
|
+
// itself, whose sentinel changes when a row is added/removed - a button
|
|
163
|
+
// click and a structural DOM change, neither of which redispatching
|
|
164
|
+
// `input`/`change` events can simulate.
|
|
165
|
+
const syncChildState = () => {
|
|
166
|
+
if (!childRoot) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
childRoot.hidden = select?.value === 'false';
|
|
170
|
+
setDescendantsRequired(childRoot, select?.value === '');
|
|
171
|
+
revalidateDescendants(childRoot);
|
|
172
|
+
resyncAtLeastOne(childRoot);
|
|
173
|
+
};
|
|
174
|
+
select?.addEventListener('change', syncChildState);
|
|
175
|
+
syncChildState();
|
|
176
|
+
|
|
177
|
+
return row;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* A required property's own value-match widget, wrapped in an opt-in
|
|
182
|
+
* "Search on this property" checkbox (default unchecked) around a disabled
|
|
183
|
+
* `<fieldset>`: a required property has no existence to ask about, but it
|
|
184
|
+
* still auto-appears with no "Remove" affordance the moment its parent
|
|
185
|
+
* object is added (search plan build order never lists it in the "Add
|
|
186
|
+
* property" pull-down at all) - and several leaf widgets now mark their own
|
|
187
|
+
* value input `required` (`buildLiteralRegexControls`'s doc), which would
|
|
188
|
+
* otherwise make the *whole* form invalid the instant such a property's
|
|
189
|
+
* object exists, before the user has asked to search on it at all.
|
|
190
|
+
* `<fieldset disabled>` is a native way to exempt a whole subtree from
|
|
191
|
+
* constraint validation in one step (every descendant control, whatever
|
|
192
|
+
* type it turns out to be, stops blocking `checkValidity`/`reportValidity`
|
|
193
|
+
* while disabled) - checking the box re-enables the fieldset, making its
|
|
194
|
+
* contents both interactive and, if left with a `required` field empty,
|
|
195
|
+
* actually invalid again.
|
|
196
|
+
* @param {{
|
|
197
|
+
* propertyName: string,
|
|
198
|
+
* propSchema: import('../../formats/schema.js').ZodexSchema,
|
|
199
|
+
* path: string,
|
|
200
|
+
* typeNamespace: string|undefined,
|
|
201
|
+
* topRoot: import('../../types.js').RootElement|undefined,
|
|
202
|
+
* types: import('../../types.js').default|undefined,
|
|
203
|
+
* originalJSON: import('../../formats/schema.js').ZodexSchema|undefined
|
|
204
|
+
* }} cfg
|
|
205
|
+
* @returns {HTMLElement}
|
|
206
|
+
*/
|
|
207
|
+
function buildRequiredPropertyRow ({
|
|
208
|
+
propertyName, propSchema, path, typeNamespace, topRoot, types, originalJSON
|
|
209
|
+
}) {
|
|
210
|
+
const childPath = `${path}/${escapeJSONPointer(propertyName)}`;
|
|
211
|
+
const name = `${typeNamespace}-requiredProperty-${propertyName}`;
|
|
212
|
+
const childArr = buildSearchWidget({
|
|
213
|
+
schemaObject: propSchema, path: childPath, typeNamespace, topRoot, types,
|
|
214
|
+
originalJSON
|
|
215
|
+
});
|
|
216
|
+
const row = /** @type {HTMLElement} */ (jml('jsoe-search-required-property', {
|
|
217
|
+
dataset: {searchPath: childPath, searchKind: 'requiredProperty', propertyName},
|
|
218
|
+
$define: {
|
|
219
|
+
/** @this {HTMLElement} */
|
|
220
|
+
getQuery () {
|
|
221
|
+
if (!readCheckbox(this)) {
|
|
222
|
+
return undefined;
|
|
223
|
+
}
|
|
224
|
+
const searchPath = this.dataset.searchPath ?? '';
|
|
225
|
+
const childEl = findSearchElement(this, searchPath);
|
|
226
|
+
return childEl && hasGetQuery(childEl) ? childEl.getQuery() : undefined;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}, [
|
|
230
|
+
buildCheckbox({name, label: `Search on "${propertyName}"`}),
|
|
231
|
+
['fieldset', {disabled: true, class: 'searchRequiredPropertyFieldset'}, [childArr]]
|
|
232
|
+
]));
|
|
233
|
+
|
|
234
|
+
const checkbox = /** @type {HTMLInputElement|undefined} */ (
|
|
235
|
+
findOwnControl(row, 'input.jsoeSearchCheckbox')
|
|
236
|
+
);
|
|
237
|
+
const fieldset = /** @type {HTMLFieldSetElement|null} */ (
|
|
238
|
+
row.querySelector('fieldset.searchRequiredPropertyFieldset')
|
|
239
|
+
);
|
|
240
|
+
checkbox?.addEventListener('change', () => {
|
|
241
|
+
if (fieldset) {
|
|
242
|
+
fieldset.disabled = !checkbox.checked;
|
|
243
|
+
}
|
|
244
|
+
const objectRoot = row.closest('jsoe-search-object');
|
|
245
|
+
if (objectRoot) {
|
|
246
|
+
syncObjectValidity(/** @type {HTMLElement} */ (objectRoot));
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
return row;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Has property <property pull-down> (README), additive: only
|
|
255
|
+
* optional properties are offered ("avoid listing required" - a required
|
|
256
|
+
* property is guaranteed present, so asking about its existence is
|
|
257
|
+
* meaningless), and picking one from the pull-down adds a row for it
|
|
258
|
+
* (disabled in the pull-down, rather than removed, so it can't be added a
|
|
259
|
+
* second time while its row exists). Each row's own "Remove" button
|
|
260
|
+
* discards the row and re-enables its property in the pull-down, for
|
|
261
|
+
* undoing an added-by-mistake property - a coarser-grained option than
|
|
262
|
+
* setting the row's toggle back to "(any)" (which already expresses "no
|
|
263
|
+
* constraint from this row" without removing it). A required property gets
|
|
264
|
+
* no pull-down entry (its existence is never in question), but does still
|
|
265
|
+
* get its own row - `buildRequiredPropertyRow`'s opt-in checkbox, defaulting
|
|
266
|
+
* unchecked/disabled, so it doesn't force a search constraint the user never
|
|
267
|
+
* asked for just by existing.
|
|
268
|
+
* @type {SearchTypeObject}
|
|
269
|
+
*/
|
|
270
|
+
const objectSearchType = {
|
|
271
|
+
buildUI ({schemaObject, path, typeNamespace, topRoot, types, originalJSON}) {
|
|
272
|
+
const label = buildPathLabel(schemaObject, path);
|
|
273
|
+
const objectSchemaObject = /** @type {import('zodexy').SzObject} */ (
|
|
274
|
+
schemaObject
|
|
275
|
+
);
|
|
276
|
+
const propertyEntries = Object.entries(objectSchemaObject.properties);
|
|
277
|
+
const availableProperties = propertyEntries.filter(
|
|
278
|
+
([, propSchema]) => propSchema.isOptional === true
|
|
279
|
+
);
|
|
280
|
+
// A required property is guaranteed present, so a has/doesn't-have
|
|
281
|
+
// toggle would be meaningless for it (same reasoning `availableProperties`
|
|
282
|
+
// already uses to leave it out of the "Add property" pull-down) - but it
|
|
283
|
+
// still gets its own row, via `buildRequiredPropertyRow`'s opt-in
|
|
284
|
+
// checkbox, so it doesn't silently force a search constraint the user
|
|
285
|
+
// never asked for just by its parent object existing.
|
|
286
|
+
const requiredProperties = propertyEntries.filter(
|
|
287
|
+
([, propSchema]) => propSchema.isOptional !== true
|
|
288
|
+
);
|
|
289
|
+
const requiredArr = requiredProperties.map(([propertyName, propSchema]) => (
|
|
290
|
+
buildRequiredPropertyRow({
|
|
291
|
+
propertyName, propSchema, path, typeNamespace, topRoot, types,
|
|
292
|
+
originalJSON
|
|
293
|
+
})
|
|
294
|
+
));
|
|
295
|
+
|
|
296
|
+
return ['jsoe-search-object', {
|
|
297
|
+
dataset: {searchPath: path, searchKind: 'object'},
|
|
298
|
+
title: label,
|
|
299
|
+
$define: {
|
|
300
|
+
/** @this {HTMLElement} */
|
|
301
|
+
connectedCallback () {
|
|
302
|
+
if (propertyEntries.length > 0) {
|
|
303
|
+
syncObjectValidity(this);
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
/** @this {HTMLElement} */
|
|
307
|
+
getQuery () {
|
|
308
|
+
const rows = [...this.children].filter(hasGetQuery);
|
|
309
|
+
return combineAnd(rows.map((row) => row.getQuery()));
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}, [
|
|
313
|
+
['div', {class: 'searchObjectControls'}, [
|
|
314
|
+
['span', {class: 'searchLabel'}, [label]],
|
|
315
|
+
availableProperties.length
|
|
316
|
+
? ['label', [
|
|
317
|
+
'Add property: ',
|
|
318
|
+
['select', {class: 'addPropertySelect'}, [
|
|
319
|
+
['option', {value: ''}, ['(choose a property)']],
|
|
320
|
+
...availableProperties.map(([propertyName]) => (
|
|
321
|
+
['option', {value: propertyName}, [propertyName]]
|
|
322
|
+
))
|
|
323
|
+
]]
|
|
324
|
+
]]
|
|
325
|
+
: ['span', ['(no optional properties to search on)']],
|
|
326
|
+
['button', {
|
|
327
|
+
type: 'button',
|
|
328
|
+
$on: {
|
|
329
|
+
click () {
|
|
330
|
+
const container = this.closest('jsoe-search-object');
|
|
331
|
+
const select = /** @type {HTMLSelectElement|null} */ (
|
|
332
|
+
container?.querySelector('select.addPropertySelect')
|
|
333
|
+
);
|
|
334
|
+
const propertyName = select?.value;
|
|
335
|
+
if (!container || !select || !propertyName) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const propSchema = objectSchemaObject.properties[propertyName];
|
|
339
|
+
const row = buildHasPropertyRow({
|
|
340
|
+
propertyName, propSchema, path, typeNamespace, topRoot, types,
|
|
341
|
+
originalJSON, addPropertySelect: select
|
|
342
|
+
});
|
|
343
|
+
container.append(row);
|
|
344
|
+
const option = /** @type {HTMLOptionElement|null} */ (
|
|
345
|
+
select.querySelector(
|
|
346
|
+
`option[value="${CSS.escape(propertyName)}"]`
|
|
347
|
+
)
|
|
348
|
+
);
|
|
349
|
+
if (option) {
|
|
350
|
+
option.disabled = true;
|
|
351
|
+
}
|
|
352
|
+
select.value = '';
|
|
353
|
+
syncObjectValidity(/** @type {HTMLElement} */ (container));
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}, ['Add']]
|
|
357
|
+
]],
|
|
358
|
+
...requiredArr,
|
|
359
|
+
// Placed last purely for markup order; a plain rendered-but-off-
|
|
360
|
+
// screen input, so its position among siblings has no visual effect.
|
|
361
|
+
...(propertyEntries.length > 0 ? [buildAtLeastOneSentinel()] : [])
|
|
362
|
+
]];
|
|
363
|
+
},
|
|
364
|
+
getQuery: getQueryViaElement
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
export default objectSearchType;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import {buildPathLabel} from '../searchUtils.js';
|
|
2
|
+
import {makePassThroughLeaf} from '../queryTreeBuilders.js';
|
|
3
|
+
import {findSearchElement, getQueryViaElement, hasGetQuery} from '../searchElementUtils.js';
|
|
4
|
+
import {buildSearchWidget} from '../searchDispatch.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Promise, Literal, catch: pass on children (README) - a promise wraps
|
|
12
|
+
* exactly one value at the same conceptual path (no path segment to add,
|
|
13
|
+
* unlike array's `*`/record's `*key`/`*value`), so this recurses into
|
|
14
|
+
* `.value`'s own search widget and wraps whatever it produces in a
|
|
15
|
+
* `passThrough` leaf (`queryTree.js`) purely so the tree keeps visible that
|
|
16
|
+
* the leaf was reached through a promise, rather than returning the child's
|
|
17
|
+
* leaf bare. ("Literal" needs no module of its own: `getSearchSchemaType`
|
|
18
|
+
* already resolves a `literal` schema straight to its value's own type via
|
|
19
|
+
* `getSchemaType`, e.g. a literal string dispatches to `stringSearchType.js`
|
|
20
|
+
* unchanged).
|
|
21
|
+
* @type {SearchTypeObject}
|
|
22
|
+
*/
|
|
23
|
+
const promiseSearchType = {
|
|
24
|
+
buildUI ({schemaObject, path, typeNamespace, topRoot, types, originalJSON}) {
|
|
25
|
+
const label = buildPathLabel(schemaObject, path);
|
|
26
|
+
const promiseSchemaObject = /** @type {import('zodexy').SzPromise} */ (
|
|
27
|
+
schemaObject
|
|
28
|
+
);
|
|
29
|
+
const childArr = buildSearchWidget({
|
|
30
|
+
schemaObject: promiseSchemaObject.value,
|
|
31
|
+
path,
|
|
32
|
+
typeNamespace,
|
|
33
|
+
topRoot,
|
|
34
|
+
types,
|
|
35
|
+
originalJSON
|
|
36
|
+
});
|
|
37
|
+
return ['jsoe-search-promise', {
|
|
38
|
+
dataset: {searchPath: path, searchKind: 'promise'},
|
|
39
|
+
title: label,
|
|
40
|
+
$define: {
|
|
41
|
+
/** @this {HTMLElement} */
|
|
42
|
+
getQuery () {
|
|
43
|
+
const searchPath = this.dataset.searchPath ?? '';
|
|
44
|
+
const childEl = findSearchElement(this, searchPath);
|
|
45
|
+
const childQuery = childEl && hasGetQuery(childEl)
|
|
46
|
+
? childEl.getQuery()
|
|
47
|
+
: undefined;
|
|
48
|
+
return childQuery === undefined
|
|
49
|
+
? undefined
|
|
50
|
+
: makePassThroughLeaf(searchPath, childQuery);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}, [
|
|
54
|
+
['span', {class: 'searchLabel'}, [`${label} (resolved value)`]],
|
|
55
|
+
childArr
|
|
56
|
+
]];
|
|
57
|
+
},
|
|
58
|
+
getQuery: getQueryViaElement
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export default promiseSearchType;
|