@memberjunction/global 6.1.0-edge.2 → 6.1.0-edge.3
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/LICENSE +180 -4
- package/README.md +2 -2
- package/dist/SQLExpressionValidator.d.ts +28 -1
- package/dist/SQLExpressionValidator.d.ts.map +1 -1
- package/dist/SQLExpressionValidator.js +42 -4
- package/dist/SQLExpressionValidator.js.map +1 -1
- package/dist/SafeExpressionEvaluator.d.ts +131 -6
- package/dist/SafeExpressionEvaluator.d.ts.map +1 -1
- package/dist/SafeExpressionEvaluator.js +344 -41
- package/dist/SafeExpressionEvaluator.js.map +1 -1
- package/dist/__tests__/DeepDiff.test.d.ts +2 -0
- package/dist/__tests__/DeepDiff.test.d.ts.map +1 -0
- package/dist/__tests__/DeepDiff.test.js +229 -0
- package/dist/__tests__/DeepDiff.test.js.map +1 -0
- package/dist/__tests__/JSONValidator.test.d.ts +2 -0
- package/dist/__tests__/JSONValidator.test.d.ts.map +1 -0
- package/dist/__tests__/JSONValidator.test.js +221 -0
- package/dist/__tests__/JSONValidator.test.js.map +1 -0
- package/dist/__tests__/MJGlobal.test.js +8 -6
- package/dist/__tests__/MJGlobal.test.js.map +1 -1
- package/dist/__tests__/ResourcePatternUtils.test.d.ts +2 -0
- package/dist/__tests__/ResourcePatternUtils.test.d.ts.map +1 -0
- package/dist/__tests__/ResourcePatternUtils.test.js +50 -0
- package/dist/__tests__/ResourcePatternUtils.test.js.map +1 -0
- package/dist/__tests__/SQLExpressionValidator.security.test.js +62 -1
- package/dist/__tests__/SQLExpressionValidator.security.test.js.map +1 -1
- package/dist/__tests__/SafeExpressionEvaluator.security.test.d.ts +2 -0
- package/dist/__tests__/SafeExpressionEvaluator.security.test.d.ts.map +1 -0
- package/dist/__tests__/SafeExpressionEvaluator.security.test.js +284 -0
- package/dist/__tests__/SafeExpressionEvaluator.security.test.js.map +1 -0
- package/dist/__tests__/SafeExpressionEvaluator.test.d.ts +2 -0
- package/dist/__tests__/SafeExpressionEvaluator.test.d.ts.map +1 -0
- package/dist/__tests__/SafeExpressionEvaluator.test.js +355 -0
- package/dist/__tests__/SafeExpressionEvaluator.test.js.map +1 -0
- package/dist/__tests__/SafeExpressionEvaluator.validateSyntax.test.d.ts +2 -0
- package/dist/__tests__/SafeExpressionEvaluator.validateSyntax.test.d.ts.map +1 -0
- package/dist/__tests__/SafeExpressionEvaluator.validateSyntax.test.js +62 -0
- package/dist/__tests__/SafeExpressionEvaluator.validateSyntax.test.js.map +1 -0
- package/dist/__tests__/util.toEpochMs.test.d.ts +2 -0
- package/dist/__tests__/util.toEpochMs.test.d.ts.map +1 -0
- package/dist/__tests__/util.toEpochMs.test.js +57 -0
- package/dist/__tests__/util.toEpochMs.test.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/util/ResourcePatternUtils.d.ts +35 -0
- package/dist/util/ResourcePatternUtils.d.ts.map +1 -0
- package/dist/util/ResourcePatternUtils.js +56 -0
- package/dist/util/ResourcePatternUtils.js.map +1 -0
- package/dist/util.d.ts +11 -0
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +16 -0
- package/dist/util.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { SafeExpressionEvaluator, defaultExpressionEvaluator, } from '../SafeExpressionEvaluator.js';
|
|
3
|
+
/**
|
|
4
|
+
* Functional tests for SafeExpressionEvaluator.
|
|
5
|
+
*
|
|
6
|
+
* These exercise the documented contract: evaluate a boolean expression against a
|
|
7
|
+
* context object, returning an {@link ExpressionEvaluationResult}. Adversarial /
|
|
8
|
+
* sandbox-escape scenarios live in SafeExpressionEvaluator.security.test.ts.
|
|
9
|
+
*/
|
|
10
|
+
describe('SafeExpressionEvaluator', () => {
|
|
11
|
+
let evaluator;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
evaluator = new SafeExpressionEvaluator();
|
|
14
|
+
});
|
|
15
|
+
// ---------------------------------------------------------------
|
|
16
|
+
// Simple comparisons over context data
|
|
17
|
+
// ---------------------------------------------------------------
|
|
18
|
+
describe('comparison operators', () => {
|
|
19
|
+
it('should evaluate == to true when values match', () => {
|
|
20
|
+
const r = evaluator.evaluate("status == 'active'", { status: 'active' });
|
|
21
|
+
expect(r.success).toBe(true);
|
|
22
|
+
expect(r.value).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
it('should evaluate == to false when values differ', () => {
|
|
25
|
+
const r = evaluator.evaluate("status == 'active'", { status: 'inactive' });
|
|
26
|
+
expect(r.success).toBe(true);
|
|
27
|
+
expect(r.value).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
it('should evaluate strict === correctly', () => {
|
|
30
|
+
expect(evaluator.evaluate('count === 5', { count: 5 }).value).toBe(true);
|
|
31
|
+
expect(evaluator.evaluate('count === 5', { count: 6 }).value).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
it('should evaluate != and !==', () => {
|
|
34
|
+
expect(evaluator.evaluate('count != 5', { count: 6 }).value).toBe(true);
|
|
35
|
+
expect(evaluator.evaluate('count !== 5', { count: 5 }).value).toBe(false);
|
|
36
|
+
});
|
|
37
|
+
it('should evaluate <, >, <=, >=', () => {
|
|
38
|
+
expect(evaluator.evaluate('n < 10', { n: 5 }).value).toBe(true);
|
|
39
|
+
expect(evaluator.evaluate('n > 10', { n: 5 }).value).toBe(false);
|
|
40
|
+
expect(evaluator.evaluate('n <= 5', { n: 5 }).value).toBe(true);
|
|
41
|
+
expect(evaluator.evaluate('n >= 6', { n: 5 }).value).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
// ---------------------------------------------------------------
|
|
45
|
+
// Logical operators
|
|
46
|
+
// ---------------------------------------------------------------
|
|
47
|
+
describe('logical operators', () => {
|
|
48
|
+
it('should evaluate && (AND)', () => {
|
|
49
|
+
const ctx = { a: true, b: false };
|
|
50
|
+
expect(evaluator.evaluate('a && b', ctx).value).toBe(false);
|
|
51
|
+
expect(evaluator.evaluate('a && !b', ctx).value).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
it('should evaluate || (OR)', () => {
|
|
54
|
+
const ctx = { a: false, b: true };
|
|
55
|
+
expect(evaluator.evaluate('a || b', ctx).value).toBe(true);
|
|
56
|
+
expect(evaluator.evaluate('a || false', ctx).value).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
it('should evaluate ! (NOT)', () => {
|
|
59
|
+
expect(evaluator.evaluate('!isActive', { isActive: false }).value).toBe(true);
|
|
60
|
+
expect(evaluator.evaluate('!isActive', { isActive: true }).value).toBe(false);
|
|
61
|
+
});
|
|
62
|
+
it('should combine comparisons with logical operators', () => {
|
|
63
|
+
const ctx = { tier: 'premium', total: 1500 };
|
|
64
|
+
const r = evaluator.evaluate("tier == 'premium' && total > 1000", ctx);
|
|
65
|
+
expect(r.success).toBe(true);
|
|
66
|
+
expect(r.value).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
// ---------------------------------------------------------------
|
|
70
|
+
// Nested property + array access
|
|
71
|
+
// ---------------------------------------------------------------
|
|
72
|
+
describe('property and array access', () => {
|
|
73
|
+
it('should resolve nested dot-notation properties', () => {
|
|
74
|
+
const ctx = {
|
|
75
|
+
payload: { customer: { tier: 'premium' }, order: { total: 1500 } },
|
|
76
|
+
};
|
|
77
|
+
const r = evaluator.evaluate("payload.customer.tier == 'premium' && payload.order.total > 1000", ctx);
|
|
78
|
+
expect(r.success).toBe(true);
|
|
79
|
+
expect(r.value).toBe(true);
|
|
80
|
+
});
|
|
81
|
+
it('should resolve array index access', () => {
|
|
82
|
+
const ctx = { items: [10, 20, 30] };
|
|
83
|
+
expect(evaluator.evaluate('items[0] == 10', ctx).value).toBe(true);
|
|
84
|
+
expect(evaluator.evaluate('items[2] > items[0]', ctx).value).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
// ---------------------------------------------------------------
|
|
88
|
+
// Safe methods
|
|
89
|
+
// ---------------------------------------------------------------
|
|
90
|
+
describe('safe string/array methods', () => {
|
|
91
|
+
it('should support .length', () => {
|
|
92
|
+
expect(evaluator.evaluate('name.length > 3', { name: 'Alice' }).value).toBe(true);
|
|
93
|
+
expect(evaluator.evaluate('name.length > 3', { name: 'Al' }).value).toBe(false);
|
|
94
|
+
});
|
|
95
|
+
it('should support .includes()', () => {
|
|
96
|
+
expect(evaluator.evaluate("tags.includes('urgent')", { tags: ['work', 'urgent'] }).value).toBe(true);
|
|
97
|
+
});
|
|
98
|
+
it('should support .startsWith() and .endsWith()', () => {
|
|
99
|
+
const ctx = { code: 'AB-123' };
|
|
100
|
+
expect(evaluator.evaluate("code.startsWith('AB')", ctx).value).toBe(true);
|
|
101
|
+
expect(evaluator.evaluate("code.endsWith('123')", ctx).value).toBe(true);
|
|
102
|
+
});
|
|
103
|
+
it('should support .toLowerCase() in a comparison', () => {
|
|
104
|
+
const r = evaluator.evaluate("name.toLowerCase() == 'alice'", { name: 'ALICE' });
|
|
105
|
+
expect(r.success).toBe(true);
|
|
106
|
+
expect(r.value).toBe(true);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
// ---------------------------------------------------------------
|
|
110
|
+
// Array higher-order methods
|
|
111
|
+
// ---------------------------------------------------------------
|
|
112
|
+
describe('array higher-order methods', () => {
|
|
113
|
+
it('should support .some()', () => {
|
|
114
|
+
const ctx = { items: [{ price: 50 }, { price: 150 }] };
|
|
115
|
+
const r = evaluator.evaluate('items.some(item => item.price > 100)', ctx);
|
|
116
|
+
expect(r.success).toBe(true);
|
|
117
|
+
expect(r.value).toBe(true);
|
|
118
|
+
});
|
|
119
|
+
it('should support .every()', () => {
|
|
120
|
+
const ctx = { items: [{ price: 50 }, { price: 150 }] };
|
|
121
|
+
expect(evaluator.evaluate('items.every(item => item.price > 0)', ctx).value).toBe(true);
|
|
122
|
+
expect(evaluator.evaluate('items.every(item => item.price > 100)', ctx).value).toBe(false);
|
|
123
|
+
});
|
|
124
|
+
it('should support .filter().length', () => {
|
|
125
|
+
const ctx = {
|
|
126
|
+
items: [{ price: 50 }, { price: 150 }, { price: 200 }],
|
|
127
|
+
};
|
|
128
|
+
const r = evaluator.evaluate('items.filter(item => item.price > 100).length == 2', ctx);
|
|
129
|
+
expect(r.success).toBe(true);
|
|
130
|
+
expect(r.value).toBe(true);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
// ---------------------------------------------------------------
|
|
134
|
+
// typeof
|
|
135
|
+
// ---------------------------------------------------------------
|
|
136
|
+
describe('typeof', () => {
|
|
137
|
+
it('should evaluate typeof checks', () => {
|
|
138
|
+
expect(evaluator.evaluate("typeof name == 'string'", { name: 'x' }).value).toBe(true);
|
|
139
|
+
expect(evaluator.evaluate("typeof count == 'number'", { count: 5 }).value).toBe(true);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
// ---------------------------------------------------------------
|
|
143
|
+
// Edge values: null / undefined / empty
|
|
144
|
+
// ---------------------------------------------------------------
|
|
145
|
+
describe('edge values', () => {
|
|
146
|
+
it('should compare against null', () => {
|
|
147
|
+
expect(evaluator.evaluate('x == null', { x: null }).value).toBe(true);
|
|
148
|
+
expect(evaluator.evaluate('x === null', { x: null }).value).toBe(true);
|
|
149
|
+
});
|
|
150
|
+
it('should treat missing property (undefined) loosely equal to null', () => {
|
|
151
|
+
const ctx = { obj: {} };
|
|
152
|
+
// obj.missing is undefined; undefined == null is true in JS
|
|
153
|
+
expect(evaluator.evaluate('obj.missing == null', ctx).value).toBe(true);
|
|
154
|
+
});
|
|
155
|
+
it('should coerce a truthy non-boolean result via Boolean()', () => {
|
|
156
|
+
// The evaluator wraps the expression in Boolean(...): a bare truthy string yields true
|
|
157
|
+
const r = evaluator.evaluate('name', { name: 'non-empty' });
|
|
158
|
+
expect(r.success).toBe(true);
|
|
159
|
+
expect(r.value).toBe(true);
|
|
160
|
+
});
|
|
161
|
+
it('should coerce an empty-string result to false', () => {
|
|
162
|
+
const r = evaluator.evaluate('name', { name: '' });
|
|
163
|
+
expect(r.success).toBe(true);
|
|
164
|
+
expect(r.value).toBe(false);
|
|
165
|
+
});
|
|
166
|
+
it('should handle an empty context object with a self-contained expression', () => {
|
|
167
|
+
const r = evaluator.evaluate('1 < 2', {});
|
|
168
|
+
expect(r.success).toBe(true);
|
|
169
|
+
expect(r.value).toBe(true);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
// ---------------------------------------------------------------
|
|
173
|
+
// Error paths for malformed / invalid input
|
|
174
|
+
// ---------------------------------------------------------------
|
|
175
|
+
describe('error handling', () => {
|
|
176
|
+
it('should fail on an empty expression', () => {
|
|
177
|
+
const r = evaluator.evaluate('', { a: 1 });
|
|
178
|
+
expect(r.success).toBe(false);
|
|
179
|
+
expect(r.error).toContain('non-empty string');
|
|
180
|
+
});
|
|
181
|
+
it('should evaluate a whitespace-only expression to false (Boolean() of no argument)', () => {
|
|
182
|
+
// A non-empty but whitespace-only string passes validation and compiles to
|
|
183
|
+
// `Boolean( )`, which is Boolean() === false — so it succeeds with value false.
|
|
184
|
+
const r = evaluator.evaluate(' ', { a: 1 });
|
|
185
|
+
expect(r.success).toBe(true);
|
|
186
|
+
expect(r.value).toBe(false);
|
|
187
|
+
});
|
|
188
|
+
it('should fail on unbalanced parentheses', () => {
|
|
189
|
+
const r = evaluator.evaluate('(a > 1', { a: 5 });
|
|
190
|
+
expect(r.success).toBe(false);
|
|
191
|
+
expect(r.error).toContain('Unbalanced parentheses');
|
|
192
|
+
});
|
|
193
|
+
it('should fail on a closing paren before an opening paren', () => {
|
|
194
|
+
const r = evaluator.evaluate('a > 1)', { a: 5 });
|
|
195
|
+
expect(r.success).toBe(false);
|
|
196
|
+
expect(r.error).toContain('Unbalanced parentheses');
|
|
197
|
+
});
|
|
198
|
+
it('should fail on a syntactically malformed expression', () => {
|
|
199
|
+
const r = evaluator.evaluate('a ===', { a: 1 });
|
|
200
|
+
expect(r.success).toBe(false);
|
|
201
|
+
expect(r.error).toBeDefined();
|
|
202
|
+
});
|
|
203
|
+
it('should fail when referencing an unknown identifier not in context', () => {
|
|
204
|
+
const r = evaluator.evaluate('missingVar > 1', { a: 1 });
|
|
205
|
+
expect(r.success).toBe(false);
|
|
206
|
+
expect(r.error).toContain('Expression evaluation failed');
|
|
207
|
+
});
|
|
208
|
+
it('should fail when the expression exceeds the 1000-character limit', () => {
|
|
209
|
+
const long = '1 == 1 && '.repeat(200) + '1 == 1'; // well over 1000 chars
|
|
210
|
+
const r = evaluator.evaluate(long, {});
|
|
211
|
+
expect(r.success).toBe(false);
|
|
212
|
+
expect(r.error).toContain('maximum length');
|
|
213
|
+
});
|
|
214
|
+
it('should fail when a context key is not a valid JS identifier', () => {
|
|
215
|
+
// Context keys become Function parameter names; "my-key" is not a valid identifier.
|
|
216
|
+
const ctx = { 'my-key': 1 };
|
|
217
|
+
const r = evaluator.evaluate('1 == 1', ctx);
|
|
218
|
+
expect(r.success).toBe(false);
|
|
219
|
+
expect(r.error).toBeDefined();
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
// ---------------------------------------------------------------
|
|
223
|
+
// Diagnostics
|
|
224
|
+
// ---------------------------------------------------------------
|
|
225
|
+
describe('diagnostics', () => {
|
|
226
|
+
it('should omit diagnostics by default', () => {
|
|
227
|
+
const r = evaluator.evaluate('a == 1', { a: 1 });
|
|
228
|
+
expect(r.diagnostics).toBeUndefined();
|
|
229
|
+
});
|
|
230
|
+
it('should include diagnostics when enabled on success', () => {
|
|
231
|
+
const r = evaluator.evaluate('a == 1', { a: 1 }, true);
|
|
232
|
+
expect(r.diagnostics).toBeDefined();
|
|
233
|
+
expect(r.diagnostics?.expression).toBe('a == 1');
|
|
234
|
+
expect(r.diagnostics?.context).toEqual({ a: 1 });
|
|
235
|
+
expect(typeof r.diagnostics?.evaluationTime).toBe('number');
|
|
236
|
+
});
|
|
237
|
+
it('should include diagnostics when enabled on failure', () => {
|
|
238
|
+
const r = evaluator.evaluate('', { a: 1 }, true);
|
|
239
|
+
expect(r.success).toBe(false);
|
|
240
|
+
expect(r.diagnostics).toBeDefined();
|
|
241
|
+
expect(r.diagnostics?.expression).toBe('');
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
// ---------------------------------------------------------------
|
|
245
|
+
// Caching behaviour (observable: repeated evals stay consistent)
|
|
246
|
+
// ---------------------------------------------------------------
|
|
247
|
+
describe('compiled-expression cache', () => {
|
|
248
|
+
it('should return consistent results across repeated evaluations of the same expression', () => {
|
|
249
|
+
const first = evaluator.evaluate('a > 1', { a: 5 });
|
|
250
|
+
const second = evaluator.evaluate('a > 1', { a: 5 });
|
|
251
|
+
expect(first.value).toBe(true);
|
|
252
|
+
expect(second.value).toBe(true);
|
|
253
|
+
});
|
|
254
|
+
it('should honour different context values on a cached expression', () => {
|
|
255
|
+
// Same expression + same context keys -> cache hit, but different values must still be applied
|
|
256
|
+
expect(evaluator.evaluate('a > 1', { a: 5 }).value).toBe(true);
|
|
257
|
+
expect(evaluator.evaluate('a > 1', { a: 0 }).value).toBe(false);
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
// ---------------------------------------------------------------
|
|
261
|
+
// evaluateMultiple
|
|
262
|
+
// ---------------------------------------------------------------
|
|
263
|
+
describe('evaluateMultiple', () => {
|
|
264
|
+
it('should evaluate several named expressions against one context', () => {
|
|
265
|
+
const results = evaluator.evaluateMultiple([
|
|
266
|
+
{ expression: 'a > 1', name: 'aPositive' },
|
|
267
|
+
{ expression: "b == 'x'", name: 'bIsX' },
|
|
268
|
+
], { a: 5, b: 'x' });
|
|
269
|
+
expect(results.aPositive.value).toBe(true);
|
|
270
|
+
expect(results.bIsX.value).toBe(true);
|
|
271
|
+
});
|
|
272
|
+
it('should key unnamed expressions by index', () => {
|
|
273
|
+
const results = evaluator.evaluateMultiple([{ expression: 'a > 1' }], { a: 5 });
|
|
274
|
+
expect(results.expression_0.value).toBe(true);
|
|
275
|
+
});
|
|
276
|
+
it('should report per-expression failures independently', () => {
|
|
277
|
+
const results = evaluator.evaluateMultiple([
|
|
278
|
+
{ expression: 'a > 1', name: 'ok' },
|
|
279
|
+
{ expression: 'a ===', name: 'broken' },
|
|
280
|
+
], { a: 5 });
|
|
281
|
+
expect(results.ok.success).toBe(true);
|
|
282
|
+
expect(results.broken.success).toBe(false);
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
// ---------------------------------------------------------------
|
|
286
|
+
// Safe globals — the shapes authored specs write
|
|
287
|
+
// ---------------------------------------------------------------
|
|
288
|
+
describe('safe global calls', () => {
|
|
289
|
+
// `condition-roots.ts` blesses these twelve names at the task-graph door, and
|
|
290
|
+
// `1efc248ac5` shipped that decision precisely because refusing them rejects specs
|
|
291
|
+
// that run correctly. Receiver and method are both fixed identifiers, so nothing
|
|
292
|
+
// here is reachable by string assembly.
|
|
293
|
+
const ctx = { payload: { count: 4, raw: '7', id: 42 }, output: { delta: -3 } };
|
|
294
|
+
it.each([
|
|
295
|
+
['Math.abs(output.delta) < 5', true],
|
|
296
|
+
['Math.max(payload.count, 9) === 9', true],
|
|
297
|
+
['Number(payload.count) > 3', true],
|
|
298
|
+
['String(payload.id).length > 0', true],
|
|
299
|
+
['Boolean(payload.count) === true', true],
|
|
300
|
+
['Array.isArray(output) === false', true],
|
|
301
|
+
['Object.keys(payload).length > 0', true],
|
|
302
|
+
["JSON.stringify(payload) !== ''", true],
|
|
303
|
+
['Date.now() > 0', true],
|
|
304
|
+
['parseInt(payload.raw) > 0', true],
|
|
305
|
+
['parseFloat(payload.raw) === 7', true],
|
|
306
|
+
['isNaN(payload.count) === false', true],
|
|
307
|
+
['isFinite(payload.count) === true', true],
|
|
308
|
+
['Number.isInteger(payload.count)', true],
|
|
309
|
+
])('should evaluate %s', (expression, expected) => {
|
|
310
|
+
const r = evaluator.evaluate(expression, ctx);
|
|
311
|
+
expect(r.error).toBeUndefined();
|
|
312
|
+
expect(r.value).toBe(expected);
|
|
313
|
+
});
|
|
314
|
+
it('should reject a namespace method that is not on the list', () => {
|
|
315
|
+
// Mutators stay out even on an allowed namespace.
|
|
316
|
+
const r = evaluator.evaluate('Object.assign(payload) !== null', ctx);
|
|
317
|
+
expect(r.success).toBe(false);
|
|
318
|
+
expect(r.error).toContain('forbidden construct');
|
|
319
|
+
});
|
|
320
|
+
it('should reject a global that is not on the list', () => {
|
|
321
|
+
expect(evaluator.evaluate('Symbol("x") !== null', {}).success).toBe(false);
|
|
322
|
+
expect(evaluator.evaluate('fetch("/x") !== null', {}).success).toBe(false);
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
// ---------------------------------------------------------------
|
|
326
|
+
// Optional chaining
|
|
327
|
+
// ---------------------------------------------------------------
|
|
328
|
+
describe('optional chaining', () => {
|
|
329
|
+
it('should read through a present chain', () => {
|
|
330
|
+
const r = evaluator.evaluate("payload?.customer?.tier == 'premium'", {
|
|
331
|
+
payload: { customer: { tier: 'premium' } },
|
|
332
|
+
});
|
|
333
|
+
expect(r.value).toBe(true);
|
|
334
|
+
});
|
|
335
|
+
it('should short-circuit on an absent link rather than throwing', () => {
|
|
336
|
+
const r = evaluator.evaluate("payload?.customer?.tier == 'premium'", { payload: {} });
|
|
337
|
+
expect(r.success).toBe(true);
|
|
338
|
+
expect(r.value).toBe(false);
|
|
339
|
+
});
|
|
340
|
+
it('should apply the same rules to an optional index and an optional call', () => {
|
|
341
|
+
expect(evaluator.evaluate('items?.[0]?.price > 100', { items: [{ price: 150 }] }).value).toBe(true);
|
|
342
|
+
expect(evaluator.evaluate("name?.toLowerCase() == 'ada'", { name: 'Ada' }).value).toBe(true);
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
// ---------------------------------------------------------------
|
|
346
|
+
// Default exported instance
|
|
347
|
+
// ---------------------------------------------------------------
|
|
348
|
+
describe('defaultExpressionEvaluator', () => {
|
|
349
|
+
it('should be a usable SafeExpressionEvaluator instance', () => {
|
|
350
|
+
expect(defaultExpressionEvaluator).toBeInstanceOf(SafeExpressionEvaluator);
|
|
351
|
+
expect(defaultExpressionEvaluator.evaluate('1 == 1', {}).value).toBe(true);
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
//# sourceMappingURL=SafeExpressionEvaluator.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SafeExpressionEvaluator.test.js","sourceRoot":"","sources":["../../src/__tests__/SafeExpressionEvaluator.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SafeExpressionEvaluator.validateSyntax.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/SafeExpressionEvaluator.validateSyntax.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `validateSyntax` — checking that an expression *could* run, without running it.
|
|
3
|
+
*
|
|
4
|
+
* The distinction this draws is the whole point. `evaluate` reports two unrelated problems the same
|
|
5
|
+
* way: given an empty context, `payload.x > 1` fails with "payload is not defined" exactly as
|
|
6
|
+
* `payload.x >` fails with "Unexpected token". One is a typo; the other is a perfectly good
|
|
7
|
+
* condition that simply has no data yet. Anything built on `evaluate` to check authoring-time
|
|
8
|
+
* correctness therefore refuses every legitimate reference — which is the bug this method exists to
|
|
9
|
+
* make impossible.
|
|
10
|
+
*
|
|
11
|
+
* So the accept-list below matters more than the refuse-list: each entry is a shape somebody has
|
|
12
|
+
* already written, and over-refusing breaks saving work that runs fine.
|
|
13
|
+
*/
|
|
14
|
+
import { describe, it, expect } from 'vitest';
|
|
15
|
+
import { SafeExpressionEvaluator } from '../SafeExpressionEvaluator.js';
|
|
16
|
+
const evaluator = new SafeExpressionEvaluator();
|
|
17
|
+
describe('validateSyntax — parses without evaluating', () => {
|
|
18
|
+
it.each([
|
|
19
|
+
['payload.x > 1', 'an identifier that will only exist at runtime'],
|
|
20
|
+
['payload.x.y === \'a\'', 'a chain one property deeper than the envelope'],
|
|
21
|
+
['payload.title.includes(\'x\')', 'a method call on a value we cannot see yet'],
|
|
22
|
+
['stepResult.step === \'Success\'', 'the flow dialect'],
|
|
23
|
+
['unknownVar === 1', 'an identifier in no dialect at all — D2 may yet add it'],
|
|
24
|
+
['succeeded', 'the shortest legal condition there is'],
|
|
25
|
+
['output.count > 0 && !failed', 'operators either dialect uses'],
|
|
26
|
+
])('accepts %s (%s)', (expression) => {
|
|
27
|
+
expect(evaluator.validateSyntax(expression)).toEqual({ Valid: true });
|
|
28
|
+
});
|
|
29
|
+
it.each([
|
|
30
|
+
['payload.x >', 'a comparison with nothing on the right'],
|
|
31
|
+
['foo(', 'an unclosed call'],
|
|
32
|
+
['(payload.x > 1', 'unbalanced parentheses'],
|
|
33
|
+
['payload.x > 1)', 'a stray closer'],
|
|
34
|
+
['a ==== b', 'an operator that does not exist'],
|
|
35
|
+
])('refuses %s (%s)', (expression) => {
|
|
36
|
+
const verdict = evaluator.validateSyntax(expression);
|
|
37
|
+
expect(verdict.Valid).toBe(false);
|
|
38
|
+
expect(verdict.Error).toBeTruthy();
|
|
39
|
+
});
|
|
40
|
+
it('refuses what the runtime would refuse anyway, rather than letting it hold forever', () => {
|
|
41
|
+
// These are policy, not grammar — but the evaluator rejects them at run time, so the edge
|
|
42
|
+
// would hold on every poll for the life of the graph. Better said now.
|
|
43
|
+
expect(evaluator.validateSyntax('a; b').Valid).toBe(false);
|
|
44
|
+
expect(evaluator.validateSyntax('this.x').Valid).toBe(false);
|
|
45
|
+
expect(evaluator.validateSyntax('x.constructor').Valid).toBe(false);
|
|
46
|
+
});
|
|
47
|
+
it('never runs the expression it is checking', () => {
|
|
48
|
+
// The guarantee that makes compile-don't-execute safe. If validation invoked the body, a
|
|
49
|
+
// condition would have side effects at SAVE time — on somebody else's machine.
|
|
50
|
+
let touched = false;
|
|
51
|
+
const globalScope = globalThis;
|
|
52
|
+
globalScope.__mjConditionProbe = () => { touched = true; return true; };
|
|
53
|
+
try {
|
|
54
|
+
evaluator.validateSyntax('__mjConditionProbe()');
|
|
55
|
+
expect(touched).toBe(false);
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
delete globalScope.__mjConditionProbe;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=SafeExpressionEvaluator.validateSyntax.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SafeExpressionEvaluator.validateSyntax.test.js","sourceRoot":"","sources":["../../src/__tests__/SafeExpressionEvaluator.validateSyntax.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAErE,MAAM,SAAS,GAAG,IAAI,uBAAuB,EAAE,CAAC;AAEhD,QAAQ,CAAC,4CAA4C,EAAE,GAAG,EAAE;IACxD,EAAE,CAAC,IAAI,CAAC;QACJ,CAAC,eAAe,EAAE,+CAA+C,CAAC;QAClE,CAAC,uBAAuB,EAAE,+CAA+C,CAAC;QAC1E,CAAC,+BAA+B,EAAE,4CAA4C,CAAC;QAC/E,CAAC,iCAAiC,EAAE,kBAAkB,CAAC;QACvD,CAAC,kBAAkB,EAAE,wDAAwD,CAAC;QAC9E,CAAC,WAAW,EAAE,uCAAuC,CAAC;QACtD,CAAC,6BAA6B,EAAE,+BAA+B,CAAC;KACnE,CAAC,CAAC,iBAAiB,EAAE,CAAC,UAAU,EAAE,EAAE;QACjC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC;QACJ,CAAC,aAAa,EAAE,wCAAwC,CAAC;QACzD,CAAC,MAAM,EAAE,kBAAkB,CAAC;QAC5B,CAAC,gBAAgB,EAAE,wBAAwB,CAAC;QAC5C,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;QACpC,CAAC,UAAU,EAAE,iCAAiC,CAAC;KAClD,CAAC,CAAC,iBAAiB,EAAE,CAAC,UAAU,EAAE,EAAE;QACjC,MAAM,OAAO,GAAG,SAAS,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QACrD,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mFAAmF,EAAE,GAAG,EAAE;QACzF,0FAA0F;QAC1F,uEAAuE;QACvE,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3D,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7D,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAChD,yFAAyF;QACzF,+EAA+E;QAC/E,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,MAAM,WAAW,GAAG,UAAgD,CAAC;QACrE,WAAW,CAAC,kBAAkB,GAAG,GAAG,EAAE,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;QACxE,IAAI,CAAC;YACD,SAAS,CAAC,cAAc,CAAC,sBAAsB,CAAC,CAAC;YACjD,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;gBAAS,CAAC;YACP,OAAO,WAAW,CAAC,kBAAkB,CAAC;QAC1C,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.toEpochMs.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/util.toEpochMs.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { ToEpochMs } from '../util.js';
|
|
3
|
+
/**
|
|
4
|
+
* `ToEpochMs` is the shared guard behind every framework date comparator, so its contract
|
|
5
|
+
* is pinned directly here rather than only through those call sites.
|
|
6
|
+
*
|
|
7
|
+
* The contract that matters to a comparator: ALWAYS return a finite number. A comparator that
|
|
8
|
+
* can return `NaN` is incoherent — `sort` gets inconsistent orderings from it — which is the
|
|
9
|
+
* subtle half of the bug the old `?? 0` / `|| 0` patterns left open.
|
|
10
|
+
*/
|
|
11
|
+
describe('ToEpochMs', () => {
|
|
12
|
+
const ISO = '2026-08-01T00:00:00.000Z';
|
|
13
|
+
const EPOCH = Date.UTC(2026, 7, 1);
|
|
14
|
+
it('returns getTime() for a Date', () => {
|
|
15
|
+
expect(ToEpochMs(new Date(ISO))).toBe(EPOCH);
|
|
16
|
+
});
|
|
17
|
+
it('parses an ISO string — the poisoned-cache shape that used to throw', () => {
|
|
18
|
+
expect(ToEpochMs(ISO)).toBe(EPOCH);
|
|
19
|
+
});
|
|
20
|
+
it('accepts a numeric timestamp', () => {
|
|
21
|
+
expect(ToEpochMs(EPOCH)).toBe(EPOCH);
|
|
22
|
+
});
|
|
23
|
+
it('returns 0 for null and undefined', () => {
|
|
24
|
+
expect(ToEpochMs(null)).toBe(0);
|
|
25
|
+
expect(ToEpochMs(undefined)).toBe(0);
|
|
26
|
+
});
|
|
27
|
+
it('returns 0 for an unparseable string rather than NaN', () => {
|
|
28
|
+
expect(ToEpochMs('not-a-date')).toBe(0);
|
|
29
|
+
});
|
|
30
|
+
it('returns 0 for an Invalid Date rather than NaN', () => {
|
|
31
|
+
// The case `?? 0` could not catch: Invalid Date's getTime() is NaN, and NaN is not
|
|
32
|
+
// nullish, so the old form propagated NaN straight into the comparator.
|
|
33
|
+
expect(ToEpochMs(new Date('garbage'))).toBe(0);
|
|
34
|
+
});
|
|
35
|
+
it('returns 0 for an empty string', () => {
|
|
36
|
+
expect(ToEpochMs('')).toBe(0);
|
|
37
|
+
});
|
|
38
|
+
it('never returns NaN for any of the above', () => {
|
|
39
|
+
const inputs = [
|
|
40
|
+
new Date(ISO), ISO, EPOCH, null, undefined, 'not-a-date', new Date('garbage'), '', 0,
|
|
41
|
+
];
|
|
42
|
+
for (const input of inputs) {
|
|
43
|
+
expect(Number.isNaN(ToEpochMs(input))).toBe(false);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
it('orders correctly when used as a descending comparator over mixed shapes', () => {
|
|
47
|
+
const rows = [
|
|
48
|
+
{ id: 'missing', at: null },
|
|
49
|
+
{ id: 'old', at: '2026-08-01T00:00:00.000Z' },
|
|
50
|
+
{ id: 'new', at: new Date('2026-08-03T00:00:00.000Z') },
|
|
51
|
+
{ id: 'mid', at: Date.UTC(2026, 7, 2) },
|
|
52
|
+
];
|
|
53
|
+
const sorted = [...rows].sort((a, b) => ToEpochMs(b.at) - ToEpochMs(a.at));
|
|
54
|
+
expect(sorted.map((r) => r.id)).toEqual(['new', 'mid', 'old', 'missing']);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
//# sourceMappingURL=util.toEpochMs.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.toEpochMs.test.js","sourceRoot":"","sources":["../../src/__tests__/util.toEpochMs.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from './ShutdownRegistry.js';
|
|
|
9
9
|
export * from './DeepDiff.js';
|
|
10
10
|
export * from './ClassUtils.js';
|
|
11
11
|
export * from './util/PatternUtils.js';
|
|
12
|
+
export * from './util/ResourcePatternUtils.js';
|
|
12
13
|
export * from './util/UUIDUtils.js';
|
|
13
14
|
export * from './util/CronUtils.js';
|
|
14
15
|
export * from './util/SerializationUtils.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAChE,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,2BAA2B,CAAA;AACzC,cAAc,cAAc,CAAA;AAC5B,cAAc,0BAA0B,CAAA;AACxC,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AAMtC,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,+BAA+B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAChE,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,2BAA2B,CAAA;AACzC,cAAc,cAAc,CAAA;AAC5B,cAAc,0BAA0B,CAAA;AACxC,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AAMtC,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,+BAA+B,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export * from './ShutdownRegistry.js';
|
|
|
10
10
|
export * from './DeepDiff.js';
|
|
11
11
|
export * from './ClassUtils.js';
|
|
12
12
|
export * from './util/PatternUtils.js';
|
|
13
|
+
export * from './util/ResourcePatternUtils.js';
|
|
13
14
|
export * from './util/UUIDUtils.js';
|
|
14
15
|
export * from './util/CronUtils.js';
|
|
15
16
|
export * from './util/SerializationUtils.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAChE,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,2BAA2B,CAAA;AACzC,cAAc,cAAc,CAAA;AAC5B,cAAc,0BAA0B,CAAA;AACxC,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AAEtC,2DAA2D;AAC3D,oCAAoC;AAEpC,0BAA0B;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,+BAA+B,CAAA;AAE7C,6DAA6D;AAC7D,oCAAoC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAChE,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,2BAA2B,CAAA;AACzC,cAAc,cAAc,CAAA;AAC5B,cAAc,0BAA0B,CAAA;AACxC,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AAEtC,2DAA2D;AAC3D,oCAAoC;AAEpC,0BAA0B;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,+BAA+B,CAAA;AAE7C,6DAA6D;AAC7D,oCAAoC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Resolution of API scope-rule `ResourcePattern` values to a single entity target.
|
|
3
|
+
*
|
|
4
|
+
* Lives here, in the one package every consumer already depends on, because the rule has to be
|
|
5
|
+
* IDENTICAL in two places that cannot import each other: CodeGenLib's mint/drift materialization
|
|
6
|
+
* gates (`ManageMetadataBase.loadAPIKeyRowFilterTargets`) and the runtime refresher's Leak-1 gate
|
|
7
|
+
* (`MaterializationRefresher.loadAPIKeyRowFilterTargets`). Those gates decide whether an entity is
|
|
8
|
+
* row-restricted; a copy that drifts open in one of them silently re-opens the leak the other one
|
|
9
|
+
* closes, and nothing in the build would notice.
|
|
10
|
+
*
|
|
11
|
+
* @module @memberjunction/global/ResourcePatternUtils
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Resolves an API scope rule's `ResourcePattern` to the single entity name it targets, normalized for
|
|
15
|
+
* lookup (trimmed and lowercased), or `null` when it cannot be resolved to exactly one entity.
|
|
16
|
+
*
|
|
17
|
+
* `null` is the FAIL-CLOSED answer, and callers must treat it as "this rule may name any entity"
|
|
18
|
+
* rather than "this rule names nothing" — a pattern we cannot map may well name the very entity the
|
|
19
|
+
* caller is about to mirror into an unscoped snapshot. Refusing to materialize is recoverable and
|
|
20
|
+
* loud; mirroring restricted rows is neither.
|
|
21
|
+
*
|
|
22
|
+
* Normalization matches the way scope rules are authored and resolved: `IsExactResourceName` gates
|
|
23
|
+
* the pattern at save time and `Metadata.EntityByName` resolves it, both case-insensitively.
|
|
24
|
+
*
|
|
25
|
+
* @param pattern the rule's raw `ResourcePattern` (null/undefined/blank all resolve to `null`).
|
|
26
|
+
* @returns the trimmed, lowercased entity name, or `null` when the pattern is not a single exact name.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ResolveSingleEntityResourceTarget(' Salaries ') // 'salaries'
|
|
30
|
+
* ResolveSingleEntityResourceTarget('MJ: AI Agents') // 'mj: ai agents'
|
|
31
|
+
* ResolveSingleEntityResourceTarget('Sk?p') // null (would otherwise fence nothing)
|
|
32
|
+
* ResolveSingleEntityResourceTarget('A,B') // null
|
|
33
|
+
*/
|
|
34
|
+
export declare function ResolveSingleEntityResourceTarget(pattern: string | null | undefined): string | null;
|
|
35
|
+
//# sourceMappingURL=ResourcePatternUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResourcePatternUtils.d.ts","sourceRoot":"","sources":["../../src/util/ResourcePatternUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAeH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CASnG"}
|