script/htmx-usage
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env perl
# SPDX-FileCopyrightText: 2026 GPForum Contributors
# SPDX-License-Identifier: BSD-3-Clause
package main;
use v5.40;
use Carp qw(croak);
use Const::Fast;
use FindBin qw($RealBin);
use Mojo::DOM;
use Mojo::File qw(path);
use Mojo::JSON qw(encode_json);
our $VERSION = '0.001';
const my $PERCENT => 100;
# Static template declarations, not rendered instances or measured traffic.
# Do not execute EP: branches and loops are deliberately counted once each.
my $root = path($RealBin)->dirname;
my @rows = map { _template_row( $_, $root ) }
grep { /[.]ep\z/msx } sort $root->child('templates')->list_tree->each;
say encode_json( { counts => _counts( \@rows ), templates => \@rows } )
or croak 'cannot write htmx usage';
sub _template_row ( $file, $base ) {
my $source = $file->slurp;
$source =~ s{ <!-- .*? --> }{}gmsx;
$source =~ s{ ^ [\t ]* [%][#] [^\n]* }{}gmsx;
$source =~ s{ <% .*? %> }{TEMPLATE}gmsx;
$source =~ s{ ^ [\t ]* [%] [^\n]* }{}gmsx;
my $dom = Mojo::DOM->new($source);
my %row = (
file => $file->to_rel($base)->to_string,
forms => 0,
htmx_forms => 0,
request_elements => 0,
attributes => {},
);
for my $element ( $dom->find(q{*})->each ) {
my $attrs = $element->attr;
my $request = _is_request($attrs);
for my $name ( grep { /\A hx- /msx } keys %{$attrs} ) {
$row{attributes}{$name} = 1;
}
if ( $element->tag eq 'form' ) {
$row{forms}++;
if ($request) {
$row{htmx_forms}++;
}
}
if ($request) {
$row{request_elements}++;
}
}
$row{attributes} = [ sort keys %{ $row{attributes} } ];
return \%row;
}
sub _is_request ($attrs) {
if ( ( $attrs->{'hx-boost'} // q{} ) eq 'true' ) {
return 1;
}
return
scalar grep { /\A hx-(?:get|post|put|patch|delete|query|action) \z/msx }
keys %{$attrs};
}
sub _counts ($rows) {
my %counts = (
templates => scalar @{$rows},
interactive_templates => 0,
request_templates => 0,
htmx_templates => 0,
forms => 0,
htmx_forms => 0,
request_elements => 0,
);
for my $row ( @{$rows} ) {
for my $name (qw(forms htmx_forms request_elements)) {
$counts{$name} += $row->{$name};
}
if ( $row->{forms} || $row->{request_elements} ) {
$counts{interactive_templates}++;
}
if ( $row->{request_elements} ) {
$counts{request_templates}++;
}
if ( @{ $row->{attributes} } ) {
$counts{htmx_templates}++;
}
}
$counts{form_coverage_percent} =
$counts{forms}
? 0 + sprintf '%.2f', $PERCENT * $counts{htmx_forms} / $counts{forms}
: 0;
return \%counts;
}
__END__
=head1 NAME
htmx-usage - Count static htmx declarations in GPForum templates.
=head1 SYNOPSIS
script/gpforum-carton exec perl script/htmx-usage
=head1 DESCRIPTION
The form coverage is the number of literal form declarations carrying an htmx
HTTP action or C<hx-boost="true"> divided by all literal form declarations.
EP instructions and HTML comments are removed before parsing. Each branch and
loop body is counted once, not once per rendered instance. Included templates
are counted at their own definition, not expanded at each call site.
This is not a measure of requests, users, page views or htmx's available features.
Custom JavaScript may intercept an enhanced form and use fetch instead. Forms
which only include shared htmx submit buttons are not counted as htmx forms;
those buttons are counted separately as request elements.
=head1 USAGE
Run from any directory with GPForum's installed Perl dependencies.
=head1 REQUIRED ARGUMENTS
None.
=head1 OPTIONS
None.
=head1 DIAGNOSTICS
File read failures and output write failures terminate with an error.
=head1 EXIT STATUS
Zero on success; nonzero if a required file cannot be read or output fails.
=head1 CONFIGURATION
Templates are found relative to this script's repository checkout.
=head1 DEPENDENCIES
Const::Fast and Mojolicious, from GPForum's locked dependency tree.
=head1 INCOMPATIBILITIES
This command parses EP source without rendering or executing Perl.
=head1 BUGS AND LIMITATIONS
Counts describe declarations. Dynamic attributes emitted by Perl and inherited
boost settings are not expanded. Runtime usage requires separate instrumentation.
=head1 AUTHOR
GPForum Contributors.
=head1 LICENSE AND COPYRIGHT
Copyright 2026 GPForum Contributors. Licensed under the BSD 3-Clause license.
=cut