@stonecrop/stonecrop 0.10.12 → 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.
Files changed (50) hide show
  1. package/dist/composables/stonecrop.js +19 -144
  2. package/dist/index.js +9 -6
  3. package/dist/plugins/index.js +4 -1
  4. package/dist/schema-validator.js +1 -13
  5. package/dist/src/composables/stonecrop.d.ts +2 -74
  6. package/dist/src/composables/stonecrop.d.ts.map +1 -1
  7. package/dist/src/doctype.d.ts +1 -27
  8. package/dist/src/doctype.d.ts.map +1 -1
  9. package/dist/src/index.d.ts +6 -9
  10. package/dist/src/index.d.ts.map +1 -1
  11. package/dist/src/plugins/index.d.ts.map +1 -1
  12. package/dist/src/schema-validator.d.ts +1 -62
  13. package/dist/src/schema-validator.d.ts.map +1 -1
  14. package/dist/src/stonecrop.d.ts +38 -17
  15. package/dist/src/stonecrop.d.ts.map +1 -1
  16. package/dist/src/stores/operation-log.d.ts +1 -1
  17. package/dist/src/types/composable.d.ts +230 -0
  18. package/dist/src/types/composable.d.ts.map +1 -0
  19. package/dist/src/types/doctype.d.ts +57 -0
  20. package/dist/src/types/doctype.d.ts.map +1 -0
  21. package/dist/src/types/index.d.ts +6 -67
  22. package/dist/src/types/index.d.ts.map +1 -1
  23. package/dist/src/types/plugin.d.ts +37 -0
  24. package/dist/src/types/plugin.d.ts.map +1 -0
  25. package/dist/src/types/schema-validator.d.ts +64 -0
  26. package/dist/src/types/schema-validator.d.ts.map +1 -0
  27. package/dist/src/types/stonecrop.d.ts +17 -0
  28. package/dist/src/types/stonecrop.d.ts.map +1 -0
  29. package/dist/stonecrop.d.ts +192 -3
  30. package/dist/stonecrop.js +1509 -1517
  31. package/dist/stonecrop.js.map +1 -1
  32. package/dist/types/composable.js +0 -0
  33. package/dist/types/doctype.js +0 -0
  34. package/dist/types/index.js +7 -2
  35. package/dist/types/plugin.js +0 -0
  36. package/dist/types/schema-validator.js +13 -0
  37. package/dist/types/stonecrop.js +0 -0
  38. package/package.json +5 -5
  39. package/src/composables/stonecrop.ts +26 -266
  40. package/src/doctype.ts +2 -29
  41. package/src/index.ts +12 -19
  42. package/src/plugins/index.ts +4 -1
  43. package/src/schema-validator.ts +3 -66
  44. package/src/stonecrop.ts +147 -16
  45. package/src/types/composable.ts +245 -0
  46. package/src/types/doctype.ts +60 -0
  47. package/src/types/index.ts +7 -74
  48. package/src/types/plugin.ts +38 -0
  49. package/src/types/schema-validator.ts +67 -0
  50. package/src/types/stonecrop.ts +17 -0
File without changes
File without changes
@@ -1,4 +1,9 @@
1
- // Re-export types
1
+ // Re-export all type files
2
+ export * from './composable';
3
+ export * from './doctype';
2
4
  export * from './field-triggers';
3
- export * from './registry';
4
5
  export * from './operation-log';
6
+ export * from './plugin';
7
+ export * from './registry';
8
+ export * from './schema-validator';
9
+ export * from './stonecrop';
File without changes
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Validation severity levels
3
+ * @public
4
+ */
5
+ export var ValidationSeverity;
6
+ (function (ValidationSeverity) {
7
+ /** Blocking error that prevents save */
8
+ ValidationSeverity["ERROR"] = "error";
9
+ /** Advisory warning that allows save */
10
+ ValidationSeverity["WARNING"] = "warning";
11
+ /** Informational message */
12
+ ValidationSeverity["INFO"] = "info";
13
+ })(ValidationSeverity || (ValidationSeverity = {}));
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stonecrop/stonecrop",
3
- "version": "0.10.12",
3
+ "version": "0.10.13",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "author": {
@@ -34,7 +34,7 @@
34
34
  "pinia-shared-state": "^1.0.1",
35
35
  "pinia-xstate": "^3.0.0",
36
36
  "xstate": "^5.25.0",
37
- "@stonecrop/schema": "0.10.12"
37
+ "@stonecrop/schema": "0.10.13"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "pinia": "^3.0.4",
@@ -60,9 +60,9 @@
60
60
  "vue-router": "^5.0.2",
61
61
  "vite": "^7.3.1",
62
62
  "vitest": "^4.0.18",
63
- "@stonecrop/aform": "0.10.12",
64
- "@stonecrop/atable": "0.10.12",
65
- "stonecrop-rig": "0.7.0"
63
+ "stonecrop-rig": "0.7.0",
64
+ "@stonecrop/atable": "0.10.13",
65
+ "@stonecrop/aform": "0.10.13"
66
66
  },
