@object-ui/core 3.3.0 → 3.3.2

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 (101) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +20 -1
  3. package/dist/actions/ActionRunner.d.ts +9 -0
  4. package/dist/actions/ActionRunner.js +41 -4
  5. package/dist/adapters/ValueDataSource.js +3 -1
  6. package/dist/registry/Registry.d.ts +47 -0
  7. package/dist/registry/Registry.js +92 -0
  8. package/dist/utils/filter-converter.js +25 -5
  9. package/package.json +32 -8
  10. package/.turbo/turbo-build.log +0 -4
  11. package/src/__benchmarks__/core.bench.ts +0 -64
  12. package/src/__tests__/protocols/DndProtocol.test.ts +0 -186
  13. package/src/__tests__/protocols/KeyboardProtocol.test.ts +0 -177
  14. package/src/__tests__/protocols/NotificationProtocol.test.ts +0 -142
  15. package/src/__tests__/protocols/ResponsiveProtocol.test.ts +0 -176
  16. package/src/__tests__/protocols/SharingProtocol.test.ts +0 -188
  17. package/src/actions/ActionEngine.ts +0 -268
  18. package/src/actions/ActionRunner.ts +0 -717
  19. package/src/actions/TransactionManager.ts +0 -521
  20. package/src/actions/UndoManager.ts +0 -215
  21. package/src/actions/__tests__/ActionEngine.test.ts +0 -206
  22. package/src/actions/__tests__/ActionRunner.params.test.ts +0 -134
  23. package/src/actions/__tests__/ActionRunner.test.ts +0 -711
  24. package/src/actions/__tests__/TransactionManager.test.ts +0 -447
  25. package/src/actions/__tests__/UndoManager.test.ts +0 -320
  26. package/src/actions/index.ts +0 -12
  27. package/src/adapters/ApiDataSource.ts +0 -376
  28. package/src/adapters/README.md +0 -180
  29. package/src/adapters/ValueDataSource.ts +0 -459
  30. package/src/adapters/__tests__/ApiDataSource.test.ts +0 -418
  31. package/src/adapters/__tests__/ValueDataSource.test.ts +0 -571
  32. package/src/adapters/__tests__/resolveDataSource.test.ts +0 -144
  33. package/src/adapters/index.ts +0 -15
  34. package/src/adapters/resolveDataSource.ts +0 -79
  35. package/src/builder/__tests__/schema-builder.test.ts +0 -235
  36. package/src/builder/schema-builder.ts +0 -584
  37. package/src/data-scope/DataScopeManager.ts +0 -269
  38. package/src/data-scope/ViewDataProvider.ts +0 -282
  39. package/src/data-scope/__tests__/DataScopeManager.test.ts +0 -211
  40. package/src/data-scope/__tests__/ViewDataProvider.test.ts +0 -270
  41. package/src/data-scope/index.ts +0 -24
  42. package/src/errors/__tests__/errors.test.ts +0 -292
  43. package/src/errors/index.ts +0 -269
  44. package/src/evaluator/ExpressionCache.ts +0 -206
  45. package/src/evaluator/ExpressionContext.ts +0 -118
  46. package/src/evaluator/ExpressionEvaluator.ts +0 -315
  47. package/src/evaluator/FormulaFunctions.ts +0 -398
  48. package/src/evaluator/SafeExpressionParser.ts +0 -893
  49. package/src/evaluator/__tests__/ExpressionCache.test.ts +0 -135
  50. package/src/evaluator/__tests__/ExpressionContext.test.ts +0 -110
  51. package/src/evaluator/__tests__/ExpressionEvaluator.test.ts +0 -558
  52. package/src/evaluator/__tests__/FormulaFunctions.test.ts +0 -447
  53. package/src/evaluator/index.ts +0 -13
  54. package/src/index.ts +0 -38
  55. package/src/protocols/DndProtocol.ts +0 -168
  56. package/src/protocols/KeyboardProtocol.ts +0 -181
  57. package/src/protocols/NotificationProtocol.ts +0 -150
  58. package/src/protocols/ResponsiveProtocol.ts +0 -210
  59. package/src/protocols/SharingProtocol.ts +0 -185
  60. package/src/protocols/index.ts +0 -13
  61. package/src/query/__tests__/query-ast.test.ts +0 -211
  62. package/src/query/__tests__/window-functions.test.ts +0 -275
  63. package/src/query/index.ts +0 -7
  64. package/src/query/query-ast.ts +0 -341
  65. package/src/registry/PluginScopeImpl.ts +0 -259
  66. package/src/registry/PluginSystem.ts +0 -206
  67. package/src/registry/Registry.ts +0 -219
  68. package/src/registry/WidgetRegistry.ts +0 -316
  69. package/src/registry/__tests__/PluginSystem.test.ts +0 -309
  70. package/src/registry/__tests__/Registry.test.ts +0 -293
  71. package/src/registry/__tests__/WidgetRegistry.test.ts +0 -321
  72. package/src/registry/__tests__/plugin-scope-integration.test.ts +0 -283
  73. package/src/theme/ThemeEngine.ts +0 -530
  74. package/src/theme/__tests__/ThemeEngine.test.ts +0 -668
  75. package/src/theme/index.ts +0 -24
  76. package/src/types/index.ts +0 -21
  77. package/src/utils/__tests__/debug-collector.test.ts +0 -102
  78. package/src/utils/__tests__/debug.test.ts +0 -134
  79. package/src/utils/__tests__/expand-fields.test.ts +0 -120
  80. package/src/utils/__tests__/extract-records.test.ts +0 -50
  81. package/src/utils/__tests__/filter-converter.test.ts +0 -118
  82. package/src/utils/__tests__/merge-views-into-objects.test.ts +0 -110
  83. package/src/utils/__tests__/normalize-quick-filter.test.ts +0 -123
  84. package/src/utils/debug-collector.ts +0 -100
  85. package/src/utils/debug.ts +0 -148
  86. package/src/utils/expand-fields.ts +0 -76
  87. package/src/utils/extract-records.ts +0 -33
  88. package/src/utils/filter-converter.ts +0 -133
  89. package/src/utils/merge-views-into-objects.ts +0 -36
  90. package/src/utils/normalize-quick-filter.ts +0 -78
  91. package/src/validation/__tests__/object-validation-engine.test.ts +0 -567
  92. package/src/validation/__tests__/schema-validator.test.ts +0 -118
  93. package/src/validation/__tests__/validation-engine.test.ts +0 -102
  94. package/src/validation/index.ts +0 -10
  95. package/src/validation/schema-validator.ts +0 -344
  96. package/src/validation/validation-engine.ts +0 -528
  97. package/src/validation/validators/index.ts +0 -25
  98. package/src/validation/validators/object-validation-engine.ts +0 -722
  99. package/tsconfig.json +0 -15
  100. package/tsconfig.tsbuildinfo +0 -1
  101. package/vitest.config.ts +0 -2
