@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,72 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, buildLiteralRegexControls, readLiteralRegexQuery,
|
|
3
|
+
buildMultiSelect, readMultiSelect, findOwnControl
|
|
4
|
+
} from '../searchUtils.js';
|
|
5
|
+
import {makeMultiSelectLeaf, combineAnd} from '../queryTreeBuilders.js';
|
|
6
|
+
import {getQueryViaElement} from '../searchElementUtils.js';
|
|
7
|
+
import regexpType from '../../fundamentalTypes/regexpType.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Regexp (source): OR literal or regex search/Does Not contain search, plus
|
|
15
|
+
* a multiple-select search of flags (README). `regexpType.js`'s own
|
|
16
|
+
* `allowedFlags` list is imported as-is for the flags control (search plan
|
|
17
|
+
* §4 - already a plain exported property, no extraction needed). Flags are
|
|
18
|
+
* a property of the regexp itself, not of how its source is being matched,
|
|
19
|
+
* but the Flags control is only shown (and only contributes to the query)
|
|
20
|
+
* while the source's own Mode is "Matches regex" - searching a source
|
|
21
|
+
* literal/substring while also constraining flags is a much rarer
|
|
22
|
+
* combination, and hiding Flags the rest of the time keeps the common case
|
|
23
|
+
* uncluttered.
|
|
24
|
+
* @type {SearchTypeObject}
|
|
25
|
+
*/
|
|
26
|
+
const regexpSearchType = {
|
|
27
|
+
buildUI ({schemaObject, path, typeNamespace}) {
|
|
28
|
+
const label = buildPathLabel(schemaObject, path);
|
|
29
|
+
const name = `${typeNamespace}-regexp`;
|
|
30
|
+
return ['jsoe-search-regexp', {
|
|
31
|
+
dataset: {searchPath: path, searchKind: 'regexp'},
|
|
32
|
+
title: label,
|
|
33
|
+
$define: {
|
|
34
|
+
/** @this {HTMLElement} */
|
|
35
|
+
getQuery () {
|
|
36
|
+
const searchPath = this.dataset.searchPath ?? '';
|
|
37
|
+
const sourceLeaf = readLiteralRegexQuery(this, searchPath);
|
|
38
|
+
const mode = /** @type {HTMLSelectElement|undefined} */ (
|
|
39
|
+
findOwnControl(this, 'select.jsoeSearchMode--')
|
|
40
|
+
)?.value;
|
|
41
|
+
const selectedFlags = mode === 'regex' ? readMultiSelect(this) : [];
|
|
42
|
+
const flagsLeaf = selectedFlags.length
|
|
43
|
+
? makeMultiSelectLeaf(searchPath, {$in: selectedFlags})
|
|
44
|
+
: undefined;
|
|
45
|
+
return combineAnd([sourceLeaf, flagsLeaf]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}, [
|
|
49
|
+
['span', {class: 'searchLabel'}, [`${label} (source)`]],
|
|
50
|
+
buildLiteralRegexControls({
|
|
51
|
+
name,
|
|
52
|
+
/** @this {HTMLElement} */
|
|
53
|
+
onModeChange () {
|
|
54
|
+
const flagsLabel = this.closest('jsoe-search-regexp')?.querySelector(
|
|
55
|
+
'.searchRegexpFlags'
|
|
56
|
+
);
|
|
57
|
+
if (flagsLabel) {
|
|
58
|
+
/** @type {HTMLElement} */ (flagsLabel).hidden =
|
|
59
|
+
/** @type {HTMLSelectElement} */ (this).value !== 'regex';
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}),
|
|
63
|
+
['label', {class: 'searchRegexpFlags', hidden: true}, [
|
|
64
|
+
'Flags: ',
|
|
65
|
+
buildMultiSelect({name: `${name}-flags`, options: regexpType.allowedFlags})
|
|
66
|
+
]]
|
|
67
|
+
]];
|
|
68
|
+
},
|
|
69
|
+
getQuery: getQueryViaElement
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export default regexpSearchType;
|
|
@@ -0,0 +1,91 @@
|
|
|
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-set` element
|
|
16
|
+
* @returns {void}
|
|
17
|
+
*/
|
|
18
|
+
function syncSetValidity (root) {
|
|
19
|
+
syncAtLeastOneCheck(
|
|
20
|
+
root, () => readLengthSizeQuery(root, '') !== undefined || readOptInChecked(root)
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Has length/size of <number> (README) - no sparse toggle: unlike
|
|
26
|
+
* `array`, a `Set` cannot have holes. Also recurses into the value schema's
|
|
27
|
+
* own search widget (as `arraySearchType.js` does for its element), via the
|
|
28
|
+
* same `*` path-segment convention (`queryTree.js`), wrapped in the same
|
|
29
|
+
* `buildOptInFieldset` `arraySearchType.js` uses and for the same reason -
|
|
30
|
+
* a length/size-only search should stay valid. Leaving *both* length/size
|
|
31
|
+
* and the element match unconfigured is still invalid, though
|
|
32
|
+
* (`buildAtLeastOneSentinel`), same as `arraySearchType.js`.
|
|
33
|
+
* @type {SearchTypeObject}
|
|
34
|
+
*/
|
|
35
|
+
const setSearchType = {
|
|
36
|
+
buildUI ({schemaObject, path, typeNamespace, topRoot, types, originalJSON}) {
|
|
37
|
+
const label = buildPathLabel(schemaObject, path);
|
|
38
|
+
const name = `${typeNamespace}-set`;
|
|
39
|
+
const setSchemaObject = /** @type {import('zodexy').SzSet} */ (
|
|
40
|
+
schemaObject
|
|
41
|
+
);
|
|
42
|
+
const elementPath = `${path}/*`;
|
|
43
|
+
const elementArr = buildSearchWidget({
|
|
44
|
+
schemaObject: setSchemaObject.value,
|
|
45
|
+
path: elementPath,
|
|
46
|
+
typeNamespace,
|
|
47
|
+
topRoot,
|
|
48
|
+
types,
|
|
49
|
+
originalJSON
|
|
50
|
+
});
|
|
51
|
+
return ['jsoe-search-set', {
|
|
52
|
+
dataset: {searchPath: path, searchKind: 'set'},
|
|
53
|
+
title: label,
|
|
54
|
+
$define: {
|
|
55
|
+
/** @this {HTMLElement} */
|
|
56
|
+
connectedCallback () {
|
|
57
|
+
wireOptInFieldset(this, '', () => syncSetValidity(this));
|
|
58
|
+
this.querySelector('input.jsoeSearchSize')?.addEventListener(
|
|
59
|
+
'input', () => syncSetValidity(this)
|
|
60
|
+
);
|
|
61
|
+
syncSetValidity(this);
|
|
62
|
+
},
|
|
63
|
+
/** @this {HTMLElement} */
|
|
64
|
+
getQuery () {
|
|
65
|
+
const searchPath = this.dataset.searchPath ?? '';
|
|
66
|
+
const lengthLeaf = readLengthSizeQuery(this, searchPath);
|
|
67
|
+
const elementEl = findSearchElement(this, `${searchPath}/*`);
|
|
68
|
+
const elementLeaf = elementEl && hasGetQuery(elementEl) && readOptInChecked(this)
|
|
69
|
+
? elementEl.getQuery()
|
|
70
|
+
: undefined;
|
|
71
|
+
return combineAnd([lengthLeaf, elementLeaf]);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}, [
|
|
75
|
+
['span', {class: 'searchLabel'}, [label]],
|
|
76
|
+
...buildLengthSizeControls({
|
|
77
|
+
name,
|
|
78
|
+
min: setSchemaObject.minSize,
|
|
79
|
+
max: setSchemaObject.maxSize,
|
|
80
|
+
includeSparse: false
|
|
81
|
+
}),
|
|
82
|
+
...buildOptInFieldset({
|
|
83
|
+
name: `${name}-element`, label: 'Element matches', children: [elementArr]
|
|
84
|
+
}),
|
|
85
|
+
buildAtLeastOneSentinel()
|
|
86
|
+
]];
|
|
87
|
+
},
|
|
88
|
+
getQuery: getQueryViaElement
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export default setSearchType;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {buildPathLabel, buildLiteralRegexControls, readLiteralRegexQuery} from '../searchUtils.js';
|
|
2
|
+
import {getQueryViaElement} from '../searchElementUtils.js';
|
|
3
|
+
import regexpType from '../../fundamentalTypes/regexpType.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* OR literal or regex search/Does Not contain search (README; also covers
|
|
11
|
+
* `StringObject` and `templateLiteral`, aliased to this same module in
|
|
12
|
+
* `searchDispatch.js` since the query semantics are identical), plus - only
|
|
13
|
+
* while "Matches regex" is the chosen mode - a Flags multi-select
|
|
14
|
+
* (`buildLiteralRegexControls`'s `flagOptions`, `regexpType.js`'s own
|
|
15
|
+
* `allowedFlags` list reused as-is, matching `regexpSearchType.js`'s flags
|
|
16
|
+
* for the actual regexp's own flags): unlike `regexpSearchType.js`, whose
|
|
17
|
+
* "source" is already a real regexp with its own flags regardless of
|
|
18
|
+
* search mode, here the regex is only ever the search's *own* device for
|
|
19
|
+
* matching the string, so flags only make sense while that regex is
|
|
20
|
+
* actually in play.
|
|
21
|
+
* @type {SearchTypeObject}
|
|
22
|
+
*/
|
|
23
|
+
const stringSearchType = {
|
|
24
|
+
buildUI ({schemaObject, path, typeNamespace}) {
|
|
25
|
+
const label = buildPathLabel(schemaObject, path);
|
|
26
|
+
const name = `${typeNamespace}-string`;
|
|
27
|
+
return ['jsoe-search-string', {
|
|
28
|
+
dataset: {searchPath: path, searchKind: 'string'},
|
|
29
|
+
title: label,
|
|
30
|
+
$define: {
|
|
31
|
+
/** @this {HTMLElement} */
|
|
32
|
+
getQuery () {
|
|
33
|
+
return readLiteralRegexQuery(this, this.dataset.searchPath ?? '');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}, [
|
|
37
|
+
['span', {class: 'searchLabel'}, [label]],
|
|
38
|
+
buildLiteralRegexControls({name, flagOptions: regexpType.allowedFlags})
|
|
39
|
+
]];
|
|
40
|
+
},
|
|
41
|
+
getQuery: getQueryViaElement
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export default stringSearchType;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {buildPathLabel, buildLiteralRegexControls, readLiteralRegexQuery} from '../searchUtils.js';
|
|
2
|
+
import {getQueryViaElement} from '../searchElementUtils.js';
|
|
3
|
+
import regexpType from '../../fundamentalTypes/regexpType.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Symbol (description): OR literal or regex search/Does Not contain search
|
|
11
|
+
* (README) - the same query semantics as `stringSearchType.js`'s, against
|
|
12
|
+
* the symbol's description rather than a string value, so it gets its own
|
|
13
|
+
* dedicated module/tag (matching the value-editing side's one-file-per-
|
|
14
|
+
* fundamental-type convention) while sharing that module's actual control
|
|
15
|
+
* building/reading via `searchUtils.js`.
|
|
16
|
+
* @type {SearchTypeObject}
|
|
17
|
+
*/
|
|
18
|
+
const symbolSearchType = {
|
|
19
|
+
buildUI ({schemaObject, path, typeNamespace}) {
|
|
20
|
+
const label = buildPathLabel(schemaObject, path);
|
|
21
|
+
const name = `${typeNamespace}-symbol`;
|
|
22
|
+
return ['jsoe-search-symbol', {
|
|
23
|
+
dataset: {searchPath: path, searchKind: 'symbol'},
|
|
24
|
+
title: label,
|
|
25
|
+
$define: {
|
|
26
|
+
/** @this {HTMLElement} */
|
|
27
|
+
getQuery () {
|
|
28
|
+
return readLiteralRegexQuery(this, this.dataset.searchPath ?? '');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}, [
|
|
32
|
+
['span', {class: 'searchLabel'}, [`${label} (description)`]],
|
|
33
|
+
buildLiteralRegexControls({name, flagOptions: regexpType.allowedFlags})
|
|
34
|
+
]];
|
|
35
|
+
},
|
|
36
|
+
getQuery: getQueryViaElement
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default symbolSearchType;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {makePresenceOnlySearchType} from '../searchElementUtils.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `undefined`/`void`: "no variants to allow for distinct search" (README).
|
|
5
|
+
* @type {import('../searchDispatch.js').SearchTypeObject}
|
|
6
|
+
*/
|
|
7
|
+
const undefinedSearchType = makePresenceOnlySearchType({
|
|
8
|
+
tagName: 'jsoe-search-undefined'
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export default undefinedSearchType;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import {jml} from '../vendor-imports.js';
|
|
2
|
+
import {getSearchTypeObject, buildSearchWidget, resolveIntersection} from './searchDispatch.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {{
|
|
6
|
+
* container: HTMLFormElement,
|
|
7
|
+
* $getQuery: () => import('./queryTree.js').QueryAnd,
|
|
8
|
+
* whenReady: Promise<void>
|
|
9
|
+
* }} SearchChoicesControl
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The top-level entry point (search plan §5): builds the whole recursive
|
|
14
|
+
* search widget tree for `schemaContent` via `buildSearchWidget`
|
|
15
|
+
* (`searchDispatch.js`), starting at `path = '#/'`. Does not route through
|
|
16
|
+
* `getTypesForSchema` for the general case - that function flattens union
|
|
17
|
+
* members into one flat `Set` of leaf types for a type-choice pull-down,
|
|
18
|
+
* whereas search needs union branches to stay distinguishable nested
|
|
19
|
+
* sub-widgets for the "has type" affordance (`unionSearchType.js` et al.) -
|
|
20
|
+
* `getTypesForSchema` is only reused narrowly, for intersection resolution,
|
|
21
|
+
* inside `buildSearchWidget`/`resolveIntersection` - which run at *every*
|
|
22
|
+
* recursive call site (every composite module's own child recursion uses
|
|
23
|
+
* `buildSearchWidget` too), not just here at the root, so an intersection
|
|
24
|
+
* schema nested anywhere in the tree resolves the same way a top-level one
|
|
25
|
+
* does rather than falling through to the `noneditableSearchType` escape
|
|
26
|
+
* hatch.
|
|
27
|
+
*
|
|
28
|
+
* `resolveIntersection` is called here too (redundantly, but cheaply, since
|
|
29
|
+
* it's a no-op for anything that isn't itself an `intersection`) purely so
|
|
30
|
+
* `$getQuery()` below dispatches through the *same* resolved schema
|
|
31
|
+
* `buildSearchWidget` actually built the UI for, rather than the original
|
|
32
|
+
* (possibly-`intersection`) one.
|
|
33
|
+
*
|
|
34
|
+
* Mirrors `buildTypeChoices`'s (`src/typeChoices.js`) `whenReady`/
|
|
35
|
+
* pull-based convention rather than inventing a push/callback API:
|
|
36
|
+
* `$getQuery()` reads the live DOM into a `QueryAnd` on demand (`{$and:
|
|
37
|
+
* []}` when nothing has been entered anywhere, matching the empty-`$and`
|
|
38
|
+
* convention of "no constraint"), and a host that wants live updates wraps
|
|
39
|
+
* it in its own `container.addEventListener('input', ...)`. Every widget
|
|
40
|
+
* built so far is synchronous, so `whenReady` (unlike `buildTypeChoices`'s)
|
|
41
|
+
* has no deferred work to wait on and settles immediately - it's still
|
|
42
|
+
* returned, so a caller can `await` either function uniformly without
|
|
43
|
+
* checking which one it has.
|
|
44
|
+
*
|
|
45
|
+
* `container` is a real `<form>` (its own `submit` prevented, since it is
|
|
46
|
+
* never actually submitted) rather than a plain `<div>`, matching the edit
|
|
47
|
+
* side's own root `<form>` (`src/types.js`'s `Types.validValuesSet` reads
|
|
48
|
+
* `form.checkValidity()`) - the various cross-field checks the individual
|
|
49
|
+
* search widgets wire up (`searchUtils.js`'s `buildRangeInputsPair`,
|
|
50
|
+
* `dateSearchType.js`, etc.) are native Constraint Validation API calls
|
|
51
|
+
* (`setCustomValidity`/`required`), so a host only needs the one native
|
|
52
|
+
* `container.checkValidity()`/`container.reportValidity()` to check them
|
|
53
|
+
* all at once, the same way `demo/index-search.js`'s "Check validity"
|
|
54
|
+
* button does.
|
|
55
|
+
* @param {{
|
|
56
|
+
* schemaContent: import('../formats/schema.js').ZodexSchema,
|
|
57
|
+
* typeNamespace?: string,
|
|
58
|
+
* topRoot?: import('../types.js').RootElement,
|
|
59
|
+
* types?: import('../types.js').default
|
|
60
|
+
* }} cfg
|
|
61
|
+
* @returns {SearchChoicesControl}
|
|
62
|
+
*/
|
|
63
|
+
export function buildSearchChoices ({schemaContent, typeNamespace, topRoot, types}) {
|
|
64
|
+
// Not '#/': `getJSONPointerParts` (`src/utils/jsonPointer.js`) splits on
|
|
65
|
+
// '/' and drops the leading '#', so '#/' parts to `['']` (one segment
|
|
66
|
+
// named the empty string) rather than `[]` (the root, no segments yet)
|
|
67
|
+
// - every recursive module here appends `${path}/segment`, so starting
|
|
68
|
+
// from the bare '#' is what keeps the first level from coming out as
|
|
69
|
+
// '#//segment'.
|
|
70
|
+
const path = '#';
|
|
71
|
+
const arr = buildSearchWidget({
|
|
72
|
+
schemaObject: schemaContent, path, typeNamespace, topRoot, types,
|
|
73
|
+
originalJSON: schemaContent
|
|
74
|
+
});
|
|
75
|
+
const container = /** @type {HTMLFormElement} */ (
|
|
76
|
+
jml('form', {
|
|
77
|
+
class: 'searchChoicesContainer',
|
|
78
|
+
$on: {
|
|
79
|
+
submit (e) {
|
|
80
|
+
e.preventDefault();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}, [arr])
|
|
84
|
+
);
|
|
85
|
+
const schemaObject = resolveIntersection(schemaContent, schemaContent);
|
|
86
|
+
return {
|
|
87
|
+
container,
|
|
88
|
+
$getQuery () {
|
|
89
|
+
const result = getSearchTypeObject(schemaObject).getQuery({
|
|
90
|
+
root: container, path
|
|
91
|
+
});
|
|
92
|
+
return {$and: result === undefined ? [] : [result]};
|
|
93
|
+
},
|
|
94
|
+
whenReady: Promise.resolve()
|
|
95
|
+
};
|
|
96
|
+
}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSDoc-only typedefs for the schema-driven search query tree. No runtime
|
|
3
|
+
* exports live here; construct nodes through `queryTreeBuilders.js` instead
|
|
4
|
+
* so every search module (and every test fixture) goes through one place.
|
|
5
|
+
*
|
|
6
|
+
* Leaf `path` values reuse the existing JSON-Pointer convention from
|
|
7
|
+
* `src/utils/jsonPointer.js` (`makeJSONPointer`/`getJSONPointerParts`)
|
|
8
|
+
* rather than Mongo's dot-notation, so the search tree shares a path format
|
|
9
|
+
* with the rest of jsoe (e.g. `arrayType.js`'s `currentPath`).
|
|
10
|
+
*
|
|
11
|
+
* The leaf vocabulary borrows MongoDB's own operator names (`$and`/`$or`,
|
|
12
|
+
* `$gt`/`$gte`/`$lt`/`$lte`, `$in`/`$nin`, `$regex`/`$options`, `$exists`)
|
|
13
|
+
* wherever a leaf kind has a clean Mongo equivalent, so a host can adapt the
|
|
14
|
+
* common cases to `sift()` (or real MongoDB) almost for free - this is not a
|
|
15
|
+
* claim of full drop-in Mongo query-document compatibility: several
|
|
16
|
+
* jsoe-specific leaf kinds have no Mongo equivalent and stay custom, and
|
|
17
|
+
* every leaf keeps jsoe's own `kind`-discriminated, path-carrying shape
|
|
18
|
+
* rather than Mongo's field-keyed document shape.
|
|
19
|
+
*
|
|
20
|
+
* A path segment of `*` (e.g. `#/tags/*`) means "any element of the array
|
|
21
|
+
* at this point" - `arraySearchType.js`/`setSearchType.js`/`filelistSearchType.js`
|
|
22
|
+
* (element/value length/count constraint aside) and `tupleSearchType.js`'s
|
|
23
|
+
* `rest` portion use it when recursing into their element/value schema's
|
|
24
|
+
* own search widget, so a single nested leaf expresses "the collection
|
|
25
|
+
* contains at least one element matching this" (Mongo's `$elemMatch` is the
|
|
26
|
+
* natural translation target for a host walking a path that contains this
|
|
27
|
+
* segment) without needing a dedicated wrapper leaf kind - the collection's
|
|
28
|
+
* own `lengthSize` leaf and the recursed element leaf simply combine via
|
|
29
|
+
* `$and`. `recordSearchType.js`/`mapSearchType.js` similarly recurse into
|
|
30
|
+
* their `key`/`value` schemas at `*key`/`*value` segments, feeding the
|
|
31
|
+
* results into a single `mapRecordJoint` leaf (below) rather than combining
|
|
32
|
+
* via `$and`, since a host needs to know whether the two must match the
|
|
33
|
+
* same entry. `functionSearchType.js` recurses into its `input`/`output`
|
|
34
|
+
* schemas at `*args`/`*output` segments (the former itself a tuple, so its
|
|
35
|
+
* own per-position segments nest under `*args`), combined via `$and`.
|
|
36
|
+
* `promiseSearchType.js`/`catchSearchType.js` recurse into their wrapped
|
|
37
|
+
* value/`innerType` at the same path (there being exactly one value, no
|
|
38
|
+
* segment to add) and wrap the result in a `passThrough` leaf (below)
|
|
39
|
+
* rather than returning it bare, so the tree keeps visible that the leaf
|
|
40
|
+
* was reached through one of these transparent wrappers.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @typedef {{$and: QueryNode[]}} QueryAnd
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @typedef {{$or: QueryNode[]}} QueryOr
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* `object` (via `$exists: true/false`).
|
|
53
|
+
* @typedef {{kind: 'hasProperty', path: string, $exists: boolean}} QueryHasPropertyLeaf
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* `array`/`set`/tuple-with-rest/`filelist` (via `$size`, or a range of
|
|
58
|
+
* operators when the schema doesn't pin an exact length), +`sparseCheck`
|
|
59
|
+
* for array sparse/not-sparse.
|
|
60
|
+
* @typedef {{
|
|
61
|
+
* kind: 'lengthSize',
|
|
62
|
+
* path: string,
|
|
63
|
+
* $size?: number,
|
|
64
|
+
* $gt?: number, $gte?: number, $lt?: number, $lte?: number,
|
|
65
|
+
* sparseCheck?: boolean
|
|
66
|
+
* }} QueryLengthSizeLeaf
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* `number`/`NumberObject`/`bigint`/`date`/`buffersource`, with `valueType`
|
|
71
|
+
* distinguishing them. Bounds are Mongo-style `$gt`/`$gte`/`$lt`/`$lte`
|
|
72
|
+
* rather than a `min`/`max` pair plus an inclusive boolean - inclusivity is
|
|
73
|
+
* simply which operator is present. The README's "Is Not Range" variant
|
|
74
|
+
* wraps the same leaf in `$not` rather than being a separate kind.
|
|
75
|
+
* @typedef {{
|
|
76
|
+
* kind: 'range',
|
|
77
|
+
* path: string,
|
|
78
|
+
* valueType: 'number'|'NumberObject'|'bigint'|'date'|'buffersource',
|
|
79
|
+
* $gt?: number|bigint|string,
|
|
80
|
+
* $gte?: number|bigint|string,
|
|
81
|
+
* $lt?: number|bigint|string,
|
|
82
|
+
* $lte?: number|bigint|string
|
|
83
|
+
* }} QueryRangeLeaf
|
|
84
|
+
*/
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @typedef {{kind: 'not', query: QueryNode}} QueryNotLeaf
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* `number`/`NumberObject`: is/is-not an integer.
|
|
92
|
+
* @typedef {{kind: 'integerCheck', path: string, isInteger: boolean}} QueryIntegerCheckLeaf
|
|
93
|
+
*/
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* `date`: is/is-not a valid `Date` (a structured-cloned `Date` can itself be
|
|
97
|
+
* an "Invalid Date" - a `NaN` internal time value - `dateType.js`'s own
|
|
98
|
+
* `notANum`/`ValidDate`/`InvalidDate` handling deals with the same state on
|
|
99
|
+
* the edit side).
|
|
100
|
+
* @typedef {{kind: 'validDateCheck', path: string, isValid: boolean}} QueryValidDateCheckLeaf
|
|
101
|
+
*/
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* `string`/`StringObject`/`Blob`/`File`/regexp-source/symbol-description
|
|
105
|
+
* (via `$in`/`$nin`).
|
|
106
|
+
* @typedef {{
|
|
107
|
+
* kind: 'literalSet',
|
|
108
|
+
* path: string,
|
|
109
|
+
* $in?: unknown[],
|
|
110
|
+
* $nin?: unknown[]
|
|
111
|
+
* }} QueryLiteralSetLeaf
|
|
112
|
+
*/
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* `string`/`StringObject`/`Blob`/`File`/regexp-source/symbol-description
|
|
116
|
+
* (via `$regex`/`$options`, matching Mongo's own field names).
|
|
117
|
+
* @typedef {{
|
|
118
|
+
* kind: 'regex',
|
|
119
|
+
* path: string,
|
|
120
|
+
* $regex: string,
|
|
121
|
+
* $options?: string
|
|
122
|
+
* }} QueryRegexLeaf
|
|
123
|
+
*/
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* `string`/`StringObject`/`Blob`/`File`/regexp-source/symbol-description:
|
|
127
|
+
* a substring the value must not contain.
|
|
128
|
+
* @typedef {{
|
|
129
|
+
* kind: 'notContains',
|
|
130
|
+
* path: string,
|
|
131
|
+
* value: string
|
|
132
|
+
* }} QueryNotContainsLeaf
|
|
133
|
+
*/
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* `enum`, SpecialNumber's `Infinity`/`-Infinity`/`NaN`/`-0` (via
|
|
137
|
+
* `$in`/`$nin`).
|
|
138
|
+
* @typedef {{
|
|
139
|
+
* kind: 'multiSelect',
|
|
140
|
+
* path: string,
|
|
141
|
+
* $in?: unknown[],
|
|
142
|
+
* $nin?: unknown[]
|
|
143
|
+
* }} QueryMultiSelectLeaf
|
|
144
|
+
*/
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Native enum key-vs-value; no Mongo equivalent, stays custom.
|
|
148
|
+
* @typedef {{
|
|
149
|
+
* kind: 'keyValueEnum',
|
|
150
|
+
* path: string,
|
|
151
|
+
* matchKeys: boolean,
|
|
152
|
+
* values: unknown[]
|
|
153
|
+
* }} QueryKeyValueEnumLeaf
|
|
154
|
+
*/
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Union/xor/discriminatedUnion "has type", carrying `discriminatorValue`
|
|
158
|
+
* when applicable, including when nested under a Map/Record key or value;
|
|
159
|
+
* no Mongo equivalent, stays custom.
|
|
160
|
+
* @typedef {{
|
|
161
|
+
* kind: 'typeOf',
|
|
162
|
+
* path: string,
|
|
163
|
+
* searchType: string,
|
|
164
|
+
* discriminatorValue?: unknown
|
|
165
|
+
* }} QueryTypeOfLeaf
|
|
166
|
+
*/
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* XPath/CSS-selector/full-text/raw-HTML-regex; no Mongo equivalent.
|
|
170
|
+
* @typedef {{
|
|
171
|
+
* kind: 'blobHTML',
|
|
172
|
+
* path: string,
|
|
173
|
+
* mode: 'xpath'|'cssSelector'|'fullText'|'rawHTMLRegex',
|
|
174
|
+
* value: string
|
|
175
|
+
* }} QueryBlobHTMLLeaf
|
|
176
|
+
*/
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Per-dimension ranges for DOMRect/Point/Matrix, each dimension itself a
|
|
180
|
+
* `range` leaf, + `readonlyCheck`/`dimensionCheck` (is/is-not readonly,
|
|
181
|
+
* is/is-not 3d); no Mongo equivalent.
|
|
182
|
+
* @typedef {{
|
|
183
|
+
* kind: 'domShape',
|
|
184
|
+
* path: string,
|
|
185
|
+
* dimensions: {[dimension: string]: QueryRangeLeaf},
|
|
186
|
+
* readonlyCheck?: boolean,
|
|
187
|
+
* dimensionCheck?: 2|3
|
|
188
|
+
* }} QueryDomShapeLeaf
|
|
189
|
+
*/
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Paired key+value leaves with a joint-match flag; no Mongo equivalent.
|
|
193
|
+
* @typedef {{
|
|
194
|
+
* kind: 'mapRecordJoint',
|
|
195
|
+
* path: string,
|
|
196
|
+
* keyQuery?: QueryNode,
|
|
197
|
+
* valueQuery?: QueryNode,
|
|
198
|
+
* joint: boolean
|
|
199
|
+
* }} QueryMapRecordJointLeaf
|
|
200
|
+
*/
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Promise/literal/catch/function: forwards to a nested `QueryNode` for the
|
|
204
|
+
* child schema so the tree stays uniform even where a type adds no
|
|
205
|
+
* constraint of its own; purely structural, no Mongo equivalent.
|
|
206
|
+
* @typedef {{
|
|
207
|
+
* kind: 'passThrough',
|
|
208
|
+
* path: string,
|
|
209
|
+
* query?: QueryNode
|
|
210
|
+
* }} QueryPassThroughLeaf
|
|
211
|
+
*/
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Undefined/void/null (via `$exists`).
|
|
215
|
+
* @typedef {{kind: 'presence', path: string, $exists: boolean}} QueryPresenceLeaf
|
|
216
|
+
*/
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Boolean/BooleanObject - Mongo would normally express this as a bare
|
|
220
|
+
* `{field: true}` shorthand, which doesn't fit our path-carrying leaf
|
|
221
|
+
* shape, so this stays a custom kind.
|
|
222
|
+
* @typedef {{
|
|
223
|
+
* kind: 'booleanEquals',
|
|
224
|
+
* path: string,
|
|
225
|
+
* value: boolean
|
|
226
|
+
* }} QueryBooleanEqualsLeaf
|
|
227
|
+
*/
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* @typedef {QueryHasPropertyLeaf|QueryLengthSizeLeaf|QueryRangeLeaf|
|
|
231
|
+
* QueryNotLeaf|QueryIntegerCheckLeaf|QueryValidDateCheckLeaf|
|
|
232
|
+
* QueryLiteralSetLeaf|QueryRegexLeaf|
|
|
233
|
+
* QueryNotContainsLeaf|QueryMultiSelectLeaf|QueryKeyValueEnumLeaf|
|
|
234
|
+
* QueryTypeOfLeaf|QueryBlobHTMLLeaf|QueryDomShapeLeaf|
|
|
235
|
+
* QueryMapRecordJointLeaf|QueryPassThroughLeaf|QueryPresenceLeaf|
|
|
236
|
+
* QueryBooleanEqualsLeaf
|
|
237
|
+
* } QueryLeaf
|
|
238
|
+
*/
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* @typedef {QueryAnd|QueryOr|QueryLeaf} QueryNode
|
|
242
|
+
*/
|
|
243
|
+
|
|
244
|
+
export {};
|