@es-joy/jsoe 0.30.0 → 0.32.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/CHANGES.md +9 -0
- package/README.md +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- 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/booleanSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/catchSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/dateSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/domexceptionSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/enumSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/fileSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/filelistSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/functionSearchType.d.ts.map +1 -1
- 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.map +1 -1
- package/dist/search/fundamentalTypes/promiseSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/regexpSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/setSearchType.d.ts.map +1 -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 +2 -0
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/queryTree.d.ts +3 -0
- package/dist/search/queryTree.d.ts.map +1 -1
- package/dist/search/queryTreeBuilders.d.ts +2 -1
- package/dist/search/queryTreeBuilders.d.ts.map +1 -1
- package/dist/search/searchDispatch.d.ts +11 -3
- package/dist/search/searchDispatch.d.ts.map +1 -1
- package/dist/search/searchElementUtils.d.ts +31 -1
- package/dist/search/searchElementUtils.d.ts.map +1 -1
- package/dist/search/searchUtils.d.ts +197 -10
- package/dist/search/searchUtils.d.ts.map +1 -1
- package/dist/search/subTypes/blobHTMLSearchType.d.ts +11 -4
- package/dist/search/subTypes/blobHTMLSearchType.d.ts.map +1 -1
- package/dist/search/subTypes/recordSearchType.d.ts.map +1 -1
- package/dist/search/subTypes/tupleSearchType.d.ts.map +1 -1
- package/dist/search/superTypes/SpecialRealNumberSearchType.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/dist/utils/json6Stringify.d.ts +2 -0
- package/dist/utils/json6Stringify.d.ts.map +1 -0
- package/dist/utils/rawTypesonEditor.d.ts.map +1 -1
- package/package.json +3 -3
- package/pnpm-workspace.yaml +26 -26
- package/src/search/fundamentalTypes/arraySearchType.js +28 -5
- package/src/search/fundamentalTypes/bigintSearchType.js +14 -3
- package/src/search/fundamentalTypes/blobSearchType.js +21 -3
- package/src/search/fundamentalTypes/booleanSearchType.js +15 -3
- package/src/search/fundamentalTypes/catchSearchType.js +20 -3
- package/src/search/fundamentalTypes/dateSearchType.js +42 -3
- package/src/search/fundamentalTypes/domexceptionSearchType.js +18 -4
- package/src/search/fundamentalTypes/enumSearchType.js +15 -3
- package/src/search/fundamentalTypes/fileSearchType.js +15 -3
- package/src/search/fundamentalTypes/filelistSearchType.js +25 -5
- package/src/search/fundamentalTypes/functionSearchType.js +31 -4
- package/src/search/fundamentalTypes/mapSearchType.js +33 -5
- package/src/search/fundamentalTypes/numberSearchType.js +15 -3
- package/src/search/fundamentalTypes/objectSearchType.js +94 -5
- package/src/search/fundamentalTypes/promiseSearchType.js +20 -3
- package/src/search/fundamentalTypes/regexpSearchType.js +24 -4
- package/src/search/fundamentalTypes/setSearchType.js +25 -5
- package/src/search/fundamentalTypes/stringSearchType.js +25 -3
- package/src/search/fundamentalTypes/symbolSearchType.js +21 -3
- package/src/search/index.js +22 -0
- package/src/search/queryTree.js +4 -1
- package/src/search/queryTreeBuilders.js +3 -2
- package/src/search/searchDispatch.js +14 -5
- package/src/search/searchElementUtils.js +98 -10
- package/src/search/searchUtils.js +440 -12
- package/src/search/subTypes/blobHTMLSearchType.js +186 -10
- package/src/search/subTypes/recordSearchType.js +30 -4
- package/src/search/subTypes/tupleSearchType.js +43 -5
- package/src/search/superTypes/SpecialRealNumberSearchType.js +15 -3
- package/src/search/superTypes/buffersourceSearchType.js +14 -3
- package/src/search/unions/unionFamilySearchType.js +45 -3
- package/src/utils/json6Stringify.js +50 -0
- package/src/utils/rawTypesonEditor.js +1 -51
- package/vendor/zod/classic/schemas.d.ts +3 -1
- package/vendor/zod/core/versions.js +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildPathLabel, buildRangeInputsPair, readRangeInputsPair, buildTriStateSelect,
|
|
3
|
-
readTriStateSelect, syncRangeValidity
|
|
3
|
+
readTriStateSelect, syncRangeValidity, applyRangeQuery, applyTriState, extractLeafOfKind
|
|
4
4
|
} from '../searchUtils.js';
|
|
5
5
|
import {makeRangeLeaf, makeIntegerCheckLeaf, combineAnd} from '../queryTreeBuilders.js';
|
|
6
|
-
import {getQueryViaElement} from '../searchElementUtils.js';
|
|
6
|
+
import {getQueryViaElement, applyQueryViaElement} from '../searchElementUtils.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
@@ -40,6 +40,17 @@ const numberSearchType = {
|
|
|
40
40
|
? undefined
|
|
41
41
|
: makeIntegerCheckLeaf(searchPath, isInteger);
|
|
42
42
|
return combineAnd([rangeLeaf, integerLeaf]);
|
|
43
|
+
},
|
|
44
|
+
/**
|
|
45
|
+
* @this {HTMLElement}
|
|
46
|
+
* @param {import('../queryTree.js').QueryNode|undefined} queryNode
|
|
47
|
+
* @returns {void}
|
|
48
|
+
*/
|
|
49
|
+
applyQuery (queryNode) {
|
|
50
|
+
const {matched: rangeLeaf} = extractLeafOfKind(queryNode, 'range');
|
|
51
|
+
applyRangeQuery(this, rangeLeaf);
|
|
52
|
+
const {matched: integerLeaf} = extractLeafOfKind(queryNode, 'integerCheck');
|
|
53
|
+
applyTriState(this, integerLeaf?.isInteger);
|
|
43
54
|
}
|
|
44
55
|
}
|
|
45
56
|
}, [
|
|
@@ -53,7 +64,8 @@ const numberSearchType = {
|
|
|
53
64
|
]]
|
|
54
65
|
]];
|
|
55
66
|
},
|
|
56
|
-
getQuery: getQueryViaElement
|
|
67
|
+
getQuery: getQueryViaElement,
|
|
68
|
+
applyQuery: applyQueryViaElement
|
|
57
69
|
};
|
|
58
70
|
|
|
59
71
|
export default numberSearchType;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import {jml} from '../../vendor-imports.js';
|
|
2
2
|
import {escapeJSONPointer} from '../../utils/jsonPointer.js';
|
|
3
3
|
import {
|
|
4
|
-
buildPathLabel, buildHasPropertyToggle, readTriStateSelect, findOwnControl,
|
|
5
|
-
buildCheckbox, readCheckbox, buildAtLeastOneSentinel, syncAtLeastOneCheck,
|
|
6
|
-
setDescendantsRequired, revalidateDescendants, resyncAtLeastOne
|
|
4
|
+
buildPathLabel, buildHasPropertyToggle, readTriStateSelect, applyTriState, findOwnControl,
|
|
5
|
+
buildCheckbox, readCheckbox, applyCheckbox, buildAtLeastOneSentinel, syncAtLeastOneCheck,
|
|
6
|
+
setDescendantsRequired, revalidateDescendants, resyncAtLeastOne,
|
|
7
|
+
extractLeafOfKind, extractClauseForPath
|
|
7
8
|
} from '../searchUtils.js';
|
|
8
9
|
import {combineAnd, makeHasPropertyLeaf} from '../queryTreeBuilders.js';
|
|
9
10
|
import {
|
|
10
|
-
findSearchElement, getQueryViaElement, hasGetQuery
|
|
11
|
+
findSearchElement, getQueryViaElement, hasGetQuery,
|
|
12
|
+
applyQueryViaElement, hasApplyQuery
|
|
11
13
|
} from '../searchElementUtils.js';
|
|
12
14
|
import {buildSearchWidget} from '../searchDispatch.js';
|
|
13
15
|
|
|
@@ -307,6 +309,91 @@ const objectSearchType = {
|
|
|
307
309
|
getQuery () {
|
|
308
310
|
const rows = [...this.children].filter(hasGetQuery);
|
|
309
311
|
return combineAnd(rows.map((row) => row.getQuery()));
|
|
312
|
+
},
|
|
313
|
+
/**
|
|
314
|
+
* `$define` methods are shared once per tag (this file's other
|
|
315
|
+
* docs), so - like `getQuery` - this reads every per-instance fact
|
|
316
|
+
* (which properties exist, their names) off `this`'s own live DOM
|
|
317
|
+
* rather than closing over `objectSchemaObject`/`propertyEntries`.
|
|
318
|
+
* A property the query doesn't reference is reset to "no
|
|
319
|
+
* constraint" (its tri-state back to "(any)"/checkbox unchecked,
|
|
320
|
+
* its own child cleared) rather than removed outright - cheaper and
|
|
321
|
+
* just as correct a way to reach the same resulting query, and
|
|
322
|
+
* non-destructive (the row, and any of the user's other in-progress
|
|
323
|
+
* edits to it, stay put to remove by hand if truly unwanted).
|
|
324
|
+
* @this {HTMLElement}
|
|
325
|
+
* @param {import('../queryTree.js').QueryNode|undefined} queryNode
|
|
326
|
+
* @returns {void}
|
|
327
|
+
*/
|
|
328
|
+
applyQuery (queryNode) {
|
|
329
|
+
const searchPath = this.dataset.searchPath ?? '';
|
|
330
|
+
let remaining = queryNode;
|
|
331
|
+
|
|
332
|
+
[...this.querySelectorAll(':scope > jsoe-search-has-property')].forEach((row) => {
|
|
333
|
+
const propertyName = /** @type {HTMLElement} */ (row).dataset.propertyName ?? '';
|
|
334
|
+
const childPath = `${searchPath}/${escapeJSONPointer(propertyName)}`;
|
|
335
|
+
const {matched, rest} = extractClauseForPath(remaining, childPath);
|
|
336
|
+
remaining = rest;
|
|
337
|
+
const {matched: existsLeaf, rest: childQuery} = extractLeafOfKind(matched, 'hasProperty');
|
|
338
|
+
applyTriState(row, existsLeaf?.$exists);
|
|
339
|
+
const childEl = findSearchElement(row, childPath);
|
|
340
|
+
if (childEl && hasApplyQuery(childEl)) {
|
|
341
|
+
childEl.applyQuery(childQuery);
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
[...this.querySelectorAll(':scope > jsoe-search-required-property')].forEach((row) => {
|
|
346
|
+
const propertyName = /** @type {HTMLElement} */ (row).dataset.propertyName ?? '';
|
|
347
|
+
const childPath = `${searchPath}/${escapeJSONPointer(propertyName)}`;
|
|
348
|
+
const {matched, rest} = extractClauseForPath(remaining, childPath);
|
|
349
|
+
remaining = rest;
|
|
350
|
+
applyCheckbox(row, matched !== undefined);
|
|
351
|
+
const childEl = findSearchElement(row, childPath);
|
|
352
|
+
if (childEl && hasApplyQuery(childEl)) {
|
|
353
|
+
childEl.applyQuery(matched);
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
// Optional properties the query references but that aren't added
|
|
358
|
+
// yet: pick each in turn from the pull-down and click "Add" (that
|
|
359
|
+
// click handler is wired per-instance, so - unlike this method -
|
|
360
|
+
// it's safe for it to close over this widget's own schema/path),
|
|
361
|
+
// then apply the same way an already-added row above would.
|
|
362
|
+
const addPropertySelect = /** @type {HTMLSelectElement|undefined} */ (
|
|
363
|
+
findOwnControl(this, 'select.addPropertySelect')
|
|
364
|
+
);
|
|
365
|
+
const addButton = /** @type {HTMLButtonElement|undefined} */ (
|
|
366
|
+
findOwnControl(this, 'button.addPropertyButton')
|
|
367
|
+
);
|
|
368
|
+
[...(addPropertySelect?.options ?? [])].
|
|
369
|
+
filter((opt) => opt.value && !opt.disabled).
|
|
370
|
+
map((opt) => opt.value).
|
|
371
|
+
forEach((propertyName) => {
|
|
372
|
+
const childPath = `${searchPath}/${escapeJSONPointer(propertyName)}`;
|
|
373
|
+
const {matched, rest} = extractClauseForPath(remaining, childPath);
|
|
374
|
+
if (matched === undefined) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
remaining = rest;
|
|
378
|
+
if (addPropertySelect) {
|
|
379
|
+
addPropertySelect.value = propertyName;
|
|
380
|
+
}
|
|
381
|
+
addButton?.click();
|
|
382
|
+
const row = [
|
|
383
|
+
...this.querySelectorAll(':scope > jsoe-search-has-property')
|
|
384
|
+
].find((r) => /** @type {HTMLElement} */ (r).dataset.propertyName === propertyName);
|
|
385
|
+
if (!row) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
const {matched: existsLeaf, rest: childQuery} = extractLeafOfKind(matched, 'hasProperty');
|
|
389
|
+
applyTriState(row, existsLeaf?.$exists);
|
|
390
|
+
const childEl = findSearchElement(row, childPath);
|
|
391
|
+
if (childEl && hasApplyQuery(childEl)) {
|
|
392
|
+
childEl.applyQuery(childQuery);
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
syncObjectValidity(this);
|
|
310
397
|
}
|
|
311
398
|
}
|
|
312
399
|
}, [
|
|
@@ -325,6 +412,7 @@ const objectSearchType = {
|
|
|
325
412
|
: ['span', ['(no optional properties to search on)']],
|
|
326
413
|
['button', {
|
|
327
414
|
type: 'button',
|
|
415
|
+
class: 'addPropertyButton',
|
|
328
416
|
$on: {
|
|
329
417
|
click () {
|
|
330
418
|
const container = this.closest('jsoe-search-object');
|
|
@@ -361,7 +449,8 @@ const objectSearchType = {
|
|
|
361
449
|
...(propertyEntries.length > 0 ? [buildAtLeastOneSentinel()] : [])
|
|
362
450
|
]];
|
|
363
451
|
},
|
|
364
|
-
getQuery: getQueryViaElement
|
|
452
|
+
getQuery: getQueryViaElement,
|
|
453
|
+
applyQuery: applyQueryViaElement
|
|
365
454
|
};
|
|
366
455
|
|
|
367
456
|
export default objectSearchType;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import {buildPathLabel} from '../searchUtils.js';
|
|
1
|
+
import {buildPathLabel, extractLeafOfKind} from '../searchUtils.js';
|
|
2
2
|
import {makePassThroughLeaf} from '../queryTreeBuilders.js';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
findSearchElement, getQueryViaElement, hasGetQuery,
|
|
5
|
+
applyQueryViaElement, hasApplyQuery
|
|
6
|
+
} from '../searchElementUtils.js';
|
|
4
7
|
import {buildSearchWidget} from '../searchDispatch.js';
|
|
5
8
|
|
|
6
9
|
/**
|
|
@@ -48,6 +51,19 @@ const promiseSearchType = {
|
|
|
48
51
|
return childQuery === undefined
|
|
49
52
|
? undefined
|
|
50
53
|
: makePassThroughLeaf(searchPath, childQuery);
|
|
54
|
+
},
|
|
55
|
+
/**
|
|
56
|
+
* @this {HTMLElement}
|
|
57
|
+
* @param {import('../queryTree.js').QueryNode|undefined} queryNode
|
|
58
|
+
* @returns {void}
|
|
59
|
+
*/
|
|
60
|
+
applyQuery (queryNode) {
|
|
61
|
+
const {matched} = extractLeafOfKind(queryNode, 'passThrough');
|
|
62
|
+
const searchPath = this.dataset.searchPath ?? '';
|
|
63
|
+
const childEl = findSearchElement(this, searchPath);
|
|
64
|
+
if (childEl && hasApplyQuery(childEl)) {
|
|
65
|
+
childEl.applyQuery(matched?.query);
|
|
66
|
+
}
|
|
51
67
|
}
|
|
52
68
|
}
|
|
53
69
|
}, [
|
|
@@ -55,7 +71,8 @@ const promiseSearchType = {
|
|
|
55
71
|
childArr
|
|
56
72
|
]];
|
|
57
73
|
},
|
|
58
|
-
getQuery: getQueryViaElement
|
|
74
|
+
getQuery: getQueryViaElement,
|
|
75
|
+
applyQuery: applyQueryViaElement
|
|
59
76
|
};
|
|
60
77
|
|
|
61
78
|
export default promiseSearchType;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
-
buildPathLabel, buildLiteralRegexControls, readLiteralRegexQuery,
|
|
3
|
-
buildMultiSelect, readMultiSelect, findOwnControl
|
|
2
|
+
buildPathLabel, buildLiteralRegexControls, readLiteralRegexQuery, applyLiteralRegexQuery,
|
|
3
|
+
buildMultiSelect, readMultiSelect, applyMultiSelect, findOwnControl, extractLeafOfKind
|
|
4
4
|
} from '../searchUtils.js';
|
|
5
5
|
import {makeMultiSelectLeaf, combineAnd} from '../queryTreeBuilders.js';
|
|
6
|
-
import {getQueryViaElement} from '../searchElementUtils.js';
|
|
6
|
+
import {getQueryViaElement, applyQueryViaElement} from '../searchElementUtils.js';
|
|
7
7
|
import regexpType from '../../fundamentalTypes/regexpType.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -43,6 +43,25 @@ const regexpSearchType = {
|
|
|
43
43
|
? makeMultiSelectLeaf(searchPath, {$in: selectedFlags})
|
|
44
44
|
: undefined;
|
|
45
45
|
return combineAnd([sourceLeaf, flagsLeaf]);
|
|
46
|
+
},
|
|
47
|
+
/**
|
|
48
|
+
* @this {HTMLElement}
|
|
49
|
+
* @param {import('../queryTree.js').QueryNode|undefined} queryNode
|
|
50
|
+
* @returns {void}
|
|
51
|
+
*/
|
|
52
|
+
applyQuery (queryNode) {
|
|
53
|
+
const {matched: flagsLeaf, rest: sourceLeaf} = extractLeafOfKind(queryNode, 'multiSelect');
|
|
54
|
+
// Sets Mode/Value first (dispatching the `change` that also
|
|
55
|
+
// toggles the Flags multi-select's own `hidden` state via this
|
|
56
|
+
// widget's `onModeChange`), then Flags.
|
|
57
|
+
applyLiteralRegexQuery(
|
|
58
|
+
this,
|
|
59
|
+
/**
|
|
60
|
+
* @type {import('../queryTree.js').QueryLiteralSetLeaf|
|
|
61
|
+
*import('../queryTree.js').QueryRegexLeaf|
|
|
62
|
+
import('../queryTree.js').QueryNotContainsLeaf|undefined} */ (sourceLeaf)
|
|
63
|
+
);
|
|
64
|
+
applyMultiSelect(this, flagsLeaf?.$in ?? []);
|
|
46
65
|
}
|
|
47
66
|
}
|
|
48
67
|
}, [
|
|
@@ -66,7 +85,8 @@ const regexpSearchType = {
|
|
|
66
85
|
]]
|
|
67
86
|
]];
|
|
68
87
|
},
|
|
69
|
-
getQuery: getQueryViaElement
|
|
88
|
+
getQuery: getQueryViaElement,
|
|
89
|
+
applyQuery: applyQueryViaElement
|
|
70
90
|
};
|
|
71
91
|
|
|
72
92
|
export default regexpSearchType;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
buildPathLabel, buildLengthSizeControls, readLengthSizeQuery,
|
|
3
|
-
buildOptInFieldset, readOptInChecked, wireOptInFieldset,
|
|
4
|
-
buildAtLeastOneSentinel, syncAtLeastOneCheck
|
|
2
|
+
buildPathLabel, buildLengthSizeControls, readLengthSizeQuery, applyLengthSizeQuery,
|
|
3
|
+
buildOptInFieldset, readOptInChecked, wireOptInFieldset, applyOptIn,
|
|
4
|
+
buildAtLeastOneSentinel, syncAtLeastOneCheck, extractLeafOfKind
|
|
5
5
|
} from '../searchUtils.js';
|
|
6
6
|
import {combineAnd} from '../queryTreeBuilders.js';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
findSearchElement, getQueryViaElement, hasGetQuery,
|
|
9
|
+
applyQueryViaElement, hasApplyQuery
|
|
10
|
+
} from '../searchElementUtils.js';
|
|
8
11
|
import {buildSearchWidget} from '../searchDispatch.js';
|
|
9
12
|
|
|
10
13
|
/**
|
|
@@ -69,6 +72,22 @@ const setSearchType = {
|
|
|
69
72
|
? elementEl.getQuery()
|
|
70
73
|
: undefined;
|
|
71
74
|
return combineAnd([lengthLeaf, elementLeaf]);
|
|
75
|
+
},
|
|
76
|
+
/**
|
|
77
|
+
* @this {HTMLElement}
|
|
78
|
+
* @param {import('../queryTree.js').QueryNode|undefined} queryNode
|
|
79
|
+
* @returns {void}
|
|
80
|
+
*/
|
|
81
|
+
applyQuery (queryNode) {
|
|
82
|
+
const searchPath = this.dataset.searchPath ?? '';
|
|
83
|
+
const {matched: lengthLeaf, rest} = extractLeafOfKind(queryNode, 'lengthSize');
|
|
84
|
+
applyLengthSizeQuery(this, lengthLeaf);
|
|
85
|
+
applyOptIn(this, rest !== undefined, '');
|
|
86
|
+
const elementEl = findSearchElement(this, `${searchPath}/*`);
|
|
87
|
+
if (elementEl && hasApplyQuery(elementEl)) {
|
|
88
|
+
elementEl.applyQuery(rest);
|
|
89
|
+
}
|
|
90
|
+
syncSetValidity(this);
|
|
72
91
|
}
|
|
73
92
|
}
|
|
74
93
|
}, [
|
|
@@ -85,7 +104,8 @@ const setSearchType = {
|
|
|
85
104
|
buildAtLeastOneSentinel()
|
|
86
105
|
]];
|
|
87
106
|
},
|
|
88
|
-
getQuery: getQueryViaElement
|
|
107
|
+
getQuery: getQueryViaElement,
|
|
108
|
+
applyQuery: applyQueryViaElement
|
|
89
109
|
};
|
|
90
110
|
|
|
91
111
|
export default setSearchType;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, buildLiteralRegexControls, readLiteralRegexQuery, applyLiteralRegexQuery
|
|
3
|
+
} from '../searchUtils.js';
|
|
4
|
+
import {getQueryViaElement, applyQueryViaElement} from '../searchElementUtils.js';
|
|
3
5
|
import regexpType from '../../fundamentalTypes/regexpType.js';
|
|
4
6
|
|
|
5
7
|
/**
|
|
@@ -31,6 +33,25 @@ const stringSearchType = {
|
|
|
31
33
|
/** @this {HTMLElement} */
|
|
32
34
|
getQuery () {
|
|
33
35
|
return readLiteralRegexQuery(this, this.dataset.searchPath ?? '');
|
|
36
|
+
},
|
|
37
|
+
/**
|
|
38
|
+
* `getQuery` returns a bare leaf here (no other facet to combine it
|
|
39
|
+
* with via `$and`), so `queryNode` normally already is one -
|
|
40
|
+
* unwrapping a trivial one-element `$and` too just tolerates a
|
|
41
|
+
* hand-edited raw query that wraps it anyway.
|
|
42
|
+
* @this {HTMLElement}
|
|
43
|
+
* @param {import('../queryTree.js').QueryNode|undefined} queryNode
|
|
44
|
+
* @returns {void}
|
|
45
|
+
*/
|
|
46
|
+
applyQuery (queryNode) {
|
|
47
|
+
const leaf = queryNode && '$and' in queryNode ? queryNode.$and[0] : queryNode;
|
|
48
|
+
applyLiteralRegexQuery(
|
|
49
|
+
this,
|
|
50
|
+
/**
|
|
51
|
+
* @type {import('../queryTree.js').QueryLiteralSetLeaf|
|
|
52
|
+
*import('../queryTree.js').QueryRegexLeaf|
|
|
53
|
+
import('../queryTree.js').QueryNotContainsLeaf|undefined} */ (leaf)
|
|
54
|
+
);
|
|
34
55
|
}
|
|
35
56
|
}
|
|
36
57
|
}, [
|
|
@@ -38,7 +59,8 @@ const stringSearchType = {
|
|
|
38
59
|
buildLiteralRegexControls({name, flagOptions: regexpType.allowedFlags})
|
|
39
60
|
]];
|
|
40
61
|
},
|
|
41
|
-
getQuery: getQueryViaElement
|
|
62
|
+
getQuery: getQueryViaElement,
|
|
63
|
+
applyQuery: applyQueryViaElement
|
|
42
64
|
};
|
|
43
65
|
|
|
44
66
|
export default stringSearchType;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, buildLiteralRegexControls, readLiteralRegexQuery, applyLiteralRegexQuery
|
|
3
|
+
} from '../searchUtils.js';
|
|
4
|
+
import {getQueryViaElement, applyQueryViaElement} from '../searchElementUtils.js';
|
|
3
5
|
import regexpType from '../../fundamentalTypes/regexpType.js';
|
|
4
6
|
|
|
5
7
|
/**
|
|
@@ -26,6 +28,21 @@ const symbolSearchType = {
|
|
|
26
28
|
/** @this {HTMLElement} */
|
|
27
29
|
getQuery () {
|
|
28
30
|
return readLiteralRegexQuery(this, this.dataset.searchPath ?? '');
|
|
31
|
+
},
|
|
32
|
+
/**
|
|
33
|
+
* @this {HTMLElement}
|
|
34
|
+
* @param {import('../queryTree.js').QueryNode|undefined} queryNode
|
|
35
|
+
* @returns {void}
|
|
36
|
+
*/
|
|
37
|
+
applyQuery (queryNode) {
|
|
38
|
+
const leaf = queryNode && '$and' in queryNode ? queryNode.$and[0] : queryNode;
|
|
39
|
+
applyLiteralRegexQuery(
|
|
40
|
+
this,
|
|
41
|
+
/**
|
|
42
|
+
* @type {import('../queryTree.js').QueryLiteralSetLeaf|
|
|
43
|
+
*import('../queryTree.js').QueryRegexLeaf|
|
|
44
|
+
import('../queryTree.js').QueryNotContainsLeaf|undefined} */ (leaf)
|
|
45
|
+
);
|
|
29
46
|
}
|
|
30
47
|
}
|
|
31
48
|
}, [
|
|
@@ -33,7 +50,8 @@ const symbolSearchType = {
|
|
|
33
50
|
buildLiteralRegexControls({name, flagOptions: regexpType.allowedFlags})
|
|
34
51
|
]];
|
|
35
52
|
},
|
|
36
|
-
getQuery: getQueryViaElement
|
|
53
|
+
getQuery: getQueryViaElement,
|
|
54
|
+
applyQuery: applyQueryViaElement
|
|
37
55
|
};
|
|
38
56
|
|
|
39
57
|
export default symbolSearchType;
|
package/src/search/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import {getSearchTypeObject, buildSearchWidget, resolveIntersection} from './sea
|
|
|
5
5
|
* @typedef {{
|
|
6
6
|
* container: HTMLFormElement,
|
|
7
7
|
* $getQuery: () => import('./queryTree.js').QueryAnd,
|
|
8
|
+
* $applyQuery: (queryDoc: import('./queryTree.js').QueryAnd) => void,
|
|
8
9
|
* whenReady: Promise<void>
|
|
9
10
|
* }} SearchChoicesControl
|
|
10
11
|
*/
|
|
@@ -91,6 +92,27 @@ export function buildSearchChoices ({schemaContent, typeNamespace, topRoot, type
|
|
|
91
92
|
});
|
|
92
93
|
return {$and: result === undefined ? [] : [result]};
|
|
93
94
|
},
|
|
95
|
+
/**
|
|
96
|
+
* The "Edit raw" round-trip's entry point - the inverse of `$getQuery`,
|
|
97
|
+
* unwrapping its own `{$and: [...]}` convention back to a bare
|
|
98
|
+
* `QueryNode` (or `undefined` for an empty `$and`, "no constraint")
|
|
99
|
+
* before handing off to the root schema's own `applyQuery`, which
|
|
100
|
+
* recurses through the whole tree exactly as `getQuery` does.
|
|
101
|
+
* @param {import('./queryTree.js').QueryAnd} queryDoc
|
|
102
|
+
* @returns {void}
|
|
103
|
+
*/
|
|
104
|
+
$applyQuery (queryDoc) {
|
|
105
|
+
const {$and: clauses} = queryDoc;
|
|
106
|
+
let queryNode;
|
|
107
|
+
if (clauses.length === 1) {
|
|
108
|
+
[queryNode] = clauses;
|
|
109
|
+
} else if (clauses.length > 1) {
|
|
110
|
+
queryNode = {$and: clauses};
|
|
111
|
+
}
|
|
112
|
+
getSearchTypeObject(schemaObject).applyQuery({
|
|
113
|
+
root: container, path, queryNode
|
|
114
|
+
});
|
|
115
|
+
},
|
|
94
116
|
whenReady: Promise.resolve()
|
|
95
117
|
};
|
|
96
118
|
}
|
package/src/search/queryTree.js
CHANGED
|
@@ -167,11 +167,14 @@
|
|
|
167
167
|
|
|
168
168
|
/**
|
|
169
169
|
* XPath/CSS-selector/full-text/raw-HTML-regex; no Mongo equivalent.
|
|
170
|
+
* `$options`, mirroring `QueryRegexLeaf`'s field of the same name, is only
|
|
171
|
+
* ever populated for `mode: 'rawHTMLRegex'`.
|
|
170
172
|
* @typedef {{
|
|
171
173
|
* kind: 'blobHTML',
|
|
172
174
|
* path: string,
|
|
173
175
|
* mode: 'xpath'|'cssSelector'|'fullText'|'rawHTMLRegex',
|
|
174
|
-
* value: string
|
|
176
|
+
* value: string,
|
|
177
|
+
* $options?: string
|
|
175
178
|
* }} QueryBlobHTMLLeaf
|
|
176
179
|
*/
|
|
177
180
|
|
|
@@ -172,10 +172,11 @@ export function makeTypeOfLeaf (path, searchType, discriminatorValue) {
|
|
|
172
172
|
* @param {string} path
|
|
173
173
|
* @param {import('./queryTree.js').QueryBlobHTMLLeaf['mode']} mode
|
|
174
174
|
* @param {string} value
|
|
175
|
+
* @param {string} [$options]
|
|
175
176
|
* @returns {import('./queryTree.js').QueryBlobHTMLLeaf}
|
|
176
177
|
*/
|
|
177
|
-
export function makeBlobHTMLLeaf (path, mode, value) {
|
|
178
|
-
return {kind: 'blobHTML', path, mode, value};
|
|
178
|
+
export function makeBlobHTMLLeaf (path, mode, value, $options) {
|
|
179
|
+
return {kind: 'blobHTML', path, mode, value, ...($options ? {$options} : {})};
|
|
179
180
|
}
|
|
180
181
|
|
|
181
182
|
/**
|
|
@@ -41,9 +41,12 @@ import blobHTMLSearchType from './subTypes/blobHTMLSearchType.js';
|
|
|
41
41
|
*/
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
|
-
* The search-side analogue of `TypeObject` (`src/types.js:308-408`):
|
|
45
|
-
* methods, `buildUI` (a `jml` array)
|
|
46
|
-
*
|
|
44
|
+
* The search-side analogue of `TypeObject` (`src/types.js:308-408`): three
|
|
45
|
+
* methods, `buildUI` (a `jml` array), `getQuery` (reads the built DOM back
|
|
46
|
+
* into a `QueryNode`, or `undefined` when no constraint was entered), and
|
|
47
|
+
* `applyQuery` (the inverse - drives the built DOM back into the state a
|
|
48
|
+
* previously-read, or hand-edited, `QueryNode` describes, for the "Edit raw"
|
|
49
|
+
* round-trip, `SearchChoicesControl.$applyQuery`, `src/search/index.js`).
|
|
47
50
|
* @typedef {{
|
|
48
51
|
* buildUI: (cfg: {
|
|
49
52
|
* schemaObject: import('../formats/schema.js').ZodexSchema,
|
|
@@ -56,7 +59,12 @@ import blobHTMLSearchType from './subTypes/blobHTMLSearchType.js';
|
|
|
56
59
|
* getQuery: (cfg: {
|
|
57
60
|
* root: HTMLElement,
|
|
58
61
|
* path: string
|
|
59
|
-
* }) => QueryNode|undefined
|
|
62
|
+
* }) => QueryNode|undefined,
|
|
63
|
+
* applyQuery: (cfg: {
|
|
64
|
+
* root: HTMLElement,
|
|
65
|
+
* path: string,
|
|
66
|
+
* queryNode: QueryNode|undefined
|
|
67
|
+
* }) => void
|
|
60
68
|
* }} SearchTypeObject
|
|
61
69
|
*/
|
|
62
70
|
|
|
@@ -71,7 +79,8 @@ import blobHTMLSearchType from './subTypes/blobHTMLSearchType.js';
|
|
|
71
79
|
function stubSearchType (searchSchemaType) {
|
|
72
80
|
return {
|
|
73
81
|
buildUI: () => ['span', [`TODO: ${searchSchemaType}`]],
|
|
74
|
-
getQuery: () => undefined
|
|
82
|
+
getQuery: () => undefined,
|
|
83
|
+
applyQuery () {}
|
|
75
84
|
};
|
|
76
85
|
}
|
|
77
86
|
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildPathLabel, buildCheckbox, readCheckbox,
|
|
3
|
-
buildLiteralRegexControls, readLiteralRegexQuery,
|
|
4
|
-
buildRangeInputsPair, readRangeInputsPair, syncRangeValidity,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
buildLiteralRegexControls, readLiteralRegexQuery, applyOptInLiteralRegexFacet,
|
|
4
|
+
buildRangeInputsPair, readRangeInputsPair, syncRangeValidity, applyOptInRangeFacet,
|
|
5
|
+
applyRangeQuery,
|
|
6
|
+
buildTriStateSelect, readTriStateSelect, applyTriState,
|
|
7
|
+
buildOptInFieldset, readOptInChecked, wireOptInFieldset, applyOptIn,
|
|
8
|
+
buildAtLeastOneSentinel, syncAtLeastOneCheck,
|
|
9
|
+
extractLeafOfKind
|
|
8
10
|
} from './searchUtils.js';
|
|
9
11
|
import {combineAnd, makeRangeLeaf, makeDomShapeLeaf} from './queryTreeBuilders.js';
|
|
10
12
|
import regexpType from '../fundamentalTypes/regexpType.js';
|
|
@@ -27,7 +29,8 @@ export function findSearchElement (root, path) {
|
|
|
27
29
|
|
|
28
30
|
/**
|
|
29
31
|
* @typedef {HTMLElement & {
|
|
30
|
-
* getQuery: () => import('./queryTree.js').QueryNode|undefined
|
|
32
|
+
* getQuery: () => import('./queryTree.js').QueryNode|undefined,
|
|
33
|
+
* applyQuery?: (queryNode: import('./queryTree.js').QueryNode|undefined) => void
|
|
31
34
|
* }} SearchElement
|
|
32
35
|
*/
|
|
33
36
|
|
|
@@ -45,6 +48,24 @@ export function getQueryViaElement ({root, path}) {
|
|
|
45
48
|
return el?.getQuery();
|
|
46
49
|
}
|
|
47
50
|
|
|
51
|
+
/**
|
|
52
|
+
* The `SearchTypeObject.applyQuery` every module implements identically -
|
|
53
|
+
* the "Edit raw" round-trip's counterpart to `getQueryViaElement`: locate
|
|
54
|
+
* the element built under `root` and delegate to its own `applyQuery(...)`
|
|
55
|
+
* method.
|
|
56
|
+
* @param {{
|
|
57
|
+
* root: HTMLElement, path: string,
|
|
58
|
+
* queryNode: import('./queryTree.js').QueryNode|undefined
|
|
59
|
+
* }} cfg
|
|
60
|
+
* @returns {void}
|
|
61
|
+
*/
|
|
62
|
+
export function applyQueryViaElement ({root, path, queryNode}) {
|
|
63
|
+
const el = /** @type {SearchElement|undefined} */ (
|
|
64
|
+
findSearchElement(root, path)
|
|
65
|
+
);
|
|
66
|
+
el?.applyQuery?.(queryNode);
|
|
67
|
+
}
|
|
68
|
+
|
|
48
69
|
/**
|
|
49
70
|
* Type-predicate guard distinguishing a built search element (leaf or
|
|
50
71
|
* container, either answers to `.getQuery()`) from a plain DOM node - used
|
|
@@ -60,6 +81,20 @@ export function hasGetQuery (el) {
|
|
|
60
81
|
'function';
|
|
61
82
|
}
|
|
62
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Same as `hasGetQuery`, for `applyQuery` - a container walking its own
|
|
86
|
+
* children to recurse an "Edit raw" apply into each needs to know which
|
|
87
|
+
* ones answer to it, same reasoning as `hasGetQuery`'s own doc.
|
|
88
|
+
* @param {Element} el
|
|
89
|
+
* @returns {el is SearchElement & {applyQuery: (
|
|
90
|
+
* queryNode: import('./queryTree.js').QueryNode|undefined
|
|
91
|
+
* ) => void}}
|
|
92
|
+
*/
|
|
93
|
+
export function hasApplyQuery (el) {
|
|
94
|
+
return typeof (/** @type {{applyQuery?: unknown}} */ (el)).applyQuery ===
|
|
95
|
+
'function';
|
|
96
|
+
}
|
|
97
|
+
|
|
63
98
|
/**
|
|
64
99
|
* Factory for the README's "no variants to allow for distinct search"
|
|
65
100
|
* leaves (`undefined`/`void`, `null`, `NaN`): the only meaningful question
|
|
@@ -89,7 +124,10 @@ export function makePresenceOnlySearchType ({tagName}) {
|
|
|
89
124
|
return checked
|
|
90
125
|
? {kind: 'presence', path: this.dataset.searchPath ?? '', $exists: true}
|
|
91
126
|
: undefined;
|
|
92
|
-
}
|
|
127
|
+
},
|
|
128
|
+
// The checkbox is permanently checked and `disabled` - nothing
|
|
129
|
+
// for a raw query to change here either way.
|
|
130
|
+
applyQuery () {}
|
|
93
131
|
}
|
|
94
132
|
}, [
|
|
95
133
|
['span', {class: 'searchLabel'}, [label]],
|
|
@@ -98,7 +136,8 @@ export function makePresenceOnlySearchType ({tagName}) {
|
|
|
98
136
|
})
|
|
99
137
|
]];
|
|
100
138
|
},
|
|
101
|
-
getQuery: getQueryViaElement
|
|
139
|
+
getQuery: getQueryViaElement,
|
|
140
|
+
applyQuery: applyQueryViaElement
|
|
102
141
|
};
|
|
103
142
|
}
|
|
104
143
|
|
|
@@ -211,11 +250,27 @@ export function makeErrorFamilySearchType ({tagName}) {
|
|
|
211
250
|
});
|
|
212
251
|
});
|
|
213
252
|
return combineAnd([...stringLeaves, ...numberLeaves]);
|
|
253
|
+
},
|
|
254
|
+
/**
|
|
255
|
+
* @this {HTMLElement}
|
|
256
|
+
* @param {import('./queryTree.js').QueryNode|undefined} queryNode
|
|
257
|
+
* @returns {void}
|
|
258
|
+
*/
|
|
259
|
+
applyQuery (queryNode) {
|
|
260
|
+
const searchPath = this.dataset.searchPath ?? '';
|
|
261
|
+
errorStringProps.forEach((prop) => {
|
|
262
|
+
applyOptInLiteralRegexFacet(this, queryNode, `${searchPath}/${prop}`, prop);
|
|
263
|
+
});
|
|
264
|
+
errorNumberProps.forEach((prop) => {
|
|
265
|
+
applyOptInRangeFacet(this, queryNode, `${searchPath}/${prop}`, prop);
|
|
266
|
+
});
|
|
267
|
+
syncErrorFamilyValidity(this);
|
|
214
268
|
}
|
|
215
269
|
}
|
|
216
270
|
}, buildErrorFamilyChildren({label, name})];
|
|
217
271
|
},
|
|
218
|
-
getQuery: getQueryViaElement
|
|
272
|
+
getQuery: getQueryViaElement,
|
|
273
|
+
applyQuery: applyQueryViaElement
|
|
219
274
|
};
|
|
220
275
|
}
|
|
221
276
|
|
|
@@ -362,12 +417,45 @@ export function makeDomShapeSearchType ({
|
|
|
362
417
|
? {}
|
|
363
418
|
: {dimensionCheck: dimensionCheck ? 3 : 2})
|
|
364
419
|
});
|
|
420
|
+
},
|
|
421
|
+
/**
|
|
422
|
+
* @this {HTMLElement}
|
|
423
|
+
* @param {import('./queryTree.js').QueryNode|undefined} queryNode
|
|
424
|
+
* @returns {void}
|
|
425
|
+
*/
|
|
426
|
+
applyQuery (queryNode) {
|
|
427
|
+
// A `domShape` leaf embeds each dimension's own `range` leaf
|
|
428
|
+
// directly (`dimensions`), not via `$and` - so, unlike
|
|
429
|
+
// `makeErrorFamilySearchType`'s flat properties,
|
|
430
|
+
// `extractClauseForPath` (which `applyOptInRangeFacet` uses)
|
|
431
|
+
// isn't needed here: read the whole leaf once and apply each
|
|
432
|
+
// dimension straight from it.
|
|
433
|
+
const {matched} = extractLeafOfKind(queryNode, 'domShape');
|
|
434
|
+
dimensionKeys.forEach((dim) => {
|
|
435
|
+
const dimLeaf = matched?.dimensions[dim];
|
|
436
|
+
applyOptIn(this, dimLeaf !== undefined, dim);
|
|
437
|
+
applyRangeQuery(this, dimLeaf, dim);
|
|
438
|
+
});
|
|
439
|
+
if (includeReadonly) {
|
|
440
|
+
applyTriState(this, matched?.readonlyCheck, 'readonly');
|
|
441
|
+
}
|
|
442
|
+
if (includeDimensionCheck) {
|
|
443
|
+
applyTriState(
|
|
444
|
+
this,
|
|
445
|
+
matched?.dimensionCheck === undefined
|
|
446
|
+
? undefined
|
|
447
|
+
: matched.dimensionCheck === 3,
|
|
448
|
+
'dimension'
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
syncDomShapeValidity({root: this, dimensionKeys, includeReadonly, includeDimensionCheck});
|
|
365
452
|
}
|
|
366
453
|
}
|
|
367
454
|
}, buildDomShapeChildren({
|
|
368
455
|
label, name, dimensionKeys, includeReadonly, includeDimensionCheck
|
|
369
456
|
})];
|
|
370
457
|
},
|
|
371
|
-
getQuery: getQueryViaElement
|
|
458
|
+
getQuery: getQueryViaElement,
|
|
459
|
+
applyQuery: applyQueryViaElement
|
|
372
460
|
};
|
|
373
461
|
}
|