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