@@ -1,118 +0,0 @@
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
- });
@@ -1,102 +0,0 @@
1
- /**
2
- * @object-ui/core - Validation Engine Tests
3
- */
4
-
5
- import { describe, it, expect } from 'vitest';
6
- import { ValidationEngine } from '../validation-engine';
7
- import type { AdvancedValidationSchema } from '@object-ui/types';
8
-
9
- describe('ValidationEngine', () => {
10
- const engine = new ValidationEngine();
11
-
12
- describe('Basic Validation', () => {
13
- it('should validate required field', async () => {
14
- const schema: AdvancedValidationSchema = {
15
- field: 'email',
16
- rules: [
17
- {
18
- type: 'required',
19
- message: 'Email is required',
20
- },
21
- ],
22
- };
23
-
24
- const result1 = await engine.validate('', schema);
25
- expect(result1.valid).toBe(false);
26
- expect(result1.errors).toHaveLength(1);
27
- expect(result1.errors[0].message).toBe('Email is required');
28
-
29
- const result2 = await engine.validate('test@example.com', schema);
30
- expect(result2.valid).toBe(true);
31
- expect(result2.errors).toHaveLength(0);
32
- });
33
-
34
- it('should validate email format', async () => {
35
- const schema: AdvancedValidationSchema = {
36
- field: 'email',
37
- rules: [
38
- {
39
- type: 'email',
40
- },
41
- ],
42
- };
43
-
44
- const result1 = await engine.validate('invalid-email', schema);
45
- expect(result1.valid).toBe(false);
46
-
47
- const result2 = await engine.validate('valid@example.com', schema);
48
- expect(result2.valid).toBe(true);
49
- });
50
-
51
- it('should validate phone format', async () => {
52
- const schema: AdvancedValidationSchema = {
53
- field: 'phone',
54
- rules: [
55
- {
56
- type: 'phone',
57
- },
58
- ],
59
- };
60
-
61
- // Valid phone numbers with various formats
62
- const validResult1 = await engine.validate('123-456-7890', schema);
63
- expect(validResult1.valid).toBe(true);
64
-
65
- const validResult2 = await engine.validate('+1 (234) 567-8900', schema);
66
- expect(validResult2.valid).toBe(true);
67
-
68
- const validResult3 = await engine.validate('1234567890', schema);
69
- expect(validResult3.valid).toBe(true);
70
-
71
- // Invalid phone number with letters
72
- const invalidResult = await engine.validate('123-abc-7890', schema);
73
- expect(invalidResult.valid).toBe(false);
74
- });
75
- });
76
-
77
- describe('Custom Validation', () => {
78
- it('should validate with custom sync function', async () => {
79
- const schema: AdvancedValidationSchema = {
80
- field: 'custom',
81
- rules: [
82
- {
83
- type: 'custom',
84
- validator: (value) => {
85
- if (value === 'forbidden') {
86
- return 'This value is forbidden';
87
- }
88
- return true;
89
- },
90
- },
91
- ],
92
- };
93
-
94
- const result1 = await engine.validate('forbidden', schema);
95
- expect(result1.valid).toBe(false);
96
- expect(result1.errors[0].message).toBe('This value is forbidden');
97
-
98
- const result2 = await engine.validate('allowed', schema);
99
- expect(result2.valid).toBe(true);
100
- });
101
- });
102
- });
@@ -1,10 +0,0 @@
1
- /**
2
- * @object-ui/core - Validation Module
3
- *
4
- * Phase 3.5: Validation engine
5
- * ObjectStack Spec v2.0.1: Object-level validation
6
- */
7
-
8
- export * from './validation-engine.js';
9
- export * from './schema-validator.js';
10
- export * from './validators/index.js';
@@ -1,344 +0,0 @@
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
- /**
10
- * @object-ui/core - Schema Validation
11
- *
12
- * Runtime validation utilities for Object UI schemas.
13
- * These utilities help ensure schemas are valid before rendering.
14
- *
15
- * @module validation
16
- * @packageDocumentation
17
- */
18
-
19
- import type { BaseSchema } from '@object-ui/types';
20
-
21
- /**
22
- * Validation error details
23
- */
24
- export interface ValidationError {
25
- path: string;
26
- message: string;
27
- type: 'error' | 'warning';
28
- code?: string;
29
- }
30
-
31
- /**
32
- * Validation result
33
- */
34
- export interface ValidationResult {
35
- valid: boolean;
36
- errors: ValidationError[];
37
- warnings: ValidationError[];
38
- }
39
-
40
- /**
41
- * Validation rules for base schema
42
- */
43
- const BASE_SCHEMA_RULES = {
44
- type: {
45
- required: true,
46
- validate: (value: any) => typeof value === 'string' && value.length > 0,
47
- message: 'type must be a non-empty string'
48
- },
49
- id: {
50
- required: false,
51
- validate: (value: any) => typeof value === 'string',
52
- message: 'id must be a string'
53
- },
54
- className: {
55
- required: false,
56
- validate: (value: any) => typeof value === 'string',
57
- message: 'className must be a string'
58
- },
59
- visible: {
60
- required: false,
61
- validate: (value: any) => typeof value === 'boolean',
62
- message: 'visible must be a boolean'
63
- },
64
- disabled: {
65
- required: false,
66
- validate: (value: any) => typeof value === 'boolean',
67
- message: 'disabled must be a boolean'
68
- }
69
- };
70
-
71
- /**
72
- * Validate a schema against base rules
73
- */
74
- function validateBaseSchema(schema: any, path: string = 'schema'): ValidationError[] {
75
- const errors: ValidationError[] = [];
76
-
77
- if (!schema || typeof schema !== 'object') {
78
- errors.push({
79
- path,
80
- message: 'Schema must be an object',
81
- type: 'error',
82
- code: 'INVALID_SCHEMA'
83
- });
84
- return errors;
85
- }
86
-
87
- // Validate required and optional properties
88
- Object.entries(BASE_SCHEMA_RULES).forEach(([key, rule]) => {
89
- const value = schema[key];
90
-
91
- if (rule.required && value === undefined) {
92
- errors.push({
93
- path: `${path}.${key}`,
94
- message: `${key} is required`,
95
- type: 'error',
96
- code: 'MISSING_REQUIRED'
97
- });
98
- }
99
-
100
- if (value !== undefined && !rule.validate(value)) {
101
- errors.push({
102
- path: `${path}.${key}`,
103
- message: rule.message,
104
- type: 'error',
105
- code: 'INVALID_TYPE'
106
- });
107
- }
108
- });
109
-
110
- return errors;
111
- }
112
-
113
- /**
114
- * Validate CRUD schema specific properties
115
- */
116
- function validateCRUDSchema(schema: any, path: string = 'schema'): ValidationError[] {
117
- const errors: ValidationError[] = [];
118
-
119
- if (schema.type === 'crud') {
120
- // Check required properties for CRUD
121
- if (!schema.columns || !Array.isArray(schema.columns)) {
122
- errors.push({
123
- path: `${path}.columns`,
124
- message: 'CRUD schema requires columns array',
125
- type: 'error',
126
- code: 'MISSING_COLUMNS'
127
- });
128
- }
129
-
130
- if (!schema.api && !schema.dataSource) {
131
- errors.push({
132
- path: `${path}.api`,
133
- message: 'CRUD schema requires api or dataSource',
134
- type: 'warning',
135
- code: 'MISSING_DATA_SOURCE'
136
- });
137
- }
138
-
139
- // Validate columns
140
- if (schema.columns && Array.isArray(schema.columns)) {
141
- schema.columns.forEach((column: any, index: number) => {
142
- if (!column.name) {
143
- errors.push({
144
- path: `${path}.columns[${index}]`,
145
- message: 'Column requires name property',
146
- type: 'error',
147
- code: 'MISSING_COLUMN_NAME'
148
- });
149
- }
150
- });
151
- }
152
-
153
- // Validate fields if present
154
- if (schema.fields && Array.isArray(schema.fields)) {
155
- schema.fields.forEach((field: any, index: number) => {
156
- if (!field.name) {
157
- errors.push({
158
- path: `${path}.fields[${index}]`,
159
- message: 'Field requires name property',
160
- type: 'error',
161
- code: 'MISSING_FIELD_NAME'
162
- });
163
- }
164
- });
165
- }
166
- }
167
-
168
- return errors;
169
- }
170
-
171
- /**
172
- * Validate form schema specific properties
173
- */
174
- function validateFormSchema(schema: any, path: string = 'schema'): ValidationError[] {
175
- const errors: ValidationError[] = [];
176
-
177
- if (schema.type === 'form') {
178
- if (schema.fields && Array.isArray(schema.fields)) {
179
- schema.fields.forEach((field: any, index: number) => {
180
- if (!field.name) {
181
- errors.push({
182
- path: `${path}.fields[${index}]`,
183
- message: 'Form field requires name property',
184
- type: 'error',
185
- code: 'MISSING_FIELD_NAME'
186
- });
187
- }
188
-
189
- // Check for duplicate field names
190
- const duplicates = schema.fields.filter((f: any) => f.name === field.name);
191
- if (duplicates.length > 1) {
192
- errors.push({
193
- path: `${path}.fields[${index}]`,
194
- message: `Duplicate field name: ${field.name}`,
195
- type: 'warning',
196
- code: 'DUPLICATE_FIELD_NAME'
197
- });
198
- }
199
- });
200
- }
201
- }
202
-
203
- return errors;
204
- }
205
-
206
- /**
207
- * Validate child schemas recursively
208
- */
209
- function validateChildren(schema: any, path: string = 'schema'): ValidationError[] {
210
- const errors: ValidationError[] = [];
211
-
212
- const children = schema.children || schema.body;
213
- if (children) {
214
- if (Array.isArray(children)) {
215
- children.forEach((child: any, index: number) => {
216
- if (typeof child === 'object' && child !== null) {
217
- const childResult = validateSchema(child, `${path}.children[${index}]`);
218
- errors.push(...childResult.errors, ...childResult.warnings);
219
- }
220
- });
221
- } else if (typeof children === 'object' && children !== null) {
222
- const childResult = validateSchema(children, `${path}.children`);
223
- errors.push(...childResult.errors, ...childResult.warnings);
224
- }
225
- }
226
-
227
- return errors;
228
- }
229
-
230
- /**
231
- * Validate a complete schema
232
- *
233
- * @param schema - The schema to validate
234
- * @param options - Validation options
235
- * @returns Validation result with errors and warnings
236
- *
237
- * @example
238
- * ```typescript
239
- * const result = validateSchema({
240
- * type: 'form',
241
- * fields: [
242
- * { name: 'email', type: 'input' }
243
- * ]
244
- * });
245
- *
246
- * if (!result.valid) {
247
- * console.error('Validation errors:', result.errors);
248
- * }
249
- * ```
250
- */
251
- export function validateSchema(
252
- schema: any,
253
- path: string = 'schema'
254
- ): ValidationResult {
255
- const allErrors: ValidationError[] = [];
256
-
257
- // Validate base schema
258
- allErrors.push(...validateBaseSchema(schema, path));
259
-
260
- // Validate type-specific schemas
261
- allErrors.push(...validateCRUDSchema(schema, path));
262
- allErrors.push(...validateFormSchema(schema, path));
263
-
264
- // Validate children recursively
265
- allErrors.push(...validateChildren(schema, path));
266
-
267
- const errors = allErrors.filter(e => e.type === 'error');
268
- const warnings = allErrors.filter(e => e.type === 'warning');
269
-
270
- return {
271
- valid: errors.length === 0,
272
- errors,
273
- warnings
274
- };
275
- }
276
-
277
- /**
278
- * Assert that a schema is valid, throwing an error if not
279
- *
280
- * @param schema - The schema to validate
281
- * @throws Error if schema is invalid
282
- *
283
- * @example
284
- * ```typescript
285
- * try {
286
- * assertValidSchema(schema);
287
- * // Schema is valid, continue rendering
288
- * } catch (error) {
289
- * console.error('Invalid schema:', error.message);
290
- * }
291
- * ```
292
- */
293
- export function assertValidSchema(schema: any): asserts schema is BaseSchema {
294
- const result = validateSchema(schema);
295
-
296
- if (!result.valid) {
297
- const errorMessages = result.errors.map(e => `${e.path}: ${e.message}`).join('\n');
298
- throw new Error(`Schema validation failed:\n${errorMessages}`);
299
- }
300
- }
301
-
302
- /**
303
- * Check if a value is a valid schema
304
- *
305
- * @param value - The value to check
306
- * @returns True if the value is a valid schema
307
- *
308
- * @example
309
- * ```typescript
310
- * if (isValidSchema(data)) {
311
- * renderSchema(data);
312
- * }
313
- * ```
314
- */
315
- export function isValidSchema(value: any): value is BaseSchema {
316
- const result = validateSchema(value);
317
- return result.valid;
318
- }
319
-
320
- /**
321
- * Get a human-readable error summary
322
- *
323
- * @param result - The validation result
324
- * @returns Formatted error summary
325
- */
326
- export function formatValidationErrors(result: ValidationResult): string {
327
- const parts: string[] = [];
328
-
329
- if (result.errors.length > 0) {
330
- parts.push('Errors:');
331
- result.errors.forEach(error => {
332
- parts.push(` - ${error.path}: ${error.message}`);
333
- });
334
- }
335
-
336
- if (result.warnings.length > 0) {
337
- parts.push('Warnings:');
338
- result.warnings.forEach(warning => {
339
- parts.push(` - ${warning.path}: ${warning.message}`);
340
- });
341
- }
342
-
343
- return parts.join('\n');
344
- }