@objectql/core 1.8.4 → 1.9.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/CHANGELOG.md +17 -0
- package/dist/formula-engine.d.ts +95 -0
- package/dist/formula-engine.js +426 -0
- package/dist/formula-engine.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/repository.d.ts +6 -0
- package/dist/repository.js +65 -2
- package/dist/repository.js.map +1 -1
- package/package.json +2 -2
- package/src/formula-engine.ts +564 -0
- package/src/index.ts +1 -0
- package/src/repository.ts +80 -3
- package/test/formula-engine.test.ts +717 -0
- package/test/formula-integration.test.ts +278 -0
- package/test/mock-driver.ts +4 -0
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @objectql/core
|
|
2
2
|
|
|
3
|
+
## 1.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Major documentation update and VS Code extension improvements
|
|
8
|
+
- Completely revised getting started documentation with emphasis on YAML-based metadata approach
|
|
9
|
+
- Improved quick start instructions for better onboarding experience
|
|
10
|
+
- Added comprehensive VS Code extension recommendations to example projects
|
|
11
|
+
- Enhanced developer experience with .vscode/extensions.json files
|
|
12
|
+
- Updated README to highlight the importance of the ObjectQL VS Code extension
|
|
13
|
+
- Added detailed documentation for all core features and API endpoints
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Updated dependencies
|
|
18
|
+
- @objectql/types@1.9.0
|
|
19
|
+
|
|
3
20
|
## 1.8.4
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formula Engine Implementation
|
|
3
|
+
*
|
|
4
|
+
* Evaluates formula expressions defined in object metadata.
|
|
5
|
+
* Formulas are read-only calculated fields computed at query time.
|
|
6
|
+
*
|
|
7
|
+
* @see @objectql/types/formula for type definitions
|
|
8
|
+
* @see docs/spec/formula.md for complete specification
|
|
9
|
+
*/
|
|
10
|
+
import { FormulaContext, FormulaEvaluationResult, FormulaEvaluationOptions, FormulaDataType, FormulaMetadata, FormulaEngineConfig, FormulaCustomFunction } from '@objectql/types';
|
|
11
|
+
/**
|
|
12
|
+
* Formula Engine for evaluating JavaScript-style expressions
|
|
13
|
+
*
|
|
14
|
+
* Features:
|
|
15
|
+
* - Field references (e.g., `quantity * unit_price`)
|
|
16
|
+
* - System variables (e.g., `$today`, `$current_user.id`)
|
|
17
|
+
* - Lookup chains (e.g., `account.owner.name`)
|
|
18
|
+
* - Built-in functions (Math, String, Date methods)
|
|
19
|
+
* - Conditional logic (ternary, if/else)
|
|
20
|
+
* - Safe sandbox execution
|
|
21
|
+
*/
|
|
22
|
+
export declare class FormulaEngine {
|
|
23
|
+
private config;
|
|
24
|
+
private customFunctions;
|
|
25
|
+
constructor(config?: FormulaEngineConfig);
|
|
26
|
+
/**
|
|
27
|
+
* Evaluate a formula expression
|
|
28
|
+
*
|
|
29
|
+
* @param expression - The JavaScript expression to evaluate
|
|
30
|
+
* @param context - Runtime context with record data, system variables, user context
|
|
31
|
+
* @param dataType - Expected return data type
|
|
32
|
+
* @param options - Evaluation options
|
|
33
|
+
* @returns Evaluation result with value, type, success flag, and optional error
|
|
34
|
+
*/
|
|
35
|
+
evaluate(expression: string, context: FormulaContext, dataType: FormulaDataType, options?: FormulaEvaluationOptions): FormulaEvaluationResult;
|
|
36
|
+
/**
|
|
37
|
+
* Build the evaluation context from FormulaContext
|
|
38
|
+
* Creates a safe object with field values, system variables, and user context
|
|
39
|
+
*/
|
|
40
|
+
private buildEvaluationContext;
|
|
41
|
+
/**
|
|
42
|
+
* Execute the expression in a sandboxed environment
|
|
43
|
+
*
|
|
44
|
+
* SECURITY NOTE: Uses Function constructor for dynamic evaluation.
|
|
45
|
+
* While we check for blocked operations, this is not a complete security sandbox.
|
|
46
|
+
* For production use with untrusted formulas, consider using a proper sandboxing library
|
|
47
|
+
* like vm2 or implementing an AST-based evaluator.
|
|
48
|
+
*/
|
|
49
|
+
private executeExpression;
|
|
50
|
+
/**
|
|
51
|
+
* Wrap expression to handle both expression and statement styles
|
|
52
|
+
*/
|
|
53
|
+
private wrapExpression;
|
|
54
|
+
/**
|
|
55
|
+
* Execute function with timeout protection
|
|
56
|
+
*
|
|
57
|
+
* NOTE: This synchronous implementation **cannot** pre-emptively interrupt execution.
|
|
58
|
+
* To avoid giving a false sense of safety, any positive finite timeout configuration
|
|
59
|
+
* is rejected up-front. Callers must not rely on timeout-based protection in this
|
|
60
|
+
* runtime; instead, formulas must be written to be fast and side-effect free.
|
|
61
|
+
*/
|
|
62
|
+
private executeWithTimeout;
|
|
63
|
+
/**
|
|
64
|
+
* Coerce the result value to the expected data type
|
|
65
|
+
*/
|
|
66
|
+
private coerceValue;
|
|
67
|
+
/**
|
|
68
|
+
* Extract metadata from a formula expression
|
|
69
|
+
* Analyzes the expression to determine dependencies and complexity
|
|
70
|
+
*/
|
|
71
|
+
extractMetadata(fieldName: string, expression: string, dataType: FormulaDataType): FormulaMetadata;
|
|
72
|
+
/**
|
|
73
|
+
* Check if identifier is a JavaScript keyword or built-in
|
|
74
|
+
*/
|
|
75
|
+
private isJavaScriptKeyword;
|
|
76
|
+
/**
|
|
77
|
+
* Estimate formula complexity based on heuristics
|
|
78
|
+
*/
|
|
79
|
+
private estimateComplexity;
|
|
80
|
+
/**
|
|
81
|
+
* Register a custom function for use in formulas
|
|
82
|
+
*/
|
|
83
|
+
registerFunction(name: string, func: FormulaCustomFunction): void;
|
|
84
|
+
/**
|
|
85
|
+
* Validate a formula expression without executing it
|
|
86
|
+
*
|
|
87
|
+
* SECURITY NOTE: Uses Function constructor for syntax validation.
|
|
88
|
+
* This doesn't execute the code but creates a function object.
|
|
89
|
+
* For stricter validation, consider using a parser library like @babel/parser.
|
|
90
|
+
*/
|
|
91
|
+
validate(expression: string): {
|
|
92
|
+
valid: boolean;
|
|
93
|
+
errors: string[];
|
|
94
|
+
};
|
|
95
|
+
}
|
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Formula Engine Implementation
|
|
4
|
+
*
|
|
5
|
+
* Evaluates formula expressions defined in object metadata.
|
|
6
|
+
* Formulas are read-only calculated fields computed at query time.
|
|
7
|
+
*
|
|
8
|
+
* @see @objectql/types/formula for type definitions
|
|
9
|
+
* @see docs/spec/formula.md for complete specification
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.FormulaEngine = void 0;
|
|
13
|
+
const types_1 = require("@objectql/types");
|
|
14
|
+
/**
|
|
15
|
+
* Formula Engine for evaluating JavaScript-style expressions
|
|
16
|
+
*
|
|
17
|
+
* Features:
|
|
18
|
+
* - Field references (e.g., `quantity * unit_price`)
|
|
19
|
+
* - System variables (e.g., `$today`, `$current_user.id`)
|
|
20
|
+
* - Lookup chains (e.g., `account.owner.name`)
|
|
21
|
+
* - Built-in functions (Math, String, Date methods)
|
|
22
|
+
* - Conditional logic (ternary, if/else)
|
|
23
|
+
* - Safe sandbox execution
|
|
24
|
+
*/
|
|
25
|
+
class FormulaEngine {
|
|
26
|
+
constructor(config = {}) {
|
|
27
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
28
|
+
this.config = {
|
|
29
|
+
enable_cache: (_a = config.enable_cache) !== null && _a !== void 0 ? _a : false,
|
|
30
|
+
cache_ttl: (_b = config.cache_ttl) !== null && _b !== void 0 ? _b : 300,
|
|
31
|
+
max_execution_time: (_c = config.max_execution_time) !== null && _c !== void 0 ? _c : 0, // 0 means no timeout enforcement
|
|
32
|
+
enable_monitoring: (_d = config.enable_monitoring) !== null && _d !== void 0 ? _d : false,
|
|
33
|
+
custom_functions: (_e = config.custom_functions) !== null && _e !== void 0 ? _e : {},
|
|
34
|
+
sandbox: {
|
|
35
|
+
enabled: (_g = (_f = config.sandbox) === null || _f === void 0 ? void 0 : _f.enabled) !== null && _g !== void 0 ? _g : true,
|
|
36
|
+
allowed_globals: (_j = (_h = config.sandbox) === null || _h === void 0 ? void 0 : _h.allowed_globals) !== null && _j !== void 0 ? _j : ['Math', 'String', 'Number', 'Boolean', 'Date', 'Array', 'Object'],
|
|
37
|
+
blocked_operations: (_l = (_k = config.sandbox) === null || _k === void 0 ? void 0 : _k.blocked_operations) !== null && _l !== void 0 ? _l : ['eval', 'Function', 'require', 'import'],
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
this.customFunctions = this.config.custom_functions || {};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Evaluate a formula expression
|
|
44
|
+
*
|
|
45
|
+
* @param expression - The JavaScript expression to evaluate
|
|
46
|
+
* @param context - Runtime context with record data, system variables, user context
|
|
47
|
+
* @param dataType - Expected return data type
|
|
48
|
+
* @param options - Evaluation options
|
|
49
|
+
* @returns Evaluation result with value, type, success flag, and optional error
|
|
50
|
+
*/
|
|
51
|
+
evaluate(expression, context, dataType, options = {}) {
|
|
52
|
+
var _a, _b;
|
|
53
|
+
const startTime = Date.now();
|
|
54
|
+
const timeout = (_b = (_a = options.timeout) !== null && _a !== void 0 ? _a : this.config.max_execution_time) !== null && _b !== void 0 ? _b : 0;
|
|
55
|
+
try {
|
|
56
|
+
// Validate expression
|
|
57
|
+
if (!expression || expression.trim() === '') {
|
|
58
|
+
throw new types_1.FormulaError(types_1.FormulaErrorType.SYNTAX_ERROR, 'Formula expression cannot be empty', expression);
|
|
59
|
+
}
|
|
60
|
+
// Prepare evaluation context
|
|
61
|
+
const evalContext = this.buildEvaluationContext(context);
|
|
62
|
+
// Execute expression with timeout
|
|
63
|
+
const value = this.executeExpression(expression, evalContext, timeout, options);
|
|
64
|
+
// Validate and coerce result type
|
|
65
|
+
const coercedValue = this.coerceValue(value, dataType, expression);
|
|
66
|
+
const executionTime = Date.now() - startTime;
|
|
67
|
+
return {
|
|
68
|
+
value: coercedValue,
|
|
69
|
+
type: dataType,
|
|
70
|
+
success: true,
|
|
71
|
+
execution_time: executionTime,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
const executionTime = Date.now() - startTime;
|
|
76
|
+
if (error instanceof types_1.FormulaError) {
|
|
77
|
+
return {
|
|
78
|
+
value: null,
|
|
79
|
+
type: dataType,
|
|
80
|
+
success: false,
|
|
81
|
+
error: error.message,
|
|
82
|
+
stack: error.stack,
|
|
83
|
+
execution_time: executionTime,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
// Wrap unknown errors
|
|
87
|
+
return {
|
|
88
|
+
value: null,
|
|
89
|
+
type: dataType,
|
|
90
|
+
success: false,
|
|
91
|
+
error: error instanceof Error ? error.message : String(error),
|
|
92
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
93
|
+
execution_time: executionTime,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Build the evaluation context from FormulaContext
|
|
99
|
+
* Creates a safe object with field values, system variables, and user context
|
|
100
|
+
*/
|
|
101
|
+
buildEvaluationContext(context) {
|
|
102
|
+
const evalContext = {};
|
|
103
|
+
// Add all record fields to context
|
|
104
|
+
for (const [key, value] of Object.entries(context.record)) {
|
|
105
|
+
evalContext[key] = value;
|
|
106
|
+
}
|
|
107
|
+
// Add system variables with $ prefix
|
|
108
|
+
evalContext.$today = context.system.today;
|
|
109
|
+
evalContext.$now = context.system.now;
|
|
110
|
+
evalContext.$year = context.system.year;
|
|
111
|
+
evalContext.$month = context.system.month;
|
|
112
|
+
evalContext.$day = context.system.day;
|
|
113
|
+
evalContext.$hour = context.system.hour;
|
|
114
|
+
evalContext.$minute = context.system.minute;
|
|
115
|
+
evalContext.$second = context.system.second;
|
|
116
|
+
// Add current user context
|
|
117
|
+
evalContext.$current_user = context.current_user;
|
|
118
|
+
// Add record context flags
|
|
119
|
+
evalContext.$is_new = context.is_new;
|
|
120
|
+
evalContext.$record_id = context.record_id;
|
|
121
|
+
// Add custom functions
|
|
122
|
+
for (const [name, func] of Object.entries(this.customFunctions)) {
|
|
123
|
+
evalContext[name] = func;
|
|
124
|
+
}
|
|
125
|
+
return evalContext;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Execute the expression in a sandboxed environment
|
|
129
|
+
*
|
|
130
|
+
* SECURITY NOTE: Uses Function constructor for dynamic evaluation.
|
|
131
|
+
* While we check for blocked operations, this is not a complete security sandbox.
|
|
132
|
+
* For production use with untrusted formulas, consider using a proper sandboxing library
|
|
133
|
+
* like vm2 or implementing an AST-based evaluator.
|
|
134
|
+
*/
|
|
135
|
+
executeExpression(expression, context, timeout, options) {
|
|
136
|
+
var _a;
|
|
137
|
+
// Check for blocked operations
|
|
138
|
+
// NOTE: This is a basic check using string matching. It will have false positives
|
|
139
|
+
// (e.g., a field named 'evaluation' contains 'eval') and can be bypassed
|
|
140
|
+
// (e.g., using this['eval'] or globalThis['eval']).
|
|
141
|
+
// For production security with untrusted formulas, use AST parsing or vm2.
|
|
142
|
+
if ((_a = this.config.sandbox) === null || _a === void 0 ? void 0 : _a.enabled) {
|
|
143
|
+
const blockedOps = this.config.sandbox.blocked_operations || [];
|
|
144
|
+
for (const op of blockedOps) {
|
|
145
|
+
if (expression.includes(op)) {
|
|
146
|
+
throw new types_1.FormulaError(types_1.FormulaErrorType.SECURITY_VIOLATION, `Blocked operation detected: ${op}`, expression);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
// Create function parameters from context keys
|
|
152
|
+
const paramNames = Object.keys(context);
|
|
153
|
+
const paramValues = Object.values(context);
|
|
154
|
+
// Wrap expression to handle both expression-style and statement-style formulas
|
|
155
|
+
const wrappedExpression = this.wrapExpression(expression);
|
|
156
|
+
// Create and execute function
|
|
157
|
+
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
158
|
+
const func = new Function(...paramNames, wrappedExpression);
|
|
159
|
+
// Execute with timeout protection
|
|
160
|
+
const result = this.executeWithTimeout(func, paramValues, timeout);
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
if (error instanceof types_1.FormulaError) {
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
// Parse JavaScript errors
|
|
168
|
+
const err = error;
|
|
169
|
+
if (error instanceof ReferenceError) {
|
|
170
|
+
throw new types_1.FormulaError(types_1.FormulaErrorType.FIELD_NOT_FOUND, `Referenced field not found: ${err.message}`, expression, { original_error: err.message });
|
|
171
|
+
}
|
|
172
|
+
if (error instanceof TypeError) {
|
|
173
|
+
throw new types_1.FormulaError(types_1.FormulaErrorType.TYPE_ERROR, `Type error in formula: ${err.message}`, expression, { original_error: err.message });
|
|
174
|
+
}
|
|
175
|
+
if (error instanceof SyntaxError) {
|
|
176
|
+
throw new types_1.FormulaError(types_1.FormulaErrorType.SYNTAX_ERROR, `Syntax error in formula: ${err.message}`, expression, { original_error: err.message });
|
|
177
|
+
}
|
|
178
|
+
throw new types_1.FormulaError(types_1.FormulaErrorType.RUNTIME_ERROR, `Runtime error: ${error instanceof Error ? err.message : String(error)}`, expression, { original_error: error instanceof Error ? err.message : String(error) });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Wrap expression to handle both expression and statement styles
|
|
183
|
+
*/
|
|
184
|
+
wrapExpression(expression) {
|
|
185
|
+
const trimmed = expression.trim();
|
|
186
|
+
// If it contains a return statement or is a block, use as-is
|
|
187
|
+
if (trimmed.includes('return ') || (trimmed.startsWith('{') && trimmed.endsWith('}'))) {
|
|
188
|
+
return trimmed;
|
|
189
|
+
}
|
|
190
|
+
// If it's multi-line with if/else, wrap in a function body
|
|
191
|
+
if (trimmed.includes('\n') || trimmed.match(/if\s*\(/)) {
|
|
192
|
+
return trimmed;
|
|
193
|
+
}
|
|
194
|
+
// Otherwise, treat as expression and return it
|
|
195
|
+
return `return (${trimmed});`;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Execute function with timeout protection
|
|
199
|
+
*
|
|
200
|
+
* NOTE: This synchronous implementation **cannot** pre-emptively interrupt execution.
|
|
201
|
+
* To avoid giving a false sense of safety, any positive finite timeout configuration
|
|
202
|
+
* is rejected up-front. Callers must not rely on timeout-based protection in this
|
|
203
|
+
* runtime; instead, formulas must be written to be fast and side-effect free.
|
|
204
|
+
*/
|
|
205
|
+
executeWithTimeout(func, args, timeout) {
|
|
206
|
+
// Reject any positive finite timeout to avoid misleading "protection" semantics.
|
|
207
|
+
if (Number.isFinite(timeout) && timeout > 0) {
|
|
208
|
+
throw new types_1.FormulaError(types_1.FormulaErrorType.TIMEOUT, 'Formula timeout enforcement is not supported for synchronous execution. ' +
|
|
209
|
+
'Remove the timeout configuration or migrate to an async/isolated runtime ' +
|
|
210
|
+
'that can safely interrupt long-running formulas.', '', { requestedTimeoutMs: timeout });
|
|
211
|
+
}
|
|
212
|
+
// No timeout configured (or non-positive/invalid value): execute directly.
|
|
213
|
+
return func(...args);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Coerce the result value to the expected data type
|
|
217
|
+
*/
|
|
218
|
+
coerceValue(value, dataType, expression) {
|
|
219
|
+
// Handle null/undefined
|
|
220
|
+
if (value === null || value === undefined) {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
try {
|
|
224
|
+
switch (dataType) {
|
|
225
|
+
case 'number':
|
|
226
|
+
case 'currency':
|
|
227
|
+
case 'percent':
|
|
228
|
+
if (typeof value === 'number') {
|
|
229
|
+
// Check for division by zero result
|
|
230
|
+
if (!isFinite(value)) {
|
|
231
|
+
throw new types_1.FormulaError(types_1.FormulaErrorType.DIVISION_BY_ZERO, 'Formula resulted in Infinity or NaN (possible division by zero)', expression);
|
|
232
|
+
}
|
|
233
|
+
return value;
|
|
234
|
+
}
|
|
235
|
+
if (typeof value === 'string') {
|
|
236
|
+
const num = Number(value);
|
|
237
|
+
if (isNaN(num)) {
|
|
238
|
+
throw new types_1.FormulaError(types_1.FormulaErrorType.TYPE_ERROR, `Cannot convert "${value}" to number`, expression);
|
|
239
|
+
}
|
|
240
|
+
return num;
|
|
241
|
+
}
|
|
242
|
+
if (typeof value === 'boolean') {
|
|
243
|
+
return value ? 1 : 0;
|
|
244
|
+
}
|
|
245
|
+
throw new types_1.FormulaError(types_1.FormulaErrorType.TYPE_ERROR, `Expected number, got ${typeof value}`, expression);
|
|
246
|
+
case 'text':
|
|
247
|
+
return String(value);
|
|
248
|
+
case 'boolean':
|
|
249
|
+
return Boolean(value);
|
|
250
|
+
case 'date':
|
|
251
|
+
case 'datetime':
|
|
252
|
+
if (value instanceof Date) {
|
|
253
|
+
return value;
|
|
254
|
+
}
|
|
255
|
+
if (typeof value === 'string') {
|
|
256
|
+
const date = new Date(value);
|
|
257
|
+
if (isNaN(date.getTime())) {
|
|
258
|
+
throw new types_1.FormulaError(types_1.FormulaErrorType.TYPE_ERROR, `Cannot convert "${value}" to date`, expression);
|
|
259
|
+
}
|
|
260
|
+
return date;
|
|
261
|
+
}
|
|
262
|
+
if (typeof value === 'number') {
|
|
263
|
+
return new Date(value);
|
|
264
|
+
}
|
|
265
|
+
throw new types_1.FormulaError(types_1.FormulaErrorType.TYPE_ERROR, `Expected date, got ${typeof value}`, expression);
|
|
266
|
+
default:
|
|
267
|
+
return value;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
if (error instanceof types_1.FormulaError) {
|
|
272
|
+
throw error;
|
|
273
|
+
}
|
|
274
|
+
throw new types_1.FormulaError(types_1.FormulaErrorType.TYPE_ERROR, `Type coercion failed: ${error instanceof Error ? error.message : String(error)}`, expression);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Extract metadata from a formula expression
|
|
279
|
+
* Analyzes the expression to determine dependencies and complexity
|
|
280
|
+
*/
|
|
281
|
+
extractMetadata(fieldName, expression, dataType) {
|
|
282
|
+
const dependencies = [];
|
|
283
|
+
const lookupChains = [];
|
|
284
|
+
const systemVariables = [];
|
|
285
|
+
const validationErrors = [];
|
|
286
|
+
try {
|
|
287
|
+
// Extract system variables (start with $)
|
|
288
|
+
const systemVarPattern = /\$([a-z_][a-z0-9_]*)/gi;
|
|
289
|
+
const systemMatches = Array.from(expression.matchAll(systemVarPattern));
|
|
290
|
+
for (const match of systemMatches) {
|
|
291
|
+
const sysVar = '$' + match[1];
|
|
292
|
+
if (!systemVariables.includes(sysVar)) {
|
|
293
|
+
systemVariables.push(sysVar);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
// Extract field references (but not system variables or keywords)
|
|
297
|
+
const fieldPattern = /\b([a-z_][a-z0-9_]*)\b/gi;
|
|
298
|
+
const matches = Array.from(expression.matchAll(fieldPattern));
|
|
299
|
+
for (const match of matches) {
|
|
300
|
+
const identifier = match[1];
|
|
301
|
+
// Skip JavaScript keywords and built-ins
|
|
302
|
+
if (this.isJavaScriptKeyword(identifier)) {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
// Field references
|
|
306
|
+
if (!dependencies.includes(identifier)) {
|
|
307
|
+
dependencies.push(identifier);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
// Extract lookup chains (e.g., account.owner.name)
|
|
311
|
+
const lookupPattern = /\b([a-z_][a-z0-9_]*(?:\.[a-z_][a-z0-9_]*)+)\b/gi;
|
|
312
|
+
const lookupMatches = Array.from(expression.matchAll(lookupPattern));
|
|
313
|
+
for (const match of lookupMatches) {
|
|
314
|
+
const chain = match[1];
|
|
315
|
+
if (!lookupChains.includes(chain)) {
|
|
316
|
+
lookupChains.push(chain);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
// Basic validation
|
|
320
|
+
if (!expression.trim()) {
|
|
321
|
+
validationErrors.push('Expression cannot be empty');
|
|
322
|
+
}
|
|
323
|
+
// Estimate complexity
|
|
324
|
+
const complexity = this.estimateComplexity(expression);
|
|
325
|
+
return {
|
|
326
|
+
field_name: fieldName,
|
|
327
|
+
expression,
|
|
328
|
+
data_type: dataType,
|
|
329
|
+
dependencies,
|
|
330
|
+
lookup_chains: lookupChains,
|
|
331
|
+
system_variables: systemVariables,
|
|
332
|
+
is_valid: validationErrors.length === 0,
|
|
333
|
+
validation_errors: validationErrors.length > 0 ? validationErrors : undefined,
|
|
334
|
+
complexity,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
return {
|
|
339
|
+
field_name: fieldName,
|
|
340
|
+
expression,
|
|
341
|
+
data_type: dataType,
|
|
342
|
+
dependencies: [],
|
|
343
|
+
lookup_chains: [],
|
|
344
|
+
system_variables: [],
|
|
345
|
+
is_valid: false,
|
|
346
|
+
validation_errors: [
|
|
347
|
+
error instanceof Error ? error.message : String(error),
|
|
348
|
+
],
|
|
349
|
+
complexity: 'simple',
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Check if identifier is a JavaScript keyword or built-in
|
|
355
|
+
*/
|
|
356
|
+
isJavaScriptKeyword(identifier) {
|
|
357
|
+
const keywords = new Set([
|
|
358
|
+
'if', 'else', 'for', 'while', 'do', 'switch', 'case', 'break', 'continue',
|
|
359
|
+
'return', 'function', 'var', 'let', 'const', 'true', 'false', 'null',
|
|
360
|
+
'undefined', 'this', 'new', 'typeof', 'instanceof', 'in', 'of',
|
|
361
|
+
'Math', 'String', 'Number', 'Boolean', 'Date', 'Array', 'Object',
|
|
362
|
+
'parseInt', 'parseFloat', 'isNaN', 'isFinite',
|
|
363
|
+
]);
|
|
364
|
+
return keywords.has(identifier);
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Estimate formula complexity based on heuristics
|
|
368
|
+
*/
|
|
369
|
+
estimateComplexity(expression) {
|
|
370
|
+
const lines = expression.split('\n').length;
|
|
371
|
+
const hasConditionals = /if\s*\(|switch\s*\(|\?/.test(expression);
|
|
372
|
+
const hasLoops = /for\s*\(|while\s*\(/.test(expression);
|
|
373
|
+
const hasLookups = /\.[a-z_][a-z0-9_]*/.test(expression);
|
|
374
|
+
if (lines > 20 || hasLoops) {
|
|
375
|
+
return 'complex';
|
|
376
|
+
}
|
|
377
|
+
if (lines > 5 || hasConditionals || hasLookups) {
|
|
378
|
+
return 'medium';
|
|
379
|
+
}
|
|
380
|
+
return 'simple';
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Register a custom function for use in formulas
|
|
384
|
+
*/
|
|
385
|
+
registerFunction(name, func) {
|
|
386
|
+
this.customFunctions[name] = func;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Validate a formula expression without executing it
|
|
390
|
+
*
|
|
391
|
+
* SECURITY NOTE: Uses Function constructor for syntax validation.
|
|
392
|
+
* This doesn't execute the code but creates a function object.
|
|
393
|
+
* For stricter validation, consider using a parser library like @babel/parser.
|
|
394
|
+
*/
|
|
395
|
+
validate(expression) {
|
|
396
|
+
var _a;
|
|
397
|
+
const errors = [];
|
|
398
|
+
if (!expression || expression.trim() === '') {
|
|
399
|
+
errors.push('Expression cannot be empty');
|
|
400
|
+
return { valid: false, errors };
|
|
401
|
+
}
|
|
402
|
+
// Check for blocked operations
|
|
403
|
+
if ((_a = this.config.sandbox) === null || _a === void 0 ? void 0 : _a.enabled) {
|
|
404
|
+
const blockedOps = this.config.sandbox.blocked_operations || [];
|
|
405
|
+
for (const op of blockedOps) {
|
|
406
|
+
if (expression.includes(op)) {
|
|
407
|
+
errors.push(`Blocked operation detected: ${op}`);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
// Try to parse as JavaScript (basic syntax check)
|
|
412
|
+
try {
|
|
413
|
+
const wrappedExpression = this.wrapExpression(expression);
|
|
414
|
+
new Function('', wrappedExpression);
|
|
415
|
+
}
|
|
416
|
+
catch (error) {
|
|
417
|
+
errors.push(`Syntax error: ${error instanceof Error ? error.message : String(error)}`);
|
|
418
|
+
}
|
|
419
|
+
return {
|
|
420
|
+
valid: errors.length === 0,
|
|
421
|
+
errors,
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
exports.FormulaEngine = FormulaEngine;
|
|
426
|
+
//# sourceMappingURL=formula-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formula-engine.js","sourceRoot":"","sources":["../src/formula-engine.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -22,4 +22,5 @@ __exportStar(require("./object"), exports);
|
|
|
22
22
|
__exportStar(require("./validator"), exports);
|
|
23
23
|
__exportStar(require("./util"), exports);
|
|
24
24
|
__exportStar(require("./ai-agent"), exports);
|
|
25
|
+
__exportStar(require("./formula-engine"), exports);
|
|
25
26
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,wCAAsB;AAEtB,2CAAyB;AACzB,yCAAuB;AACvB,2CAAyB;AACzB,8CAA4B;AAC5B,yCAAuB;AACvB,6CAA2B"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,wCAAsB;AAEtB,2CAAyB;AACzB,yCAAuB;AACvB,2CAAyB;AACzB,8CAA4B;AAC5B,yCAAuB;AACvB,6CAA2B;AAC3B,mDAAiC"}
|
package/dist/repository.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export declare class ObjectRepository {
|
|
|
4
4
|
private context;
|
|
5
5
|
private app;
|
|
6
6
|
private validator;
|
|
7
|
+
private formulaEngine;
|
|
7
8
|
constructor(objectName: string, context: ObjectQLContext, app: IObjectQL);
|
|
8
9
|
private getDriver;
|
|
9
10
|
private getOptions;
|
|
@@ -16,6 +17,11 @@ export declare class ObjectRepository {
|
|
|
16
17
|
* while object-level rules use the merged record (previousRecord + updates).
|
|
17
18
|
*/
|
|
18
19
|
private validateRecord;
|
|
20
|
+
/**
|
|
21
|
+
* Evaluate formula fields for a record
|
|
22
|
+
* Adds computed formula field values to the record
|
|
23
|
+
*/
|
|
24
|
+
private evaluateFormulas;
|
|
19
25
|
find(query?: UnifiedQuery): Promise<any[]>;
|
|
20
26
|
findOne(idOrQuery: string | number | UnifiedQuery): Promise<any>;
|
|
21
27
|
count(filters: any): Promise<number>;
|