@barefootjs/jinja 0.25.0 → 0.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/index.js +4 -1
- package/dist/adapter/jinja-adapter.d.ts.map +1 -1
- package/dist/build.js +4 -1
- package/dist/index.js +5 -3
- package/package.json +3 -3
- package/python/barefootjs/runtime.py +53 -14
- package/python/pyproject.toml +4 -1
- package/python/tests/test_format_date.py +47 -0
- package/src/adapter/jinja-adapter.ts +8 -1
- package/src/conformance-pins.ts +4 -4
package/dist/adapter/index.js
CHANGED
|
@@ -188498,10 +188498,13 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188498
188498
|
const resolution = resolveDangerousInnerHtml(element);
|
|
188499
188499
|
if (!resolution)
|
|
188500
188500
|
return null;
|
|
188501
|
-
if (resolution.kind === "
|
|
188501
|
+
if (resolution.kind === "unlowerable") {
|
|
188502
188502
|
this.errors.push(dangerousInnerHtmlDiagnostic(resolution.expr, resolution.loc));
|
|
188503
188503
|
return "";
|
|
188504
188504
|
}
|
|
188505
|
+
if (resolution.kind === "dynamic") {
|
|
188506
|
+
return `{{ ${this.convertExpressionToJinja(resolution.valueExpr, resolution.valueParsed)} | safe }}`;
|
|
188507
|
+
}
|
|
188505
188508
|
const violation = dangerousInnerHtmlMetacharViolation(resolution.html, this.name);
|
|
188506
188509
|
if (violation) {
|
|
188507
188510
|
const attr = element.attrs.find(isDangerousInnerHtmlAttr);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/jinja-adapter.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"jinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/jinja-adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/build.js
CHANGED
|
@@ -188498,10 +188498,13 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188498
188498
|
const resolution = resolveDangerousInnerHtml(element);
|
|
188499
188499
|
if (!resolution)
|
|
188500
188500
|
return null;
|
|
188501
|
-
if (resolution.kind === "
|
|
188501
|
+
if (resolution.kind === "unlowerable") {
|
|
188502
188502
|
this.errors.push(dangerousInnerHtmlDiagnostic(resolution.expr, resolution.loc));
|
|
188503
188503
|
return "";
|
|
188504
188504
|
}
|
|
188505
|
+
if (resolution.kind === "dynamic") {
|
|
188506
|
+
return `{{ ${this.convertExpressionToJinja(resolution.valueExpr, resolution.valueParsed)} | safe }}`;
|
|
188507
|
+
}
|
|
188505
188508
|
const violation = dangerousInnerHtmlMetacharViolation(resolution.html, this.name);
|
|
188506
188509
|
if (violation) {
|
|
188507
188510
|
const attr = element.attrs.find(isDangerousInnerHtmlAttr);
|
package/dist/index.js
CHANGED
|
@@ -188498,10 +188498,13 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188498
188498
|
const resolution = resolveDangerousInnerHtml(element);
|
|
188499
188499
|
if (!resolution)
|
|
188500
188500
|
return null;
|
|
188501
|
-
if (resolution.kind === "
|
|
188501
|
+
if (resolution.kind === "unlowerable") {
|
|
188502
188502
|
this.errors.push(dangerousInnerHtmlDiagnostic(resolution.expr, resolution.loc));
|
|
188503
188503
|
return "";
|
|
188504
188504
|
}
|
|
188505
|
+
if (resolution.kind === "dynamic") {
|
|
188506
|
+
return `{{ ${this.convertExpressionToJinja(resolution.valueExpr, resolution.valueParsed)} | safe }}`;
|
|
188507
|
+
}
|
|
188505
188508
|
const violation = dangerousInnerHtmlMetacharViolation(resolution.html, this.name);
|
|
188506
188509
|
if (violation) {
|
|
188507
188510
|
const attr = element.attrs.find(isDangerousInnerHtmlAttr);
|
|
@@ -189207,8 +189210,7 @@ var conformancePins = {
|
|
|
189207
189210
|
"filter-nested-find-predicate": [
|
|
189208
189211
|
{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2320" }
|
|
189209
189212
|
],
|
|
189210
|
-
"
|
|
189211
|
-
"date-method-uncatalogued": [{ code: "BF021", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2274" }]
|
|
189213
|
+
"date-method-uncatalogued": [{ code: "BF021", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2356" }]
|
|
189212
189214
|
};
|
|
189213
189215
|
// src/render-divergences.ts
|
|
189214
189216
|
var renderDivergences = {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/jinja",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.1",
|
|
4
4
|
"description": "Jinja2 adapter for BarefootJS — compiles IR to .jinja templates and ships the Python BarefootJS rendering runtime; runs under any Python web framework (Flask, etc.)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -53,14 +53,14 @@
|
|
|
53
53
|
"directory": "packages/adapter-jinja"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@barefootjs/shared": "0.
|
|
56
|
+
"@barefootjs/shared": "0.26.1"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@barefootjs/jsx": ">=0.2.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@barefootjs/adapter-tests": "0.1.0",
|
|
63
|
-
"@barefootjs/jsx": "0.
|
|
63
|
+
"@barefootjs/jsx": "0.26.1",
|
|
64
64
|
"typescript": "^5.0.0"
|
|
65
65
|
}
|
|
66
66
|
}
|
|
@@ -75,6 +75,7 @@ import functools
|
|
|
75
75
|
import math
|
|
76
76
|
import re
|
|
77
77
|
import uuid
|
|
78
|
+
import zoneinfo
|
|
78
79
|
from typing import Any, Callable, Optional
|
|
79
80
|
|
|
80
81
|
from markupsafe import Markup
|
|
@@ -958,7 +959,11 @@ class BarefootJS:
|
|
|
958
959
|
)
|
|
959
960
|
return 0
|
|
960
961
|
|
|
961
|
-
|
|
962
|
+
# Range-valid fixed offset ±HH:MM — hours 00-23, minutes 00-59 (#2344,
|
|
963
|
+
# mirrors OFFSET_RE in packages/client/src/format-date.ts). An
|
|
964
|
+
# out-of-range shape ('+25:00') falls through to the tzdata lookup,
|
|
965
|
+
# fails it, and raises — matching the JS reference's RangeError.
|
|
966
|
+
_FORMAT_DATE_TZ_RE = re.compile(r"^([+-])([01]\d|2[0-3]):([0-5]\d)$")
|
|
962
967
|
_FORMAT_DATE_TOKEN_RE = re.compile(r"YYYY|MMMM|MMM|MM|DD|dddd|ddd|M|D")
|
|
963
968
|
|
|
964
969
|
# `names`-table section offsets (spec/template-helpers.md "format_date",
|
|
@@ -982,14 +987,21 @@ class BarefootJS:
|
|
|
982
987
|
4 -- the lowering always supplies `tz` and `names` (defaulting
|
|
983
988
|
`'UTC'` and `[]`).
|
|
984
989
|
|
|
985
|
-
`tz` is `'UTC'
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
990
|
+
`tz` (#2344) is `'UTC'`, a range-valid fixed offset `±HH:MM`, or a
|
|
991
|
+
canonical IANA zone name ('Asia/Tokyo') resolved through tzdata
|
|
992
|
+
via `zoneinfo` -- the zone's UTC offset AT THE INSTANT being
|
|
993
|
+
formatted (DST-aware, historical-transition-aware, seconds
|
|
994
|
+
precision: pre-standard LMT offsets like Tokyo's +09:18:59 count).
|
|
995
|
+
Any other value -- an unknown zone, a non-canonical spelling, a
|
|
996
|
+
malformed or out-of-range offset ('+9:00', '+25:00') -- raises
|
|
997
|
+
ValueError, aborting the render loudly: the JS reference throws a
|
|
998
|
+
RangeError there, and a silently substituted timezone is the one
|
|
999
|
+
failure mode this helper must not have (the pre-#2344
|
|
1000
|
+
normalize-to-UTC total function is gone). The receiver contract
|
|
1001
|
+
still precedes tz validation (nil/unparseable -> '' first). The
|
|
1002
|
+
shifted instant's UTC calendar fields are what the pattern tokens
|
|
1003
|
+
read -- the shifted UTC clock face IS the local clock face in that
|
|
1004
|
+
zone. The shift and field derivation run on
|
|
993
1005
|
integers (Hinnant civil-from-days), NOT on a shifted `datetime`:
|
|
994
1006
|
a positive offset on 9999-12-31 lands in year 10000, past
|
|
995
1007
|
`datetime.max`, and must render `10000-…` like the JS reference
|
|
@@ -1033,13 +1045,18 @@ class BarefootJS:
|
|
|
1033
1045
|
except ValueError:
|
|
1034
1046
|
return ""
|
|
1035
1047
|
dt = dt.replace(tzinfo=datetime.timezone.utc) if dt.tzinfo is None else dt.astimezone(datetime.timezone.utc)
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1048
|
+
offset_ms = 0
|
|
1049
|
+
if tz != "UTC":
|
|
1050
|
+
m = self._FORMAT_DATE_TZ_RE.match(tz)
|
|
1051
|
+
if m:
|
|
1052
|
+
offset_ms = (-1 if m.group(1) == "-" else 1) * (
|
|
1053
|
+
int(m.group(2)) * 3_600 + int(m.group(3)) * 60
|
|
1054
|
+
) * 1_000
|
|
1055
|
+
else:
|
|
1056
|
+
offset_ms = self._format_date_zone_offset_ms(tz, dt)
|
|
1040
1057
|
delta = dt - _DATE_EPOCH
|
|
1041
1058
|
epoch_ms = (delta.days * 86_400 + delta.seconds) * 1_000 + delta.microseconds // 1_000
|
|
1042
|
-
shifted_ms = epoch_ms +
|
|
1059
|
+
shifted_ms = epoch_ms + offset_ms
|
|
1043
1060
|
# Hinnant civil-from-days over Python's floor division (exact for
|
|
1044
1061
|
# negative epochs and for days past datetime.max).
|
|
1045
1062
|
z = shifted_ms // 86_400_000 + 719_468
|
|
@@ -1085,6 +1102,28 @@ class BarefootJS:
|
|
|
1085
1102
|
|
|
1086
1103
|
return self._FORMAT_DATE_TOKEN_RE.sub(_sub, pattern)
|
|
1087
1104
|
|
|
1105
|
+
@staticmethod
|
|
1106
|
+
def _format_date_zone_offset_ms(tz: str, dt: datetime.datetime) -> int:
|
|
1107
|
+
"""Resolve a canonical IANA zone ID's UTC offset (whole ms, always
|
|
1108
|
+
second-granular) at instant `dt` through `zoneinfo` (#2344). An
|
|
1109
|
+
unresolvable id raises ValueError — loud, never a silent UTC
|
|
1110
|
+
fallback. `astimezone` on an instant within ~14h of `datetime.max`
|
|
1111
|
+
overflows year 9999 while the SHIFTED rendering must not (the
|
|
1112
|
+
civil-from-days integer path handles year 10000); no real zone
|
|
1113
|
+
transitions in the final days of December, so the offset two days
|
|
1114
|
+
earlier is the same offset — the retry keeps the far-future vector
|
|
1115
|
+
inside `datetime`'s range without changing the resolved offset."""
|
|
1116
|
+
try:
|
|
1117
|
+
zone = zoneinfo.ZoneInfo(tz)
|
|
1118
|
+
except (zoneinfo.ZoneInfoNotFoundError, ValueError, KeyError, OSError):
|
|
1119
|
+
raise ValueError(f"format_date: unresolvable timeZone {tz!r}") from None
|
|
1120
|
+
try:
|
|
1121
|
+
offset = dt.astimezone(zone).utcoffset()
|
|
1122
|
+
except OverflowError:
|
|
1123
|
+
offset = (dt - datetime.timedelta(days=2)).astimezone(zone).utcoffset()
|
|
1124
|
+
assert offset is not None # ZoneInfo always yields a concrete offset
|
|
1125
|
+
return (offset.days * 86_400 + offset.seconds) * 1_000
|
|
1126
|
+
|
|
1088
1127
|
# -----------------------------------------------------------------
|
|
1089
1128
|
# Array / String method helpers (#1448 Tier A)
|
|
1090
1129
|
# -----------------------------------------------------------------
|
package/python/pyproject.toml
CHANGED
|
@@ -20,7 +20,10 @@ classifiers = [
|
|
|
20
20
|
"Programming Language :: Python :: 3.11",
|
|
21
21
|
"Programming Language :: Python :: 3.12",
|
|
22
22
|
]
|
|
23
|
-
|
|
23
|
+
# tzdata (#2344): IANA data for zoneinfo-based named-zone resolution in
|
|
24
|
+
# `format_date` on platforms without a system zoneinfo directory (Windows,
|
|
25
|
+
# slim containers); zoneinfo prefers the system copy where one exists.
|
|
26
|
+
dependencies = ["jinja2>=3.1", "markupsafe>=2.0", "tzdata>=2024.1"]
|
|
24
27
|
|
|
25
28
|
[project.urls]
|
|
26
29
|
Homepage = "https://github.com/piconic-ai/barefootjs"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""`format_date` tz error contract (#2344).
|
|
2
|
+
|
|
3
|
+
Canonical IANA zone names resolve through tzdata (`zoneinfo`); an
|
|
4
|
+
unresolvable ``tz`` raises ValueError — the loud-not-silent replacement
|
|
5
|
+
for the pre-#2344 normalize-to-UTC total function. The resolvable grid is
|
|
6
|
+
pinned by the golden vectors (test_helper_vectors.py); this suite pins the
|
|
7
|
+
error side, which is outside the vector domain (spec/template-helpers.md
|
|
8
|
+
JS-throws rule).
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import unittest
|
|
14
|
+
|
|
15
|
+
from barefootjs.runtime import BarefootJS
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class _PureBackend:
|
|
19
|
+
def mark_raw(self, s):
|
|
20
|
+
return s
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
bf = BarefootJS(None, {"backend": _PureBackend()})
|
|
24
|
+
|
|
25
|
+
RECV = "2024-01-01T23:00:00.000Z"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class FormatDateTzTest(unittest.TestCase):
|
|
29
|
+
def test_unresolvable_time_zones_raise(self) -> None:
|
|
30
|
+
for tz in ["garbage", "Asia/Tokyoo", "+9:00", "+25:00", "asia/tokyo", "Local", ""]:
|
|
31
|
+
with self.subTest(tz=tz):
|
|
32
|
+
with self.assertRaises(ValueError):
|
|
33
|
+
bf.format_date(RECV, "YYYY-MM-DD", tz)
|
|
34
|
+
|
|
35
|
+
def test_receiver_contract_precedes_tz_validation(self) -> None:
|
|
36
|
+
# nil / unparseable receivers render '' without inspecting tz.
|
|
37
|
+
self.assertEqual(bf.format_date(None, "YYYY-MM-DD", "garbage"), "")
|
|
38
|
+
self.assertEqual(bf.format_date("not a date", "YYYY-MM-DD", "garbage"), "")
|
|
39
|
+
|
|
40
|
+
def test_named_zone_happy_path(self) -> None:
|
|
41
|
+
# Redundant with the golden vectors, but keeps this file
|
|
42
|
+
# self-sufficient outside the monorepo checkout.
|
|
43
|
+
self.assertEqual(bf.format_date(RECV, "YYYY-MM-DD", "Asia/Tokyo"), "2024-01-02")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
if __name__ == "__main__":
|
|
47
|
+
unittest.main()
|
|
@@ -584,10 +584,17 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
584
584
|
private renderDangerousInnerHtml(element: IRElement): string | null {
|
|
585
585
|
const resolution = resolveDangerousInnerHtml(element)
|
|
586
586
|
if (!resolution) return null
|
|
587
|
-
if (resolution.kind === '
|
|
587
|
+
if (resolution.kind === 'unlowerable') {
|
|
588
588
|
this.errors.push(dangerousInnerHtmlDiagnostic(resolution.expr, resolution.loc))
|
|
589
589
|
return ''
|
|
590
590
|
}
|
|
591
|
+
if (resolution.kind === 'dynamic') {
|
|
592
|
+
// Lower the `__html` expression and emit it through Jinja's `| safe`
|
|
593
|
+
// filter, which suppresses the environment's autoescape for this one
|
|
594
|
+
// value. The runtime evaluates the expression, so no template-metachar
|
|
595
|
+
// guard applies; the element already carries its hydration slot marker. #2319.
|
|
596
|
+
return `{{ ${this.convertExpressionToJinja(resolution.valueExpr, resolution.valueParsed)} | safe }}`
|
|
597
|
+
}
|
|
591
598
|
const violation = dangerousInnerHtmlMetacharViolation(resolution.html, this.name)
|
|
592
599
|
if (violation) {
|
|
593
600
|
const attr = element.attrs.find(isDangerousInnerHtmlAttr)!
|
package/src/conformance-pins.ts
CHANGED
|
@@ -100,13 +100,13 @@ 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 Jinja's `| safe` filter
|
|
104
|
+
// (#2319) — `dangerous-inner-html-dynamic` is no longer pinned and renders
|
|
105
|
+
// 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
|
|
109
109
|
// `adapter.generate()`), not an adapter-specific gap, so it is pinned
|
|
110
110
|
// identically across every adapter package including Hono.
|
|
111
|
-
'date-method-uncatalogued': [{ code: 'BF021', severity: 'error', issue: 'https://github.com/piconic-ai/barefootjs/issues/
|
|
111
|
+
'date-method-uncatalogued': [{ code: 'BF021', severity: 'error', issue: 'https://github.com/piconic-ai/barefootjs/issues/2356' }],
|
|
112
112
|
}
|