@barefootjs/rust 0.24.1 → 0.26.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/dist/adapter/index.js +4 -1
- package/dist/adapter/minijinja-adapter.d.ts.map +1 -1
- package/dist/build.js +4 -1
- package/dist/index.js +4 -2
- package/package.json +3 -3
- package/runtime/Cargo.lock +60 -0
- package/runtime/Cargo.toml +6 -0
- package/runtime/src/date.rs +91 -24
- package/runtime/src/runtime.rs +7 -4
- package/runtime/tests/helper_vectors.rs +4 -1
- package/src/adapter/minijinja-adapter.ts +8 -1
- package/src/conformance-pins.ts +3 -3
package/dist/adapter/index.js
CHANGED
|
@@ -188493,10 +188493,13 @@ class MinijinjaAdapter extends BaseAdapter {
|
|
|
188493
188493
|
const resolution = resolveDangerousInnerHtml(element);
|
|
188494
188494
|
if (!resolution)
|
|
188495
188495
|
return null;
|
|
188496
|
-
if (resolution.kind === "
|
|
188496
|
+
if (resolution.kind === "unlowerable") {
|
|
188497
188497
|
this.errors.push(dangerousInnerHtmlDiagnostic(resolution.expr, resolution.loc));
|
|
188498
188498
|
return "";
|
|
188499
188499
|
}
|
|
188500
|
+
if (resolution.kind === "dynamic") {
|
|
188501
|
+
return `{{ ${this.convertExpressionToJinja(resolution.valueExpr, resolution.valueParsed)} | safe }}`;
|
|
188502
|
+
}
|
|
188500
188503
|
const violation = dangerousInnerHtmlMetacharViolation(resolution.html, this.name);
|
|
188501
188504
|
if (violation) {
|
|
188502
188505
|
const attr = element.attrs.find(isDangerousInnerHtmlAttr);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"minijinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/minijinja-adapter.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"minijinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/minijinja-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiHG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,MAAM,EACN,SAAS,EACT,MAAM,EACN,YAAY,EACZ,aAAa,EACb,MAAM,EACN,WAAW,EACX,UAAU,EACV,MAAM,EACN,aAAa,EACb,UAAU,EACV,OAAO,EAKP,yBAAyB,EAE1B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAE3B,KAAK,aAAa,EAClB,KAAK,UAAU,EA+BhB,MAAM,iBAAiB,CAAA;AAKxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AA6BpD,YAAY,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAC7D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AA8B7D,qBAAa,gBAAiB,SAAQ,WAAY,YAAW,aAAa,CAAC,cAAc,CAAC;IACxF,IAAI,SAAc;IAClB,SAAS,SAAQ;IACjB,qBAAqB,UAAO;IAG5B,kBAAkB,EAAG,cAAc,CAAS;IAE5C;;;;;OAKG;IACH,kBAAkB,EAAE,yBAAyB,CAA2B;IAExE,OAAO,CAAC,aAAa,CAAa;IAClC;;;uCAGmC;IACnC,OAAO,CAAC,cAAc,CAAyB;IAC/C,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,MAAM,CAAiB;IAC/B;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB,CAAI;IAC/B;;;;;OAKG;IACH,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,iBAAiB,CAAyB;IAClD;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB,CAAyB;IAEjD;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB,CAAiC;IAE3D;;;;;;;OAOG;IACH,OAAO,CAAC,mBAAmB,CAAyB;IAEpD;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB,CAAwB;IAEjD;;;;;OAKG;IACH,OAAO,CAAC,cAAc,CAAmC;IAEzD;;;;;;;;OAQG;IACH,OAAO,CAAC,0BAA0B,CAAyB;IAE3D;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB,CAAyB;IAEtD,YAAY,OAAO,GAAE,uBAA4B,EAMhD;IAED,QAAQ,CAAC,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,aAAa,CA6EzE;IAMD,OAAO,CAAC,2BAA2B;IAyBnC;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/B;IAMD,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,MAAM,CAE5F;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI7B;IAED,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAEzC;IAED,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,MAAM,CAEpG;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,MAAM,CAEtF;IAED,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,MAAM,CAEhG;IAED,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,MAAM,CAE9F;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7B;IAED,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,MAAM,CAEpG;IAED,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,MAAM,CAe9F;IAED,uEAAuE;IACvE,OAAO,CAAC,kBAAkB;IAmB1B;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,0BAA0B;IAYlC,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,MAAM,CAExF;IAMD,aAAa,CAAC,OAAO,EAAE,SAAS,GAAG,MAAM,CAqCxC;IAED;;;;;OAKG;IACH,OAAO,CAAC,wBAAwB;IA2BhC,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAqB3C;IAMD,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAuC7C;IAED,OAAO,CAAC,gBAAgB;IAOxB;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAcnC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqQ/B;IAMD;;;;;;;;OAQG;IACH,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAoCpC;IAED;;;;;;;;;;OAUG;IACH,OAAO,CAAC,2BAA2B;IAUnC;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,4BAA4B;IAiBpC,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAoGzC;IAED,OAAO,CAAC,sBAAsB,CAAI;IAElC;+DAC2D;IAC3D,OAAO,CAAC,kBAAkB,CAAI;IAE9B,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,UAAU;IAYT,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAQ1C;IAMD;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CA0JlC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,gBAAgB;IAoCxB,iBAAiB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAIjD;IAED,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEvC;IAED,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEvC;IAMD;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;IAuB7B,OAAO,CAAC,kCAAkC;IAoC1C;;;;;OAKG;IACH,OAAO,CAAC,iCAAiC;IAmBzC;;;;;OAKG;IACH,OAAO,CAAC,+BAA+B;IAuBvC;;;;;;;OAOG;IACH,OAAO,KAAK,OAAO,GASlB;IAED;;;;;OAKG;IACH,OAAO,KAAK,SAAS,GASpB;IAED,sEAAsE;IACtE,OAAO,KAAK,OAAO,GAKlB;IAED,OAAO,CAAC,wBAAwB;IAyEhC;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB;IAK/B;;;;;;;OAOG;IACH,OAAO,CAAC,iBAAiB;IAOzB;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAI/B;;gFAE4E;IAC5E,OAAO,CAAC,kBAAkB;IAI1B;;;;OAIG;IACH,8BAA8B,CAC5B,IAAI,EAAE,MAAM,GACX;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAgBlD;IAED,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAO3C;IAED;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,aAAa;IAKrB;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,oBAAoB;IAW5B;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,2BAA2B;IASnC,OAAO,CAAC,yBAAyB;IAUjC,OAAO,CAAC,gBAAgB;IAcxB,iFAAiF;IACjF,OAAO,CAAC,4BAA4B;CAGrC;AAED,eAAO,MAAM,gBAAgB,kBAAyB,CAAA"}
|
package/dist/build.js
CHANGED
|
@@ -188493,10 +188493,13 @@ class MinijinjaAdapter extends BaseAdapter {
|
|
|
188493
188493
|
const resolution = resolveDangerousInnerHtml(element);
|
|
188494
188494
|
if (!resolution)
|
|
188495
188495
|
return null;
|
|
188496
|
-
if (resolution.kind === "
|
|
188496
|
+
if (resolution.kind === "unlowerable") {
|
|
188497
188497
|
this.errors.push(dangerousInnerHtmlDiagnostic(resolution.expr, resolution.loc));
|
|
188498
188498
|
return "";
|
|
188499
188499
|
}
|
|
188500
|
+
if (resolution.kind === "dynamic") {
|
|
188501
|
+
return `{{ ${this.convertExpressionToJinja(resolution.valueExpr, resolution.valueParsed)} | safe }}`;
|
|
188502
|
+
}
|
|
188500
188503
|
const violation = dangerousInnerHtmlMetacharViolation(resolution.html, this.name);
|
|
188501
188504
|
if (violation) {
|
|
188502
188505
|
const attr = element.attrs.find(isDangerousInnerHtmlAttr);
|
package/dist/index.js
CHANGED
|
@@ -188493,10 +188493,13 @@ class MinijinjaAdapter extends BaseAdapter {
|
|
|
188493
188493
|
const resolution = resolveDangerousInnerHtml(element);
|
|
188494
188494
|
if (!resolution)
|
|
188495
188495
|
return null;
|
|
188496
|
-
if (resolution.kind === "
|
|
188496
|
+
if (resolution.kind === "unlowerable") {
|
|
188497
188497
|
this.errors.push(dangerousInnerHtmlDiagnostic(resolution.expr, resolution.loc));
|
|
188498
188498
|
return "";
|
|
188499
188499
|
}
|
|
188500
|
+
if (resolution.kind === "dynamic") {
|
|
188501
|
+
return `{{ ${this.convertExpressionToJinja(resolution.valueExpr, resolution.valueParsed)} | safe }}`;
|
|
188502
|
+
}
|
|
188500
188503
|
const violation = dangerousInnerHtmlMetacharViolation(resolution.html, this.name);
|
|
188501
188504
|
if (violation) {
|
|
188502
188505
|
const attr = element.attrs.find(isDangerousInnerHtmlAttr);
|
|
@@ -189201,7 +189204,6 @@ var conformancePins = {
|
|
|
189201
189204
|
"filter-nested-find-predicate": [
|
|
189202
189205
|
{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2320" }
|
|
189203
189206
|
],
|
|
189204
|
-
"dangerous-inner-html-dynamic": [{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2319" }],
|
|
189205
189207
|
"date-method-uncatalogued": [{ code: "BF021", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2274" }]
|
|
189206
189208
|
};
|
|
189207
189209
|
// src/render-divergences.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/rust",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "minijinja (Rust) adapter for BarefootJS — compiles IR to .j2 templates and ships a Rust rendering runtime (packages/adapter-rust/runtime/); runs under any Rust web framework (axum, etc.)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -54,14 +54,14 @@
|
|
|
54
54
|
"directory": "packages/adapter-rust"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@barefootjs/shared": "0.
|
|
57
|
+
"@barefootjs/shared": "0.26.0"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"@barefootjs/jsx": ">=0.2.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@barefootjs/adapter-tests": "0.1.0",
|
|
64
|
-
"@barefootjs/jsx": "0.
|
|
64
|
+
"@barefootjs/jsx": "0.26.0",
|
|
65
65
|
"typescript": "^5.0.0"
|
|
66
66
|
}
|
|
67
67
|
}
|
package/runtime/Cargo.lock
CHANGED
|
@@ -2,15 +2,42 @@
|
|
|
2
2
|
# It is not intended for manual editing.
|
|
3
3
|
version = 4
|
|
4
4
|
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "autocfg"
|
|
7
|
+
version = "1.5.1"
|
|
8
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
9
|
+
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
|
10
|
+
|
|
5
11
|
[[package]]
|
|
6
12
|
name = "barefootjs"
|
|
7
13
|
version = "0.1.0"
|
|
8
14
|
dependencies = [
|
|
15
|
+
"chrono",
|
|
16
|
+
"chrono-tz",
|
|
9
17
|
"minijinja",
|
|
10
18
|
"serde",
|
|
11
19
|
"serde_json",
|
|
12
20
|
]
|
|
13
21
|
|
|
22
|
+
[[package]]
|
|
23
|
+
name = "chrono"
|
|
24
|
+
version = "0.4.45"
|
|
25
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
26
|
+
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
|
|
27
|
+
dependencies = [
|
|
28
|
+
"num-traits",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[[package]]
|
|
32
|
+
name = "chrono-tz"
|
|
33
|
+
version = "0.10.4"
|
|
34
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
35
|
+
checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3"
|
|
36
|
+
dependencies = [
|
|
37
|
+
"chrono",
|
|
38
|
+
"phf",
|
|
39
|
+
]
|
|
40
|
+
|
|
14
41
|
[[package]]
|
|
15
42
|
name = "itoa"
|
|
16
43
|
version = "1.0.18"
|
|
@@ -39,6 +66,33 @@ dependencies = [
|
|
|
39
66
|
"serde",
|
|
40
67
|
]
|
|
41
68
|
|
|
69
|
+
[[package]]
|
|
70
|
+
name = "num-traits"
|
|
71
|
+
version = "0.2.19"
|
|
72
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
73
|
+
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
|
74
|
+
dependencies = [
|
|
75
|
+
"autocfg",
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
[[package]]
|
|
79
|
+
name = "phf"
|
|
80
|
+
version = "0.12.1"
|
|
81
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
82
|
+
checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7"
|
|
83
|
+
dependencies = [
|
|
84
|
+
"phf_shared",
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
[[package]]
|
|
88
|
+
name = "phf_shared"
|
|
89
|
+
version = "0.12.1"
|
|
90
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
91
|
+
checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981"
|
|
92
|
+
dependencies = [
|
|
93
|
+
"siphasher",
|
|
94
|
+
]
|
|
95
|
+
|
|
42
96
|
[[package]]
|
|
43
97
|
name = "proc-macro2"
|
|
44
98
|
version = "1.0.106"
|
|
@@ -100,6 +154,12 @@ dependencies = [
|
|
|
100
154
|
"zmij",
|
|
101
155
|
]
|
|
102
156
|
|
|
157
|
+
[[package]]
|
|
158
|
+
name = "siphasher"
|
|
159
|
+
version = "1.0.3"
|
|
160
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
161
|
+
checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
|
|
162
|
+
|
|
103
163
|
[[package]]
|
|
104
164
|
name = "syn"
|
|
105
165
|
version = "2.0.118"
|
package/runtime/Cargo.toml
CHANGED
|
@@ -22,5 +22,11 @@ path = "src/bin/bf-render.rs"
|
|
|
22
22
|
minijinja = { version = "2", features = ["loader"] }
|
|
23
23
|
serde = { version = "1", features = ["derive"] }
|
|
24
24
|
serde_json = { version = "1", features = ["float_roundtrip"] }
|
|
25
|
+
# #2344 named-IANA-zone resolution in `format_date` (src/date.rs). chrono-tz
|
|
26
|
+
# embeds tzdata at a release pinned per crate version, so zone resolution is
|
|
27
|
+
# deterministic per build — no host tzdata read. The narrow feature set
|
|
28
|
+
# keeps chrono's clock ("now") API out: helpers must stay pure functions.
|
|
29
|
+
chrono = { version = "0.4", default-features = false, features = ["std"] }
|
|
30
|
+
chrono-tz = "0.10"
|
|
25
31
|
|
|
26
32
|
[dev-dependencies]
|
package/runtime/src/date.rs
CHANGED
|
@@ -5,9 +5,14 @@
|
|
|
5
5
|
//! the host populated it) -- both normalize to a single epoch-ms integer
|
|
6
6
|
//! via [`epoch_ms_of`] before dispatch.
|
|
7
7
|
//!
|
|
8
|
-
//!
|
|
9
|
-
//!
|
|
10
|
-
//!
|
|
8
|
+
//! Calendar arithmetic stays hand-rolled (no date crate on the numeric
|
|
9
|
+
//! paths -- the same constraint `num.rs`'s numeric-string grammar
|
|
10
|
+
//! docstring cites for avoiding `regex`), with ONE deliberate exception
|
|
11
|
+
//! (#2344): named-IANA-zone resolution in `format_date` uses
|
|
12
|
+
//! `chrono`/`chrono-tz`, because a timezone database is not something to
|
|
13
|
+
//! hand-roll and `chrono-tz` embeds tzdata at a pinned release
|
|
14
|
+
//! (deterministic per build, no host tzdata read). Fidelity to the JS
|
|
15
|
+
//! reference outranks the zero-dependency stance here.
|
|
11
16
|
//! Calendar <-> day-count conversion is Howard Hinnant's `civil_from_days`
|
|
12
17
|
//! / `days_from_civil` (public-domain algorithm,
|
|
13
18
|
//! <http://howardhinnant.github.io/date_algorithms.html>), correct for the
|
|
@@ -161,31 +166,56 @@ pub fn date(recv: &JsValue, op: &str) -> JsValue {
|
|
|
161
166
|
}
|
|
162
167
|
}
|
|
163
168
|
|
|
164
|
-
/// Parse a fixed UTC offset `tz` matching
|
|
165
|
-
///
|
|
169
|
+
/// Parse a fixed UTC offset `tz` matching `±HH:MM` within ECMA-402's valid
|
|
170
|
+
/// range -- hours 00-23, minutes 00-59 -- into signed SECONDS, or `None`
|
|
171
|
+
/// for any other shape. Mirrors `OFFSET_RE` in
|
|
166
172
|
/// `packages/client/src/format-date.ts` and `tzOffsetRE` in the Go
|
|
167
|
-
/// runtime's `bf.go
|
|
168
|
-
///
|
|
169
|
-
///
|
|
170
|
-
///
|
|
171
|
-
///
|
|
172
|
-
|
|
173
|
-
fn parse_tz_offset(tz: &str) -> i64 {
|
|
173
|
+
/// runtime's `bf.go` -- byte/ascii-digit checks here, not a `regex` crate
|
|
174
|
+
/// dependency. A `None` falls through to [`zone_offset_seconds`]'s tzdata
|
|
175
|
+
/// lookup (#2344): an out-of-range offset like `"+25:00"` is not a zone
|
|
176
|
+
/// name either, so it errors there -- matching the JS reference's
|
|
177
|
+
/// RangeError, never a silent UTC.
|
|
178
|
+
fn parse_tz_offset(tz: &str) -> Option<i64> {
|
|
174
179
|
let b = tz.as_bytes();
|
|
175
180
|
if b.len() != 6 || b[3] != b':' {
|
|
176
|
-
return
|
|
181
|
+
return None;
|
|
177
182
|
}
|
|
178
183
|
let sign = match b[0] {
|
|
179
184
|
b'+' => 1i64,
|
|
180
185
|
b'-' => -1i64,
|
|
181
|
-
_ => return
|
|
186
|
+
_ => return None,
|
|
182
187
|
};
|
|
183
188
|
if !b[1].is_ascii_digit() || !b[2].is_ascii_digit() || !b[4].is_ascii_digit() || !b[5].is_ascii_digit() {
|
|
184
|
-
return
|
|
189
|
+
return None;
|
|
185
190
|
}
|
|
186
191
|
let hh = (b[1] - b'0') as i64 * 10 + (b[2] - b'0') as i64;
|
|
187
192
|
let mm = (b[4] - b'0') as i64 * 10 + (b[5] - b'0') as i64;
|
|
188
|
-
|
|
193
|
+
if hh > 23 || mm > 59 {
|
|
194
|
+
return None;
|
|
195
|
+
}
|
|
196
|
+
Some(sign * (hh * 3600 + mm * 60))
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/// Resolve a canonical IANA zone name's UTC offset (whole seconds) at the
|
|
200
|
+
/// epoch-ms instant through `chrono-tz` (#2344) -- tzdata is EMBEDDED in
|
|
201
|
+
/// the crate at a pinned release, so resolution is deterministic per build
|
|
202
|
+
/// (no host tzdata read), DST-aware and historical-transition-aware at
|
|
203
|
+
/// seconds precision (pre-standard LMT offsets like Tokyo's `+09:18:59`
|
|
204
|
+
/// count). An unresolvable name errors -- the loud-not-silent replacement
|
|
205
|
+
/// for the pre-#2344 normalize-to-UTC total function (the JS reference
|
|
206
|
+
/// throws a RangeError there). `chrono-tz` accepts link names as a
|
|
207
|
+
/// superset of the canonical IDs; the JS reference throws on those, so
|
|
208
|
+
/// that region is unspecified by the spec.
|
|
209
|
+
fn zone_offset_seconds(tz: &str, ms: i64) -> Result<i64, String> {
|
|
210
|
+
use chrono::{Offset as _, TimeZone as _};
|
|
211
|
+
let zone: chrono_tz::Tz = tz
|
|
212
|
+
.parse()
|
|
213
|
+
.map_err(|_| format!("format_date: unresolvable timeZone {tz:?}"))?;
|
|
214
|
+
let instant = chrono::DateTime::from_timestamp(ms.div_euclid(1000), 0)
|
|
215
|
+
.ok_or_else(|| format!("format_date: instant out of range for timeZone {tz:?}"))?;
|
|
216
|
+
Ok(i64::from(
|
|
217
|
+
zone.offset_from_utc_datetime(&instant.naive_utc()).fix().local_minus_utc(),
|
|
218
|
+
))
|
|
189
219
|
}
|
|
190
220
|
|
|
191
221
|
/// `names`-table section offsets (#2334, mirrors `MONTHS_WIDE` /
|
|
@@ -228,10 +258,15 @@ fn name_at(names: &JsValue, index: usize) -> &str {
|
|
|
228
258
|
/// there is no accessor/`getTime` numeric fallback here, since
|
|
229
259
|
/// `format_date` always returns a string.
|
|
230
260
|
///
|
|
231
|
-
/// `tz`
|
|
232
|
-
/// `
|
|
261
|
+
/// `tz` (#2344) is `"UTC"`, a range-valid fixed offset (via
|
|
262
|
+
/// [`parse_tz_offset`]), or a canonical IANA zone name (via
|
|
263
|
+
/// [`zone_offset_seconds`]); anything unresolvable is an `Err`, which the
|
|
264
|
+
/// minijinja dispatch surfaces as a template error -- loud, never a
|
|
265
|
+
/// silent UTC (the receiver contract still precedes tz validation:
|
|
266
|
+
/// nil/unparseable renders `Ok("")` first). The instant is shifted by
|
|
267
|
+
/// `offset_seconds * 1000` ms and the shifted instant's UTC calendar
|
|
233
268
|
/// fields (not the original instant's) are what the pattern tokens read --
|
|
234
|
-
/// the shifted UTC clock face IS the local clock face
|
|
269
|
+
/// the shifted UTC clock face IS the local clock face in that zone.
|
|
235
270
|
///
|
|
236
271
|
/// `names` (#2334) is a flat table in fixed layout: `[0..11]` wide month
|
|
237
272
|
/// names, `[12..23]` abbreviated month names, `[24..30]` wide weekday names
|
|
@@ -255,13 +290,19 @@ fn name_at(names: &JsValue, index: usize) -> &str {
|
|
|
255
290
|
/// `(days + 4).rem_euclid(7)` -- 1970-01-01 (`days == 0`) is a Thursday,
|
|
256
291
|
/// and `rem_euclid` (not `%`, which truncates toward zero in Rust) keeps
|
|
257
292
|
/// the result in `[0, 6]` for a negative (pre-1970) `days` too.
|
|
258
|
-
pub fn format_date(recv: &JsValue, pattern: &str, tz: &str, names: &JsValue) -> String {
|
|
293
|
+
pub fn format_date(recv: &JsValue, pattern: &str, tz: &str, names: &JsValue) -> Result<String, String> {
|
|
259
294
|
let ms = match epoch_ms_of(recv) {
|
|
260
295
|
Some(ms) => ms,
|
|
261
|
-
None => return String::new(),
|
|
296
|
+
None => return Ok(String::new()),
|
|
297
|
+
};
|
|
298
|
+
let offset_seconds = if tz == "UTC" {
|
|
299
|
+
0
|
|
300
|
+
} else if let Some(seconds) = parse_tz_offset(tz) {
|
|
301
|
+
seconds
|
|
302
|
+
} else {
|
|
303
|
+
zone_offset_seconds(tz, ms)?
|
|
262
304
|
};
|
|
263
|
-
let
|
|
264
|
-
let shifted = ms + offset_minutes * 60_000;
|
|
305
|
+
let shifted = ms + offset_seconds * 1000;
|
|
265
306
|
let days = shifted.div_euclid(MS_PER_DAY);
|
|
266
307
|
let (year, month, day) = civil_from_days(days);
|
|
267
308
|
let yyyy = if year < 0 { format!("-{:04}", -year) } else { format!("{year:04}") };
|
|
@@ -304,7 +345,7 @@ pub fn format_date(recv: &JsValue, pattern: &str, tz: &str, names: &JsValue) ->
|
|
|
304
345
|
i += ch.len_utf8();
|
|
305
346
|
}
|
|
306
347
|
}
|
|
307
|
-
out
|
|
348
|
+
Ok(out)
|
|
308
349
|
}
|
|
309
350
|
|
|
310
351
|
#[cfg(test)]
|
|
@@ -339,4 +380,30 @@ mod tests {
|
|
|
339
380
|
assert_eq!(format_iso8601(ms), "9999-12-31T23:59:59.999Z");
|
|
340
381
|
assert_eq!(date_op(ms, "getUTCFullYear"), JsValue::Number(9999.0));
|
|
341
382
|
}
|
|
383
|
+
|
|
384
|
+
// #2344: named IANA zones resolve through chrono-tz's embedded tzdata;
|
|
385
|
+
// anything unresolvable is an Err — the loud-not-silent replacement for
|
|
386
|
+
// the pre-#2344 normalize-to-UTC total function. The resolvable grid is
|
|
387
|
+
// pinned by the golden vectors (tests/helper_vectors.rs); this pins the
|
|
388
|
+
// error side, which is outside the vector domain
|
|
389
|
+
// (spec/template-helpers.md JS-throws rule).
|
|
390
|
+
#[test]
|
|
391
|
+
fn unresolvable_time_zones_error() {
|
|
392
|
+
let recv = JsValue::String("2024-01-01T23:00:00.000Z".to_string());
|
|
393
|
+
let names = JsValue::Null;
|
|
394
|
+
for tz in ["garbage", "Asia/Tokyoo", "+9:00", "+25:00", "asia/tokyo", "Local", ""] {
|
|
395
|
+
assert!(
|
|
396
|
+
format_date(&recv, "YYYY-MM-DD", tz, &names).is_err(),
|
|
397
|
+
"tz {tz:?} must error"
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
// The receiver contract precedes tz validation.
|
|
401
|
+
assert_eq!(format_date(&JsValue::Null, "YYYY-MM-DD", "garbage", &names), Ok(String::new()));
|
|
402
|
+
// Named-zone happy path (redundant with the vectors, but keeps this
|
|
403
|
+
// file self-sufficient outside the monorepo checkout).
|
|
404
|
+
assert_eq!(
|
|
405
|
+
format_date(&recv, "YYYY-MM-DD", "Asia/Tokyo", &names),
|
|
406
|
+
Ok("2024-01-02".to_string())
|
|
407
|
+
);
|
|
408
|
+
}
|
|
342
409
|
}
|
package/runtime/src/runtime.rs
CHANGED
|
@@ -1339,15 +1339,18 @@ impl Object for BfInstance {
|
|
|
1339
1339
|
// stays a plain string arg, never routed through `js_number`.
|
|
1340
1340
|
"date" => Ok(js_to_mj(&date::date(a(0), a(1).as_str().unwrap_or("")))),
|
|
1341
1341
|
// `format_date(recv, pattern, tz, names)` (spec/template-helpers.md
|
|
1342
|
-
// "format_date", #2324, #2334) --
|
|
1342
|
+
// "format_date", #2324, #2334, #2344) -- locale-free date-pattern
|
|
1343
1343
|
// formatting layered on the same `recv` normalization as
|
|
1344
1344
|
// `date` above. `names` stays the array-shaped `JsValue` that
|
|
1345
1345
|
// `mj_to_js`'s `Seq`/`Iterable` arm already produced above (the
|
|
1346
1346
|
// compiler's lowering always passes 4 args); a non-array or
|
|
1347
1347
|
// missing `names` degrades to `""` for every name token, per
|
|
1348
|
-
// `date::name_at`.
|
|
1349
|
-
//
|
|
1350
|
-
|
|
1348
|
+
// `date::name_at`. An unresolvable tz (#2344) surfaces as a
|
|
1349
|
+
// template error -- loud, never a silent UTC. See
|
|
1350
|
+
// `date::format_date`'s docstring for the full contract.
|
|
1351
|
+
"format_date" => date::format_date(a(0), a(1).as_str().unwrap_or(""), a(2).as_str().unwrap_or(""), a(3))
|
|
1352
|
+
.map(MjValue::from)
|
|
1353
|
+
.map_err(|msg| Error::new(ErrorKind::InvalidOperation, msg)),
|
|
1351
1354
|
|
|
1352
1355
|
// -- Array / string method helpers (#1448 Tier A) ------------------
|
|
1353
1356
|
"includes" => Ok(MjValue::from(includes(a(0), a(1)))),
|
|
@@ -150,7 +150,10 @@ fn call_binding(fn_name: &str, args: &[JsValue]) -> Option<JsValue> {
|
|
|
150
150
|
JsValue::String(num::to_fixed(runtime::js_number(&a(0)), digits))
|
|
151
151
|
}
|
|
152
152
|
"date" => date::date(&a(0), a(1).as_str().unwrap_or("")),
|
|
153
|
-
"format_date" => JsValue::String(
|
|
153
|
+
"format_date" => JsValue::String(
|
|
154
|
+
date::format_date(&a(0), a(1).as_str().unwrap_or(""), a(2).as_str().unwrap_or(""), &a(3))
|
|
155
|
+
.expect("unresolvable-tz inputs are outside the vector domain (#2344)"),
|
|
156
|
+
),
|
|
154
157
|
"lower" => JsValue::String(runtime::js_string(&a(0)).to_lowercase()),
|
|
155
158
|
"upper" => JsValue::String(runtime::js_string(&a(0)).to_uppercase()),
|
|
156
159
|
"trim" => JsValue::String(runtime::trim(&a(0))),
|
|
@@ -632,10 +632,17 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
|
|
|
632
632
|
private renderDangerousInnerHtml(element: IRElement): string | null {
|
|
633
633
|
const resolution = resolveDangerousInnerHtml(element)
|
|
634
634
|
if (!resolution) return null
|
|
635
|
-
if (resolution.kind === '
|
|
635
|
+
if (resolution.kind === 'unlowerable') {
|
|
636
636
|
this.errors.push(dangerousInnerHtmlDiagnostic(resolution.expr, resolution.loc))
|
|
637
637
|
return ''
|
|
638
638
|
}
|
|
639
|
+
if (resolution.kind === 'dynamic') {
|
|
640
|
+
// Lower the `__html` expression and emit it through MiniJinja's `| safe`
|
|
641
|
+
// filter, which suppresses autoescape for this one value. The runtime
|
|
642
|
+
// evaluates the expression, so no template-metachar guard applies; the
|
|
643
|
+
// element already carries its hydration slot marker. #2319.
|
|
644
|
+
return `{{ ${this.convertExpressionToJinja(resolution.valueExpr, resolution.valueParsed)} | safe }}`
|
|
645
|
+
}
|
|
639
646
|
const violation = dangerousInnerHtmlMetacharViolation(resolution.html, this.name)
|
|
640
647
|
if (violation) {
|
|
641
648
|
const attr = element.attrs.find(isDangerousInnerHtmlAttr)!
|
package/src/conformance-pins.ts
CHANGED
|
@@ -100,9 +100,9 @@ export const conformancePins: ConformancePins = {
|
|
|
100
100
|
// `dangerous-inner-html` no longer pinned — a compile-time string-literal
|
|
101
101
|
// `dangerouslySetInnerHTML={{ __html: '...' }}` is spliced directly into
|
|
102
102
|
// the template as trusted raw text (`resolveDangerousInnerHtml`, #2207).
|
|
103
|
-
// A dynamic/signal-derived value
|
|
104
|
-
// `dangerous-inner-html-dynamic`
|
|
105
|
-
|
|
103
|
+
// A dynamic/signal-derived value now lowers through MiniJinja's `| safe`
|
|
104
|
+
// filter (#2319) — `dangerous-inner-html-dynamic` is no longer pinned and
|
|
105
|
+
// renders to Hono parity, same as the static case.
|
|
106
106
|
// #2273: a method call on a prop typed as a built-in host rich type
|
|
107
107
|
// (Date, Map, …) has no catalogued lowering in any adapter — this is a
|
|
108
108
|
// compiler-level refusal (`checkRichTypeMethodCalls`, wired ahead of
|