@es-joy/jsoe 0.31.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.
Files changed (71) hide show
  1. package/CHANGES.md +4 -0
  2. package/dist/index.js +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/search/fundamentalTypes/arraySearchType.d.ts.map +1 -1
  5. package/dist/search/fundamentalTypes/bigintSearchType.d.ts.map +1 -1
  6. package/dist/search/fundamentalTypes/blobSearchType.d.ts.map +1 -1
  7. package/dist/search/fundamentalTypes/booleanSearchType.d.ts.map +1 -1
  8. package/dist/search/fundamentalTypes/catchSearchType.d.ts.map +1 -1
  9. package/dist/search/fundamentalTypes/dateSearchType.d.ts.map +1 -1
  10. package/dist/search/fundamentalTypes/domexceptionSearchType.d.ts.map +1 -1
  11. package/dist/search/fundamentalTypes/enumSearchType.d.ts.map +1 -1
  12. package/dist/search/fundamentalTypes/fileSearchType.d.ts.map +1 -1
  13. package/dist/search/fundamentalTypes/filelistSearchType.d.ts.map +1 -1
  14. package/dist/search/fundamentalTypes/functionSearchType.d.ts.map +1 -1
  15. package/dist/search/fundamentalTypes/mapSearchType.d.ts.map +1 -1
  16. package/dist/search/fundamentalTypes/numberSearchType.d.ts.map +1 -1
  17. package/dist/search/fundamentalTypes/objectSearchType.d.ts.map +1 -1
  18. package/dist/search/fundamentalTypes/promiseSearchType.d.ts.map +1 -1
  19. package/dist/search/fundamentalTypes/regexpSearchType.d.ts.map +1 -1
  20. package/dist/search/fundamentalTypes/setSearchType.d.ts.map +1 -1
  21. package/dist/search/fundamentalTypes/stringSearchType.d.ts.map +1 -1
  22. package/dist/search/fundamentalTypes/symbolSearchType.d.ts.map +1 -1
  23. package/dist/search/index.d.ts +2 -0
  24. package/dist/search/index.d.ts.map +1 -1
  25. package/dist/search/searchDispatch.d.ts +11 -3
  26. package/dist/search/searchDispatch.d.ts.map +1 -1
  27. package/dist/search/searchElementUtils.d.ts +31 -1
  28. package/dist/search/searchElementUtils.d.ts.map +1 -1
  29. package/dist/search/searchUtils.d.ts +180 -0
  30. package/dist/search/searchUtils.d.ts.map +1 -1
  31. package/dist/search/subTypes/blobHTMLSearchType.d.ts.map +1 -1
  32. package/dist/search/subTypes/recordSearchType.d.ts.map +1 -1
  33. package/dist/search/subTypes/tupleSearchType.d.ts.map +1 -1
  34. package/dist/search/superTypes/SpecialRealNumberSearchType.d.ts.map +1 -1
  35. package/dist/search/superTypes/buffersourceSearchType.d.ts.map +1 -1
  36. package/dist/search/unions/unionFamilySearchType.d.ts.map +1 -1
  37. package/dist/utils/json6Stringify.d.ts +2 -0
  38. package/dist/utils/json6Stringify.d.ts.map +1 -0
  39. package/dist/utils/rawTypesonEditor.d.ts.map +1 -1
  40. package/package.json +1 -1
  41. package/src/search/fundamentalTypes/arraySearchType.js +28 -5
  42. package/src/search/fundamentalTypes/bigintSearchType.js +14 -3
  43. package/src/search/fundamentalTypes/blobSearchType.js +21 -3
  44. package/src/search/fundamentalTypes/booleanSearchType.js +15 -3
  45. package/src/search/fundamentalTypes/catchSearchType.js +20 -3
  46. package/src/search/fundamentalTypes/dateSearchType.js +42 -3
  47. package/src/search/fundamentalTypes/domexceptionSearchType.js +18 -4
  48. package/src/search/fundamentalTypes/enumSearchType.js +15 -3
  49. package/src/search/fundamentalTypes/fileSearchType.js +15 -3
  50. package/src/search/fundamentalTypes/filelistSearchType.js +25 -5
  51. package/src/search/fundamentalTypes/functionSearchType.js +31 -4
  52. package/src/search/fundamentalTypes/mapSearchType.js +33 -5
  53. package/src/search/fundamentalTypes/numberSearchType.js +15 -3
  54. package/src/search/fundamentalTypes/objectSearchType.js +94 -5
  55. package/src/search/fundamentalTypes/promiseSearchType.js +20 -3
  56. package/src/search/fundamentalTypes/regexpSearchType.js +24 -4
  57. package/src/search/fundamentalTypes/setSearchType.js +25 -5
  58. package/src/search/fundamentalTypes/stringSearchType.js +25 -3
  59. package/src/search/fundamentalTypes/symbolSearchType.js +21 -3
  60. package/src/search/index.js +22 -0
  61. package/src/search/searchDispatch.js +14 -5
  62. package/src/search/searchElementUtils.js +98 -10
  63. package/src/search/searchUtils.js +368 -0
  64. package/src/search/subTypes/blobHTMLSearchType.js +43 -3
  65. package/src/search/subTypes/recordSearchType.js +30 -4
  66. package/src/search/subTypes/tupleSearchType.js +43 -5
  67. package/src/search/superTypes/SpecialRealNumberSearchType.js +15 -3
  68. package/src/search/superTypes/buffersourceSearchType.js +14 -3
  69. package/src/search/unions/unionFamilySearchType.js +45 -3
  70. package/src/utils/json6Stringify.js +50 -0
  71. package/src/utils/rawTypesonEditor.js +1 -51
