@object-ui/core 0.5.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +11 -0
  3. package/dist/actions/ActionRunner.d.ts +228 -4
  4. package/dist/actions/ActionRunner.js +397 -45
  5. package/dist/actions/TransactionManager.d.ts +193 -0
  6. package/dist/actions/TransactionManager.js +410 -0
  7. package/dist/actions/index.d.ts +1 -0
  8. package/dist/actions/index.js +1 -0
  9. package/dist/adapters/ApiDataSource.d.ts +69 -0
  10. package/dist/adapters/ApiDataSource.js +293 -0
  11. package/dist/adapters/ValueDataSource.d.ts +55 -0
  12. package/dist/adapters/ValueDataSource.js +287 -0
  13. package/dist/adapters/index.d.ts +3 -0
  14. package/dist/adapters/index.js +5 -2
  15. package/dist/adapters/resolveDataSource.d.ts +40 -0
  16. package/dist/adapters/resolveDataSource.js +59 -0
  17. package/dist/data-scope/DataScopeManager.d.ts +127 -0
  18. package/dist/data-scope/DataScopeManager.js +229 -0
  19. package/dist/data-scope/index.d.ts +10 -0
  20. package/dist/data-scope/index.js +10 -0
  21. package/dist/evaluator/ExpressionEvaluator.d.ts +11 -1
  22. package/dist/evaluator/ExpressionEvaluator.js +32 -8
  23. package/dist/evaluator/FormulaFunctions.d.ts +58 -0
  24. package/dist/evaluator/FormulaFunctions.js +350 -0
  25. package/dist/evaluator/index.d.ts +1 -0
  26. package/dist/evaluator/index.js +1 -0
  27. package/dist/index.d.ts +4 -0
  28. package/dist/index.js +4 -2
  29. package/dist/query/query-ast.d.ts +2 -2
  30. package/dist/query/query-ast.js +3 -3
  31. package/dist/registry/Registry.d.ts +10 -0
  32. package/dist/registry/Registry.js +2 -1
  33. package/dist/registry/WidgetRegistry.d.ts +120 -0
  34. package/dist/registry/WidgetRegistry.js +275 -0
  35. package/dist/theme/ThemeEngine.d.ts +82 -0
  36. package/dist/theme/ThemeEngine.js +400 -0
  37. package/dist/theme/index.d.ts +8 -0
  38. package/dist/theme/index.js +8 -0
  39. package/dist/validation/index.d.ts +1 -1
  40. package/dist/validation/index.js +1 -1
  41. package/dist/validation/validation-engine.d.ts +19 -1
  42. package/dist/validation/validation-engine.js +67 -2
  43. package/dist/validation/validators/index.d.ts +1 -1
  44. package/dist/validation/validators/index.js +1 -1
  45. package/dist/validation/validators/object-validation-engine.d.ts +2 -2
  46. package/dist/validation/validators/object-validation-engine.js +1 -1
  47. package/package.json +4 -3
  48. package/src/actions/ActionRunner.ts +577 -55
  49. package/src/actions/TransactionManager.ts +521 -0
  50. package/src/actions/__tests__/ActionRunner.params.test.ts +134 -0
  51. package/src/actions/__tests__/ActionRunner.test.ts +711 -0
  52. package/src/actions/__tests__/TransactionManager.test.ts +447 -0
  53. package/src/actions/index.ts +1 -0
  54. package/src/adapters/ApiDataSource.ts +349 -0
  55. package/src/adapters/ValueDataSource.ts +332 -0
  56. package/src/adapters/__tests__/ApiDataSource.test.ts +418 -0
  57. package/src/adapters/__tests__/ValueDataSource.test.ts +325 -0
  58. package/src/adapters/__tests__/resolveDataSource.test.ts +144 -0
  59. package/src/adapters/index.ts +6 -1
  60. package/src/adapters/resolveDataSource.ts +79 -0
  61. package/src/builder/__tests__/schema-builder.test.ts +235 -0
  62. package/src/data-scope/DataScopeManager.ts +269 -0
  63. package/src/data-scope/__tests__/DataScopeManager.test.ts +211 -0
  64. package/src/data-scope/index.ts +16 -0
  65. package/src/evaluator/ExpressionEvaluator.ts +34 -8
  66. package/src/evaluator/FormulaFunctions.ts +398 -0
  67. package/src/evaluator/__tests__/ExpressionContext.test.ts +110 -0
  68. package/src/evaluator/__tests__/FormulaFunctions.test.ts +447 -0
  69. package/src/evaluator/index.ts +1 -0
  70. package/src/index.ts +4 -3
  71. package/src/query/__tests__/window-functions.test.ts +1 -1
  72. package/src/query/query-ast.ts +3 -3
  73. package/src/registry/Registry.ts +12 -1
  74. package/src/registry/WidgetRegistry.ts +316 -0
  75. package/src/registry/__tests__/WidgetRegistry.test.ts +321 -0
  76. package/src/theme/ThemeEngine.ts +452 -0
  77. package/src/theme/__tests__/ThemeEngine.test.ts +606 -0
  78. package/src/theme/index.ts +22 -0
  79. package/src/validation/__tests__/object-validation-engine.test.ts +1 -1
  80. package/src/validation/__tests__/schema-validator.test.ts +118 -0
  81. package/src/validation/index.ts +1 -1
  82. package/src/validation/validation-engine.ts +61 -2
  83. package/src/validation/validators/index.ts +1 -1
  84. package/src/validation/validators/object-validation-engine.ts +2 -2
  85. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,118 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ validateSchema,
