@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.
Files changed (167) hide show
  1. package/.claude/scheduled_tasks.lock +1 -0
  2. package/CHANGES.md +25 -0
  3. package/README.md +4 -0
  4. package/dist/formatAndTypeChoices.d.ts +6 -6
  5. package/dist/formatAndTypeChoices.d.ts.map +1 -1
  6. package/dist/formats/schema.d.ts +5 -0
  7. package/dist/formats/schema.d.ts.map +1 -1
  8. package/dist/formats.d.ts +2 -2
  9. package/dist/formats.d.ts.map +1 -1
  10. package/dist/fundamentalTypes/dateType.d.ts +26 -2
  11. package/dist/fundamentalTypes/dateType.d.ts.map +1 -1
  12. package/dist/fundamentalTypes/domexceptionType.d.ts +7 -0
  13. package/dist/fundamentalTypes/domexceptionType.d.ts.map +1 -1
  14. package/dist/index.d.ts +2 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +2 -2
  17. package/dist/index.js.map +1 -1
  18. package/dist/jtltExtensions.d.ts +112 -0
  19. package/dist/jtltExtensions.d.ts.map +1 -0
  20. package/dist/search/fundamentalTypes/arraySearchType.d.ts +22 -0
  21. package/dist/search/fundamentalTypes/arraySearchType.d.ts.map +1 -0
  22. package/dist/search/fundamentalTypes/bigintSearchType.d.ts +10 -0
  23. package/dist/search/fundamentalTypes/bigintSearchType.d.ts.map +1 -0
  24. package/dist/search/fundamentalTypes/blobSearchType.d.ts +19 -0
  25. package/dist/search/fundamentalTypes/blobSearchType.d.ts.map +1 -0
  26. package/dist/search/fundamentalTypes/booleanSearchType.d.ts +11 -0
  27. package/dist/search/fundamentalTypes/booleanSearchType.d.ts.map +1 -0
  28. package/dist/search/fundamentalTypes/catchSearchType.d.ts +18 -0
  29. package/dist/search/fundamentalTypes/catchSearchType.d.ts.map +1 -0
  30. package/dist/search/fundamentalTypes/dateSearchType.d.ts +15 -0
  31. package/dist/search/fundamentalTypes/dateSearchType.d.ts.map +1 -0
  32. package/dist/search/fundamentalTypes/domexceptionSearchType.d.ts +16 -0
  33. package/dist/search/fundamentalTypes/domexceptionSearchType.d.ts.map +1 -0
  34. package/dist/search/fundamentalTypes/enumSearchType.d.ts +26 -0
  35. package/dist/search/fundamentalTypes/enumSearchType.d.ts.map +1 -0
  36. package/dist/search/fundamentalTypes/errorSearchType.d.ts +9 -0
  37. package/dist/search/fundamentalTypes/errorSearchType.d.ts.map +1 -0
  38. package/dist/search/fundamentalTypes/fileSearchType.d.ts +28 -0
  39. package/dist/search/fundamentalTypes/fileSearchType.d.ts.map +1 -0
  40. package/dist/search/fundamentalTypes/filelistSearchType.d.ts +24 -0
  41. package/dist/search/fundamentalTypes/filelistSearchType.d.ts.map +1 -0
  42. package/dist/search/fundamentalTypes/functionSearchType.d.ts +18 -0
  43. package/dist/search/fundamentalTypes/functionSearchType.d.ts.map +1 -0
  44. package/dist/search/fundamentalTypes/mapSearchType.d.ts +22 -0
  45. package/dist/search/fundamentalTypes/mapSearchType.d.ts.map +1 -0
  46. package/dist/search/fundamentalTypes/nanSearchType.d.ts +7 -0
  47. package/dist/search/fundamentalTypes/nanSearchType.d.ts.map +1 -0
  48. package/dist/search/fundamentalTypes/nullSearchType.d.ts +7 -0
  49. package/dist/search/fundamentalTypes/nullSearchType.d.ts.map +1 -0
  50. package/dist/search/fundamentalTypes/numberSearchType.d.ts +11 -0
  51. package/dist/search/fundamentalTypes/numberSearchType.d.ts.map +1 -0
  52. package/dist/search/fundamentalTypes/objectSearchType.d.ts +21 -0
  53. package/dist/search/fundamentalTypes/objectSearchType.d.ts.map +1 -0
  54. package/dist/search/fundamentalTypes/promiseSearchType.d.ts +20 -0
  55. package/dist/search/fundamentalTypes/promiseSearchType.d.ts.map +1 -0
  56. package/dist/search/fundamentalTypes/regexpSearchType.d.ts +20 -0
  57. package/dist/search/fundamentalTypes/regexpSearchType.d.ts.map +1 -0
  58. package/dist/search/fundamentalTypes/setSearchType.d.ts +15 -0
  59. package/dist/search/fundamentalTypes/setSearchType.d.ts.map +1 -0
  60. package/dist/search/fundamentalTypes/stringSearchType.d.ts +21 -0
  61. package/dist/search/fundamentalTypes/stringSearchType.d.ts.map +1 -0
  62. package/dist/search/fundamentalTypes/symbolSearchType.d.ts +16 -0
  63. package/dist/search/fundamentalTypes/symbolSearchType.d.ts.map +1 -0
  64. package/dist/search/fundamentalTypes/undefinedSearchType.d.ts +7 -0
  65. package/dist/search/fundamentalTypes/undefinedSearchType.d.ts.map +1 -0
  66. package/dist/search/index.d.ts +70 -0
  67. package/dist/search/index.d.ts.map +1 -0
  68. package/dist/search/queryTree.d.ts +12 -1
  69. package/dist/search/queryTree.d.ts.map +1 -1
  70. package/dist/search/queryTreeBuilders.d.ts +18 -0
  71. package/dist/search/queryTreeBuilders.d.ts.map +1 -1
  72. package/dist/search/searchDispatch.d.ts +44 -0
  73. package/dist/search/searchDispatch.d.ts.map +1 -1
  74. package/dist/search/searchElementUtils.d.ts +106 -0
  75. package/dist/search/searchElementUtils.d.ts.map +1 -0
  76. package/dist/search/searchUtils.d.ts +550 -0
  77. package/dist/search/searchUtils.d.ts.map +1 -0
  78. package/dist/search/subTypes/blobHTMLSearchType.d.ts +36 -0
  79. package/dist/search/subTypes/blobHTMLSearchType.d.ts.map +1 -0
  80. package/dist/search/subTypes/recordSearchType.d.ts +18 -0
  81. package/dist/search/subTypes/recordSearchType.d.ts.map +1 -0
  82. package/dist/search/subTypes/tupleSearchType.d.ts +21 -0
  83. package/dist/search/subTypes/tupleSearchType.d.ts.map +1 -0
  84. package/dist/search/superTypes/SpecialRealNumberSearchType.d.ts +14 -0
  85. package/dist/search/superTypes/SpecialRealNumberSearchType.d.ts.map +1 -0
  86. package/dist/search/superTypes/buffersourceSearchType.d.ts +17 -0
  87. package/dist/search/superTypes/buffersourceSearchType.d.ts.map +1 -0
  88. package/dist/search/superTypes/dommatrixSearchType.d.ts +11 -0
  89. package/dist/search/superTypes/dommatrixSearchType.d.ts.map +1 -0
  90. package/dist/search/superTypes/dompointSearchType.d.ts +9 -0
  91. package/dist/search/superTypes/dompointSearchType.d.ts.map +1 -0
  92. package/dist/search/superTypes/domrectSearchType.d.ts +9 -0
  93. package/dist/search/superTypes/domrectSearchType.d.ts.map +1 -0
  94. package/dist/search/superTypes/errorsSpecialSearchType.d.ts +11 -0
  95. package/dist/search/superTypes/errorsSpecialSearchType.d.ts.map +1 -0
  96. package/dist/search/unions/discriminatedUnionSearchType.d.ts +12 -0
  97. package/dist/search/unions/discriminatedUnionSearchType.d.ts.map +1 -0
  98. package/dist/search/unions/unionFamilySearchType.d.ts +36 -0
  99. package/dist/search/unions/unionFamilySearchType.d.ts.map +1 -0
  100. package/dist/search/unions/unionSearchType.d.ts +8 -0
  101. package/dist/search/unions/unionSearchType.d.ts.map +1 -0
  102. package/dist/search/unions/xorSearchType.d.ts +12 -0
  103. package/dist/search/unions/xorSearchType.d.ts.map +1 -0
  104. package/dist/superTypes/buffersourceType.d.ts.map +1 -1
  105. package/dist/typeChoices.d.ts +3 -3
  106. package/dist/typeChoices.d.ts.map +1 -1
  107. package/dist/types.d.ts +3 -3
  108. package/dist/types.d.ts.map +1 -1
  109. package/package.json +5 -4
  110. package/pnpm-workspace.yaml +1 -1
  111. package/rollup.config.js +12 -0
  112. package/src/formatAndTypeChoices.js +4 -4
  113. package/src/formats/schema.js +1 -1
  114. package/src/formats.js +1 -1
  115. package/src/fundamentalTypes/dateType.js +40 -14
  116. package/src/fundamentalTypes/domexceptionType.js +41 -33
  117. package/src/fundamentalTypes/regexpType.js +1 -1
  118. package/src/index.js +6 -0
  119. package/src/jsoe.css +204 -0
  120. package/src/jtltExtensions.js +103 -0
  121. package/src/search/fundamentalTypes/arraySearchType.js +101 -0
  122. package/src/search/fundamentalTypes/bigintSearchType.js +68 -0
  123. package/src/search/fundamentalTypes/blobSearchType.js +42 -0
  124. package/src/search/fundamentalTypes/booleanSearchType.js +40 -0
  125. package/src/search/fundamentalTypes/catchSearchType.js +59 -0
  126. package/src/search/fundamentalTypes/dateSearchType.js +166 -0
  127. package/src/search/fundamentalTypes/domexceptionSearchType.js +84 -0
  128. package/src/search/fundamentalTypes/enumSearchType.js +62 -0
  129. package/src/search/fundamentalTypes/errorSearchType.js +11 -0
  130. package/src/search/fundamentalTypes/fileSearchType.js +94 -0
  131. package/src/search/fundamentalTypes/filelistSearchType.js +103 -0
  132. package/src/search/fundamentalTypes/functionSearchType.js +102 -0
  133. package/src/search/fundamentalTypes/mapSearchType.js +117 -0
  134. package/src/search/fundamentalTypes/nanSearchType.js +11 -0
  135. package/src/search/fundamentalTypes/nullSearchType.js +11 -0
  136. package/src/search/fundamentalTypes/numberSearchType.js +59 -0
  137. package/src/search/fundamentalTypes/objectSearchType.js +367 -0
  138. package/src/search/fundamentalTypes/promiseSearchType.js +61 -0
  139. package/src/search/fundamentalTypes/regexpSearchType.js +72 -0
  140. package/src/search/fundamentalTypes/setSearchType.js +91 -0
  141. package/src/search/fundamentalTypes/stringSearchType.js +44 -0
  142. package/src/search/fundamentalTypes/symbolSearchType.js +39 -0
  143. package/src/search/fundamentalTypes/undefinedSearchType.js +11 -0
  144. package/src/search/index.js +96 -0
  145. package/src/search/queryTree.js +244 -0
  146. package/src/search/queryTreeBuilders.js +233 -0
  147. package/src/search/searchDispatch.js +291 -0
  148. package/src/search/searchElementUtils.js +373 -0
  149. package/src/search/searchUtils.js +847 -0
  150. package/src/search/subTypes/blobHTMLSearchType.js +122 -0
  151. package/src/search/subTypes/recordSearchType.js +105 -0
  152. package/src/search/subTypes/tupleSearchType.js +152 -0
  153. package/src/search/superTypes/SpecialRealNumberSearchType.js +42 -0
  154. package/src/search/superTypes/buffersourceSearchType.js +53 -0
  155. package/src/search/superTypes/dommatrixSearchType.js +24 -0
  156. package/src/search/superTypes/dompointSearchType.js +15 -0
  157. package/src/search/superTypes/domrectSearchType.js +15 -0
  158. package/src/search/superTypes/errorsSpecialSearchType.js +15 -0
  159. package/src/search/unions/discriminatedUnionSearchType.js +16 -0
  160. package/src/search/unions/unionFamilySearchType.js +168 -0
  161. package/src/search/unions/unionSearchType.js +12 -0
  162. package/src/search/unions/xorSearchType.js +16 -0
  163. package/src/superTypes/buffersourceType.js +13 -15
  164. package/src/typeChoices.js +2 -2
  165. package/src/types.js +2 -2
  166. package/tsconfig-prod.json +12 -0
  167. package/tsconfig.json +5 -10