@@ -1,5 +1,7 @@
1
- import {buildPathLabel, buildLiteralRegexControls, readLiteralRegexQuery} from '../searchUtils.js';
2
- import {getQueryViaElement} from '../searchElementUtils.js';
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
  /**
@@ -29,6 +31,21 @@ const blobSearchType = {
29
31
  /** @this {HTMLElement} */
30
32
  getQuery () {
31
33
  return readLiteralRegexQuery(this, this.dataset.searchPath ?? '');
34
+ },
35
+ /**
36
+ * @this {HTMLElement}
37
+ * @param {import('../queryTree.js').QueryNode|undefined} queryNode
38
+ * @returns {void}
39
+ */
40
+ applyQuery (queryNode) {
41
+ const leaf = queryNode && '$and' in queryNode ? queryNode.$and[0] : queryNode;
42
+ applyLiteralRegexQuery(
43
+ this,
44
+ /**
45
+ * @type {import('../queryTree.js').QueryLiteralSetLeaf|
46
+ *import('../queryTree.js').QueryRegexLeaf|
47
+ import('../queryTree.js').QueryNotContainsLeaf|undefined} */ (leaf)
48
+ );
32
49
  }
33
50
  }
34
51
  }, [
@@ -36,7 +53,8 @@ const blobSearchType = {
36
53
  buildLiteralRegexControls({name, flagOptions: regexpType.allowedFlags})
37
54
  ]];
38
55
  },
39
- getQuery: getQueryViaElement
56
+ getQuery: getQueryViaElement,
57
+ applyQuery: applyQueryViaElement
40
58
  };
41
59
 
42
60
  export default blobSearchType;
@@ -1,6 +1,8 @@
1
- import {buildPathLabel, buildTriStateSelect, readTriStateSelect} from '../searchUtils.js';
1
+ import {
2
+ buildPathLabel, buildTriStateSelect, readTriStateSelect, applyTriState, extractLeafOfKind
3
+ } from '../searchUtils.js';
2
4
  import {makeBooleanEqualsLeaf} from '../queryTreeBuilders.js';
3
- import {getQueryViaElement} from '../searchElementUtils.js';
5
+ import {getQueryViaElement, applyQueryViaElement} from '../searchElementUtils.js';
4
6
 