4
+ assertValidSchema,
5
+ isValidSchema,
6
+ formatValidationErrors,
7
+ } from '../../validation/schema-validator';
8
+
9
+ describe('schema-validator', () => {
10
+ describe('validateSchema', () => {
11
+ it('validates a minimal valid schema', () => {
12
+ const result = validateSchema({ type: 'form' });
13
+ expect(result.valid).toBe(true);
14
+ expect(result.errors).toHaveLength(0);
15
+ });
16
+
17
+ it('rejects schema without type', () => {
18
+ const result = validateSchema({} as any);
19
+ expect(result.valid).toBe(false);
20
+ expect(result.errors.length).toBeGreaterThan(0);
21
+ });
22
+
23
+ it('validates CRUD schema with columns', () => {
24
+ const result = validateSchema({
25
+ type: 'crud',
26
+ columns: [{ name: 'id', label: 'ID' }],
27
+ api: '/api/users',
28
+ });
29
+ expect(result.valid).toBe(true);
30
+ });
31
+
32
+ it('warns about CRUD without columns', () => {
33
+ const result = validateSchema({ type: 'crud' });
34
+ const hasColumnsIssue = [...result.errors, ...result.warnings].some(
35
+ (e) => e.message.toLowerCase().includes('column'),
36
+ );
37
+ expect(hasColumnsIssue).toBe(true);
38
+ });
39
+
40
+ it('validates form with fields', () => {
41
+ const result = validateSchema({
42
+ type: 'form',
43
+ fields: [
44
+ { name: 'email', label: 'Email', type: 'string' },
45
+ ],
46
+ });
47
+ expect(result.valid).toBe(true);
48
+ });
49
+
50
+ it('detects duplicate field names in forms', () => {
51
+ const result = validateSchema({
52
+ type: 'form',
53
+ fields: [
54
+ { name: 'email', label: 'Email', type: 'string' },
55
+ { name: 'email', label: 'Email 2', type: 'string' },
56
+ ],
57
+ });
58
+ const hasDuplicateWarning = [...result.errors, ...result.warnings].some(
59
+ (e) => e.message.toLowerCase().includes('duplicate'),
60
+ );
61
+ expect(hasDuplicateWarning).toBe(true);
62
+ });
63
+
64
+ it('validates nested children', () => {
65
+ const result = validateSchema({
66
+ type: 'grid',
67
+ children: [
68
+ { type: 'button', label: 'OK' },
69
+ ],
70
+ });
71
+ expect(result.valid).toBe(true);
72
+ });
73
+ });
74
+
75
+ describe('isValidSchema', () => {
76
+ it('returns true for valid schema', () => {
77
+ expect(isValidSchema({ type: 'form' })).toBe(true);
78
+ });
79
+
80
+ it('returns false for invalid schema', () => {
81
+ expect(isValidSchema({})).toBe(false);
82
+ });
83
+
84
+ it('returns false for empty object', () => {
85
+ expect(isValidSchema({} as any)).toBe(false);
86
+ });
87
+
88
+ it('returns false for non-object values', () => {
89
+ expect(isValidSchema('string' as any)).toBe(false);
90
+ expect(isValidSchema(42 as any)).toBe(false);
91
+ });
92
+ });
93
+
94
+ describe('assertValidSchema', () => {
95
+ it('does not throw for valid schema', () => {
96
+ expect(() => assertValidSchema({ type: 'form' })).not.toThrow();
97
+ });
98
+
99
+ it('throws for invalid schema', () => {
100
+ expect(() => assertValidSchema({} as any)).toThrow();
101
+ });
102
+ });
103
+
104
+ describe('formatValidationErrors', () => {
105
+ it('formats validation errors', () => {
106
+ const result = validateSchema({} as any);
107
+ const formatted = formatValidationErrors(result);
108
+ expect(typeof formatted).toBe('string');
109
+ expect(formatted.length).toBeGreaterThan(0);
110
+ });
111
+
112
+ it('returns empty string for valid schemas', () => {
113
+ const result = validateSchema({ type: 'form' });
114
+ const formatted = formatValidationErrors(result);
115
+ expect(formatted).toBe('');
116
+ });
117
+ });
118
+ });
@@ -2,7 +2,7 @@
2
2
  * @object-ui/core - Validation Module
