@json-layout/vocabulary 0.1.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/LICENSE +21 -0
- package/package.json +54 -0
- package/src/index.js +4 -0
- package/src/layout-keyword/index.js +62 -0
- package/src/layout-keyword/schema.js +367 -0
- package/src/layout-keyword/schema.json +209 -0
- package/src/layout-keyword/types.ts +109 -0
- package/src/layout-keyword/validate.js +2 -0
- package/src/normalize.js +313 -0
- package/src/normalized-layout/index.js +105 -0
- package/src/normalized-layout/schema.js +824 -0
- package/src/normalized-layout/schema.json +413 -0
- package/src/normalized-layout/types.ts +243 -0
- package/src/normalized-layout/validate.js +3 -0
- package/src/types.ts +19 -0
- package/types/index.d.ts +5 -0
- package/types/index.d.ts.map +1 -0
- package/types/layout-keyword/index.d.ts +42 -0
- package/types/layout-keyword/index.d.ts.map +1 -0
- package/types/layout-keyword/schema.d.ts +279 -0
- package/types/layout-keyword/schema.d.ts.map +1 -0
- package/types/layout-keyword/types.d.ts +90 -0
- package/types/layout-keyword/types.d.ts.map +1 -0
- package/types/layout-keyword/validate.d.ts +24 -0
- package/types/layout-keyword/validate.d.ts.map +1 -0
- package/types/normalize.d.ts +18 -0
- package/types/normalize.d.ts.map +1 -0
- package/types/normalized-layout/index.d.ts +96 -0
- package/types/normalized-layout/index.d.ts.map +1 -0
- package/types/normalized-layout/schema.d.ts +626 -0
- package/types/normalized-layout/schema.d.ts.map +1 -0
- package/types/normalized-layout/types.d.ts +221 -0
- package/types/normalized-layout/types.d.ts.map +1 -0
- package/types/normalized-layout/validate.d.ts +23 -0
- package/types/normalized-layout/validate.d.ts.map +1 -0
- package/types/types.d.ts +19 -0
- package/types/types.d.ts.map +1 -0
package/src/normalize.js
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { validateLayoutKeyword, isComponentName, isPartialCompObject, isPartialChildren, isPartialSwitch, isPartialGetItemsExpr, isPartialGetItemsObj, isPartialSlotMarkdown, isPartialGetItemsFetch } from './layout-keyword/index.js'
|
|
2
|
+
import { validateNormalizedLayout, normalizedLayoutSchema, isSectionLayout, isCompositeLayout } from './index.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {import('./index.js').Child} Child
|
|
6
|
+
* @typedef {import('./index.js').Children} Children
|
|
7
|
+
* @typedef {import('./index.js').CompObject} CompObject
|
|
8
|
+
* @typedef {import('./index.js').Expression} Expression
|
|
9
|
+
* @typedef {import('./index.js').NormalizedLayout} NormalizedLayout
|
|
10
|
+
* @typedef {import('./index.js').LayoutKeyword} LayoutKeyword
|
|
11
|
+
* @typedef {import('./index.js').PartialChildren} PartialChildren
|
|
12
|
+
* @typedef {import('./index.js').PartialCompObject} PartialCompObject
|
|
13
|
+
* @typedef {import("./types.js").SchemaFragment} SchemaFragment
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// export type Markdown = (src: string) => string
|
|
17
|
+
|
|
18
|
+
// this navice implementation is sufficient here, not used very often
|
|
19
|
+
const clone = (/** @type {any} */ obj) => JSON.parse(JSON.stringify(obj))
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {import('./types.js').SchemaFragment} schemaFragment
|
|
23
|
+
* @returns {Children}
|
|
24
|
+
*/
|
|
25
|
+
function getDefaultChildren (schemaFragment) {
|
|
26
|
+
/** @type {Children} */
|
|
27
|
+
const children = []
|
|
28
|
+
if (schemaFragment.type === 'object') {
|
|
29
|
+
if (schemaFragment.properties) {
|
|
30
|
+
for (const key of Object.keys(schemaFragment.properties)) {
|
|
31
|
+
children.push({ key })
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (schemaFragment.allOf?.length) {
|
|
35
|
+
for (let i = 0; i < schemaFragment.allOf.length; i++) {
|
|
36
|
+
children.push({ key: `$allOf-${i}` })
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (schemaFragment.oneOf) {
|
|
40
|
+
children.push({ key: '$oneOf' })
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (schemaFragment.type === 'array' && Array.isArray(schemaFragment.items)) {
|
|
44
|
+
for (let i = 0; i < schemaFragment.items.length; i++) {
|
|
45
|
+
children.push({ key: i })
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return children
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @param {Children} defaultChildren
|
|
53
|
+
* @param {PartialChildren} [partialChildren]
|
|
54
|
+
* @returns {Children}
|
|
55
|
+
*/
|
|
56
|
+
function getChildren (defaultChildren, partialChildren) {
|
|
57
|
+
if (!partialChildren) return defaultChildren
|
|
58
|
+
let compI = 0
|
|
59
|
+
return partialChildren.map(partialChild => {
|
|
60
|
+
if (typeof partialChild === 'string') { // simple string/key referencing a known child
|
|
61
|
+
const matchingDefaultChild = defaultChildren.find(c => c.key === partialChild)
|
|
62
|
+
if (!matchingDefaultChild) throw new Error(`child unknown ${partialChild}`)
|
|
63
|
+
return matchingDefaultChild
|
|
64
|
+
} else {
|
|
65
|
+
if (typeof partialChild.cols === 'number') partialChild.cols = { sm: partialChild.cols }
|
|
66
|
+
if (typeof partialChild.cols === 'object' && partialChild.cols.xs === undefined) partialChild.cols.xs = 12
|
|
67
|
+
if (partialChild.key) { // object referencing known child and overwriting cols
|
|
68
|
+
const matchingDefaultChild = defaultChildren.find(c => c.key === partialChild.key)
|
|
69
|
+
if (!matchingDefaultChild) throw new Error(`child unknown ${partialChild.key}`)
|
|
70
|
+
return /** @type {Child} */ (partialChild)
|
|
71
|
+
} else { // a composite component definition, not directly related to a known child
|
|
72
|
+
const child = partialChild
|
|
73
|
+
if (partialChild.children) {
|
|
74
|
+
if (!partialChild.comp) child.comp = 'section'
|
|
75
|
+
child.children = getChildren(defaultChildren, partialChild.children)
|
|
76
|
+
}
|
|
77
|
+
if (!('key' in partialChild)) {
|
|
78
|
+
child.key = `$comp-${compI}`
|
|
79
|
+
compI++
|
|
80
|
+
}
|
|
81
|
+
return /** @type {Child} */ (child)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @param {SchemaFragment} schemaFragment
|
|
89
|
+
* @param {string} schemaPath
|
|
90
|
+
* @returns {import('./index.js').CompObject}
|
|
91
|
+
*/
|
|
92
|
+
function getDefaultCompObject (schemaFragment, schemaPath) {
|
|
93
|
+
const key = schemaPath.slice(schemaPath.lastIndexOf('/') + 1)
|
|
94
|
+
if ('const' in schemaFragment) return { comp: 'none' }
|
|
95
|
+
if (!schemaFragment.type) return { comp: 'none' }
|
|
96
|
+
if (schemaFragment.type === 'object') {
|
|
97
|
+
return { comp: 'section', title: schemaFragment.title ?? null, children: getDefaultChildren(schemaFragment) }
|
|
98
|
+
}
|
|
99
|
+
if (schemaFragment.type === 'array') {
|
|
100
|
+
if (!schemaFragment.items) return { comp: 'none' }
|
|
101
|
+
if (Array.isArray(schemaFragment.items)) {
|
|
102
|
+
return { comp: 'section', title: schemaFragment.title ?? null, children: getDefaultChildren(schemaFragment) } // tuples
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
comp: 'list',
|
|
106
|
+
title: schemaFragment.title ?? key,
|
|
107
|
+
listEditMode: schemaFragment.items.type === 'object' ? 'inline-single' : 'inline',
|
|
108
|
+
listActions: ['add', 'edit', 'delete', 'duplicate', 'sort']
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const hasSimpleType = ['string', 'integer', 'number'].includes(schemaFragment.type)
|
|
112
|
+
if (schemaFragment.enum && hasSimpleType) {
|
|
113
|
+
return {
|
|
114
|
+
comp: 'select',
|
|
115
|
+
label: schemaFragment.title ?? key,
|
|
116
|
+
items: schemaFragment.enum.map((/** @type {string} */ value) => ({ key: value + '', title: value + '', value }))
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (schemaFragment.oneOf && !(schemaFragment.oneOf.find((/** @type {any} */ oneOfItem) => !('const' in oneOfItem))) && hasSimpleType) {
|
|
120
|
+
return {
|
|
121
|
+
comp: 'select',
|
|
122
|
+
label: schemaFragment.title ?? key,
|
|
123
|
+
items: schemaFragment.oneOf.map((/** @type {{ const: string; title: any; }} */ oneOfItem) => ({ key: oneOfItem.const + '', title: (oneOfItem.title ?? oneOfItem.const) + '', value: oneOfItem.const }))
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (schemaFragment.type === 'string') {
|
|
127
|
+
if (schemaFragment.format) {
|
|
128
|
+
/** @type {CompObject | null} */
|
|
129
|
+
let formatCompObject = null
|
|
130
|
+
if (schemaFragment.format === 'date') formatCompObject = { comp: 'date-picker', label: schemaFragment.title ?? key, format: 'date' }
|
|
131
|
+
if (schemaFragment.format === 'date-time') formatCompObject = { comp: 'date-time-picker', label: schemaFragment.title ?? key }
|
|
132
|
+
if (schemaFragment.format === 'time') formatCompObject = { comp: 'time-picker', label: schemaFragment.title ?? key }
|
|
133
|
+
if (formatCompObject) {
|
|
134
|
+
if ('formatMinimum' in schemaFragment) formatCompObject.min = schemaFragment.formatMinimum
|
|
135
|
+
if ('formatMaximum' in schemaFragment) formatCompObject.max = schemaFragment.formatMaximum
|
|
136
|
+
return formatCompObject
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return { comp: 'text-field', label: schemaFragment.title ?? key }
|
|
140
|
+
}
|
|
141
|
+
if (schemaFragment.type === 'integer' || schemaFragment.type === 'number') {
|
|
142
|
+
/** @type {import('./index.js').NumberField} */
|
|
143
|
+
const compObject = { comp: 'number-field', label: schemaFragment.title ?? key }
|
|
144
|
+
if (schemaFragment.type === 'integer') compObject.step = 1
|
|
145
|
+
if ('minimum' in schemaFragment) compObject.min = schemaFragment.minimum
|
|
146
|
+
if ('maximum' in schemaFragment) compObject.max = schemaFragment.maximum
|
|
147
|
+
return compObject
|
|
148
|
+
}
|
|
149
|
+
if (schemaFragment.type === 'boolean') return { comp: 'checkbox', label: schemaFragment.title ?? key }
|
|
150
|
+
console.warn(`failed to calculate default layout for schema ${schemaPath}`, schemaFragment)
|
|
151
|
+
return { comp: 'none' }
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* @param {LayoutKeyword} layoutKeyword
|
|
156
|
+
* @returns {PartialCompObject | null}
|
|
157
|
+
*/
|
|
158
|
+
function getPartialCompObject (layoutKeyword) {
|
|
159
|
+
if (isPartialCompObject(layoutKeyword)) return { ...layoutKeyword }
|
|
160
|
+
else if (isComponentName(layoutKeyword)) return { comp: layoutKeyword }
|
|
161
|
+
else if (isPartialChildren(layoutKeyword)) return { children: layoutKeyword }
|
|
162
|
+
return null
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* @param {import("./index.js").PartialExpression} expression
|
|
167
|
+
* @param {Expression['type']} defaultType
|
|
168
|
+
* @returns {Expression}
|
|
169
|
+
*/
|
|
170
|
+
function normalizeExpression (expression, defaultType = 'js-eval') {
|
|
171
|
+
if (typeof expression === 'string') return { type: defaultType, expr: expression }
|
|
172
|
+
else return { ...expression, type: expression.type ?? defaultType }
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* @param {LayoutKeyword} layoutKeyword
|
|
177
|
+
* @param {CompObject} defaultCompObject
|
|
178
|
+
* @param {SchemaFragment} schemaFragment
|
|
179
|
+
* @param {(text: string) => string} markdown
|
|
180
|
+
* @returns {CompObject}
|
|
181
|
+
*/
|
|
182
|
+
function getCompObject (layoutKeyword, defaultCompObject, schemaFragment, markdown) {
|
|
183
|
+
const partial = getPartialCompObject(layoutKeyword)
|
|
184
|
+
if (!partial) return defaultCompObject
|
|
185
|
+
|
|
186
|
+
if (partial.if) partial.if = normalizeExpression(partial.if)
|
|
187
|
+
if (partial.getItems && isPartialGetItemsExpr(partial.getItems)) partial.getItems = normalizeExpression(partial.getItems)
|
|
188
|
+
if (partial.getItems && isPartialGetItemsObj(partial.getItems)) {
|
|
189
|
+
if (schemaFragment.type === 'object') partial.getItems.returnObjects = true
|
|
190
|
+
if (partial.getItems.itemTitle) partial.getItems.itemTitle = normalizeExpression(partial.getItems.itemTitle)
|
|
191
|
+
if (partial.getItems.itemKey) partial.getItems.itemKey = normalizeExpression(partial.getItems.itemKey)
|
|
192
|
+
if (partial.getItems.itemValue) partial.getItems.itemValue = normalizeExpression(partial.getItems.itemValue)
|
|
193
|
+
if (partial.getItems.itemsResults) partial.getItems.itemsResults = normalizeExpression(partial.getItems.itemsResults)
|
|
194
|
+
}
|
|
195
|
+
if (partial.getItems && isPartialGetItemsFetch(partial.getItems)) {
|
|
196
|
+
partial.getItems.url = normalizeExpression(partial.getItems.url, 'js-tpl')
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (partial.items) {
|
|
200
|
+
partial.items = partial.items.map((/** @type {import('./index.js').PartialSelectItem} */ item) => {
|
|
201
|
+
if (['string', 'integer', 'number'].includes(typeof item)) {
|
|
202
|
+
return { title: item + '', key: item + '', value: item }
|
|
203
|
+
} else if (typeof item === 'object') {
|
|
204
|
+
return {
|
|
205
|
+
key: (item.key ?? item.value) + '',
|
|
206
|
+
title: (item.title ?? item.key ?? item.value) + '',
|
|
207
|
+
value: item.value ?? item.key
|
|
208
|
+
}
|
|
209
|
+
} else {
|
|
210
|
+
throw new Error(`bad item for select: ${JSON.stringify(item)}`)
|
|
211
|
+
}
|
|
212
|
+
})
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (!partial.comp && (partial.items ?? partial.getItems)) {
|
|
216
|
+
partial.comp = 'select'
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (partial.comp === 'date-picker' && schemaFragment.format === 'date-time') {
|
|
220
|
+
partial.format = 'date-time'
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (partial.slots) {
|
|
224
|
+
for (const [name, slot] of Object.entries(partial.slots)) {
|
|
225
|
+
if (typeof slot === 'string') {
|
|
226
|
+
if (['before', 'after'].includes(name)) {
|
|
227
|
+
partial.slots[name] = { markdown: slot }
|
|
228
|
+
} else {
|
|
229
|
+
partial.slots[name] = { name: slot }
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const slotObj = partial.slots[name]
|
|
233
|
+
if (isPartialSlotMarkdown(slotObj)) {
|
|
234
|
+
slotObj.markdown = markdown(slotObj.markdown).trim()
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** @type {any} */
|
|
240
|
+
const compObject = {}
|
|
241
|
+
if (partial.comp && defaultCompObject.comp !== partial.comp) {
|
|
242
|
+
const compProperties = normalizedLayoutSchema.$defs[partial.comp]?.properties
|
|
243
|
+
if (typeof compProperties === 'object') {
|
|
244
|
+
for (const key of Object.keys(compProperties).concat(['if', 'help', 'cols', 'props', 'slots', 'options'])) {
|
|
245
|
+
if (key in defaultCompObject) compObject[key] = defaultCompObject[key]
|
|
246
|
+
if (key in partial) compObject[key] = partial[key]
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
} else {
|
|
250
|
+
Object.assign(compObject, defaultCompObject, partial)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (isSectionLayout(defaultCompObject) && isCompositeLayout(compObject)) {
|
|
254
|
+
compObject.children = getChildren((defaultCompObject).children, partial.children)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (compObject.description && !compObject.help) compObject.help = compObject.description
|
|
258
|
+
if (compObject.help) compObject.help = markdown(compObject.help).trim()
|
|
259
|
+
|
|
260
|
+
if (typeof compObject.cols === 'number') compObject.cols = { xs: compObject.cols }
|
|
261
|
+
if (typeof compObject.cols === 'object' && compObject.cols.xs === undefined) compObject.cols.xs = 12
|
|
262
|
+
|
|
263
|
+
return compObject
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* @param {LayoutKeyword} layoutKeyword
|
|
268
|
+
* @param {CompObject} defaultCompObject
|
|
269
|
+
* @param {SchemaFragment} schemaFragment
|
|
270
|
+
* @param {(text: string) => string} markdown
|
|
271
|
+
* @returns {NormalizedLayout}
|
|
272
|
+
*/
|
|
273
|
+
function getNormalizedLayout (layoutKeyword, defaultCompObject, schemaFragment, markdown) {
|
|
274
|
+
if (isPartialSwitch(layoutKeyword)) {
|
|
275
|
+
const switchCases = layoutKeyword.switch.map(layout => getCompObject(layout, clone(defaultCompObject), schemaFragment, markdown))
|
|
276
|
+
if (!switchCases.find(switchCase => !switchCase.if)) switchCases.push(clone(defaultCompObject))
|
|
277
|
+
return { switch: switchCases }
|
|
278
|
+
} else {
|
|
279
|
+
return getCompObject(layoutKeyword, defaultCompObject, schemaFragment, markdown)
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* @param {SchemaFragment} schemaFragment
|
|
285
|
+
* @param {string} schemaPath
|
|
286
|
+
* @param {(text: string) => string} markdown
|
|
287
|
+
* @param {'oneOf'} [arrayChild]
|
|
288
|
+
* @returns {NormalizedLayout}
|
|
289
|
+
*/
|
|
290
|
+
export function normalizeLayoutFragment (schemaFragment, schemaPath, markdown = (src) => src, arrayChild) {
|
|
291
|
+
let layoutKeyword
|
|
292
|
+
/** @type {CompObject} */
|
|
293
|
+
let defaultCompObject
|
|
294
|
+
if (arrayChild === 'oneOf') {
|
|
295
|
+
layoutKeyword = schemaFragment.oneOfLayout ?? {}
|
|
296
|
+
defaultCompObject = { comp: 'one-of-select' } // TODO: default label ?
|
|
297
|
+
} else {
|
|
298
|
+
layoutKeyword = schemaFragment.layout ?? {}
|
|
299
|
+
defaultCompObject = getDefaultCompObject(schemaFragment, schemaPath)
|
|
300
|
+
}
|
|
301
|
+
if (!validateLayoutKeyword(layoutKeyword)) {
|
|
302
|
+
console.error(`layout keyword validation errors at path ${schemaPath}`, layoutKeyword, validateLayoutKeyword.errors)
|
|
303
|
+
return defaultCompObject
|
|
304
|
+
// throw new Error(`invalid layout keyword at path ${schemaPath}`, { cause: validateLayoutKeyword.errors })
|
|
305
|
+
}
|
|
306
|
+
const normalizedLayout = getNormalizedLayout(layoutKeyword, defaultCompObject, schemaFragment, markdown)
|
|
307
|
+
if (!validateNormalizedLayout(normalizedLayout)) {
|
|
308
|
+
console.error(`normalized layout validation errors at path ${schemaPath}`, normalizedLayout, validateNormalizedLayout.errors)
|
|
309
|
+
return defaultCompObject
|
|
310
|
+
// throw new Error(`invalid layout at path ${schemaPath}`, { cause: validateNormalizedLayout.errors })
|
|
311
|
+
}
|
|
312
|
+
return normalizedLayout
|
|
313
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import validate from './validate.js'
|
|
2
|
+
import schema from './schema.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {import('./types.js').NormalizedLayout} NormalizedLayout
|
|
6
|
+
* @typedef {import('./types.js').SwitchStruct} SwitchStruct
|
|
7
|
+
* @typedef {import('./types.js').CompObject} CompObject
|
|
8
|
+
* @typedef {import('./types.js').Section} Section
|
|
9
|
+
* @typedef {import('./types.js').GetItems} GetItems
|
|
10
|
+
* @typedef {import('./types.js').Expression} Expression
|
|
11
|
+
* @typedef {import('./types.js').Select} Select
|
|
12
|
+
* @typedef {import('./types.js').SelectItem} SelectItem
|
|
13
|
+
* @typedef {import('./types.js').SelectItems} SelectItems
|
|
14
|
+
* @typedef {import('./types.js').GetItemsFetch} GetItemsFetch
|
|
15
|
+
* @typedef {import('./types.js').TextField} TextField
|
|
16
|
+
* @typedef {import('./types.js').Textarea} Textarea
|
|
17
|
+
* @typedef {import('./types.js').NumberField} NumberField
|
|
18
|
+
* @typedef {import('./types.js').Slider} Slider
|
|
19
|
+
* @typedef {import('./types.js').Checkbox} Checkbox
|
|
20
|
+
* @typedef {import('./types.js').Switch} Switch
|
|
21
|
+
* @typedef {import('./types.js').DatePicker} DatePicker
|
|
22
|
+
* @typedef {import('./types.js').TimePicker} TimePicker
|
|
23
|
+
* @typedef {import('./types.js').DateTimePicker} DateTimePicker
|
|
24
|
+
* @typedef {import('./types.js').ColorPicker} ColorPicker
|
|
25
|
+
* @typedef {import('./types.js').OneOfSelect} OneOfSelect
|
|
26
|
+
* @typedef {import('./types.js').Child} Child
|
|
27
|
+
* @typedef {import('./types.js').Children} Children
|
|
28
|
+
* @typedef {import('./types.js').CompositeCompObject} CompositeCompObject
|
|
29
|
+
* @typedef {import('./types.js').Tabs} Tabs
|
|
30
|
+
* @typedef {import('./types.js').VerticalTabs} VerticalTabs
|
|
31
|
+
* @typedef {import('./types.js').ExpansionPanels} ExpansionPanels
|
|
32
|
+
* @typedef {import('./types.js').List} List
|
|
33
|
+
* @typedef {import('./types.js').Cols} Cols
|
|
34
|
+
* @typedef {import('./types.js').ColsObj} ColsObj
|
|
35
|
+
* @typedef {import('./types.js').StateNodeOptions} StateNodeOptions
|
|
36
|
+
* @typedef {import('./types.js').Slot} Slot
|
|
37
|
+
* @typedef {{ errors: any, (layoutKeyword: any): layoutKeyword is NormalizedLayout }} ValidateNormalizedLayout
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
export const /** @type {ValidateNormalizedLayout} */ validateNormalizedLayout = /** @type {any} */ (validate)
|
|
41
|
+
|
|
42
|
+
export const normalizedLayoutSchema = /** @type {any} */ (schema)
|
|
43
|
+
|
|
44
|
+
/** @type {(layout: NormalizedLayout) => layout is SwitchStruct} */
|
|
45
|
+
export function isSwitchStruct (layout) {
|
|
46
|
+
return typeof layout === 'object' && 'switch' in layout
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** @type {(layout: NormalizedLayout) => layout is CompObject} */
|
|
50
|
+
export function isCompObject (layout) {
|
|
51
|
+
return !isSwitchStruct(layout)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** @type {(child: Child) => child is Child & CompositeCompObject} */
|
|
55
|
+
export function childIsCompObject (child) {
|
|
56
|
+
return !!child.comp
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** @type {(layout: CompObject) => layout is Section} */
|
|
60
|
+
export function isSectionLayout (layout) {
|
|
61
|
+
return layout.comp === 'section'
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** @type {(layout: CompObject) => layout is CompositeCompObject} */
|
|
65
|
+
export function isCompositeLayout (layout) {
|
|
66
|
+
return ['section', 'tabs', 'vertical-tabs', 'expansion-panels'].includes(layout.comp)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** @type {(layout: CompObject) => layout is TextField} */
|
|
70
|
+
export function isTextFieldLayout (layout) {
|
|
71
|
+
return layout.comp === 'text-field'
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** @type {(layout: CompObject) => layout is Select} */
|
|
75
|
+
export function isSelectLayout (layout) {
|
|
76
|
+
return layout.comp === 'select'
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** @type {(getItems: GetItems) => getItems is Expression} */
|
|
80
|
+
export function isGetItemsExpression (getItems) {
|
|
81
|
+
return !!getItems.expr
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** @type {(getItems: GetItems) => getItems is GetItemsFetch} */
|
|
85
|
+
export function isGetItemsFetch (getItems) {
|
|
86
|
+
return !!getItems.url
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** @type {(slot: Slot) => slot is {text: string}} */
|
|
90
|
+
export function isTextSlot (slot) {
|
|
91
|
+
// @ts-ignore
|
|
92
|
+
return !!slot.text
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** @type {(slot: Slot) => slot is {markdown: string}} */
|
|
96
|
+
export function isMarkdownSlot (slot) {
|
|
97
|
+
// @ts-ignore
|
|
98
|
+
return !!slot.markdown
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** @type {(slot: Slot) => slot is {name: string}} */
|
|
102
|
+
export function isNameSlot (slot) {
|
|
103
|
+
// @ts-ignore
|
|
104
|
+
return !!slot.name
|
|
105
|
+
}
|