@stonecrop/stonecrop 0.10.11 → 0.10.13
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/dist/composables/stonecrop.js +26 -110
- package/dist/field-triggers.js +5 -6
- package/dist/index.js +9 -6
- package/dist/plugins/index.js +4 -1
- package/dist/registry.js +62 -61
- package/dist/schema-validator.js +1 -13
- package/dist/src/composables/stonecrop.d.ts +2 -74
- package/dist/src/composables/stonecrop.d.ts.map +1 -1
- package/dist/src/doctype.d.ts +1 -27
- package/dist/src/doctype.d.ts.map +1 -1
- package/dist/src/field-triggers.d.ts.map +1 -1
- package/dist/src/index.d.ts +6 -9
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/plugins/index.d.ts.map +1 -1
- package/dist/src/registry.d.ts +13 -10
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/schema-validator.d.ts +1 -62
- package/dist/src/schema-validator.d.ts.map +1 -1
- package/dist/src/stonecrop.d.ts +38 -17
- package/dist/src/stonecrop.d.ts.map +1 -1
- package/dist/src/stores/operation-log.d.ts +1 -1
- package/dist/src/types/composable.d.ts +230 -0
- package/dist/src/types/composable.d.ts.map +1 -0
- package/dist/src/types/doctype.d.ts +57 -0
- package/dist/src/types/doctype.d.ts.map +1 -0
- package/dist/src/types/index.d.ts +6 -67
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/plugin.d.ts +37 -0
- package/dist/src/types/plugin.d.ts.map +1 -0
- package/dist/src/types/schema-validator.d.ts +64 -0
- package/dist/src/types/schema-validator.d.ts.map +1 -0
- package/dist/src/types/stonecrop.d.ts +17 -0
- package/dist/src/types/stonecrop.d.ts.map +1 -0
- package/dist/stonecrop.css +1 -0
- package/dist/stonecrop.d.ts +206 -14
- package/dist/stonecrop.js +1751 -1631
- package/dist/stonecrop.js.map +1 -1
- package/dist/types/composable.js +0 -0
- package/dist/types/doctype.js +0 -0
- package/dist/types/index.js +7 -2
- package/dist/types/plugin.js +0 -0
- package/dist/types/schema-validator.js +13 -0
- package/dist/types/stonecrop.js +0 -0
- package/package.json +4 -4
- package/src/composables/stonecrop.ts +34 -218
- package/src/doctype.ts +2 -29
- package/src/field-triggers.ts +5 -6
- package/src/index.ts +12 -19
- package/src/plugins/index.ts +4 -1
- package/src/registry.ts +61 -66
- package/src/schema-validator.ts +3 -66
- package/src/stonecrop.ts +148 -17
- package/src/types/composable.ts +245 -0
- package/src/types/doctype.ts +60 -0
- package/src/types/index.ts +7 -74
- package/src/types/plugin.ts +38 -0
- package/src/types/schema-validator.ts +67 -0
- package/src/types/stonecrop.ts +17 -0
package/src/registry.ts
CHANGED
|
@@ -85,17 +85,18 @@ export default class Registry {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/**
|
|
88
|
-
* Resolve nested Doctype
|
|
88
|
+
* Resolve nested Doctype fields in a schema by embedding child schemas inline.
|
|
89
89
|
*
|
|
90
90
|
* @remarks
|
|
91
91
|
* Walks the schema array and for each field with `fieldtype: 'Doctype'` and a string
|
|
92
|
-
* `options` value, looks up the referenced doctype in the registry and
|
|
93
|
-
* as the field's `schema` property. Recurses for deeply nested doctypes.
|
|
92
|
+
* `options` value, looks up the referenced doctype in the registry and:
|
|
94
93
|
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
94
|
+
* - If `cardinality: 'many'`: auto-derives `columns` from the child doctype's schema,
|
|
95
|
+
* sets `component: 'ATable'`, `config: { view: 'list' }`, and initializes `rows: []`.
|
|
96
|
+
* - Otherwise (default/`cardinality: 'one'`): embeds the child schema as the field's
|
|
97
|
+
* `schema` property for 1:1 nested forms.
|
|
98
|
+
*
|
|
99
|
+
* Recurses for deeply nested doctypes. Circular references are protected against.
|
|
99
100
|
*
|
|
100
101
|
* Returns a new array — does not mutate the original schema.
|
|
101
102
|
*
|
|
@@ -137,64 +138,52 @@ export default class Registry {
|
|
|
137
138
|
// Convert Immutable.List to plain array if needed
|
|
138
139
|
const childSchema: SchemaTypes[] = Array.isArray(doctype.schema) ? doctype.schema : Array.from(doctype.schema)
|
|
139
140
|
|
|
140
|
-
//
|
|
141
|
-
|
|
142
|
-
const resolvedChild = this.resolveSchema(childSchema, seen)
|
|
143
|
-
seen.delete(doctypeSlug)
|
|
144
|
-
|
|
145
|
-
return { ...field, schema: resolvedChild }
|
|
146
|
-
}
|
|
147
|
-
}
|
|
141
|
+
// Check cardinality to determine handling
|
|
142
|
+
const cardinality = 'cardinality' in field ? field.cardinality : undefined
|
|
148
143
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
field.fieldtype === 'Table' &&
|
|
153
|
-
'options' in field &&
|
|
154
|
-
typeof field.options === 'string'
|
|
155
|
-
) {
|
|
156
|
-
const doctypeSlug = field.options
|
|
144
|
+
if (cardinality === 'many') {
|
|
145
|
+
// 1:many child table - derive columns, set component, config, rows
|
|
146
|
+
const resolved: Record<string, any> = { ...field }
|
|
157
147
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
148
|
+
// Auto-derive columns from child schema fields if not already provided
|
|
149
|
+
if (!('columns' in field) || !field.columns) {
|
|
150
|
+
resolved.columns = childSchema.map(childField => ({
|
|
151
|
+
name: childField.fieldname,
|
|
152
|
+
fieldname: childField.fieldname,
|
|
153
|
+
label: ('label' in childField && childField.label) || childField.fieldname,
|
|
154
|
+
fieldtype: 'fieldtype' in childField ? childField.fieldtype : 'Data',
|
|
155
|
+
align: ('align' in childField && childField.align) || 'left',
|
|
156
|
+
edit: 'edit' in childField ? childField.edit : true,
|
|
157
|
+
width: ('width' in childField && childField.width) || '20ch',
|
|
158
|
+
}))
|
|
159
|
+
}
|
|
162
160
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
161
|
+
// Set default component if not already specified
|
|
162
|
+
if (!resolved.component) {
|
|
163
|
+
resolved.component = 'ATable'
|
|
164
|
+
}
|
|
167
165
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
fieldname: childField.fieldname,
|
|
173
|
-
label: ('label' in childField && childField.label) || childField.fieldname,
|
|
174
|
-
fieldtype: 'fieldtype' in childField ? childField.fieldtype : 'Data',
|
|
175
|
-
align: ('align' in childField && childField.align) || 'left',
|
|
176
|
-
edit: 'edit' in childField ? childField.edit : true,
|
|
177
|
-
width: ('width' in childField && childField.width) || '20ch',
|
|
178
|
-
}))
|
|
179
|
-
}
|
|
166
|
+
// Set default config if not already specified
|
|
167
|
+
if (!('config' in field) || !field.config) {
|
|
168
|
+
resolved.config = { view: 'list' }
|
|
169
|
+
}
|
|
180
170
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
171
|
+
// Initialize rows to empty array so componentProps fallback
|
|
172
|
+
// routes data from the form's dataModel[fieldname]
|
|
173
|
+
if (!('rows' in field) || !field.rows) {
|
|
174
|
+
resolved.rows = []
|
|
175
|
+
}
|
|
185
176
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
177
|
+
return resolved as SchemaTypes
|
|
178
|
+
} else {
|
|
179
|
+
// 1:1 nested form (default cardinality: 'one')
|
|
180
|
+
// Recurse into child schema to resolve deeply nested doctypes
|
|
181
|
+
seen.add(doctypeSlug)
|
|
182
|
+
const resolvedChild = this.resolveSchema(childSchema, seen)
|
|
183
|
+
seen.delete(doctypeSlug)
|
|
190
184
|
|
|
191
|
-
|
|
192
|
-
// routes data from the form's dataModel[fieldname]
|
|
193
|
-
if (!('rows' in field) || !field.rows) {
|
|
194
|
-
resolved.rows = []
|
|
185
|
+
return { ...field, schema: resolvedChild }
|
|
195
186
|
}
|
|
196
|
-
|
|
197
|
-
return resolved as SchemaTypes
|
|
198
187
|
}
|
|
199
188
|
}
|
|
200
189
|
|
|
@@ -211,11 +200,13 @@ export default class Registry {
|
|
|
211
200
|
* - Data, Text → `''`
|
|
212
201
|
* - Check → `false`
|
|
213
202
|
* - Int, Float, Decimal, Currency, Quantity → `0`
|
|
214
|
-
* -
|
|
215
|
-
* -
|
|
203
|
+
* - JSON → `{}`
|
|
204
|
+
* - Doctype with `cardinality: 'many'` → `[]`
|
|
205
|
+
* - Doctype without `cardinality` or `cardinality: 'one'` → recursively initializes nested record
|
|
216
206
|
* - All others → `null`
|
|
217
207
|
*
|
|
218
|
-
* For Doctype fields with a resolved `schema` array, recursively
|
|
208
|
+
* For Doctype fields with a resolved `schema` array (cardinality: 'one'), recursively
|
|
209
|
+
* initializes the nested record.
|
|
219
210
|
*
|
|
220
211
|
* @param schema - The schema array to derive defaults from
|
|
221
212
|
* @returns A plain object with default values for each field
|
|
@@ -250,20 +241,24 @@ export default class Registry {
|
|
|
250
241
|
case 'Quantity':
|
|
251
242
|
record[field.fieldname] = 0
|
|
252
243
|
break
|
|
253
|
-
case 'Table':
|
|
254
|
-
record[field.fieldname] = []
|
|
255
|
-
break
|
|
256
244
|
case 'JSON':
|
|
257
245
|
record[field.fieldname] = {}
|
|
258
246
|
break
|
|
259
|
-
case 'Doctype':
|
|
260
|
-
//
|
|
261
|
-
|
|
247
|
+
case 'Doctype': {
|
|
248
|
+
// Check cardinality to determine initial value
|
|
249
|
+
const cardinality = 'cardinality' in field ? field.cardinality : undefined
|
|
250
|
+
if (cardinality === 'many') {
|
|
251
|
+
// 1:many child table - initialize as empty array
|
|
252
|
+
record[field.fieldname] = []
|
|
253
|
+
} else if ('schema' in field && Array.isArray(field.schema)) {
|
|
254
|
+
// 1:1 nested form with resolved schema - recursively initialize
|
|
262
255
|
record[field.fieldname] = this.initializeRecord(field.schema)
|
|
263
256
|
} else {
|
|
257
|
+
// 1:1 without resolved schema - empty object
|
|
264
258
|
record[field.fieldname] = {}
|
|
265
259
|
}
|
|
266
260
|
break
|
|
261
|
+
}
|
|
267
262
|
default:
|
|
268
263
|
record[field.fieldname] = null
|
|
269
264
|
}
|
package/src/schema-validator.ts
CHANGED
|
@@ -7,74 +7,11 @@
|
|
|
7
7
|
import type { SchemaTypes } from '@stonecrop/aform'
|
|
8
8
|
import type { List, Map as ImmutableMap } from 'immutable'
|
|
9
9
|
import type { AnyStateNodeConfig } from 'xstate'
|
|
10
|
+
|
|
10
11
|
import { getGlobalTriggerEngine } from './field-triggers'
|
|
11
12
|
import type Registry from './registry'
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* Validation severity levels
|
|
15
|
-
* @public
|
|
16
|
-
*/
|
|
17
|
-
export enum ValidationSeverity {
|
|
18
|
-
/** Blocking error that prevents save */
|
|
19
|
-
ERROR = 'error',
|
|
20
|
-
/** Advisory warning that allows save */
|
|
21
|
-
WARNING = 'warning',
|
|
22
|
-
/** Informational message */
|
|
23
|
-
INFO = 'info',
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Validation issue
|
|
28
|
-
* @public
|
|
29
|
-
*/
|
|
30
|
-
export interface ValidationIssue {
|
|
31
|
-
/** Severity level */
|
|
32
|
-
severity: ValidationSeverity
|
|
33
|
-
/** Validation rule that failed */
|
|
34
|
-
rule: string
|
|
35
|
-
/** Human-readable message */
|
|
36
|
-
message: string
|
|
37
|
-
/** Doctype name */
|
|
38
|
-
doctype?: string
|
|
39
|
-
/** Field name if applicable */
|
|
40
|
-
fieldname?: string
|
|
41
|
-
/** Additional context */
|
|
42
|
-
context?: Record<string, unknown>
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Validation result
|
|
47
|
-
* @public
|
|
48
|
-
*/
|
|
49
|
-
export interface ValidationResult {
|
|
50
|
-
/** Whether validation passed (no blocking errors) */
|
|
51
|
-
valid: boolean
|
|
52
|
-
/** List of validation issues */
|
|
53
|
-
issues: ValidationIssue[]
|
|
54
|
-
/** Count of errors */
|
|
55
|
-
errorCount: number
|
|
56
|
-
/** Count of warnings */
|
|
57
|
-
warningCount: number
|
|
58
|
-
/** Count of info messages */
|
|
59
|
-
infoCount: number
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Schema validator options
|
|
64
|
-
* @public
|
|
65
|
-
*/
|
|
66
|
-
export interface ValidatorOptions {
|
|
67
|
-
/** Registry instance for doctype lookups */
|
|
68
|
-
registry?: Registry
|
|
69
|
-
/** Whether to validate Link field targets */
|
|
70
|
-
validateLinkTargets?: boolean
|
|
71
|
-
/** Whether to validate workflow reachability */
|
|
72
|
-
validateWorkflows?: boolean
|
|
73
|
-
/** Whether to validate action registration */
|
|
74
|
-
validateActions?: boolean
|
|
75
|
-
/** Whether to validate required schema properties */
|
|
76
|
-
validateRequiredProperties?: boolean
|
|
77
|
-
}
|
|
13
|
+
import { ValidationSeverity } from './types/schema-validator'
|
|
14
|
+
import type { ValidationIssue, ValidationResult, ValidatorOptions } from './types/schema-validator'
|
|
78
15
|
|
|
79
16
|
/**
|
|
80
17
|
* Schema validator class
|
package/src/stonecrop.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
type DoctypeManySchema,
|
|
3
|
+
type DoctypeOneSchema,
|
|
4
|
+
type DoctypeSchema,
|
|
5
|
+
type SchemaTypes,
|
|
6
|
+
isDoctypeMany,
|
|
7
|
+
} from '@stonecrop/aform'
|
|
8
|
+
import type { DataClient } from '@stonecrop/schema'
|
|
2
9
|
import { reactive } from 'vue'
|
|
3
10
|
|
|
4
11
|
import Doctype from './doctype'
|
|
@@ -7,28 +14,21 @@ import { createHST, type HSTNode } from './stores/hst'
|
|
|
7
14
|
import { useOperationLogStore } from './stores/operation-log'
|
|
8
15
|
import type { OperationLogConfig } from './types/operation-log'
|
|
9
16
|
import type { RouteContext } from './types/registry'
|
|
17
|
+
import type { StonecropOptions } from './types/stonecrop'
|
|
10
18
|
|
|
11
19
|
/**
|
|
12
|
-
*
|
|
13
|
-
* When using the Vue plugin, pass these via `InstallOptions` instead.
|
|
20
|
+
* Main Stonecrop class with HST integration and built-in Operation Log
|
|
14
21
|
* @public
|
|
15
22
|
*/
|
|
16
|
-
export
|
|
23
|
+
export class Stonecrop {
|
|
17
24
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* Can be set later via `setClient()` for deferred configuration.
|
|
25
|
+
* Singleton instance of Stonecrop. Only one Stonecrop instance can exist
|
|
26
|
+
* per application, ensuring consistent HST state and registry access.
|
|
27
|
+
* Subsequent constructor calls return this instance instead of creating new ones.
|
|
28
|
+
* @internal
|
|
23
29
|
*/
|
|
24
|
-
|
|
25
|
-
}
|
|
30
|
+
static _root: Stonecrop
|
|
26
31
|
|
|
27
|
-
/**
|
|
28
|
-
* Main Stonecrop class with HST integration and built-in Operation Log
|
|
29
|
-
* @public
|
|
30
|
-
*/
|
|
31
|
-
export class Stonecrop {
|
|
32
32
|
private hstStore: HSTNode
|
|
33
33
|
private _operationLogStore?: ReturnType<typeof useOperationLogStore>
|
|
34
34
|
private _operationLogConfig?: Partial<OperationLogConfig>
|
|
@@ -38,12 +38,17 @@ export class Stonecrop {
|
|
|
38
38
|
readonly registry: Registry
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
* Creates a new Stonecrop instance with HST integration
|
|
41
|
+
* Creates a new Stonecrop instance with HST integration (singleton pattern)
|
|
42
42
|
* @param registry - The Registry instance containing doctype definitions
|
|
43
43
|
* @param operationLogConfig - Optional configuration for the operation log
|
|
44
44
|
* @param options - Options including the data client (can be set later via setClient)
|
|
45
45
|
*/
|
|
46
46
|
constructor(registry: Registry, operationLogConfig?: Partial<OperationLogConfig>, options?: StonecropOptions) {
|
|
47
|
+
if (Stonecrop._root) {
|
|
48
|
+
return Stonecrop._root
|
|
49
|
+
}
|
|
50
|
+
Stonecrop._root = this
|
|
51
|
+
|
|
47
52
|
this.registry = registry
|
|
48
53
|
|
|
49
54
|
// Store config for lazy initialization
|
|
@@ -417,4 +422,130 @@ export class Stonecrop {
|
|
|
417
422
|
|
|
418
423
|
return status || initialState
|
|
419
424
|
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Collect a record payload with all nested doctype fields from HST
|
|
428
|
+
* @param doctype - The doctype metadata
|
|
429
|
+
* @param recordId - The record ID to collect
|
|
430
|
+
* @returns The complete record payload ready for API submission
|
|
431
|
+
* @public
|
|
432
|
+
*/
|
|
433
|
+
collectRecordPayload(doctype: Doctype, recordId: string): Record<string, any> {
|
|
434
|
+
const recordPath = `${doctype.slug}.${recordId}`
|
|
435
|
+
const recordData = this.hstStore.get(recordPath) || {}
|
|
436
|
+
|
|
437
|
+
const payload: Record<string, any> = { ...recordData }
|
|
438
|
+
|
|
439
|
+
const schemaArray = doctype.schema
|
|
440
|
+
? Array.isArray(doctype.schema)
|
|
441
|
+
? doctype.schema
|
|
442
|
+
: Array.from(doctype.schema)
|
|
443
|
+
: []
|
|
444
|
+
const resolved = this.registry.resolveSchema(schemaArray)
|
|
445
|
+
|
|
446
|
+
const doctypeFields = resolved.filter(
|
|
447
|
+
field =>
|
|
448
|
+
'fieldtype' in field &&
|
|
449
|
+
field.fieldtype === 'Doctype' &&
|
|
450
|
+
!isDoctypeMany(field as DoctypeSchema) &&
|
|
451
|
+
'schema' in field &&
|
|
452
|
+
Array.isArray(field.schema)
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
for (const field of doctypeFields) {
|
|
456
|
+
const doctypeField = field as DoctypeOneSchema
|
|
457
|
+
const fieldPath = `${recordPath}.${doctypeField.fieldname}`
|
|
458
|
+
const nestedData = collectNestedData(doctypeField.schema!, fieldPath, this.hstStore)
|
|
459
|
+
payload[doctypeField.fieldname] = nestedData
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const doctypeManyFields = resolved.filter(
|
|
463
|
+
field => 'fieldtype' in field && field.fieldtype === 'Doctype' && isDoctypeMany(field as DoctypeSchema)
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
for (const field of doctypeManyFields) {
|
|
467
|
+
const doctypeField = field as DoctypeManySchema
|
|
468
|
+
const fieldPath = `${recordPath}.${doctypeField.fieldname}`
|
|
469
|
+
const arrayData = this.hstStore.get(fieldPath)
|
|
470
|
+
if (Array.isArray(arrayData)) {
|
|
471
|
+
payload[doctypeField.fieldname] = arrayData
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
return payload
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Load nested data from HST or initialize with defaults
|
|
480
|
+
* @param parentPath - The HST path to check for existing data
|
|
481
|
+
* @param childDoctype - The child doctype metadata
|
|
482
|
+
* @param _recordId - Optional record ID to load
|
|
483
|
+
* @returns The loaded or initialized data
|
|
484
|
+
* @public
|
|
485
|
+
*/
|
|
486
|
+
loadNestedData(parentPath: string, childDoctype: Doctype, _recordId?: string): Record<string, any> {
|
|
487
|
+
// Check if data already exists in HST
|
|
488
|
+
const existingData = this.hstStore.get(parentPath)
|
|
489
|
+
if (existingData && typeof existingData === 'object') {
|
|
490
|
+
return existingData as Record<string, any>
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// TODO: If recordId provided and no HST data, fetch from API using this._client
|
|
494
|
+
// For now, always fall through to initialize new record
|
|
495
|
+
|
|
496
|
+
// Resolve schema and initialize with defaults
|
|
497
|
+
const schemaArray = childDoctype.schema
|
|
498
|
+
? Array.isArray(childDoctype.schema)
|
|
499
|
+
? childDoctype.schema
|
|
500
|
+
: Array.from(childDoctype.schema)
|
|
501
|
+
: []
|
|
502
|
+
const resolvedSchema = this.registry.resolveSchema(schemaArray)
|
|
503
|
+
return this.registry.initializeRecord(resolvedSchema)
|
|
504
|
+
}
|
|
420
505
|
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Recursively collect nested data from HST using pre-resolved schemas
|
|
509
|
+
* @param resolvedSchema - The already-resolved schema (with nested schemas embedded)
|
|
510
|
+
* @param basePath - The base path in HST (e.g., "customer.123.address")
|
|
511
|
+
* @param hstStore - The HST store instance
|
|
512
|
+
* @returns The collected data object
|
|
513
|
+
* @public
|
|
514
|
+
*/
|
|
515
|
+
function collectNestedData(resolvedSchema: SchemaTypes[], basePath: string, hstStore: HSTNode): Record<string, any> {
|
|
516
|
+
const data = hstStore.get(basePath) || {}
|
|
517
|
+
const payload: Record<string, any> = { ...data }
|
|
518
|
+
|
|
519
|
+
const doctypeFields = resolvedSchema.filter(
|
|
520
|
+
field =>
|
|
521
|
+
'fieldtype' in field &&
|
|
522
|
+
field.fieldtype === 'Doctype' &&
|
|
523
|
+
!isDoctypeMany(field as DoctypeSchema) &&
|
|
524
|
+
'schema' in field &&
|
|
525
|
+
Array.isArray(field.schema)
|
|
526
|
+
)
|
|
527
|
+
|
|
528
|
+
for (const field of doctypeFields) {
|
|
529
|
+
const doctypeField = field as DoctypeOneSchema
|
|
530
|
+
const fieldPath = `${basePath}.${doctypeField.fieldname}`
|
|
531
|
+
const nestedData = collectNestedData(doctypeField.schema!, fieldPath, hstStore)
|
|
532
|
+
payload[doctypeField.fieldname] = nestedData
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const doctypeManyFields = resolvedSchema.filter(
|
|
536
|
+
field => 'fieldtype' in field && field.fieldtype === 'Doctype' && isDoctypeMany(field as DoctypeSchema)
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
for (const field of doctypeManyFields) {
|
|
540
|
+
const doctypeField = field as DoctypeManySchema
|
|
541
|
+
const fieldPath = `${basePath}.${doctypeField.fieldname}`
|
|
542
|
+
const arrayData = hstStore.get(fieldPath)
|
|
543
|
+
if (Array.isArray(arrayData)) {
|
|
544
|
+
payload[doctypeField.fieldname] = arrayData
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
return payload
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
export { collectNestedData }
|