5
7
  /**
6
8
  * @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
@@ -24,6 +26,15 @@ const booleanSearchType = {
24
26
  return value === undefined
25
27
  ? undefined
26
28
  : makeBooleanEqualsLeaf(this.dataset.searchPath ?? '', value);
29
+ },
30
+ /**
31
+ * @this {HTMLElement}
32
+ * @param {import('../queryTree.js').QueryNode|undefined} queryNode
33
+ * @returns {void}
34
+ */
35
+ applyQuery (queryNode) {
36
+ const {matched} = extractLeafOfKind(queryNode, 'booleanEquals');
37
+ applyTriState(this, matched?.value);
27
38
  }
28
39
  }
29
40
  }, [
@@ -34,7 +45,8 @@ const booleanSearchType = {
34
45
  ]]
35
46
  ]];
36
47
  },
37
- getQuery: getQueryViaElement
48
+ getQuery: getQueryViaElement,
49
+ applyQuery: applyQueryViaElement
38
50
  };
39
51
 
40
52
  export default booleanSearchType;
@@ -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 {findSearchElement, getQueryViaElement, hasGetQuery} from '../searchElementUtils.js';
3
+ import {
4
+ findSearchElement, getQueryViaElement, hasGetQuery,
5
+ applyQueryViaElement, hasApplyQuery
6
+ } from '../searchElementUtils.js';
4
7
  import {buildSearchWidget} from '../searchDispatch.js';
5
8
 
6
9
  /**
@@ -46,6 +49,19 @@ const catchSearchType = {
46
49
  return childQuery === undefined
47
50
  ? undefined
48
51
  : makePassThroughLeaf(searchPath, childQuery);
52
+ },
53
+ /**
54
+ * @this {HTMLElement}
55
+ * @param {import('../queryTree.js').QueryNode|undefined} queryNode
56
+ * @returns {void}
57
+ */
58
+ applyQuery (queryNode) {
59
+ const {matched} = extractLeafOfKind(queryNode, 'passThrough');
60
+ const searchPath = this.dataset.searchPath ?? '';
61
+ const childEl = findSearchElement(this, searchPath);
62
+ if (childEl && hasApplyQuery(childEl)) {
63
+ childEl.applyQuery(matched?.query);
64
+ }
49
65
  }
50
66
  }
51
67
  }, [
@@ -53,7 +69,8 @@ const catchSearchType = {
53
69
  childArr
54
70
  ]];
55
71
  },
56
- getQuery: getQueryViaElement
72
+ getQuery: getQueryViaElement,
73
+ applyQuery: applyQueryViaElement
57
74
  };
58
75
 
59
76
  export default catchSearchType;
@@ -1,9 +1,10 @@
1
1
  import {buildDateInputControl} from '../../fundamentalTypes/dateType.js';
2
2
  import {
3
- buildPathLabel, buildTriStateSelect, readTriStateSelect, isExemptedByAncestorHasProperty
3
+ buildPathLabel, buildTriStateSelect, readTriStateSelect, isExemptedByAncestorHasProperty,
4
+ applyTriState, extractLeafOfKind
4
5
  } from '../searchUtils.js';
5
6
  import {makeRangeLeaf, makeValidDateCheckLeaf, combineAnd} from '../queryTreeBuilders.js';
6
- import {getQueryViaElement} from '../searchElementUtils.js';
7
+ import {getQueryViaElement, applyQueryViaElement} from '../searchElementUtils.js';
7
8
 
