@object-ui/core 0.3.0 → 0.3.1
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 +8 -0
- package/dist/actions/ActionRunner.d.ts +40 -0
- package/dist/actions/ActionRunner.js +160 -0
- package/dist/actions/index.d.ts +8 -0
- package/dist/actions/index.js +8 -0
- package/dist/adapters/index.d.ts +7 -0
- package/dist/adapters/index.js +10 -0
- package/dist/builder/schema-builder.d.ts +7 -0
- package/dist/builder/schema-builder.js +4 -6
- package/dist/evaluator/ExpressionContext.d.ts +51 -0
- package/dist/evaluator/ExpressionContext.js +110 -0
- package/dist/evaluator/ExpressionEvaluator.d.ts +99 -0
- package/dist/evaluator/ExpressionEvaluator.js +200 -0
- package/dist/evaluator/index.d.ts +9 -0
- package/dist/evaluator/index.js +9 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -1
- package/dist/registry/Registry.d.ts +7 -0
- package/dist/registry/Registry.js +7 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.js +7 -0
- package/dist/utils/filter-converter.d.ts +57 -0
- package/dist/utils/filter-converter.js +100 -0
- package/dist/validation/schema-validator.d.ts +7 -0
- package/dist/validation/schema-validator.js +4 -6
- package/package.json +16 -5
- package/src/actions/ActionRunner.ts +195 -0
- package/src/actions/index.ts +9 -0
- package/src/adapters/README.md +180 -0
- package/src/adapters/index.d.ts +8 -0
- package/src/adapters/index.js +10 -0
- package/src/adapters/index.ts +10 -0
- package/src/builder/schema-builder.d.ts +7 -0
- package/src/builder/schema-builder.js +4 -6
- package/src/builder/schema-builder.ts +8 -0
- package/src/evaluator/ExpressionContext.ts +118 -0
- package/src/evaluator/ExpressionEvaluator.ts +248 -0
- package/src/evaluator/__tests__/ExpressionEvaluator.test.ts +101 -0
- package/src/evaluator/index.ts +10 -0
- package/src/index.d.ts +9 -0
- package/src/index.js +10 -1
- package/src/index.test.ts +8 -0
- package/src/index.ts +11 -1
- package/src/registry/Registry.d.ts +7 -0
- package/src/registry/Registry.js +7 -0
- package/src/registry/Registry.ts +8 -0
- package/src/types/index.d.ts +7 -0
- package/src/types/index.js +7 -0
- package/src/types/index.ts +8 -0
- package/src/utils/__tests__/filter-converter.test.ts +118 -0
- package/src/utils/filter-converter.d.ts +57 -0
- package/src/utils/filter-converter.js +100 -0
- package/src/utils/filter-converter.ts +133 -0
- package/src/validation/schema-validator.d.ts +7 -0
- package/src/validation/schema-validator.js +4 -6
- package/src/validation/schema-validator.ts +8 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,200 @@
|
|
|
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 - Expression Evaluator
|
|
10
|
+
*
|
|
11
|
+
* Evaluates template string expressions like ${data.amount > 1000} for dynamic UI behavior.
|
|
12
|
+
* Supports variable substitution, comparison operators, and basic JavaScript expressions.
|
|
13
|
+
*
|
|
14
|
+
* @module evaluator
|
|
15
|
+
* @packageDocumentation
|
|
16
|
+
*/
|
|
17
|
+
import { ExpressionContext } from './ExpressionContext';
|
|
18
|
+
/**
|
|
19
|
+
* Expression evaluator for dynamic UI expressions
|
|
20
|
+
*/
|
|
21
|
+
export class ExpressionEvaluator {
|
|
22
|
+
constructor(context) {
|
|
23
|
+
Object.defineProperty(this, "context", {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
configurable: true,
|
|
26
|
+
writable: true,
|
|
27
|
+
value: void 0
|
|
28
|
+
});
|
|
29
|
+
if (context instanceof ExpressionContext) {
|
|
30
|
+
this.context = context;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
this.context = new ExpressionContext(context || {});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Evaluate a string that may contain template expressions like ${...}
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* const evaluator = new ExpressionEvaluator({ data: { amount: 1500 } });
|
|
42
|
+
* evaluator.evaluate('${data.amount > 1000}'); // Returns: true
|
|
43
|
+
* evaluator.evaluate('Amount is ${data.amount}'); // Returns: "Amount is 1500"
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
evaluate(expression, options = {}) {
|
|
47
|
+
// Handle non-string primitives
|
|
48
|
+
if (typeof expression !== 'string') {
|
|
49
|
+
return expression;
|
|
50
|
+
}
|
|
51
|
+
const { defaultValue, throwOnError = false, sanitize = true } = options;
|
|
52
|
+
try {
|
|
53
|
+
// Check if string contains template expressions
|
|
54
|
+
const hasTemplates = expression.includes('${');
|
|
55
|
+
if (!hasTemplates) {
|
|
56
|
+
// No templates, return as-is
|
|
57
|
+
return expression;
|
|
58
|
+
}
|
|
59
|
+
// Special case: if the entire string is a single template expression, return the value directly
|
|
60
|
+
const singleTemplateMatch = expression.match(/^\$\{([^}]+)\}$/);
|
|
61
|
+
if (singleTemplateMatch) {
|
|
62
|
+
return this.evaluateExpression(singleTemplateMatch[1].trim(), { sanitize });
|
|
63
|
+
}
|
|
64
|
+
// Replace all ${...} expressions in a string with multiple parts
|
|
65
|
+
return expression.replace(/\$\{([^}]+)\}/g, (match, expr) => {
|
|
66
|
+
try {
|
|
67
|
+
const result = this.evaluateExpression(expr.trim(), { sanitize });
|
|
68
|
+
return String(result ?? '');
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
if (throwOnError) {
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
console.warn(`Expression evaluation failed for: ${expr}`, error);
|
|
75
|
+
return match; // Return original if evaluation fails
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
if (throwOnError) {
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
console.warn(`Failed to evaluate expression: ${expression}`, error);
|
|
84
|
+
return defaultValue ?? expression;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Evaluate a single expression (without ${} wrapper)
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* evaluator.evaluateExpression('data.amount > 1000'); // Returns: true
|
|
93
|
+
* evaluator.evaluateExpression('data.user.name'); // Returns: "John"
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
evaluateExpression(expression, options = {}) {
|
|
97
|
+
const { sanitize = true } = options;
|
|
98
|
+
if (!expression || expression.trim() === '') {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
// Sanitize expression to prevent dangerous code execution
|
|
102
|
+
if (sanitize && this.isDangerous(expression)) {
|
|
103
|
+
throw new Error(`Potentially dangerous expression detected: ${expression}`);
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
// Create a safe evaluation function
|
|
107
|
+
const contextObj = this.context.toObject();
|
|
108
|
+
// Build safe function with context variables
|
|
109
|
+
const varNames = Object.keys(contextObj);
|
|
110
|
+
const varValues = Object.values(contextObj);
|
|
111
|
+
// SECURITY NOTE: Using Function constructor for expression evaluation.
|
|
112
|
+
// This is a controlled use case with:
|
|
113
|
+
// 1. Sanitization check (isDangerous) blocks dangerous patterns
|
|
114
|
+
// 2. Strict mode enabled ("use strict")
|
|
115
|
+
// 3. Limited scope (only contextObj variables available)
|
|
116
|
+
// 4. No access to global objects (process, window, etc.)
|
|
117
|
+
// For production use, consider: expr-eval, safe-eval, or a custom parser
|
|
118
|
+
const fn = new Function(...varNames, `"use strict"; return (${expression});`);
|
|
119
|
+
// Execute with context values
|
|
120
|
+
return fn(...varValues);
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
throw new Error(`Failed to evaluate expression "${expression}": ${error.message}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Check if expression contains potentially dangerous code
|
|
128
|
+
*/
|
|
129
|
+
isDangerous(expression) {
|
|
130
|
+
const dangerousPatterns = [
|
|
131
|
+
/eval\s*\(/i,
|
|
132
|
+
/Function\s*\(/i,
|
|
133
|
+
/setTimeout\s*\(/i,
|
|
134
|
+
/setInterval\s*\(/i,
|
|
135
|
+
/import\s*\(/i,
|
|
136
|
+
/require\s*\(/i,
|
|
137
|
+
/process\./i,
|
|
138
|
+
/global\./i,
|
|
139
|
+
/window\./i,
|
|
140
|
+
/document\./i,
|
|
141
|
+
/__proto__/i,
|
|
142
|
+
/constructor\s*\(/i,
|
|
143
|
+
/prototype\./i,
|
|
144
|
+
];
|
|
145
|
+
return dangerousPatterns.some(pattern => pattern.test(expression));
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Evaluate a conditional expression and return boolean
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* evaluator.evaluateCondition('${data.age >= 18}'); // Returns: true/false
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
evaluateCondition(condition, options = {}) {
|
|
156
|
+
if (typeof condition === 'boolean') {
|
|
157
|
+
return condition;
|
|
158
|
+
}
|
|
159
|
+
if (!condition) {
|
|
160
|
+
return true; // Default to visible/enabled if no condition
|
|
161
|
+
}
|
|
162
|
+
const result = this.evaluate(condition, options);
|
|
163
|
+
// Convert result to boolean
|
|
164
|
+
return Boolean(result);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Update the context with new data
|
|
168
|
+
*/
|
|
169
|
+
updateContext(data) {
|
|
170
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
171
|
+
this.context.set(key, value);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Get the current context
|
|
176
|
+
*/
|
|
177
|
+
getContext() {
|
|
178
|
+
return this.context;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Create a new evaluator with additional context data
|
|
182
|
+
*/
|
|
183
|
+
withContext(data) {
|
|
184
|
+
return new ExpressionEvaluator(this.context.createChild(data));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Convenience function to quickly evaluate an expression
|
|
189
|
+
*/
|
|
190
|
+
export function evaluateExpression(expression, context = {}, options = {}) {
|
|
191
|
+
const evaluator = new ExpressionEvaluator(context);
|
|
192
|
+
return evaluator.evaluate(expression, options);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Convenience function to evaluate a condition
|
|
196
|
+
*/
|
|
197
|
+
export function evaluateCondition(condition, context = {}) {
|
|
198
|
+
const evaluator = new ExpressionEvaluator(context);
|
|
199
|
+
return evaluator.evaluateCondition(condition);
|
|
200
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
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
|
+
export * from './ExpressionContext';
|
|
9
|
+
export * from './ExpressionEvaluator';
|
|
@@ -0,0 +1,9 @@
|
|
|
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
|
+
export * from './ExpressionContext';
|
|
9
|
+
export * from './ExpressionEvaluator';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
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
|
+
*/
|
|
1
8
|
export * from './types';
|
|
2
9
|
export * from './registry/Registry';
|
|
3
10
|
export * from './validation/schema-validator';
|
|
4
11
|
export * from './builder/schema-builder';
|
|
12
|
+
export * from './utils/filter-converter';
|
|
13
|
+
export * from './evaluator';
|
|
14
|
+
export * from './actions';
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
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
|
+
*/
|
|
1
8
|
export * from './types';
|
|
2
9
|
export * from './registry/Registry';
|
|
3
10
|
export * from './validation/schema-validator';
|
|
4
11
|
export * from './builder/schema-builder';
|
|
12
|
+
export * from './utils/filter-converter';
|
|
13
|
+
export * from './evaluator';
|
|
14
|
+
export * from './actions';
|
|
5
15
|
// export * from './data-scope'; // TODO
|
|
6
|
-
// export * from './evaluator'; // TODO
|
|
7
16
|
// export * from './validators'; // TODO
|
|
@@ -1,3 +1,10 @@
|
|
|
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
|
+
*/
|
|
1
8
|
import type { SchemaNode } from '../types';
|
|
2
9
|
export type ComponentRenderer<T = any> = T;
|
|
3
10
|
export type ComponentInput = {
|
|
@@ -1,3 +1,10 @@
|
|
|
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
|
+
*/
|
|
1
8
|
export class Registry {
|
|
2
9
|
constructor() {
|
|
3
10
|
Object.defineProperty(this, "components", {
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
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
|
+
*/
|
|
1
8
|
export interface SchemaNode {
|
|
2
9
|
type: string;
|
|
3
10
|
id?: string;
|
package/dist/types/index.js
CHANGED
|
@@ -0,0 +1,57 @@
|
|
|
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
|
+
* Filter Converter Utilities
|
|
10
|
+
*
|
|
11
|
+
* Shared utilities for converting MongoDB-like filter operators
|
|
12
|
+
* to ObjectStack FilterNode AST format.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* FilterNode AST type definition
|
|
16
|
+
* Represents a filter condition or a logical combination of conditions
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // Simple condition
|
|
20
|
+
* ['status', '=', 'active']
|
|
21
|
+
*
|
|
22
|
+
* // Logical combination
|
|
23
|
+
* ['and', ['age', '>=', 18], ['status', '=', 'active']]
|
|
24
|
+
*/
|
|
25
|
+
export type FilterNode = [string, string, any] | [string, ...FilterNode[]];
|
|
26
|
+
/**
|
|
27
|
+
* Map MongoDB-like operators to ObjectStack filter operators.
|
|
28
|
+
*
|
|
29
|
+
* @param operator - MongoDB-style operator (e.g., '$gte', '$in')
|
|
30
|
+
* @returns ObjectStack operator or null if not recognized
|
|
31
|
+
*/
|
|
32
|
+
export declare function convertOperatorToAST(operator: string): string | null;
|
|
33
|
+
/**
|
|
34
|
+
* Convert object-based filters to ObjectStack FilterNode AST format.
|
|
35
|
+
* Converts MongoDB-like operators to ObjectStack filter expressions.
|
|
36
|
+
*
|
|
37
|
+
* @param filter - Object-based filter with optional operators
|
|
38
|
+
* @returns FilterNode AST array
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* // Simple filter - converted to AST
|
|
42
|
+
* convertFiltersToAST({ status: 'active' })
|
|
43
|
+
* // => ['status', '=', 'active']
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* // Complex filter with operators
|
|
47
|
+
* convertFiltersToAST({ age: { $gte: 18 } })
|
|
48
|
+
* // => ['age', '>=', 18]
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* // Multiple conditions
|
|
52
|
+
* convertFiltersToAST({ age: { $gte: 18, $lte: 65 }, status: 'active' })
|
|
53
|
+
* // => ['and', ['age', '>=', 18], ['age', '<=', 65], ['status', '=', 'active']]
|
|
54
|
+
*
|
|
55
|
+
* @throws {Error} If an unknown operator is encountered
|
|
56
|
+
*/
|
|
57
|
+
export declare function convertFiltersToAST(filter: Record<string, any>): FilterNode | Record<string, any>;
|
|
@@ -0,0 +1,100 @@
|
|
|
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
|
+
* Map MongoDB-like operators to ObjectStack filter operators.
|
|
10
|
+
*
|
|
11
|
+
* @param operator - MongoDB-style operator (e.g., '$gte', '$in')
|
|
12
|
+
* @returns ObjectStack operator or null if not recognized
|
|
13
|
+
*/
|
|
14
|
+
export function convertOperatorToAST(operator) {
|
|
15
|
+
const operatorMap = {
|
|
16
|
+
'$eq': '=',
|
|
17
|
+
'$ne': '!=',
|
|
18
|
+
'$gt': '>',
|
|
19
|
+
'$gte': '>=',
|
|
20
|
+
'$lt': '<',
|
|
21
|
+
'$lte': '<=',
|
|
22
|
+
'$in': 'in',
|
|
23
|
+
'$nin': 'notin',
|
|
24
|
+
'$notin': 'notin',
|
|
25
|
+
'$contains': 'contains',
|
|
26
|
+
'$startswith': 'startswith',
|
|
27
|
+
'$between': 'between',
|
|
28
|
+
};
|
|
29
|
+
return operatorMap[operator] || null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Convert object-based filters to ObjectStack FilterNode AST format.
|
|
33
|
+
* Converts MongoDB-like operators to ObjectStack filter expressions.
|
|
34
|
+
*
|
|
35
|
+
* @param filter - Object-based filter with optional operators
|
|
36
|
+
* @returns FilterNode AST array
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* // Simple filter - converted to AST
|
|
40
|
+
* convertFiltersToAST({ status: 'active' })
|
|
41
|
+
* // => ['status', '=', 'active']
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* // Complex filter with operators
|
|
45
|
+
* convertFiltersToAST({ age: { $gte: 18 } })
|
|
46
|
+
* // => ['age', '>=', 18]
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* // Multiple conditions
|
|
50
|
+
* convertFiltersToAST({ age: { $gte: 18, $lte: 65 }, status: 'active' })
|
|
51
|
+
* // => ['and', ['age', '>=', 18], ['age', '<=', 65], ['status', '=', 'active']]
|
|
52
|
+
*
|
|
53
|
+
* @throws {Error} If an unknown operator is encountered
|
|
54
|
+
*/
|
|
55
|
+
export function convertFiltersToAST(filter) {
|
|
56
|
+
const conditions = [];
|
|
57
|
+
for (const [field, value] of Object.entries(filter)) {
|
|
58
|
+
if (value === null || value === undefined)
|
|
59
|
+
continue;
|
|
60
|
+
// Check if value is a complex operator object
|
|
61
|
+
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
62
|
+
// Handle operator-based filters
|
|
63
|
+
for (const [operator, operatorValue] of Object.entries(value)) {
|
|
64
|
+
// Special handling for $regex - warn users about limited support
|
|
65
|
+
if (operator === '$regex') {
|
|
66
|
+
console.warn(`[ObjectUI] Warning: $regex operator is not fully supported. ` +
|
|
67
|
+
`Converting to 'contains' which only supports substring matching, not regex patterns. ` +
|
|
68
|
+
`Field: '${field}', Value: ${JSON.stringify(operatorValue)}. ` +
|
|
69
|
+
`Consider using $contains or $startswith instead.`);
|
|
70
|
+
conditions.push([field, 'contains', operatorValue]);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const astOperator = convertOperatorToAST(operator);
|
|
74
|
+
if (astOperator) {
|
|
75
|
+
conditions.push([field, astOperator, operatorValue]);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// Unknown operator - throw error to avoid silent failure
|
|
79
|
+
throw new Error(`[ObjectUI] Unknown filter operator '${operator}' for field '${field}'. ` +
|
|
80
|
+
`Supported operators: $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $contains, $startswith, $between. ` +
|
|
81
|
+
`If you need exact object matching, use the value directly without an operator.`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// Simple equality filter
|
|
87
|
+
conditions.push([field, '=', value]);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// If no conditions, return original filter
|
|
91
|
+
if (conditions.length === 0) {
|
|
92
|
+
return filter;
|
|
93
|
+
}
|
|
94
|
+
// If only one condition, return it directly
|
|
95
|
+
if (conditions.length === 1) {
|
|
96
|
+
return conditions[0];
|
|
97
|
+
}
|
|
98
|
+
// Multiple conditions: combine with 'and'
|
|
99
|
+
return ['and', ...conditions];
|
|
100
|
+
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* @module validation
|
|
8
|
-
* @packageDocumentation
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
9
7
|
*/
|
|
10
8
|
/**
|
|
11
9
|
* Validation rules for base schema
|
package/package.json
CHANGED
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"license": "MIT",
|
|
5
|
+
"description": "Core logic, types, and validation for Object UI. Zero React dependencies.",
|
|
6
|
+
"homepage": "https://www.objectui.org",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/objectstack-ai/objectui.git",
|
|
10
|
+
"directory": "packages/core"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/objectstack-ai/objectui/issues"
|
|
14
|
+
},
|
|
5
15
|
"main": "dist/index.js",
|
|
6
16
|
"types": "dist/index.d.ts",
|
|
7
17
|
"dependencies": {
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
18
|
+
"@objectstack/spec": "^0.3.3",
|
|
19
|
+
"lodash": "^4.17.23",
|
|
20
|
+
"zod": "^4.3.6",
|
|
21
|
+
"@object-ui/types": "0.3.1"
|
|
11
22
|
},
|
|
12
23
|
"devDependencies": {
|
|
13
24
|
"typescript": "^5.9.3",
|
|
14
|
-
"vitest": "^4.0.
|
|
25
|
+
"vitest": "^4.0.18"
|
|
15
26
|
},
|
|
16
27
|
"scripts": {
|
|
17
28
|
"build": "tsc",
|