@objectstack/formula 9.8.0 → 9.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/.turbo/turbo-build.log +10 -10
- package/CHANGELOG.md +34 -0
- package/dist/index.d.mts +23 -2
- package/dist/index.d.ts +23 -2
- package/dist/index.js +45 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +44 -12
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/cel-engine.test.ts +19 -2
- package/src/cel-engine.ts +3 -3
- package/src/index.ts +1 -1
- package/src/seed-eval.test.ts +6 -2
- package/src/skill-catalog-sync.test.ts +32 -0
- package/src/stdlib.ts +42 -3
- package/src/template-engine.ts +39 -5
- package/src/template-formatters.test.ts +36 -3
- package/src/types.ts +7 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @objectstack/formula@9.
|
|
2
|
+
> @objectstack/formula@9.9.0 build /home/runner/work/framework/framework/packages/formula
|
|
3
3
|
> tsup --config ../../tsup.config.ts
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
[34mCLI[39m Cleaning output folder
|
|
11
11
|
[34mESM[39m Build start
|
|
12
12
|
[34mCJS[39m Build start
|
|
13
|
-
[32mCJS[39m [1mdist/index.js [22m[
|
|
14
|
-
[32mCJS[39m [1mdist/index.js.map [22m[
|
|
15
|
-
[32mCJS[39m ⚡️ Build success in
|
|
16
|
-
[32mESM[39m [1mdist/index.mjs [22m[
|
|
17
|
-
[32mESM[39m [1mdist/index.mjs.map [22m[
|
|
18
|
-
[32mESM[39m ⚡️ Build success in
|
|
13
|
+
[32mCJS[39m [1mdist/index.js [22m[32m31.13 KB[39m
|
|
14
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m83.10 KB[39m
|
|
15
|
+
[32mCJS[39m ⚡️ Build success in 67ms
|
|
16
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m29.37 KB[39m
|
|
17
|
+
[32mESM[39m [1mdist/index.mjs.map [22m[32m81.72 KB[39m
|
|
18
|
+
[32mESM[39m ⚡️ Build success in 84ms
|
|
19
19
|
[34mDTS[39m Build start
|
|
20
|
-
[32mDTS[39m ⚡️ Build success in
|
|
21
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[
|
|
22
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[
|
|
20
|
+
[32mDTS[39m ⚡️ Build success in 4303ms
|
|
21
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m16.79 KB[39m
|
|
22
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m16.79 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# @objectstack/formula
|
|
2
2
|
|
|
3
|
+
## 9.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- d99a75a: feat(formula): timezone-aware `today()` / `daysFromNow()` / `daysAgo()` (ADR-0053 Phase 2)
|
|
8
|
+
|
|
9
|
+
These are now **calendar-day** functions resolved in a reference timezone, threaded from `ExecutionContext.timezone` (#1978) through `EvalContext.timezone` into the CEL stdlib. Each returns the reference-tz calendar day expressed as a **UTC-midnight `Date`** (ADR-0053 decision D1) — the one representation consistent with how `Field.date` strings hydrate, how the SQL driver normalizes date filters, and how Phase 1 stores dates. So `record.close_date == daysFromNow(30)` now matches in-memory too, not just at the storage boundary. The timezone calculation uses `Intl.DateTimeFormat` (DST-safe; no hand-rolled offset math).
|
|
10
|
+
|
|
11
|
+
**⚠️ Behavior change:** `daysFromNow(n)` / `daysAgo(n)` previously kept the wall-clock time of `now` (e.g. `daysFromNow(30)` at `10:00Z` → `…T10:00:00Z`). They now drop the time and return the calendar day at **midnight** (`…T00:00:00Z`) — the ADR-0053 "defect #3" fix. `today()` is unchanged at UTC (it already truncated to start-of-day). For a genuine sub-day offset use the documented escape hatch `now() + duration("Nh")`.
|
|
12
|
+
|
|
13
|
+
With no reference timezone configured the zone resolves to `UTC`, so `today()` is byte-for-byte unchanged; only the `daysFromNow`/`daysAgo` midnight-truncation differs from before. `objectql` threads `execCtx.timezone` into read-time formula evaluation (`applyFormulaPlan`) and default-value expressions (`applyFieldDefaults`).
|
|
14
|
+
|
|
15
|
+
Part of #1980. (Consuming a non-UTC reference timezone end-to-end also needs the `localization` settings manifest noted in #1978.)
|
|
16
|
+
|
|
17
|
+
- 575448d: feat(formula,email): render `datetime` in a reference timezone (ADR-0053 Phase 2)
|
|
18
|
+
|
|
19
|
+
`datetime` template holes now render in a reference timezone's wall-clock when one is supplied, at the presentation boundary — storage stays UTC.
|
|
20
|
+
|
|
21
|
+
- **Formula template engine** — the `datetime` formatter takes the reference timezone from `EvalContext.timezone` (threaded in #1980) and passes it to `Intl.DateTimeFormat`. `{{ ts | datetime }}` renders in that zone; `{{ ts | datetime:iso }}` stays UTC (machine-readable). Calendar-day `date` rendering is intentionally **unchanged** (tz-naive — a `Field.date` has no zone). New exported `formatValue(name, value, arg, { locale, timeZone })` makes the whitelisted formatters reusable outside the full CEL template engine.
|
|
22
|
+
- **Email pipeline** — `plugin-email`'s renderer previously bypassed the formatter pipeline (`String()` only), so a datetime went out as raw ISO. Email holes now accept the shared formula formatters — `{{ order.total | currency }}`, `{{ ts | datetime }}` — reusing `formatValue` (single source of truth), while keeping the engine's HTML-escaping and `{{{ }}}` raw-output semantics. `SendTemplateInput.timezone` (mirroring the existing `locale`) flows into rendering so an email's datetime shows the recipient's wall-clock.
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
- Updated dependencies [84249a4]
|
|
27
|
+
- Updated dependencies [11af299]
|
|
28
|
+
- Updated dependencies [d5774b5]
|
|
29
|
+
- Updated dependencies [134043a]
|
|
30
|
+
- Updated dependencies [90108e0]
|
|
31
|
+
- Updated dependencies [9afeb2d]
|
|
32
|
+
- Updated dependencies [6bec07e]
|
|
33
|
+
- Updated dependencies [601cc11]
|
|
34
|
+
- Updated dependencies [575448d]
|
|
35
|
+
- @objectstack/spec@9.9.0
|
|
36
|
+
|
|
3
37
|
## 9.8.0
|
|
4
38
|
|
|
5
39
|
### Minor Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -24,6 +24,13 @@ import { Environment } from '@marcbachmann/cel-js';
|
|
|
24
24
|
interface EvalContext {
|
|
25
25
|
/** Logical "now" snapshot — pinned per evaluation run for determinism. */
|
|
26
26
|
now?: Date;
|
|
27
|
+
/**
|
|
28
|
+
* Reference timezone (IANA name, e.g. `America/New_York`) for calendar-day
|
|
29
|
+
* functions `today()` / `daysFromNow()` / `daysAgo()` and for rendering
|
|
30
|
+
* `datetime` template holes in that zone's wall-clock (ADR-0053 Phase 2).
|
|
31
|
+
* Defaults to `UTC` when unset. Calendar-day `date` rendering stays tz-naive.
|
|
32
|
+
*/
|
|
33
|
+
timezone?: string;
|
|
27
34
|
/** Current authenticated subject (hook / action / view contexts). */
|
|
28
35
|
user?: {
|
|
29
36
|
id: string;
|
|
@@ -198,6 +205,20 @@ declare const cronEngine: DialectEngine;
|
|
|
198
205
|
|
|
199
206
|
/** Public list of whitelisted template formatters (for introspection/docs). */
|
|
200
207
|
declare const TEMPLATE_FORMATTERS: string[];
|
|
208
|
+
/**
|
|
209
|
+
* Apply a whitelisted formatter to a value, the single source of truth for
|
|
210
|
+
* value→string semantics across dialects. Returns `undefined` for an unknown
|
|
211
|
+
* formatter name so callers can decide how to handle it (the template engine
|
|
212
|
+
* rejects at compile time; other consumers may pass the raw value through).
|
|
213
|
+
*
|
|
214
|
+
* Exported so renderers that don't run the full CEL template engine — notably
|
|
215
|
+
* the email pipeline (ADR-0053 Phase 2 slice 4) — format dates, money, etc.
|
|
216
|
+
* identically to in-app templates, including reference-timezone `datetime`.
|
|
217
|
+
*/
|
|
218
|
+
declare function formatValue(name: string, value: unknown, arg: string | undefined, opts?: {
|
|
219
|
+
locale?: string;
|
|
220
|
+
timeZone?: string;
|
|
221
|
+
}): string | undefined;
|
|
201
222
|
declare const templateEngine: DialectEngine;
|
|
202
223
|
|
|
203
224
|
/**
|
|
@@ -221,7 +242,7 @@ declare const templateEngine: DialectEngine;
|
|
|
221
242
|
* and dependency-free — they're the contract surface for AI authors and must
|
|
222
243
|
* stay legible.
|
|
223
244
|
*/
|
|
224
|
-
declare function registerStdLib(env: Environment, now: () => Date): Environment;
|
|
245
|
+
declare function registerStdLib(env: Environment, now: () => Date, timezone?: string): Environment;
|
|
225
246
|
/**
|
|
226
247
|
* Build the variable scope for a single evaluation. Absent fields are simply
|
|
227
248
|
* not bound — CEL macros (`has(record.foo)`) handle missing-key safely.
|
|
@@ -372,4 +393,4 @@ declare function introspectScope(role: FieldRole, schema?: ExprSchemaHint): {
|
|
|
372
393
|
*/
|
|
373
394
|
declare const CEL_STDLIB_FUNCTIONS: string[];
|
|
374
395
|
|
|
375
|
-
export { CEL_STDLIB_FUNCTIONS, DEFAULT_LIMITS, type DialectEngine, type EvalContext, type EvalError, type EvalResult, type ExprSchemaHint, type ExprValidationError, type ExprValidationResult, ExpressionEngine, type FieldRole, type SeedPrimitive, type SeedValue, TEMPLATE_FORMATTERS, buildScope, celEngine, cronEngine, expectedDialect, getEngine, hasDialect, introspectScope, normalizeExpression, normalizeExpressionTree, register, registerStdLib, resolveSeed, resolveSeedRecord, templateEngine, validateExpression };
|
|
396
|
+
export { CEL_STDLIB_FUNCTIONS, DEFAULT_LIMITS, type DialectEngine, type EvalContext, type EvalError, type EvalResult, type ExprSchemaHint, type ExprValidationError, type ExprValidationResult, ExpressionEngine, type FieldRole, type SeedPrimitive, type SeedValue, TEMPLATE_FORMATTERS, buildScope, celEngine, cronEngine, expectedDialect, formatValue, getEngine, hasDialect, introspectScope, normalizeExpression, normalizeExpressionTree, register, registerStdLib, resolveSeed, resolveSeedRecord, templateEngine, validateExpression };
|
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,13 @@ import { Environment } from '@marcbachmann/cel-js';
|
|
|
24
24
|
interface EvalContext {
|
|
25
25
|
/** Logical "now" snapshot — pinned per evaluation run for determinism. */
|
|
26
26
|
now?: Date;
|
|
27
|
+
/**
|
|
28
|
+
* Reference timezone (IANA name, e.g. `America/New_York`) for calendar-day
|
|
29
|
+
* functions `today()` / `daysFromNow()` / `daysAgo()` and for rendering
|
|
30
|
+
* `datetime` template holes in that zone's wall-clock (ADR-0053 Phase 2).
|
|
31
|
+
* Defaults to `UTC` when unset. Calendar-day `date` rendering stays tz-naive.
|
|
32
|
+
*/
|
|
33
|
+
timezone?: string;
|
|
27
34
|
/** Current authenticated subject (hook / action / view contexts). */
|
|
28
35
|
user?: {
|
|
29
36
|
id: string;
|
|
@@ -198,6 +205,20 @@ declare const cronEngine: DialectEngine;
|
|
|
198
205
|
|
|
199
206
|
/** Public list of whitelisted template formatters (for introspection/docs). */
|
|
200
207
|
declare const TEMPLATE_FORMATTERS: string[];
|
|
208
|
+
/**
|
|
209
|
+
* Apply a whitelisted formatter to a value, the single source of truth for
|
|
210
|
+
* value→string semantics across dialects. Returns `undefined` for an unknown
|
|
211
|
+
* formatter name so callers can decide how to handle it (the template engine
|
|
212
|
+
* rejects at compile time; other consumers may pass the raw value through).
|
|
213
|
+
*
|
|
214
|
+
* Exported so renderers that don't run the full CEL template engine — notably
|
|
215
|
+
* the email pipeline (ADR-0053 Phase 2 slice 4) — format dates, money, etc.
|
|
216
|
+
* identically to in-app templates, including reference-timezone `datetime`.
|
|
217
|
+
*/
|
|
218
|
+
declare function formatValue(name: string, value: unknown, arg: string | undefined, opts?: {
|
|
219
|
+
locale?: string;
|
|
220
|
+
timeZone?: string;
|
|
221
|
+
}): string | undefined;
|
|
201
222
|
declare const templateEngine: DialectEngine;
|
|
202
223
|
|
|
203
224
|
/**
|
|
@@ -221,7 +242,7 @@ declare const templateEngine: DialectEngine;
|
|
|
221
242
|
* and dependency-free — they're the contract surface for AI authors and must
|
|
222
243
|
* stay legible.
|
|
223
244
|
*/
|
|
224
|
-
declare function registerStdLib(env: Environment, now: () => Date): Environment;
|
|
245
|
+
declare function registerStdLib(env: Environment, now: () => Date, timezone?: string): Environment;
|
|
225
246
|
/**
|
|
226
247
|
* Build the variable scope for a single evaluation. Absent fields are simply
|
|
227
248
|
* not bound — CEL macros (`has(record.foo)`) handle missing-key safely.
|
|
@@ -372,4 +393,4 @@ declare function introspectScope(role: FieldRole, schema?: ExprSchemaHint): {
|
|
|
372
393
|
*/
|
|
373
394
|
declare const CEL_STDLIB_FUNCTIONS: string[];
|
|
374
395
|
|
|
375
|
-
export { CEL_STDLIB_FUNCTIONS, DEFAULT_LIMITS, type DialectEngine, type EvalContext, type EvalError, type EvalResult, type ExprSchemaHint, type ExprValidationError, type ExprValidationResult, ExpressionEngine, type FieldRole, type SeedPrimitive, type SeedValue, TEMPLATE_FORMATTERS, buildScope, celEngine, cronEngine, expectedDialect, getEngine, hasDialect, introspectScope, normalizeExpression, normalizeExpressionTree, register, registerStdLib, resolveSeed, resolveSeedRecord, templateEngine, validateExpression };
|
|
396
|
+
export { CEL_STDLIB_FUNCTIONS, DEFAULT_LIMITS, type DialectEngine, type EvalContext, type EvalError, type EvalResult, type ExprSchemaHint, type ExprValidationError, type ExprValidationResult, ExpressionEngine, type FieldRole, type SeedPrimitive, type SeedValue, TEMPLATE_FORMATTERS, buildScope, celEngine, cronEngine, expectedDialect, formatValue, getEngine, hasDialect, introspectScope, normalizeExpression, normalizeExpressionTree, register, registerStdLib, resolveSeed, resolveSeedRecord, templateEngine, validateExpression };
|
package/dist/index.js
CHANGED
|
@@ -28,6 +28,7 @@ __export(index_exports, {
|
|
|
28
28
|
celEngine: () => celEngine,
|
|
29
29
|
cronEngine: () => cronEngine,
|
|
30
30
|
expectedDialect: () => expectedDialect,
|
|
31
|
+
formatValue: () => formatValue,
|
|
31
32
|
getEngine: () => getEngine,
|
|
32
33
|
hasDialect: () => hasDialect,
|
|
33
34
|
introspectScope: () => introspectScope,
|
|
@@ -46,6 +47,26 @@ module.exports = __toCommonJS(index_exports);
|
|
|
46
47
|
var import_cel_js = require("@marcbachmann/cel-js");
|
|
47
48
|
|
|
48
49
|
// src/stdlib.ts
|
|
50
|
+
function partsInTz(d, tz) {
|
|
51
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
52
|
+
timeZone: tz,
|
|
53
|
+
year: "numeric",
|
|
54
|
+
month: "2-digit",
|
|
55
|
+
day: "2-digit"
|
|
56
|
+
}).formatToParts(d);
|
|
57
|
+
const get = (t) => Number(parts.find((p) => p.type === t)?.value);
|
|
58
|
+
return { y: get("year"), m: get("month"), day: get("day") };
|
|
59
|
+
}
|
|
60
|
+
function calendarDayUtc(d, tz) {
|
|
61
|
+
if (tz && tz !== "UTC") {
|
|
62
|
+
try {
|
|
63
|
+
const { y, m, day } = partsInTz(d, tz);
|
|
64
|
+
return new Date(Date.UTC(y, m - 1, day));
|
|
65
|
+
} catch {
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return startOfDayUtc(d);
|
|
69
|
+
}
|
|
49
70
|
function startOfDayUtc(d) {
|
|
50
71
|
const out = new Date(d.getTime());
|
|
51
72
|
out.setUTCHours(0, 0, 0, 0);
|
|
@@ -62,16 +83,16 @@ function addDaysUtc(d, n) {
|
|
|
62
83
|
out.setUTCDate(out.getUTCDate() + n);
|
|
63
84
|
return out;
|
|
64
85
|
}
|
|
65
|
-
function registerStdLib(env, now) {
|
|
86
|
+
function registerStdLib(env, now, timezone = "UTC") {
|
|
66
87
|
return env.registerFunction("now(): google.protobuf.Timestamp", () => now()).registerFunction(
|
|
67
88
|
"today(): google.protobuf.Timestamp",
|
|
68
|
-
() =>
|
|
89
|
+
() => calendarDayUtc(now(), timezone)
|
|
69
90
|
).registerFunction(
|
|
70
91
|
"daysFromNow(int): google.protobuf.Timestamp",
|
|
71
|
-
(n) => addDaysUtc(now(), Number(n))
|
|
92
|
+
(n) => addDaysUtc(calendarDayUtc(now(), timezone), Number(n))
|
|
72
93
|
).registerFunction(
|
|
73
94
|
"daysAgo(int): google.protobuf.Timestamp",
|
|
74
|
-
(n) => addDaysUtc(now(), -Number(n))
|
|
95
|
+
(n) => addDaysUtc(calendarDayUtc(now(), timezone), -Number(n))
|
|
75
96
|
).registerFunction(
|
|
76
97
|
"isBlank(dyn): bool",
|
|
77
98
|
(value) => {
|
|
@@ -153,13 +174,13 @@ var DEFAULT_LIMITS = {
|
|
|
153
174
|
maxMapEntries: 64,
|
|
154
175
|
maxCallArguments: 16
|
|
155
176
|
};
|
|
156
|
-
function buildEnv(now) {
|
|
177
|
+
function buildEnv(now, timezone = "UTC") {
|
|
157
178
|
const env = new import_cel_js.Environment({
|
|
158
179
|
unlistedVariablesAreDyn: true,
|
|
159
180
|
enableOptionalTypes: true,
|
|
160
181
|
limits: DEFAULT_LIMITS
|
|
161
182
|
});
|
|
162
|
-
return registerNumericCoercions(registerStdLib(env, now));
|
|
183
|
+
return registerNumericCoercions(registerStdLib(env, now, timezone));
|
|
163
184
|
}
|
|
164
185
|
var SCOPE_ROOTS = [
|
|
165
186
|
"record",
|
|
@@ -305,7 +326,7 @@ var celEngine = {
|
|
|
305
326
|
}
|
|
306
327
|
const now = () => ctx.now ?? /* @__PURE__ */ new Date();
|
|
307
328
|
try {
|
|
308
|
-
const env = buildEnv(now);
|
|
329
|
+
const env = buildEnv(now, ctx.timezone ?? "UTC");
|
|
309
330
|
const scope = buildScope(ctx);
|
|
310
331
|
try {
|
|
311
332
|
const raw = env.evaluate(source, scope);
|
|
@@ -445,7 +466,9 @@ var FORMATTERS = {
|
|
|
445
466
|
maximumFractionDigits: Number.isNaN(digits) ? 0 : digits
|
|
446
467
|
}).format(n);
|
|
447
468
|
},
|
|
448
|
-
// date | date:long | date:iso → date-only
|
|
469
|
+
// date | date:long | date:iso → date-only. Intentionally tz-naive
|
|
470
|
+
// (ADR-0053): a `Field.date` is a calendar day with no zone, so rendering
|
|
471
|
+
// never applies a reference timezone — that would shift the day.
|
|
449
472
|
date: (v, arg, locale) => {
|
|
450
473
|
const d = asDate(v);
|
|
451
474
|
if (!d) return baseString(v);
|
|
@@ -453,15 +476,18 @@ var FORMATTERS = {
|
|
|
453
476
|
const style = arg === "long" ? "long" : arg === "medium" ? "medium" : "short";
|
|
454
477
|
return new Intl.DateTimeFormat(locale, { dateStyle: style }).format(d);
|
|
455
478
|
},
|
|
456
|
-
// datetime | datetime:long | datetime:iso
|
|
457
|
-
|
|
479
|
+
// datetime | datetime:long | datetime:iso. A `datetime` is a UTC instant;
|
|
480
|
+
// when a reference `timeZone` is supplied (ADR-0053 Phase 2) the wall-clock
|
|
481
|
+
// styles render in that zone. `iso` stays UTC (machine-readable, unambiguous).
|
|
482
|
+
datetime: (v, arg, locale, timeZone) => {
|
|
458
483
|
const d = asDate(v);
|
|
459
484
|
if (!d) return baseString(v);
|
|
460
485
|
if (arg === "iso") return d.toISOString();
|
|
461
486
|
const style = arg === "long" ? "long" : arg === "medium" ? "medium" : "short";
|
|
462
487
|
return new Intl.DateTimeFormat(locale, {
|
|
463
488
|
dateStyle: style,
|
|
464
|
-
timeStyle: style
|
|
489
|
+
timeStyle: style,
|
|
490
|
+
...timeZone ? { timeZone } : {}
|
|
465
491
|
}).format(d);
|
|
466
492
|
},
|
|
467
493
|
// truncate:80 → cut with an ellipsis
|
|
@@ -485,6 +511,11 @@ var FORMATTERS = {
|
|
|
485
511
|
}
|
|
486
512
|
};
|
|
487
513
|
var TEMPLATE_FORMATTERS = Object.keys(FORMATTERS);
|
|
514
|
+
function formatValue(name, value, arg, opts = {}) {
|
|
515
|
+
const fmt = FORMATTERS[name];
|
|
516
|
+
if (!fmt) return void 0;
|
|
517
|
+
return fmt(value, arg, opts.locale ?? "en-US", opts.timeZone);
|
|
518
|
+
}
|
|
488
519
|
function baseString(value) {
|
|
489
520
|
if (value === null || value === void 0) return "";
|
|
490
521
|
if (value instanceof Date) return value.toISOString();
|
|
@@ -570,12 +601,13 @@ var templateEngine = {
|
|
|
570
601
|
if (!check.ok) return check;
|
|
571
602
|
const scope = buildScope(ctx);
|
|
572
603
|
const locale = ctx.extra && typeof ctx.extra.locale === "string" && ctx.extra.locale || typeof ctx.locale === "string" && ctx.locale || "en-US";
|
|
604
|
+
const timeZone = typeof ctx.timezone === "string" ? ctx.timezone : void 0;
|
|
573
605
|
const out = expr.source.replace(HOLE_RE, (_match, inner) => {
|
|
574
606
|
const parsed = parseHole(String(inner));
|
|
575
607
|
if (!parsed) return _match;
|
|
576
608
|
const value = resolvePath(scope, parsed.path);
|
|
577
609
|
if (parsed.filter) {
|
|
578
|
-
return FORMATTERS[parsed.filter.name](value, parsed.filter.arg, locale);
|
|
610
|
+
return FORMATTERS[parsed.filter.name](value, parsed.filter.arg, locale, timeZone);
|
|
579
611
|
}
|
|
580
612
|
return baseString(value);
|
|
581
613
|
});
|
|
@@ -919,6 +951,7 @@ var CEL_STDLIB_FUNCTIONS = [
|
|
|
919
951
|
celEngine,
|
|
920
952
|
cronEngine,
|
|
921
953
|
expectedDialect,
|
|
954
|
+
formatValue,
|
|
922
955
|
getEngine,
|
|
923
956
|
hasDialect,
|
|
924
957
|
introspectScope,
|