8
9
  /**
9
10
  * @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
@@ -80,6 +81,25 @@ function validateRange () {
80
81
  lteInput.setCustomValidity(lteMessage);
81
82
  }
82
83
 
84
+ /**
85
+ * The inverse of `readInputs` - `undefined` clears a bound, mirroring
86
+ * `dateType.js`'s own ISO-slicing convention (`toISOString().slice(0, -8)`)
87
+ * used to seed a `datetime-local` input's value from a real `Date`.
88
+ * @param {Element} el
89
+ * @param {string|undefined} gte
90
+ * @param {string|undefined} lte
91
+ * @returns {void}
92
+ */
93
+ function applyInputs (el, gte, lte) {
94
+ const [gteInput, lteInput] = /** @type {HTMLInputElement[]} */ (
95
+ [...el.querySelectorAll('input[type="datetime-local"]')]
96
+ );
97
+ gteInput.value = gte === undefined ? '' : new Date(gte).toISOString().slice(0, -8);
98
+ lteInput.value = lte === undefined ? '' : new Date(lte).toISOString().slice(0, -8);
99
+ gteInput.dispatchEvent(new Event('input'));
100
+ lteInput.dispatchEvent(new Event('input'));
101
+ }
102
+
83
103
  /**
84
104
  * OR date range/Is Not Range, Is/Is not a valid date (README) -
85
105
  * `dateType.js`'s own `buildDateInputControl` is reused twice (range start/
@@ -121,6 +141,24 @@ const dateSearchType = {
121
141
  ...(lte ? {$lte: new Date(lte).toISOString()} : {})
122
142
  });
123
143
  return combineAnd([validLeaf, rangeLeaf]);
144
+ },
145
+ /**
146
+ * @this {HTMLElement}
147
+ * @param {import('../queryTree.js').QueryNode|undefined} queryNode
148
+ * @returns {void}
149
+ */
150
+ applyQuery (queryNode) {
151
+ const {matched: validLeaf} = extractLeafOfKind(queryNode, 'validDateCheck');
152
+ // Dispatches `change`, which runs the tri-state's own `onChange`
153
+ // (toggling the range fieldset's `disabled` state and re-running
154
+ // `validateRange`) before the range inputs below are set.
155
+ applyTriState(this, validLeaf?.isValid, 'valid');
156
+ const {matched: rangeLeaf} = extractLeafOfKind(queryNode, 'range');
157
+ applyInputs(
158
+ this,
159
+ /** @type {string|undefined} */ (rangeLeaf?.$gte),
160
+ /** @type {string|undefined} */ (rangeLeaf?.$lte)
161
+ );
124
162
  }
125
163
  }
126
164
  }, [
@@ -160,7 +198,8 @@ const dateSearchType = {
160
198
  ]]
161
199
  ]];
162
200
  },
163
- getQuery: getQueryViaElement
201
+ getQuery: getQueryViaElement,
202
+ applyQuery: applyQueryViaElement
164
203
  };
165
204
 
166
205
  export default dateSearchType;
@@ -1,11 +1,12 @@
1
1
  import {domExceptionNames} from '../../fundamentalTypes/domexceptionType.js';
2
2
  import {
3
- buildPathLabel, buildMultiSelect, readMultiSelect, buildLiteralRegexControls,
3
+ buildPathLabel, buildMultiSelect, readMultiSelect, applyMultiSelect,
4
+ buildLiteralRegexControls,
4
5
  readLiteralRegexQuery, buildOptInFieldset, readOptInChecked, wireOptInFieldset,
5
- buildAtLeastOneSentinel, syncAtLeastOneCheck
6
+ buildAtLeastOneSentinel, syncAtLeastOneCheck, extractLeafOfKind, applyOptInLiteralRegexFacet
6
7
  } from '../searchUtils.js';
7
8
  import {makeMultiSelectLeaf, combineAnd} from '../queryTreeBuilders.js';
8
- import {getQueryViaElement} from '../searchElementUtils.js';
9
+ import {getQueryViaElement, applyQueryViaElement} from '../searchElementUtils.js';
9
10
  import regexpType from '../../fundamentalTypes/regexpType.js';
10
11
 
11
12
  /**
@@ -61,6 +62,18 @@ const domexceptionSearchType = {
61
62
  ? readLiteralRegexQuery(this, `${searchPath}/message`, 'message')
62
63
  : undefined;
63
64
  return combineAnd([nameLeaf, messageLeaf]);
65
+ },
66
+ /**
67
+ * @this {HTMLElement}
68
+ * @param {import('../queryTree.js').QueryNode|undefined} queryNode
69
+ * @returns {void}
70
+ */
71
+ applyQuery (queryNode) {
72
+ const searchPath = this.dataset.searchPath ?? '';
73
+ const {matched: nameLeaf} = extractLeafOfKind(queryNode, 'multiSelect');
74
+ applyMultiSelect(this, nameLeaf?.$in ?? []);
75
+ applyOptInLiteralRegexFacet(this, queryNode, `${searchPath}/message`, 'message');
76
+ syncDomexceptionValidity(this);
64
77
  }
