@es-joy/jsoe 0.28.1 → 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.
- package/CHANGES.md +23 -0
- package/README.md +2 -0
- package/badges/coverage-badge.svg +1 -1
- package/badges/tests-badge.svg +1 -1
- package/dist/deepEqual.d.ts +3 -0
- package/dist/deepEqual.d.ts.map +1 -0
- package/dist/formatAndTypeChoices.d.ts +6 -6
- package/dist/formatAndTypeChoices.d.ts.map +1 -1
- package/dist/formats/schema.d.ts +5 -0
- package/dist/formats/schema.d.ts.map +1 -1
- package/dist/formats.d.ts +2 -2
- package/dist/formats.d.ts.map +1 -1
- package/dist/fundamentalTypes/dateType.d.ts +21 -2
- package/dist/fundamentalTypes/dateType.d.ts.map +1 -1
- package/dist/fundamentalTypes/domexceptionType.d.ts +7 -0
- package/dist/fundamentalTypes/domexceptionType.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/jtltExtensions.d.ts +112 -0
- package/dist/jtltExtensions.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/arraySearchType.d.ts +15 -0
- package/dist/search/fundamentalTypes/arraySearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/bigintSearchType.d.ts +10 -0
- package/dist/search/fundamentalTypes/bigintSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/blobSearchType.d.ts +19 -0
- package/dist/search/fundamentalTypes/blobSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/booleanSearchType.d.ts +11 -0
- package/dist/search/fundamentalTypes/booleanSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/catchSearchType.d.ts +18 -0
- package/dist/search/fundamentalTypes/catchSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/dateSearchType.d.ts +10 -0
- package/dist/search/fundamentalTypes/dateSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/domexceptionSearchType.d.ts +16 -0
- package/dist/search/fundamentalTypes/domexceptionSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/enumSearchType.d.ts +22 -0
- package/dist/search/fundamentalTypes/enumSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/errorSearchType.d.ts +9 -0
- package/dist/search/fundamentalTypes/errorSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/fileSearchType.d.ts +19 -0
- package/dist/search/fundamentalTypes/fileSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/filelistSearchType.d.ts +32 -0
- package/dist/search/fundamentalTypes/filelistSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/functionSearchType.d.ts +18 -0
- package/dist/search/fundamentalTypes/functionSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/mapSearchType.d.ts +18 -0
- package/dist/search/fundamentalTypes/mapSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/nanSearchType.d.ts +7 -0
- package/dist/search/fundamentalTypes/nanSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/nullSearchType.d.ts +7 -0
- package/dist/search/fundamentalTypes/nullSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/numberSearchType.d.ts +11 -0
- package/dist/search/fundamentalTypes/numberSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/objectSearchType.d.ts +15 -0
- package/dist/search/fundamentalTypes/objectSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/promiseSearchType.d.ts +20 -0
- package/dist/search/fundamentalTypes/promiseSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/regexpSearchType.d.ts +14 -0
- package/dist/search/fundamentalTypes/regexpSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/setSearchType.d.ts +14 -0
- package/dist/search/fundamentalTypes/setSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/stringSearchType.d.ts +13 -0
- package/dist/search/fundamentalTypes/stringSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/symbolSearchType.d.ts +16 -0
- package/dist/search/fundamentalTypes/symbolSearchType.d.ts.map +1 -0
- package/dist/search/fundamentalTypes/undefinedSearchType.d.ts +7 -0
- package/dist/search/fundamentalTypes/undefinedSearchType.d.ts.map +1 -0
- package/dist/search/index.d.ts +60 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/queryTree.d.ts +180 -0
- package/dist/search/queryTree.d.ts.map +1 -0
- package/dist/search/queryTreeBuilders.d.ts +168 -0
- package/dist/search/queryTreeBuilders.d.ts.map +1 -0
- package/dist/search/searchDispatch.d.ts +121 -0
- package/dist/search/searchDispatch.d.ts.map +1 -0
- package/dist/search/searchElementUtils.d.ts +97 -0
- package/dist/search/searchElementUtils.d.ts.map +1 -0
- package/dist/search/searchUtils.d.ts +225 -0
- package/dist/search/searchUtils.d.ts.map +1 -0
- package/dist/search/subTypes/blobHTMLSearchType.d.ts +16 -0
- package/dist/search/subTypes/blobHTMLSearchType.d.ts.map +1 -0
- package/dist/search/subTypes/recordSearchType.d.ts +18 -0
- package/dist/search/subTypes/recordSearchType.d.ts.map +1 -0
- package/dist/search/subTypes/tupleSearchType.d.ts +21 -0
- package/dist/search/subTypes/tupleSearchType.d.ts.map +1 -0
- package/dist/search/superTypes/SpecialRealNumberSearchType.d.ts +14 -0
- package/dist/search/superTypes/SpecialRealNumberSearchType.d.ts.map +1 -0
- package/dist/search/superTypes/buffersourceSearchType.d.ts +17 -0
- package/dist/search/superTypes/buffersourceSearchType.d.ts.map +1 -0
- package/dist/search/superTypes/dommatrixSearchType.d.ts +11 -0
- package/dist/search/superTypes/dommatrixSearchType.d.ts.map +1 -0
- package/dist/search/superTypes/dompointSearchType.d.ts +9 -0
- package/dist/search/superTypes/dompointSearchType.d.ts.map +1 -0
- package/dist/search/superTypes/domrectSearchType.d.ts +9 -0
- package/dist/search/superTypes/domrectSearchType.d.ts.map +1 -0
- package/dist/search/superTypes/errorsSpecialSearchType.d.ts +11 -0
- package/dist/search/superTypes/errorsSpecialSearchType.d.ts.map +1 -0
- package/dist/search/unions/discriminatedUnionSearchType.d.ts +12 -0
- package/dist/search/unions/discriminatedUnionSearchType.d.ts.map +1 -0
- package/dist/search/unions/unionFamilySearchType.d.ts +36 -0
- package/dist/search/unions/unionFamilySearchType.d.ts.map +1 -0
- package/dist/search/unions/unionSearchType.d.ts +8 -0
- package/dist/search/unions/unionSearchType.d.ts.map +1 -0
- package/dist/search/unions/xorSearchType.d.ts +12 -0
- package/dist/search/unions/xorSearchType.d.ts.map +1 -0
- package/dist/superTypes/buffersourceType.d.ts.map +1 -1
- package/dist/typeChoices.d.ts +3 -3
- package/dist/typeChoices.d.ts.map +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/rawTypesonEditor.d.ts.map +1 -1
- package/docs/proposals/search-plan.md +166 -0
- package/package.json +5 -4
- package/pnpm-workspace.yaml +1 -1
- package/rollup.config.js +12 -0
- package/src/formatAndTypeChoices.js +4 -4
- package/src/formats/schema.js +2 -1
- package/src/formats.js +1 -1
- package/src/fundamentalTypes/dateType.js +35 -14
- package/src/fundamentalTypes/domexceptionType.js +41 -33
- package/src/index.js +6 -0
- package/src/jtltExtensions.js +103 -0
- package/src/search/fundamentalTypes/arraySearchType.js +66 -0
- package/src/search/fundamentalTypes/bigintSearchType.js +62 -0
- package/src/search/fundamentalTypes/blobSearchType.js +41 -0
- package/src/search/fundamentalTypes/booleanSearchType.js +40 -0
- package/src/search/fundamentalTypes/catchSearchType.js +59 -0
- package/src/search/fundamentalTypes/dateSearchType.js +73 -0
- package/src/search/fundamentalTypes/domexceptionSearchType.js +55 -0
- package/src/search/fundamentalTypes/enumSearchType.js +58 -0
- package/src/search/fundamentalTypes/errorSearchType.js +11 -0
- package/src/search/fundamentalTypes/fileSearchType.js +41 -0
- package/src/search/fundamentalTypes/filelistSearchType.js +78 -0
- package/src/search/fundamentalTypes/functionSearchType.js +78 -0
- package/src/search/fundamentalTypes/mapSearchType.js +87 -0
- package/src/search/fundamentalTypes/nanSearchType.js +11 -0
- package/src/search/fundamentalTypes/nullSearchType.js +11 -0
- package/src/search/fundamentalTypes/numberSearchType.js +52 -0
- package/src/search/fundamentalTypes/objectSearchType.js +148 -0
- package/src/search/fundamentalTypes/promiseSearchType.js +61 -0
- package/src/search/fundamentalTypes/regexpSearchType.js +48 -0
- package/src/search/fundamentalTypes/setSearchType.js +65 -0
- package/src/search/fundamentalTypes/stringSearchType.js +35 -0
- package/src/search/fundamentalTypes/symbolSearchType.js +38 -0
- package/src/search/fundamentalTypes/undefinedSearchType.js +11 -0
- package/src/search/index.js +79 -0
- package/src/search/queryTree.js +235 -0
- package/src/search/queryTreeBuilders.js +224 -0
- package/src/search/searchDispatch.js +291 -0
- package/src/search/searchElementUtils.js +289 -0
- package/src/search/searchUtils.js +355 -0
- package/src/search/subTypes/blobHTMLSearchType.js +65 -0
- package/src/search/subTypes/recordSearchType.js +84 -0
- package/src/search/subTypes/tupleSearchType.js +111 -0
- package/src/search/superTypes/SpecialRealNumberSearchType.js +42 -0
- package/src/search/superTypes/buffersourceSearchType.js +47 -0
- package/src/search/superTypes/dommatrixSearchType.js +24 -0
- package/src/search/superTypes/dompointSearchType.js +15 -0
- package/src/search/superTypes/domrectSearchType.js +15 -0
- package/src/search/superTypes/errorsSpecialSearchType.js +15 -0
- package/src/search/unions/discriminatedUnionSearchType.js +16 -0
- package/src/search/unions/unionFamilySearchType.js +160 -0
- package/src/search/unions/unionSearchType.js +12 -0
- package/src/search/unions/xorSearchType.js +16 -0
- package/src/superTypes/buffersourceType.js +13 -15
- package/src/typeChoices.js +2 -2
- package/src/types.js +2 -2
- package/src/utils/rawTypesonEditor.js +12 -2
- package/tsconfig-prod.json +12 -0
- package/tsconfig.json +5 -10
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import {getSchemaType, getTypesForSchema} from '../formats/schema.js';
|
|
2
|
+
|
|
3
|
+
import dateSearchType from './fundamentalTypes/dateSearchType.js';
|
|
4
|
+
import numberSearchType from './fundamentalTypes/numberSearchType.js';
|
|
5
|
+
import bigintSearchType from './fundamentalTypes/bigintSearchType.js';
|
|
6
|
+
import stringSearchType from './fundamentalTypes/stringSearchType.js';
|
|
7
|
+
import regexpSearchType from './fundamentalTypes/regexpSearchType.js';
|
|
8
|
+
import booleanSearchType from './fundamentalTypes/booleanSearchType.js';
|
|
9
|
+
import symbolSearchType from './fundamentalTypes/symbolSearchType.js';
|
|
10
|
+
import undefinedSearchType from './fundamentalTypes/undefinedSearchType.js';
|
|
11
|
+
import nullSearchType from './fundamentalTypes/nullSearchType.js';
|
|
12
|
+
import nanSearchType from './fundamentalTypes/nanSearchType.js';
|
|
13
|
+
import enumSearchType from './fundamentalTypes/enumSearchType.js';
|
|
14
|
+
import arraySearchType from './fundamentalTypes/arraySearchType.js';
|
|
15
|
+
import setSearchType from './fundamentalTypes/setSearchType.js';
|
|
16
|
+
import objectSearchType from './fundamentalTypes/objectSearchType.js';
|
|
17
|
+
import filelistSearchType from './fundamentalTypes/filelistSearchType.js';
|
|
18
|
+
import tupleSearchType from './subTypes/tupleSearchType.js';
|
|
19
|
+
import recordSearchType from './subTypes/recordSearchType.js';
|
|
20
|
+
import mapSearchType from './fundamentalTypes/mapSearchType.js';
|
|
21
|
+
import promiseSearchType from './fundamentalTypes/promiseSearchType.js';
|
|
22
|
+
import catchSearchType from './fundamentalTypes/catchSearchType.js';
|
|
23
|
+
import functionSearchType from './fundamentalTypes/functionSearchType.js';
|
|
24
|
+
import fileSearchType from './fundamentalTypes/fileSearchType.js';
|
|
25
|
+
import blobSearchType from './fundamentalTypes/blobSearchType.js';
|
|
26
|
+
import unionSearchType from './unions/unionSearchType.js';
|
|
27
|
+
import xorSearchType from './unions/xorSearchType.js';
|
|
28
|
+
import discriminatedUnionSearchType from './unions/discriminatedUnionSearchType.js';
|
|
29
|
+
import errorSearchType from './fundamentalTypes/errorSearchType.js';
|
|
30
|
+
import errorsSpecialSearchType from './superTypes/errorsSpecialSearchType.js';
|
|
31
|
+
import domexceptionSearchType from './fundamentalTypes/domexceptionSearchType.js';
|
|
32
|
+
import domrectSearchType from './superTypes/domrectSearchType.js';
|
|
33
|
+
import dompointSearchType from './superTypes/dompointSearchType.js';
|
|
34
|
+
import dommatrixSearchType from './superTypes/dommatrixSearchType.js';
|
|
35
|
+
import SpecialRealNumberSearchType from './superTypes/SpecialRealNumberSearchType.js';
|
|
36
|
+
import buffersourceSearchType from './superTypes/buffersourceSearchType.js';
|
|
37
|
+
import blobHTMLSearchType from './subTypes/blobHTMLSearchType.js';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @typedef {import('./queryTree.js').QueryNode} QueryNode
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The search-side analogue of `TypeObject` (`src/types.js:308-408`): two
|
|
45
|
+
* methods, `buildUI` (a `jml` array) and `getQuery` (reads the built DOM
|
|
46
|
+
* back into a `QueryNode`, or `undefined` when no constraint was entered).
|
|
47
|
+
* @typedef {{
|
|
48
|
+
* buildUI: (cfg: {
|
|
49
|
+
* schemaObject: import('../formats/schema.js').ZodexSchema,
|
|
50
|
+
* path: string,
|
|
51
|
+
* typeNamespace?: string,
|
|
52
|
+
* topRoot?: import('../types.js').RootElement,
|
|
53
|
+
* types?: import('../types.js').default,
|
|
54
|
+
* originalJSON?: import('../formats/schema.js').ZodexSchema
|
|
55
|
+
* }) => import('../types.js').JamilihArray,
|
|
56
|
+
* getQuery: (cfg: {
|
|
57
|
+
* root: HTMLElement,
|
|
58
|
+
* path: string
|
|
59
|
+
* }) => QueryNode|undefined
|
|
60
|
+
* }} SearchTypeObject
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Temporary placeholder used while a given search type's real module is
|
|
65
|
+
* still to-do (build order, `docs/proposals/search-plan.md` §6). Renders a
|
|
66
|
+
* plainly-labelled marker rather than throwing, so the full dispatch table
|
|
67
|
+
* is exercisable end-to-end before every leaf/composite is implemented.
|
|
68
|
+
* @param {string} searchSchemaType
|
|
69
|
+
* @returns {SearchTypeObject}
|
|
70
|
+
*/
|
|
71
|
+
function stubSearchType (searchSchemaType) {
|
|
72
|
+
return {
|
|
73
|
+
buildUI: () => ['span', [`TODO: ${searchSchemaType}`]],
|
|
74
|
+
getQuery: () => undefined
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Escape hatch for `instanceof`-outside-`FileList` and any schema shape not
|
|
80
|
+
* (yet) recognized: no widget is rendered for it, only this stand-in.
|
|
81
|
+
* @type {SearchTypeObject}
|
|
82
|
+
*/
|
|
83
|
+
const noneditableSearchType = stubSearchType('noneditable');
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* `Record<string, SearchTypeObject>` registry, analogous to
|
|
87
|
+
* `Types.prototype.availableTypes` (`src/types.js:473-581`). Every entry is
|
|
88
|
+
* a stub for now (build order step 1); later steps replace individual
|
|
89
|
+
* entries with their real `*SearchType.js` module, one at a time, without
|
|
90
|
+
* touching this shape.
|
|
91
|
+
*
|
|
92
|
+
* A few keys deliberately share one module reference rather than getting
|
|
93
|
+
* their own: `BooleanObject`/`NumberObject`/`StringObject`/`bigintObject`
|
|
94
|
+
* point at their primitive counterpart's module because a search leaf only
|
|
95
|
+
* cares about the query semantics (e.g. "true or false"), never about how
|
|
96
|
+
* the value-editing side constructs the boxed wrapper at runtime. Likewise
|
|
97
|
+
* `arrayNonindexKeys` mirrors `array`, `looseRecord` mirrors `record`, and
|
|
98
|
+
* `templateLiteral` mirrors `string` (README: a template literal is still
|
|
99
|
+
* fundamentally a string-shape constraint for this pass; see §3 of the
|
|
100
|
+
* search plan).
|
|
101
|
+
* @type {{[key: string]: SearchTypeObject}}
|
|
102
|
+
*/
|
|
103
|
+
const availableSearchTypes = {
|
|
104
|
+
// fundamentalTypes
|
|
105
|
+
date: dateSearchType,
|
|
106
|
+
number: numberSearchType,
|
|
107
|
+
NumberObject: numberSearchType,
|
|
108
|
+
bigint: bigintSearchType,
|
|
109
|
+
bigintObject: bigintSearchType,
|
|
110
|
+
string: stringSearchType,
|
|
111
|
+
StringObject: stringSearchType,
|
|
112
|
+
regexp: regexpSearchType,
|
|
113
|
+
boolean: booleanSearchType,
|
|
114
|
+
BooleanObject: booleanSearchType,
|
|
115
|
+
symbol: symbolSearchType,
|
|
116
|
+
undef: undefinedSearchType,
|
|
117
|
+
null: nullSearchType,
|
|
118
|
+
nan: nanSearchType,
|
|
119
|
+
array: arraySearchType,
|
|
120
|
+
arrayNonindexKeys: arraySearchType,
|
|
121
|
+
object: objectSearchType,
|
|
122
|
+
map: mapSearchType,
|
|
123
|
+
set: setSearchType,
|
|
124
|
+
filelist: filelistSearchType,
|
|
125
|
+
file: fileSearchType,
|
|
126
|
+
blob: blobSearchType,
|
|
127
|
+
error: errorSearchType,
|
|
128
|
+
domexception: domexceptionSearchType,
|
|
129
|
+
promise: promiseSearchType,
|
|
130
|
+
function: functionSearchType,
|
|
131
|
+
enum: enumSearchType,
|
|
132
|
+
|
|
133
|
+
// subTypes
|
|
134
|
+
tuple: tupleSearchType,
|
|
135
|
+
record: recordSearchType,
|
|
136
|
+
looseRecord: recordSearchType,
|
|
137
|
+
blobHTML: blobHTMLSearchType,
|
|
138
|
+
|
|
139
|
+
// superTypes
|
|
140
|
+
domrect: domrectSearchType,
|
|
141
|
+
dompoint: dompointSearchType,
|
|
142
|
+
dommatrix: dommatrixSearchType,
|
|
143
|
+
errors: errorsSpecialSearchType,
|
|
144
|
+
SpecialNumber: stubSearchType('SpecialNumber'),
|
|
145
|
+
SpecialRealNumber: SpecialRealNumberSearchType,
|
|
146
|
+
buffersource: buffersourceSearchType,
|
|
147
|
+
|
|
148
|
+
// unions
|
|
149
|
+
union: unionSearchType,
|
|
150
|
+
xor: xorSearchType,
|
|
151
|
+
discriminatedUnion: discriminatedUnionSearchType,
|
|
152
|
+
|
|
153
|
+
// string-shape alias (§3)
|
|
154
|
+
templateLiteral: stringSearchType,
|
|
155
|
+
|
|
156
|
+
// `getSchemaType` has no case for `catch` at all (unlike `promise`/
|
|
157
|
+
// `function`, already in `zodexToStructuredCloningTypeMap`), so it's
|
|
158
|
+
// added as its own extra case in `getSearchSchemaType` below
|
|
159
|
+
catch: catchSearchType,
|
|
160
|
+
|
|
161
|
+
// escape hatch, also the fallback for any unrecognized/not-yet-supported
|
|
162
|
+
// schema shape (see `getSearchTypeObject`)
|
|
163
|
+
resurrectable: noneditableSearchType
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Schema-only analogue of `getSchemaType` (`src/formats/schema.js:145-166`).
|
|
168
|
+
* Must not reimplement that function's special-casing (stringbool pipe,
|
|
169
|
+
* `codec`/filelist, `instanceof`, `literal`, `enum`, `templateLiteral`,
|
|
170
|
+
* `getCheckedType` fallback) - it calls straight through to it, and only
|
|
171
|
+
* adds the extra shape distinctions `getSchemaType`'s own
|
|
172
|
+
* `AvailableArbitraryType` output collapses (tuple, record/looseRecord,
|
|
173
|
+
* union/xor/discriminatedUnion all currently reduce to `'array'`/`'object'`/
|
|
174
|
+
* nothing, per `zodexToStructuredCloningTypeMap`,
|
|
175
|
+
* `src/formats/schema.js:30-56`).
|
|
176
|
+
*
|
|
177
|
+
* Intersection schemas are deliberately not a case here - they're resolved
|
|
178
|
+
* before dispatch, by the search-widget walker calling `getTypesForSchema`
|
|
179
|
+
* (search plan §3), reusing jsoe's existing intersection-merging machinery
|
|
180
|
+
* rather than this function reinventing it.
|
|
181
|
+
* @param {import('../formats/schema.js').ZodexSchema} schemaObject
|
|
182
|
+
* @returns {string}
|
|
183
|
+
*/
|
|
184
|
+
export function getSearchSchemaType (schemaObject) {
|
|
185
|
+
if (schemaObject.type === 'tuple') {
|
|
186
|
+
return 'tuple';
|
|
187
|
+
}
|
|
188
|
+
if (schemaObject.type === 'record' || schemaObject.type === 'looseRecord') {
|
|
189
|
+
return schemaObject.type;
|
|
190
|
+
}
|
|
191
|
+
if (['union', 'xor', 'discriminatedUnion'].includes(schemaObject.type)) {
|
|
192
|
+
return schemaObject.type;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// An `enum` control can show a multiple-select list and template literal
|
|
196
|
+
// parts might justify their own search controls, so need to detect
|
|
197
|
+
// these schema types.
|
|
198
|
+
if (['templateLiteral', 'enum'].includes(schemaObject.type)) {
|
|
199
|
+
return schemaObject.type;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// `getSchemaType` (`src/formats/schema.js`) has no `catch` case at all -
|
|
203
|
+
// its `zodexToStructuredCloningTypeMap` never mapped it, unlike
|
|
204
|
+
// `promise`/`function` - so it's added here rather than there, matching
|
|
205
|
+
// how tuple/record/union already extend the search-only shape space.
|
|
206
|
+
if (schemaObject.type === 'catch') {
|
|
207
|
+
return 'catch';
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return /** @type {string} */ (
|
|
211
|
+
getSchemaType(schemaObject)
|
|
212
|
+
); // inherits stringbool/codec/instanceof/checks handling verbatim
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* The one exported call site every recursive search widget uses (analogous
|
|
217
|
+
* to `types.getTypeObject(type)`, `src/types.js:1106-1108`, but schema-in
|
|
218
|
+
* rather than type-string-in, since there's no value to key off). Falls
|
|
219
|
+
* back to `noneditableSearchType` for any schema shape `getSearchSchemaType`
|
|
220
|
+
* reports that isn't (yet) registered, rather than throwing - the same
|
|
221
|
+
* escape hatch a bare top-level `instanceof` schema falls through to.
|
|
222
|
+
* @param {import('../formats/schema.js').ZodexSchema} schemaObject
|
|
223
|
+
* @returns {SearchTypeObject}
|
|
224
|
+
*/
|
|
225
|
+
export function getSearchTypeObject (schemaObject) {
|
|
226
|
+
const searchSchemaType = getSearchSchemaType(schemaObject);
|
|
227
|
+
return availableSearchTypes[searchSchemaType] ?? noneditableSearchType;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Intersection schemas are never registered in `availableSearchTypes` -
|
|
232
|
+
* resolved here instead of in `getSearchSchemaType`, reusing jsoe's
|
|
233
|
+
* existing intersection-merging machinery (`getTypesForSchema`,
|
|
234
|
+
* `src/formats/schema.js`) rather than reinventing it (search plan §3/§5).
|
|
235
|
+
* A single merged result replaces the intersection outright; more than one
|
|
236
|
+
* (e.g. one side of the intersection is itself a union) is handed to
|
|
237
|
+
* `unionSearchType.js` unchanged via a synthesized `union` wrapper, the
|
|
238
|
+
* same way `unionSearchType.js` already treats distinguishable branches.
|
|
239
|
+
* @param {import('../formats/schema.js').ZodexSchema} schemaObject
|
|
240
|
+
* @param {import('../formats/schema.js').ZodexSchema} originalJSON
|
|
241
|
+
* @returns {import('../formats/schema.js').ZodexSchema}
|
|
242
|
+
*/
|
|
243
|
+
function resolveIntersection (schemaObject, originalJSON) {
|
|
244
|
+
if (schemaObject.type !== 'intersection') {
|
|
245
|
+
return schemaObject;
|
|
246
|
+
}
|
|
247
|
+
const merged = [...getTypesForSchema(schemaObject, originalJSON)];
|
|
248
|
+
return merged.length === 1
|
|
249
|
+
? merged[0]
|
|
250
|
+
: /** @type {import('../formats/schema.js').ZodexSchema} */ (
|
|
251
|
+
/** @type {unknown} */ ({type: 'union', options: merged})
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* The call site every *recursive* search widget uses in place of calling
|
|
257
|
+
* `getSearchTypeObject(...).buildUI(...)` directly - it's the same thing,
|
|
258
|
+
* plus `resolveIntersection` run first, so an intersection schema at any
|
|
259
|
+
* depth (not just the one `buildSearchChoices` is called with) still
|
|
260
|
+
* resolves instead of falling through to the `noneditableSearchType`
|
|
261
|
+
* escape hatch. `originalJSON` (needed for the `getTypesForSchema` call's
|
|
262
|
+
* own `$ref` resolution) defaults to `schemaObject` itself only as a last
|
|
263
|
+
* resort for a call site that has none to pass down - every recursive
|
|
264
|
+
* caller should be threading the true document root through via its own
|
|
265
|
+
* `originalJSON` parameter instead.
|
|
266
|
+
* @param {{
|
|
267
|
+
* schemaObject: import('../formats/schema.js').ZodexSchema,
|
|
268
|
+
* path: string,
|
|
269
|
+
* typeNamespace?: string,
|
|
270
|
+
* topRoot?: import('../types.js').RootElement,
|
|
271
|
+
* types?: import('../types.js').default,
|
|
272
|
+
* originalJSON?: import('../formats/schema.js').ZodexSchema
|
|
273
|
+
* }} cfg
|
|
274
|
+
* @returns {import('../types.js').JamilihArray}
|
|
275
|
+
*/
|
|
276
|
+
export function buildSearchWidget ({
|
|
277
|
+
schemaObject, path, typeNamespace, topRoot, types, originalJSON
|
|
278
|
+
}) {
|
|
279
|
+
const resolvedOriginalJSON = originalJSON ?? schemaObject;
|
|
280
|
+
const resolvedSchema = resolveIntersection(schemaObject, resolvedOriginalJSON);
|
|
281
|
+
return getSearchTypeObject(resolvedSchema).buildUI({
|
|
282
|
+
schemaObject: resolvedSchema,
|
|
283
|
+
path,
|
|
284
|
+
typeNamespace,
|
|
285
|
+
topRoot,
|
|
286
|
+
types,
|
|
287
|
+
originalJSON: resolvedOriginalJSON
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export {availableSearchTypes, noneditableSearchType, resolveIntersection};
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, buildCheckbox, readCheckbox,
|
|
3
|
+
buildLiteralRegexControls, readLiteralRegexQuery,
|
|
4
|
+
buildRangeInputsPair, readRangeInputsPair,
|
|
5
|
+
buildTriStateSelect, readTriStateSelect
|
|
6
|
+
} from './searchUtils.js';
|
|
7
|
+
import {combineAnd, makeRangeLeaf, makeDomShapeLeaf} from './queryTreeBuilders.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Locates a built search element by the JSON-Pointer path it was built for.
|
|
11
|
+
* Compares `dataset.searchPath` in JS rather than interpolating `path` into
|
|
12
|
+
* a `querySelector` attribute-value string, since a schema path can embed
|
|
13
|
+
* arbitrary property-name characters (only `~`/`/` are escaped by
|
|
14
|
+
* `makeJSONPointer`) that would otherwise need CSS-selector escaping.
|
|
15
|
+
* @param {ParentNode} root
|
|
16
|
+
* @param {string} path
|
|
17
|
+
* @returns {HTMLElement|undefined}
|
|
18
|
+
*/
|
|
19
|
+
export function findSearchElement (root, path) {
|
|
20
|
+
return /** @type {HTMLElement[]} */ (
|
|
21
|
+
[...root.querySelectorAll('[data-search-path]')]
|
|
22
|
+
).find((el) => el.dataset.searchPath === path);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {HTMLElement & {
|
|
27
|
+
* getQuery: () => import('./queryTree.js').QueryNode|undefined
|
|
28
|
+
* }} SearchElement
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The `SearchTypeObject.getQuery` every leaf module implements identically:
|
|
33
|
+
* locate the element it built under `root` and delegate to its own
|
|
34
|
+
* (per-element, `dataset`-driven) `getQuery()` method.
|
|
35
|
+
* @param {{root: HTMLElement, path: string}} cfg
|
|
36
|
+
* @returns {import('./queryTree.js').QueryNode|undefined}
|
|
37
|
+
*/
|
|
38
|
+
export function getQueryViaElement ({root, path}) {
|
|
39
|
+
const el = /** @type {SearchElement|undefined} */ (
|
|
40
|
+
findSearchElement(root, path)
|
|
41
|
+
);
|
|
42
|
+
return el?.getQuery();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Type-predicate guard distinguishing a built search element (leaf or
|
|
47
|
+
* container, either answers to `.getQuery()`) from a plain DOM node - used
|
|
48
|
+
* by container elements (e.g. `objectSearchType.js`'s `<jsoe-search-object>`)
|
|
49
|
+
* that walk `this.children` polymorphically (search plan §8) without
|
|
50
|
+
* knowing which children are search elements and which are plain layout
|
|
51
|
+
* (a controls `<div>`, etc.).
|
|
52
|
+
* @param {Element} el
|
|
53
|
+
* @returns {el is SearchElement}
|
|
54
|
+
*/
|
|
55
|
+
export function hasGetQuery (el) {
|
|
56
|
+
return typeof (/** @type {{getQuery?: unknown}} */ (el)).getQuery ===
|
|
57
|
+
'function';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Factory for the README's "no variants to allow for distinct search"
|
|
62
|
+
* leaves (`undefined`/`void`, `null`, `NaN`): the only meaningful question
|
|
63
|
+
* is whether the path is present at all, which only matters once the path
|
|
64
|
+
* is optional or nested in a union - so all three share one tiny, single-
|
|
65
|
+
* checkbox implementation, differing only in tag name/label.
|
|
66
|
+
* @param {{tagName: string}} cfg
|
|
67
|
+
* @returns {import('./searchDispatch.js').SearchTypeObject}
|
|
68
|
+
*/
|
|
69
|
+
export function makePresenceOnlySearchType ({tagName}) {
|
|
70
|
+
return {
|
|
71
|
+
buildUI ({schemaObject, path, typeNamespace}) {
|
|
72
|
+
const label = buildPathLabel(schemaObject, path);
|
|
73
|
+
const name = `${typeNamespace}-${tagName}`;
|
|
74
|
+
return [tagName, {
|
|
75
|
+
dataset: {searchPath: path, searchKind: tagName},
|
|
76
|
+
title: label,
|
|
77
|
+
$define: {
|
|
78
|
+
/** @this {HTMLElement} */
|
|
79
|
+
getQuery () {
|
|
80
|
+
const checked = readCheckbox(this);
|
|
81
|
+
return checked
|
|
82
|
+
? {kind: 'presence', path: this.dataset.searchPath ?? '', $exists: true}
|
|
83
|
+
: undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}, [
|
|
87
|
+
['span', {class: 'searchLabel'}, [label]],
|
|
88
|
+
buildCheckbox({name, label: `Require ${label} present`})
|
|
89
|
+
]];
|
|
90
|
+
},
|
|
91
|
+
getQuery: getQueryViaElement
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The Error family's fixed known properties (`errorType.js`'s own
|
|
97
|
+
* `setValue`/`getValue` hard-code this same set - `message`/`name`/
|
|
98
|
+
* `fileName`/`stack` as strings, `lineNumber`/`columnNumber` as numbers -
|
|
99
|
+
* since a `checked`-type schema like `error`/`errors` carries no structural
|
|
100
|
+
* detail of its own to derive property names/types from, unlike `object`).
|
|
101
|
+
* @type {string[]}
|
|
102
|
+
*/
|
|
103
|
+
const errorStringProps = ['message', 'name', 'fileName', 'stack'];
|
|
104
|
+
|
|
105
|
+
/** @type {string[]} */
|
|
106
|
+
const errorNumberProps = ['lineNumber', 'columnNumber'];
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @param {{label: string, name: string}} cfg
|
|
110
|
+
* @returns {import('./searchUtils.js').JamilihArray[]}
|
|
111
|
+
*/
|
|
112
|
+
function buildErrorFamilyChildren ({label, name}) {
|
|
113
|
+
/** @type {import('./searchUtils.js').JamilihArray[]} */
|
|
114
|
+
const children = [['span', {class: 'searchLabel'}, [label]]];
|
|
115
|
+
errorStringProps.forEach((prop) => {
|
|
116
|
+
children.push(['div', {class: `errorProp-${prop}`}, [
|
|
117
|
+
['span', [`${prop}: `]],
|
|
118
|
+
buildLiteralRegexControls({name: `${name}-${prop}`, key: prop})
|
|
119
|
+
]]);
|
|
120
|
+
});
|
|
121
|
+
errorNumberProps.forEach((prop) => {
|
|
122
|
+
children.push(['div', {class: `errorProp-${prop}`}, [
|
|
123
|
+
['span', [`${prop}: `]],
|
|
124
|
+
...buildRangeInputsPair({name: `${name}-${prop}`, key: prop})
|
|
125
|
+
]]);
|
|
126
|
+
});
|
|
127
|
+
return children;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Factory for `errorSearchType.js`/`errorsSpecialSearchType.js`, offering
|
|
132
|
+
* literal/regex search of child string properties, numeric of number
|
|
133
|
+
* children (README) - one `buildLiteralRegexControls`/`buildRangeInputsPair` pair
|
|
134
|
+
* per known property (`key`-distinguished so they coexist in one widget;
|
|
135
|
+
* see those helpers' docs), combined via `$and`. `.cause` (a recursive,
|
|
136
|
+
* arbitrarily-typed property) and `errorsSpecial`'s `AggregateError.errors`
|
|
137
|
+
* array are deliberately left out of this pass - the README's bullet asks
|
|
138
|
+
* only for the flat string/number children, and open-ended recursion into
|
|
139
|
+
* an arbitrary `cause` chain is a materially bigger feature than "the same
|
|
140
|
+
* shape, twice more".
|
|
141
|
+
* @param {{tagName: string}} cfg
|
|
142
|
+
* @returns {import('./searchDispatch.js').SearchTypeObject}
|
|
143
|
+
*/
|
|
144
|
+
export function makeErrorFamilySearchType ({tagName}) {
|
|
145
|
+
return {
|
|
146
|
+
buildUI ({schemaObject, path, typeNamespace}) {
|
|
147
|
+
const label = buildPathLabel(schemaObject, path);
|
|
148
|
+
const name = `${typeNamespace}-${tagName}`;
|
|
149
|
+
return [tagName, {
|
|
150
|
+
dataset: {searchPath: path, searchKind: tagName},
|
|
151
|
+
title: label,
|
|
152
|
+
$define: {
|
|
153
|
+
/** @this {HTMLElement} */
|
|
154
|
+
getQuery () {
|
|
155
|
+
const searchPath = this.dataset.searchPath ?? '';
|
|
156
|
+
const stringLeaves = errorStringProps.map((prop) => (
|
|
157
|
+
readLiteralRegexQuery(this, `${searchPath}/${prop}`, prop)
|
|
158
|
+
));
|
|
159
|
+
const numberLeaves = errorNumberProps.map((prop) => {
|
|
160
|
+
const {gte, lte} = readRangeInputsPair(this, prop);
|
|
161
|
+
if (gte === '' && lte === '') {
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
return makeRangeLeaf(`${searchPath}/${prop}`, 'number', {
|
|
165
|
+
...(gte === '' ? {} : {$gte: Number(gte)}),
|
|
166
|
+
...(lte === '' ? {} : {$lte: Number(lte)})
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
return combineAnd([...stringLeaves, ...numberLeaves]);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}, buildErrorFamilyChildren({label, name})];
|
|
173
|
+
},
|
|
174
|
+
getQuery: getQueryViaElement
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* @param {{
|
|
180
|
+
* label: string, name: string, dimensionKeys: string[],
|
|
181
|
+
* includeReadonly: boolean, includeDimensionCheck: boolean
|
|
182
|
+
* }} cfg
|
|
183
|
+
* @returns {import('./searchUtils.js').JamilihArray[]}
|
|
184
|
+
*/
|
|
185
|
+
function buildDomShapeChildren ({
|
|
186
|
+
label, name, dimensionKeys, includeReadonly, includeDimensionCheck
|
|
187
|
+
}) {
|
|
188
|
+
/** @type {import('./searchUtils.js').JamilihArray[]} */
|
|
189
|
+
const children = [['span', {class: 'searchLabel'}, [label]]];
|
|
190
|
+
dimensionKeys.forEach((dim) => {
|
|
191
|
+
children.push(['div', {class: `domShapeDimension-${dim}`}, [
|
|
192
|
+
['span', [`${dim}: `]],
|
|
193
|
+
...buildRangeInputsPair({name: `${name}-${dim}`, key: dim})
|
|
194
|
+
]]);
|
|
195
|
+
});
|
|
196
|
+
if (includeReadonly) {
|
|
197
|
+
children.push(['label', [
|
|
198
|
+
'Readonly: ',
|
|
199
|
+
buildTriStateSelect({
|
|
200
|
+
name: `${name}-readonly`, key: 'readonly',
|
|
201
|
+
trueLabel: 'Readonly', falseLabel: 'Not readonly'
|
|
202
|
+
})
|
|
203
|
+
]]);
|
|
204
|
+
}
|
|
205
|
+
if (includeDimensionCheck) {
|
|
206
|
+
children.push(['label', [
|
|
207
|
+
'3d: ',
|
|
208
|
+
buildTriStateSelect({
|
|
209
|
+
name: `${name}-dimension`, key: 'dimension',
|
|
210
|
+
trueLabel: '3d', falseLabel: 'Not 3d'
|
|
211
|
+
})
|
|
212
|
+
]]);
|
|
213
|
+
}
|
|
214
|
+
return children;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Factory for `domrectSearchType.js`/`dompointSearchType.js`/
|
|
219
|
+
* `dommatrixSearchType.js`: numeric search ranges for children; "Is/Is not
|
|
220
|
+
* Readonly"; DOMMatrix: "Is/Is not 3d" (README) - one `buildRangeInputsPair`
|
|
221
|
+
* per known dimension (`key`-distinguished so they coexist in one widget;
|
|
222
|
+
* `dimensionKeys` covers DOMMatrix's 2D (`a`-`f`) *and* 3D (`m11`-`m44`)
|
|
223
|
+
* shapes at once rather than switching the control set on an "Is/Is not 3d"
|
|
224
|
+
* answer that's itself just another optional search constraint, not a
|
|
225
|
+
* schema fact - `domrect`/`dompoint`/`dommatrix` are all "checked" types
|
|
226
|
+
* with no structural schema to derive dimension names from in the first
|
|
227
|
+
* place, same reasoning as `makeErrorFamilySearchType`), combined into one
|
|
228
|
+
* `domShape` leaf (`queryTree.js`) rather than separate leaves via `$and`.
|
|
229
|
+
* @param {{
|
|
230
|
+
* tagName: string,
|
|
231
|
+
* dimensionKeys: string[],
|
|
232
|
+
* includeReadonly?: boolean,
|
|
233
|
+
* includeDimensionCheck?: boolean
|
|
234
|
+
* }} cfg
|
|
235
|
+
* @returns {import('./searchDispatch.js').SearchTypeObject}
|
|
236
|
+
*/
|
|
237
|
+
export function makeDomShapeSearchType ({
|
|
238
|
+
tagName, dimensionKeys, includeReadonly = false, includeDimensionCheck = false
|
|
239
|
+
}) {
|
|
240
|
+
return {
|
|
241
|
+
buildUI ({schemaObject, path, typeNamespace}) {
|
|
242
|
+
const label = buildPathLabel(schemaObject, path);
|
|
243
|
+
const name = `${typeNamespace}-${tagName}`;
|
|
244
|
+
return [tagName, {
|
|
245
|
+
dataset: {searchPath: path, searchKind: tagName},
|
|
246
|
+
title: label,
|
|
247
|
+
$define: {
|
|
248
|
+
/** @this {HTMLElement} */
|
|
249
|
+
getQuery () {
|
|
250
|
+
const searchPath = this.dataset.searchPath ?? '';
|
|
251
|
+
/** @type {{[dim: string]: import('./queryTree.js').QueryRangeLeaf}} */
|
|
252
|
+
const dimensions = {};
|
|
253
|
+
dimensionKeys.forEach((dim) => {
|
|
254
|
+
const {gte, lte} = readRangeInputsPair(this, dim);
|
|
255
|
+
if (gte === '' && lte === '') {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
dimensions[dim] = makeRangeLeaf(`${searchPath}/${dim}`, 'number', {
|
|
259
|
+
...(gte === '' ? {} : {$gte: Number(gte)}),
|
|
260
|
+
...(lte === '' ? {} : {$lte: Number(lte)})
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
const readonlyCheck = includeReadonly
|
|
264
|
+
? readTriStateSelect(this, 'readonly')
|
|
265
|
+
: undefined;
|
|
266
|
+
const dimensionCheck = includeDimensionCheck
|
|
267
|
+
? readTriStateSelect(this, 'dimension')
|
|
268
|
+
: undefined;
|
|
269
|
+
if (
|
|
270
|
+
readonlyCheck === undefined && dimensionCheck === undefined &&
|
|
271
|
+
Object.keys(dimensions).length === 0
|
|
272
|
+
) {
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
return makeDomShapeLeaf(searchPath, dimensions, {
|
|
276
|
+
...(readonlyCheck === undefined ? {} : {readonlyCheck}),
|
|
277
|
+
...(dimensionCheck === undefined
|
|
278
|
+
? {}
|
|
279
|
+
: {dimensionCheck: dimensionCheck ? 3 : 2})
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}, buildDomShapeChildren({
|
|
284
|
+
label, name, dimensionKeys, includeReadonly, includeDimensionCheck
|
|
285
|
+
})];
|
|
286
|
+
},
|
|
287
|
+
getQuery: getQueryViaElement
|
|
288
|
+
};
|
|
289
|
+
}
|