@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,122 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, findOwnControl, isExemptedByAncestorHasProperty
|
|
3
|
+
} from '../searchUtils.js';
|
|
4
|
+
import {makeBlobHTMLLeaf} from '../queryTreeBuilders.js';
|
|
5
|
+
import {getQueryViaElement} from '../searchElementUtils.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Blob HTML: XPath, CSS selectors, full text search, regex search of raw
|
|
13
|
+
* HTML (README) - a mode `<select>` plus one value control, the same
|
|
14
|
+
* "pick a mode, give it one value" shape as `buildLiteralRegexControls`
|
|
15
|
+
* (`searchUtils.js`), but not built through it: the four modes and the
|
|
16
|
+
* `blobHTML` leaf kind they produce are specific to this one type, with no
|
|
17
|
+
* second caller to share the helper with. The value control is a single-line
|
|
18
|
+
* `<input>` for XPath/CSS-selector/regex, but swaps to a `<textarea>` for
|
|
19
|
+
* "Full text search" mode alone, since a search phrase in a body of text is
|
|
20
|
+
* the one mode actually expected to run to more than one line - both share
|
|
21
|
+
* the same class, so the mode `<select>`'s `change` handler (and `getQuery`)
|
|
22
|
+
* only need the tag name to tell them apart. Only the currently-visible one
|
|
23
|
+
* of the pair is ever `required` (toggled alongside `hidden` by the mode
|
|
24
|
+
* `change` handler): a `required` field that's merely hidden, rather than
|
|
25
|
+
* also un-required, still blocks the form's validity even though the user
|
|
26
|
+
* has no way to see or fill it.
|
|
27
|
+
*
|
|
28
|
+
* The `change` handler also checks `isExemptedByAncestorHasProperty` before
|
|
29
|
+
* (re-)asserting `required` on the now-visible control: nested as an
|
|
30
|
+
* optional object property's own child widget, an enclosing "Has property"
|
|
31
|
+
* already provides a complete constraint on its own (the same relief
|
|
32
|
+
* `setDescendantsRequired` gives other `required`-attribute controls), but
|
|
33
|
+
* that relief is a one-time toggle applied *before* `revalidateDescendants`
|
|
34
|
+
* re-dispatches a synthetic `change` on this very `<select>` - without this
|
|
35
|
+
* check, that synthetic event would immediately reassert `required` on
|
|
36
|
+
* whichever control the current mode makes visible, undoing the exemption
|
|
37
|
+
* `setDescendantsRequired` had just granted.
|
|
38
|
+
* @type {SearchTypeObject}
|
|
39
|
+
*/
|
|
40
|
+
const blobHTMLSearchType = {
|
|
41
|
+
buildUI ({schemaObject, path, typeNamespace}) {
|
|
42
|
+
const label = buildPathLabel(schemaObject, path);
|
|
43
|
+
const name = `${typeNamespace}-blobHTML`;
|
|
44
|
+
return ['jsoe-search-blob-html', {
|
|
45
|
+
dataset: {searchPath: path, searchKind: 'blobHTML'},
|
|
46
|
+
title: label,
|
|
47
|
+
$define: {
|
|
48
|
+
/** @this {HTMLElement} */
|
|
49
|
+
getQuery () {
|
|
50
|
+
const searchPath = this.dataset.searchPath ?? '';
|
|
51
|
+
const mode = /** @type {HTMLSelectElement|undefined} */ (
|
|
52
|
+
findOwnControl(this, 'select.jsoeSearchBlobHTMLMode')
|
|
53
|
+
)?.value;
|
|
54
|
+
const value = /** @type {HTMLInputElement|HTMLTextAreaElement|undefined} */ (
|
|
55
|
+
findOwnControl(
|
|
56
|
+
this,
|
|
57
|
+
`${mode === 'fullText' ? 'textarea' : 'input'}.jsoeSearchBlobHTMLValue`
|
|
58
|
+
)
|
|
59
|
+
)?.value;
|
|
60
|
+
if (!value || !mode) {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
return makeBlobHTMLLeaf(
|
|
64
|
+
searchPath,
|
|
65
|
+
/** @type {import('../queryTree.js').QueryBlobHTMLLeaf['mode']} */ (mode),
|
|
66
|
+
value
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}, [
|
|
71
|
+
['span', {class: 'searchLabel'}, [label]],
|
|
72
|
+
['label', [
|
|
73
|
+
'Mode: ',
|
|
74
|
+
['select', {
|
|
75
|
+
name: `${name}-mode`,
|
|
76
|
+
class: 'jsoeSearchBlobHTMLMode',
|
|
77
|
+
$on: {
|
|
78
|
+
change () {
|
|
79
|
+
const container = this.closest('jsoe-search-blob-html');
|
|
80
|
+
const input = /** @type {HTMLInputElement|null|undefined} */ (
|
|
81
|
+
container?.querySelector('input.jsoeSearchBlobHTMLValue')
|
|
82
|
+
);
|
|
83
|
+
const textarea = /** @type {HTMLTextAreaElement|null|undefined} */ (
|
|
84
|
+
container?.querySelector('textarea.jsoeSearchBlobHTMLValue')
|
|
85
|
+
);
|
|
86
|
+
const isFullText = /** @type {HTMLSelectElement} */ (this).value ===
|
|
87
|
+
'fullText';
|
|
88
|
+
const exempted = container !== null &&
|
|
89
|
+
isExemptedByAncestorHasProperty(container);
|
|
90
|
+
if (input) {
|
|
91
|
+
input.hidden = isFullText;
|
|
92
|
+
input.required = !isFullText && !exempted;
|
|
93
|
+
}
|
|
94
|
+
if (textarea) {
|
|
95
|
+
textarea.hidden = !isFullText;
|
|
96
|
+
textarea.required = isFullText && !exempted;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}, [
|
|
101
|
+
['option', {value: 'xpath'}, ['XPath']],
|
|
102
|
+
['option', {value: 'cssSelector'}, ['CSS selector']],
|
|
103
|
+
['option', {value: 'fullText'}, ['Full text search']],
|
|
104
|
+
['option', {value: 'rawHTMLRegex'}, ['Regex search of raw HTML']]
|
|
105
|
+
]]
|
|
106
|
+
]],
|
|
107
|
+
['label', [
|
|
108
|
+
'Value: ',
|
|
109
|
+
['input', {
|
|
110
|
+
type: 'text', name: `${name}-value`, class: 'jsoeSearchBlobHTMLValue',
|
|
111
|
+
required: true
|
|
112
|
+
}],
|
|
113
|
+
['textarea', {
|
|
114
|
+
name: `${name}-value`, class: 'jsoeSearchBlobHTMLValue', hidden: true
|
|
115
|
+
}]
|
|
116
|
+
]]
|
|
117
|
+
]];
|
|
118
|
+
},
|
|
119
|
+
getQuery: getQueryViaElement
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export default blobHTMLSearchType;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, buildCheckbox, readCheckbox, buildOptInFieldset,
|
|
3
|
+
readOptInChecked, wireOptInFieldset, buildAtLeastOneSentinel, syncAtLeastOneCheck
|
|
4
|
+
} from '../searchUtils.js';
|
|
5
|
+
import {makeMapRecordJointLeaf} from '../queryTreeBuilders.js';
|
|
6
|
+
import {findSearchElement, getQueryViaElement, hasGetQuery} from '../searchElementUtils.js';
|
|
7
|
+
import {buildSearchWidget} from '../searchDispatch.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {Element} root - a `jsoe-search-record` element
|
|
15
|
+
* @returns {void}
|
|
16
|
+
*/
|
|
17
|
+
function syncKeyValueValidity (root) {
|
|
18
|
+
syncAtLeastOneCheck(
|
|
19
|
+
root, () => readOptInChecked(root, 'key') || readOptInChecked(root, 'value')
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Record search is "key-schema search AND/OR value-schema search,"
|
|
25
|
+
* structurally unlike object's additive "has property" (search plan §1) -
|
|
26
|
+
* recurses into both the `key` and `value` schemas' own search widgets
|
|
27
|
+
* (`*key`/`*value` path segments, `queryTree.js`), and lets the user say
|
|
28
|
+
* whether a match must come from the *same* entry ("has key 2-4 and value
|
|
29
|
+
* 7-9", README) via the "joint" toggle on the resulting `mapRecordJoint`
|
|
30
|
+
* leaf - also used for `looseRecord`, aliased to this same module in
|
|
31
|
+
* `searchDispatch.js` since the search semantics are identical. Key and
|
|
32
|
+
* value each get their own `buildOptInFieldset` (see `mapSearchType.js`'s
|
|
33
|
+
* matching doc for why), but leaving *both* unopted-in is itself invalid via
|
|
34
|
+
* `buildAtLeastOneSentinel`.
|
|
35
|
+
* @type {SearchTypeObject}
|
|
36
|
+
*/
|
|
37
|
+
const recordSearchType = {
|
|
38
|
+
buildUI ({schemaObject, path, typeNamespace, topRoot, types, originalJSON}) {
|
|
39
|
+
const label = buildPathLabel(schemaObject, path);
|
|
40
|
+
const name = `${typeNamespace}-record`;
|
|
41
|
+
const recordSchemaObject = /** @type {import('zodexy').SzRecord} */ (
|
|
42
|
+
schemaObject
|
|
43
|
+
);
|
|
44
|
+
const keyPath = `${path}/*key`;
|
|
45
|
+
const valuePath = `${path}/*value`;
|
|
46
|
+
const keyArr = buildSearchWidget({
|
|
47
|
+
schemaObject: recordSchemaObject.key,
|
|
48
|
+
path: keyPath,
|
|
49
|
+
typeNamespace,
|
|
50
|
+
topRoot,
|
|
51
|
+
types,
|
|
52
|
+
originalJSON
|
|
53
|
+
});
|
|
54
|
+
const valueArr = buildSearchWidget({
|
|
55
|
+
schemaObject: recordSchemaObject.value,
|
|
56
|
+
path: valuePath,
|
|
57
|
+
typeNamespace,
|
|
58
|
+
topRoot,
|
|
59
|
+
types,
|
|
60
|
+
originalJSON
|
|
61
|
+
});
|
|
62
|
+
return ['jsoe-search-record', {
|
|
63
|
+
dataset: {searchPath: path, searchKind: 'record'},
|
|
64
|
+
title: label,
|
|
65
|
+
$define: {
|
|
66
|
+
/** @this {HTMLElement} */
|
|
67
|
+
connectedCallback () {
|
|
68
|
+
wireOptInFieldset(this, 'key', () => syncKeyValueValidity(this));
|
|
69
|
+
wireOptInFieldset(this, 'value', () => syncKeyValueValidity(this));
|
|
70
|
+
syncKeyValueValidity(this);
|
|
71
|
+
},
|
|
72
|
+
/** @this {HTMLElement} */
|
|
73
|
+
getQuery () {
|
|
74
|
+
const searchPath = this.dataset.searchPath ?? '';
|
|
75
|
+
const keyEl = findSearchElement(this, `${searchPath}/*key`);
|
|
76
|
+
const valueEl = findSearchElement(this, `${searchPath}/*value`);
|
|
77
|
+
const keyQuery = keyEl && hasGetQuery(keyEl) && readOptInChecked(this, 'key')
|
|
78
|
+
? keyEl.getQuery()
|
|
79
|
+
: undefined;
|
|
80
|
+
const valueQuery = valueEl && hasGetQuery(valueEl) && readOptInChecked(this, 'value')
|
|
81
|
+
? valueEl.getQuery()
|
|
82
|
+
: undefined;
|
|
83
|
+
if (!keyQuery && !valueQuery) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
const joint = readCheckbox(this);
|
|
87
|
+
return makeMapRecordJointLeaf(searchPath, joint, keyQuery, valueQuery);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}, [
|
|
91
|
+
['span', {class: 'searchLabel'}, [label]],
|
|
92
|
+
...buildOptInFieldset({
|
|
93
|
+
name: `${name}-key`, key: 'key', label: 'Key matches', children: [keyArr]
|
|
94
|
+
}),
|
|
95
|
+
...buildOptInFieldset({
|
|
96
|
+
name: `${name}-value`, key: 'value', label: 'Value matches', children: [valueArr]
|
|
97
|
+
}),
|
|
98
|
+
buildCheckbox({name: `${name}-joint`, label: 'Require same entry'}),
|
|
99
|
+
buildAtLeastOneSentinel()
|
|
100
|
+
]];
|
|
101
|
+
},
|
|
102
|
+
getQuery: getQueryViaElement
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export default recordSearchType;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, buildLengthSizeControls, readLengthSizeQuery,
|
|
3
|
+
buildOptInFieldset, readOptInChecked, wireOptInFieldset,
|
|
4
|
+
buildAtLeastOneSentinel, syncAtLeastOneCheck
|
|
5
|
+
} from '../searchUtils.js';
|
|
6
|
+
import {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-tuple` element
|
|
16
|
+
* @returns {void}
|
|
17
|
+
*/
|
|
18
|
+
function syncTupleValidity (root) {
|
|
19
|
+
const itemCount = Number(/** @type {HTMLElement} */ (root).dataset.itemCount ?? '0');
|
|
20
|
+
const hasRest = /** @type {HTMLElement} */ (root).dataset.hasRest === 'true';
|
|
21
|
+
syncAtLeastOneCheck(root, () => (
|
|
22
|
+
Array.from({length: itemCount}, (_, idx) => String(idx)).some(
|
|
23
|
+
(key) => readOptInChecked(root, key)
|
|
24
|
+
) ||
|
|
25
|
+
(hasRest && (readOptInChecked(root, 'rest') || readLengthSizeQuery(root, '') !== undefined))
|
|
26
|
+
));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Each fixed position gets its own control from `.items[i]`, not one
|
|
31
|
+
* control repeated per element (search plan §1 - unlike the value-editing
|
|
32
|
+
* side, this gets a dedicated module rather than delegating to
|
|
33
|
+
* `arraySearchType.js`, since positions aren't interchangeable). A tuple
|
|
34
|
+
* with no `rest` has an inherently fixed length (`items.length`), so - as
|
|
35
|
+
* with a fixed-length array - no length control is shown for it; "with rest
|
|
36
|
+
* has size search as with arrays" (README) applies once `rest` is present:
|
|
37
|
+
* total length becomes a variable-length `lengthSize` control (`min:
|
|
38
|
+
* items.length`, no sparse toggle - not applicable to a tuple), and the
|
|
39
|
+
* `rest` element itself recurses into its own search widget under the same
|
|
40
|
+
* `*` path-segment convention `arraySearchType.js` uses for its element.
|
|
41
|
+
* Leaving every position, the rest element, and (when present) the length
|
|
42
|
+
* unconfigured at once is invalid (`buildAtLeastOneSentinel`), the same as
|
|
43
|
+
* `arraySearchType.js`/`setSearchType.js`/`filelistSearchType.js`.
|
|
44
|
+
* @type {SearchTypeObject}
|
|
45
|
+
*/
|
|
46
|
+
const tupleSearchType = {
|
|
47
|
+
buildUI ({schemaObject, path, typeNamespace, topRoot, types, originalJSON}) {
|
|
48
|
+
const label = buildPathLabel(schemaObject, path);
|
|
49
|
+
const name = `${typeNamespace}-tuple`;
|
|
50
|
+
const tupleSchemaObject = /** @type {import('zodexy').SzTuple} */ (
|
|
51
|
+
schemaObject
|
|
52
|
+
);
|
|
53
|
+
const {items, rest} = tupleSchemaObject;
|
|
54
|
+
|
|
55
|
+
const itemArrs = items.map((itemSchema, idx) => buildSearchWidget({
|
|
56
|
+
schemaObject: itemSchema,
|
|
57
|
+
path: `${path}/${idx}`,
|
|
58
|
+
typeNamespace,
|
|
59
|
+
topRoot,
|
|
60
|
+
types,
|
|
61
|
+
originalJSON
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
const restElementPath = `${path}/*`;
|
|
65
|
+
const restArr = rest
|
|
66
|
+
? buildSearchWidget({
|
|
67
|
+
schemaObject: rest,
|
|
68
|
+
path: restElementPath,
|
|
69
|
+
typeNamespace,
|
|
70
|
+
topRoot,
|
|
71
|
+
types,
|
|
72
|
+
originalJSON
|
|
73
|
+
})
|
|
74
|
+
: undefined;
|
|
75
|
+
|
|
76
|
+
/** @type {import('../../types.js').JamilihArray[]} */
|
|
77
|
+
const children = [['span', {class: 'searchLabel'}, [label]]];
|
|
78
|
+
itemArrs.forEach((itemArr, idx) => {
|
|
79
|
+
children.push(...buildOptInFieldset({
|
|
80
|
+
name: `${name}-${idx}`, key: String(idx), label: `Position ${idx} matches`,
|
|
81
|
+
children: [itemArr]
|
|
82
|
+
}));
|
|
83
|
+
});
|
|
84
|
+
if (rest) {
|
|
85
|
+
const restChild = /** @type {import('../../types.js').JamilihArray} */ (restArr);
|
|
86
|
+
children.push(
|
|
87
|
+
...buildLengthSizeControls({
|
|
88
|
+
name, min: items.length, max: undefined, includeSparse: false
|
|
89
|
+
}),
|
|
90
|
+
...buildOptInFieldset({
|
|
91
|
+
name: `${name}-rest`, key: 'rest', label: 'Rest element matches',
|
|
92
|
+
children: [restChild]
|
|
93
|
+
})
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
children.push(buildAtLeastOneSentinel());
|
|
97
|
+
|
|
98
|
+
return ['jsoe-search-tuple', {
|
|
99
|
+
dataset: {
|
|
100
|
+
searchPath: path, searchKind: 'tuple',
|
|
101
|
+
itemCount: String(items.length), hasRest: rest ? 'true' : ''
|
|
102
|
+
},
|
|
103
|
+
title: label,
|
|
104
|
+
$define: {
|
|
105
|
+
// Reads `itemCount`/`hasRest` off `this.dataset` rather than
|
|
106
|
+
// closing over `items`/`rest`: `$define`'s mixin is installed
|
|
107
|
+
// once on the shared prototype the first time this tag is
|
|
108
|
+
// defined, so a second tuple widget on the same page would
|
|
109
|
+
// otherwise silently reuse the first tuple's item count/rest-ness.
|
|
110
|
+
/** @this {HTMLElement} */
|
|
111
|
+
connectedCallback () {
|
|
112
|
+
const itemCount = Number(this.dataset.itemCount ?? '0');
|
|
113
|
+
Array.from({length: itemCount}, (_, idx) => String(idx)).forEach(
|
|
114
|
+
(key) => wireOptInFieldset(this, key, () => syncTupleValidity(this))
|
|
115
|
+
);
|
|
116
|
+
if (this.dataset.hasRest === 'true') {
|
|
117
|
+
wireOptInFieldset(this, 'rest', () => syncTupleValidity(this));
|
|
118
|
+
this.querySelector('input.jsoeSearchSize')?.addEventListener(
|
|
119
|
+
'input', () => syncTupleValidity(this)
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
syncTupleValidity(this);
|
|
123
|
+
},
|
|
124
|
+
/** @this {HTMLElement} */
|
|
125
|
+
getQuery () {
|
|
126
|
+
const searchPath = this.dataset.searchPath ?? '';
|
|
127
|
+
const itemCount = Number(this.dataset.itemCount ?? '0');
|
|
128
|
+
const hasRest = this.dataset.hasRest === 'true';
|
|
129
|
+
const itemLeaves = Array.from({length: itemCount}, (_, idx) => {
|
|
130
|
+
if (!readOptInChecked(this, String(idx))) {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
const itemEl = findSearchElement(this, `${searchPath}/${idx}`);
|
|
134
|
+
return itemEl && hasGetQuery(itemEl) ? itemEl.getQuery() : undefined;
|
|
135
|
+
});
|
|
136
|
+
if (!hasRest) {
|
|
137
|
+
return combineAnd(itemLeaves);
|
|
138
|
+
}
|
|
139
|
+
const lengthLeaf = readLengthSizeQuery(this, searchPath);
|
|
140
|
+
const restEl = findSearchElement(this, `${searchPath}/*`);
|
|
141
|
+
const restLeaf = restEl && hasGetQuery(restEl) && readOptInChecked(this, 'rest')
|
|
142
|
+
? restEl.getQuery()
|
|
143
|
+
: undefined;
|
|
144
|
+
return combineAnd([...itemLeaves, lengthLeaf, restLeaf]);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}, children];
|
|
148
|
+
},
|
|
149
|
+
getQuery: getQueryViaElement
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export default tupleSearchType;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {buildPathLabel, buildMultiSelect, readMultiSelect} from '../searchUtils.js';
|
|
2
|
+
import {makeMultiSelectLeaf} from '../queryTreeBuilders.js';
|
|
3
|
+
import {getQueryViaElement} from '../searchElementUtils.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Special number: multiple select of "Infinity", "-Infinity" (README;
|
|
11
|
+
* `NaN` is covered separately by `nanSearchType.js`'s presence-only
|
|
12
|
+
* control, since it's its own zodex schema type - `SpecialRealNumberType.js`
|
|
13
|
+
* itself covers exactly `Infinity`/`-Infinity`/`-0`, not `NaN`).
|
|
14
|
+
* @type {SearchTypeObject}
|
|
15
|
+
*/
|
|
16
|
+
const SpecialRealNumberSearchType = {
|
|
17
|
+
buildUI ({schemaObject, path, typeNamespace}) {
|
|
18
|
+
const label = buildPathLabel(schemaObject, path);
|
|
19
|
+
const name = `${typeNamespace}-SpecialRealNumber`;
|
|
20
|
+
return ['jsoe-search-special-real-number', {
|
|
21
|
+
dataset: {searchPath: path, searchKind: 'SpecialRealNumber'},
|
|
22
|
+
title: label,
|
|
23
|
+
$define: {
|
|
24
|
+
/** @this {HTMLElement} */
|
|
25
|
+
getQuery () {
|
|
26
|
+
const selected = readMultiSelect(this);
|
|
27
|
+
return selected.length
|
|
28
|
+
? makeMultiSelectLeaf(this.dataset.searchPath ?? '', {$in: selected})
|
|
29
|
+
: undefined;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}, [
|
|
33
|
+
['span', {class: 'searchLabel'}, [label]],
|
|
34
|
+
buildMultiSelect({
|
|
35
|
+
name, options: ['Infinity', '-Infinity', '-0'], required: true
|
|
36
|
+
})
|
|
37
|
+
]];
|
|
38
|
+
},
|
|
39
|
+
getQuery: getQueryViaElement
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default SpecialRealNumberSearchType;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, buildRangeInputsPair, readRangeInputsPair, syncRangeValidity
|
|
3
|
+
} from '../searchUtils.js';
|
|
4
|
+
import {makeRangeLeaf} from '../queryTreeBuilders.js';
|
|
5
|
+
import {getQueryViaElement} from '../searchElementUtils.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* BufferSource: OR Range/Is Not Range (README) - a byte-length range, per
|
|
13
|
+
* the build order's own note that `buffersource` (like `function`) is
|
|
14
|
+
* "fuzzy" enough in the README to ship as a minimal, honest stub rather
|
|
15
|
+
* than over-build past what the spec defines. `buffersource` is one of
|
|
16
|
+
* jsoe's "checked" types (`{type: 'any', checks: [{name: 'buffersource'}]}`)
|
|
17
|
+
* with no schema-level byte-length bounds to read `min`/`max` HTML
|
|
18
|
+
* attributes from, unlike `array`'s `minLength`/`maxLength`.
|
|
19
|
+
* @type {SearchTypeObject}
|
|
20
|
+
*/
|
|
21
|
+
const buffersourceSearchType = {
|
|
22
|
+
buildUI ({schemaObject, path, typeNamespace}) {
|
|
23
|
+
const label = buildPathLabel(schemaObject, path);
|
|
24
|
+
const name = `${typeNamespace}-buffersource`;
|
|
25
|
+
return ['jsoe-search-buffersource', {
|
|
26
|
+
dataset: {searchPath: path, searchKind: 'buffersource'},
|
|
27
|
+
title: label,
|
|
28
|
+
$define: {
|
|
29
|
+
/** @this {HTMLElement} */
|
|
30
|
+
connectedCallback () {
|
|
31
|
+
syncRangeValidity(this);
|
|
32
|
+
},
|
|
33
|
+
/** @this {HTMLElement} */
|
|
34
|
+
getQuery () {
|
|
35
|
+
const {gte, lte} = readRangeInputsPair(this);
|
|
36
|
+
if (gte === '' && lte === '') {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
return makeRangeLeaf(this.dataset.searchPath ?? '', 'buffersource', {
|
|
40
|
+
...(gte === '' ? {} : {$gte: Number(gte)}),
|
|
41
|
+
...(lte === '' ? {} : {$lte: Number(lte)})
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}, [
|
|
46
|
+
['span', {class: 'searchLabel'}, [`${label} (byte length)`]],
|
|
47
|
+
...buildRangeInputsPair({name, min: 0})
|
|
48
|
+
]];
|
|
49
|
+
},
|
|
50
|
+
getQuery: getQueryViaElement
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default buffersourceSearchType;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {makeDomShapeSearchType} from '../searchElementUtils.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* DOMMatrix: numeric search ranges for children; "Is/Is not Readonly";
|
|
5
|
+
* "Is/Is not 3d" (README) - see `searchElementUtils.js`'s
|
|
6
|
+
* `makeDomShapeSearchType` for the shared implementation. `dimensionKeys`
|
|
7
|
+
* covers both the 2D (`a`-`f`) and 3D (`m11`-`m44`) property sets at once;
|
|
8
|
+
* see that factory's doc for why.
|
|
9
|
+
* @type {import('../searchDispatch.js').SearchTypeObject}
|
|
10
|
+
*/
|
|
11
|
+
const dommatrixSearchType = makeDomShapeSearchType({
|
|
12
|
+
tagName: 'jsoe-search-dommatrix',
|
|
13
|
+
dimensionKeys: [
|
|
14
|
+
'a', 'b', 'c', 'd', 'e', 'f',
|
|
15
|
+
'm11', 'm12', 'm13', 'm14',
|
|
16
|
+
'm21', 'm22', 'm23', 'm24',
|
|
17
|
+
'm31', 'm32', 'm33', 'm34',
|
|
18
|
+
'm41', 'm42', 'm43', 'm44'
|
|
19
|
+
],
|
|
20
|
+
includeReadonly: true,
|
|
21
|
+
includeDimensionCheck: true
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export default dommatrixSearchType;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {makeDomShapeSearchType} from '../searchElementUtils.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* DOMPoint: numeric search ranges for children; "Is/Is not Readonly"
|
|
5
|
+
* (README) - see `searchElementUtils.js`'s `makeDomShapeSearchType` for the
|
|
6
|
+
* shared implementation.
|
|
7
|
+
* @type {import('../searchDispatch.js').SearchTypeObject}
|
|
8
|
+
*/
|
|
9
|
+
const dompointSearchType = makeDomShapeSearchType({
|
|
10
|
+
tagName: 'jsoe-search-dompoint',
|
|
11
|
+
dimensionKeys: ['x', 'y', 'z', 'w'],
|
|
12
|
+
includeReadonly: true
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export default dompointSearchType;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {makeDomShapeSearchType} from '../searchElementUtils.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* DOMRect: numeric search ranges for children; "Is/Is not Readonly"
|
|
5
|
+
* (README) - see `searchElementUtils.js`'s `makeDomShapeSearchType` for the
|
|
6
|
+
* shared implementation.
|
|
7
|
+
* @type {import('../searchDispatch.js').SearchTypeObject}
|
|
8
|
+
*/
|
|
9
|
+
const domrectSearchType = makeDomShapeSearchType({
|
|
10
|
+
tagName: 'jsoe-search-domrect',
|
|
11
|
+
dimensionKeys: ['x', 'y', 'width', 'height'],
|
|
12
|
+
includeReadonly: true
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export default domrectSearchType;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {makeErrorFamilySearchType} from '../searchElementUtils.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Special Errors (RangeError/TypeError/SyntaxError/AggregateError/etc.):
|
|
5
|
+
* Literal/Regex search of child string properties, numeric of number
|
|
6
|
+
* children (README, same bullet as plain `Error`) - see
|
|
7
|
+
* `searchElementUtils.js`'s `makeErrorFamilySearchType` for the shared
|
|
8
|
+
* implementation.
|
|
9
|
+
* @type {import('../searchDispatch.js').SearchTypeObject}
|
|
10
|
+
*/
|
|
11
|
+
const errorsSpecialSearchType = makeErrorFamilySearchType({
|
|
12
|
+
tagName: 'jsoe-search-errors-special'
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export default errorsSpecialSearchType;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {makeUnionFamilySearchType} from './unionFamilySearchType.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Discriminated Union: "Has type <type pull-down>", using the
|
|
5
|
+
* discriminator of discriminated union (README) - the type pull-down's
|
|
6
|
+
* options are labelled by each branch's discriminator value (e.g.
|
|
7
|
+
* `'circle'`/`'square'`) rather than a generic type name, and the resulting
|
|
8
|
+
* `typeOf` leaf carries that value too (`queryTree.js`). See
|
|
9
|
+
* `unionFamilySearchType.js` for the shared implementation.
|
|
10
|
+
* @type {import('../searchDispatch.js').SearchTypeObject}
|
|
11
|
+
*/
|
|
12
|
+
const discriminatedUnionSearchType = makeUnionFamilySearchType({
|
|
13
|
+
tagName: 'jsoe-search-discriminated-union', discriminated: true
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export default discriminatedUnionSearchType;
|