65
78
  }
66
79
  }, [
@@ -78,7 +91,8 @@ const domexceptionSearchType = {
78
91
  buildAtLeastOneSentinel()
79
92
  ]];
80
93
  },
81
- getQuery: getQueryViaElement
94
+ getQuery: getQueryViaElement,
95
+ applyQuery: applyQueryViaElement
82
96
  };
83
97
 
84
98
  export default domexceptionSearchType;
@@ -1,6 +1,8 @@
1
- import {buildPathLabel, buildMultiSelect, readMultiSelect} from '../searchUtils.js';
1
+ import {
2
+ buildPathLabel, buildMultiSelect, readMultiSelect, applyMultiSelect, extractLeafOfKind
3
+ } from '../searchUtils.js';
2
4
  import {makeMultiSelectLeaf} from '../queryTreeBuilders.js';
3
- import {getQueryViaElement} from '../searchElementUtils.js';
5
+ import {getQueryViaElement, applyQueryViaElement} from '../searchElementUtils.js';
4
6
 
5
7
  /**
6
8
  * @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
@@ -49,6 +51,15 @@ const enumSearchType = {
49
51
  return selected.length
50
52
  ? makeMultiSelectLeaf(this.dataset.searchPath ?? '', {$in: selected})
51
53
  : undefined;
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, 'multiSelect');
62
+ applyMultiSelect(this, matched?.$in ?? []);
52
63
  }
53
64
  }
54
65
  }, [
@@ -56,7 +67,8 @@ const enumSearchType = {
56
67
  buildMultiSelect({name, options, required: true})
57
68
  ]];
58
69
  },
59
- getQuery: getQueryViaElement
70
+ getQuery: getQueryViaElement,
71
+ applyQuery: applyQueryViaElement
60
72
  };
61
73
 
62
74
  export default enumSearchType;
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  buildPathLabel, buildLiteralRegexControls, readLiteralRegexQuery,
3
3
  buildOptInFieldset, readOptInChecked, wireOptInFieldset,
4
- buildAtLeastOneSentinel, syncAtLeastOneCheck
4
+ buildAtLeastOneSentinel, syncAtLeastOneCheck, applyOptInLiteralRegexFacet
5
5
  } from '../searchUtils.js';
6
6
  import {combineAnd} from '../queryTreeBuilders.js';
7
- import {getQueryViaElement} from '../searchElementUtils.js';
7
+ import {getQueryViaElement, applyQueryViaElement} from '../searchElementUtils.js';
8
8
  import regexpType from '../../fundamentalTypes/regexpType.js';
9
9
 
10
10
  /**
@@ -69,6 +69,17 @@ const fileSearchType = {
69
69
  ? readLiteralRegexQuery(this, `${searchPath}/type`, 'type')
70
70
  : undefined;
71
71
  return combineAnd([nameLeaf, typeLeaf]);
72
+ },
73
+ /**
74
+ * @this {HTMLElement}
75
+ * @param {import('../queryTree.js').QueryNode|undefined} queryNode
76
+ * @returns {void}
77
+ */
78
+ applyQuery (queryNode) {
79
+ const searchPath = this.dataset.searchPath ?? '';
80
+ applyOptInLiteralRegexFacet(this, queryNode, `${searchPath}/name`, 'name');
81
+ applyOptInLiteralRegexFacet(this, queryNode, `${searchPath}/type`, 'type');
82
+ syncFileValidity(this);
72
83
  }
73
84
  }
74
85
  }, [
@@ -88,7 +99,8 @@ const fileSearchType = {
88
99
  buildAtLeastOneSentinel()
89
100
  ]];
90
101
  },
91
- getQuery: getQueryViaElement
102
+ getQuery: getQueryViaElement,
103
+ applyQuery: applyQueryViaElement
92
104
  };
93
105
 
