@barefootjs/jinja 0.19.1 → 0.21.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 +1 -1
- package/dist/adapter/jinja-adapter.d.ts.map +1 -1
- package/dist/build.js +1 -1
- package/dist/conformance-pins.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/package.json +3 -3
- package/python/barefootjs/runtime.py +65 -0
- package/python/tests/test_helper_vectors.py +20 -1
- package/python/tests/test_render.py +50 -5
- package/src/__tests__/jinja-adapter-unit.test.ts +38 -0
- package/src/adapter/jinja-adapter.ts +4 -1
- package/src/conformance-pins.ts +6 -0
- package/src/test-render.ts +9 -0
package/dist/adapter/index.js
CHANGED
|
@@ -188820,7 +188820,7 @@ ${alternate}
|
|
|
188820
188820
|
renderFragment(fragment) {
|
|
188821
188821
|
const children = this.renderChildren(fragment.children);
|
|
188822
188822
|
if (fragment.needsScopeComment) {
|
|
188823
|
-
return `{{ bf.scope_comment() | safe }}${children}`;
|
|
188823
|
+
return `{{ bf.scope_comment() | safe }}${children}{{ bf.scope_comment_end() | safe }}`;
|
|
188824
188824
|
}
|
|
188825
188825
|
return children;
|
|
188826
188826
|
}
|
|
@@ -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
|
@@ -188820,7 +188820,7 @@ ${alternate}
|
|
|
188820
188820
|
renderFragment(fragment) {
|
|
188821
188821
|
const children = this.renderChildren(fragment.children);
|
|
188822
188822
|
if (fragment.needsScopeComment) {
|
|
188823
|
-
return `{{ bf.scope_comment() | safe }}${children}`;
|
|
188823
|
+
return `{{ bf.scope_comment() | safe }}${children}{{ bf.scope_comment_end() | safe }}`;
|
|
188824
188824
|
}
|
|
188825
188825
|
return children;
|
|
188826
188826
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conformance-pins.d.ts","sourceRoot":"","sources":["../src/conformance-pins.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,eAAO,MAAM,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"conformance-pins.d.ts","sourceRoot":"","sources":["../src/conformance-pins.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,eAAO,MAAM,eAAe,EAAE,eAmG7B,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -188820,7 +188820,7 @@ ${alternate}
|
|
|
188820
188820
|
renderFragment(fragment) {
|
|
188821
188821
|
const children = this.renderChildren(fragment.children);
|
|
188822
188822
|
if (fragment.needsScopeComment) {
|
|
188823
|
-
return `{{ bf.scope_comment() | safe }}${children}`;
|
|
188823
|
+
return `{{ bf.scope_comment() | safe }}${children}{{ bf.scope_comment_end() | safe }}`;
|
|
188824
188824
|
}
|
|
188825
188825
|
return children;
|
|
188826
188826
|
}
|
|
@@ -189207,7 +189207,8 @@ var conformancePins = {
|
|
|
189207
189207
|
"filter-nested-find-predicate": [
|
|
189208
189208
|
{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2038" }
|
|
189209
189209
|
],
|
|
189210
|
-
"dangerous-inner-html-dynamic": [{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2215" }]
|
|
189210
|
+
"dangerous-inner-html-dynamic": [{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2215" }],
|
|
189211
|
+
"date-method-uncatalogued": [{ code: "BF021", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2274" }]
|
|
189211
189212
|
};
|
|
189212
189213
|
// src/render-divergences.ts
|
|
189213
189214
|
var renderDivergences = {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/jinja",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
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.21.0"
|
|
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.21.0",
|
|
64
64
|
"typescript": "^5.0.0"
|
|
65
65
|
}
|
|
66
66
|
}
|
|
@@ -70,6 +70,7 @@ site below):
|
|
|
70
70
|
|
|
71
71
|
from __future__ import annotations
|
|
72
72
|
|
|
73
|
+
import datetime
|
|
73
74
|
import functools
|
|
74
75
|
import math
|
|
75
76
|
import re
|
|
@@ -473,6 +474,12 @@ def _numeric_value(v: Any) -> float:
|
|
|
473
474
|
return 0.0
|
|
474
475
|
|
|
475
476
|
|
|
477
|
+
# Epoch anchor for `date()`'s `getTime` -- an aware UTC `datetime` so
|
|
478
|
+
# subtraction from any other aware `datetime` (any tzinfo) yields the correct
|
|
479
|
+
# instant delta regardless of the operand's own offset.
|
|
480
|
+
_DATE_EPOCH = datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc)
|
|
481
|
+
|
|
482
|
+
|
|
476
483
|
def _derive_stash_from_defaults(defaults: dict, props: dict) -> dict:
|
|
477
484
|
"""Derive template-stash kvs from a manifest entry's `ssrDefaults`
|
|
478
485
|
section. See BarefootJS.pm's `_derive_stash_from_defaults` docstring for
|
|
@@ -649,6 +656,13 @@ class BarefootJS:
|
|
|
649
656
|
props_json = "|" + self.backend.encode_json(props)
|
|
650
657
|
return f"<!--bf-scope:{scope_id}{host_segment}{props_json}-->"
|
|
651
658
|
|
|
659
|
+
def scope_comment_end(self) -> str:
|
|
660
|
+
"""Paired end marker for `scope_comment`, emitted after the
|
|
661
|
+
fragment's last top-level node. No host/props segments -- the
|
|
662
|
+
client only needs the scope id to close the boundary (#2289)."""
|
|
663
|
+
scope_id = self._scope_id() or ""
|
|
664
|
+
return f"<!--bf-/scope:{scope_id}-->"
|
|
665
|
+
|
|
652
666
|
# -----------------------------------------------------------------
|
|
653
667
|
# Script Registration
|
|
654
668
|
# -----------------------------------------------------------------
|
|
@@ -893,6 +907,57 @@ class BarefootJS:
|
|
|
893
907
|
n = js_number(value)
|
|
894
908
|
return n if _is_nan(n) else abs(n)
|
|
895
909
|
|
|
910
|
+
def date(self, recv: Any, op: str) -> Any:
|
|
911
|
+
"""`date(recv, op)` -- zero-arg `Date.prototype` method lowering
|
|
912
|
+
(#2274, spec entry "date"). `recv` arrives as either this runtime's
|
|
913
|
+
own `datetime` or an ISO-8601 string (a template prop may carry
|
|
914
|
+
either depending on how the host populated it). A naive `datetime`
|
|
915
|
+
is treated as already-UTC (this runtime never produces one); an
|
|
916
|
+
aware one converts via `astimezone` so a non-UTC-offset input still
|
|
917
|
+
dispatches against the right instant. `.month` is 1-based in
|
|
918
|
+
Python; only `getUTCMonth` subtracts 1 to match JS's 0-based month.
|
|
919
|
+
`getTime` divides the exact `timedelta` from the epoch by a 1ms
|
|
920
|
+
`timedelta` (floor division on an exact `timedelta` ratio) rather
|
|
921
|
+
than rounding a float ms value, so a pre-epoch instant stays
|
|
922
|
+
exact."""
|
|
923
|
+
if isinstance(recv, datetime.datetime):
|
|
924
|
+
dt = recv
|
|
925
|
+
else:
|
|
926
|
+
# `fromisoformat` only learned the bare `Z` suffix in 3.11 but
|
|
927
|
+
# accepts an explicit `+00:00` offset since 3.7, so a `>=3.10`
|
|
928
|
+
# install parses the same string once rewritten. A nil or
|
|
929
|
+
# unparseable receiver degrades to the zero value the Go / Rust
|
|
930
|
+
# / Perl helpers document, not a render-time crash.
|
|
931
|
+
s = str(recv)
|
|
932
|
+
if s.endswith("Z"):
|
|
933
|
+
s = s[:-1] + "+00:00"
|
|
934
|
+
try:
|
|
935
|
+
dt = datetime.datetime.fromisoformat(s)
|
|
936
|
+
except ValueError:
|
|
937
|
+
return "" if op == "toISOString" else 0
|
|
938
|
+
dt = dt.replace(tzinfo=datetime.timezone.utc) if dt.tzinfo is None else dt.astimezone(datetime.timezone.utc)
|
|
939
|
+
if op == "getUTCFullYear":
|
|
940
|
+
return dt.year
|
|
941
|
+
if op == "getUTCMonth":
|
|
942
|
+
return dt.month - 1
|
|
943
|
+
if op == "getUTCDate":
|
|
944
|
+
return dt.day
|
|
945
|
+
if op == "getUTCHours":
|
|
946
|
+
return dt.hour
|
|
947
|
+
if op == "getUTCMinutes":
|
|
948
|
+
return dt.minute
|
|
949
|
+
if op == "getUTCSeconds":
|
|
950
|
+
return dt.second
|
|
951
|
+
if op == "getTime":
|
|
952
|
+
return (dt - _DATE_EPOCH) // datetime.timedelta(milliseconds=1)
|
|
953
|
+
if op == "toISOString":
|
|
954
|
+
return (
|
|
955
|
+
f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d}T"
|
|
956
|
+
f"{dt.hour:02d}:{dt.minute:02d}:{dt.second:02d}."
|
|
957
|
+
f"{dt.microsecond // 1000:03d}Z"
|
|
958
|
+
)
|
|
959
|
+
return 0
|
|
960
|
+
|
|
896
961
|
# -----------------------------------------------------------------
|
|
897
962
|
# Array / String method helpers (#1448 Tier A)
|
|
898
963
|
# -----------------------------------------------------------------
|
|
@@ -23,6 +23,7 @@ monorepo checkout), matching the Perl/Go harnesses' `skip_all` policy.
|
|
|
23
23
|
from __future__ import annotations
|
|
24
24
|
|
|
25
25
|
import builtins
|
|
26
|
+
import datetime
|
|
26
27
|
import json
|
|
27
28
|
import math
|
|
28
29
|
import os
|
|
@@ -89,6 +90,22 @@ def _bind_reduce(recv, op, key_kind, key, rtype, init, direction):
|
|
|
89
90
|
)
|
|
90
91
|
|
|
91
92
|
|
|
93
|
+
def _materialize_arg(v):
|
|
94
|
+
"""Materializes the `{"$date": "<ISO>"}` native-date arg sentinel
|
|
95
|
+
(#2288) into a real `datetime`, so `date`'s native-receiver branch (not
|
|
96
|
+
just its ISO-string branch) is exercised. Recurses through lists/dicts
|
|
97
|
+
the same shape the Perl port's `normalize_arg` walks, since a vector's
|
|
98
|
+
`args` may nest the sentinel inside a higher-order projection payload."""
|
|
99
|
+
if isinstance(v, list):
|
|
100
|
+
return [_materialize_arg(x) for x in v]
|
|
101
|
+
if isinstance(v, dict) and list(v) == ["$date"]:
|
|
102
|
+
s = v["$date"]
|
|
103
|
+
return datetime.datetime.fromisoformat(s[:-1] + "+00:00" if s.endswith("Z") else s)
|
|
104
|
+
if isinstance(v, dict):
|
|
105
|
+
return {k: _materialize_arg(x) for k, x in v.items()}
|
|
106
|
+
return v
|
|
107
|
+
|
|
108
|
+
|
|
92
109
|
def _bind_flat_map_tuple(recv, *flat):
|
|
93
110
|
flat = list(flat)
|
|
94
111
|
specs = []
|
|
@@ -121,6 +138,7 @@ BINDINGS = {
|
|
|
121
138
|
"max": bf.max,
|
|
122
139
|
"abs": bf.abs,
|
|
123
140
|
"to_fixed": lambda *a: bf.to_fixed(*a),
|
|
141
|
+
"date": lambda recv, op: bf.date(recv, op),
|
|
124
142
|
"lower": bf.lc,
|
|
125
143
|
"upper": bf.uc,
|
|
126
144
|
"trim": bf.trim,
|
|
@@ -240,7 +258,8 @@ class HelperVectorsTest(unittest.TestCase):
|
|
|
240
258
|
seen_declarations = set()
|
|
241
259
|
|
|
242
260
|
for case in doc["cases"]:
|
|
243
|
-
fn, note,
|
|
261
|
+
fn, note, expect = case["fn"], case["note"], case["expect"]
|
|
262
|
+
args = [_materialize_arg(a) for a in case["args"]]
|
|
244
263
|
key = f"{fn}/{note}"
|
|
245
264
|
with self.subTest(key=key):
|
|
246
265
|
if fn in UNSUPPORTED:
|
|
@@ -8,16 +8,18 @@ comment markers, autoescaping, and `spread_attrs`.
|
|
|
8
8
|
|
|
9
9
|
Jinja idiom note: helpers that return already-safe HTML syntax but are NOT
|
|
10
10
|
wrapped by the backend's `mark_raw` (`scope_attr`, `hydration_attrs`,
|
|
11
|
-
`text_start`, `text_end`, `comment`, `scope_comment`)
|
|
12
|
-
`| safe` filter at the call site -- the Jinja-syntax
|
|
13
|
-
`| mark_raw` pipe seen in the Perl port's `render.t`.
|
|
14
|
-
returns a `markupsafe.Markup` value (via
|
|
15
|
-
filter, matching the Perl template's
|
|
11
|
+
`text_start`, `text_end`, `comment`, `scope_comment`, `scope_comment_end`)
|
|
12
|
+
need an explicit `| safe` filter at the call site -- the Jinja-syntax
|
|
13
|
+
equivalent of Kolon's `| mark_raw` pipe seen in the Perl port's `render.t`.
|
|
14
|
+
`spread_attrs` already returns a `markupsafe.Markup` value (via
|
|
15
|
+
`backend.mark_raw`), so it needs no filter, matching the Perl template's
|
|
16
|
+
call site exactly.
|
|
16
17
|
"""
|
|
17
18
|
|
|
18
19
|
from __future__ import annotations
|
|
19
20
|
|
|
20
21
|
import json
|
|
22
|
+
import re
|
|
21
23
|
import tempfile
|
|
22
24
|
import unittest
|
|
23
25
|
from pathlib import Path
|
|
@@ -32,6 +34,17 @@ WIDGET_TEMPLATE = (
|
|
|
32
34
|
"</div>"
|
|
33
35
|
)
|
|
34
36
|
|
|
37
|
+
# A fragment-rooted component template, matching what `renderFragment` emits
|
|
38
|
+
# for `fragment.needsScopeComment` (#2289): the begin marker precedes the
|
|
39
|
+
# fragment's children, the end marker follows its last top-level node so the
|
|
40
|
+
# client's range query has a lower bound and doesn't leak onto later
|
|
41
|
+
# siblings owned by the parent.
|
|
42
|
+
FRAGMENT_TEMPLATE = (
|
|
43
|
+
"{{ bf.scope_comment() | safe }}"
|
|
44
|
+
"<button>add</button><p>hint</p>"
|
|
45
|
+
"{{ bf.scope_comment_end() | safe }}"
|
|
46
|
+
)
|
|
47
|
+
|
|
35
48
|
|
|
36
49
|
class RenderTest(unittest.TestCase):
|
|
37
50
|
def setUp(self):
|
|
@@ -97,6 +110,38 @@ class RenderTest(unittest.TestCase):
|
|
|
97
110
|
out = self.backend.render_named("parent", self.bf, {})
|
|
98
111
|
self.assertEqual(out, "parent:[c1:hi]")
|
|
99
112
|
|
|
113
|
+
def test_scope_comment_end_marker_pairs_with_begin(self):
|
|
114
|
+
"""#2289: the end marker closes the fragment's scope range with the
|
|
115
|
+
SAME scope id as the begin marker, and no host/props segment."""
|
|
116
|
+
template_dir = Path(self._tmpdir.name)
|
|
117
|
+
(template_dir / "fragment.jinja").write_text(FRAGMENT_TEMPLATE, encoding="utf-8")
|
|
118
|
+
out = self.backend.render_named("fragment", self.bf, {})
|
|
119
|
+
|
|
120
|
+
self.assertIn("<!--bf-scope:Widget_test-->", out)
|
|
121
|
+
self.assertIn("<!--bf-/scope:Widget_test-->", out)
|
|
122
|
+
# End marker follows the fragment's last top-level node.
|
|
123
|
+
self.assertTrue(out.endswith("<!--bf-/scope:Widget_test-->"))
|
|
124
|
+
|
|
125
|
+
begin_id = re.search(r"<!--bf-scope:([^|>-]+)", out).group(1)
|
|
126
|
+
end_id = re.search(r"<!--bf-/scope:([^>-]+)-->", out).group(1)
|
|
127
|
+
self.assertEqual(begin_id, end_id)
|
|
128
|
+
|
|
129
|
+
def test_scope_comment_end_carries_no_host_or_props_segment(self):
|
|
130
|
+
"""Unlike `scope_comment`, the end marker never carries `|h=`/`|m=`
|
|
131
|
+
or a props JSON segment -- the client only needs the scope id to
|
|
132
|
+
confirm the range closes (#2289)."""
|
|
133
|
+
template_dir = Path(self._tmpdir.name)
|
|
134
|
+
(template_dir / "fragment_child.jinja").write_text(FRAGMENT_TEMPLATE, encoding="utf-8")
|
|
135
|
+
|
|
136
|
+
child_bf = BarefootJS(None, {"backend": self.backend})
|
|
137
|
+
child_bf._scope_id("Widget_test_s2")
|
|
138
|
+
child_bf._bf_parent("Widget_test")
|
|
139
|
+
child_bf._bf_mount("s2")
|
|
140
|
+
out = self.backend.render_named("fragment_child", child_bf, {})
|
|
141
|
+
|
|
142
|
+
self.assertIn("<!--bf-scope:Widget_test_s2|h=Widget_test|m=s2-->", out)
|
|
143
|
+
self.assertIn("<!--bf-/scope:Widget_test_s2-->", out)
|
|
144
|
+
|
|
100
145
|
|
|
101
146
|
if __name__ == "__main__":
|
|
102
147
|
unittest.main()
|
|
@@ -529,3 +529,41 @@ function Widget({ rows }: { rows: { x: string }[] }) {
|
|
|
529
529
|
expect(template).toContain("bf.string(cfg['x'])")
|
|
530
530
|
})
|
|
531
531
|
})
|
|
532
|
+
|
|
533
|
+
// A fragment-rooted component (top-level `<>...</>` return) has no single
|
|
534
|
+
// wrapping element to bound the client's scope query, so `renderFragment`
|
|
535
|
+
// brackets its children with a comment-based scope marker pair instead of
|
|
536
|
+
// element attributes. Without the end marker, a range query anchored on the
|
|
537
|
+
// begin marker has no lower bound and leaks onto later siblings owned by
|
|
538
|
+
// the parent (#2289). Mirrors the hono/xslate/mojo/go/erb adapters' fix —
|
|
539
|
+
// see `wrapWithScopeComment` in packages/adapter-hono/src/adapter/hono-adapter.ts.
|
|
540
|
+
describe('JinjaAdapter - fragment-root scope comment end marker (#2289)', () => {
|
|
541
|
+
test('renderFragment brackets a multi-root fragment with paired begin/end scope_comment calls', () => {
|
|
542
|
+
const { template } = compileAndGenerate(`
|
|
543
|
+
export function ChildFragment() {
|
|
544
|
+
return <><button>add</button><p>hint</p></>
|
|
545
|
+
}
|
|
546
|
+
`)
|
|
547
|
+
expect(template).toContain('{{ bf.scope_comment() | safe }}')
|
|
548
|
+
expect(template).toContain('{{ bf.scope_comment_end() | safe }}')
|
|
549
|
+
// Begin marker precedes the children; end marker follows the fragment's
|
|
550
|
+
// last top-level node -- both read the same `bf._scope_id()` at render
|
|
551
|
+
// time, so the emitted scope ids are identical by construction.
|
|
552
|
+
const beginIdx = template.indexOf('bf.scope_comment() | safe')
|
|
553
|
+
const buttonIdx = template.indexOf('<button>')
|
|
554
|
+
const pIdx = template.indexOf('<p>')
|
|
555
|
+
const endIdx = template.indexOf('bf.scope_comment_end() | safe')
|
|
556
|
+
expect(beginIdx).toBeLessThan(buttonIdx)
|
|
557
|
+
expect(buttonIdx).toBeLessThan(pIdx)
|
|
558
|
+
expect(pIdx).toBeLessThan(endIdx)
|
|
559
|
+
})
|
|
560
|
+
|
|
561
|
+
test('a non-fragment (single element) root does NOT get scope_comment_end (element attrs bound the scope instead)', () => {
|
|
562
|
+
const { template } = compileAndGenerate(`
|
|
563
|
+
export function Child() {
|
|
564
|
+
return <div>hi</div>
|
|
565
|
+
}
|
|
566
|
+
`)
|
|
567
|
+
expect(template).not.toContain('scope_comment')
|
|
568
|
+
})
|
|
569
|
+
})
|
|
@@ -1213,7 +1213,10 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
1213
1213
|
private renderFragment(fragment: IRFragment): string {
|
|
1214
1214
|
const children = this.renderChildren(fragment.children)
|
|
1215
1215
|
if (fragment.needsScopeComment) {
|
|
1216
|
-
|
|
1216
|
+
// End marker bounds the scope's sibling range -- without it, queries
|
|
1217
|
+
// from the fragment scope leak onto later siblings owned by the
|
|
1218
|
+
// parent (#2289).
|
|
1219
|
+
return `{{ bf.scope_comment() | safe }}${children}{{ bf.scope_comment_end() | safe }}`
|
|
1217
1220
|
}
|
|
1218
1221
|
return children
|
|
1219
1222
|
}
|
package/src/conformance-pins.ts
CHANGED
|
@@ -103,4 +103,10 @@ export const conformancePins: ConformancePins = {
|
|
|
103
103
|
// A dynamic/signal-derived value still refuses with BF101 — see the
|
|
104
104
|
// `dangerous-inner-html-dynamic` fixture/pin below (tracked: #2215).
|
|
105
105
|
'dangerous-inner-html-dynamic': [{ code: 'BF101', severity: 'error', issue: 'https://github.com/piconic-ai/barefootjs/issues/2215' }],
|
|
106
|
+
// #2273: a method call on a prop typed as a built-in host rich type
|
|
107
|
+
// (Date, Map, …) has no catalogued lowering in any adapter — this is a
|
|
108
|
+
// compiler-level refusal (`checkRichTypeMethodCalls`, wired ahead of
|
|
109
|
+
// `adapter.generate()`), not an adapter-specific gap, so it is pinned
|
|
110
|
+
// identically across every adapter package including Hono.
|
|
111
|
+
'date-method-uncatalogued': [{ code: 'BF021', severity: 'error', issue: 'https://github.com/piconic-ai/barefootjs/issues/2274' }],
|
|
106
112
|
}
|
package/src/test-render.ts
CHANGED
|
@@ -570,6 +570,15 @@ function toPyLiteral(value: unknown): string {
|
|
|
570
570
|
if (typeof value === 'string') return pyStr(value)
|
|
571
571
|
if (typeof value === 'number') return pyNumber(value)
|
|
572
572
|
if (typeof value === 'boolean') return value ? 'True' : 'False'
|
|
573
|
+
if (value instanceof Date) {
|
|
574
|
+
// A Date prop crosses the language boundary as its ISO-8601 string —
|
|
575
|
+
// the shared `date()` runtime helper (#2274/#2288) accepts an ISO
|
|
576
|
+
// string as well as a native `datetime`. MUST come before the generic
|
|
577
|
+
// `value && typeof value === 'object'` branch below, which would
|
|
578
|
+
// otherwise `Object.entries()` a Date's (non-enumerable) internals
|
|
579
|
+
// into an empty dict literal, silently erasing the value.
|
|
580
|
+
return pyStr(value.toISOString())
|
|
581
|
+
}
|
|
573
582
|
if (Array.isArray(value)) {
|
|
574
583
|
return `[${value.map(toPyLiteral).join(', ')}]`
|
|
575
584
|
}
|