67
67
  "description": "Schema-driven framework with XState workflows and HST state management",
68
68
  "publishConfig": {
@@ -1,100 +1,14 @@
1
- import {
2
- type DoctypeManySchema,
3
- type DoctypeOneSchema,
4
- type DoctypeSchema,
5
- type SchemaTypes,
6
- isDoctypeMany,
7
- } from '@stonecrop/aform'
1
+ import { type SchemaTypes } from '@stonecrop/aform'
8
2
  import { storeToRefs } from 'pinia'
9
- import { inject, onMounted, Ref, ref, watch, provide, computed, type ComputedRef } from 'vue'
3
+ import { inject, onMounted, Ref, ref, watch, provide, computed } from 'vue'
10
4
 
5
+ import Doctype from '../doctype'
11
6
  import Registry from '../registry'
12
7
  import { Stonecrop } from '../stonecrop'
13
- import Doctype from '../doctype'
14
8
  import type { HSTNode } from '../stores/hst'
9
+ import type { BaseStonecropReturn, HSTStonecropReturn, HSTChangeData, OperationLogAPI } from '../types/composable'
10
+ import type { HSTOperation, OperationLogConfig } from '../types/operation-log'
15
11
  import type { RouteContext } from '../types/registry'
16
- import type { HSTOperation, OperationLogConfig, OperationLogSnapshot } from '../types/operation-log'
17
-
18
- /**
19
- * Operation Log API - nested object containing all operation log functionality
20
- * @public
21
- */
22
- export type OperationLogAPI = {
23
- operations: Ref<HSTOperation[]>
24
- currentIndex: Ref<number>
25
- undoRedoState: ComputedRef<{
26
- canUndo: boolean
27
- canRedo: boolean
28
- undoCount: number
29
- redoCount: number
30
- currentIndex: number
31
- }>
32
- canUndo: ComputedRef<boolean>
33
- canRedo: ComputedRef<boolean>
34
- undoCount: ComputedRef<number>
35
- redoCount: ComputedRef<number>
36
- undo: (hstStore: HSTNode) => boolean
37
- redo: (hstStore: HSTNode) => boolean
38
- startBatch: () => void
39
- commitBatch: (description?: string) => string | null
40
- cancelBatch: () => void
41
- clear: () => void
42
- getOperationsFor: (doctype: string, recordId?: string) => HSTOperation[]
43
- getSnapshot: () => OperationLogSnapshot
44
- markIrreversible: (operationId: string, reason: string) => void
45
- logAction: (
46
- doctype: string,
47
- actionName: string,
48
- recordIds?: string[],
49
- result?: 'success' | 'failure' | 'pending',
50
- error?: string
51
- ) => string
52
- configure: (options: Partial<OperationLogConfig>) => void
53
- }
54
-
55
- /**
56
- * Base Stonecrop composable return type - includes operation log functionality
57
- * @public
58
- */
59
- export type BaseStonecropReturn = {
60
- stonecrop: Ref<Stonecrop | undefined>
61
- operationLog: OperationLogAPI
62
- }
63
-
64
- /**
65
- * HST-enabled Stonecrop composable return type
66
- * @public
67
- */
68
- export type HSTStonecropReturn = BaseStonecropReturn & {
69
- provideHSTPath: (fieldname: string, recordId?: string) => string
70
- handleHSTChange: (changeData: HSTChangeData) => void
71
- hstStore: Ref<HSTNode | undefined>
72
- formData: Ref<Record<string, any>>
73
- resolvedSchema: Ref<SchemaTypes[]>
74
- loadNestedData: (parentPath: string, childDoctype: Doctype, recordId?: string) => Record<string, any>
75
- collectRecordPayload: (doctype: Doctype, recordId: string) => Record<string, any>
76
- createNestedContext: (
77
- basePath: string,
78
- childDoctype: Doctype
79
- ) => {
80
- provideHSTPath: (fieldname: string) => string
81
- handleHSTChange: (changeData: HSTChangeData) => void
82
- }
83
- isLoading: Ref<boolean>
84
- error: Ref<Error | null>
85
- resolvedDoctype: Ref<Doctype | undefined>
86
- }
87
-
88
- /**
89
- * HST Change data structure
90
- * @public
91
- */
92
- export type HSTChangeData = {
93
- path: string
94
- value: any
95
- fieldname: string
96
- recordId?: string
97
- }
98
12
 
99
13
  /**
100
14
  * Unified Stonecrop composable - handles both general operations and HST reactive integration
@@ -128,7 +42,7 @@ export function useStonecrop(options?: {
128
42
 
129
43
  const registry = options.registry || inject<Registry>('$registry')
130
44
  const providedStonecrop = inject<Stonecrop>('$stonecrop')
131
- const stonecrop = ref<Stonecrop>()
45
+ const stonecrop = ref<Stonecrop | undefined>()
132
46
  const hstStore = ref<HSTNode>()
133
47
  const formData = ref<Record<string, any>>({})
134
48
 
@@ -144,6 +58,13 @@ export function useStonecrop(options?: {
144
58
  const error = ref<Error | null>(null)
145
59
  const resolvedDoctype = ref<Doctype | undefined>()
146
60
 
61
+ // Initialize stonecrop instance synchronously using singleton pattern
62
+ // Use injected instance if available, otherwise fall back to the singleton root
63
+ const stonecropInstance = providedStonecrop || Stonecrop._root
64
+ if (stonecropInstance) {
65
+ stonecrop.value = stonecropInstance
66
+ }
67
+
147
68
  // If doctype is a Doctype instance (not string), set resolved immediately
148
69
  if (options?.doctype && typeof options.doctype !== 'string') {
149
70
  resolvedDoctype.value = options.doctype
@@ -228,12 +149,10 @@ export function useStonecrop(options?: {
228
149
 
229
150
  // Initialize Stonecrop instance
230
151
  onMounted(async () => {
231
- if (!registry) {
152
+ if (!registry || !stonecrop.value) {
232
153
  return
233
154
  }
234
155
 
235
- stonecrop.value = providedStonecrop || new Stonecrop(registry)
236
-
237
156
  // Set up reactive refs from operation log store - only if Pinia is available
238
157
  try {
239
158
  const opLogStore = stonecrop.value.getOperationLogStore()
@@ -308,11 +227,11 @@ export function useStonecrop(options?: {
308
227
  formData.value = loadedRecord.get('') || {}
309
228
  }
310
229
  } catch {
311
- formData.value = initializeNewRecord(doctype)
230
+ formData.value = registry.initializeRecord(resolvedSchema.value)
312
231
  }
313
232
  }
314
233
  } else {
315
- formData.value = initializeNewRecord(doctype)
234
+ formData.value = registry.initializeRecord(resolvedSchema.value)
316
235
  }
317
236
 
318
237
  if (hstStore.value) {
@@ -395,11 +314,11 @@ export function useStonecrop(options?: {
395
314
  formData.value = loadedRecord.get('') || {}
396
315
  }
397
316
  } catch {
398
- formData.value = initializeNewRecord(doctype)
317
+ formData.value = registry.initializeRecord(resolvedSchema.value)
399
318
  }
400
319
  }
401
320
  } else {
402
- formData.value = initializeNewRecord(doctype)
321
+ formData.value = registry.initializeRecord(resolvedSchema.value)
403
322
  }
404
323
 
405
324
  if (hstStore.value) {
@@ -475,96 +394,31 @@ export function useStonecrop(options?: {
475
394
 
476
395
  /**
477
396
  * Load nested doctype data from API or initialize empty structure
397
+ * Delegates to Stonecrop.loadNestedData method
478
398
  * @param parentPath - The parent path (e.g., "customer.123.address")
479
399
  * @param childDoctype - The child doctype metadata
480
400
  * @param recordId - Optional record ID to load
481
- * @returns Promise resolving to the loaded or initialized data
401
+ * @returns The loaded or initialized data
482
402
  */
483
403
  const loadNestedData = (parentPath: string, childDoctype: Doctype, recordId?: string): Record<string, any> => {
484
404
  if (!stonecrop.value) {
485
- return initializeNewRecord(childDoctype)
405
+ throw new Error('Stonecrop instance not available')
486
406
  }
487
-
488
- // If recordId provided, try to load existing data
489
- if (recordId) {
490
- try {
491
- // Check if data already exists in HST
492
- const existingData = hstStore.value?.get(parentPath)
493
- if (existingData && typeof existingData === 'object') {
494
- return existingData as Record<string, any>
495
- }
496
-
497
- // TODO: Add API fetch logic here if needed
498
- // For now, initialize new record
499
- return initializeNewRecord(childDoctype)
500
- } catch {
501
- return initializeNewRecord(childDoctype)
502
- }
503
- }
504
-
505
- // Initialize new record
506
- return initializeNewRecord(childDoctype)
407
+ return stonecrop.value.loadNestedData(parentPath, childDoctype, recordId)
507
408
  }
508
409
 
509
410
  /**
510
411
  * Collect a record payload with all nested doctype fields from HST
412
+ * Delegates to Stonecrop.collectRecordPayload method
511
413
  * @param doctype - The doctype metadata
512
414
  * @param recordId - The record ID to collect
513
415
  * @returns The complete record payload ready for API submission
514
416
  */
515
417
  const collectRecordPayload = (doctype: Doctype, recordId: string): Record<string, any> => {
516
- if (!hstStore.value || !stonecrop.value) {
517
- throw new Error('HST store not initialized')
518
- }
519
-
520
- const recordPath = `${doctype.slug}.${recordId}`
521
- const recordData = hstStore.value.get(recordPath) || {}
522
-
523
- // Build the save payload using resolved schema
524
- const payload: Record<string, any> = { ...recordData }
525
-
526
- // Use resolveSchema to get the full resolved tree, then walk Doctype fields
527
- const schemaArray = doctype.schema
528
- ? Array.isArray(doctype.schema)
529
- ? doctype.schema
530
- : Array.from(doctype.schema)
531
- : []
532
- const resolved = registry ? registry.resolveSchema(schemaArray) : schemaArray
533
-
534
- // 1:1 nested Doctype fields (cardinality: 'one' or undefined)
535
- const doctypeFields = resolved.filter(
536
- field =>
537
- 'fieldtype' in field &&
538
- field.fieldtype === 'Doctype' &&
539
- !isDoctypeMany(field as DoctypeSchema) &&
540
- 'schema' in field &&
541
- Array.isArray(field.schema)
542
- )
543
-
544
- // Recursively collect nested data from HST using resolved schemas
545
- for (const field of doctypeFields) {
546
- const doctypeField = field as DoctypeOneSchema
547
- const fieldPath = `${recordPath}.${doctypeField.fieldname}`
548
- const nestedData = collectNestedData(doctypeField.schema!, fieldPath, hstStore.value)
549
- payload[doctypeField.fieldname] = nestedData
550
- }
551
-
552
- // 1:many child tables (cardinality: 'many')
553
- const doctypeManyFields = resolved.filter(
554
- field => 'fieldtype' in field && field.fieldtype === 'Doctype' && isDoctypeMany(field as DoctypeSchema)
555
- )
556
-
557
- // Read array data from HST for cardinality: 'many' fields
558
- for (const field of doctypeManyFields) {
559
- const doctypeField = field as DoctypeManySchema
560
- const fieldPath = `${recordPath}.${doctypeField.fieldname}`
561
- const arrayData = hstStore.value.get(fieldPath)
562
- if (Array.isArray(arrayData)) {
563
- payload[doctypeField.fieldname] = arrayData
564
- }
418
+ if (!stonecrop.value) {
419
+ throw new Error('Stonecrop instance not available')
565
420
  }
566
-
567
- return payload
421
+ return stonecrop.value.collectRecordPayload(doctype, recordId)
568
422
  }
569
423
 
570
424
  /**
@@ -659,54 +513,6 @@ export function useStonecrop(options?: {
659
513
  } as BaseStonecropReturn
660
514
  }
661
515
 
662
- /**
663
- * Initialize new record structure based on doctype schema
664
- */
665
- function initializeNewRecord(doctype: Doctype): Record<string, any> {
666
- const initialData: Record<string, any> = {}
667
-
668
- if (!doctype.schema) {
669
- return initialData
670
- }
671
-
672
- doctype.schema.forEach(field => {
673
- const fieldtype = 'fieldtype' in field ? field.fieldtype : 'Data'
674
-
675
- switch (fieldtype) {
676
- case 'Data':
677
- case 'Text':
678
- initialData[field.fieldname] = ''
679
- break
680
- case 'Check':
681
- initialData[field.fieldname] = false
682
- break
683
- case 'Int':
684
- case 'Float':
685
- initialData[field.fieldname] = 0
686
- break
687
- case 'JSON':
688
- initialData[field.fieldname] = {}
689
- break
690
- case 'Doctype': {
691
- // Check cardinality to determine initial value
692
- const cardinality = 'cardinality' in field ? field.cardinality : undefined
693
- if (cardinality === 'many') {
694
- // 1:many child table - initialize as empty array
695
- initialData[field.fieldname] = []
696
- } else {
697
- // 1:1 nested form - initialize as empty object
698
- initialData[field.fieldname] = {}
699
- }
700
- break
701
- }
702
- default:
703
- initialData[field.fieldname] = null
704
- }
705
- })
706
-
707
- return initialData
708
- }
709
-
710
516
  /**
711
517
  * Setup deep reactivity between form data and HST store
712
518
  */
@@ -753,49 +559,3 @@ function updateNestedObject(obj: any, path: string[], value: any): void {
753
559
  const finalKey = path[path.length - 1]
754
560
  current[finalKey] = value
755
561
  }
756
-
757
- /**
758
- * Recursively collect nested data from HST using pre-resolved schemas
759
- * @param resolvedSchema - The already-resolved schema (with nested schemas embedded)
760
- * @param basePath - The base path in HST (e.g., "customer.123.address")
761
- * @param hstStore - The HST store instance
762
- * @returns The collected data object
763
- */
764
- function collectNestedData(resolvedSchema: SchemaTypes[], basePath: string, hstStore: HSTNode): Record<string, any> {
765
- const data = hstStore.get(basePath) || {}
766
- const payload: Record<string, any> = { ...data }
767
-
768
- // Find Doctype fields that have resolved child schemas (1:1 only, not cardinality: 'many')
769
- const doctypeFields = resolvedSchema.filter(
770
- field =>
771
- 'fieldtype' in field &&
772
- field.fieldtype === 'Doctype' &&
773
- !isDoctypeMany(field as DoctypeSchema) &&
774
- 'schema' in field &&
775
- Array.isArray(field.schema)
776
- )
777
-
778
- // Recursively collect nested data
779
- for (const field of doctypeFields) {
780
- const doctypeField = field as DoctypeOneSchema
781
- const fieldPath = `${basePath}.${doctypeField.fieldname}`
782
- const nestedData = collectNestedData(doctypeField.schema!, fieldPath, hstStore)
783
- payload[doctypeField.fieldname] = nestedData
784
- }
785
-
786
- // Also collect array data for cardinality: 'many' fields
787
- const doctypeManyFields = resolvedSchema.filter(
788
- field => 'fieldtype' in field && field.fieldtype === 'Doctype' && isDoctypeMany(field as DoctypeSchema)
789
- )
790
-
791
- for (const field of doctypeManyFields) {
792
- const doctypeField = field as DoctypeManySchema
793
- const fieldPath = `${basePath}.${doctypeField.fieldname}`
794
- const arrayData = hstStore.get(fieldPath)
795
- if (Array.isArray(arrayData)) {
796
- payload[doctypeField.fieldname] = arrayData
797
- }
798
- }
799
-
800
- return payload
801
- }
package/src/doctype.ts CHANGED
@@ -5,32 +5,7 @@ import { Component } from 'vue'
5
5
  import type { UnknownMachineConfig } from 'xstate'
6
6
 
7
7
  import type { ImmutableDoctype } from './types'
8
-
9
- /**
10
- * Plain object representation of doctype configuration for serialization/API responses.
11
- * Compatible with the DoctypeMeta type from \@stonecrop/schema.
12
- * @public
13
- */
14
- export type DoctypeConfig = {
15
- /** Display name of the doctype */
16
- name: string
17
- /** URL-friendly slug (kebab-case) */
18
- slug?: string
19
- /** Database table name */
20
- tableName?: string
21
- /** Field definitions */
22
- fields?: SchemaTypes[]
23
- /** Workflow configuration (XState format or simple WorkflowMeta) */
24
- workflow?: UnknownMachineConfig | WorkflowMeta
25
- /** Actions and their field triggers */
26
- actions?: Record<string, string[]>
27
- /** Parent doctype for inheritance */
28
- inherits?: string
29
- /** Doctype to use for list views */
30
- listDoctype?: string
31
- /** Parent doctype for child tables */
32
- parentDoctype?: string
33
- }
8
+ import type { DoctypeConfig } from './types/doctype'
34
9
 
35
10
  /**
36
11
  * Doctype runtime class with Immutable.js collections for HST change tracking.
@@ -249,9 +224,7 @@ export default class Doctype {
249
224
  *
250
225
  * @public
251
226
  */
252
- getActionMeta(
253
- actionName: string
254
- ):
227
+ getActionMeta(actionName: string):
255
228
  | {
256
229
  label: string
257
230
  handler: string
package/src/index.ts CHANGED
@@ -3,8 +3,9 @@ export type * from '@stonecrop/atable/types'
3
3
 
4
4
  import { useStonecrop } from './composables/stonecrop'
5
5
  import { useOperationLog, useUndoRedoShortcuts, withBatch } from './composables/operation-log'
6
- import Doctype, { type DoctypeConfig } from './doctype'
6
+ import Doctype from './doctype'
7
7
  import {
8
+ FieldTriggerEngine,
8
9
  getGlobalTriggerEngine,
9
10
  markOperationIrreversible,
10
11
  registerGlobalAction,
@@ -14,39 +15,29 @@ import {
14
15
  } from './field-triggers'
15
16
  import plugin from './plugins'
16
17
  import Registry from './registry'
17
- import { type StonecropOptions, Stonecrop } from './stonecrop'
18
+ import { Stonecrop, collectNestedData } from './stonecrop'
18
19
  import { HST, createHST, type HSTNode } from './stores/hst'
19
20
  import { useOperationLogStore } from './stores/operation-log'
20
- // Export schema validator
21
21
  import { SchemaValidator, createValidator, validateSchema } from './schema-validator'
22
+ import { ValidationSeverity } from './types/schema-validator'
23
+
24
+ // Export all types from ./types
22
25
  export type * from './types'
23
- export type { BaseStonecropReturn, HSTChangeData, HSTStonecropReturn, OperationLogAPI } from './composables/stonecrop'
24
- export type { FieldTriggerEngine } from './field-triggers'
25
- export type {
26
- FieldChangeContext,
27
- TransitionChangeContext,
28
- FieldTriggerExecutionResult,
29
- ActionExecutionResult,
30
- TransitionExecutionResult,
31
- FieldActionFunction,
32
- TransitionActionFunction,
33
- } from './types/field-triggers'
34
- // Export schema validator types
35
- export type { ValidationIssue, ValidationResult, ValidatorOptions } from './schema-validator'
36
- export { ValidationSeverity } from './schema-validator'
26
+
27
+ // Export enum as value (enums need runtime export, not just type)
28
+ export { ValidationSeverity }
37
29
 
38
30
  export {
39
31
  Doctype,
40
- DoctypeConfig,
41
32
  Registry,
42
33
  Stonecrop,
43
- StonecropOptions,
44
34
  useStonecrop,
45
35
  // HST exports for advanced usage
46
36
  HST,
47
37
  createHST,
48
38
  HSTNode,
49
39
  // Field trigger system exports
40
+ FieldTriggerEngine,
50
41
  getGlobalTriggerEngine,
51
42
  registerGlobalAction,
52
43
  registerTransitionAction,
@@ -62,6 +53,8 @@ export {
62
53
  useOperationLogStore,
63
54
  useUndoRedoShortcuts,
64
55
  withBatch,
56
+ // Utility functions
57
+ collectNestedData,
65
58
  }
66
59
 
67
60
  // Default export is the Vue plugin
@@ -72,7 +72,10 @@ const plugin: Plugin = {
72
72
  app.config.globalProperties.$registry = registry
73
73
 
74
74
  // Create and provide a global Stonecrop instance
75
- const stonecrop = new Stonecrop(registry, undefined, options?.client ? { client: options.client } : undefined)
75
+ const stonecrop = new Stonecrop(registry)
76
+ if (options?.client) {
77
+ stonecrop.setClient(options.client)
78
+ }
76
79
  app.provide('$stonecrop', stonecrop)
77
80
  app.config.globalProperties.$stonecrop = stonecrop
78
81
 
@@ -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