94
106
  export default fileSearchType;
@@ -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 {findSearchElement, getQueryViaElement, hasGetQuery} from '../searchElementUtils.js';
7
+ import {
8
+ findSearchElement, getQueryViaElement, hasGetQuery,
9
+ applyQueryViaElement, hasApplyQuery
10
+ } from '../searchElementUtils.js';
8
11
  import {buildSearchWidget} from '../searchDispatch.js';
9
12
 
10
13
  /**
@@ -81,6 +84,22 @@ const filelistSearchType = {
81
84
  ? elementEl.getQuery()
82
85
  : undefined;
83
86
  return combineAnd([lengthLeaf, elementLeaf]);
87
+ },
88
+ /**
89
+ * @this {HTMLElement}
90
+ * @param {import('../queryTree.js').QueryNode|undefined} queryNode
91
+ * @returns {void}
92
+ */
93
+ applyQuery (queryNode) {
94
+ const searchPath = this.dataset.searchPath ?? '';
95
+ const {matched: lengthLeaf, rest} = extractLeafOfKind(queryNode, 'lengthSize');
96
+ applyLengthSizeQuery(this, lengthLeaf);
97
+ applyOptIn(this, rest !== undefined, '');
98
+ const elementEl = findSearchElement(this, `${searchPath}/*`);
99
+ if (elementEl && hasApplyQuery(elementEl)) {
100
+ elementEl.applyQuery(rest);
101
+ }
102
+ syncFilelistValidity(this);
84
103
  }
85
104
  }
86
105
  }, [
@@ -97,7 +116,8 @@ const filelistSearchType = {
97
116
  buildAtLeastOneSentinel()
98
117
  ]];
99
118
  },
100
- getQuery: getQueryViaElement
119
+ getQuery: getQueryViaElement,
120
+ applyQuery: applyQueryViaElement
101
121
  };
102
122
 
103
123
  export default filelistSearchType;
@@ -1,9 +1,12 @@
1
1
  import {
2
- buildPathLabel, buildOptInFieldset, readOptInChecked, wireOptInFieldset,
3
- buildAtLeastOneSentinel, syncAtLeastOneCheck
2
+ buildPathLabel, buildOptInFieldset, readOptInChecked, wireOptInFieldset, applyOptIn,
3
+ buildAtLeastOneSentinel, syncAtLeastOneCheck, extractClauseForPath
4
4
  } from '../searchUtils.js';
5
5
  import {combineAnd} from '../queryTreeBuilders.js';
6
- import {findSearchElement, getQueryViaElement, hasGetQuery} from '../searchElementUtils.js';
6
+ import {
7
+ findSearchElement, getQueryViaElement, hasGetQuery,
8
+ applyQueryViaElement, hasApplyQuery
9
+ } from '../searchElementUtils.js';
7
10
  import {buildSearchWidget} from '../searchDispatch.js';
8
11
 
9
12
  /**
@@ -82,6 +85,29 @@ const functionSearchType = {
82
85
  ? outputEl.getQuery()
83
86
  : undefined;
84
87
  return combineAnd([argsQuery, outputQuery]);
88
+ },
89
+ /**
90
+ * @this {HTMLElement}
91
+ * @param {import('../queryTree.js').QueryNode|undefined} queryNode
92
+ * @returns {void}
93
+ */
94
+ applyQuery (queryNode) {
95
+ const searchPath = this.dataset.searchPath ?? '';
96
+ const argsPath = `${searchPath}/*args`;
97
+ const outputPath = `${searchPath}/*output`;
98
+ const {matched: argsMatched, rest} = extractClauseForPath(queryNode, argsPath);
99
+ const {matched: outputMatched} = extractClauseForPath(rest, outputPath);
100
+ applyOptIn(this, argsMatched !== undefined, 'args');
101
+ applyOptIn(this, outputMatched !== undefined, 'output');
102
+ const argsEl = findSearchElement(this, argsPath);
103
+ if (argsEl && hasApplyQuery(argsEl)) {
104
+ argsEl.applyQuery(argsMatched);
105
+ }
106
+ const outputEl = findSearchElement(this, outputPath);
107
+ if (outputEl && hasApplyQuery(outputEl)) {
108
+ outputEl.applyQuery(outputMatched);
109
+ }
110
+ syncFunctionValidity(this);
85
111
  }
