From c60888088e6cd474fb91d0b988acae61ddff02cf Mon Sep 17 00:00:00 2001 From: Pragmatic Software Date: Tue, 21 Oct 2025 01:23:01 -0700 Subject: [PATCH] Plugin/FuncBuiltins: add jsonval and unescape --- lib/PBot/Plugin/FuncBuiltins.pm | 116 ++++++++++++++++++++++++++++++++ lib/PBot/VERSION.pm | 4 +- 2 files changed, 118 insertions(+), 2 deletions(-) diff --git a/lib/PBot/Plugin/FuncBuiltins.pm b/lib/PBot/Plugin/FuncBuiltins.pm index 4f5175a3..be41b6f1 100644 --- a/lib/PBot/Plugin/FuncBuiltins.pm +++ b/lib/PBot/Plugin/FuncBuiltins.pm @@ -15,6 +15,8 @@ use PBot::Core::Utils::Indefinite; use Lingua::EN::Tagger; use URI::Escape qw/uri_escape_utf8/; +use JSON::XS; + sub initialize($self, %conf) { $self->{pbot}->{functions}->register( 'title', @@ -56,6 +58,14 @@ sub initialize($self, %conf) { subref => sub { $self->func_unquote(@_) } } ); + $self->{pbot}->{functions}->register( + 'unescape', + { + desc => 'removes unescaped escapes', + usage => 'unescape ', + subref => sub { $self->func_unescape(@_) } + } + ); $self->{pbot}->{functions}->register( 'shquote', { @@ -120,6 +130,14 @@ sub initialize($self, %conf) { subref => sub { $self->func_length(@_) } } ); + $self->{pbot}->{functions}->register( + 'jsonval', + { + desc => 'extract a JSON value from a JSON structure', + usage => 'jsonval ; e.g. jsonval .a.b[1] {"a": {"b": [10, 20, 30]}}', + subref => sub { $self->func_jsonval(@_) } + } + ); $self->{tagger} = Lingua::EN::Tagger->new; } @@ -130,6 +148,7 @@ sub unload($self) { $self->{pbot}->{functions}->unregister('uc'); $self->{pbot}->{functions}->unregister('lc'); $self->{pbot}->{functions}->unregister('unquote'); + $self->{pbot}->{functions}->unregister('unescape'); $self->{pbot}->{functions}->unregister('shquote'); $self->{pbot}->{functions}->unregister('quotemeta'); $self->{pbot}->{functions}->unregister('uri_escape'); @@ -137,6 +156,8 @@ sub unload($self) { $self->{pbot}->{functions}->unregister('maybe-the'); $self->{pbot}->{functions}->unregister('maybe-to'); $self->{pbot}->{functions}->unregister('maybe-on'); + $self->{pbot}->{functions}->unregister('length'); + $self->{pbot}->{functions}->unregister('jsonval'); } sub func_unquote($self, @rest) { @@ -147,6 +168,12 @@ sub func_unquote($self, @rest) { return $text; } +sub func_unescape($self, @rest) { + my $text = "@rest"; + $text =~ s/(? ; e.g. jsonval .a.b[1] {"a": {"b": [10, 20, 30]}}'; + } + + my $h = eval { + my $decoder = JSON::XS->new; + return $decoder->decode($text); + }; + + if (my $exception = $@) { + $exception =~ s/(.*) at .*/$1/; + return $exception; + } + + my ($memb) = $member =~ m/^([^\[.]+)/; + + if (defined $memb && length $memb) { + $h = eval { + return $h->{$memb}; + }; + + if (my $exception = $@) { + $exception =~ s/(.*) at .*/$1/; + return $exception; + } + } + + my $result = eval { + while ($member =~ m/ + (?: + \['(?(?:[^'\\]|\\.)*)'\] + | \["(?(?:[^"\\]|\\.)*)"\] + | \[(?[^\]]+)\] + | \.'(?(?:[^'\\]|\\.)*)' + | \."(?(?:[^"\\]|\\.)*)" + | \.(?[^\[\.]+) + | (?.) + ) + /gx) + { + if (defined $+{invalid}) { + return "Unexpected $+{invalid} at position $-[0]"; + } + + if (defined $+{index}) { + my $index = $+{index}; + if ($index !~ /^\d+$/) { + return "Invalid index $index at position " . ($-[0] + 1); + } + $h = $h->[$index]; + } + + if (defined $+{key}) { + my $key = $+{key}; + $key =~ s/(?{$key}; + } + + if (not defined $h) { + return 'null'; + } + } + }; + + if (my $exception = $@) { + $exception =~ s/(.*) at .*/$1/; + return $exception; + } + + if (defined $result && length $result) { + return $result; + } + + if (not defined $h) { + return 'null'; + } + + if (ref $h eq 'HASH' || ref $h eq 'ARRAY') { + my $encoder = JSON::XS->new; + return $encoder->space_after->encode($h); + } + + return $h; +} + 1; diff --git a/lib/PBot/VERSION.pm b/lib/PBot/VERSION.pm index efed5d3c..72124671 100644 --- a/lib/PBot/VERSION.pm +++ b/lib/PBot/VERSION.pm @@ -25,8 +25,8 @@ use PBot::Imports; # These are set by the /misc/update_version script use constant { BUILD_NAME => "PBot", - BUILD_REVISION => 4911, - BUILD_DATE => "2025-10-19", + BUILD_REVISION => 4913, + BUILD_DATE => "2025-10-21", }; sub initialize {}