@objectstack/formula 7.5.0 → 7.7.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/.turbo/turbo-build.log +10 -10
- package/CHANGELOG.md +57 -0
- package/dist/index.d.mts +84 -12
- package/dist/index.d.ts +84 -12
- package/dist/index.js +331 -31
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +325 -30
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/cel-engine.test.ts +65 -0
- package/src/cel-engine.ts +73 -2
- package/src/index.ts +5 -1
- package/src/template-engine.ts +194 -42
- package/src/template-formatters.test.ts +55 -0
- package/src/validate.test.ts +73 -0
- package/src/validate.ts +207 -0
package/dist/index.js
CHANGED
|
@@ -20,20 +20,25 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
CEL_STDLIB_FUNCTIONS: () => CEL_STDLIB_FUNCTIONS,
|
|
23
24
|
DEFAULT_LIMITS: () => DEFAULT_LIMITS,
|
|
24
25
|
ExpressionEngine: () => ExpressionEngine,
|
|
26
|
+
TEMPLATE_FORMATTERS: () => TEMPLATE_FORMATTERS,
|
|
25
27
|
buildScope: () => buildScope,
|
|
26
28
|
celEngine: () => celEngine,
|
|
27
29
|
cronEngine: () => cronEngine,
|
|
30
|
+
expectedDialect: () => expectedDialect,
|
|
28
31
|
getEngine: () => getEngine,
|
|
29
32
|
hasDialect: () => hasDialect,
|
|
33
|
+
introspectScope: () => introspectScope,
|
|
30
34
|
normalizeExpression: () => normalizeExpression,
|
|
31
35
|
normalizeExpressionTree: () => normalizeExpressionTree,
|
|
32
36
|
register: () => register,
|
|
33
37
|
registerStdLib: () => registerStdLib,
|
|
34
38
|
resolveSeed: () => resolveSeed,
|
|
35
39
|
resolveSeedRecord: () => resolveSeedRecord,
|
|
36
|
-
templateEngine: () => templateEngine
|
|
40
|
+
templateEngine: () => templateEngine,
|
|
41
|
+
validateExpression: () => validateExpression
|
|
37
42
|
});
|
|
38
43
|
module.exports = __toCommonJS(index_exports);
|
|
39
44
|
|
|
@@ -138,6 +143,28 @@ function coerce(value) {
|
|
|
138
143
|
}
|
|
139
144
|
return value;
|
|
140
145
|
}
|
|
146
|
+
var NUMERIC_STRING_RE = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/;
|
|
147
|
+
function isNumericOverloadError(err) {
|
|
148
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
149
|
+
return /no such overload/i.test(message);
|
|
150
|
+
}
|
|
151
|
+
function hydrateNumericStrings(value) {
|
|
152
|
+
if (typeof value === "string") {
|
|
153
|
+
const trimmed = value.trim();
|
|
154
|
+
if (trimmed.length > 0 && NUMERIC_STRING_RE.test(trimmed)) {
|
|
155
|
+
const n = Number(trimmed);
|
|
156
|
+
if (Number.isFinite(n)) return n;
|
|
157
|
+
}
|
|
158
|
+
return value;
|
|
159
|
+
}
|
|
160
|
+
if (Array.isArray(value)) return value.map(hydrateNumericStrings);
|
|
161
|
+
if (value && typeof value === "object" && !(value instanceof Date)) {
|
|
162
|
+
const out = {};
|
|
163
|
+
for (const [k, v] of Object.entries(value)) out[k] = hydrateNumericStrings(v);
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
141
168
|
function classifyError(err) {
|
|
142
169
|
const message = err instanceof Error ? err.message : String(err);
|
|
143
170
|
let kind = "runtime";
|
|
@@ -182,8 +209,19 @@ var celEngine = {
|
|
|
182
209
|
try {
|
|
183
210
|
const env = buildEnv(now);
|
|
184
211
|
const scope = buildScope(ctx);
|
|
185
|
-
|
|
186
|
-
|
|
212
|
+
try {
|
|
213
|
+
const raw = env.evaluate(source, scope);
|
|
214
|
+
return { ok: true, value: coerce(raw) };
|
|
215
|
+
} catch (err) {
|
|
216
|
+
if (!isNumericOverloadError(err)) throw err;
|
|
217
|
+
const hydrated = hydrateNumericStrings(scope);
|
|
218
|
+
try {
|
|
219
|
+
const raw = env.evaluate(source, hydrated);
|
|
220
|
+
return { ok: true, value: coerce(raw) };
|
|
221
|
+
} catch {
|
|
222
|
+
throw err;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
187
225
|
} catch (err) {
|
|
188
226
|
return classifyError(err);
|
|
189
227
|
}
|
|
@@ -260,18 +298,96 @@ var cronEngine = {
|
|
|
260
298
|
};
|
|
261
299
|
|
|
262
300
|
// src/template-engine.ts
|
|
263
|
-
var
|
|
264
|
-
function
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
301
|
+
var HOLE_RE = /\{\{([^}]*)\}\}/g;
|
|
302
|
+
function asNumber(v) {
|
|
303
|
+
if (typeof v === "number") return v;
|
|
304
|
+
if (typeof v === "bigint") return Number(v);
|
|
305
|
+
if (typeof v === "string" && v.trim() !== "" && !Number.isNaN(Number(v))) return Number(v);
|
|
306
|
+
return void 0;
|
|
307
|
+
}
|
|
308
|
+
function asDate(v) {
|
|
309
|
+
if (v instanceof Date) return v;
|
|
310
|
+
if (typeof v === "number") return new Date(v);
|
|
311
|
+
if (typeof v === "string") {
|
|
312
|
+
const d = new Date(v);
|
|
313
|
+
if (!Number.isNaN(d.getTime())) return d;
|
|
271
314
|
}
|
|
272
|
-
return
|
|
315
|
+
return void 0;
|
|
273
316
|
}
|
|
274
|
-
|
|
317
|
+
var FORMATTERS = {
|
|
318
|
+
upper: (v) => baseString(v).toUpperCase(),
|
|
319
|
+
lower: (v) => baseString(v).toLowerCase(),
|
|
320
|
+
trim: (v) => baseString(v).trim(),
|
|
321
|
+
// number | number:2 → grouped, optional fixed decimals
|
|
322
|
+
number: (v, arg, locale) => {
|
|
323
|
+
const n = asNumber(v);
|
|
324
|
+
if (n === void 0) return baseString(v);
|
|
325
|
+
const digits = arg !== void 0 ? Number(arg) : void 0;
|
|
326
|
+
return new Intl.NumberFormat(locale, digits !== void 0 && !Number.isNaN(digits) ? { minimumFractionDigits: digits, maximumFractionDigits: digits } : {}).format(n);
|
|
327
|
+
},
|
|
328
|
+
// currency | currency:EUR → defaults to USD
|
|
329
|
+
currency: (v, arg, locale) => {
|
|
330
|
+
const n = asNumber(v);
|
|
331
|
+
if (n === void 0) return baseString(v);
|
|
332
|
+
const code = arg && arg.trim() || "USD";
|
|
333
|
+
try {
|
|
334
|
+
return new Intl.NumberFormat(locale, { style: "currency", currency: code }).format(n);
|
|
335
|
+
} catch {
|
|
336
|
+
return new Intl.NumberFormat(locale, { style: "currency", currency: "USD" }).format(n);
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
// percent | percent:1 → 0.42 → "42%" (value is a 0..1 ratio)
|
|
340
|
+
percent: (v, arg, locale) => {
|
|
341
|
+
const n = asNumber(v);
|
|
342
|
+
if (n === void 0) return baseString(v);
|
|
343
|
+
const digits = arg !== void 0 ? Number(arg) : 0;
|
|
344
|
+
return new Intl.NumberFormat(locale, {
|
|
345
|
+
style: "percent",
|
|
346
|
+
minimumFractionDigits: Number.isNaN(digits) ? 0 : digits,
|
|
347
|
+
maximumFractionDigits: Number.isNaN(digits) ? 0 : digits
|
|
348
|
+
}).format(n);
|
|
349
|
+
},
|
|
350
|
+
// date | date:long | date:iso → date-only
|
|
351
|
+
date: (v, arg, locale) => {
|
|
352
|
+
const d = asDate(v);
|
|
353
|
+
if (!d) return baseString(v);
|
|
354
|
+
if (arg === "iso") return d.toISOString().slice(0, 10);
|
|
355
|
+
const style = arg === "long" ? "long" : arg === "medium" ? "medium" : "short";
|
|
356
|
+
return new Intl.DateTimeFormat(locale, { dateStyle: style }).format(d);
|
|
357
|
+
},
|
|
358
|
+
// datetime | datetime:long | datetime:iso
|
|
359
|
+
datetime: (v, arg, locale) => {
|
|
360
|
+
const d = asDate(v);
|
|
361
|
+
if (!d) return baseString(v);
|
|
362
|
+
if (arg === "iso") return d.toISOString();
|
|
363
|
+
const style = arg === "long" ? "long" : arg === "medium" ? "medium" : "short";
|
|
364
|
+
return new Intl.DateTimeFormat(locale, {
|
|
365
|
+
dateStyle: style,
|
|
366
|
+
timeStyle: style
|
|
367
|
+
}).format(d);
|
|
368
|
+
},
|
|
369
|
+
// truncate:80 → cut with an ellipsis
|
|
370
|
+
truncate: (v, arg) => {
|
|
371
|
+
const s = baseString(v);
|
|
372
|
+
const len = arg !== void 0 ? Number(arg) : 80;
|
|
373
|
+
if (Number.isNaN(len) || s.length <= len) return s;
|
|
374
|
+
return s.slice(0, Math.max(0, len - 1)) + "\u2026";
|
|
375
|
+
},
|
|
376
|
+
// default:'N/A' → fallback when the value is null/undefined/empty
|
|
377
|
+
default: (v, arg) => {
|
|
378
|
+
const s = baseString(v);
|
|
379
|
+
return s === "" ? arg ?? "" : s;
|
|
380
|
+
},
|
|
381
|
+
json: (v) => {
|
|
382
|
+
try {
|
|
383
|
+
return JSON.stringify(v);
|
|
384
|
+
} catch {
|
|
385
|
+
return String(v);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
var TEMPLATE_FORMATTERS = Object.keys(FORMATTERS);
|
|
390
|
+
function baseString(value) {
|
|
275
391
|
if (value === null || value === void 0) return "";
|
|
276
392
|
if (value instanceof Date) return value.toISOString();
|
|
277
393
|
if (typeof value === "string") return value;
|
|
@@ -283,21 +399,59 @@ function stringify(value) {
|
|
|
283
399
|
return String(value);
|
|
284
400
|
}
|
|
285
401
|
}
|
|
402
|
+
function resolvePath(scope, path) {
|
|
403
|
+
const normalized = path.replace(/\[(\w+)\]/g, ".$1");
|
|
404
|
+
const segments = normalized.split(".").filter(Boolean);
|
|
405
|
+
let cursor = scope;
|
|
406
|
+
for (const seg of segments) {
|
|
407
|
+
if (cursor == null || typeof cursor !== "object") return void 0;
|
|
408
|
+
cursor = cursor[seg];
|
|
409
|
+
}
|
|
410
|
+
return cursor;
|
|
411
|
+
}
|
|
412
|
+
var PATH_ONLY_RE = /^[\w.[\]]+$/;
|
|
413
|
+
function parseHole(inner) {
|
|
414
|
+
const pipe = inner.indexOf("|");
|
|
415
|
+
if (pipe === -1) {
|
|
416
|
+
const path2 = inner.trim();
|
|
417
|
+
return PATH_ONLY_RE.test(path2) ? { path: path2 } : null;
|
|
418
|
+
}
|
|
419
|
+
const path = inner.slice(0, pipe).trim();
|
|
420
|
+
if (!PATH_ONLY_RE.test(path)) return null;
|
|
421
|
+
const filterPart = inner.slice(pipe + 1).trim();
|
|
422
|
+
const colon = filterPart.indexOf(":");
|
|
423
|
+
let name = filterPart;
|
|
424
|
+
let arg;
|
|
425
|
+
if (colon !== -1) {
|
|
426
|
+
name = filterPart.slice(0, colon).trim();
|
|
427
|
+
arg = filterPart.slice(colon + 1).trim().replace(/^['"]|['"]$/g, "");
|
|
428
|
+
}
|
|
429
|
+
if (!FORMATTERS[name]) return null;
|
|
430
|
+
return { path, filter: { name, arg } };
|
|
431
|
+
}
|
|
286
432
|
function compileTemplate(source) {
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
error: { kind: "parse", message: "template has unbalanced {{ }} delimiters" }
|
|
292
|
-
};
|
|
433
|
+
const open = (source.match(/\{\{/g) ?? []).length;
|
|
434
|
+
const close = (source.match(/\}\}/g) ?? []).length;
|
|
435
|
+
if (open !== close) {
|
|
436
|
+
return { ok: false, error: { kind: "parse", message: "template has unbalanced {{ }} delimiters" } };
|
|
293
437
|
}
|
|
294
|
-
const
|
|
438
|
+
const holes = [];
|
|
295
439
|
let m;
|
|
296
|
-
|
|
297
|
-
while ((m =
|
|
298
|
-
|
|
440
|
+
HOLE_RE.lastIndex = 0;
|
|
441
|
+
while ((m = HOLE_RE.exec(source)) !== null) {
|
|
442
|
+
const parsed = parseHole(m[1]);
|
|
443
|
+
if (!parsed) {
|
|
444
|
+
return {
|
|
445
|
+
ok: false,
|
|
446
|
+
error: {
|
|
447
|
+
kind: "parse",
|
|
448
|
+
message: `invalid template hole \`{{ ${m[1]} }}\` \u2014 holes are a field path with an optional formatter (\`{{ record.amount | currency }}\`), not arbitrary logic. Move logic into a CEL field. Known formatters: ${TEMPLATE_FORMATTERS.join(", ")}.`
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
holes.push(parsed);
|
|
299
453
|
}
|
|
300
|
-
return { ok: true, value:
|
|
454
|
+
return { ok: true, value: holes };
|
|
301
455
|
}
|
|
302
456
|
var templateEngine = {
|
|
303
457
|
dialect: "template",
|
|
@@ -312,16 +466,20 @@ var templateEngine = {
|
|
|
312
466
|
};
|
|
313
467
|
}
|
|
314
468
|
if (typeof expr.source !== "string") {
|
|
315
|
-
return {
|
|
316
|
-
ok: false,
|
|
317
|
-
error: { kind: "parse", message: "template Expression.source required" }
|
|
318
|
-
};
|
|
469
|
+
return { ok: false, error: { kind: "parse", message: "template Expression.source required" } };
|
|
319
470
|
}
|
|
320
471
|
const check = compileTemplate(expr.source);
|
|
321
472
|
if (!check.ok) return check;
|
|
322
473
|
const scope = buildScope(ctx);
|
|
323
|
-
const
|
|
324
|
-
|
|
474
|
+
const locale = ctx.extra && typeof ctx.extra.locale === "string" && ctx.extra.locale || typeof ctx.locale === "string" && ctx.locale || "en-US";
|
|
475
|
+
const out = expr.source.replace(HOLE_RE, (_match, inner) => {
|
|
476
|
+
const parsed = parseHole(String(inner));
|
|
477
|
+
if (!parsed) return _match;
|
|
478
|
+
const value = resolvePath(scope, parsed.path);
|
|
479
|
+
if (parsed.filter) {
|
|
480
|
+
return FORMATTERS[parsed.filter.name](value, parsed.filter.arg, locale);
|
|
481
|
+
}
|
|
482
|
+
return baseString(value);
|
|
325
483
|
});
|
|
326
484
|
return { ok: true, value: out };
|
|
327
485
|
}
|
|
@@ -487,21 +645,163 @@ function looksLikeExpression(value) {
|
|
|
487
645
|
if (typeof v.dialect !== "string") return false;
|
|
488
646
|
return import_spec2.ExpressionSchema.safeParse(v).success;
|
|
489
647
|
}
|
|
648
|
+
|
|
649
|
+
// src/validate.ts
|
|
650
|
+
var SINGLE_BRACE_RE = /(?:^|[^{])\{\s*([A-Za-z_$][\w.$]*)\s*\}(?!\})/;
|
|
651
|
+
var RECORD_REF_RE = /\b(?:record|previous)\.([A-Za-z_$][\w$]*)/g;
|
|
652
|
+
function expectedDialect(role) {
|
|
653
|
+
return role === "template" ? "template" : "cel";
|
|
654
|
+
}
|
|
655
|
+
function toSource(input) {
|
|
656
|
+
if (input == null) return { source: "" };
|
|
657
|
+
if (typeof input === "string") return { source: input };
|
|
658
|
+
return { dialect: input.dialect, source: input.source ?? "" };
|
|
659
|
+
}
|
|
660
|
+
function bracesHint(source) {
|
|
661
|
+
const m = SINGLE_BRACE_RE.exec(source);
|
|
662
|
+
if (!m) return null;
|
|
663
|
+
const ref = m[1];
|
|
664
|
+
return `it looks like a \`{${ref}}\` template brace was used inside a CEL expression \u2014 \`{\u2026}\` parses as a CEL map literal and fails. Write the bare reference instead, e.g. \`${ref}\`.`;
|
|
665
|
+
}
|
|
666
|
+
function checkFieldExistence(source, schema, errors) {
|
|
667
|
+
if (!schema?.fields || schema.fields.length === 0) return;
|
|
668
|
+
const known = new Set(schema.fields);
|
|
669
|
+
const seen = /* @__PURE__ */ new Set();
|
|
670
|
+
let m;
|
|
671
|
+
RECORD_REF_RE.lastIndex = 0;
|
|
672
|
+
while ((m = RECORD_REF_RE.exec(source)) !== null) {
|
|
673
|
+
const field = m[1];
|
|
674
|
+
if (seen.has(field) || known.has(field)) continue;
|
|
675
|
+
seen.add(field);
|
|
676
|
+
const suggestion = nearest(field, schema.fields);
|
|
677
|
+
errors.push({
|
|
678
|
+
source,
|
|
679
|
+
message: `unknown field \`${field}\`${schema.objectName ? ` on \`${schema.objectName}\`` : ""}` + (suggestion ? ` \u2014 did you mean \`${suggestion}\`?` : "")
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
function nearest(name, candidates) {
|
|
684
|
+
let best;
|
|
685
|
+
let bestD = Infinity;
|
|
686
|
+
for (const c of candidates) {
|
|
687
|
+
const d = levenshtein(name, c);
|
|
688
|
+
if (d < bestD) {
|
|
689
|
+
bestD = d;
|
|
690
|
+
best = c;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return bestD <= Math.max(2, Math.floor(name.length / 3)) ? best : void 0;
|
|
694
|
+
}
|
|
695
|
+
function levenshtein(a, b) {
|
|
696
|
+
const m = a.length, n = b.length;
|
|
697
|
+
const dp = Array.from({ length: m + 1 }, (_, i) => i);
|
|
698
|
+
for (let j = 1; j <= n; j++) {
|
|
699
|
+
let prev = dp[0];
|
|
700
|
+
dp[0] = j;
|
|
701
|
+
for (let i = 1; i <= m; i++) {
|
|
702
|
+
const tmp = dp[i];
|
|
703
|
+
dp[i] = Math.min(dp[i] + 1, dp[i - 1] + 1, prev + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
704
|
+
prev = tmp;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
return dp[m];
|
|
708
|
+
}
|
|
709
|
+
function validateExpression(role, input, schema) {
|
|
710
|
+
const { dialect, source } = toSource(input);
|
|
711
|
+
const errors = [];
|
|
712
|
+
if (!source.trim()) return { ok: true, errors };
|
|
713
|
+
if (role === "template") {
|
|
714
|
+
if (dialect && dialect !== "template") {
|
|
715
|
+
errors.push({ source, message: `expected a text template but got a \`${dialect}\` expression.` });
|
|
716
|
+
return { ok: false, errors };
|
|
717
|
+
}
|
|
718
|
+
const compiled2 = templateEngine.compile(source);
|
|
719
|
+
if (!compiled2.ok) {
|
|
720
|
+
errors.push({ source, message: `invalid template: ${compiled2.error.message} (holes use \`{{ path }}\`).` });
|
|
721
|
+
}
|
|
722
|
+
const hint = SINGLE_BRACE_RE.test(source) ? bracesHintForTemplate(source) : null;
|
|
723
|
+
if (hint) errors.push({ source, message: hint });
|
|
724
|
+
return { ok: errors.length === 0, errors };
|
|
725
|
+
}
|
|
726
|
+
if (dialect && dialect !== "cel") {
|
|
727
|
+
errors.push({ source, message: `expected a CEL expression but got a \`${dialect}\` dialect.` });
|
|
728
|
+
return { ok: false, errors };
|
|
729
|
+
}
|
|
730
|
+
const compiled = celEngine.compile(source);
|
|
731
|
+
if (!compiled.ok) {
|
|
732
|
+
const hint = bracesHint(source);
|
|
733
|
+
errors.push({
|
|
734
|
+
source,
|
|
735
|
+
message: `invalid CEL ${role}: ${compiled.error.message}` + (hint ? ` \u2014 ${hint}` : ` \u2014 ${role}s are bare CEL (e.g. \`record.rating >= 4\`).`)
|
|
736
|
+
});
|
|
737
|
+
} else {
|
|
738
|
+
checkFieldExistence(source, schema, errors);
|
|
739
|
+
}
|
|
740
|
+
return { ok: errors.length === 0, errors };
|
|
741
|
+
}
|
|
742
|
+
function bracesHintForTemplate(source) {
|
|
743
|
+
const m = SINGLE_BRACE_RE.exec(source);
|
|
744
|
+
const ref = m?.[1] ?? "field";
|
|
745
|
+
return `single-brace \`{${ref}}\` is not a valid template hole \u2014 use double braces: \`{{ ${ref} }}\`.`;
|
|
746
|
+
}
|
|
747
|
+
function introspectScope(role, schema) {
|
|
748
|
+
return {
|
|
749
|
+
dialect: expectedDialect(role),
|
|
750
|
+
fields: [...schema?.fields ?? []],
|
|
751
|
+
roots: ["record", "previous", "input", "os", "vars"],
|
|
752
|
+
functions: CEL_STDLIB_FUNCTIONS
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
var CEL_STDLIB_FUNCTIONS = [
|
|
756
|
+
"now",
|
|
757
|
+
"today",
|
|
758
|
+
"daysFromNow",
|
|
759
|
+
"daysBetween",
|
|
760
|
+
"date",
|
|
761
|
+
"datetime",
|
|
762
|
+
"timestamp",
|
|
763
|
+
"isBlank",
|
|
764
|
+
"isEmpty",
|
|
765
|
+
"coalesce",
|
|
766
|
+
"len",
|
|
767
|
+
"size",
|
|
768
|
+
"int",
|
|
769
|
+
"float",
|
|
770
|
+
"string",
|
|
771
|
+
"bool",
|
|
772
|
+
"upper",
|
|
773
|
+
"lower",
|
|
774
|
+
"trim",
|
|
775
|
+
"contains",
|
|
776
|
+
"startsWith",
|
|
777
|
+
"endsWith",
|
|
778
|
+
"matches",
|
|
779
|
+
"has",
|
|
780
|
+
"min",
|
|
781
|
+
"max",
|
|
782
|
+
"abs",
|
|
783
|
+
"round"
|
|
784
|
+
];
|
|
490
785
|
// Annotate the CommonJS export names for ESM import in node:
|
|
491
786
|
0 && (module.exports = {
|
|
787
|
+
CEL_STDLIB_FUNCTIONS,
|
|
492
788
|
DEFAULT_LIMITS,
|
|
493
789
|
ExpressionEngine,
|
|
790
|
+
TEMPLATE_FORMATTERS,
|
|
494
791
|
buildScope,
|
|
495
792
|
celEngine,
|
|
496
793
|
cronEngine,
|
|
794
|
+
expectedDialect,
|
|
497
795
|
getEngine,
|
|
498
796
|
hasDialect,
|
|
797
|
+
introspectScope,
|
|
499
798
|
normalizeExpression,
|
|
500
799
|
normalizeExpressionTree,
|
|
501
800
|
register,
|
|
502
801
|
registerStdLib,
|
|
503
802
|
resolveSeed,
|
|
504
803
|
resolveSeedRecord,
|
|
505
|
-
templateEngine
|
|
804
|
+
templateEngine,
|
|
805
|
+
validateExpression
|
|
506
806
|
});
|
|
507
807
|
//# sourceMappingURL=index.js.map
|