@es-joy/jsoe 0.29.0 → 0.31.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 +11 -0
- package/README.md +3 -0
- package/dist/fundamentalTypes/dateType.d.ts +8 -3
- package/dist/fundamentalTypes/dateType.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/search/fundamentalTypes/arraySearchType.d.ts +11 -4
- package/dist/search/fundamentalTypes/arraySearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/bigintSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/blobSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/dateSearchType.d.ts +8 -3
- package/dist/search/fundamentalTypes/dateSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/domexceptionSearchType.d.ts +5 -5
- package/dist/search/fundamentalTypes/domexceptionSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/enumSearchType.d.ts +4 -0
- package/dist/search/fundamentalTypes/enumSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/fileSearchType.d.ts +19 -10
- package/dist/search/fundamentalTypes/fileSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/filelistSearchType.d.ts +4 -12
- package/dist/search/fundamentalTypes/filelistSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/functionSearchType.d.ts +4 -4
- package/dist/search/fundamentalTypes/functionSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/mapSearchType.d.ts +8 -4
- package/dist/search/fundamentalTypes/mapSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/numberSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/objectSearchType.d.ts +10 -4
- package/dist/search/fundamentalTypes/objectSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/regexpSearchType.d.ts +7 -1
- package/dist/search/fundamentalTypes/regexpSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/setSearchType.d.ts +5 -4
- package/dist/search/fundamentalTypes/setSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/stringSearchType.d.ts +9 -1
- package/dist/search/fundamentalTypes/stringSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/symbolSearchType.d.ts.map +1 -1
- package/dist/search/index.d.ts +18 -8
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/queryTree.d.ts +15 -1
- package/dist/search/queryTree.d.ts.map +1 -1
- package/dist/search/queryTreeBuilders.d.ts +8 -1
- package/dist/search/queryTreeBuilders.d.ts.map +1 -1
- package/dist/search/searchElementUtils.d.ts +17 -8
- package/dist/search/searchElementUtils.d.ts.map +1 -1
- package/dist/search/searchUtils.d.ts +350 -18
- package/dist/search/searchUtils.d.ts.map +1 -1
- package/dist/search/subTypes/blobHTMLSearchType.d.ts +32 -5
- package/dist/search/subTypes/blobHTMLSearchType.d.ts.map +1 -1
- package/dist/search/subTypes/recordSearchType.d.ts +4 -4
- package/dist/search/subTypes/recordSearchType.d.ts.map +1 -1
- package/dist/search/subTypes/tupleSearchType.d.ts +3 -3
- package/dist/search/subTypes/tupleSearchType.d.ts.map +1 -1
- package/dist/search/superTypes/buffersourceSearchType.d.ts.map +1 -1
- package/dist/search/unions/unionFamilySearchType.d.ts.map +1 -1
- package/package.json +3 -3
- package/pnpm-workspace.yaml +26 -26
- package/src/fundamentalTypes/dateType.js +9 -4
- package/src/fundamentalTypes/regexpType.js +1 -1
- package/src/jsoe.css +204 -0
- package/src/search/fundamentalTypes/arraySearchType.js +42 -7
- package/src/search/fundamentalTypes/bigintSearchType.js +7 -1
- package/src/search/fundamentalTypes/blobSearchType.js +2 -1
- package/src/search/fundamentalTypes/booleanSearchType.js +1 -1
- package/src/search/fundamentalTypes/dateSearchType.js +113 -20
- package/src/search/fundamentalTypes/domexceptionSearchType.js +39 -10
- package/src/search/fundamentalTypes/enumSearchType.js +5 -1
- package/src/search/fundamentalTypes/fileSearchType.js +64 -11
- package/src/search/fundamentalTypes/filelistSearchType.js +32 -7
- package/src/search/fundamentalTypes/functionSearchType.js +36 -12
- package/src/search/fundamentalTypes/mapSearchType.js +43 -13
- package/src/search/fundamentalTypes/numberSearchType.js +8 -1
- package/src/search/fundamentalTypes/objectSearchType.js +236 -17
- package/src/search/fundamentalTypes/regexpSearchType.js +29 -5
- package/src/search/fundamentalTypes/setSearchType.js +33 -7
- package/src/search/fundamentalTypes/stringSearchType.js +11 -2
- package/src/search/fundamentalTypes/symbolSearchType.js +2 -1
- package/src/search/index.js +26 -9
- package/src/search/queryTree.js +14 -2
- package/src/search/queryTreeBuilders.js +12 -2
- package/src/search/searchElementUtils.js +108 -24
- package/src/search/searchUtils.js +576 -24
- package/src/search/subTypes/blobHTMLSearchType.js +202 -9
- package/src/search/subTypes/recordSearchType.js +34 -13
- package/src/search/subTypes/tupleSearchType.js +51 -10
- package/src/search/superTypes/SpecialRealNumberSearchType.js +1 -1
- package/src/search/superTypes/buffersourceSearchType.js +7 -1
- package/src/search/unions/unionFamilySearchType.js +8 -0
- package/vendor/zod/classic/schemas.d.ts +3 -1
- package/vendor/zod/core/versions.js +1 -1
|
@@ -1,19 +1,37 @@
|
|
|
1
1
|
import {domExceptionNames} from '../../fundamentalTypes/domexceptionType.js';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
buildPathLabel, buildMultiSelect, readMultiSelect, buildLiteralRegexControls,
|
|
4
|
+
readLiteralRegexQuery, buildOptInFieldset, readOptInChecked, wireOptInFieldset,
|
|
5
|
+
buildAtLeastOneSentinel, syncAtLeastOneCheck
|
|
6
|
+
} from '../searchUtils.js';
|
|
3
7
|
import {makeMultiSelectLeaf, combineAnd} from '../queryTreeBuilders.js';
|
|
4
8
|
import {getQueryViaElement} from '../searchElementUtils.js';
|
|
9
|
+
import regexpType from '../../fundamentalTypes/regexpType.js';
|
|
5
10
|
|
|
6
11
|
/**
|
|
7
12
|
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
8
13
|
*/
|
|
9
14
|
|
|
15
|
+
/**
|
|
16
|
+
* @param {Element} root - a `jsoe-search-domexception` element
|
|
17
|
+
* @returns {void}
|
|
18
|
+
*/
|
|
19
|
+
function syncDomexceptionValidity (root) {
|
|
20
|
+
syncAtLeastOneCheck(
|
|
21
|
+
root, () => readMultiSelect(root).length > 0 || readOptInChecked(root, 'message')
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
10
25
|
/**
|
|
11
26
|
* DOMException: Literal/Regex search of child string properties; also
|
|
12
27
|
* pull-down of name for DOMException (README) - `.name` gets the
|
|
13
28
|
* multi-select pull-down (its standard predefined values, imported as-is
|
|
14
29
|
* from `domexceptionType.js`'s own `domExceptionNames` export rather than a
|
|
15
|
-
* second copy of the list
|
|
16
|
-
*
|
|
30
|
+
* second copy of the list, and already properly optional on its own - an
|
|
31
|
+
* empty selection needs no opt-in gate), `.message` gets the usual literal/
|
|
32
|
+
* regex/does-not-contain control (wrapped in `buildOptInFieldset`, since
|
|
33
|
+
* that one *does* carry a `required` Value input), combined via `$and`.
|
|
34
|
+
* `buildAtLeastOneSentinel` requires at least one of the two.
|
|
17
35
|
* @type {SearchTypeObject}
|
|
18
36
|
*/
|
|
19
37
|
const domexceptionSearchType = {
|
|
@@ -24,6 +42,14 @@ const domexceptionSearchType = {
|
|
|
24
42
|
dataset: {searchPath: path, searchKind: 'domexception'},
|
|
25
43
|
title: label,
|
|
26
44
|
$define: {
|
|
45
|
+
/** @this {HTMLElement} */
|
|
46
|
+
connectedCallback () {
|
|
47
|
+
this.querySelector('select.jsoeSearchMultiSelect')?.addEventListener(
|
|
48
|
+
'change', () => syncDomexceptionValidity(this)
|
|
49
|
+
);
|
|
50
|
+
wireOptInFieldset(this, 'message', () => syncDomexceptionValidity(this));
|
|
51
|
+
syncDomexceptionValidity(this);
|
|
52
|
+
},
|
|
27
53
|
/** @this {HTMLElement} */
|
|
28
54
|
getQuery () {
|
|
29
55
|
const searchPath = this.dataset.searchPath ?? '';
|
|
@@ -31,9 +57,9 @@ const domexceptionSearchType = {
|
|
|
31
57
|
const nameLeaf = selectedNames.length
|
|
32
58
|
? makeMultiSelectLeaf(`${searchPath}/name`, {$in: selectedNames})
|
|
33
59
|
: undefined;
|
|
34
|
-
const messageLeaf =
|
|
35
|
-
this, `${searchPath}/message`, 'message'
|
|
36
|
-
|
|
60
|
+
const messageLeaf = readOptInChecked(this, 'message')
|
|
61
|
+
? readLiteralRegexQuery(this, `${searchPath}/message`, 'message')
|
|
62
|
+
: undefined;
|
|
37
63
|
return combineAnd([nameLeaf, messageLeaf]);
|
|
38
64
|
}
|
|
39
65
|
}
|
|
@@ -43,10 +69,13 @@ const domexceptionSearchType = {
|
|
|
43
69
|
['span', ['Name: ']],
|
|
44
70
|
buildMultiSelect({name: `${name}-name`, options: domExceptionNames})
|
|
45
71
|
]],
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
buildLiteralRegexControls({
|
|
49
|
-
|
|
72
|
+
...buildOptInFieldset({
|
|
73
|
+
name: `${name}-message`, key: 'message', label: 'Message',
|
|
74
|
+
children: [buildLiteralRegexControls({
|
|
75
|
+
name: `${name}-message`, key: 'message', flagOptions: regexpType.allowedFlags
|
|
76
|
+
})]
|
|
77
|
+
}),
|
|
78
|
+
buildAtLeastOneSentinel()
|
|
50
79
|
]];
|
|
51
80
|
},
|
|
52
81
|
getQuery: getQueryViaElement
|
|
@@ -19,6 +19,10 @@ import {getQueryViaElement} from '../searchElementUtils.js';
|
|
|
19
19
|
* from its values (unlike a plain `z.enum([...])`, where they're the same)
|
|
20
20
|
* still gets a usable widget here, just not that extra key-vs-value mode
|
|
21
21
|
* yet; `values`'s keys are shown alongside their value as a hint.
|
|
22
|
+
* `buildMultiSelect`'s `required` leaves the whole selection invalid until
|
|
23
|
+
* at least one value is picked, natively (no build-time-empty gap like
|
|
24
|
+
* `buildRangeInputsPair`'s custom validity needed a `connectedCallback`
|
|
25
|
+
* for - `<select multiple required>` is evaluated by the browser itself).
|
|
22
26
|
* @type {SearchTypeObject}
|
|
23
27
|
*/
|
|
24
28
|
const enumSearchType = {
|
|
@@ -49,7 +53,7 @@ const enumSearchType = {
|
|
|
49
53
|
}
|
|
50
54
|
}, [
|
|
51
55
|
['span', {class: 'searchLabel'}, [label]],
|
|
52
|
-
buildMultiSelect({name, options})
|
|
56
|
+
buildMultiSelect({name, options, required: true})
|
|
53
57
|
]];
|
|
54
58
|
},
|
|
55
59
|
getQuery: getQueryViaElement
|
|
@@ -1,20 +1,48 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, buildLiteralRegexControls, readLiteralRegexQuery,
|
|
3
|
+
buildOptInFieldset, readOptInChecked, wireOptInFieldset,
|
|
4
|
+
buildAtLeastOneSentinel, syncAtLeastOneCheck
|
|
5
|
+
} from '../searchUtils.js';
|
|
6
|
+
import {combineAnd} from '../queryTreeBuilders.js';
|
|
2
7
|
import {getQueryViaElement} from '../searchElementUtils.js';
|
|
8
|
+
import regexpType from '../../fundamentalTypes/regexpType.js';
|
|
3
9
|
|
|
4
10
|
/**
|
|
5
11
|
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
6
12
|
*/
|
|
7
13
|
|
|
14
|
+
/**
|
|
15
|
+
* @param {Element} root - a `jsoe-search-file` element
|
|
16
|
+
* @returns {void}
|
|
17
|
+
*/
|
|
18
|
+
function syncFileValidity (root) {
|
|
19
|
+
syncAtLeastOneCheck(
|
|
20
|
+
root, () => readOptInChecked(root, 'name') || readOptInChecked(root, 'type')
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
8
24
|
/**
|
|
9
25
|
* File: OR literal or regex search/Does Not contain search (README, grouped
|
|
10
26
|
* with string/StringObject/Blob/regexp-source/symbol-description) - against
|
|
11
|
-
* the File's `.name
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
27
|
+
* both the File's `.name` and its `.type` (content/MIME type, the same
|
|
28
|
+
* facet `blobSearchType.js` targets for `Blob`), each a value-level facet
|
|
29
|
+
* the schema itself carries no constraint for (`SzFile` only has
|
|
30
|
+
* `min`/`max`/`mime`, and `mime` is a fixed *allow-list* for validation, not
|
|
31
|
+
* a per-instance value to search against). `name`/`type` sub-paths
|
|
32
|
+
* distinguish the two facets (`${path}/name`, `${path}/type`, matching the
|
|
33
|
+
* real `File` property each reads back), the same convention
|
|
34
|
+
* `errorSearchType.js` uses for its own multiple flat facets, combined via
|
|
35
|
+
* `$and`. Each facet is independently opt-in (`buildOptInFieldset`, so
|
|
36
|
+
* checking against just the name, or just the content type, is as easy as
|
|
37
|
+
* checking against both), but leaving *both* unopted-in is itself invalid
|
|
38
|
+
* (`buildAtLeastOneSentinel`) - the same "key or value, not necessarily
|
|
39
|
+
* both" shape `mapSearchType.js`/`recordSearchType.js` use. `SzFile`'s own
|
|
40
|
+
* `min`/`max` (byte size) is left for a later pass - the README's literal/
|
|
41
|
+
* regex bullet doesn't ask for a size range here, and README explicitly
|
|
42
|
+
* reserves that shape of control ("OR Range/Is Not Range") for
|
|
43
|
+
* `buffersource` instead. `filelistSearchType.js` recurses its element
|
|
44
|
+
* schema through this same module, so a `FileList`'s per-file search gets
|
|
45
|
+
* both facets for free.
|
|
18
46
|
* @type {SearchTypeObject}
|
|
19
47
|
*/
|
|
20
48
|
const fileSearchType = {
|
|
@@ -25,14 +53,39 @@ const fileSearchType = {
|
|
|
25
53
|
dataset: {searchPath: path, searchKind: 'file'},
|
|
26
54
|
title: label,
|
|
27
55
|
$define: {
|
|
56
|
+
/** @this {HTMLElement} */
|
|
57
|
+
connectedCallback () {
|
|
58
|
+
wireOptInFieldset(this, 'name', () => syncFileValidity(this));
|
|
59
|
+
wireOptInFieldset(this, 'type', () => syncFileValidity(this));
|
|
60
|
+
syncFileValidity(this);
|
|
61
|
+
},
|
|
28
62
|
/** @this {HTMLElement} */
|
|
29
63
|
getQuery () {
|
|
30
|
-
|
|
64
|
+
const searchPath = this.dataset.searchPath ?? '';
|
|
65
|
+
const nameLeaf = readOptInChecked(this, 'name')
|
|
66
|
+
? readLiteralRegexQuery(this, `${searchPath}/name`, 'name')
|
|
67
|
+
: undefined;
|
|
68
|
+
const typeLeaf = readOptInChecked(this, 'type')
|
|
69
|
+
? readLiteralRegexQuery(this, `${searchPath}/type`, 'type')
|
|
70
|
+
: undefined;
|
|
71
|
+
return combineAnd([nameLeaf, typeLeaf]);
|
|
31
72
|
}
|
|
32
73
|
}
|
|
33
74
|
}, [
|
|
34
|
-
['span', {class: 'searchLabel'}, [
|
|
35
|
-
|
|
75
|
+
['span', {class: 'searchLabel'}, [label]],
|
|
76
|
+
...buildOptInFieldset({
|
|
77
|
+
name: `${name}-name`, key: 'name', label: 'Name',
|
|
78
|
+
children: [buildLiteralRegexControls({
|
|
79
|
+
name: `${name}-name`, key: 'name', flagOptions: regexpType.allowedFlags
|
|
80
|
+
})]
|
|
81
|
+
}),
|
|
82
|
+
...buildOptInFieldset({
|
|
83
|
+
name: `${name}-type`, key: 'type', label: 'Content type',
|
|
84
|
+
children: [buildLiteralRegexControls({
|
|
85
|
+
name: `${name}-type`, key: 'type', flagOptions: regexpType.allowedFlags
|
|
86
|
+
})]
|
|
87
|
+
}),
|
|
88
|
+
buildAtLeastOneSentinel()
|
|
36
89
|
]];
|
|
37
90
|
},
|
|
38
91
|
getQuery: getQueryViaElement
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, buildLengthSizeControls, readLengthSizeQuery,
|
|
3
|
+
buildOptInFieldset, readOptInChecked, wireOptInFieldset,
|
|
4
|
+
buildAtLeastOneSentinel, syncAtLeastOneCheck
|
|
5
|
+
} from '../searchUtils.js';
|
|
2
6
|
import {combineAnd} from '../queryTreeBuilders.js';
|
|
3
7
|
import {findSearchElement, getQueryViaElement, hasGetQuery} from '../searchElementUtils.js';
|
|
4
8
|
import {buildSearchWidget} from '../searchDispatch.js';
|
|
@@ -16,6 +20,16 @@ import {buildSearchWidget} from '../searchDispatch.js';
|
|
|
16
20
|
* }} FilelistOutputSchema
|
|
17
21
|
*/
|
|
18
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @param {Element} root - a `jsoe-search-filelist` element
|
|
25
|
+
* @returns {void}
|
|
26
|
+
*/
|
|
27
|
+
function syncFilelistValidity (root) {
|
|
28
|
+
syncAtLeastOneCheck(
|
|
29
|
+
root, () => readLengthSizeQuery(root, '') !== undefined || readOptInChecked(root)
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
19
33
|
/**
|
|
20
34
|
* Has length/size of <number> (README, grouped with array/set/
|
|
21
35
|
* tuple-with-rest) - no sparse toggle, matching `setSearchType.js`. A
|
|
@@ -24,7 +38,10 @@ import {buildSearchWidget} from '../searchDispatch.js';
|
|
|
24
38
|
* (`src/formats/schema.js`'s `codec`/`filelist` handling); the length
|
|
25
39
|
* bounds and element schema both live on that `output` array shape, whose
|
|
26
40
|
* element recurses into `fileSearchType.js` under the same `*` path-segment
|
|
27
|
-
* convention `arraySearchType.js` uses.
|
|
41
|
+
* convention `arraySearchType.js` uses. Leaving *both* length/size and the
|
|
42
|
+
* element match unconfigured is still invalid, though
|
|
43
|
+
* (`buildAtLeastOneSentinel`), same as `arraySearchType.js`/
|
|
44
|
+
* `setSearchType.js`.
|
|
28
45
|
* @type {SearchTypeObject}
|
|
29
46
|
*/
|
|
30
47
|
const filelistSearchType = {
|
|
@@ -47,12 +64,20 @@ const filelistSearchType = {
|
|
|
47
64
|
dataset: {searchPath: path, searchKind: 'filelist'},
|
|
48
65
|
title: label,
|
|
49
66
|
$define: {
|
|
67
|
+
/** @this {HTMLElement} */
|
|
68
|
+
connectedCallback () {
|
|
69
|
+
wireOptInFieldset(this, '', () => syncFilelistValidity(this));
|
|
70
|
+
this.querySelector('input.jsoeSearchSize')?.addEventListener(
|
|
71
|
+
'input', () => syncFilelistValidity(this)
|
|
72
|
+
);
|
|
73
|
+
syncFilelistValidity(this);
|
|
74
|
+
},
|
|
50
75
|
/** @this {HTMLElement} */
|
|
51
76
|
getQuery () {
|
|
52
77
|
const searchPath = this.dataset.searchPath ?? '';
|
|
53
78
|
const lengthLeaf = readLengthSizeQuery(this, searchPath);
|
|
54
79
|
const elementEl = findSearchElement(this, `${searchPath}/*`);
|
|
55
|
-
const elementLeaf = elementEl && hasGetQuery(elementEl)
|
|
80
|
+
const elementLeaf = elementEl && hasGetQuery(elementEl) && readOptInChecked(this)
|
|
56
81
|
? elementEl.getQuery()
|
|
57
82
|
: undefined;
|
|
58
83
|
return combineAnd([lengthLeaf, elementLeaf]);
|
|
@@ -66,10 +91,10 @@ const filelistSearchType = {
|
|
|
66
91
|
max: outputSchema.maxLength,
|
|
67
92
|
includeSparse: false
|
|
68
93
|
}),
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
94
|
+
...buildOptInFieldset({
|
|
95
|
+
name: `${name}-element`, label: 'File matches', children: [elementArr]
|
|
96
|
+
}),
|
|
97
|
+
buildAtLeastOneSentinel()
|
|
73
98
|
]];
|
|
74
99
|
},
|
|
75
100
|
getQuery: getQueryViaElement
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, buildOptInFieldset, readOptInChecked, wireOptInFieldset,
|
|
3
|
+
buildAtLeastOneSentinel, syncAtLeastOneCheck
|
|
4
|
+
} from '../searchUtils.js';
|
|
2
5
|
import {combineAnd} from '../queryTreeBuilders.js';
|
|
3
6
|
import {findSearchElement, getQueryViaElement, hasGetQuery} from '../searchElementUtils.js';
|
|
4
7
|
import {buildSearchWidget} from '../searchDispatch.js';
|
|
@@ -7,6 +10,16 @@ import {buildSearchWidget} from '../searchDispatch.js';
|
|
|
7
10
|
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
8
11
|
*/
|
|
9
12
|
|
|
13
|
+
/**
|
|
14
|
+
* @param {Element} root - a `jsoe-search-function` element
|
|
15
|
+
* @returns {void}
|
|
16
|
+
*/
|
|
17
|
+
function syncFunctionValidity (root) {
|
|
18
|
+
syncAtLeastOneCheck(
|
|
19
|
+
root, () => readOptInChecked(root, 'args') || readOptInChecked(root, 'output')
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
10
23
|
/**
|
|
11
24
|
* Function; pass on args, return type (README) - recurses into both
|
|
12
25
|
* `.input` (itself a tuple, so its own per-position controls come for free
|
|
@@ -15,12 +28,16 @@ import {buildSearchWidget} from '../searchDispatch.js';
|
|
|
15
28
|
* note that `function` is "fuzzy" in the README and could ship as a
|
|
16
29
|
* minimal stub predates `tupleSearchType.js` existing; now that it does,
|
|
17
30
|
* recursing into `.input` through it is no more work than `.output` alone
|
|
18
|
-
* would have been.
|
|
31
|
+
* would have been. Each is wrapped in its own `buildOptInFieldset` (an args
|
|
32
|
+
* tuple's own positions are themselves individually opt-in, so args as a
|
|
33
|
+
* whole needs the same treatment one level up), with
|
|
34
|
+
* `buildAtLeastOneSentinel` requiring at least one of the two.
|
|
19
35
|
* @type {SearchTypeObject}
|
|
20
36
|
*/
|
|
21
37
|
const functionSearchType = {
|
|
22
38
|
buildUI ({schemaObject, path, typeNamespace, topRoot, types, originalJSON}) {
|
|
23
39
|
const label = buildPathLabel(schemaObject, path);
|
|
40
|
+
const name = `${typeNamespace}-function`;
|
|
24
41
|
const functionSchemaObject = /** @type {import('zodexy').SzFunction<any, any>} */ (
|
|
25
42
|
schemaObject
|
|
26
43
|
);
|
|
@@ -46,15 +63,22 @@ const functionSearchType = {
|
|
|
46
63
|
dataset: {searchPath: path, searchKind: 'function'},
|
|
47
64
|
title: label,
|
|
48
65
|
$define: {
|
|
66
|
+
/** @this {HTMLElement} */
|
|
67
|
+
connectedCallback () {
|
|
68
|
+
wireOptInFieldset(this, 'args', () => syncFunctionValidity(this));
|
|
69
|
+
wireOptInFieldset(this, 'output', () => syncFunctionValidity(this));
|
|
70
|
+
syncFunctionValidity(this);
|
|
71
|
+
},
|
|
49
72
|
/** @this {HTMLElement} */
|
|
50
73
|
getQuery () {
|
|
51
74
|
const searchPath = this.dataset.searchPath ?? '';
|
|
52
75
|
const argsEl = findSearchElement(this, `${searchPath}/*args`);
|
|
53
76
|
const outputEl = findSearchElement(this, `${searchPath}/*output`);
|
|
54
|
-
const argsQuery = argsEl && hasGetQuery(argsEl)
|
|
77
|
+
const argsQuery = argsEl && hasGetQuery(argsEl) && readOptInChecked(this, 'args')
|
|
55
78
|
? argsEl.getQuery()
|
|
56
79
|
: undefined;
|
|
57
|
-
const outputQuery = outputEl && hasGetQuery(outputEl)
|
|
80
|
+
const outputQuery = outputEl && hasGetQuery(outputEl) &&
|
|
81
|
+
readOptInChecked(this, 'output')
|
|
58
82
|
? outputEl.getQuery()
|
|
59
83
|
: undefined;
|
|
60
84
|
return combineAnd([argsQuery, outputQuery]);
|
|
@@ -62,14 +86,14 @@ const functionSearchType = {
|
|
|
62
86
|
}
|
|
63
87
|
}, [
|
|
64
88
|
['span', {class: 'searchLabel'}, [label]],
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
89
|
+
...buildOptInFieldset({
|
|
90
|
+
name: `${name}-args`, key: 'args', label: 'Args match', children: [argsArr]
|
|
91
|
+
}),
|
|
92
|
+
...buildOptInFieldset({
|
|
93
|
+
name: `${name}-output`, key: 'output', label: 'Return value matches',
|
|
94
|
+
children: [outputArr]
|
|
95
|
+
}),
|
|
96
|
+
buildAtLeastOneSentinel()
|
|
73
97
|
]];
|
|
74
98
|
},
|
|
75
99
|
getQuery: getQueryViaElement
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, buildCheckbox, readCheckbox, buildLengthSizeControls,
|
|
3
|
+
readLengthSizeQuery, buildOptInFieldset, readOptInChecked, wireOptInFieldset,
|
|
4
|
+
buildAtLeastOneSentinel, syncAtLeastOneCheck
|
|
5
|
+
} from '../searchUtils.js';
|
|
2
6
|
import {makeMapRecordJointLeaf, combineAnd} from '../queryTreeBuilders.js';
|
|
3
7
|
import {findSearchElement, getQueryViaElement, hasGetQuery} from '../searchElementUtils.js';
|
|
4
8
|
import {buildSearchWidget} from '../searchDispatch.js';
|
|
@@ -7,6 +11,17 @@ import {buildSearchWidget} from '../searchDispatch.js';
|
|
|
7
11
|
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
8
12
|
*/
|
|
9
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
|
+
|
|
10
25
|
/**
|
|
11
26
|
* Map, Record: string-type searches of keys, values; ideally would allow
|
|
12
27
|
* search to insist on match of key and value (README) - structurally the
|
|
@@ -15,7 +30,14 @@ import {buildSearchWidget} from '../searchDispatch.js';
|
|
|
15
30
|
* leaf), plus a `lengthSize` control for `min`/`max` (a `Map`, unlike a
|
|
16
31
|
* `Record`, carries its own size bounds in the schema - the same
|
|
17
32
|
* affordance `setSearchType.js` gets for the analogous reason), combined
|
|
18
|
-
* with the joint leaf via `$and`.
|
|
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`.
|
|
19
41
|
* @type {SearchTypeObject}
|
|
20
42
|
*/
|
|
21
43
|
const mapSearchType = {
|
|
@@ -47,16 +69,25 @@ const mapSearchType = {
|
|
|
47
69
|
dataset: {searchPath: path, searchKind: 'map'},
|
|
48
70
|
title: label,
|
|
49
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
|
+
},
|
|
50
81
|
/** @this {HTMLElement} */
|
|
51
82
|
getQuery () {
|
|
52
83
|
const searchPath = this.dataset.searchPath ?? '';
|
|
53
84
|
const lengthLeaf = readLengthSizeQuery(this, searchPath);
|
|
54
85
|
const keyEl = findSearchElement(this, `${searchPath}/*key`);
|
|
55
86
|
const valueEl = findSearchElement(this, `${searchPath}/*value`);
|
|
56
|
-
const keyQuery = keyEl && hasGetQuery(keyEl)
|
|
87
|
+
const keyQuery = keyEl && hasGetQuery(keyEl) && readOptInChecked(this, 'key')
|
|
57
88
|
? keyEl.getQuery()
|
|
58
89
|
: undefined;
|
|
59
|
-
const valueQuery = valueEl && hasGetQuery(valueEl)
|
|
90
|
+
const valueQuery = valueEl && hasGetQuery(valueEl) && readOptInChecked(this, 'value')
|
|
60
91
|
? valueEl.getQuery()
|
|
61
92
|
: undefined;
|
|
62
93
|
const jointLeaf = keyQuery || valueQuery
|
|
@@ -70,15 +101,14 @@ const mapSearchType = {
|
|
|
70
101
|
...buildLengthSizeControls({
|
|
71
102
|
name, min: mapSchemaObject.min, max: mapSchemaObject.max, includeSparse: false
|
|
72
103
|
}),
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
buildCheckbox({name: `${name}-joint`, label: 'Require same entry'})
|
|
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()
|
|
82
112
|
]];
|
|
83
113
|
},
|
|
84
114
|
getQuery: getQueryViaElement
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, buildRangeInputsPair, readRangeInputsPair, buildTriStateSelect,
|
|
3
|
+
readTriStateSelect, syncRangeValidity
|
|
4
|
+
} from '../searchUtils.js';
|
|
2
5
|
import {makeRangeLeaf, makeIntegerCheckLeaf, combineAnd} from '../queryTreeBuilders.js';
|
|
3
6
|
import {getQueryViaElement} from '../searchElementUtils.js';
|
|
4
7
|
|
|
@@ -18,6 +21,10 @@ const numberSearchType = {
|
|
|
18
21
|
dataset: {searchPath: path, searchKind: 'number'},
|
|
19
22
|
title: label,
|
|
20
23
|
$define: {
|
|
24
|
+
/** @this {HTMLElement} */
|
|
25
|
+
connectedCallback () {
|
|
26
|
+
syncRangeValidity(this);
|
|
27
|
+
},
|
|
21
28
|
/** @this {HTMLElement} */
|
|
22
29
|
getQuery () {
|
|
23
30
|
const searchPath = this.dataset.searchPath ?? '';
|