@barefootjs/perl 0.16.0 → 0.17.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.
@@ -9,6 +9,12 @@ use Scalar::Util qw(looks_like_number);
9
9
  use lib "$FindBin::Bin/../lib";
10
10
  use BarefootJS;
11
11
 
12
+ # vectors.json is UTF-8 (string args like "café"; `≡` in some notes). Decode it
13
+ # as UTF-8 (below) and route TAP through a UTF-8 layer so wide test names don't
14
+ # trigger "Wide character in print".
15
+ binmode Test::More->builder->$_, ':encoding(UTF-8)'
16
+ for qw(output failure_output todo_output);
17
+
12
18
  # Pure-Perl backend (core JSON::PP only) so this test runs with zero
13
19
  # Mojo present — same pattern as t/template_primitives.t.
14
20
  {
@@ -37,7 +43,10 @@ plan skip_all => 'golden vectors not available outside the monorepo checkout'
37
43
  my $doc = do {
38
44
  open my $fh, '<:raw', $vectors_path or die "open $vectors_path: $!";
39
45
  local $/;
40
- JSON::PP->new->decode(<$fh>);
46
+ # ->utf8 decodes the file's UTF-8 bytes into Perl characters, so a value
47
+ # like "café" round-trips to a single é (U+00E9) instead of its two raw
48
+ # bytes — otherwise _form_escape would re-encode them and double-escape.
49
+ JSON::PP->new->utf8->decode(scalar <$fh>);
41
50
  };
42
51
 
43
52
  # One binding per canonical helper id in the spec catalogue, bound to
@@ -99,6 +108,11 @@ my %bindings = (
99
108
  # and '' for present-but-empty, so the Perl backend matches JS exactly.
100
109
  search_params_get => sub { BarefootJS->search_params($_[0])->get($_[1]) },
101
110
 
111
+ # queryHref SSR builder (#2042): (base, include, key, value, …) → URL. The
112
+ # include flags arrive as JSON booleans (JSON::PP::Boolean, truthy/falsy
113
+ # under `next unless`); the helper form-encodes to match URLSearchParams.
114
+ query => sub { $bf->query(@_) },
115
+
102
116
  # Higher-order entries arrive in the canonical projection form
103
117
  # (spec: items + field [+ value]); the closures below rebuild the
104
118
  # predicate the adapters compile (`i => i.field === value`,
@@ -210,10 +224,6 @@ my %DIVERGENCES = (
210
224
  expect => '0.3',
211
225
  reason => 'Perl stringifies doubles via %.15g',
212
226
  },
213
- 'includes/cross-type probe is strict-equality false' => {
214
- expect => 1,
215
- reason => 'bf->includes scans with eq (string equality), so 2 eq "2" matches',
216
- },
217
227
  'filter_truthy/the string "0" is truthy' => {
218
228
  expect => ['x'],
219
229
  reason => 'Perl truthiness treats the string "0" as false',
package/t/query.t ADDED
@@ -0,0 +1,49 @@
1
+ use Test2::V0;
2
+ use utf8;
3
+
4
+ # BarefootJS->query — the `queryHref(base, { … })` URL-query builder helper
5
+ # (#2042).
6
+ #
7
+ # The full CROSS-BACKEND behaviour (control flow + form-encoding parity with the
8
+ # browser's URLSearchParams) is defined ONCE in the shared golden helper vectors
9
+ # — packages/adapter-tests/helper-vectors/vectors.json, fn "query" — and run
10
+ # here by t/helper_vectors.t and by the Go runtime's TestHelperVectors, so the
11
+ # Perl and Go expectations can't drift apart.
12
+ #
13
+ # This file keeps a few representative cases for always-on coverage (the golden
14
+ # file is monorepo-only, absent from the CPAN dist) plus the Perl-runtime-
15
+ # SPECIFIC defensive behaviour the golden vectors can't express: an `undef`
16
+ # value. JSON has no `undefined`, and a JSON `null` stringifies to "null" under
17
+ # JS `String()`, so it can't be a shared vector; Perl coerces `undef` to '' and
18
+ # omits the empty pair.
19
+
20
+ use FindBin qw($Bin);
21
+ use lib "$Bin/../lib";
22
+
23
+ use BarefootJS;
24
+
25
+ # `query` is a pure helper (no backend / controller), so a bare blessed stub is
26
+ # enough — mirroring t/helper_vectors.t. Triples are (include, key, value).
27
+ my $bf = bless {}, 'BarefootJS';
28
+
29
+ # Representative control flow: a repeated key overwrites at its first position
30
+ # (URLSearchParams.set), surrounding order preserved.
31
+ is $bf->query('/blog', 1, 'sort', 'title', 1, 'tag', 'go', 1, 'sort', 'date'),
32
+ '/blog?sort=date&tag=go', 'order preserved, repeated key overwrites at first position';
33
+
34
+ # Representative form-encoding: space → '+', '~' → %7E, '*' kept (URLSearchParams,
35
+ # not Go's url.QueryEscape).
36
+ is $bf->query('/s', 1, 't', 'a~b *c'), '/s?t=a%7Eb+*c', 'form-encode: ~ → %7E, * kept, space → +';
37
+
38
+ # Representative array value: an array ref appends one pair per non-empty member
39
+ # (#2048), skipping empties.
40
+ is $bf->query('/list', 1, 'tag', ['a', '', 'b']), '/list?tag=a&tag=b',
41
+ 'array value appends a pair per non-empty member';
42
+
43
+ # Perl-specific: an `undef` value is coerced to '' and then omitted, without
44
+ # disturbing the surrounding pairs.
45
+ is $bf->query('/list', 1, 'tag', undef), '/list', 'undef value coerced to empty → omitted';
46
+ is $bf->query('/list', 1, 'tag', undef, 1, 'keep', 'me'), '/list?keep=me',
47
+ 'undef value dropped, surrounding pairs intact';
48
+
49
+ done_testing;
@@ -81,11 +81,16 @@ subtest 'floor / ceil / round — Math.* mirrors; propagate NaN' => sub {
81
81
  # `Array.prototype.includes(x)` + `String.prototype.includes(sub)` lower
82
82
  # to the same `$bf->includes($recv, $elem)` shape — see #1448 Tier A.
83
83
  # The Perl helper dispatches on `ref()`: ARRAY ref scans elements with
84
- # `eq`; scalar falls back to `index(..., ...) != -1`. Anything else
85
- # (HASH ref, code ref) returns false to match the JS semantic that
86
- # `.includes` is only defined on Array / TypedArray / String.
84
+ # `BarefootJS::Evaluator::_same_value_zero` (SameValueZero no cross-type
85
+ # coercion, NaN matches NaN), matching the evaluator's serialized-callback
86
+ # `.includes` path so both positions agree; scalar falls back to
87
+ # `index(..., ...) != -1`. Anything else (HASH ref, code ref) returns
88
+ # false to match the JS semantic that `.includes` is only defined on
89
+ # Array / TypedArray / String.
87
90
  subtest 'includes — array + string + non-array/string dispatch' => sub {
88
- # Array receiver: element-wise `eq` (handles defined/undef parity).
91
+ # Array receiver: SameValueZero element search (handles defined/undef
92
+ # parity, and no numeric/string coercion — see the cross-type cases
93
+ # below).
89
94
  ok $bf->includes(['a', 'b', 'c'], 'b'), 'array contains element → 1';
90
95
  ok !$bf->includes(['a', 'b', 'c'], 'z'), 'array does not contain → 0';
91
96
  ok $bf->includes([1, 2, 3], 2), 'numeric element';
@@ -93,6 +98,12 @@ subtest 'includes — array + string + non-array/string dispatch' => sub {
93
98
  ok $bf->includes([undef, 'a'], undef), 'undef element matches undef needle';
94
99
  ok !$bf->includes(['a', 'b'], undef), 'undef needle, no undef element → 0';
95
100
 
101
+ # SameValueZero never coerces across types — pins the divergence from
102
+ # the old stringy `eq` scan (where `[2].includes("2")` was true).
103
+ ok !$bf->includes([2], '2'), '[2].includes("2") → 0 (no numeric→string coercion)';
104
+ ok $bf->includes([2], 2), '[2].includes(2) → 1';
105
+ ok $bf->includes(['2'], '2'), '["2"].includes("2") → 1 (string vs string still matches)';
106
+
96
107
  # String receiver: substring search.
97
108
  ok $bf->includes('hello world', 'world'), 'substring present → 1';
98
109
  ok !$bf->includes('hello world', 'earth'), 'substring absent → 0';