@es-joy/jsoe 0.28.2 → 0.29.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 (163) hide show
  1. package/CHANGES.md +19 -0
  2. package/README.md +2 -0
  3. package/dist/formatAndTypeChoices.d.ts +6 -6
  4. package/dist/formatAndTypeChoices.d.ts.map +1 -1
  5. package/dist/formats/schema.d.ts +5 -0
  6. package/dist/formats/schema.d.ts.map +1 -1
  7. package/dist/formats.d.ts +2 -2
  8. package/dist/formats.d.ts.map +1 -1
  9. package/dist/fundamentalTypes/dateType.d.ts +21 -2
  10. package/dist/fundamentalTypes/dateType.d.ts.map +1 -1
  11. package/dist/fundamentalTypes/domexceptionType.d.ts +7 -0
  12. package/dist/fundamentalTypes/domexceptionType.d.ts.map +1 -1
  13. package/dist/index.d.ts +2 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +2 -2
  16. package/dist/index.js.map +1 -1
  17. package/dist/jtltExtensions.d.ts +112 -0
  18. package/dist/jtltExtensions.d.ts.map +1 -0
  19. package/dist/search/fundamentalTypes/arraySearchType.d.ts +15 -0
  20. package/dist/search/fundamentalTypes/arraySearchType.d.ts.map +1 -0
  21. package/dist/search/fundamentalTypes/bigintSearchType.d.ts +10 -0
  22. package/dist/search/fundamentalTypes/bigintSearchType.d.ts.map +1 -0
  23. package/dist/search/fundamentalTypes/blobSearchType.d.ts +19 -0
  24. package/dist/search/fundamentalTypes/blobSearchType.d.ts.map +1 -0
  25. package/dist/search/fundamentalTypes/booleanSearchType.d.ts +11 -0
  26. package/dist/search/fundamentalTypes/booleanSearchType.d.ts.map +1 -0
  27. package/dist/search/fundamentalTypes/catchSearchType.d.ts +18 -0
  28. package/dist/search/fundamentalTypes/catchSearchType.d.ts.map +1 -0
  29. package/dist/search/fundamentalTypes/dateSearchType.d.ts +10 -0
  30. package/dist/search/fundamentalTypes/dateSearchType.d.ts.map +1 -0
  31. package/dist/search/fundamentalTypes/domexceptionSearchType.d.ts +16 -0
  32. package/dist/search/fundamentalTypes/domexceptionSearchType.d.ts.map +1 -0
  33. package/dist/search/fundamentalTypes/enumSearchType.d.ts +22 -0
  34. package/dist/search/fundamentalTypes/enumSearchType.d.ts.map +1 -0
  35. package/dist/search/fundamentalTypes/errorSearchType.d.ts +9 -0
  36. package/dist/search/fundamentalTypes/errorSearchType.d.ts.map +1 -0
  37. package/dist/search/fundamentalTypes/fileSearchType.d.ts +19 -0
  38. package/dist/search/fundamentalTypes/fileSearchType.d.ts.map +1 -0
  39. package/dist/search/fundamentalTypes/filelistSearchType.d.ts +32 -0
  40. package/dist/search/fundamentalTypes/filelistSearchType.d.ts.map +1 -0
  41. package/dist/search/fundamentalTypes/functionSearchType.d.ts +18 -0
  42. package/dist/search/fundamentalTypes/functionSearchType.d.ts.map +1 -0
  43. package/dist/search/fundamentalTypes/mapSearchType.d.ts +18 -0
  44. package/dist/search/fundamentalTypes/mapSearchType.d.ts.map +1 -0
  45. package/dist/search/fundamentalTypes/nanSearchType.d.ts +7 -0
  46. package/dist/search/fundamentalTypes/nanSearchType.d.ts.map +1 -0
  47. package/dist/search/fundamentalTypes/nullSearchType.d.ts +7 -0
  48. package/dist/search/fundamentalTypes/nullSearchType.d.ts.map +1 -0
  49. package/dist/search/fundamentalTypes/numberSearchType.d.ts +11 -0
  50. package/dist/search/fundamentalTypes/numberSearchType.d.ts.map +1 -0
  51. package/dist/search/fundamentalTypes/objectSearchType.d.ts +15 -0
  52. package/dist/search/fundamentalTypes/objectSearchType.d.ts.map +1 -0
  53. package/dist/search/fundamentalTypes/promiseSearchType.d.ts +20 -0
  54. package/dist/search/fundamentalTypes/promiseSearchType.d.ts.map +1 -0
  55. package/dist/search/fundamentalTypes/regexpSearchType.d.ts +14 -0
  56. package/dist/search/fundamentalTypes/regexpSearchType.d.ts.map +1 -0
  57. package/dist/search/fundamentalTypes/setSearchType.d.ts +14 -0
  58. package/dist/search/fundamentalTypes/setSearchType.d.ts.map +1 -0
  59. package/dist/search/fundamentalTypes/stringSearchType.d.ts +13 -0
  60. package/dist/search/fundamentalTypes/stringSearchType.d.ts.map +1 -0
  61. package/dist/search/fundamentalTypes/symbolSearchType.d.ts +16 -0
  62. package/dist/search/fundamentalTypes/symbolSearchType.d.ts.map +1 -0
  63. package/dist/search/fundamentalTypes/undefinedSearchType.d.ts +7 -0
  64. package/dist/search/fundamentalTypes/undefinedSearchType.d.ts.map +1 -0
  65. package/dist/search/index.d.ts +60 -0
  66. package/dist/search/index.d.ts.map +1 -0
  67. package/dist/search/queryTree.d.ts.map +1 -1
  68. package/dist/search/queryTreeBuilders.d.ts +12 -0
  69. package/dist/search/queryTreeBuilders.d.ts.map +1 -1
  70. package/dist/search/searchDispatch.d.ts +44 -0
  71. package/dist/search/searchDispatch.d.ts.map +1 -1
  72. package/dist/search/searchElementUtils.d.ts +97 -0
  73. package/dist/search/searchElementUtils.d.ts.map +1 -0
  74. package/dist/search/searchUtils.d.ts +225 -0
  75. package/dist/search/searchUtils.d.ts.map +1 -0
  76. package/dist/search/subTypes/blobHTMLSearchType.d.ts +16 -0
  77. package/dist/search/subTypes/blobHTMLSearchType.d.ts.map +1 -0
  78. package/dist/search/subTypes/recordSearchType.d.ts +18 -0
  79. package/dist/search/subTypes/recordSearchType.d.ts.map +1 -0
  80. package/dist/search/subTypes/tupleSearchType.d.ts +21 -0
  81. package/dist/search/subTypes/tupleSearchType.d.ts.map +1 -0
  82. package/dist/search/superTypes/SpecialRealNumberSearchType.d.ts +14 -0
  83. package/dist/search/superTypes/SpecialRealNumberSearchType.d.ts.map +1 -0
  84. package/dist/search/superTypes/buffersourceSearchType.d.ts +17 -0
  85. package/dist/search/superTypes/buffersourceSearchType.d.ts.map +1 -0
  86. package/dist/search/superTypes/dommatrixSearchType.d.ts +11 -0
  87. package/dist/search/superTypes/dommatrixSearchType.d.ts.map +1 -0
  88. package/dist/search/superTypes/dompointSearchType.d.ts +9 -0
  89. package/dist/search/superTypes/dompointSearchType.d.ts.map +1 -0
  90. package/dist/search/superTypes/domrectSearchType.d.ts +9 -0
  91. package/dist/search/superTypes/domrectSearchType.d.ts.map +1 -0
  92. package/dist/search/superTypes/errorsSpecialSearchType.d.ts +11 -0
  93. package/dist/search/superTypes/errorsSpecialSearchType.d.ts.map +1 -0
  94. package/dist/search/unions/discriminatedUnionSearchType.d.ts +12 -0
  95. package/dist/search/unions/discriminatedUnionSearchType.d.ts.map +1 -0
  96. package/dist/search/unions/unionFamilySearchType.d.ts +36 -0
  97. package/dist/search/unions/unionFamilySearchType.d.ts.map +1 -0
  98. package/dist/search/unions/unionSearchType.d.ts +8 -0
  99. package/dist/search/unions/unionSearchType.d.ts.map +1 -0
  100. package/dist/search/unions/xorSearchType.d.ts +12 -0
  101. package/dist/search/unions/xorSearchType.d.ts.map +1 -0
  102. package/dist/superTypes/buffersourceType.d.ts.map +1 -1
  103. package/dist/typeChoices.d.ts +3 -3
  104. package/dist/typeChoices.d.ts.map +1 -1
  105. package/dist/types.d.ts +3 -3
  106. package/dist/types.d.ts.map +1 -1
  107. package/package.json +5 -4
  108. package/pnpm-workspace.yaml +1 -1
  109. package/rollup.config.js +12 -0
  110. package/src/formatAndTypeChoices.js +4 -4
  111. package/src/formats/schema.js +1 -1
  112. package/src/formats.js +1 -1
  113. package/src/fundamentalTypes/dateType.js +35 -14
  114. package/src/fundamentalTypes/domexceptionType.js +41 -33
  115. package/src/index.js +6 -0
  116. package/src/jtltExtensions.js +103 -0
  117. package/src/search/fundamentalTypes/arraySearchType.js +66 -0
  118. package/src/search/fundamentalTypes/bigintSearchType.js +62 -0
  119. package/src/search/fundamentalTypes/blobSearchType.js +41 -0
  120. package/src/search/fundamentalTypes/booleanSearchType.js +40 -0
  121. package/src/search/fundamentalTypes/catchSearchType.js +59 -0
  122. package/src/search/fundamentalTypes/dateSearchType.js +73 -0
  123. package/src/search/fundamentalTypes/domexceptionSearchType.js +55 -0
  124. package/src/search/fundamentalTypes/enumSearchType.js +58 -0
  125. package/src/search/fundamentalTypes/errorSearchType.js +11 -0
  126. package/src/search/fundamentalTypes/fileSearchType.js +41 -0
  127. package/src/search/fundamentalTypes/filelistSearchType.js +78 -0
  128. package/src/search/fundamentalTypes/functionSearchType.js +78 -0
  129. package/src/search/fundamentalTypes/mapSearchType.js +87 -0
  130. package/src/search/fundamentalTypes/nanSearchType.js +11 -0
  131. package/src/search/fundamentalTypes/nullSearchType.js +11 -0
  132. package/src/search/fundamentalTypes/numberSearchType.js +52 -0
  133. package/src/search/fundamentalTypes/objectSearchType.js +148 -0
  134. package/src/search/fundamentalTypes/promiseSearchType.js +61 -0
  135. package/src/search/fundamentalTypes/regexpSearchType.js +48 -0
  136. package/src/search/fundamentalTypes/setSearchType.js +65 -0
  137. package/src/search/fundamentalTypes/stringSearchType.js +35 -0
  138. package/src/search/fundamentalTypes/symbolSearchType.js +38 -0
  139. package/src/search/fundamentalTypes/undefinedSearchType.js +11 -0
  140. package/src/search/index.js +79 -0
  141. package/src/search/queryTree.js +235 -0
  142. package/src/search/queryTreeBuilders.js +224 -0
  143. package/src/search/searchDispatch.js +291 -0
  144. package/src/search/searchElementUtils.js +289 -0
  145. package/src/search/searchUtils.js +355 -0
  146. package/src/search/subTypes/blobHTMLSearchType.js +65 -0
  147. package/src/search/subTypes/recordSearchType.js +84 -0
  148. package/src/search/subTypes/tupleSearchType.js +111 -0
  149. package/src/search/superTypes/SpecialRealNumberSearchType.js +42 -0
  150. package/src/search/superTypes/buffersourceSearchType.js +47 -0
  151. package/src/search/superTypes/dommatrixSearchType.js +24 -0
  152. package/src/search/superTypes/dompointSearchType.js +15 -0
  153. package/src/search/superTypes/domrectSearchType.js +15 -0
  154. package/src/search/superTypes/errorsSpecialSearchType.js +15 -0
  155. package/src/search/unions/discriminatedUnionSearchType.js +16 -0
  156. package/src/search/unions/unionFamilySearchType.js +160 -0
  157. package/src/search/unions/unionSearchType.js +12 -0
  158. package/src/search/unions/xorSearchType.js +16 -0
  159. package/src/superTypes/buffersourceType.js +13 -15
  160. package/src/typeChoices.js +2 -2
  161. package/src/types.js +2 -2
  162. package/tsconfig-prod.json +12 -0
  163. package/tsconfig.json +5 -10
