@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,59 @@
1
+ /**
2
+ * ObjectUI — resolveDataSource
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
+ * Factory function to create the right DataSource from a ViewData config.
9
+ */
10
+ import { ApiDataSource } from './ApiDataSource.js';
11
+ import { ValueDataSource } from './ValueDataSource.js';
12
+ /**
13
+ * Resolve a ViewData configuration into a concrete DataSource instance.
14
+ *
15
+ * - `provider: 'object'` → returns `fallback` (the context DataSource — typically ObjectStackAdapter)
16
+ * - `provider: 'api'` → returns a new `ApiDataSource`
17
+ * - `provider: 'value'` → returns a new `ValueDataSource`
18
+ *
19
+ * @param viewData - The ViewData configuration from the schema
20
+ * @param fallback - The default DataSource from context (for `provider: 'object'`)
21
+ * @param options - Additional options for adapter construction
22
+ * @returns A DataSource instance, or null if neither viewData nor fallback is available
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * const ds = resolveDataSource(
27
+ * { provider: 'api', read: { url: '/api/users' } },
28
+ * contextDataSource,
29
+ * );
30
+ * const result = await ds.find('users');
31
+ * ```
32
+ */
33
+ export function resolveDataSource(viewData, fallback, options) {
34
+ if (!viewData) {
35
+ return fallback ?? null;
36
+ }
37
+ switch (viewData.provider) {
38
+ case 'object':
39
+ // Delegate to the context DataSource (ObjectStackAdapter, etc.)
40
+ return fallback ?? null;
41
+ case 'api': {
42
+ const config = {
43
+ read: viewData.read,
44
+ write: viewData.write,
45
+ fetch: options?.fetch,
46
+ defaultHeaders: options?.defaultHeaders,
47
+ };
48
+ return new ApiDataSource(config);
49
+ }
50
+ case 'value':
51
+ return new ValueDataSource({
52
+ items: (viewData.items ?? []),
53
+ idField: options?.idField,
54
+ });
55
+ default:
56
+ // Unknown provider — fall back to context
57
+ return fallback ?? null;
58
+ }
59
+ }
@@ -0,0 +1,127 @@
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
+ * @object-ui/core - DataScope Manager
10
+ *
11
+ * Runtime implementation of the DataContext interface for managing
12
+ * named data scopes. Provides row-level data access control and
13
+ * reactive data state management within the UI component tree.
14
+ *
15
+ * @module data-scope
16
+ * @packageDocumentation
17
+ */
18
+ import type { DataScope, DataContext, DataSource } from '@object-ui/types';
19
+ /**
20
+ * Row-level filter for restricting data access within a scope
21
+ */
22
+ export interface RowLevelFilter {
23
+ /** Field to filter on */
24
+ field: string;
25
+ /** Filter operator */
26
+ operator: 'eq' | 'ne' | 'gt' | 'lt' | 'gte' | 'lte' | 'in' | 'nin' | 'contains';
27
+ /** Filter value */
28
+ value: any;
29
+ }
30
+ /**
31
+ * Configuration for creating a data scope
32
+ */
33
+ export interface DataScopeConfig {
34
+ /** Data source instance */
35
+ dataSource?: DataSource;
36
+ /** Initial data */
37
+ data?: any;
38
+ /** Row-level filters to apply */
39
+ filters?: RowLevelFilter[];
40
+ /** Whether this scope is read-only */
41
+ readOnly?: boolean;
42
+ }
43
+ /**
44
+ * DataScopeManager — Runtime implementation of DataContext.
45
+ *
46
+ * Manages named data scopes for the component tree, providing:
47
+ * - Scope registration and lookup
48
+ * - Row-level security via filters
49
+ * - Data state management (data, loading, error)
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * const manager = new DataScopeManager();
54
+ * manager.registerScope('contacts', {
55
+ * dataSource: myDataSource,
56
+ * data: [],
57
+ * });
58
+ * const scope = manager.getScope('contacts');
59
+ * ```
60
+ */
61
+ export declare class DataScopeManager implements DataContext {
62
+ scopes: Record<string, DataScope>;
63
+ private filters;
64
+ private readOnlyScopes;
65
+ private listeners;
66
+ /**
67
+ * Register a data scope
68
+ */
69
+ registerScope(name: string, scope: DataScope): void;
70
+ /**
71
+ * Register a data scope with configuration
72
+ */
73
+ registerScopeWithConfig(name: string, config: DataScopeConfig): void;
74
+ /**
75
+ * Get a data scope by name
76
+ */
77
+ getScope(name: string): DataScope | undefined;
78
+ /**
79
+ * Remove a data scope
80
+ */
81
+ removeScope(name: string): void;
82
+ /**
83
+ * Check if a scope is read-only
84
+ */
85
+ isReadOnly(name: string): boolean;
86
+ /**
87
+ * Get row-level filters for a scope
88
+ */
89
+ getFilters(name: string): RowLevelFilter[];
90
+ /**
91
+ * Set row-level filters for a scope
92
+ */
93
+ setFilters(name: string, filters: RowLevelFilter[]): void;
94
+ /**
95
+ * Apply row-level filters to a dataset
96
+ */
97
+ applyFilters(name: string, data: any[]): any[];
98
+ /**
99
+ * Update data in a scope
100
+ */
101
+ updateScopeData(name: string, data: any): void;
102
+ /**
103
+ * Update loading state for a scope
104
+ */
105
+ updateScopeLoading(name: string, loading: boolean): void;
106
+ /**
107
+ * Update error state for a scope
108
+ */
109
+ updateScopeError(name: string, error: Error | string | null): void;
110
+ /**
111
+ * Subscribe to scope changes
112
+ */
113
+ onScopeChange(name: string, listener: (scope: DataScope) => void): () => void;
114
+ /**
115
+ * Get all registered scope names
116
+ */
117
+ getScopeNames(): string[];
118
+ /**
119
+ * Clear all scopes
120
+ */
121
+ clear(): void;
122
+ private notifyListeners;
123
+ }
124
+ /**
125
+ * Default DataScopeManager instance
126
+ */
127
+ export declare const defaultDataScopeManager: DataScopeManager;
@@ -0,0 +1,229 @@
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
+ * DataScopeManager — Runtime implementation of DataContext.
10
+ *
11
+ * Manages named data scopes for the component tree, providing:
12
+ * - Scope registration and lookup
13
+ * - Row-level security via filters
14
+ * - Data state management (data, loading, error)
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const manager = new DataScopeManager();
19
+ * manager.registerScope('contacts', {
20
+ * dataSource: myDataSource,
21
+ * data: [],
22
+ * });
23
+ * const scope = manager.getScope('contacts');
24
+ * ```
25
+ */
26
+ export class DataScopeManager {
27
+ constructor() {
28
+ Object.defineProperty(this, "scopes", {
29
+ enumerable: true,
30
+ configurable: true,
31
+ writable: true,
32
+ value: {}
33
+ });
34
+ Object.defineProperty(this, "filters", {
35
+ enumerable: true,
36
+ configurable: true,
37
+ writable: true,
38
+ value: {}
39
+ });
40
+ Object.defineProperty(this, "readOnlyScopes", {
41
+ enumerable: true,
42
+ configurable: true,
43
+ writable: true,
44
+ value: new Set()
45
+ });
46
+ Object.defineProperty(this, "listeners", {
47
+ enumerable: true,
48
+ configurable: true,
49
+ writable: true,
50
+ value: new Map()
51
+ });
52
+ }
53
+ /**
54
+ * Register a data scope
55
+ */
56
+ registerScope(name, scope) {
57
+ this.scopes[name] = scope;
58
+ this.notifyListeners(name, scope);
59
+ }
60
+ /**
61
+ * Register a data scope with configuration
62
+ */
63
+ registerScopeWithConfig(name, config) {
64
+ const scope = {
65
+ dataSource: config.dataSource,
66
+ data: config.data,
67
+ loading: false,
68
+ error: null,
69
+ };
70
+ if (config.filters) {
71
+ this.filters[name] = config.filters;
72
+ }
73
+ if (config.readOnly) {
74
+ this.readOnlyScopes.add(name);
75
+ }
76
+ this.scopes[name] = scope;
77
+ this.notifyListeners(name, scope);
78
+ }
79
+ /**
80
+ * Get a data scope by name
81
+ */
82
+ getScope(name) {
83
+ return this.scopes[name];
84
+ }
85
+ /**
86
+ * Remove a data scope
87
+ */
88
+ removeScope(name) {
89
+ delete this.scopes[name];
90
+ delete this.filters[name];
91
+ this.readOnlyScopes.delete(name);
92
+ this.listeners.delete(name);
93
+ }
94
+ /**
95
+ * Check if a scope is read-only
96
+ */
97
+ isReadOnly(name) {
98
+ return this.readOnlyScopes.has(name);
99
+ }
100
+ /**
101
+ * Get row-level filters for a scope
102
+ */
103
+ getFilters(name) {
104
+ return this.filters[name] || [];
105
+ }
106
+ /**
107
+ * Set row-level filters for a scope
108
+ */
109
+ setFilters(name, filters) {
110
+ this.filters[name] = filters;
111
+ }
112
+ /**
113
+ * Apply row-level filters to a dataset
114
+ */
115
+ applyFilters(name, data) {
116
+ const scopeFilters = this.filters[name];
117
+ if (!scopeFilters || scopeFilters.length === 0) {
118
+ return data;
119
+ }
120
+ return data.filter(row => {
121
+ return scopeFilters.every(filter => {
122
+ const fieldValue = row[filter.field];
123
+ return evaluateFilter(fieldValue, filter.operator, filter.value);
124
+ });
125
+ });
126
+ }
127
+ /**
128
+ * Update data in a scope
129
+ */
130
+ updateScopeData(name, data) {
131
+ const scope = this.scopes[name];
132
+ if (!scope)
133
+ return;
134
+ if (this.readOnlyScopes.has(name)) {
135
+ throw new Error(`Cannot update read-only scope: ${name}`);
136
+ }
137
+ scope.data = data;
138
+ this.notifyListeners(name, scope);
139
+ }
140
+ /**
141
+ * Update loading state for a scope
142
+ */
143
+ updateScopeLoading(name, loading) {
144
+ const scope = this.scopes[name];
145
+ if (!scope)
146
+ return;
147
+ scope.loading = loading;
148
+ this.notifyListeners(name, scope);
149
+ }
150
+ /**
151
+ * Update error state for a scope
152
+ */
153
+ updateScopeError(name, error) {
154
+ const scope = this.scopes[name];
155
+ if (!scope)
156
+ return;
157
+ scope.error = error;
158
+ this.notifyListeners(name, scope);
159
+ }
160
+ /**
161
+ * Subscribe to scope changes
162
+ */
163
+ onScopeChange(name, listener) {
164
+ if (!this.listeners.has(name)) {
165
+ this.listeners.set(name, []);
166
+ }
167
+ this.listeners.get(name).push(listener);
168
+ return () => {
169
+ const arr = this.listeners.get(name);
170
+ if (arr) {
171
+ const idx = arr.indexOf(listener);
172
+ if (idx >= 0)
173
+ arr.splice(idx, 1);
174
+ }
175
+ };
176
+ }
177
+ /**
178
+ * Get all registered scope names
179
+ */
180
+ getScopeNames() {
181
+ return Object.keys(this.scopes);
182
+ }
183
+ /**
184
+ * Clear all scopes
185
+ */
186
+ clear() {
187
+ this.scopes = {};
188
+ this.filters = {};
189
+ this.readOnlyScopes.clear();
190
+ this.listeners.clear();
191
+ }
192
+ notifyListeners(name, scope) {
193
+ const arr = this.listeners.get(name);
194
+ if (arr) {
195
+ arr.forEach(listener => listener(scope));
196
+ }
197
+ }
198
+ }
199
+ /**
200
+ * Evaluate a single filter condition against a field value
201
+ */
202
+ function evaluateFilter(fieldValue, operator, filterValue) {
203
+ switch (operator) {
204
+ case 'eq':
205
+ return fieldValue === filterValue;
206
+ case 'ne':
207
+ return fieldValue !== filterValue;
208
+ case 'gt':
209
+ return fieldValue > filterValue;
210
+ case 'lt':
211
+ return fieldValue < filterValue;
212
+ case 'gte':
213
+ return fieldValue >= filterValue;
214
+ case 'lte':
215
+ return fieldValue <= filterValue;
216
+ case 'in':
217
+ return Array.isArray(filterValue) && filterValue.includes(fieldValue);
218
+ case 'nin':
219
+ return Array.isArray(filterValue) && !filterValue.includes(fieldValue);
220
+ case 'contains':
221
+ return typeof fieldValue === 'string' && fieldValue.includes(String(filterValue));
222
+ default:
223
+ return true;
224
+ }
225
+ }
226
+ /**
227
+ * Default DataScopeManager instance
228
+ */
229
+ export const defaultDataScopeManager = new DataScopeManager();
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @object-ui/core - DataScope Module
3
+ *
4
+ * Runtime data scope management for row-level security and
5
+ * reactive data state within the UI component tree.
6
+ *
7
+ * @module data-scope
8
+ * @packageDocumentation
9
+ */
10
+ export { DataScopeManager, defaultDataScopeManager, type RowLevelFilter, type DataScopeConfig, } from './DataScopeManager.js';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @object-ui/core - DataScope Module
3
+ *
4
+ * Runtime data scope management for row-level security and
5
+ * reactive data state within the UI component tree.
6
+ *
7
+ * @module data-scope
8
+ * @packageDocumentation
9
+ */
10
+ export { DataScopeManager, defaultDataScopeManager, } from './DataScopeManager.js';
@@ -16,6 +16,7 @@
16
16
  */
17
17
  import { ExpressionContext } from './ExpressionContext.js';
18
18
  import { ExpressionCache } from './ExpressionCache.js';
19
+ import { FormulaFunctions } from './FormulaFunctions.js';
19
20
  /**
20
21
  * Options for expression evaluation
21
22
  */
@@ -41,7 +42,8 @@ export interface EvaluationOptions {
41
42
  export declare class ExpressionEvaluator {
42
43
  private context;
43
44
  private cache;
44
- constructor(context?: ExpressionContext | Record<string, any>, cache?: ExpressionCache);
45
+ private formulas;
46
+ constructor(context?: ExpressionContext | Record<string, any>, cache?: ExpressionCache, formulas?: FormulaFunctions);
45
47
  /**
46
48
  * Evaluate a string that may contain template expressions like ${...}
47
49
  *
@@ -106,6 +108,14 @@ export declare class ExpressionEvaluator {
106
108
  * Clear the expression cache
107
109
  */
108
110
  clearCache(): void;
111
+ /**
112
+ * Get the formula functions registry
113
+ */
114
+ getFormulas(): FormulaFunctions;
115
+ /**
116
+ * Register a custom formula function
117
+ */
118
+ registerFunction(name: string, fn: (...args: any[]) => any): void;
109
119
  }
110
120
  /**
111
121
  * Convenience function to quickly evaluate an expression
@@ -16,11 +16,12 @@
16
16
  */
17
17
  import { ExpressionContext } from './ExpressionContext.js';
18
18
  import { ExpressionCache } from './ExpressionCache.js';
19
+ import { FormulaFunctions } from './FormulaFunctions.js';
19
20
  /**
20
21
  * Expression evaluator for dynamic UI expressions
21
22
  */
22
23
  export class ExpressionEvaluator {
23
- constructor(context, cache) {
24
+ constructor(context, cache, formulas) {
24
25
  Object.defineProperty(this, "context", {
25
26
  enumerable: true,
26
27
  configurable: true,
@@ -33,6 +34,12 @@ export class ExpressionEvaluator {
33
34
  writable: true,
34
35
  value: void 0
35
36
  });
37
+ Object.defineProperty(this, "formulas", {
38
+ enumerable: true,
39
+ configurable: true,
40
+ writable: true,
41
+ value: void 0
42
+ });
36
43
  if (context instanceof ExpressionContext) {
37
44
  this.context = context;
38
45
  }
@@ -41,6 +48,7 @@ export class ExpressionEvaluator {
41
48
  }
42
49
  // Use provided cache or create a new one
43
50
  this.cache = cache || new ExpressionCache();
51
+ this.formulas = formulas || new FormulaFunctions();
44
52
  }
45
53
  /**
46
54
  * Evaluate a string that may contain template expressions like ${...}
@@ -114,9 +122,12 @@ export class ExpressionEvaluator {
114
122
  try {
115
123
  // Create a safe evaluation function
116
124
  const contextObj = this.context.toObject();
125
+ // Inject formula functions into the evaluation context
126
+ const formulaObj = this.formulas.toObject();
127
+ const mergedContext = { ...formulaObj, ...contextObj };
117
128
  // Build safe function with context variables
118
- const varNames = Object.keys(contextObj);
119
- const varValues = Object.values(contextObj);
129
+ const varNames = Object.keys(mergedContext);
130
+ const varValues = Object.values(mergedContext);
120
131
  // Use cached compilation
121
132
  const compiled = this.cache.compile(expression, varNames);
122
133
  // Execute with context values
@@ -184,8 +195,8 @@ export class ExpressionEvaluator {
184
195
  * Create a new evaluator with additional context data
185
196
  */
186
197
  withContext(data) {
187
- // Share the cache with the new evaluator for maximum efficiency
188
- return new ExpressionEvaluator(this.context.createChild(data), this.cache);
198
+ // Share the cache and formulas with the new evaluator for maximum efficiency
199
+ return new ExpressionEvaluator(this.context.createChild(data), this.cache, this.formulas);
189
200
  }
190
201
  /**
191
202
  * Get cache statistics (useful for debugging and optimization)
@@ -199,22 +210,35 @@ export class ExpressionEvaluator {
199
210
  clearCache() {
200
211
  this.cache.clear();
201
212
  }
213
+ /**
214
+ * Get the formula functions registry
215
+ */
216
+ getFormulas() {
217
+ return this.formulas;
218
+ }
219
+ /**
220
+ * Register a custom formula function
221
+ */
222
+ registerFunction(name, fn) {
223
+ this.formulas.register(name, fn);
224
+ }
202
225
  }
203
226
  /**
204
- * Shared global cache for convenience functions
227
+ * Shared global cache and formulas for convenience functions
205
228
  */
206
229
  const globalCache = new ExpressionCache();
230
+ const globalFormulas = new FormulaFunctions();
207
231
  /**
208
232
  * Convenience function to quickly evaluate an expression
209
233
  */
210
234
  export function evaluateExpression(expression, context = {}, options = {}) {
211
- const evaluator = new ExpressionEvaluator(context, globalCache);
235
+ const evaluator = new ExpressionEvaluator(context, globalCache, globalFormulas);
212
236
  return evaluator.evaluate(expression, options);
213
237
  }
214
238
  /**
215
239
  * Convenience function to evaluate a condition
216
240
  */
217
241
  export function evaluateCondition(condition, context = {}) {
218
- const evaluator = new ExpressionEvaluator(context, globalCache);
242
+ const evaluator = new ExpressionEvaluator(context, globalCache, globalFormulas);
219
243
  return evaluator.evaluateCondition(condition);
220
244
  }
@@ -0,0 +1,58 @@
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
+ * @object-ui/core - Formula Functions
10
+ *
11
+ * Built-in formula functions for the expression engine.
12
+ * Provides aggregation, date, logic, and string functions
13
+ * compatible with low-code platform expression evaluation.
14
+ *
15
+ * @module evaluator
16
+ * @packageDocumentation
17
+ */
18
+ /**
19
+ * A formula function that can be registered with the expression evaluator
20
+ */
21
+ export type FormulaFunction = (...args: any[]) => any;
22
+ /**
23
+ * Registry of built-in formula functions
24
+ */
25
+ export declare class FormulaFunctions {
26
+ private functions;
27
+ constructor();
28
+ /**
29
+ * Register a custom formula function
30
+ */
31
+ register(name: string, fn: FormulaFunction): void;
32
+ /**
33
+ * Get a formula function by name
34
+ */
35
+ get(name: string): FormulaFunction | undefined;
36
+ /**
37
+ * Check if a function is registered
38
+ */
39
+ has(name: string): boolean;
40
+ /**
41
+ * Get all registered function names
42
+ */
43
+ getNames(): string[];
44
+ /**
45
+ * Get all functions as a plain object (for injection into expression context)
46
+ */
47
+ toObject(): Record<string, FormulaFunction>;
48
+ /**
49
+ * Register all default built-in functions
50
+ */
51
+ private registerDefaults;
52
+ private registerAggregationFunctions;
53
+ private registerDateFunctions;
54
+ private registerLogicFunctions;
55
+ private registerStringFunctions;
56
+ private registerStringSearchFunctions;
57
+ private registerStatisticalFunctions;
58
+ }