BarefootJS
view release on metacpan or search on metacpan
t/template_primitives.t view on Meta::CPAN
is $bf->repeat('x', 1), 'x', 'once â unchanged';
is $bf->repeat('ab', 0), '', 'zero â empty';
is $bf->repeat('ab', -2), '', 'negative â empty (JS throws; SSR degrades)';
is $bf->repeat('ab', 2.9),'abab', 'fractional count truncates toward zero';
is $bf->repeat('', 5), '', 'empty receiver â empty';
is $bf->repeat(undef, 3), '', 'undef receiver â empty';
};
# `String.prototype.padStart` / `padEnd` (#1448 Tier B) â pad to a
# target width with a repeat-and-truncate fill (default pad = space).
# Mirrors Go's rune-based `bf_pad_*`.
subtest 'pad_start / pad_end â pad to target width' => sub {
is $bf->pad_start('42', 5, '0'), '00042', 'left-pad with 0';
is $bf->pad_end('42', 5, '.'), '42...', 'right-pad with .';
# Default pad is a single space when omitted.
is $bf->pad_start('42', 5), ' 42', 'default pad = space (start)';
is $bf->pad_end('42', 5), '42 ', 'default pad = space (end)';
# Multi-char pad repeated then truncated to fill.
is $bf->pad_start('x', 5, 'ab'), 'ababx', 'multi-char pad truncated (start)';
is $bf->pad_end('x', 5, 'ab'), 'xabab', 'multi-char pad truncated (end)';
# Already >= target, or empty pad â unchanged.
is $bf->pad_start('hello', 3, '0'), 'hello', 'already >= target â unchanged';
is $bf->pad_start('42', 5, ''), '42', 'empty pad â unchanged';
# Target truncates toward zero; undef receiver coerces to empty.
is $bf->pad_start('7', 4.9, '0'), '0007', 'fractional target truncates';
is $bf->pad_start(undef, 3, '0'), '000', 'undef receiver pads from empty';
};
# `Array.prototype.sort(cmp)` / `Array.prototype.toSorted(cmp)`
# lowering (#1448 Tier B). The opts hash-ref carries a `keys` list of
# the structured comparison keys the compiler extracted at parse time
# â adapter-side emit is a single call shape; the runtime walks the
# keys in priority order, branching on key_kind / compare_type /
# direction per key.
subtest 'sort â structured comparator dispatch' => sub {
my $items = [
{ name => 'c', price => 30 },
{ name => 'a', price => 10 },
{ name => 'b', price => 20 },
];
# Numeric field, ascending â the canonical struct-field case.
is $bf->sort($items, { keys => [{ key_kind => 'field', key => 'price', compare_type => 'numeric', direction => 'asc' }] }),
[ { name => 'a', price => 10 }, { name => 'b', price => 20 }, { name => 'c', price => 30 } ],
'numeric field asc';
# Numeric field, descending â reverse direction.
is $bf->sort($items, { keys => [{ key_kind => 'field', key => 'price', compare_type => 'numeric', direction => 'desc' }] }),
[ { name => 'c', price => 30 }, { name => 'b', price => 20 }, { name => 'a', price => 10 } ],
'numeric field desc';
# Primitive numeric â `(a, b) => a - b` shape (key_kind=self).
is $bf->sort([3, 1, 2], { keys => [{ key_kind => 'self', compare_type => 'numeric', direction => 'asc' }] }),
[1, 2, 3],
'numeric self asc';
# Primitive string â `(a, b) => a.localeCompare(b)`. The Perl
# helper falls back to plain `cmp` (byte-ordering); within the
# same case it matches lexicographic order.
is $bf->sort(['charlie', 'alice', 'bob'], { keys => [{ key_kind => 'self', compare_type => 'string', direction => 'asc' }] }),
['alice', 'bob', 'charlie'],
'string self asc';
is $bf->sort(['charlie', 'alice', 'bob'], { keys => [{ key_kind => 'self', compare_type => 'string', direction => 'desc' }] }),
['charlie', 'bob', 'alice'],
'string self desc';
# Stable sort: equal keys preserve relative order. Perl `sort`
# has been stable since 5.8; pinning the guarantee so a future
# `use sort` pragma swap surfaces here.
my $stable_input = [
{ name => 'first', price => 10 },
{ name => 'second', price => 10 },
{ name => 'third', price => 10 },
];
is $bf->sort($stable_input, { keys => [{ key_kind => 'field', key => 'price', compare_type => 'numeric', direction => 'asc' }] }),
$stable_input,
'stable sort preserves equal-key order';
# Mutation isolation: caller's source array must survive.
my $src = [{ price => 3 }, { price => 1 }, { price => 2 }];
my $out = $bf->sort($src, { keys => [{ key_kind => 'field', key => 'price', compare_type => 'numeric', direction => 'asc' }] });
push @$out, { price => 99 };
is $src, [{ price => 3 }, { price => 1 }, { price => 2 }],
'source unchanged after mutating sort result';
# Non-array receivers fall back to empty.
is $bf->sort(undef, { keys => [{ key_kind => 'self', compare_type => 'numeric', direction => 'asc' }] }), [], 'undef receiver â []';
is $bf->sort('not an array', { keys => [{ key_kind => 'self', compare_type => 'numeric', direction => 'asc' }] }), [], 'scalar receiver â []';
is $bf->sort({a => 1}, { keys => [{ key_kind => 'self', compare_type => 'numeric', direction => 'asc' }] }), [], 'hash ref receiver â []';
# Empty array short-circuits.
is $bf->sort([], { keys => [{ key_kind => 'field', key => 'price', compare_type => 'numeric', direction => 'asc' }] }), [], 'empty array â []';
};
# Multi-key (`||`-chained) comparator: a tie on the primary key falls
# through to the next key. (#1448 Tier B follow-up.)
subtest 'sort â multi-key (||-chain) tie-breaks' => sub {
# `(a,b) => a.p - b.p || a.name.localeCompare(b.name)`.
my $items = [
{ p => 1, name => 'b' },
{ p => 1, name => 'a' },
{ p => 0, name => 'c' },
];
is $bf->sort($items, { keys => [
{ key_kind => 'field', key => 'p', compare_type => 'numeric', direction => 'asc' },
{ key_kind => 'field', key => 'name', compare_type => 'string', direction => 'asc' },
] }),
[ { p => 0, name => 'c' }, { p => 1, name => 'a' }, { p => 1, name => 'b' } ],
'tie on primary key broken by secondary asc';
# Descending secondary key: all primaries tie, so price desc orders.
my $items2 = [
{ name => 'a', price => 10 },
{ name => 'a', price => 30 },
{ name => 'a', price => 20 },
];
is $bf->sort($items2, { keys => [
{ key_kind => 'field', key => 'name', compare_type => 'string', direction => 'asc' },
{ key_kind => 'field', key => 'price', compare_type => 'numeric', direction => 'desc' },
] }),
[ { name => 'a', price => 30 }, { name => 'a', price => 20 }, { name => 'a', price => 10 } ],
'all primary tie â secondary price desc';
};
# `compare_type => 'auto'` (relational-ternary lowering): numeric when
# both keys look like numbers, else lexical. Mirrors Go's `bf_sort`.
subtest 'sort â auto compare (relational ternary)' => sub {
is $bf->sort([3, 1, 2], { keys => [{ key_kind => 'self', compare_type => 'auto', direction => 'asc' }] }),
[1, 2, 3],
'auto numeric asc';
is $bf->sort(['charlie', 'alice', 'bob'], { keys => [{ key_kind => 'self', compare_type => 'auto', direction => 'asc' }] }),
['alice', 'bob', 'charlie'],
'auto non-numeric strings â lexical';
# Numeric strings parse as numbers under auto (Go/Perl parity):
# "10" sorts after "9", not lexically before it.
is $bf->sort(['10', '9', '100'], { keys => [{ key_kind => 'self', compare_type => 'auto', direction => 'asc' }] }),
['9', '10', '100'],
'auto numeric strings compare numerically';
};
done_testing;
( run in 0.521 second using v1.01-cache-2.11-cpan-a5162978ef8 )