3
3
  *
4
4
  * Phase 3.5: Validation engine
5
- * ObjectStack Spec v0.7.1: Object-level validation
5
+ * ObjectStack Spec v2.0.1: Object-level validation
6
6
  */
7
7
 
8
8
  export * from './validation-engine.js';
@@ -34,6 +34,39 @@ import type {
34
34
  * Validation Engine - Executes validation rules
35
35
  */
36
36
  export class ValidationEngine {
37
+ private customValidators = new Map<string, ValidationFunction>();
38
+ private customAsyncValidators = new Map<string, AsyncValidationFunction>();
39
+
40
+ /**
41
+ * Register a custom synchronous validator by name
42
+ */
43
+ registerValidator(name: string, fn: ValidationFunction): void {
44
+ this.customValidators.set(name, fn);
45
+ }
46
+
47
+ /**
48
+ * Register a custom asynchronous validator by name
49
+ */
50
+ registerAsyncValidator(name: string, fn: AsyncValidationFunction): void {
51
+ this.customAsyncValidators.set(name, fn);
52
+ }
53
+
54
+ /**
55
+ * Check if a custom validator is registered
56
+ */
57
+ hasValidator(name: string): boolean {
58
+ return this.customValidators.has(name) || this.customAsyncValidators.has(name);
59
+ }
60
+
61
+ /**
62
+ * Get all registered custom validator names
63
+ */
64
+ getValidatorNames(): string[] {
65
+ return [
66
+ ...Array.from(this.customValidators.keys()),
67
+ ...Array.from(this.customAsyncValidators.keys()),
68
+ ];
69
+ }
37
70
  /**
38
71
  * Validate a value against validation schema
39
72
  */
@@ -80,7 +113,7 @@ export class ValidationEngine {
80
113
  rule: AdvancedValidationRule,
81
114
  context?: ValidationContext
82
115
  ): Promise<string | null> {
83
- // Custom async validator
116
+ // Custom async validator (inline)
84
117
  if (rule.async_validator) {
85
118
  const result = await rule.async_validator(value, context);
86
119
  if (result === false) {
@@ -92,7 +125,7 @@ export class ValidationEngine {
92
125
  return null;
93
126
  }
94
127
 
95
- // Custom sync validator
128
+ // Custom sync validator (inline)
96
129
  if (rule.validator) {
97
130
  const result = rule.validator(value, context);
98
131
  if (result === false) {
@@ -104,6 +137,32 @@ export class ValidationEngine {
104
137
  return null;
105
138
  }
106
139
 
140
+ // Registered custom async validator (by name)
141
+ const registeredAsync = this.customAsyncValidators.get(rule.type);
142
+ if (registeredAsync) {
143
+ const result = await registeredAsync(value, context);
144
+ if (result === false) {
145
+ return rule.message || 'Async validation failed';
146
+ }
147
+ if (typeof result === 'string') {
148
+ return result;
149
+ }
150
+ return null;
151
+ }
152
+
153
+ // Registered custom sync validator (by name)
154
+ const registeredSync = this.customValidators.get(rule.type);
155
+ if (registeredSync) {
156
+ const result = registeredSync(value, context);
157
+ if (result === false) {
158
+ return rule.message || 'Validation failed';
159
+ }
160
+ if (typeof result === 'string') {
161
+ return result;
162
+ }
163
+ return null;
164
+ }
165
+
107
166
  // Built-in validators
108
167
  return this.validateBuiltInRule(value, rule, context);
109
168
  }
@@ -9,7 +9,7 @@
9
9
  /**
10
10
  * @object-ui/core - Validators
11
11
  *
12
- * ObjectStack Spec v0.7.1 compliant validators
12
+ * ObjectStack Spec v2.0.1 compliant validators
13
13
  *
14
14
  * @module validators
15
15
  * @packageDocumentation
@@ -9,7 +9,7 @@
9
9
  /**
10
10
  * @object-ui/core - Object-Level Validation Engine
11
11
  *
12
- * ObjectStack Spec v0.7.1 compliant validation engine for object-level validation rules.
12
+ * ObjectStack Spec v2.0.1 compliant validation engine for object-level validation rules.
13
13
  * Supports all 9 validation types from the specification:
14
14
  * - ScriptValidation
15
15
  * - UniquenessValidation
@@ -256,7 +256,7 @@ class SimpleExpressionEvaluator implements ValidationExpressionEvaluator {
256
256
 
257
257
  /**
258
258
  * Object-Level Validation Engine
259
- * Implements ObjectStack Spec v0.7.1 validation framework
259
+ * Implements ObjectStack Spec v2.0.1 validation framework
260
260
  */
261
261
  export class ObjectValidationEngine {
262
262
  private expressionEvaluator: ValidationExpressionEvaluator;