@@ -0,0 +1,87 @@
1
+ import {buildPathLabel, buildCheckbox, readCheckbox, buildLengthSizeControls, readLengthSizeQuery} from '../searchUtils.js';
2
+ import {makeMapRecordJointLeaf, combineAnd} from '../queryTreeBuilders.js';
3
+ import {findSearchElement, getQueryViaElement, hasGetQuery} from '../searchElementUtils.js';
4
+ import {buildSearchWidget} from '../searchDispatch.js';
5
+
6
+ /**
7
+ * @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
8
+ */
9
+
10
+ /**
11
+ * Map, Record: string-type searches of keys, values; ideally would allow
12
+ * search to insist on match of key and value (README) - structurally the
13
+ * same as `recordSearchType.js` (`key`/`value` recursion at `*key`/`*value`
14
+ * segments, a "require same entry" toggle producing one `mapRecordJoint`
15
+ * leaf), plus a `lengthSize` control for `min`/`max` (a `Map`, unlike a
16
+ * `Record`, carries its own size bounds in the schema - the same
17
+ * affordance `setSearchType.js` gets for the analogous reason), combined
18
+ * with the joint leaf via `$and`.
19
+ * @type {SearchTypeObject}
20
+ */
21
+ const mapSearchType = {
22
+ buildUI ({schemaObject, path, typeNamespace, topRoot, types, originalJSON}) {
23
+ const label = buildPathLabel(schemaObject, path);
24
+ const name = `${typeNamespace}-map`;
25
+ const mapSchemaObject = /** @type {import('zodexy').SzMap<any, any>} */ (
26
+ schemaObject
27
+ );
28
+ const keyPath = `${path}/*key`;
29
+ const valuePath = `${path}/*value`;
30
+ const keyArr = buildSearchWidget({
31
+ schemaObject: mapSchemaObject.key,
32
+ path: keyPath,
33
+ typeNamespace,
34
+ topRoot,
35
+ types,
36
+ originalJSON
37
+ });
38
+ const valueArr = buildSearchWidget({
39
+ schemaObject: mapSchemaObject.value,
40
+ path: valuePath,
41
+ typeNamespace,
42
+ topRoot,
43
+ types,
44
+ originalJSON
45
+ });
46
+ return ['jsoe-search-map', {
47
+ dataset: {searchPath: path, searchKind: 'map'},
48
+ title: label,
49
+ $define: {
50
+ /** @this {HTMLElement} */
51
+ getQuery () {
52
+ const searchPath = this.dataset.searchPath ?? '';
53
+ const lengthLeaf = readLengthSizeQuery(this, searchPath);
54
+ const keyEl = findSearchElement(this, `${searchPath}/*key`);
55
+ const valueEl = findSearchElement(this, `${searchPath}/*value`);
56
+ const keyQuery = keyEl && hasGetQuery(keyEl)
57
+ ? keyEl.getQuery()
58
+ : undefined;
59
+ const valueQuery = valueEl && hasGetQuery(valueEl)
60
+ ? valueEl.getQuery()
61
+ : undefined;
62
+ const jointLeaf = keyQuery || valueQuery
63
+ ? makeMapRecordJointLeaf(searchPath, readCheckbox(this), keyQuery, valueQuery)
64
+ : undefined;
65
+ return combineAnd([lengthLeaf, jointLeaf]);
66
+ }
67
+ }
68
+ }, [
69
+ ['span', {class: 'searchLabel'}, [label]],
70
+ ...buildLengthSizeControls({
71
+ name, min: mapSchemaObject.min, max: mapSchemaObject.max, includeSparse: false
72
+ }),
73
+ ['div', {class: 'searchMapKey'}, [
74
+ ['span', ['Key matches: ']],
75
+ keyArr
76
+ ]],
77
+ ['div', {class: 'searchMapValue'}, [
78
+ ['span', ['Value matches: ']],
79
+ valueArr
80
+ ]],
81
+ buildCheckbox({name: `${name}-joint`, label: 'Require same entry'})
82
+ ]];
83
+ },
84
+ getQuery: getQueryViaElement
85
+ };
86
+
87
+ export default mapSearchType;
@@ -0,0 +1,11 @@
1
+ import {makePresenceOnlySearchType} from '../searchElementUtils.js';
2
+
3
+ /**
4
+ * `NaN`: "no variants to allow for distinct search" (README).
5
+ * @type {import('../searchDispatch.js').SearchTypeObject}
6
+ */
7
+ const nanSearchType = makePresenceOnlySearchType({
8
+ tagName: 'jsoe-search-nan'
9
+ });
10
+
11
+ export default nanSearchType;
@@ -0,0 +1,11 @@
1
+ import {makePresenceOnlySearchType} from '../searchElementUtils.js';
2
+
3
+ /**
4
+ * `null`: "no variants to allow for distinct search" (README).
5
+ * @type {import('../searchDispatch.js').SearchTypeObject}
6
+ */
7
+ const nullSearchType = makePresenceOnlySearchType({
8
+ tagName: 'jsoe-search-null'
9
+ });
10
+
11
+ export default nullSearchType;
@@ -0,0 +1,52 @@
1
+ import {buildPathLabel, buildRangeInputsPair, readRangeInputsPair, buildTriStateSelect, readTriStateSelect} from '../searchUtils.js';
2
+ import {makeRangeLeaf, makeIntegerCheckLeaf, combineAnd} from '../queryTreeBuilders.js';
3
+ import {getQueryViaElement} from '../searchElementUtils.js';
4
+
5
+ /**
6
+ * @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
7
+ */
8
+
9
+ /**
10
+ * OR Ranges/Is Not Range, Is/Is Not Integer (README).
11
+ * @type {SearchTypeObject}
12
+ */
13
+ const numberSearchType = {
14
+ buildUI ({schemaObject, path, typeNamespace}) {
15
+ const label = buildPathLabel(schemaObject, path);
16
+ const name = `${typeNamespace}-number`;
17
+ return ['jsoe-search-number', {
18
+ dataset: {searchPath: path, searchKind: 'number'},
19
+ title: label,
20
+ $define: {
21
+ /** @this {HTMLElement} */
22
+ getQuery () {
23
+ const searchPath = this.dataset.searchPath ?? '';
24
+ const {gte, lte} = readRangeInputsPair(this);
25
+ const rangeLeaf = gte === '' && lte === ''
26
+ ? undefined
27
+ : makeRangeLeaf(searchPath, 'number', {
28
+ ...(gte === '' ? {} : {$gte: Number(gte)}),
29
+ ...(lte === '' ? {} : {$lte: Number(lte)})
30
+ });
31
+ const isInteger = readTriStateSelect(this);
32
+ const integerLeaf = isInteger === undefined
33
+ ? undefined
34
+ : makeIntegerCheckLeaf(searchPath, isInteger);
35
+ return combineAnd([rangeLeaf, integerLeaf]);
36
+ }
37
+ }
38
+ }, [
39
+ ['span', {class: 'searchLabel'}, [label]],
40
+ ...buildRangeInputsPair({name}),
41
+ ['label', [
42
+ 'Integer: ',
43
+ buildTriStateSelect({
44
+ name: `${name}-integer`, trueLabel: 'Integer', falseLabel: 'Not integer'
45
+ })
46
+ ]]
47
+ ]];
48
+ },
49
+ getQuery: getQueryViaElement
50
+ };
51
+
52
+ export default numberSearchType;
@@ -0,0 +1,148 @@
1
+ import {jml} from '../../vendor-imports.js';
2
+ import {escapeJSONPointer} from '../../utils/jsonPointer.js';
3
+ import {buildPathLabel, buildHasPropertyToggle, readTriStateSelect} from '../searchUtils.js';
4
+ import {combineAnd, makeHasPropertyLeaf} from '../queryTreeBuilders.js';
5
+ import {
6
+ findSearchElement, getQueryViaElement, hasGetQuery
7
+ } from '../searchElementUtils.js';
8
+ import {buildSearchWidget} from '../searchDispatch.js';
9
+
10
+ /**
11
+ * @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
12
+ */
13
+
14
+ /**
15
+ * One added property's row: the fixed "has property" tri-state toggle
16
+ * (`buildHasPropertyToggle`) plus, immediately recursing (search plan §6
17
+ * build order: "Object / Array / Set - first types recursing into child
18
+ * schemas via `getSearchTypeObject`"), that property's own full search
19
+ * widget - so a user can combine "has property X" with "X matches Y" in
20
+ * one row rather than only being able to ask about existence.
21
+ * @param {{
22
+ * propertyName: string,
23
+ * propSchema: import('../../formats/schema.js').ZodexSchema,
24
+ * path: string,
25
+ * typeNamespace: string|undefined,
26
+ * topRoot: import('../../types.js').RootElement|undefined,
27
+ * types: import('../../types.js').default|undefined,
28
+ * originalJSON: import('../../formats/schema.js').ZodexSchema|undefined
29
+ * }} cfg
30
+ * @returns {HTMLElement}
31
+ */
32
+ function buildHasPropertyRow ({
33
+ propertyName, propSchema, path, typeNamespace, topRoot, types, originalJSON
34
+ }) {
35
+ const childPath = `${path}/${escapeJSONPointer(propertyName)}`;
36
+ const name = `${typeNamespace}-hasProperty-${propertyName}`;
37
+ const childArr = buildSearchWidget({
38
+ schemaObject: propSchema, path: childPath, typeNamespace, topRoot, types,
39
+ originalJSON
40
+ });
41
+ return /** @type {HTMLElement} */ (jml('jsoe-search-has-property', {
42
+ dataset: {searchPath: childPath, searchKind: 'hasProperty', propertyName},
43
+ $define: {
44
+ // Reads `childPath` off `this.dataset` rather than closing over the
45
+ // outer `path`/`propertyName`: `$define`'s mixin is installed once
46
+ // on the shared prototype the first time this tag is defined, so
47
+ // every later `<jsoe-search-has-property>` instance must read its
48
+ // own per-row state off `this`. `readTriStateSelect`/
49
+ // `findSearchElement` are themselves closure-free (class- and
50
+ // `dataset`-driven; see `searchUtils.js`'s `findOwnControl`), so no
51
+ // further per-instance state needs storing here.
52
+ /** @this {HTMLElement} */
53
+ getQuery () {
54
+ const searchPath = this.dataset.searchPath ?? '';
55
+ const existsCheck = readTriStateSelect(this);
56
+ const existsLeaf = existsCheck === undefined
57
+ ? undefined
58
+ : makeHasPropertyLeaf(searchPath, existsCheck);
59
+ const childEl = findSearchElement(this, searchPath);
60
+ const childLeaf = childEl && hasGetQuery(childEl)
61
+ ? childEl.getQuery()
62
+ : undefined;
63
+ return combineAnd([existsLeaf, childLeaf]);
64
+ }
65
+ }
66
+ }, [
67
+ buildHasPropertyToggle({name, propertyName}),
68
+ childArr
69
+ ]));
70
+ }
71
+
72
+ /**
73
+ * Has property &lt;property pull-down&gt; (README), additive: only
74
+ * optional properties are offered ("avoid listing required" - a required
75
+ * property is guaranteed present, so asking about its existence is
76
+ * meaningless), and picking one from the pull-down adds a row for it
77
+ * (removed from the pull-down so it can't be added twice); there is no
78
+ * remove affordance, since setting a row's toggle back to "(any)" already
79
+ * expresses "no constraint from this row" for the existence half, same as
80
+ * clearing the nested widget does for the value half.
81
+ * @type {SearchTypeObject}
82
+ */
83
+ const objectSearchType = {
84
+ buildUI ({schemaObject, path, typeNamespace, topRoot, types, originalJSON}) {
85
+ const label = buildPathLabel(schemaObject, path);
86
+ const objectSchemaObject = /** @type {import('zodexy').SzObject} */ (
87
+ schemaObject
88
+ );
89
+ const availableProperties = Object.entries(
90
+ objectSchemaObject.properties
91
+ ).filter(([, propSchema]) => propSchema.isOptional === true);
92
+
93
+ return ['jsoe-search-object', {
94
+ dataset: {searchPath: path, searchKind: 'object'},
95
+ title: label,
96
+ $define: {
97
+ /** @this {HTMLElement} */
98
+ getQuery () {
99
+ const rows = [...this.children].filter(hasGetQuery);
100
+ return combineAnd(rows.map((row) => row.getQuery()));
101
+ }
102
+ }
103
+ }, [
104
+ ['div', {class: 'searchObjectControls'}, [
105
+ ['span', {class: 'searchLabel'}, [label]],
106
+ availableProperties.length
107
+ ? ['label', [
108
+ 'Add property: ',
109
+ ['select', {class: 'addPropertySelect'}, [
110
+ ['option', {value: ''}, ['(choose a property)']],
111
+ ...availableProperties.map(([propertyName]) => (
112
+ ['option', {value: propertyName}, [propertyName]]
113
+ ))
114
+ ]]
115
+ ]]
116
+ : ['span', ['(no optional properties to search on)']],
117
+ ['button', {
118
+ type: 'button',
119
+ $on: {
120
+ click () {
121
+ const container = this.closest('jsoe-search-object');
122
+ const select = /** @type {HTMLSelectElement|null} */ (
123
+ container?.querySelector('select.addPropertySelect')
124
+ );
125
+ const propertyName = select?.value;
126
+ if (!container || !select || !propertyName) {
127
+ return;
128
+ }
129
+ const propSchema = objectSchemaObject.properties[propertyName];
130
+ const row = buildHasPropertyRow({
131
+ propertyName, propSchema, path, typeNamespace, topRoot, types,
132
+ originalJSON
133
+ });
134
+ container.append(row);
135
+ const option = select.querySelector(
136
+ `option[value="${CSS.escape(propertyName)}"]`
137
+ );
138
+ option?.remove();
139
+ }
140
+ }
141
+ }, ['Add']]
142
+ ]]
143
+ ]];
144
+ },
145
+ getQuery: getQueryViaElement
146
+ };
147
+
148
+ export default objectSearchType;
@@ -0,0 +1,61 @@
1
+ import {buildPathLabel} from '../searchUtils.js';
2
+ import {makePassThroughLeaf} from '../queryTreeBuilders.js';
3
+ import {findSearchElement, getQueryViaElement, hasGetQuery} from '../searchElementUtils.js';
4
+ import {buildSearchWidget} from '../searchDispatch.js';
5
+
6
+ /**
7
+ * @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
8
+ */
9
+
10
+ /**
11
+ * Promise, Literal, catch: pass on children (README) - a promise wraps
12
+ * exactly one value at the same conceptual path (no path segment to add,
13
+ * unlike array's `*`/record's `*key`/`*value`), so this recurses into
14
+ * `.value`'s own search widget and wraps whatever it produces in a
15
+ * `passThrough` leaf (`queryTree.js`) purely so the tree keeps visible that
16
+ * the leaf was reached through a promise, rather than returning the child's
17
+ * leaf bare. ("Literal" needs no module of its own: `getSearchSchemaType`
18
+ * already resolves a `literal` schema straight to its value's own type via
19
+ * `getSchemaType`, e.g. a literal string dispatches to `stringSearchType.js`
20
+ * unchanged).
21
+ * @type {SearchTypeObject}
22
+ */
23
+ const promiseSearchType = {
24
+ buildUI ({schemaObject, path, typeNamespace, topRoot, types, originalJSON}) {
25
+ const label = buildPathLabel(schemaObject, path);
26
+ const promiseSchemaObject = /** @type {import('zodexy').SzPromise} */ (
27
+ schemaObject
28
+ );
29
+ const childArr = buildSearchWidget({
30
+ schemaObject: promiseSchemaObject.value,
31
+ path,
32
+ typeNamespace,
33
+ topRoot,
34
+ types,
35
+ originalJSON
36
+ });
37
+ return ['jsoe-search-promise', {
38
+ dataset: {searchPath: path, searchKind: 'promise'},
39
+ title: label,
40
+ $define: {
41
+ /** @this {HTMLElement} */
42
+ getQuery () {
43
+ const searchPath = this.dataset.searchPath ?? '';
44
+ const childEl = findSearchElement(this, searchPath);
45
+ const childQuery = childEl && hasGetQuery(childEl)
46
+ ? childEl.getQuery()
47
+ : undefined;
48
+ return childQuery === undefined
49
+ ? undefined
50
+ : makePassThroughLeaf(searchPath, childQuery);
51
+ }
52
+ }
53
+ }, [
54
+ ['span', {class: 'searchLabel'}, [`${label} (resolved value)`]],
55
+ childArr
56
+ ]];
57
+ },
58
+ getQuery: getQueryViaElement
59
+ };
60
+
61
+ export default promiseSearchType;
@@ -0,0 +1,48 @@
1
+ import {buildPathLabel, buildLiteralRegexControls, readLiteralRegexQuery, buildMultiSelect, readMultiSelect} from '../searchUtils.js';
2
+ import {makeMultiSelectLeaf, combineAnd} from '../queryTreeBuilders.js';
3
+ import {getQueryViaElement} from '../searchElementUtils.js';
4
+ import regexpType from '../../fundamentalTypes/regexpType.js';
5
+
6
+ /**
7
+ * @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
8
+ */
9
+
10
+ /**
11
+ * Regexp (source): OR literal or regex search/Does Not contain search, plus
12
+ * a multiple-select search of flags (README). `regexpType.js`'s own
13
+ * `allowedFlags` list is imported as-is for the flags control (search plan
14
+ * §4 - already a plain exported property, no extraction needed).
15
+ * @type {SearchTypeObject}
16
+ */
17
+ const regexpSearchType = {
18
+ buildUI ({schemaObject, path, typeNamespace}) {
19
+ const label = buildPathLabel(schemaObject, path);
20
+ const name = `${typeNamespace}-regexp`;
21
+ return ['jsoe-search-regexp', {
22
+ dataset: {searchPath: path, searchKind: 'regexp'},
23
+ title: label,
24
+ $define: {
25
+ /** @this {HTMLElement} */
26
+ getQuery () {
27
+ const searchPath = this.dataset.searchPath ?? '';
28
+ const sourceLeaf = readLiteralRegexQuery(this, searchPath);
29
+ const selectedFlags = readMultiSelect(this);
30
+ const flagsLeaf = selectedFlags.length
31
+ ? makeMultiSelectLeaf(searchPath, {$in: selectedFlags})
32
+ : undefined;
33
+ return combineAnd([sourceLeaf, flagsLeaf]);
34
+ }
35
+ }
36
+ }, [
37
+ ['span', {class: 'searchLabel'}, [`${label} (source)`]],
38
+ buildLiteralRegexControls({name}),
39
+ ['label', [
40
+ 'Flags: ',
41
+ buildMultiSelect({name: `${name}-flags`, options: regexpType.allowedFlags})
42
+ ]]
43
+ ]];
44
+ },
45
+ getQuery: getQueryViaElement
46
+ };
47
+
48
+ export default regexpSearchType;
@@ -0,0 +1,65 @@
1
+ import {buildPathLabel, buildLengthSizeControls, readLengthSizeQuery} from '../searchUtils.js';
2
+ import {combineAnd} from '../queryTreeBuilders.js';
3
+ import {findSearchElement, getQueryViaElement, hasGetQuery} from '../searchElementUtils.js';
4
+ import {buildSearchWidget} from '../searchDispatch.js';
5
+
6
+ /**
7
+ * @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
8
+ */
9
+
10
+ /**
11
+ * Has length/size of &lt;number&gt; (README) - no sparse toggle: unlike
12
+ * `array`, a `Set` cannot have holes. Also recurses into the value schema's
13
+ * own search widget (as `arraySearchType.js` does for its element), via the
14
+ * same `*` path-segment convention (`queryTree.js`).
15
+ * @type {SearchTypeObject}
16
+ */
17
+ const setSearchType = {
18
+ buildUI ({schemaObject, path, typeNamespace, topRoot, types, originalJSON}) {
19
+ const label = buildPathLabel(schemaObject, path);
20
+ const name = `${typeNamespace}-set`;
21
+ const setSchemaObject = /** @type {import('zodexy').SzSet} */ (
22
+ schemaObject
23
+ );
24
+ const elementPath = `${path}/*`;
25
+ const elementArr = buildSearchWidget({
26
+ schemaObject: setSchemaObject.value,
27
+ path: elementPath,
28
+ typeNamespace,
29
+ topRoot,
30
+ types,
31
+ originalJSON
32
+ });
33
+ return ['jsoe-search-set', {
34
+ dataset: {searchPath: path, searchKind: 'set'},
35
+ title: label,
36
+ $define: {
37
+ /** @this {HTMLElement} */
38
+ getQuery () {
39
+ const searchPath = this.dataset.searchPath ?? '';
40
+ const lengthLeaf = readLengthSizeQuery(this, searchPath);
41
+ const elementEl = findSearchElement(this, `${searchPath}/*`);
42
+ const elementLeaf = elementEl && hasGetQuery(elementEl)
43
+ ? elementEl.getQuery()
44
+ : undefined;
45
+ return combineAnd([lengthLeaf, elementLeaf]);
46
+ }
47
+ }
48
+ }, [
49
+ ['span', {class: 'searchLabel'}, [label]],
50
+ ...buildLengthSizeControls({
51
+ name,
52
+ min: setSchemaObject.minSize,
53
+ max: setSchemaObject.maxSize,
54
+ includeSparse: false
55
+ }),
56
+ ['div', {class: 'searchSetElement'}, [
57
+ ['span', ['Element matches: ']],
58
+ elementArr
59
+ ]]
60
+ ]];
61
+ },
62
+ getQuery: getQueryViaElement
63
+ };
64
+
65
+ export default setSearchType;
@@ -0,0 +1,35 @@
1
+ import {buildPathLabel, buildLiteralRegexControls, readLiteralRegexQuery} from '../searchUtils.js';
2
+ import {getQueryViaElement} from '../searchElementUtils.js';
3
+
4
+ /**
5
+ * @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
6
+ */
7
+
8
+ /**
9
+ * OR literal or regex search/Does Not contain search (README; also covers
10
+ * `StringObject` and `templateLiteral`, aliased to this same module in
11
+ * `searchDispatch.js` since the query semantics are identical).
12
+ * @type {SearchTypeObject}
13
+ */
14
+ const stringSearchType = {
15
+ buildUI ({schemaObject, path, typeNamespace}) {
16
+ const label = buildPathLabel(schemaObject, path);
17
+ const name = `${typeNamespace}-string`;
18
+ return ['jsoe-search-string', {
19
+ dataset: {searchPath: path, searchKind: 'string'},
20
+ title: label,
21
+ $define: {
22
+ /** @this {HTMLElement} */
23
+ getQuery () {
24
+ return readLiteralRegexQuery(this, this.dataset.searchPath ?? '');
25
+ }
26
+ }
27
+ }, [
28
+ ['span', {class: 'searchLabel'}, [label]],
29
+ buildLiteralRegexControls({name})
30
+ ]];
31
+ },
32
+ getQuery: getQueryViaElement
33
+ };
34
+
35
+ export default stringSearchType;
@@ -0,0 +1,38 @@
1
+ import {buildPathLabel, buildLiteralRegexControls, readLiteralRegexQuery} from '../searchUtils.js';
2
+ import {getQueryViaElement} from '../searchElementUtils.js';
3
+
4
+ /**
5
+ * @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
6
+ */
7
+
8
+ /**
9
+ * Symbol (description): OR literal or regex search/Does Not contain search
10
+ * (README) - the same query semantics as `stringSearchType.js`'s, against
11
+ * the symbol's description rather than a string value, so it gets its own
12
+ * dedicated module/tag (matching the value-editing side's one-file-per-
13
+ * fundamental-type convention) while sharing that module's actual control
14
+ * building/reading via `searchUtils.js`.
15
+ * @type {SearchTypeObject}
16
+ */
17
+ const symbolSearchType = {
18
+ buildUI ({schemaObject, path, typeNamespace}) {
19
+ const label = buildPathLabel(schemaObject, path);
20
+ const name = `${typeNamespace}-symbol`;
21
+ return ['jsoe-search-symbol', {
22
+ dataset: {searchPath: path, searchKind: 'symbol'},
23
+ title: label,
24
+ $define: {
25
+ /** @this {HTMLElement} */
26
+ getQuery () {
27
+ return readLiteralRegexQuery(this, this.dataset.searchPath ?? '');
28
+ }
29
+ }
30
+ }, [
31
+ ['span', {class: 'searchLabel'}, [`${label} (description)`]],
32
+ buildLiteralRegexControls({name})
33
+ ]];
34
+ },
35
+ getQuery: getQueryViaElement
36
+ };
37
+
38
+ export default symbolSearchType;
@@ -0,0 +1,11 @@
1
+ import {makePresenceOnlySearchType} from '../searchElementUtils.js';
2
+
3
+ /**
4
+ * `undefined`/`void`: "no variants to allow for distinct search" (README).
5
+ * @type {import('../searchDispatch.js').SearchTypeObject}
6
+ */
7
+ const undefinedSearchType = makePresenceOnlySearchType({
8
+ tagName: 'jsoe-search-undefined'
9
+ });
10
+
11
+ export default undefinedSearchType;
@@ -0,0 +1,79 @@
1
+ import {jml} from '../vendor-imports.js';
2
+ import {getSearchTypeObject, buildSearchWidget, resolveIntersection} from './searchDispatch.js';
3
+
4
+ /**
5
+ * @typedef {{
6
+ * container: HTMLDivElement,
7
+ * $getQuery: () => import('./queryTree.js').QueryAnd,
8
+ * whenReady: Promise<void>
9
+ * }} SearchChoicesControl
10
+ */
11
+
12
+ /**
13
+ * The top-level entry point (search plan §5): builds the whole recursive
14
+ * search widget tree for `schemaContent` via `buildSearchWidget`
15
+ * (`searchDispatch.js`), starting at `path = '#/'`. Does not route through
16
+ * `getTypesForSchema` for the general case - that function flattens union
17
+ * members into one flat `Set` of leaf types for a type-choice pull-down,
18
+ * whereas search needs union branches to stay distinguishable nested
19
+ * sub-widgets for the "has type" affordance (`unionSearchType.js` et al.) -
20
+ * `getTypesForSchema` is only reused narrowly, for intersection resolution,
21
+ * inside `buildSearchWidget`/`resolveIntersection` - which run at *every*
22
+ * recursive call site (every composite module's own child recursion uses
23
+ * `buildSearchWidget` too), not just here at the root, so an intersection
24
+ * schema nested anywhere in the tree resolves the same way a top-level one
25
+ * does rather than falling through to the `noneditableSearchType` escape
26
+ * hatch.
27
+ *
28
+ * `resolveIntersection` is called here too (redundantly, but cheaply, since
29
+ * it's a no-op for anything that isn't itself an `intersection`) purely so
30
+ * `$getQuery()` below dispatches through the *same* resolved schema
31
+ * `buildSearchWidget` actually built the UI for, rather than the original
32
+ * (possibly-`intersection`) one.
33
+ *
34
+ * Mirrors `buildTypeChoices`'s (`src/typeChoices.js`) `whenReady`/
35
+ * pull-based convention rather than inventing a push/callback API:
36
+ * `$getQuery()` reads the live DOM into a `QueryAnd` on demand (`{$and:
37
+ * []}` when nothing has been entered anywhere, matching the empty-`$and`
38
+ * convention of "no constraint"), and a host that wants live updates wraps
39
+ * it in its own `container.addEventListener('input', ...)` since
40
+ * `container` is a plain `HTMLDivElement`. Every widget built so far is
41
+ * synchronous, so `whenReady` (unlike `buildTypeChoices`'s) has no deferred
42
+ * work to wait on and settles immediately - it's still returned, so a
43
+ * caller can `await` either function uniformly without checking which one
44
+ * it has.
45
+ * @param {{
46
+ * schemaContent: import('../formats/schema.js').ZodexSchema,
47
+ * typeNamespace?: string,
48
+ * topRoot?: import('../types.js').RootElement,
49
+ * types?: import('../types.js').default
50
+ * }} cfg
51
+ * @returns {SearchChoicesControl}
52
+ */
53
+ export function buildSearchChoices ({schemaContent, typeNamespace, topRoot, types}) {
54
+ // Not '#/': `getJSONPointerParts` (`src/utils/jsonPointer.js`) splits on
55
+ // '/' and drops the leading '#', so '#/' parts to `['']` (one segment
56
+ // named the empty string) rather than `[]` (the root, no segments yet)
57
+ // - every recursive module here appends `${path}/segment`, so starting
58
+ // from the bare '#' is what keeps the first level from coming out as
59
+ // '#//segment'.
60
+ const path = '#';
61
+ const arr = buildSearchWidget({
62
+ schemaObject: schemaContent, path, typeNamespace, topRoot, types,
63
+ originalJSON: schemaContent
64
+ });
65
+ const container = /** @type {HTMLDivElement} */ (
66
+ jml('div', {class: 'searchChoicesContainer'}, [arr])
67
+ );
68
+ const schemaObject = resolveIntersection(schemaContent, schemaContent);
69
+ return {
70
+ container,
71
+ $getQuery () {
72
+ const result = getSearchTypeObject(schemaObject).getQuery({
73
+ root: container, path
74
+ });
75
+ return {$and: result === undefined ? [] : [result]};
76
+ },
77
+ whenReady: Promise.resolve()
78
+ };
79
+ }