86
112
  }
87
113
  }, [
@@ -96,7 +122,8 @@ const functionSearchType = {
96
122
  buildAtLeastOneSentinel()
97
123
  ]];
98
124
  },
99
- getQuery: getQueryViaElement
125
+ getQuery: getQueryViaElement,
126
+ applyQuery: applyQueryViaElement
100
127
  };
101
128
 
102
129
  export default functionSearchType;
@@ -1,10 +1,14 @@
1
1
  import {
2
- buildPathLabel, buildCheckbox, readCheckbox, buildLengthSizeControls,
3
- readLengthSizeQuery, buildOptInFieldset, readOptInChecked, wireOptInFieldset,
4
- buildAtLeastOneSentinel, syncAtLeastOneCheck
2
+ buildPathLabel, buildCheckbox, readCheckbox, applyCheckbox, buildLengthSizeControls,
3
+ readLengthSizeQuery, applyLengthSizeQuery,
4
+ buildOptInFieldset, readOptInChecked, wireOptInFieldset, applyOptIn,
5
+ buildAtLeastOneSentinel, syncAtLeastOneCheck, extractLeafOfKind
5
6
  } from '../searchUtils.js';
6
7
  import {makeMapRecordJointLeaf, combineAnd} from '../queryTreeBuilders.js';
7
- import {findSearchElement, getQueryViaElement, hasGetQuery} from '../searchElementUtils.js';
8
+ import {
9
+ findSearchElement, getQueryViaElement, hasGetQuery,
10
+ applyQueryViaElement, hasApplyQuery
11
+ } from '../searchElementUtils.js';
8
12
  import {buildSearchWidget} from '../searchDispatch.js';
9
13
 
10
14
  /**
@@ -94,6 +98,29 @@ const mapSearchType = {
94
98
  ? makeMapRecordJointLeaf(searchPath, readCheckbox(this), keyQuery, valueQuery)
95
99
  : undefined;
96
100
  return combineAnd([lengthLeaf, jointLeaf]);
101
+ },
102
+ /**
103
+ * @this {HTMLElement}
104
+ * @param {import('../queryTree.js').QueryNode|undefined} queryNode
105
+ * @returns {void}
106
+ */
107
+ applyQuery (queryNode) {
108
+ const searchPath = this.dataset.searchPath ?? '';
109
+ const {matched: lengthLeaf, rest} = extractLeafOfKind(queryNode, 'lengthSize');
110
+ applyLengthSizeQuery(this, lengthLeaf);
111
+ const {matched: jointLeaf} = extractLeafOfKind(rest, 'mapRecordJoint');
112
+ applyCheckbox(this, Boolean(jointLeaf?.joint));
113
+ applyOptIn(this, jointLeaf?.keyQuery !== undefined, 'key');
114
+ applyOptIn(this, jointLeaf?.valueQuery !== undefined, 'value');
115
+ const keyEl = findSearchElement(this, `${searchPath}/*key`);
116
+ if (keyEl && hasApplyQuery(keyEl)) {
117
+ keyEl.applyQuery(jointLeaf?.keyQuery);
118
+ }
119
+ const valueEl = findSearchElement(this, `${searchPath}/*value`);
120
+ if (valueEl && hasApplyQuery(valueEl)) {
121
+ valueEl.applyQuery(jointLeaf?.valueQuery);
122
+ }
123
+ syncMapValidity(this);
97
124
  }
98
125
  }
99
126
  }, [
@@ -111,7 +138,8 @@ const mapSearchType = {
111
138
  buildAtLeastOneSentinel()
112
139
  ]];
113
140
  },
114
- getQuery: getQueryViaElement
141
+ getQuery: getQueryViaElement,
142
+ applyQuery: applyQueryViaElement
115
143
  };
116
144
 
117
145
  export default mapSearchType;
@@ -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;