@@ -0,0 +1,166 @@
1
+ import {buildDateInputControl} from '../../fundamentalTypes/dateType.js';
2
+ import {
3
+ buildPathLabel, buildTriStateSelect, readTriStateSelect, isExemptedByAncestorHasProperty
4
+ } from '../searchUtils.js';
5
+ import {makeRangeLeaf, makeValidDateCheckLeaf, combineAnd} from '../queryTreeBuilders.js';
6
+ import {getQueryViaElement} from '../searchElementUtils.js';
7
+
8
+ /**
9
+ * @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
10
+ */
11
+
12
+ /**
13
+ * Reads the two `datetime-local` inputs directly off the element rather
14
+ * than off any closed-over reference, since a custom element's mixin
15
+ * methods (`$define`, search plan §8) are installed once on the shared
16
+ * prototype the first time the tag is defined - every instance must read
17
+ * its own state off `this`, never off a build-time closure variable.
18
+ * @param {Element} el
19
+ * @returns {{gte: string, lte: string}}
20
+ */
21
+ function readInputs (el) {
22
+ const [gteInput, lteInput] = /** @type {HTMLInputElement[]} */ (
23
+ [...el.querySelectorAll('input[type="datetime-local"]')]
24
+ );
25
+ return {gte: gteInput.value, lte: lteInput.value};
26
+ }
27
+
28
+ /**
29
+ * Cross-validates the pair the same way `searchUtils.js`'s
30
+ * `buildRangeInputsPair` does for its own (numeric) range pairs: leaving
31
+ * both ends blank is invalid (an added range row needs *some* bound, same
32
+ * "no absent values" reasoning as `buildLiteralRegexControls`'s Value
33
+ * input) - but only while the "Valid: (any)" tri-state is still unset.
34
+ * Once "Valid date" or "Invalid date" is explicitly chosen, that alone is
35
+ * already a complete constraint, so the range goes back to being fully
36
+ * optional (an empty range combined with "Valid date" still means
37
+ * something: "matches any valid date"); "Invalid date" additionally
38
+ * disables the whole fieldset (an "Invalid Date" has no orderable time
39
+ * value to compare), which independently exempts it from constraint
40
+ * validation regardless. If both ends are filled with "To" before "From",
41
+ * that's invalid either way. `datetime-local` values (`YYYY-MM-DDTHH:mm`)
42
+ * compare correctly as plain strings, so no `Date` parsing is needed here.
43
+ * Also called (with `this` as the `<jsoe-search-date>` root itself, which
44
+ * `this.closest('jsoe-search-date')` still resolves to - `closest` checks
45
+ * the element itself first) from the widget's own `connectedCallback` below
46
+ * and from the "Valid" tri-state's own `change` handler (the "at least one
47
+ * bound" requirement itself flips based on that selection, not just the
48
+ * range values) - the same reason `searchUtils.js`'s `syncRangeValidity`
49
+ * gives for `connectedCallback`: the `input`/`change` events wired below
50
+ * only fire from the user's first interaction, so a freshly-built pair
51
+ * would otherwise stay "valid" until then. Also relaxed, independently of
52
+ * its own local "Valid" tri-state, while `isExemptedByAncestorHasProperty`
53
+ * says an enclosing `objectSearchType.js` has-property row's own "Has"/
54
+ * "Doesn't have" already provides a complete constraint (e.g. this is a
55
+ * `date`-typed property's own widget).
56
+ * @this {Element}
57
+ * @returns {void}
58
+ */
59
+ function validateRange () {
60
+ const root = this.closest('jsoe-search-date');
61
+ if (!root) {
62
+ return;
63
+ }
64
+ const {gte, lte} = readInputs(root);
65
+ const [gteInput, lteInput] = /** @type {HTMLInputElement[]} */ (
66
+ [...root.querySelectorAll('input[type="datetime-local"]')]
67
+ );
68
+ const requiresBound = readTriStateSelect(root, 'valid') === undefined &&
69
+ !isExemptedByAncestorHasProperty(root);
70
+ const bothEmpty = requiresBound && gte === '' && lte === '';
71
+ const outOfOrder = gte !== '' && lte !== '' && lte < gte;
72
+ const emptyMessage = 'Enter at least one bound (From or To).';
73
+ gteInput.setCustomValidity(bothEmpty ? emptyMessage : '');
74
+ let lteMessage = '';
75
+ if (bothEmpty) {
76
+ lteMessage = emptyMessage;
77
+ } else if (outOfOrder) {
78
+ lteMessage = 'End of range must not be before the start of the range.';
79
+ }
80
+ lteInput.setCustomValidity(lteMessage);
81
+ }
82
+
83
+ /**
84
+ * OR date range/Is Not Range, Is/Is not a valid date (README) -
85
+ * `dateType.js`'s own `buildDateInputControl` is reused twice (range start/
86
+ * end) so the min/max wiring and ISO-slicing stay in one place. Choosing
87
+ * "Invalid date" disables the range fieldset (an "Invalid Date" has no
88
+ * orderable time value to compare - same as `dateType.js`'s own
89
+ * `notANum`/`ValidDate`/`InvalidDate` handling treating it as a distinct
90
+ * state from an ordinary `Date`), producing a `validDateCheck` leaf
91
+ * (`queryTreeBuilders.js`) instead of/alongside the range leaf.
92
+ * @type {SearchTypeObject}
93
+ */
94
+ const dateSearchType = {
95
+ buildUI ({schemaObject, path, typeNamespace}) {
96
+ const label = buildPathLabel(schemaObject, path);
97
+ const dateSchemaObject = /** @type {import('zodexy').SzDate} */ (
98
+ schemaObject
99
+ );
100
+ const name = `${typeNamespace}-date`;
101
+ return ['jsoe-search-date', {
102
+ dataset: {searchPath: path, searchKind: 'date'},
103
+ title: label,
104
+ $define: {
105
+ /** @this {HTMLElement} */
106
+ connectedCallback () {
107
+ validateRange.call(this);
108
+ },
109
+ /** @this {HTMLElement} */
110
+ getQuery () {
111
+ const searchPath = this.dataset.searchPath ?? '';
112
+ const validCheck = readTriStateSelect(this, 'valid');
113
+ const validLeaf = validCheck === undefined
114
+ ? undefined
115
+ : makeValidDateCheckLeaf(searchPath, validCheck);
116
+ const {gte, lte} = readInputs(this);
117
+ const rangeLeaf = validCheck === false || (!gte && !lte)
118
+ ? undefined
119
+ : makeRangeLeaf(searchPath, 'date', {
120
+ ...(gte ? {$gte: new Date(gte).toISOString()} : {}),
121
+ ...(lte ? {$lte: new Date(lte).toISOString()} : {})
122
+ });
123
+ return combineAnd([validLeaf, rangeLeaf]);
124
+ }
125
+ }
126
+ }, [
127
+ ['span', {class: 'searchLabel'}, [label]],
128
+ ['label', [
129
+ 'Valid: ',
130
+ buildTriStateSelect({
131
+ name: `${name}-valid`, key: 'valid', trueLabel: 'Valid date',
132
+ falseLabel: 'Invalid date',
133
+ /** @this {HTMLElement} */
134
+ onChange () {
135
+ const root = this.closest('jsoe-search-date');
136
+ const fieldset = root?.querySelector('fieldset.searchDateRangeFieldset');
137
+ if (fieldset) {
138
+ /** @type {HTMLFieldSetElement} */ (fieldset).disabled =
139
+ /** @type {HTMLSelectElement} */ (this).value === 'false';
140
+ }
141
+ if (root) {
142
+ validateRange.call(root);
143
+ }
144
+ }
145
+ })
146
+ ]],
147
+ ['fieldset', {class: 'searchDateRangeFieldset'}, [
148
+ ['label', [
149
+ 'From: ',
150
+ buildDateInputControl({
151
+ name: `${name}-gte`, dateSchemaObject, onValidate: validateRange
152
+ })
153
+ ]],
154
+ ['label', [
155
+ 'To: ',
156
+ buildDateInputControl({
157
+ name: `${name}-lte`, dateSchemaObject, onValidate: validateRange
158
+ })
159
+ ]]
160
+ ]]
161
+ ]];
162
+ },
163
+ getQuery: getQueryViaElement
164
+ };
165
+
166
+ export default dateSearchType;
@@ -0,0 +1,84 @@
1
+ import {domExceptionNames} from '../../fundamentalTypes/domexceptionType.js';
2
+ import {
3
+ buildPathLabel, buildMultiSelect, readMultiSelect, buildLiteralRegexControls,
4
+ readLiteralRegexQuery, buildOptInFieldset, readOptInChecked, wireOptInFieldset,
5
+ buildAtLeastOneSentinel, syncAtLeastOneCheck
6
+ } from '../searchUtils.js';
7
+ import {makeMultiSelectLeaf, combineAnd} from '../queryTreeBuilders.js';
8
+ import {getQueryViaElement} from '../searchElementUtils.js';
9
+ import regexpType from '../../fundamentalTypes/regexpType.js';
10
+
11
+ /**
12
+ * @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
13
+ */
14
+
15
+ /**
16
+ * @param {Element} root - a `jsoe-search-domexception` element
17
+ * @returns {void}
18
+ */
19
+ function syncDomexceptionValidity (root) {
20
+ syncAtLeastOneCheck(
21
+ root, () => readMultiSelect(root).length > 0 || readOptInChecked(root, 'message')
22
+ );
23
+ }
24
+
25
+ /**
26
+ * DOMException: Literal/Regex search of child string properties; also
27
+ * pull-down of name for DOMException (README) - `.name` gets the
28
+ * multi-select pull-down (its standard predefined values, imported as-is
29
+ * from `domexceptionType.js`'s own `domExceptionNames` export rather than a
30
+ * second copy of the list, and already properly optional on its own - an
31
+ * empty selection needs no opt-in gate), `.message` gets the usual literal/
32
+ * regex/does-not-contain control (wrapped in `buildOptInFieldset`, since
33
+ * that one *does* carry a `required` Value input), combined via `$and`.
34
+ * `buildAtLeastOneSentinel` requires at least one of the two.
35
+ * @type {SearchTypeObject}
36
+ */
37
+ const domexceptionSearchType = {
38
+ buildUI ({schemaObject, path, typeNamespace}) {
39
+ const label = buildPathLabel(schemaObject, path);
40
+ const name = `${typeNamespace}-domexception`;
41
+ return ['jsoe-search-domexception', {
42
+ dataset: {searchPath: path, searchKind: 'domexception'},
43
+ title: label,
44
+ $define: {
45
+ /** @this {HTMLElement} */
46
+ connectedCallback () {
47
+ this.querySelector('select.jsoeSearchMultiSelect')?.addEventListener(
48
+ 'change', () => syncDomexceptionValidity(this)
49
+ );
50
+ wireOptInFieldset(this, 'message', () => syncDomexceptionValidity(this));
51
+ syncDomexceptionValidity(this);
52
+ },
53
+ /** @this {HTMLElement} */
54
+ getQuery () {
55
+ const searchPath = this.dataset.searchPath ?? '';
56
+ const selectedNames = readMultiSelect(this);
57
+ const nameLeaf = selectedNames.length
58
+ ? makeMultiSelectLeaf(`${searchPath}/name`, {$in: selectedNames})
59
+ : undefined;
60
+ const messageLeaf = readOptInChecked(this, 'message')
61
+ ? readLiteralRegexQuery(this, `${searchPath}/message`, 'message')
62
+ : undefined;
63
+ return combineAnd([nameLeaf, messageLeaf]);
64
+ }
65
+ }
66
+ }, [
67
+ ['span', {class: 'searchLabel'}, [label]],
68
+ ['div', {class: 'domexceptionName'}, [
69
+ ['span', ['Name: ']],
70
+ buildMultiSelect({name: `${name}-name`, options: domExceptionNames})
71
+ ]],
72
+ ...buildOptInFieldset({
73
+ name: `${name}-message`, key: 'message', label: 'Message',
74
+ children: [buildLiteralRegexControls({
75
+ name: `${name}-message`, key: 'message', flagOptions: regexpType.allowedFlags
76
+ })]
77
+ }),
78
+ buildAtLeastOneSentinel()
79
+ ]];
80
+ },
81
+ getQuery: getQueryViaElement
82
+ };
83
+
84
+ export default domexceptionSearchType;
@@ -0,0 +1,62 @@
1
+ import {buildPathLabel, buildMultiSelect, readMultiSelect} from '../searchUtils.js';
2
+ import {makeMultiSelectLeaf} from '../queryTreeBuilders.js';
3
+ import {getQueryViaElement} from '../searchElementUtils.js';
4
+
5
+ /**
6
+ * @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
7
+ */
8
+
9
+ /**
10
+ * Enum, Native Enum: multiple select (README). The value-editing side has
11
+ * no dedicated `enumType.js` (`getSchemaType` resolves `enum` to whatever
12
+ * its underlying value type is), but search needs the actual allowed
13
+ * values listed, so this is one of the search-only dedicated modules
14
+ * (search plan §1).
15
+ *
16
+ * The README's further "native enum also can search key vs. value" is not
17
+ * implemented by this pass - only the plain multi-select-of-values
18
+ * affordance every enum gets either way. A native enum whose keys differ
19
+ * from its values (unlike a plain `z.enum([...])`, where they're the same)
20
+ * still gets a usable widget here, just not that extra key-vs-value mode
21
+ * yet; `values`'s keys are shown alongside their value as a hint.
22
+ * `buildMultiSelect`'s `required` leaves the whole selection invalid until
23
+ * at least one value is picked, natively (no build-time-empty gap like
24
+ * `buildRangeInputsPair`'s custom validity needed a `connectedCallback`
25
+ * for - `<select multiple required>` is evaluated by the browser itself).
26
+ * @type {SearchTypeObject}
27
+ */
28
+ const enumSearchType = {
29
+ buildUI ({schemaObject, path, typeNamespace}) {
30
+ const label = buildPathLabel(schemaObject, path);
31
+ const name = `${typeNamespace}-enum`;
32
+ const {values} = /** @type {import('zodexy').SzEnum} */ (
33
+ schemaObject
34
+ );
35
+ const options = Object.entries(values).map(([key, value]) => {
36
+ const strValue = String(value);
37
+ return /** @type {[string, string]} */ ([
38
+ strValue,
39
+ key === strValue ? strValue : `${strValue} (${key})`
40
+ ]);
41
+ });
42
+ return ['jsoe-search-enum', {
43
+ dataset: {searchPath: path, searchKind: 'enum'},
44
+ title: label,
45
+ $define: {
46
+ /** @this {HTMLElement} */
47
+ getQuery () {
48
+ const selected = readMultiSelect(this);
49
+ return selected.length
50
+ ? makeMultiSelectLeaf(this.dataset.searchPath ?? '', {$in: selected})
51
+ : undefined;
52
+ }
53
+ }
54
+ }, [
55
+ ['span', {class: 'searchLabel'}, [label]],
56
+ buildMultiSelect({name, options, required: true})
57
+ ]];
58
+ },
59
+ getQuery: getQueryViaElement
60
+ };
61
+
62
+ export default enumSearchType;
@@ -0,0 +1,11 @@
1
+ import {makeErrorFamilySearchType} from '../searchElementUtils.js';
2
+
3
+ /**
4
+ * Error: Literal/Regex search of child string properties, numeric of
5
+ * number children (README) - see `searchElementUtils.js`'s
6
+ * `makeErrorFamilySearchType` for the shared implementation.
7
+ * @type {import('../searchDispatch.js').SearchTypeObject}
8
+ */
9
+ const errorSearchType = makeErrorFamilySearchType({tagName: 'jsoe-search-error'});
10
+
11
+ export default errorSearchType;
@@ -0,0 +1,94 @@
1
+ import {
2
+ buildPathLabel, buildLiteralRegexControls, readLiteralRegexQuery,
3
+ buildOptInFieldset, readOptInChecked, wireOptInFieldset,
4
+ buildAtLeastOneSentinel, syncAtLeastOneCheck
5
+ } from '../searchUtils.js';
6
+ import {combineAnd} from '../queryTreeBuilders.js';
7
+ import {getQueryViaElement} from '../searchElementUtils.js';
8
+ import regexpType from '../../fundamentalTypes/regexpType.js';
9
+
10
+ /**
11
+ * @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
12
+ */
13
+
14
+ /**
15
+ * @param {Element} root - a `jsoe-search-file` element
16
+ * @returns {void}
17
+ */
18
+ function syncFileValidity (root) {
19
+ syncAtLeastOneCheck(
20
+ root, () => readOptInChecked(root, 'name') || readOptInChecked(root, 'type')
21
+ );
22
+ }
23
+
24
+ /**
25
+ * File: OR literal or regex search/Does Not contain search (README, grouped
26
+ * with string/StringObject/Blob/regexp-source/symbol-description) - against
27
+ * both the File's `.name` and its `.type` (content/MIME type, the same
28
+ * facet `blobSearchType.js` targets for `Blob`), each a value-level facet
29
+ * the schema itself carries no constraint for (`SzFile` only has
30
+ * `min`/`max`/`mime`, and `mime` is a fixed *allow-list* for validation, not
31
+ * a per-instance value to search against). `name`/`type` sub-paths
32
+ * distinguish the two facets (`${path}/name`, `${path}/type`, matching the
33
+ * real `File` property each reads back), the same convention
34
+ * `errorSearchType.js` uses for its own multiple flat facets, combined via
35
+ * `$and`. Each facet is independently opt-in (`buildOptInFieldset`, so
36
+ * checking against just the name, or just the content type, is as easy as
37
+ * checking against both), but leaving *both* unopted-in is itself invalid
38
+ * (`buildAtLeastOneSentinel`) - the same "key or value, not necessarily
39
+ * both" shape `mapSearchType.js`/`recordSearchType.js` use. `SzFile`'s own
40
+ * `min`/`max` (byte size) is left for a later pass - the README's literal/
41
+ * regex bullet doesn't ask for a size range here, and README explicitly
42
+ * reserves that shape of control ("OR Range/Is Not Range") for
43
+ * `buffersource` instead. `filelistSearchType.js` recurses its element
44
+ * schema through this same module, so a `FileList`'s per-file search gets
45
+ * both facets for free.
46
+ * @type {SearchTypeObject}
47
+ */
48
+ const fileSearchType = {
49
+ buildUI ({schemaObject, path, typeNamespace}) {
50
+ const label = buildPathLabel(schemaObject, path);
51
+ const name = `${typeNamespace}-file`;
52
+ return ['jsoe-search-file', {
53
+ dataset: {searchPath: path, searchKind: 'file'},
54
+ title: label,
55
+ $define: {
56
+ /** @this {HTMLElement} */
57
+ connectedCallback () {
58
+ wireOptInFieldset(this, 'name', () => syncFileValidity(this));
59
+ wireOptInFieldset(this, 'type', () => syncFileValidity(this));
60
+ syncFileValidity(this);
61
+ },
62
+ /** @this {HTMLElement} */
63
+ getQuery () {
64
+ const searchPath = this.dataset.searchPath ?? '';
65
+ const nameLeaf = readOptInChecked(this, 'name')
66
+ ? readLiteralRegexQuery(this, `${searchPath}/name`, 'name')
67
+ : undefined;
68
+ const typeLeaf = readOptInChecked(this, 'type')
69
+ ? readLiteralRegexQuery(this, `${searchPath}/type`, 'type')
70
+ : undefined;
71
+ return combineAnd([nameLeaf, typeLeaf]);
72
+ }
73
+ }
74
+ }, [
75
+ ['span', {class: 'searchLabel'}, [label]],
76
+ ...buildOptInFieldset({
77
+ name: `${name}-name`, key: 'name', label: 'Name',
78
+ children: [buildLiteralRegexControls({
79
+ name: `${name}-name`, key: 'name', flagOptions: regexpType.allowedFlags
80
+ })]
81
+ }),
82
+ ...buildOptInFieldset({
83
+ name: `${name}-type`, key: 'type', label: 'Content type',
84
+ children: [buildLiteralRegexControls({
85
+ name: `${name}-type`, key: 'type', flagOptions: regexpType.allowedFlags
86
+ })]
87
+ }),
88
+ buildAtLeastOneSentinel()
89
+ ]];
90
+ },
91
+ getQuery: getQueryViaElement
92
+ };
93
+
94
+ export default fileSearchType;
@@ -0,0 +1,103 @@
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
+ * @typedef {{
16
+ * type: 'array',
17
+ * element: import('../../formats/schema.js').ZodexSchema,
18
+ * minLength?: number,
19
+ * maxLength?: number
20
+ * }} FilelistOutputSchema
21
+ */
22
+
23
+ /**
24
+ * @param {Element} root - a `jsoe-search-filelist` element
25
+ * @returns {void}
26
+ */
27
+ function syncFilelistValidity (root) {
28
+ syncAtLeastOneCheck(
29
+ root, () => readLengthSizeQuery(root, '') !== undefined || readOptInChecked(root)
30
+ );
31
+ }
32
+
33
+ /**
34
+ * Has length/size of &lt;number&gt; (README, grouped with array/set/
35
+ * tuple-with-rest) - no sparse toggle, matching `setSearchType.js`. A
36
+ * `FileList` schema serializes as `{type: 'codec', name: 'filelist',
37
+ * output: {type: 'array', element: {type: 'file', ...}}}`
38
+ * (`src/formats/schema.js`'s `codec`/`filelist` handling); the length
39
+ * bounds and element schema both live on that `output` array shape, whose
40
+ * element recurses into `fileSearchType.js` under the same `*` path-segment
41
+ * convention `arraySearchType.js` uses. Leaving *both* length/size and the
42
+ * element match unconfigured is still invalid, though
43
+ * (`buildAtLeastOneSentinel`), same as `arraySearchType.js`/
44
+ * `setSearchType.js`.
45
+ * @type {SearchTypeObject}
46
+ */
47
+ const filelistSearchType = {
48
+ buildUI ({schemaObject, path, typeNamespace, topRoot, types, originalJSON}) {
49
+ const label = buildPathLabel(schemaObject, path);
50
+ const name = `${typeNamespace}-filelist`;
51
+ const outputSchema = /** @type {FilelistOutputSchema} */ (
52
+ /** @type {{output: unknown}} */ (schemaObject).output
53
+ );
54
+ const elementPath = `${path}/*`;
55
+ const elementArr = buildSearchWidget({
56
+ schemaObject: outputSchema.element,
57
+ path: elementPath,
58
+ typeNamespace,
59
+ topRoot,
60
+ types,
61
+ originalJSON
62
+ });
63
+ return ['jsoe-search-filelist', {
64
+ dataset: {searchPath: path, searchKind: 'filelist'},
65
+ title: label,
66
+ $define: {
67
+ /** @this {HTMLElement} */
68
+ connectedCallback () {
69
+ wireOptInFieldset(this, '', () => syncFilelistValidity(this));
70
+ this.querySelector('input.jsoeSearchSize')?.addEventListener(
71
+ 'input', () => syncFilelistValidity(this)
72
+ );
73
+ syncFilelistValidity(this);
74
+ },
75
+ /** @this {HTMLElement} */
76
+ getQuery () {
77
+ const searchPath = this.dataset.searchPath ?? '';
78
+ const lengthLeaf = readLengthSizeQuery(this, searchPath);
79
+ const elementEl = findSearchElement(this, `${searchPath}/*`);
80
+ const elementLeaf = elementEl && hasGetQuery(elementEl) && readOptInChecked(this)
81
+ ? elementEl.getQuery()
82
+ : undefined;
83
+ return combineAnd([lengthLeaf, elementLeaf]);
84
+ }
85
+ }
86
+ }, [
87
+ ['span', {class: 'searchLabel'}, [label]],
88
+ ...buildLengthSizeControls({
89
+ name,
90
+ min: outputSchema.minLength,
91
+ max: outputSchema.maxLength,
92
+ includeSparse: false
93
+ }),
94
+ ...buildOptInFieldset({
95
+ name: `${name}-element`, label: 'File matches', children: [elementArr]
96
+ }),
97
+ buildAtLeastOneSentinel()
98
+ ]];
99
+ },
100
+ getQuery: getQueryViaElement
101
+ };
102
+
103
+ export default filelistSearchType;
@@ -0,0 +1,102 @@
1
+ import {
2
+ buildPathLabel, buildOptInFieldset, readOptInChecked, wireOptInFieldset,
3
+ buildAtLeastOneSentinel, syncAtLeastOneCheck
4
+ } from '../searchUtils.js';
5
+ import {combineAnd} from '../queryTreeBuilders.js';
6
+ import {findSearchElement, getQueryViaElement, hasGetQuery} from '../searchElementUtils.js';
7
+ import {buildSearchWidget} from '../searchDispatch.js';
8
+
9
+ /**
10
+ * @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
11
+ */
12
+
13
+ /**
14
+ * @param {Element} root - a `jsoe-search-function` element
15
+ * @returns {void}
16
+ */
17
+ function syncFunctionValidity (root) {
18
+ syncAtLeastOneCheck(
19
+ root, () => readOptInChecked(root, 'args') || readOptInChecked(root, 'output')
20
+ );
21
+ }
22
+
23
+ /**
24
+ * Function; pass on args, return type (README) - recurses into both
25
+ * `.input` (itself a tuple, so its own per-position controls come for free
26
+ * via `tupleSearchType.js`) and `.output`, at `*args`/`*output` path
27
+ * segments (`queryTree.js`), combined via `$and`. The build order's own
28
+ * note that `function` is "fuzzy" in the README and could ship as a
29
+ * minimal stub predates `tupleSearchType.js` existing; now that it does,
30
+ * recursing into `.input` through it is no more work than `.output` alone
31
+ * would have been. Each is wrapped in its own `buildOptInFieldset` (an args
32
+ * tuple's own positions are themselves individually opt-in, so args as a
33
+ * whole needs the same treatment one level up), with
34
+ * `buildAtLeastOneSentinel` requiring at least one of the two.
35
+ * @type {SearchTypeObject}
36
+ */
37
+ const functionSearchType = {
38
+ buildUI ({schemaObject, path, typeNamespace, topRoot, types, originalJSON}) {
39
+ const label = buildPathLabel(schemaObject, path);
40
+ const name = `${typeNamespace}-function`;
41
+ const functionSchemaObject = /** @type {import('zodexy').SzFunction<any, any>} */ (
42
+ schemaObject
43
+ );
44
+ const argsPath = `${path}/*args`;
45
+ const outputPath = `${path}/*output`;
46
+ const argsArr = buildSearchWidget({
47
+ schemaObject: functionSchemaObject.input,
48
+ path: argsPath,
49
+ typeNamespace,
50
+ topRoot,
51
+ types,
52
+ originalJSON
53
+ });
54
+ const outputArr = buildSearchWidget({
55
+ schemaObject: functionSchemaObject.output,
56
+ path: outputPath,
57
+ typeNamespace,
58
+ topRoot,
59
+ types,
60
+ originalJSON
61
+ });
62
+ return ['jsoe-search-function', {
63
+ dataset: {searchPath: path, searchKind: 'function'},
64
+ title: label,
65
+ $define: {
66
+ /** @this {HTMLElement} */
67
+ connectedCallback () {
68
+ wireOptInFieldset(this, 'args', () => syncFunctionValidity(this));
69
+ wireOptInFieldset(this, 'output', () => syncFunctionValidity(this));
70
+ syncFunctionValidity(this);
71
+ },
72
+ /** @this {HTMLElement} */
73
+ getQuery () {
74
+ const searchPath = this.dataset.searchPath ?? '';
75
+ const argsEl = findSearchElement(this, `${searchPath}/*args`);
76
+ const outputEl = findSearchElement(this, `${searchPath}/*output`);
77
+ const argsQuery = argsEl && hasGetQuery(argsEl) && readOptInChecked(this, 'args')
78
+ ? argsEl.getQuery()
79
+ : undefined;
80
+ const outputQuery = outputEl && hasGetQuery(outputEl) &&
81
+ readOptInChecked(this, 'output')
82
+ ? outputEl.getQuery()
83
+ : undefined;
84
+ return combineAnd([argsQuery, outputQuery]);
85
+ }
86
+ }
87
+ }, [
88
+ ['span', {class: 'searchLabel'}, [label]],
89
+ ...buildOptInFieldset({
90
+ name: `${name}-args`, key: 'args', label: 'Args match', children: [argsArr]
91
+ }),
92
+ ...buildOptInFieldset({
93
+ name: `${name}-output`, key: 'output', label: 'Return value matches',
94
+ children: [outputArr]
95
+ }),
96
+ buildAtLeastOneSentinel()
97
+ ]];
98
+ },
99
+ getQuery: getQueryViaElement
100
+ };
101
+
102
+ export default functionSearchType;