BarefootJS
view release on metacpan or search on metacpan
lib/BarefootJS/SearchParams.pm view on Meta::CPAN
package BarefootJS::SearchParams;
our $VERSION = "0.14.0";
use strict;
use warnings;
use utf8;
use feature 'signatures';
no warnings 'experimental::signatures';
# Request-scoped SSR view of the query string behind the reactive
# `searchParams()` environment signal (router v0.5, #1922). The framework
# integration builds one per request from the request URL and threads it into
# the template scope as `$searchParams` (the camelCase JS name the adapters
# keep, like every other signal/prop var); the compiled template reads it via
# `$searchParams->get('key')` (Mojo) / `$searchParams.get('key')` (Xslate).
#
# This runtime is template-engine- and framework-agnostic (core Perl only),
# matching the rest of BarefootJS.pm, so it can ship in the standalone
# @barefootjs/perl distribution.
#
# Semantics mirror the browser's URLSearchParams.get exactly under the
# adapters' `?? â //` lowering: get() returns the first value for a key, or
# `undef` when the key is absent. Perl's `//` (defined-or) coalesces only
# `undef`, so an absent key falls back to the author's default while a
# present-but-empty value (`?sort=`) keeps the empty string â the same
# distinction JS `??` draws between `null` and `''`. (This is a closer match
# than the Go adapter, whose `or` lowering also coalesces the empty string.)
# new($class, $query = '')
#
# Parse a raw query string into the reader. A leading '?' is tolerated, '+'
# decodes to a space, and %XX escapes are decoded â mirroring URLSearchParams's
# application/x-www-form-urlencoded parsing. A malformed pair never dies; it
# simply contributes nothing, matching the browser's lenient parsing.
sub new ($class, $query = '') {
$query //= '';
$query =~ s/\A\?//;
my %values;
for my $pair (split /[&;]/, $query) {
next if $pair eq '';
my ($key, $val) = split /=/, $pair, 2;
$key = _decode($key);
$val = defined $val ? _decode($val) : '';
push @{ $values{$key} }, $val;
}
return bless { values => \%values }, $class;
}
# get($self, $key)
#
# First value for $key, or `undef` when the key is absent (see the package
# docstring for why `undef` â not '' â is the right "missing" sentinel under
# the `//` lowering). A present-but-empty value returns ''.
sub get ($self, $key) {
my $vals = $self->{values}{$key};
return undef unless $vals && @$vals;
return $vals->[0];
}
sub _decode ($s) {
$s //= '';
$s =~ tr/+/ /;
# %XX â raw octet, then interpret the octet stream as UTF-8 (what
# URLSearchParams does). `utf8::decode` is a core builtin â no CPAN URI /
# URI::Escape dependency, keeping this runtime core-Perl-only. A byte run
# that isn't valid UTF-8 is left as-is rather than dying (lenient parsing).
$s =~ s/%([0-9A-Fa-f]{2})/chr hex $1/ge;
utf8::decode($s);
return $s;
}
1;
( run in 0.493 second using v1.01-cache-2.11-cpan-6aa56a78535 )