Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package perl-Mojolicious for 
openSUSE:Factory checked in at 2026-05-13 17:21:28
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/perl-Mojolicious (Old)
 and      /work/SRC/openSUSE:Factory/.perl-Mojolicious.new.1966 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "perl-Mojolicious"

Wed May 13 17:21:28 2026 rev:183 rq:1352905 version:9.450.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/perl-Mojolicious/perl-Mojolicious.changes        
2025-10-10 17:13:28.651666682 +0200
+++ 
/work/SRC/openSUSE:Factory/.perl-Mojolicious.new.1966/perl-Mojolicious.changes  
    2026-05-13 17:23:19.221201375 +0200
@@ -1,0 +2,18 @@
+Wed May  6 07:47:09 UTC 2026 - Tina Müller <[email protected]>
+
+- updated to 9.450.0 (9.45)
+   see /usr/share/doc/packages/perl-Mojolicious/Changes
+
+  9.45  2026-05-05
+    - Fixed portability issue in WebSocket tests.
+
+  9.44  2026-05-05
+    - Fixed various spec compliance issues in Mojo::DOM.
+    - Fixed permessage-deflate support in Mojo::Transaction::WebSocket to be 
more interoperable with non-spec compliant
+      implementations.
+
+  9.43  2026-05-04
+    - Fixed punycode roundtrip bug in Mojo::Util.
+    - Fixed Windows compatibility issues of Mojo::File::list_tree.
+
+-------------------------------------------------------------------

Old:
----
  Mojolicious-9.42.tar.gz

New:
----
  Mojolicious-9.45.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ perl-Mojolicious.spec ++++++
--- /var/tmp/diff_new_pack.w1XIkd/_old  2026-05-13 17:23:20.093237570 +0200
+++ /var/tmp/diff_new_pack.w1XIkd/_new  2026-05-13 17:23:20.097237737 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package perl-Mojolicious
 #
-# Copyright (c) 2025 SUSE LLC and contributors
+# Copyright (c) 2026 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,10 +18,10 @@
 
 %define cpan_name Mojolicious
 Name:           perl-Mojolicious
-Version:        9.420.0
+Version:        9.450.0
 Release:        0
-# 9.42 -> normalize -> 9.420.0
-%define cpan_version 9.42
+# 9.45 -> normalize -> 9.450.0
+%define cpan_version 9.45
 License:        Artistic-2.0
 Summary:        Real-time web framework
 URL:            https://metacpan.org/release/%{cpan_name}

++++++ Mojolicious-9.42.tar.gz -> Mojolicious-9.45.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-9.42/Changes new/Mojolicious-9.45/Changes
--- old/Mojolicious-9.42/Changes        2025-10-01 16:40:36.000000000 +0200
+++ new/Mojolicious-9.45/Changes        2026-05-05 20:30:05.000000000 +0200
@@ -1,4 +1,16 @@
 
+9.45  2026-05-05
+  - Fixed portability issue in WebSocket tests.
+
+9.44  2026-05-05
+  - Fixed various spec compliance issues in Mojo::DOM.
+  - Fixed permessage-deflate support in Mojo::Transaction::WebSocket to be 
more interoperable with non-spec compliant
+    implementations.
+
+9.43  2026-05-04
+  - Fixed punycode roundtrip bug in Mojo::Util.
+  - Fixed Windows compatibility issues of Mojo::File::list_tree.
+
 9.42  2025-10-01
   - Un-deprecated the spurt method in Mojo::File, it is now an alternative to 
spew.
   - Removed experimental status from top-level await support in Mojo::Promise.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-9.42/META.json 
new/Mojolicious-9.45/META.json
--- old/Mojolicious-9.42/META.json      2025-10-01 16:46:10.000000000 +0200
+++ new/Mojolicious-9.45/META.json      2026-05-05 20:33:03.000000000 +0200
@@ -52,7 +52,7 @@
       },
       "homepage" : "https://mojolicious.org";,
       "license" : [
-         "http://www.opensource.org/licenses/artistic-license-2.0";
+         "https://opensource.org/license/artistic-2-0";
       ],
       "repository" : {
          "type" : "git",
@@ -64,6 +64,6 @@
          "web" : "https://web.libera.chat/#mojo";
       }
    },
-   "version" : "9.42",
+   "version" : "9.45",
    "x_serialization_backend" : "JSON::PP version 4.16"
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-9.42/META.yml 
new/Mojolicious-9.45/META.yml
--- old/Mojolicious-9.42/META.yml       2025-10-01 16:46:10.000000000 +0200
+++ new/Mojolicious-9.45/META.yml       2026-05-05 20:33:03.000000000 +0200
@@ -33,7 +33,7 @@
     web: https://web.libera.chat/#mojo
   bugtracker: https://github.com/mojolicious/mojo/issues
   homepage: https://mojolicious.org
-  license: http://www.opensource.org/licenses/artistic-license-2.0
+  license: https://opensource.org/license/artistic-2-0
   repository: https://github.com/mojolicious/mojo.git
-version: '9.42'
+version: '9.45'
 x_serialization_backend: 'CPAN::Meta::YAML version 0.020'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-9.42/Makefile.PL 
