@object-ui/core 0.5.0 → 3.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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +28 -0
- package/dist/__benchmarks__/core.bench.d.ts +8 -0
- package/dist/__benchmarks__/core.bench.js +53 -0
- package/dist/actions/ActionRunner.d.ts +228 -4
- package/dist/actions/ActionRunner.js +397 -45
- package/dist/actions/TransactionManager.d.ts +193 -0
- package/dist/actions/TransactionManager.js +410 -0
- package/dist/actions/index.d.ts +1 -0
- package/dist/actions/index.js +1 -0
- package/dist/adapters/ApiDataSource.d.ts +69 -0
- package/dist/adapters/ApiDataSource.js +293 -0
- package/dist/adapters/ValueDataSource.d.ts +55 -0
- package/dist/adapters/ValueDataSource.js +287 -0
- package/dist/adapters/index.d.ts +3 -0
- package/dist/adapters/index.js +5 -2
- package/dist/adapters/resolveDataSource.d.ts +40 -0
- package/dist/adapters/resolveDataSource.js +59 -0
- package/dist/data-scope/DataScopeManager.d.ts +127 -0
- package/dist/data-scope/DataScopeManager.js +229 -0
- package/dist/data-scope/index.d.ts +10 -0
- package/dist/data-scope/index.js +10 -0
- package/dist/errors/index.d.ts +75 -0
- package/dist/errors/index.js +224 -0
- package/dist/evaluator/ExpressionEvaluator.d.ts +11 -1
- package/dist/evaluator/ExpressionEvaluator.js +32 -8
- package/dist/evaluator/FormulaFunctions.d.ts +58 -0
- package/dist/evaluator/FormulaFunctions.js +350 -0
- package/dist/evaluator/index.d.ts +1 -0
- package/dist/evaluator/index.js +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -2
- package/dist/query/query-ast.d.ts +2 -2
- package/dist/query/query-ast.js +3 -3
- package/dist/registry/Registry.d.ts +10 -0
- package/dist/registry/Registry.js +9 -2
- package/dist/registry/WidgetRegistry.d.ts +120 -0
- package/dist/registry/WidgetRegistry.js +275 -0
- package/dist/theme/ThemeEngine.d.ts +105 -0
- package/dist/theme/ThemeEngine.js +469 -0
- package/dist/theme/index.d.ts +8 -0
- package/dist/theme/index.js +8 -0
- package/dist/utils/debug.d.ts +31 -0
- package/dist/utils/debug.js +62 -0
- package/dist/validation/index.d.ts +1 -1
- package/dist/validation/index.js +1 -1
- package/dist/validation/validation-engine.d.ts +19 -1
- package/dist/validation/validation-engine.js +74 -3
- package/dist/validation/validators/index.d.ts +1 -1
- package/dist/validation/validators/index.js +1 -1
- package/dist/validation/validators/object-validation-engine.d.ts +2 -2
- package/dist/validation/validators/object-validation-engine.js +1 -1
- package/package.json +4 -3
- package/src/__benchmarks__/core.bench.ts +64 -0
- package/src/actions/ActionRunner.ts +577 -55
- package/src/actions/TransactionManager.ts +521 -0
- package/src/actions/__tests__/ActionRunner.params.test.ts +134 -0
- package/src/actions/__tests__/ActionRunner.test.ts +711 -0
- package/src/actions/__tests__/TransactionManager.test.ts +447 -0
- package/src/actions/index.ts +1 -0
- package/src/adapters/ApiDataSource.ts +349 -0
- package/src/adapters/ValueDataSource.ts +332 -0
- package/src/adapters/__tests__/ApiDataSource.test.ts +418 -0
- package/src/adapters/__tests__/ValueDataSource.test.ts +325 -0
- package/src/adapters/__tests__/resolveDataSource.test.ts +144 -0
- package/src/adapters/index.ts +6 -1
- package/src/adapters/resolveDataSource.ts +79 -0
- package/src/builder/__tests__/schema-builder.test.ts +235 -0
- package/src/data-scope/DataScopeManager.ts +269 -0
- package/src/data-scope/__tests__/DataScopeManager.test.ts +211 -0
- package/src/data-scope/index.ts +16 -0
- package/src/errors/__tests__/errors.test.ts +292 -0
- package/src/errors/index.ts +270 -0
- package/src/evaluator/ExpressionEvaluator.ts +34 -8
- package/src/evaluator/FormulaFunctions.ts +398 -0
- package/src/evaluator/__tests__/ExpressionContext.test.ts +110 -0
- package/src/evaluator/__tests__/FormulaFunctions.test.ts +447 -0
- package/src/evaluator/index.ts +1 -0
- package/src/index.ts +6 -3
- package/src/query/__tests__/window-functions.test.ts +1 -1
- package/src/query/query-ast.ts +3 -3
- package/src/registry/Registry.ts +19 -2
- package/src/registry/WidgetRegistry.ts +316 -0
- package/src/registry/__tests__/WidgetRegistry.test.ts +321 -0
- package/src/theme/ThemeEngine.ts +530 -0
- package/src/theme/__tests__/ThemeEngine.test.ts +668 -0
- package/src/theme/index.ts +24 -0
- package/src/utils/__tests__/debug.test.ts +83 -0
- package/src/utils/debug.ts +66 -0
- package/src/validation/__tests__/object-validation-engine.test.ts +1 -1
- package/src/validation/__tests__/schema-validator.test.ts +118 -0
- package/src/validation/index.ts +1 -1
- package/src/validation/validation-engine.ts +70 -3
- package/src/validation/validators/index.ts +1 -1
- package/src/validation/validators/object-validation-engine.ts +2 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
10
|
+
import { debugLog, debugTime, debugTimeEnd } from '../debug';
|
|
11
|
+
|
|
12
|
+
describe('Debug Utilities', () => {
|
|
13
|
+
let consoleSpy: ReturnType<typeof vi.spyOn>;
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
consoleSpy.mockRestore();
|
|
21
|
+
(globalThis as any).OBJECTUI_DEBUG = undefined;
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('debugLog', () => {
|
|
25
|
+
it('should not log when debug is disabled', () => {
|
|
26
|
+
(globalThis as any).OBJECTUI_DEBUG = false;
|
|
27
|
+
debugLog('schema', 'test message');
|
|
28
|
+
expect(consoleSpy).not.toHaveBeenCalled();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should log when OBJECTUI_DEBUG is true', () => {
|
|
32
|
+
(globalThis as any).OBJECTUI_DEBUG = true;
|
|
33
|
+
debugLog('schema', 'Resolving component');
|
|
34
|
+
expect(consoleSpy).toHaveBeenCalledWith('[ObjectUI Debug][schema] Resolving component');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should log with data when provided', () => {
|
|
38
|
+
(globalThis as any).OBJECTUI_DEBUG = true;
|
|
39
|
+
debugLog('registry', 'Registered', { type: 'Button' });
|
|
40
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
41
|
+
'[ObjectUI Debug][registry] Registered',
|
|
42
|
+
{ type: 'Button' }
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should not log when debug is undefined', () => {
|
|
47
|
+
debugLog('action', 'test');
|
|
48
|
+
expect(consoleSpy).not.toHaveBeenCalled();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe('debugTime / debugTimeEnd', () => {
|
|
53
|
+
it('should not log timing when debug is disabled', () => {
|
|
54
|
+
(globalThis as any).OBJECTUI_DEBUG = false;
|
|
55
|
+
debugTime('test-timer');
|
|
56
|
+
debugTimeEnd('test-timer');
|
|
57
|
+
expect(consoleSpy).not.toHaveBeenCalled();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should measure and log elapsed time when debug is enabled', () => {
|
|
61
|
+
(globalThis as any).OBJECTUI_DEBUG = true;
|
|
62
|
+
debugTime('render-test');
|
|
63
|
+
|
|
64
|
+
// Simulate some delay via a busy loop
|
|
65
|
+
const start = performance.now();
|
|
66
|
+
while (performance.now() - start < 5) {
|
|
67
|
+
// wait ~5ms
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
debugTimeEnd('render-test');
|
|
71
|
+
expect(consoleSpy).toHaveBeenCalledTimes(1);
|
|
72
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
73
|
+
expect.stringMatching(/^\[ObjectUI Debug\]\[perf\] render-test: \d+\.\d{2}ms$/)
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should not log if debugTimeEnd is called without debugTime', () => {
|
|
78
|
+
(globalThis as any).OBJECTUI_DEBUG = true;
|
|
79
|
+
debugTimeEnd('nonexistent');
|
|
80
|
+
expect(consoleSpy).not.toHaveBeenCalled();
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
type DebugCategory = 'schema' | 'registry' | 'expression' | 'action' | 'plugin' | 'render';
|
|
10
|
+
|
|
11
|
+
function isDebugEnabled(): boolean {
|
|
12
|
+
try {
|
|
13
|
+
const g = typeof globalThis !== 'undefined' && (globalThis as any).OBJECTUI_DEBUG;
|
|
14
|
+
return (
|
|
15
|
+
(g === true || g === 'true') ||
|
|
16
|
+
(typeof process !== 'undefined' && process.env?.OBJECTUI_DEBUG === 'true')
|
|
17
|
+
);
|
|
18
|
+
} catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Log a debug message when OBJECTUI_DEBUG is enabled.
|
|
25
|
+
* No-op in production or when debug mode is off.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* // Enable debug mode
|
|
30
|
+
* globalThis.OBJECTUI_DEBUG = true;
|
|
31
|
+
*
|
|
32
|
+
* debugLog('schema', 'Resolving component', { type: 'Button' });
|
|
33
|
+
* // [ObjectUI Debug][schema] Resolving component { type: 'Button' }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export function debugLog(category: DebugCategory, message: string, data?: unknown): void {
|
|
37
|
+
if (!isDebugEnabled()) return;
|
|
38
|
+
if (data !== undefined) {
|
|
39
|
+
console.log(`[ObjectUI Debug][${category}] ${message}`, data);
|
|
40
|
+
} else {
|
|
41
|
+
console.log(`[ObjectUI Debug][${category}] ${message}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const timers = new Map<string, number>();
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Start a debug timer. Pair with {@link debugTimeEnd}.
|
|
49
|
+
*/
|
|
50
|
+
export function debugTime(label: string): void {
|
|
51
|
+
if (!isDebugEnabled()) return;
|
|
52
|
+
timers.set(label, performance.now());
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* End a debug timer and log the elapsed time.
|
|
57
|
+
*/
|
|
58
|
+
export function debugTimeEnd(label: string): void {
|
|
59
|
+
if (!isDebugEnabled()) return;
|
|
60
|
+
const start = timers.get(label);
|
|
61
|
+
if (start !== undefined) {
|
|
62
|
+
const elapsed = (performance.now() - start).toFixed(2);
|
|
63
|
+
console.log(`[ObjectUI Debug][perf] ${label}: ${elapsed}ms`);
|
|
64
|
+
timers.delete(label);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -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
|
+
});
|
package/src/validation/index.ts
CHANGED
|
@@ -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
|
}
|
|
@@ -342,7 +401,15 @@ export class ValidationEngine {
|
|
|
342
401
|
*/
|
|
343
402
|
private evaluateCondition(condition: any, values: Record<string, any>): boolean {
|
|
344
403
|
if (typeof condition === 'function') {
|
|
345
|
-
console.warn(
|
|
404
|
+
console.warn(
|
|
405
|
+
'Function-based conditions are deprecated and will be removed. Use declarative conditions instead.\n\n' +
|
|
406
|
+
' Migration:\n' +
|
|
407
|
+
' // Before (deprecated):\n' +
|
|
408
|
+
' { condition: (values) => values.age > 18 }\n\n' +
|
|
409
|
+
' // After:\n' +
|
|
410
|
+
' { condition: { field: "age", operator: ">", value: 18 } }\n\n' +
|
|
411
|
+
' See: https://github.com/objectstack-ai/objectui/blob/main/MIGRATION_GUIDE.md'
|
|
412
|
+
);
|
|
346
413
|
return false; // Security: reject function-based conditions
|
|
347
414
|
}
|
|
348
415
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
/**
|
|
10
10
|
* @object-ui/core - Object-Level Validation Engine
|
|
11
11
|
*
|
|
12
|
-
* ObjectStack Spec
|
|
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
|
|
259
|
+
* Implements ObjectStack Spec v2.0.1 validation framework
|
|
260
260
|
*/
|
|
261
261
|
export class ObjectValidationEngine {
|
|
262
262
|
private expressionEvaluator: ValidationExpressionEvaluator;
|