new/Mojolicious-9.45/Makefile.PL
--- old/Mojolicious-9.42/Makefile.PL    2022-06-14 13:31:51.000000000 +0200
+++ new/Mojolicious-9.45/Makefile.PL    2026-02-12 12:07:38.000000000 +0100
@@ -22,7 +22,7 @@
     resources => {
       bugtracker => {web => 'https://github.com/mojolicious/mojo/issues'},
       homepage   => 'https://mojolicious.org',
-      license    => 
['http://www.opensource.org/licenses/artistic-license-2.0'],
+      license    => ['https://opensource.org/license/artistic-2-0'],
       repository => {
         type => 'git',
         url  => 'https://github.com/mojolicious/mojo.git',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-9.42/lib/Mojo/DOM/CSS.pm 
new/Mojolicious-9.45/lib/Mojo/DOM/CSS.pm
--- old/Mojolicious-9.42/lib/Mojo/DOM/CSS.pm    2023-03-08 19:43:29.000000000 
+0100
+++ new/Mojolicious-9.45/lib/Mojo/DOM/CSS.pm    2026-05-05 18:08:48.000000000 
+0200
@@ -22,7 +22,8 @@
 
 sub matches {
   my $tree = shift->tree;
-  return $tree->[0] ne 'tag' ? undef : _match(_compile(@_), $tree, $tree, 
_root($tree));
+  return undef if $tree->[0] ne 'tag';
+  return _match(_compile(@_), $tree, $tree, _root($tree));
 }
 
 sub select     { _select(0, shift->tree, _compile(@_)) }
@@ -30,16 +31,18 @@
 
 sub _absolutize { [map { _is_scoped($_) ? $_ : [[['pc', 'scope']], ' ', @$_] } 
@{shift()}] }
 
-sub _ancestor {
-  my ($selectors, $current, $tree, $scope, $one, $pos) = @_;
+sub _all_tags {
+  my $tree = shift;
 
-  while ($current ne $scope && $current->[0] ne 'root' && ($current = 
$current->[3])) {
-    return 1     if _combinator($selectors, $current, $tree, $scope, $pos);
-    return undef if $current eq $scope;
-    last         if $one;
+  my @tags;
+  my @queue = @$tree[($tree->[0] eq 'root' ? 1 : 4) .. $#$tree];
+  while (my $current = shift @queue) {
+    next unless $current->[0] eq 'tag';
+    push @tags, $current;
+    unshift @queue, @$current[4 .. $#$current];
   }
 
-  return undef;
+  return \@tags;
 }
 
 sub _attr {
@@ -55,29 +58,6 @@
   return undef;
 }
 
-sub _combinator {
-  my ($selectors, $current, $tree, $scope, $pos) = @_;
-
-  # Selector
-  return undef unless my $c = $selectors->[$pos];
-  if (ref $c) {
-    return undef unless _selector($c, $current, $tree, $scope);
-    return 1 unless $c = $selectors->[++$pos];
-  }
-
-  # ">" (parent only)
-  return _ancestor($selectors, $current, $tree, $scope, 1, ++$pos) if $c eq 
'>';
-
-  # "~" (preceding siblings)
-  return _sibling($selectors, $current, $tree, $scope, 0, ++$pos) if $c eq '~';
-
-  # "+" (immediately preceding siblings)
-  return _sibling($selectors, $current, $tree, $scope, 1, ++$pos) if $c eq '+';
-
-  # " " (ancestor)
-  return _ancestor($selectors, $current, $tree, $scope, 0, ++$pos);
-}
-
 sub _compile {
   my ($css, %ns) = (trim('' . shift), @_);
 
@@ -90,13 +70,19 @@
     if ($css =~ /\G\s*,\s*/gc) { push @$group, [] }
 
     # Combinator
-    elsif ($css =~ /\G\s*([ >+~])\s*/gc) {
+    elsif ($css =~ /\G\s*([>+~])\s*/gc) {
       push @$last,      ['pc', 'scope'] unless @$last;
       push @$selectors, $1;
     }
 
+    # Descendant combinator
+    elsif ($css =~ /\G\s+/gc) {
+      push @$last,      ['pc', 'scope'] unless @$last;
+      push @$selectors, ' ';
+    }
+
     # Class or ID
-    elsif ($css =~ /\G([.#])((?:$ESCAPE_RE\s|\\.|[^,.#:[ >~+])+)/gco) {
+    elsif ($css =~ /\G([.#])((?:$ESCAPE_RE\s?|[^,.#:[\s>~+])+)/gco) {
       my ($name, $op) = $1 eq '.' ? ('class', '~') : ('id', '');
       push @$last, ['attr', _name($name), _value($op, $2)];
     }
@@ -124,7 +110,7 @@
     }
 
     # Tag
-    elsif ($css =~ /\G((?:$ESCAPE_RE\s|\\.|[^,.#:[ >~+])+)/gco) {
+    elsif ($css =~ /\G((?:$ESCAPE_RE\s|\\[\s\S]|[^,.#:[\s>~+])+)/gco) {
       my $alias = (my $name = $1) =~ s/^([^|]*)\|// && $1 ne '*' ? $1          
                        : undef;
       my $ns    = length $alias                                  ? $ns{$alias} 
// return [['invalid']] : $alias;
       push @$last, ['tag', $name eq '*' ? undef : _name($name), 
_unescape($ns)];
@@ -154,6 +140,42 @@
   return [$1 eq '-' ? -1 : !length $1 ? 1 : $1, join('', split(' ', $2 // 0))];
 }
 
+sub _evaluate {
+  my ($group, $tree, $scope, $pool) = @_;
+
+  my (@results, %seen);
+  push @results, grep { !$seen{$_}++ } _evaluate_one($_, $tree, $scope, $pool) 
for @$group;
+
+  return \@results;
+}
+
+sub _evaluate_one {
+  my ($selector, $tree, $scope, $pool) = @_;
+
+  # Match the leftmost compound, then propagate forward through combinators
+  my @parts    = @$selector;
+  my $compound = shift @parts;
+  return () unless ref $compound;
+  my @candidates = grep { _selector($compound, $_, $tree, $scope) } @$pool;
+
+  while (@parts) {
+    my $combinator = shift @parts;
+    my $next       = shift @parts;
+    return () unless ref $next;
+
+    my (%seen, @new);
+    for my $node (@candidates) {
+      for my $cand (_step_forward($combinator, $node)) {
+        next if $seen{$cand}++;
+        push @new, $cand if _selector($next, $cand, $tree, $scope);
+      }
+    }
+    @candidates = @new;
+  }
+
+  return @candidates;
+}
+
 sub _is_scoped {
   my $selector = shift;
 
@@ -171,10 +193,38 @@
 
 sub _match {
   my ($group, $current, $tree, $scope) = @_;
-  _combinator([reverse @$_], $current, $tree, $scope, 0) and return 1 for 
@$group;
+  _match_one($_, $current, $tree, $scope) and return 1 for @$group;
   return undef;
 }
 
+sub _match_one {
+  my ($selector, $current, $tree, $scope) = @_;
+
+  # Match the rightmost compound, then propagate backward through combinators
+  my @parts    = reverse @$selector;
+  my $compound = shift @parts;
+  return undef unless ref $compound && _selector($compound, $current, $tree, 
$scope);
+
+  my @candidates = ($current);
+  while (@parts) {
+    my $combinator = shift @parts;
+    my $next       = shift @parts;
+    return undef unless ref $next;
+
+    my (%seen, @new);
+    for my $node (@candidates) {
+      for my $cand (_step_back($combinator, $node, $scope)) {
+        next if $seen{$cand}++;
+        push @new, $cand if _selector($next, $cand, $tree, $scope);
+      }
+    }
+    return undef unless @new;
+    @candidates = @new;
+  }
+
+  return 1;
+}
+
 sub _name {qr/(?:^|:)\Q@{[_unescape(shift)]}\E$/}
 
 sub _namespace {
@@ -267,14 +317,15 @@
   my $tree = $scope;
   ($group, $tree) = (_absolutize($group), _root($scope)) if grep { 
_is_scoped($_) } @$group;
 
-  my @results;
-  my @queue = @$tree[($tree->[0] eq 'root' ? 1 : 4) .. $#$tree];
-  while (my $current = shift @queue) {
-    next unless $current->[0] eq 'tag';
+  # Pool includes $tree so ":scope" can match it, but results exclude it
+  my $tags  = _all_tags($tree);
+  my %match = map { $_ => 1 } @{_evaluate($group, $tree, $scope, [$tree, 
@$tags])};
 
-    unshift @queue, @$current[4 .. $#$current];
-    next unless _match($group, $current, $tree, $scope);
-    $one ? return $current : push @results, $current;
+  my @results;
+  for my $node (@$tags) {
+    next unless $match{$node};
+    return $node if $one;
+    push @results, $node;
   }
 
   return $one ? undef : \@results;
@@ -307,31 +358,54 @@
   return 1;
 }
 
-sub _sibling {
-  my ($selectors, $current, $tree, $scope, $immediate, $pos) = @_;
-
-  my $found;
-  for my $sibling (@{_siblings($current)}) {
-    return $found if $sibling eq $current;
+sub _siblings {
+  my ($current, $type) = @_;
+  my $parent   = $current->[3];
+  my @siblings = grep { $_->[0] eq 'tag' } @$parent[($parent->[0] eq 'root' ? 
1 : 4) .. $#$parent];
+  @siblings = grep { $type eq $_->[1] } @siblings if defined $type;
+  return \@siblings;
+}
 
-    # "+" (immediately preceding sibling)
-    if ($immediate) { $found = _combinator($selectors, $sibling, $tree, 
$scope, $pos) }
+sub _step_back {
+  my ($combinator, $node, $scope) = @_;
 
-    # "~" (preceding sibling)
-    else { return 1 if _combinator($selectors, $sibling, $tree, $scope, $pos) }
+  # " " (ancestors) and ">" (parent only)
+  if ($combinator eq ' ' || $combinator eq '>') {
+    my @ancestors;
+    while ($node ne $scope && $node->[0] ne 'root' && ($node = $node->[3])) {
+      push @ancestors, $node;
+      last if $combinator eq '>' || $node eq $scope;
+    }
+    return @ancestors;
   }
 
-  return undef;
+  # "~" (preceding siblings) and "+" (immediately preceding)
+  return () if $node->[0] eq 'root';
+  my @prev;
+  for my $sib (@{_siblings($node)}) {
+    last if $sib eq $node;
+    push @prev, $sib;
+  }
+  return $combinator eq '+' ? ($prev[-1] || ()) : @prev;
 }
 
-sub _siblings {
-  my ($current, $type) = @_;
+sub _step_forward {
+  my ($combinator, $node) = @_;
 
-  my $parent   = $current->[3];
-  my @siblings = grep { $_->[0] eq 'tag' } @$parent[($parent->[0] eq 'root' ? 
1 : 4) .. $#$parent];
-  @siblings = grep { $type eq $_->[1] } @siblings if defined $type;
+  # " " (descendants)
+  return @{_all_tags($node)} if $combinator eq ' ';
 
-  return \@siblings;
+  # ">" (children only)
+  return grep { $_->[0] eq 'tag' } @$node[($node->[0] eq 'root' ? 1 : 4) .. 
$#$node] if $combinator eq '>';
+
+  # "~" (following siblings) and "+" (immediately following)
+  return () if $node->[0] eq 'root';
+  my (@next, $found);
+  for my $sib (@{_siblings($node)}) {
+    push @next, $sib if $found;
+    $found = 1 if $sib eq $node;
+  }
+  return $combinator eq '+' ? ($next[0] || ()) : @next;
 }
 
 sub _unescape {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-9.42/lib/Mojo/DOM/HTML.pm 
new/Mojolicious-9.45/lib/Mojo/DOM/HTML.pm
--- old/Mojolicious-9.42/lib/Mojo/DOM/HTML.pm   2023-03-08 19:43:29.000000000 
+0100
+++ new/Mojolicious-9.45/lib/Mojo/DOM/HTML.pm   2026-05-05 17:48:04.000000000 
+0200
@@ -29,14 +29,14 @@
         (?:\s+\[.+?\])?                                                        
# Int Subset
         \s*)
       |
-        --(.*?)--\s*                                                           
# Comment
+        --(.*?)(?:--!?|(?<=<!--)-?(?=>))                                      
# Comment
       |
         \[CDATA\[(.*?)\]\]                                                     
# CDATA
       )
     |
       \?(.*?)\?                                                                
# Processing Instruction
     |
-      \s*((?:\/\s*)?[^<>\s\/0-9.\-][^<>\s\/]*\s*(?:(?:$ATTR_RE){0,32766})*+)   
# Tag
+      ((?:\/\s*)?[^<>\s\/0-9.\-][^<>\s\/]*\s*(?:(?:$ATTR_RE){0,32766})*+)      
# Tag
     )>
   |
     (<)                                                                        
# Runaway "<"
@@ -144,6 +144,14 @@
 
         # Raw text elements
         next if $xml || !$RAW{$start} && !$RCDATA{$start};
+
+        if ($start eq 'script') {
+          my ($script, $found_end) = _script_content(\$html);
+          _node($current, 'raw', $script) if length $script;
+          _end($start, 0, \$current)      if $found_end;
+          next;
+        }
+
         next unless $html =~ m!\G(.*?)</\Q$start\E(?:\s+|\s*>)!gcsi;
         _node($current, 'raw', $RCDATA{$start} ? html_unescape $1 : $1);
         _end($start, 0, \$current);
@@ -257,6 +265,38 @@
   return '';
 }
 
+sub _script_content {
+  my $html  = shift;
+  my $start = pos $$html;
+
+  my $state = 0;
+
+  while (1) {
+    if   ($state == 0) { $$html =~ /\G[^<]*/gcs }
+    else               { $$html =~ /\G[^<\-]*/gcs }
+
+    my $p = pos $$html;
+    return (substr($$html, $start), 0) if $p >= length $$html;
+
+    if ($state == 0) {
+      if    ($$html =~ m!\G</script(?:\s+|\s*>)!gcsi) { return (substr($$html, 
$start, $p - $start), 1) }
+      elsif ($$html =~ /\G<!--/gcs)                   { $state = 1 }
+      else                                            { pos($$html) = $p + 1 }
+    }
+    elsif ($state == 1) {
+      if    ($$html =~ m!\G</script(?:\s+|\s*>)!gcsi) { return (substr($$html, 
$start, $p - $start), 1) }
+      elsif ($$html =~ /\G-->/gcs)                    { $state = 0 }
+      elsif ($$html =~ m!\G<script(?=[\s/>])!gcsi)    { $state = 2 }
+      else                                            { pos($$html) = $p + 1 }
+    }
+    else {
+      if    ($$html =~ m!\G</script(?:\s+|\s*>)!gcsi) { $state      = 1 }
+      elsif ($$html =~ /\G-->/gcs)                    { $state      = 0 }
+      else                                            { pos($$html) = $p + 1 }
+    }
+  }
+}
+
 sub _start {
   my ($start, $attrs, $xml, $current) = @_;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-9.42/lib/Mojo/File.pm 
new/Mojolicious-9.45/lib/Mojo/File.pm
--- old/Mojolicious-9.42/lib/Mojo/File.pm       2025-10-01 16:30:21.000000000 
+0200
+++ new/Mojolicious-9.45/lib/Mojo/File.pm       2026-05-04 17:29:38.000000000 
+0200
@@ -7,7 +7,6 @@
 use Exporter              qw(import);
 use File::Basename        ();
 use File::Copy            qw(copy move);
-use File::Find            qw(find);
 use File::Path            ();
 use File::Spec::Functions qw(abs2rel canonpath catfile file_name_is_absolute 
rel2abs splitdir);
 use File::stat            ();
@@ -65,25 +64,24 @@
 
 sub list_tree {
   my ($self, $options) = (shift, shift // {});
+  return Mojo::Collection->new unless -d $$self;
 
-  # This may break in the future, but is worth it for performance
-  local $File::Find::skip_pattern = qr/^\./ unless $options->{hidden};
-
-  # The File::Find documentation lies, this is needed for CIFS
-  local $File::Find::dont_use_nlink = 1 if $options->{dont_use_nlink};
-
-  my %all;
-  my $wanted = sub {
-    if ($options->{max_depth}) {
-      (my $rel = $File::Find::name) =~ s!^\Q$$self\E/?!!;
-      $File::Find::prune = 1 if splitdir($rel) >= $options->{max_depth};
+  my (@results, $walk);
+  $walk = sub {
+    my ($path, $depth) = @_;
+    opendir my $dh, $path or return;
+    my @names = sort grep { $_ ne '.' && $_ ne '..' } readdir $dh;
+    @names = grep { !/^\./ } @names unless $options->{hidden};
+    for my $name (@names) {
+      my $child  = $self->new($path, $name);
+      my $is_dir = -d $$child;
+      push @results, $child if $options->{dir} || !$is_dir;
+      $walk->($$child, $depth + 1) if $is_dir && (!$options->{max_depth} || 
$depth + 1 < $options->{max_depth});
     }
-    $all{$File::Find::name}++ if $options->{dir} || !-d $File::Find::name;
   };
-  find {wanted => $wanted, no_chdir => 1}, $$self if -d $$self;
-  delete $all{$$self};
+  $walk->($$self, 0);
 
-  return Mojo::Collection->new(map { $self->new(canonpath $_) } sort keys 
%all);
+  return Mojo::Collection->new(@results);
 }
 
 sub lstat { File::stat::lstat(${shift()}) }
@@ -395,12 +393,6 @@
 
 Include directories.
 
-=item dont_use_nlink
-
-  dont_use_nlink => 1
-
-Force L<File::Find> to always stat directories.
-
 =item hidden
 
   hidden => 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-9.42/lib/Mojo/Transaction/WebSocket.pm 
new/Mojolicious-9.45/lib/Mojo/Transaction/WebSocket.pm
--- old/Mojolicious-9.42/lib/Mojo/Transaction/WebSocket.pm      2023-03-08 
19:43:30.000000000 +0100
+++ new/Mojolicious-9.45/lib/Mojo/Transaction/WebSocket.pm      2026-05-05 
17:48:04.000000000 +0200
@@ -29,6 +29,7 @@
     ||= Compress::Raw::Zlib::Deflate->new(AppendOutput => 1, MemLevel => 8, 
WindowBits => -15);
   $deflate->deflate($frame->[5], my $out);
   $deflate->flush($out, Z_SYNC_FLUSH);
+  $deflate->deflateReset;
   @$frame[1, 5] = (1, substr($out, 0, length($out) - 4));
 
   return $frame;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-9.42/lib/Mojo/Util.pm 
new/Mojolicious-9.45/lib/Mojo/Util.pm
--- old/Mojolicious-9.42/lib/Mojo/Util.pm       2025-10-01 16:38:12.000000000 
+0200
+++ new/Mojolicious-9.45/lib/Mojo/Util.pm       2026-02-12 12:07:38.000000000 
+0100
@@ -303,7 +303,7 @@
   my $h = my $basic = length $output;
   $output .= "\x2d" if $basic > 0;
 
-  for my $m (sort grep { $_ >= PC_INITIAL_N } @input) {
+  for my $m (sort { $a <=> $b } grep { $_ >= PC_INITIAL_N } @input) {
     next if $m < $n;
     $delta += ($m - $n) * ($h + 1);
     $n = $m;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-9.42/lib/Mojolicious.pm 
new/Mojolicious-9.45/lib/Mojolicious.pm
--- old/Mojolicious-9.42/lib/Mojolicious.pm     2025-10-01 16:41:31.000000000 
+0200
+++ new/Mojolicious-9.45/lib/Mojolicious.pm     2026-05-05 20:09:38.000000000 
+0200
@@ -57,7 +57,7 @@
 has validator => sub { Mojolicious::Validator->new };
 
 our $CODENAME = 'Waffle';
-our $VERSION  = '9.42';
+our $VERSION  = '9.45';
 
 sub BUILD_DYNAMIC {
   my ($class, $method, $dyn_methods) = @_;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-9.42/t/mojo/dom.t 
new/Mojolicious-9.45/t/mojo/dom.t
--- old/Mojolicious-9.42/t/mojo/dom.t   2023-03-08 19:43:33.000000000 +0100
+++ new/Mojolicious-9.45/t/mojo/dom.t   2026-05-05 18:10:15.000000000 +0200
@@ -327,6 +327,20 @@
   is $dom->at('script')->text, "alert('lalala');", 'right script content';
 };
 
+subtest 'Script tag with HTML comment containing nested script tags' => sub {
+  my $dom = Mojo::DOM->new(q{<script> console.log("<!--"); </script>});
+  is $dom->at('script')->text, ' console.log("<!--"); ', 'right script 
content';
+
+  $dom = Mojo::DOM->new(q{<script> console.log("<!-- <script> -->"); 
</script>});
+  is $dom->at('script')->text, ' console.log("<!-- <script> -->"); ', 'right 
script content';
+
+  $dom = Mojo::DOM->new(q{<script> console.log("<!-- <script> </script>"); 
</script>});
+  is $dom->at('script')->text, ' console.log("<!-- <script> </script>"); ', 
'right script content';
+
+  $dom = Mojo::DOM->new(q{<script> console.log("<!-- <script> </script> -->"); 
</script>});
+  is $dom->at('script')->text, ' console.log("<!-- <script> </script> -->"); 
', 'right script content';
+};
+
 subtest 'HTML5 (unquoted values)' => sub {
   my $dom = Mojo::DOM->new('<div id = test foo ="bar" class=tset bar=/baz/ 
value baz=//>works</div>');
   is $dom->at('#test')->text,                'works', 'right text';
@@ -1274,6 +1288,25 @@
   is $dom->at('#♥ ~ *:nth-last-child(2)')->text,      'F',   'right text';
 };
 
+subtest 'Whitespace as descendant combinator' => sub {
+  my $dom = Mojo::DOM->new("<ul> <li>Ax1</li> </ul>");
+  is $dom->at("ul li")->text,    'Ax1', 'space combinator';
+  is $dom->at("ul\tli")->text,   'Ax1', 'tab combinator';
+  is $dom->at("ul \tli")->text,  'Ax1', 'space + tab combinator';
+  is $dom->at("ul\t li")->text,  'Ax1', 'tab + space combinator';
+  is $dom->at("ul\t\tli")->text, 'Ax1', 'multiple tab combinator';
+  is $dom->at("ul\nli")->text,   'Ax1', 'newline combinator';
+  is $dom->at("ul\rli")->text,   'Ax1', 'carriage return combinator';
+  is $dom->at("ul\fli")->text,   'Ax1', 'form feed combinator';
+
+  my $multi = Mojo::DOM->new("<ul><li>A</li><li>B</li></ul>");
+  is_deeply $multi->find("ul\tli")->map('text')->to_array, ['A', 'B'], 'find 
with tab combinator';
+
+  my $child = Mojo::DOM->new("<ul><li>Ax1</li></ul>");
+  is $child->at("ul\t>\tli")->text, 'Ax1', 'tabs around child combinator';
+  is $child->at("ul\n>\nli")->text, 'Ax1', 'newlines around child combinator';
+};
+
 subtest 'Scoped selectors' => sub {
   my $dom = Mojo::DOM->new(<<EOF);
 <p>Zero</p>
@@ -1775,14 +1808,12 @@
         alert('<123>');
       }
     </script>
-    < sCriPt two="23" >if (b > c) { alert('&<ohoh>') }</scRiPt  >
   <body>Foo!</body>
 EOF
   is $dom->find('html > body')->[0]->text,         'Foo!',                     
        'right text';
   is $dom->find('html > head > style')->[0]->text, "#style { foo: 
style('<test>'); }", 'right text';
   is $dom->find('html > head > script')->[0]->text, "\n      if (a < b) {\n    
    alert('<123>');\n      }\n    ",
     'right text';
-  is $dom->find('html > head > script')->[1]->text, "if (b > c) { 
alert('&<ohoh>') }", 'right text';
 };
 
 subtest 'More real world JavaScript' => sub {
@@ -1819,12 +1850,11 @@
   <body>Bar</body>
 </html>
 EOF
-  is $dom->at('title')->text,                              'Foo',          
'right text';
-  is $dom->find('html > head > script')->[0]->attr('src'), '/js/one.js',   
'right attribute';
-  is $dom->find('html > head > script')->[1]->attr('src'), '/js/two.js',   
'right attribute';
-  is $dom->find('html > head > script')->[2]->attr('src'), '/js/three.js', 
'right attribute';
-  is $dom->find('html > head > script')->[2]->text,        "\n  ",         'no 
text';
-  is $dom->at('html > body')->text,                        'Bar',          
'right text';
+  is $dom->at('title')->text,                              'Foo',              
                   'right text';
+  is $dom->find('html > head > script')->[0]->attr('src'), '/js/one.js',       
                   'right attribute';
+  is $dom->find('html > head > script')->[1]->attr('src'), '/js/two.js',       
                   'right attribute';
+  is $dom->find('html > head > script')->[2]->attr('src'), '/js/three.js',     
                   'right attribute';
+  is $dom->find('html > head > script')->[2]->text, "\n  </head>\n  
<body>Bar</body>\n</html>\n", 'raw content to EOF';
 };
 
 subtest 'Inline DTD' => sub {
@@ -2567,10 +2597,9 @@
 
 subtest 'Extra whitespace' => sub {
   my $dom = Mojo::DOM->new('< span>a< /span><b >b</b><span >c</ span>');
-  is $dom->at('span')->text,     'a',                                    
'right text';
-  is $dom->at('span + b')->text, 'b',                                    
'right text';
-  is $dom->at('b + span')->text, 'c',                                    
'right text';
-  is "$dom",                     '<span>a</span><b>b</b><span>c</span>', 
'right result';
+  is $dom->at('b')->text,        'b',                                          
        'right text';
+  is $dom->at('b + span')->text, 'c',                                          
        'right text';
+  is "$dom",                     '&lt; span&gt;a&lt; 
/span&gt;<b>b</b><span>c</span>', 'right result';
 };
 
 subtest 'Selectors with leading and trailing whitespace' => sub {
@@ -2592,8 +2621,8 @@
 
 subtest 'Not self-closing' => sub {
   my $dom = Mojo::DOM->new('<div />< div ><pre />test</div >123');
-  is $dom->at('div > div > pre')->text, 'test',                                
     'right text';
-  is "$dom",                            
'<div><div><pre>test</pre></div>123</div>', 'right result';
+  is $dom->at('div > pre')->text, 'test',                                      
 'right text';
+  is "$dom",                      '<div>&lt; div 
&gt;<pre>test</pre></div>123', 'right result';
   $dom = Mojo::DOM->new('<p /><svg><circle /><circle /></svg>');
   is $dom->find('p > svg > circle')->size, 2,                                  
                    'two circles';
   is "$dom",                               
'<p><svg><circle></circle><circle></circle></svg></p>', 'right result';
@@ -2640,13 +2669,26 @@
   my $dom = Mojo::DOM->new(<<EOF);
 <!-- HTML5 -->
 <!-- bad idea -- HTML5 -->
-<!-- HTML4 -- >
-<!-- bad idea -- HTML4 -- >
 EOF
   is $dom->tree->[1][1], ' HTML5 ',             'right comment';
   is $dom->tree->[3][1], ' bad idea -- HTML5 ', 'right comment';
-  is $dom->tree->[5][1], ' HTML4 ',             'right comment';
-  is $dom->tree->[7][1], ' bad idea -- HTML4 ', 'right comment';
+};
+
+subtest 'Comment is not terminated by "-- >"' => sub {
+  my $dom = Mojo::DOM->new('<!-- a > -- > b <blink>c</blink> -->');
+  is $dom->at('blink'),  undef,                           'blink element is 
inside comment';
+  is $dom->tree->[1][1], ' a > -- > b <blink>c</blink> ', 'right comment';
+};
+
+subtest 'Abrupt and bang-terminated comments' => sub {
+  my $dom = Mojo::DOM->new("<!DOCTYPE html>\n<!--> <p>OK</p> <!-- -->");
+  is $dom->at('p')->text, 'OK', 'abrupt empty comment closure';
+
+  $dom = Mojo::DOM->new("<!DOCTYPE html>\n<!---> <p>OK</p> <!-- -->");
+  is $dom->at('p')->text, 'OK', 'dash-terminated empty comment';
+
+  $dom = Mojo::DOM->new("<!DOCTYPE html>\n<!-- --!> <p>OK</p> <!-- -->");
+  is $dom->at('p')->text, 'OK', 'bang-terminated comment';
 };
 
 subtest 'Huge number of attributes' => sub {
@@ -3023,6 +3065,19 @@
   is $dom->at('.test')->text, 'works', 'right text';
 };
 
+subtest '"<" followed by space is not a tag opener' => sub {
+  my $dom = Mojo::DOM->new('if a < script then="<!--"> </script> 
<p>FAIL</p>-->');
+  is_deeply $dom->find('script, p')->map('to_string')->to_array, [], 'fragment 
contains no tags, just a comment';
+
+  $dom = Mojo::DOM->new('a < b');
+  is "$dom", 'a &lt; b', 'right result';
+  is_deeply $dom->find('*')->to_array, [], 'no elements';
+
+  $dom = Mojo::DOM->new('a < b <p>ok</p>');
+  is_deeply $dom->find('*')->map('tag')->to_array, ['p'], 'only one element';
+  is $dom->at('p')->text, 'ok', 'right text';
+};
+
 subtest 'XML name characters' => sub {
   my $dom = Mojo::DOM->new->xml(1)->parse('<Foo><1a>foo</1a></Foo>');
   is $dom->at('Foo')->text, '<1a>foo</1a>',                        'right 
text';
@@ -3092,6 +3147,20 @@
   like $dom->at('div')->text,    qr/^\s+$/s,                           'right 
text';
 };
 
+subtest 'Descendant combinator chain with non-matching selector' => sub {
+  my $dom = Mojo::DOM->new('<div> ' x 100 . '</div> ' x 100);
+  is_deeply $dom->find('#gobbledygook * * * *')->map(sub { $_->to_string 
})->to_array, [],
+    'non-existent elements have no descendants';
+  is $dom->at('#gobbledygook * * * *'), undef, 'no match';
+
+  is_deeply $dom->find('* * * * #gobbledygook')->map(sub { $_->to_string 
})->to_array, [],
+    'non-existent elements have no ancestors';
+  is $dom->at('* * * * #gobbledygook'), undef, 'no match';
+
+  my $exists = Mojo::DOM->new('<div 
id="x"><a><b><c><d>ok</d></c></b></a></div>');
+  is $exists->at('#x * * * *')->text, 'ok', 'matching id still resolves 
descendants';
+};
+
 subtest 'Unknown CSS selector' => sub {
   my $dom = 
Mojo::DOM->new('<html><head></head><body><div><div>x</div></div></body></html>');
   eval { $dom->at('div[') };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-9.42/t/mojo/ioloop_tls.t 
new/Mojolicious-9.45/t/mojo/ioloop_tls.t
--- old/Mojolicious-9.42/t/mojo/ioloop_tls.t    2023-03-08 19:43:33.000000000 
+0100
+++ new/Mojolicious-9.45/t/mojo/ioloop_tls.t    2026-02-12 12:07:38.000000000 
+0100
@@ -335,7 +335,7 @@
 is $client, 'connected', 'right result';
 ok !$client_err, 'no error';
 my $expect = $version eq 'TLSv1_3' ? 'TLS_AES_256_GCM_SHA384' : 'AES256-SHA';
-is $cipher, $expect, "$expect has been negotiatied";
+is $cipher, $expect, "$expect has been negotiated";
 
 # Ignore missing client certificate
 ($server, $client, $client_err) = ();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-9.42/t/mojo/tls.t 
new/Mojolicious-9.45/t/mojo/tls.t
--- old/Mojolicious-9.42/t/mojo/tls.t   2023-03-08 19:43:35.000000000 +0100
+++ new/Mojolicious-9.45/t/mojo/tls.t   2026-02-12 12:07:38.000000000 +0100
@@ -58,8 +58,8 @@
   is ref $client_result, 'IO::Socket::SSL', 'right class';
   is ref $server_result, 'IO::Socket::SSL', 'right class';
   my $expect = $server_result->get_sslversion eq 'TLSv1_3' ? 
'TLS_AES_256_GCM_SHA384' : 'AES256-SHA';
-  is $client_result->get_cipher, $expect, "$expect has been negotiatied";
-  is $server_result->get_cipher, $expect, "$expect has been negotiatied";
+  is $client_result->get_cipher, $expect, "$expect has been negotiated";
+  is $server_result->get_cipher, $expect, "$expect has been negotiated";
 };
 
 done_testing;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-9.42/t/mojo/user_agent_tls.t 
new/Mojolicious-9.45/t/mojo/user_agent_tls.t
--- old/Mojolicious-9.42/t/mojo/user_agent_tls.t        2023-03-08 
19:43:36.000000000 +0100
+++ new/Mojolicious-9.45/t/mojo/user_agent_tls.t        2026-02-12 
12:07:38.000000000 +0100
@@ -94,8 +94,8 @@
   $ua->cert('t/mojo/certs/bad.crt')->key('t/mojo/certs/bad.key');
   $tx = $ua->get("https://127.0.0.1:$port";);
   ok !$tx->error, 'no error';
-  is $ua->ioloop->stream($tx->connection)->handle->get_cipher,     
'AES256-SHA', 'AES256-SHA has been negotiatied';
-  is $ua->ioloop->stream($tx->connection)->handle->get_sslversion, 'TLSv1',    
  'TLSv1 has been negotiatied';
+  is $ua->ioloop->stream($tx->connection)->handle->get_cipher,     
'AES256-SHA', 'AES256-SHA has been negotiated';
+  is $ua->ioloop->stream($tx->connection)->handle->get_sslversion, 'TLSv1',    
  'TLSv1 has been negotiated';
 };
 
 subtest 'Client side TLS options' => sub {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-9.42/t/mojo/util.t 
new/Mojolicious-9.45/t/mojo/util.t
--- old/Mojolicious-9.42/t/mojo/util.t  2024-11-22 12:13:40.000000000 +0100
+++ new/Mojolicious-9.45/t/mojo/util.t  2026-02-12 12:07:38.000000000 +0100
@@ -289,6 +289,11 @@
   is punycode_decode('bcher-kva'), 'bücher', 'right punycode decoded result';
 };
 
+subtest 'punycode_decode/punycode_encode roundtrip' => sub {
+  is punycode_decode(punycode_encode('☃⭐️ ')), '☃⭐️ ', 'right punycode 
roundtrip result';
+  is punycode_decode(punycode_encode('🐳')),    '🐳',    'right punycode 
roundtrip result';
+};
+
 subtest 'RFC 3492' => sub {
   my @tests = (
     '(A) Arabic (Egyptian):',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-9.42/t/mojo/websocket_frames.t 
new/Mojolicious-9.45/t/mojo/websocket_frames.t
--- old/Mojolicious-9.42/t/mojo/websocket_frames.t      2025-07-03 
14:03:09.000000000 +0200
+++ new/Mojolicious-9.45/t/mojo/websocket_frames.t      2026-05-05 
20:29:16.000000000 +0200
@@ -1,6 +1,7 @@
 use Mojo::Base -strict;
 
 use Test::More;
+use Compress::Raw::Zlib;
 use Mojo::Transaction::WebSocket;
 use Mojo::WebSocket qw(WS_BINARY WS_CLOSE WS_CONTINUATION WS_PING WS_PONG 
WS_TEXT), qw(build_frame parse_frame);
 
@@ -268,9 +269,6 @@
   is $frame->[3], 0,         'rsv3 flag is not set';
   is $frame->[4], WS_BINARY, 'binary frame';
   ok $frame->[5], 'has payload';
-  my $payload = $compressed->build_message({binary => 'just works'})->[5];
-  isnt $frame->[5], $payload, 'different payload';
-  ok length $frame->[5] > length $payload, 'payload is smaller';
   my $uncompressed = Mojo::Transaction::WebSocket->new;
   my $frame2       = $uncompressed->build_message({binary => 'just works'});
   is $frame2->[0], 1,         'fin flag is set';
@@ -297,4 +295,34 @@
   is $text, 'just works', 'decoded correctly';
 };
 
+subtest 'Compressed messages are independently decodable per message' => sub {
+  my $tx       = Mojo::Transaction::WebSocket->new({compressed => 1});
+  my @payloads = map {qq[{"action":"heartbeat","client_ts":$_}]} 1 .. 3;
+
+  for my $i (0 .. $#payloads) {
+    my $frame = $tx->build_message({text => $payloads[$i]});
+
+    my $inflate = Compress::Raw::Zlib::Inflate->new(WindowBits => -15, 
LimitOutput => 1, Bufsize => 65536);
+    my $data    = $frame->[5] . "\x00\x00\xff\xff";
+    my $status  = $inflate->inflate($data, my $out);
+
+    cmp_ok $status, '==', Z_OK, "message @{[$i + 1]} inflates without error";
+    is length $data, 0,             "message @{[$i + 1]} fully consumed";
+    is $out,         $payloads[$i], "message @{[$i + 1]} round-trips";
+  }
+};
+
+subtest 'Compressed messages round-trip between two transactions' => sub {
+  my $sender = Mojo::Transaction::WebSocket->new({compressed => 1});
+  my $peer   = Mojo::Transaction::WebSocket->new({compressed => 1});
+
+  my @got;
+  $peer->on(message => sub { push @got, pop });
+
+  my @payloads = map {qq[{"action":"heartbeat","client_ts":$_}]} 1 .. 3;
+  $peer->parse_message($sender->build_message({text => $_})) for @payloads;
+
+  is_deeply \@got, \@payloads, 'all messages decoded';
+};
+
 done_testing();

++++++ _scmsync.obsinfo ++++++
--- /var/tmp/diff_new_pack.w1XIkd/_old  2026-05-13 17:23:20.781266129 +0200
+++ /var/tmp/diff_new_pack.w1XIkd/_new  2026-05-13 17:23:20.789266461 +0200
@@ -1,6 +1,6 @@
-mtime: 1760040066
-commit: 8c438d306d27aa758414e2190e55169dc3152bb54022f13e5c20ff2add1fd14f
-url: https://src.opensuse.org/perl/perl-Mojolicious.git
-revision: 8c438d306d27aa758414e2190e55169dc3152bb54022f13e5c20ff2add1fd14f
+mtime: 1778053630
+commit: 9cad6b445729b6947032c8fc69fe825d33858ae62150882fb10b468f6cc1e9ad
+url: https://src.opensuse.org/perl/perl-Mojolicious
+revision: 9cad6b445729b6947032c8fc69fe825d33858ae62150882fb10b468f6cc1e9ad
 projectscmsync: https://src.opensuse.org/perl/_ObsPrj
 

++++++ build.specials.obscpio ++++++

++++++ build.specials.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/.gitignore new/.gitignore
--- old/.gitignore      1970-01-01 01:00:00.000000000 +0100
+++ new/.gitignore      2026-05-06 09:47:10.000000000 +0200
@@ -0,0 +1 @@
+.osc

Reply via email to