line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package HTML::Blitz; |
2
|
11
|
|
|
11
|
|
2622458
|
use HTML::Blitz::pragma; |
|
11
|
|
|
|
|
33
|
|
|
11
|
|
|
|
|
71
|
|
3
|
11
|
|
|
11
|
|
9439
|
use HTML::Blitz::Template (); |
|
11
|
|
|
|
|
31
|
|
|
11
|
|
|
|
|
279
|
|
4
|
11
|
|
|
11
|
|
5857
|
use HTML::Blitz::RuleSet (); |
|
11
|
|
|
|
|
41
|
|
|
11
|
|
|
|
|
505
|
|
5
|
11
|
|
|
11
|
|
4775
|
use HTML::Blitz::SSSelector (); |
|
11
|
|
|
|
|
36
|
|
|
11
|
|
|
|
|
472
|
|
6
|
11
|
|
|
|
|
967
|
use HTML::Blitz::SelectorType qw( |
7
|
|
|
|
|
|
|
ST_FALSE |
8
|
|
|
|
|
|
|
ST_TAG_NAME |
9
|
|
|
|
|
|
|
ST_ATTR_HAS |
10
|
|
|
|
|
|
|
ST_ATTR_EQ |
11
|
|
|
|
|
|
|
ST_ATTR_PREFIX |
12
|
|
|
|
|
|
|
ST_ATTR_SUFFIX |
13
|
|
|
|
|
|
|
ST_ATTR_INFIX |
14
|
|
|
|
|
|
|
ST_ATTR_LIST_HAS |
15
|
|
|
|
|
|
|
ST_ATTR_LANG_PREFIX |
16
|
|
|
|
|
|
|
ST_NTH_CHILD |
17
|
|
|
|
|
|
|
ST_NTH_CHILD_OF_TYPE |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
LT_DESCENDANT |
20
|
|
|
|
|
|
|
LT_CHILD |
21
|
|
|
|
|
|
|
LT_SIBLING |
22
|
|
|
|
|
|
|
LT_ADJACENT_SIBLING |
23
|
11
|
|
|
11
|
|
81
|
); |
|
11
|
|
|
|
|
23
|
|
24
|
11
|
|
|
|
|
778
|
use HTML::Blitz::ActionType qw( |
25
|
|
|
|
|
|
|
AT_REMOVE_IF |
26
|
|
|
|
|
|
|
AT_REPLACE_INNER |
27
|
|
|
|
|
|
|
AT_REPLACE_OUTER |
28
|
|
|
|
|
|
|
AT_REPEAT_OUTER |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
AT_AS_MODIFY_ATTRS |
31
|
|
|
|
|
|
|
AT_AS_REPLACE_ATTRS |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
AT_A_REMOVE_ATTR |
34
|
|
|
|
|
|
|
AT_A_SET_ATTR |
35
|
|
|
|
|
|
|
AT_A_MODIFY_ATTR |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
AT_P_VARIABLE |
38
|
|
|
|
|
|
|
AT_P_IMMEDIATE |
39
|
|
|
|
|
|
|
AT_P_TRANSFORM |
40
|
|
|
|
|
|
|
AT_P_FRAGMENT |
41
|
|
|
|
|
|
|
AT_P_VARHTML |
42
|
11
|
|
|
11
|
|
73
|
); |
|
11
|
|
|
|
|
26
|
|
43
|
11
|
|
|
11
|
|
73
|
use Carp qw(croak); |
|
11
|
|
|
|
|
23
|
|
|
11
|
|
|
|
|
565
|
|
44
|
11
|
|
|
11
|
|
69
|
use Scalar::Util qw(blessed); |
|
11
|
|
|
|
|
22
|
|
|
11
|
|
|
|
|
496
|
|
45
|
11
|
|
|
11
|
|
65
|
use overload (); |
|
11
|
|
|
|
|
23
|
|
|
11
|
|
|
|
|
3086
|
|
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
our $VERSION = '0.09'; |
48
|
|
|
|
|
|
|
|
49
|
251
|
50
|
|
251
|
1
|
140051
|
method new($class: @rules) { |
|
251
|
|
|
|
|
514
|
|
|
251
|
|
|
|
|
489
|
|
|
251
|
|
|
|
|
346
|
|
50
|
251
|
|
|
|
|
862
|
my $self = bless { |
51
|
|
|
|
|
|
|
ruleset => HTML::Blitz::RuleSet->new, |
52
|
|
|
|
|
|
|
}, $class; |
53
|
251
|
100
|
100
|
|
|
1349
|
if (@rules && ref($rules[0]) eq 'HASH') { |
54
|
7
|
|
|
|
|
14
|
my %opt = %{shift @rules}; |
|
7
|
|
|
|
|
26
|
|
55
|
7
|
50
|
|
|
|
24
|
$self->set_keep_doctype(delete $opt{keep_doctype}) if exists $opt{keep_doctype}; |
56
|
7
|
100
|
|
|
|
28
|
$self->set_keep_comments_re(delete $opt{keep_comments_re}) if exists $opt{keep_comments_re}; |
57
|
7
|
100
|
|
|
|
29
|
$self->set_dummy_marker_re(delete $opt{dummy_marker_re}) if exists $opt{dummy_marker_re}; |
58
|
7
|
50
|
|
|
|
24
|
croak "Invalid HTML::Blitz option name(s): " . join(", ", sort keys %opt) |
59
|
|
|
|
|
|
|
if keys %opt; |
60
|
|
|
|
|
|
|
} |
61
|
251
|
|
|
|
|
828
|
$self->add_rules(@rules); |
62
|
251
|
|
|
|
|
813
|
$self |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
1
|
50
|
|
1
|
1
|
321
|
method set_keep_doctype($val) { |
|
1
|
50
|
|
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
2
|
|
66
|
1
|
|
|
|
|
6
|
$self->{ruleset}->set_keep_doctype($val); |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
|
69
|
4
|
50
|
|
4
|
1
|
18
|
method set_keep_comments_re($keep_comments_re) { |
|
4
|
50
|
|
|
|
10
|
|
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
8
|
|
70
|
4
|
|
|
|
|
20
|
$self->{ruleset}->set_keep_comments_re($keep_comments_re); |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
5
|
50
|
|
5
|
1
|
19
|
method set_dummy_marker_re($dummy_marker_re) { |
|
5
|
50
|
|
|
|
12
|
|
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
6
|
|
74
|
5
|
|
|
|
|
18
|
$self->{ruleset}->set_dummy_marker_re($dummy_marker_re); |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
306
|
50
|
|
306
|
|
623
|
fun _css_unescape($str) { |
|
306
|
50
|
|
|
|
593
|
|
|
306
|
|
|
|
|
793
|
|
|
306
|
|
|
|
|
411
|
|
78
|
306
|
|
|
|
|
1835
|
$str =~ s{ |
79
|
|
|
|
|
|
|
\\ (?: |
80
|
|
|
|
|
|
|
( [[:xdigit:]]{1,6} ) (?: \r\n | [ \t\r\n\f] )?+ |
81
|
|
|
|
|
|
|
| |
82
|
|
|
|
|
|
|
( [^\n\r\f[:xdigit:]] ) |
83
|
|
|
|
|
|
|
) |
84
|
|
|
|
|
|
|
}{ |
85
|
30
|
|
66
|
|
|
122
|
$2 // do { |
86
|
20
|
|
|
|
|
47
|
my $n = hex $1; |
87
|
20
|
50
|
|
|
|
151
|
$n > 0x10_ffff ? "\x{fffd}" : chr $n |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
}xegr |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
20
|
50
|
|
20
|
|
42
|
fun _css_unescape_string($str) { |
|
20
|
50
|
|
|
|
36
|
|
|
20
|
|
|
|
|
37
|
|
|
20
|
|
|
|
|
24
|
|
93
|
20
|
100
|
|
|
|
75
|
if ($str =~ s/\A"//) { |
94
|
15
|
50
|
|
|
|
62
|
$str =~ s/"\z// or die "Internal error: unterminated \" string"; |
95
|
|
|
|
|
|
|
} else { |
96
|
5
|
50
|
|
|
|
32
|
$str =~ s/\A'// or die "Internal error: malformed (unquoted) string: $str"; |
97
|
5
|
50
|
|
|
|
23
|
$str =~ s/'\z// or die "Internal error: unterminated ' string"; |
98
|
|
|
|
|
|
|
} |
99
|
20
|
|
|
|
|
68
|
$str =~ s{ |
100
|
|
|
|
|
|
|
\\ (?: |
101
|
|
|
|
|
|
|
( [[:xdigit:]]{1,6} ) (?: \r\n | [ \t\r\n\f] )?+ |
102
|
|
|
|
|
|
|
| |
103
|
|
|
|
|
|
|
( [^\n\r\f[:xdigit:]] ) |
104
|
|
|
|
|
|
|
| |
105
|
|
|
|
|
|
|
( \r \n?+ | [\n\f] ) |
106
|
|
|
|
|
|
|
) |
107
|
|
|
|
|
|
|
}{ |
108
|
|
|
|
|
|
|
defined $3 ? '' : |
109
|
6
|
50
|
66
|
|
|
33
|
$2 // do { |
110
|
4
|
|
|
|
|
13
|
my $n = hex $1; |
111
|
4
|
50
|
|
|
|
22
|
$n > 0x10_ffff ? "\x{fffd}" : chr $n |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
}xegr |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
my $ws = qr/[ \t\r\n\f]/; |
117
|
|
|
|
|
|
|
my $nmchar = qr{ |
118
|
|
|
|
|
|
|
(?: |
119
|
|
|
|
|
|
|
[a-zA-Z0-9_\-] |
120
|
|
|
|
|
|
|
| |
121
|
|
|
|
|
|
|
[^\x00-\x7f] |
122
|
|
|
|
|
|
|
| |
123
|
|
|
|
|
|
|
\\ [[:xdigit:]]{1,6} (?: \r\n | $ws )?+ |
124
|
|
|
|
|
|
|
| |
125
|
|
|
|
|
|
|
\\ [^\n\r\f[:xdigit:]] |
126
|
|
|
|
|
|
|
) |
127
|
|
|
|
|
|
|
}x; |
128
|
|
|
|
|
|
|
my $ident = qr{ -? (?! [0-9\-] ) $nmchar++ }x; |
129
|
|
|
|
|
|
|
my $string = qr{ |
130
|
|
|
|
|
|
|
" (?: [^\n\r\f\\"] | \\ (?: \r \n?+ | [^\r[:xdigit:]] | [[:xdigit:]]{1,6} (?: \r\n | $ws )?+ ) | [^\x00-\x7f] )*+ " |
131
|
|
|
|
|
|
|
| |
132
|
|
|
|
|
|
|
' (?: [^\n\r\f\\'] | \\ (?: \r \n?+ | [^\r[:xdigit:]] | [[:xdigit:]]{1,6} (?: \r\n | $ws )?+ ) | [^\x00-\x7f] )*+ ' |
133
|
|
|
|
|
|
|
}x; |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
my %attr_op_type = ( |
136
|
|
|
|
|
|
|
'' => ST_ATTR_EQ, |
137
|
|
|
|
|
|
|
'^' => ST_ATTR_PREFIX, |
138
|
|
|
|
|
|
|
'$' => ST_ATTR_SUFFIX, |
139
|
|
|
|
|
|
|
'*' => ST_ATTR_INFIX, |
140
|
|
|
|
|
|
|
'~' => ST_ATTR_LIST_HAS, |
141
|
|
|
|
|
|
|
'|' => ST_ATTR_LANG_PREFIX, |
142
|
|
|
|
|
|
|
); |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
my %comb_type = ( |
145
|
|
|
|
|
|
|
' ' => LT_DESCENDANT, |
146
|
|
|
|
|
|
|
'>' => LT_CHILD, |
147
|
|
|
|
|
|
|
'~' => LT_SIBLING, |
148
|
|
|
|
|
|
|
'+' => LT_ADJACENT_SIBLING, |
149
|
|
|
|
|
|
|
); |
150
|
|
|
|
|
|
|
|
151
|
606
|
50
|
33
|
606
|
|
1175
|
fun _try_parse_simple_selector($src_ref, :$allow_tag_name) { |
|
606
|
50
|
|
|
|
2153
|
|
|
606
|
50
|
|
|
|
1561
|
|
|
606
|
50
|
|
|
|
1536
|
|
|
606
|
|
|
|
|
1326
|
|
|
606
|
|
|
|
|
726
|
|
152
|
606
|
100
|
100
|
|
|
3787
|
if ($allow_tag_name && $$src_ref =~ /\G(\*|$ident)/gc) { |
153
|
160
|
|
|
|
|
429
|
return { type => ST_TAG_NAME, name => _css_unescape($1) }; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
446
|
100
|
|
|
|
2427
|
if ($$src_ref =~ /\G#($nmchar++)/gc) { |
157
|
60
|
|
|
|
|
154
|
return { type => ST_ATTR_EQ, attr => 'id', value => _css_unescape($1) }; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
386
|
100
|
|
|
|
1920
|
if ($$src_ref =~ /\G\.($ident)/gc) { |
161
|
35
|
|
|
|
|
101
|
return { type => ST_ATTR_LIST_HAS, attr => 'class', value => _css_unescape($1) }; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
351
|
100
|
|
|
|
4261
|
if ( |
165
|
|
|
|
|
|
|
$$src_ref =~ m{ |
166
|
|
|
|
|
|
|
\G |
167
|
|
|
|
|
|
|
\[ $ws*+ |
168
|
|
|
|
|
|
|
($ident) $ws*+ |
169
|
|
|
|
|
|
|
(?: |
170
|
|
|
|
|
|
|
( [\^\$\*~\|]?+ ) = $ws*+ (?: ($ident) | ($string) ) $ws*+ |
171
|
|
|
|
|
|
|
)?+ |
172
|
|
|
|
|
|
|
\] |
173
|
|
|
|
|
|
|
}xgc |
174
|
|
|
|
|
|
|
) { |
175
|
40
|
|
|
|
|
179
|
my ($attr, $op, $val_ident, $val_string) = ($1, $2, $3, $4); |
176
|
40
|
|
|
|
|
88
|
$attr = _css_unescape $attr; |
177
|
40
|
|
|
|
|
88
|
$attr =~ tr/A-Z/a-z/; |
178
|
40
|
100
|
|
|
|
88
|
if (!defined $op) { |
179
|
9
|
|
|
|
|
53
|
return { type => ST_ATTR_HAS, attr => $attr }; |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
|
182
|
31
|
100
|
|
|
|
75
|
my $value = defined($val_ident) ? _css_unescape($val_ident) : _css_unescape_string($val_string); |
183
|
31
|
100
|
66
|
|
|
222
|
if ( |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
184
|
|
|
|
|
|
|
($op eq '~' && ($value eq '' || $value =~ /$ws/)) || |
185
|
|
|
|
|
|
|
($op =~ /\A[\^\$*]\z/ && $value eq '') |
186
|
|
|
|
|
|
|
) { |
187
|
4
|
|
|
|
|
34
|
return { type => ST_FALSE }; |
188
|
|
|
|
|
|
|
} |
189
|
27
|
|
|
|
|
192
|
return { type => $attr_op_type{$op}, attr => $attr, value => $value }; |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
311
|
100
|
|
|
|
754
|
if ($$src_ref =~ /\G:(nth-child|nth-of-type())\(/iaagc) { |
193
|
17
|
|
|
|
|
53
|
my $pos = $-[0]; |
194
|
17
|
|
|
|
|
48
|
my $name = $1; |
195
|
17
|
100
|
|
|
|
48
|
my $type = defined $2 ? ST_NTH_CHILD_OF_TYPE : ST_NTH_CHILD; |
196
|
17
|
|
|
|
|
96
|
$$src_ref =~ /\G$ws++/gc; |
197
|
17
|
50
|
|
|
|
189
|
$$src_ref =~ m{ |
198
|
|
|
|
|
|
|
\G |
199
|
|
|
|
|
|
|
( |
200
|
|
|
|
|
|
|
( [\-+]? [0-9]* ) [Nn] (?: $ws*+ ([\-+]) $ws*+ ([0-9]+) )?+ |
201
|
|
|
|
|
|
|
| |
202
|
|
|
|
|
|
|
[\-+]? [0-9]+ |
203
|
|
|
|
|
|
|
| |
204
|
|
|
|
|
|
|
[Oo][Dd][Dd] |
205
|
|
|
|
|
|
|
| |
206
|
|
|
|
|
|
|
[Ee][Vv][Ee][Nn] |
207
|
|
|
|
|
|
|
) |
208
|
|
|
|
|
|
|
}xgc |
209
|
|
|
|
|
|
|
or croak "Bad argument to :$name(): " . substr($$src_ref, $pos, 100); |
210
|
17
|
|
|
|
|
68
|
my ($arg, $num1, $sign, $num2) = ($1, $2, $3, $4); |
211
|
17
|
|
|
|
|
67
|
$$src_ref =~ /\G$ws++/gc; |
212
|
17
|
50
|
|
|
|
52
|
$$src_ref =~ /\G\)/gc |
213
|
|
|
|
|
|
|
or croak "Missing ')' after argument to :$name(): " . substr($$src_ref, $pos, 100); |
214
|
|
|
|
|
|
|
|
215
|
17
|
100
|
|
|
|
46
|
if (defined $num1) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
216
|
11
|
100
|
66
|
|
|
51
|
if ($num1 eq '+' || $num1 eq '') { |
|
|
100
|
|
|
|
|
|
217
|
2
|
|
|
|
|
11
|
$num1 = 1; |
218
|
|
|
|
|
|
|
} elsif ($num1 eq '-') { |
219
|
3
|
|
|
|
|
8
|
$num1 = -1; |
220
|
|
|
|
|
|
|
} else { |
221
|
6
|
|
|
|
|
12
|
$num1 = 0 + $num1; |
222
|
|
|
|
|
|
|
} |
223
|
11
|
50
|
|
|
|
19
|
if (defined $sign) { |
224
|
11
|
|
|
|
|
18
|
$num2 = 0 + $num2; |
225
|
11
|
100
|
|
|
|
24
|
$num2 = -$num2 if $sign eq '-'; |
226
|
|
|
|
|
|
|
} else { |
227
|
0
|
|
|
|
|
0
|
$num2 = 0; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
} elsif (lc($arg) eq 'odd') { |
230
|
2
|
|
|
|
|
5
|
$num1 = 2; |
231
|
2
|
|
|
|
|
3
|
$num2 = 1; |
232
|
|
|
|
|
|
|
} elsif (lc($arg) eq 'even') { |
233
|
2
|
|
|
|
|
5
|
$num1 = 2; |
234
|
2
|
|
|
|
|
3
|
$num2 = 0; |
235
|
|
|
|
|
|
|
} else { |
236
|
2
|
|
|
|
|
5
|
$num1 = 0; |
237
|
2
|
|
|
|
|
4
|
$num2 = 0 + $arg; |
238
|
|
|
|
|
|
|
} |
239
|
17
|
|
|
|
|
99
|
return { type => $type, a => $num1, b => $num2 }; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
294
|
100
|
|
|
|
613
|
if ($$src_ref =~ /\G:first-child(?![^.#:\[\]),>~ \t\r\n\f])/iaagc) { |
243
|
2
|
|
|
|
|
16
|
return { type => ST_NTH_CHILD, a => 0, b => 1 }; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
292
|
100
|
|
|
|
510
|
if ($$src_ref =~ /\G:first-of-type(?![^.#:\[\]),>~ \t\r\n\f])/iaagc) { |
247
|
2
|
|
|
|
|
20
|
return { type => ST_NTH_CHILD_OF_TYPE, a => 0, b => 1 }; |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
290
|
50
|
|
|
|
1340
|
if ($$src_ref =~ /\G:($ident)/gc) { |
251
|
0
|
|
|
|
|
0
|
croak "Unsupported pseudo-class :$1"; |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
undef |
255
|
290
|
|
|
|
|
2496
|
} |
256
|
|
|
|
|
|
|
|
257
|
256
|
50
|
|
256
|
|
546
|
fun _parse_selector($src) { |
|
256
|
50
|
|
|
|
478
|
|
|
256
|
|
|
|
|
393
|
|
|
256
|
|
|
|
|
337
|
|
258
|
256
|
50
|
|
|
|
452
|
croak "Invalid selector: $src" if ref $src; |
259
|
|
|
|
|
|
|
|
260
|
256
|
|
|
|
|
343
|
my @alternatives; |
261
|
256
|
|
|
|
|
409
|
my $sequences = []; |
262
|
256
|
|
|
|
|
380
|
my $simples = []; |
263
|
|
|
|
|
|
|
|
264
|
256
|
|
|
|
|
709
|
pos($src) = 0; |
265
|
256
|
|
|
|
|
1927
|
$src =~ /\G$ws++/gc; |
266
|
|
|
|
|
|
|
|
267
|
256
|
|
|
|
|
832
|
while () { |
268
|
606
|
100
|
|
|
|
1871
|
if ($src =~ /\G:not\(/iaagc) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
269
|
5
|
|
|
|
|
16
|
my $pos = $-[0]; |
270
|
5
|
|
|
|
|
98
|
$src =~ /\G$ws++/gc; |
271
|
5
|
50
|
|
|
|
19
|
my $simple = _try_parse_simple_selector \$src, allow_tag_name => 1 |
272
|
|
|
|
|
|
|
or croak "Unparsable selector in argument to ':not()': " . substr($src, $pos, 100); |
273
|
5
|
|
|
|
|
53
|
$src =~ /\G$ws++/gc; |
274
|
5
|
50
|
|
|
|
22
|
$src =~ /\G\)/gc |
275
|
|
|
|
|
|
|
or croak "Missing ')' after argument to ':not(': " . substr($src, pos($src), 100); |
276
|
5
|
|
|
|
|
12
|
$simple->{negated} = 1; |
277
|
5
|
|
|
|
|
85
|
push @$simples, $simple; |
278
|
|
|
|
|
|
|
} elsif (defined(my $simple = _try_parse_simple_selector \$src, allow_tag_name => !@$simples)) { |
279
|
311
|
|
|
|
|
790
|
push @$simples, $simple; |
280
|
|
|
|
|
|
|
} elsif ($src =~ /\G(?>$ws*([>~+])|$ws)$ws*+/gc) { |
281
|
33
|
|
100
|
|
|
125
|
my $comb = $1 // ' '; |
282
|
33
|
50
|
|
|
|
72
|
@$simples |
283
|
|
|
|
|
|
|
or croak "Selector list before '$comb' cannot be empty: " . substr($src, $-[0], 100); |
284
|
|
|
|
|
|
|
push @$sequences, HTML::Blitz::SSSelector->new( |
285
|
|
|
|
|
|
|
simple_selectors => $simples, |
286
|
33
|
|
|
|
|
179
|
link_type => $comb_type{$comb}, |
287
|
|
|
|
|
|
|
); |
288
|
33
|
|
|
|
|
405
|
$simples = []; |
289
|
|
|
|
|
|
|
} elsif ($src =~ /\G,$ws*+/gc) { |
290
|
1
|
50
|
|
|
|
6
|
@$simples |
291
|
|
|
|
|
|
|
or croak "Selector list before ',' cannot be empty: " . substr($src, $-[0], 100); |
292
|
1
|
|
|
|
|
5
|
push @$sequences, HTML::Blitz::SSSelector->new( |
293
|
|
|
|
|
|
|
simple_selectors => $simples, |
294
|
|
|
|
|
|
|
link_type => undef, |
295
|
|
|
|
|
|
|
); |
296
|
1
|
|
|
|
|
3
|
$simples = []; |
297
|
1
|
|
|
|
|
3
|
push @alternatives, $sequences; |
298
|
1
|
|
|
|
|
3
|
$sequences = []; |
299
|
|
|
|
|
|
|
} else { |
300
|
256
|
|
|
|
|
597
|
last; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
256
|
50
|
|
|
|
1487
|
$src =~ /\G$ws*+\z/ |
305
|
|
|
|
|
|
|
or croak "Unparsable selector: " . substr($src, pos($src), 100); |
306
|
256
|
0
|
|
|
|
594
|
@$simples |
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
307
|
|
|
|
|
|
|
or croak |
308
|
|
|
|
|
|
|
@$sequences ? "Trailing combinator after last selector list" : |
309
|
|
|
|
|
|
|
@alternatives ? "trailing comma after last selector list" : |
310
|
|
|
|
|
|
|
"Selector cannot be empty"; |
311
|
|
|
|
|
|
|
|
312
|
256
|
|
|
|
|
1058
|
push @$sequences, HTML::Blitz::SSSelector->new( |
313
|
|
|
|
|
|
|
simple_selectors => $simples, |
314
|
|
|
|
|
|
|
link_type => undef, |
315
|
|
|
|
|
|
|
); |
316
|
256
|
|
|
|
|
490
|
push @alternatives, $sequences; |
317
|
|
|
|
|
|
|
\@alternatives |
318
|
256
|
|
|
|
|
699
|
} |
319
|
|
|
|
|
|
|
|
320
|
132
|
50
|
|
132
|
|
333
|
fun _text($str) { |
|
132
|
50
|
|
|
|
241
|
|
|
132
|
|
|
|
|
235
|
|
|
132
|
|
|
|
|
192
|
|
321
|
132
|
|
|
|
|
1689
|
+{ type => AT_P_IMMEDIATE, value => '' . $str } |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
|
324
|
82
|
50
|
|
82
|
|
170
|
fun _varify($throw, $var) { |
|
82
|
50
|
|
|
|
159
|
|
|
82
|
|
|
|
|
135
|
|
|
82
|
|
|
|
|
104
|
|
325
|
82
|
50
|
|
|
|
366
|
$var =~ /\A[^\W\d][\w\-.]*\z/ or $throw->("Invalid variable name '$var'"); |
326
|
82
|
|
|
|
|
698
|
[undef, $var] |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
41
|
50
|
|
41
|
|
161
|
fun _var($throw, $var) { |
|
41
|
50
|
|
|
|
100
|
|
|
41
|
|
|
|
|
82
|
|
|
41
|
|
|
|
|
87
|
|
330
|
41
|
|
|
|
|
106
|
+{ type => AT_P_VARIABLE, value => _varify($throw, $var) } |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
|
333
|
30
|
50
|
|
30
|
|
72
|
fun _is_callable($val) { |
|
30
|
50
|
|
|
|
68
|
|
|
30
|
|
|
|
|
56
|
|
|
30
|
|
|
|
|
37
|
|
334
|
30
|
50
|
0
|
|
|
122
|
ref($val) eq 'CODE' || |
335
|
|
|
|
|
|
|
(blessed($val) && overload::Method($val, '&{}')) |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
7
|
50
|
|
7
|
|
23
|
fun _template($throw, $val) { |
|
7
|
50
|
|
|
|
20
|
|
|
7
|
|
|
|
|
17
|
|
|
7
|
|
|
|
|
10
|
|
339
|
7
|
50
|
33
|
|
|
77
|
blessed($val) && $val->isa('HTML::Blitz::Template') |
340
|
|
|
|
|
|
|
or $throw->("Argument must be an instance of HTML::Blitz::Template: '$val'"); |
341
|
7
|
|
|
|
|
38
|
+{ type => AT_P_FRAGMENT, value => $val->_codegen } |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
5
|
50
|
|
5
|
|
14
|
fun _dyn_builder($throw, $var) { |
|
5
|
50
|
|
|
|
14
|
|
|
5
|
|
|
|
|
14
|
|
|
5
|
|
|
|
|
6
|
|
345
|
5
|
|
|
|
|
15
|
+{ type => AT_P_VARHTML, value => _varify($throw, $var) } |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
my %_nop = ( |
349
|
|
|
|
|
|
|
type => AT_REPLACE_INNER, |
350
|
|
|
|
|
|
|
attrset => { |
351
|
|
|
|
|
|
|
type => AT_AS_MODIFY_ATTRS, |
352
|
|
|
|
|
|
|
content => {}, |
353
|
|
|
|
|
|
|
}, |
354
|
|
|
|
|
|
|
content => undef, |
355
|
|
|
|
|
|
|
repeat => [], |
356
|
|
|
|
|
|
|
); |
357
|
|
|
|
|
|
|
|
358
|
33
|
50
|
|
33
|
|
84
|
fun _id($x) { $x } |
|
33
|
50
|
|
|
|
72
|
|
|
33
|
|
|
|
|
72
|
|
|
33
|
|
|
|
|
57
|
|
|
33
|
|
|
|
|
83
|
|
359
|
|
|
|
|
|
|
|
360
|
17
|
50
|
|
17
|
|
48
|
fun _mk_transform_attr($attr, $fn) { |
|
17
|
50
|
|
|
|
38
|
|
|
17
|
|
|
|
|
35
|
|
|
17
|
|
|
|
|
23
|
|
361
|
|
|
|
|
|
|
+{ |
362
|
17
|
|
|
|
|
395
|
%_nop, |
363
|
|
|
|
|
|
|
attrset => { |
364
|
|
|
|
|
|
|
type => AT_AS_MODIFY_ATTRS, |
365
|
|
|
|
|
|
|
content => { |
366
|
|
|
|
|
|
|
$attr => { |
367
|
|
|
|
|
|
|
type => AT_A_MODIFY_ATTR, |
368
|
|
|
|
|
|
|
param => { type => AT_P_TRANSFORM, static => $fn, dynamic => [] }, |
369
|
|
|
|
|
|
|
}, |
370
|
|
|
|
|
|
|
}, |
371
|
|
|
|
|
|
|
}, |
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
6
|
50
|
|
6
|
|
16
|
fun _attr_add_word($throw, $attr, @words) { |
|
6
|
|
|
|
|
21
|
|
|
6
|
|
|
|
|
8
|
|
376
|
6
|
|
|
|
|
17
|
for my $word (@words) { |
377
|
14
|
50
|
|
|
|
39
|
$throw->("Argument cannot contain whitespace: '$word'") |
378
|
|
|
|
|
|
|
if $word =~ /[ \t\r\n\f]/; |
379
|
|
|
|
|
|
|
} |
380
|
30
|
50
|
|
30
|
|
69
|
_mk_transform_attr $attr, fun ($value) { |
|
30
|
50
|
|
|
|
80
|
|
|
30
|
|
|
|
|
71
|
|
|
30
|
|
|
|
|
38
|
|
381
|
30
|
|
|
|
|
49
|
my (@list, %seen); |
382
|
30
|
|
100
|
|
|
119
|
for my $word (($value // '') =~ /[^ \t\r\n\f]+/g, @words) { |
383
|
41
|
100
|
|
|
|
148
|
push @list, $word if !$seen{$word}++; |
384
|
|
|
|
|
|
|
} |
385
|
30
|
|
|
|
|
113
|
join ' ', @list |
386
|
6
|
|
|
|
|
33
|
} |
387
|
|
|
|
|
|
|
} |
388
|
|
|
|
|
|
|
|
389
|
6
|
50
|
|
6
|
|
16
|
fun _attr_remove_word($throw, $attr, @words) { |
|
6
|
|
|
|
|
17
|
|
|
6
|
|
|
|
|
7
|
|
390
|
6
|
|
|
|
|
8
|
my %banned; |
391
|
6
|
|
|
|
|
13
|
for my $word (@words) { |
392
|
22
|
50
|
|
|
|
46
|
$throw->("Argument cannot contain whitespace: '$word'") |
393
|
|
|
|
|
|
|
if $word =~ /[ \t\r\n\f]/; |
394
|
22
|
|
|
|
|
42
|
$banned{$word} = 1; |
395
|
|
|
|
|
|
|
} |
396
|
6
|
50
|
|
6
|
|
18
|
_mk_transform_attr $attr, fun ($value) { |
|
6
|
50
|
|
|
|
13
|
|
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
10
|
|
397
|
6
|
|
|
|
|
9
|
my @list; |
398
|
6
|
|
100
|
|
|
69
|
my $new_value = join ' ', grep !$banned{$_}, ($value // '') =~ /[^ \t\r\n\f]+/g; |
399
|
6
|
100
|
|
|
|
27
|
length $new_value ? $new_value : undef |
400
|
6
|
|
|
|
|
27
|
} |
401
|
|
|
|
|
|
|
} |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
my %actions = ( |
404
|
|
|
|
|
|
|
remove => fun ($throw, @args) { |
405
|
|
|
|
|
|
|
$throw->("Expected 0 arguments, got " . @args) |
406
|
|
|
|
|
|
|
if @args != 0; |
407
|
|
|
|
|
|
|
+{ type => AT_REPLACE_OUTER, param => _text('') } |
408
|
|
|
|
|
|
|
}, |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
remove_inner => fun ($throw, @args) { |
411
|
|
|
|
|
|
|
$throw->("Expected 0 arguments, got " . @args) |
412
|
|
|
|
|
|
|
if @args != 0; |
413
|
|
|
|
|
|
|
+{ %_nop, content => _text('') } |
414
|
|
|
|
|
|
|
}, |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
remove_if => fun ($throw, @args) { |
417
|
|
|
|
|
|
|
$throw->("Expected 1 argument, got " . @args) |
418
|
|
|
|
|
|
|
if @args != 1; |
419
|
|
|
|
|
|
|
my $var = _varify $throw, $args[0]; |
420
|
|
|
|
|
|
|
+{ type => AT_REMOVE_IF, cond => [$var], else => undef } |
421
|
|
|
|
|
|
|
}, |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
replace_inner_text => fun ($throw, @args) { |
424
|
|
|
|
|
|
|
$throw->("Expected 1 argument, got " . @args) |
425
|
|
|
|
|
|
|
if @args != 1; |
426
|
|
|
|
|
|
|
+{ %_nop, content => _text($args[0]) } |
427
|
|
|
|
|
|
|
}, |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
replace_inner_var => fun ($throw, @args) { |
430
|
|
|
|
|
|
|
$throw->("Expected 1 argument, got " . @args) |
431
|
|
|
|
|
|
|
if @args != 1; |
432
|
|
|
|
|
|
|
+{ %_nop, content => _var($throw, $args[0]) } |
433
|
|
|
|
|
|
|
}, |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
replace_inner_template => fun ($throw, @args) { |
436
|
|
|
|
|
|
|
$throw->("Expected 1 argument, got " . @args) |
437
|
|
|
|
|
|
|
if @args != 1; |
438
|
|
|
|
|
|
|
+{ %_nop, content => _template($throw, $args[0]) } |
439
|
|
|
|
|
|
|
}, |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
#replace_inner_builder => fun ($throw, @args) { |
442
|
|
|
|
|
|
|
# $throw->("Expected 1 argument, got " . @args) |
443
|
|
|
|
|
|
|
# if @args != 1; |
444
|
|
|
|
|
|
|
# +{ %_nop, content => _builder($throw, $args[0]) } |
445
|
|
|
|
|
|
|
#}, |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
replace_inner_dyn_builder => fun ($throw, @args) { |
448
|
|
|
|
|
|
|
$throw->("Expected 1 argument, got " . @args) |
449
|
|
|
|
|
|
|
if @args != 1; |
450
|
|
|
|
|
|
|
+{ %_nop, content => _dyn_builder($throw, $args[0]) } |
451
|
|
|
|
|
|
|
}, |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
replace_outer_text => fun ($throw, @args) { |
454
|
|
|
|
|
|
|
$throw->("Expected 1 argument, got " . @args) |
455
|
|
|
|
|
|
|
if @args != 1; |
456
|
|
|
|
|
|
|
+{ type => AT_REPLACE_OUTER, param => _text($args[0]) } |
457
|
|
|
|
|
|
|
}, |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
replace_outer_var => fun ($throw, @args) { |
460
|
|
|
|
|
|
|
$throw->("Expected 1 argument, got " . @args) |
461
|
|
|
|
|
|
|
if @args != 1; |
462
|
|
|
|
|
|
|
+{ type => AT_REPLACE_OUTER, param => _var($throw, $args[0]) } |
463
|
|
|
|
|
|
|
}, |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
replace_outer_template => fun ($throw, @args) { |
466
|
|
|
|
|
|
|
$throw->("Expected 1 argument, got " . @args) |
467
|
|
|
|
|
|
|
if @args != 1; |
468
|
|
|
|
|
|
|
+{ type => AT_REPLACE_OUTER, param => _template($throw, $args[0]) } |
469
|
|
|
|
|
|
|
}, |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
#replace_outer_builder => fun ($throw, @args) { |
472
|
|
|
|
|
|
|
# $throw->("Expected 1 argument, got " . @args) |
473
|
|
|
|
|
|
|
# if @args != 1; |
474
|
|
|
|
|
|
|
# +{ type => AT_REPLACE_OUTER, param => _builder($throw, $args[0]) } |
475
|
|
|
|
|
|
|
#}, |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
replace_outer_dyn_builder => fun ($throw, @args) { |
478
|
|
|
|
|
|
|
$throw->("Expected 1 argument, got " . @args) |
479
|
|
|
|
|
|
|
if @args != 1; |
480
|
|
|
|
|
|
|
+{ type => AT_REPLACE_OUTER, param => _dyn_builder($throw, $args[0]) } |
481
|
|
|
|
|
|
|
}, |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
transform_inner_sub => fun ($throw, @args) { |
484
|
|
|
|
|
|
|
$throw->("Expected 1 argument, got " . @args) |
485
|
|
|
|
|
|
|
if @args != 1; |
486
|
|
|
|
|
|
|
my $fn = $args[0]; |
487
|
|
|
|
|
|
|
_is_callable $fn |
488
|
|
|
|
|
|
|
or $throw->("Argument must be a function"); |
489
|
|
|
|
|
|
|
+{ %_nop, content => { type => AT_P_TRANSFORM, static => $fn, dynamic => [] } } |
490
|
|
|
|
|
|
|
}, |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
transform_inner_var => fun ($throw, @args) { |
493
|
|
|
|
|
|
|
$throw->("Expected 1 argument, got " . @args) |
494
|
|
|
|
|
|
|
if @args != 1; |
495
|
|
|
|
|
|
|
my $var = _varify $throw, $args[0]; |
496
|
|
|
|
|
|
|
+{ %_nop, content => { type => AT_P_TRANSFORM, static => \&_id, dynamic => [$var] } } |
497
|
|
|
|
|
|
|
}, |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
transform_outer_sub => fun ($throw, @args) { |
500
|
|
|
|
|
|
|
$throw->("Expected 1 argument, got " . @args) |
501
|
|
|
|
|
|
|
if @args != 1; |
502
|
|
|
|
|
|
|
my $fn = $args[0]; |
503
|
|
|
|
|
|
|
_is_callable $fn |
504
|
|
|
|
|
|
|
or $throw->("Argument must be a function"); |
505
|
|
|
|
|
|
|
+{ type => AT_REPLACE_OUTER, param => { type => AT_P_TRANSFORM, static => $fn, dynamic => [] } } |
506
|
|
|
|
|
|
|
}, |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
transform_outer_var => fun ($throw, @args) { |
509
|
|
|
|
|
|
|
$throw->("Expected 1 argument, got " . @args) |
510
|
|
|
|
|
|
|
if @args != 1; |
511
|
|
|
|
|
|
|
my $var = _varify $throw, $args[0]; |
512
|
|
|
|
|
|
|
+{ type => AT_REPLACE_OUTER, param => { type => AT_P_TRANSFORM, static => \&_id, dynamic => [$var] } } |
513
|
|
|
|
|
|
|
}, |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
remove_attribute => fun ($throw, @args) { |
516
|
|
|
|
|
|
|
+{ %_nop, attrset => { type => AT_AS_MODIFY_ATTRS, content => { map +($_ => { type => AT_A_REMOVE_ATTR }), @args } } } |
517
|
|
|
|
|
|
|
}, |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
replace_all_attributes => fun ($throw, @args) { |
520
|
|
|
|
|
|
|
$throw->("Expected 1 argument, got " . @args) |
521
|
|
|
|
|
|
|
if @args != 1; |
522
|
|
|
|
|
|
|
my $attr = $args[0]; |
523
|
|
|
|
|
|
|
+{ |
524
|
|
|
|
|
|
|
%_nop, |
525
|
|
|
|
|
|
|
attrset => { |
526
|
|
|
|
|
|
|
type => AT_AS_REPLACE_ATTRS, |
527
|
|
|
|
|
|
|
content => { |
528
|
|
|
|
|
|
|
map { |
529
|
|
|
|
|
|
|
my $v = $attr->{$_}; |
530
|
|
|
|
|
|
|
ref($v) eq 'ARRAY' |
531
|
|
|
|
|
|
|
or $throw->("Attribute replacement value must be an array reference, not '$v'"); |
532
|
|
|
|
|
|
|
@$v == 2 |
533
|
|
|
|
|
|
|
or $throw->("Attribute replacement value must have 2 elements, not " . @$v); |
534
|
|
|
|
|
|
|
$_ => |
535
|
|
|
|
|
|
|
$v->[0] eq 'text' ? _text($v->[1]) : |
536
|
|
|
|
|
|
|
$v->[0] eq 'var' ? _var($throw, $v->[1]) : |
537
|
|
|
|
|
|
|
$throw->("Invalid attribute replacement type (must be 'text' or 'var'): '$v->[0]'") |
538
|
|
|
|
|
|
|
} keys %$attr |
539
|
|
|
|
|
|
|
}, |
540
|
|
|
|
|
|
|
}, |
541
|
|
|
|
|
|
|
} |
542
|
|
|
|
|
|
|
}, |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
remove_all_attributes => fun ($throw, @args) { |
545
|
|
|
|
|
|
|
$throw->("Expected 0 arguments, got " . @args) |
546
|
|
|
|
|
|
|
if @args != 0; |
547
|
|
|
|
|
|
|
+{ %_nop, attrset => { type => AT_AS_REPLACE_ATTRS, content => {} } } |
548
|
|
|
|
|
|
|
}, |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
set_attribute_text => fun ($throw, @args) { |
551
|
|
|
|
|
|
|
$throw->("Expected 1 or 2 arguments, got " . @args) |
552
|
|
|
|
|
|
|
if @args < 1 || @args > 2; |
553
|
|
|
|
|
|
|
if (@args == 1) { |
554
|
|
|
|
|
|
|
ref(my $attr = $args[0]) eq 'HASH' |
555
|
|
|
|
|
|
|
or $throw->(ref $args[0] ? "Invalid reference type (must be HASH): $args[0]" : "Missing value for attribute '$args[0]'"); |
556
|
|
|
|
|
|
|
return +{ %_nop, attrset => { type => AT_AS_MODIFY_ATTRS, content => { map +($_ => { type => AT_A_SET_ATTR, param => _text($attr->{$_}) }), keys %$attr } } }; |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
+{ %_nop, attrset => { type => AT_AS_MODIFY_ATTRS, content => { $args[0] => { type => AT_A_SET_ATTR, param => _text($args[1]) } } } } |
559
|
|
|
|
|
|
|
}, |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
set_attribute_var => fun ($throw, @args) { |
562
|
|
|
|
|
|
|
$throw->("Expected 1 or 2 arguments, got " . @args) |
563
|
|
|
|
|
|
|
if @args < 1 || @args > 2; |
564
|
|
|
|
|
|
|
if (@args == 1) { |
565
|
|
|
|
|
|
|
ref(my $attr = $args[0]) eq 'HASH' |
566
|
|
|
|
|
|
|
or $throw->(ref $args[0] ? "Invalid reference type (must be HASH): $args[0]" : "Missing value for attribute '$args[0]'"); |
567
|
|
|
|
|
|
|
return +{ %_nop, attrset => { type => AT_AS_MODIFY_ATTRS, content => { map +($_ => { type => AT_A_SET_ATTR, param => _var($throw, $attr->{$_}) }), keys %$attr } } }; |
568
|
|
|
|
|
|
|
} |
569
|
|
|
|
|
|
|
+{ %_nop, attrset => { type => AT_AS_MODIFY_ATTRS, content => { $args[0] => { type => AT_A_SET_ATTR, param => _var($throw, $args[1]) } } } } |
570
|
|
|
|
|
|
|
}, |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
set_attributes => fun ($throw, @args) { |
573
|
|
|
|
|
|
|
$throw->("Expected 1 argument, got " . @args) |
574
|
|
|
|
|
|
|
if @args != 1; |
575
|
|
|
|
|
|
|
my $attr = $args[0]; |
576
|
|
|
|
|
|
|
+{ |
577
|
|
|
|
|
|
|
%_nop, |
578
|
|
|
|
|
|
|
attrset => { |
579
|
|
|
|
|
|
|
type => AT_AS_MODIFY_ATTRS, |
580
|
|
|
|
|
|
|
content => { |
581
|
|
|
|
|
|
|
map { |
582
|
|
|
|
|
|
|
my $v = $attr->{$_}; |
583
|
|
|
|
|
|
|
ref($v) eq 'ARRAY' |
584
|
|
|
|
|
|
|
or $throw->("Attribute replacement value must be an array reference, not '$v'"); |
585
|
|
|
|
|
|
|
@$v == 2 |
586
|
|
|
|
|
|
|
or $throw->("Attribute replacement value must have 2 elements, not " . @$v); |
587
|
|
|
|
|
|
|
$_ => { |
588
|
|
|
|
|
|
|
type => AT_A_SET_ATTR, |
589
|
|
|
|
|
|
|
param => |
590
|
|
|
|
|
|
|
$v->[0] eq 'text' ? _text($v->[1]) : |
591
|
|
|
|
|
|
|
$v->[0] eq 'var' ? _var($throw, $v->[1]) : |
592
|
|
|
|
|
|
|
$throw->("Invalid attribute replacement type (must be 'text' or 'var'): '$v->[0]'") |
593
|
|
|
|
|
|
|
} |
594
|
|
|
|
|
|
|
} keys %$attr |
595
|
|
|
|
|
|
|
}, |
596
|
|
|
|
|
|
|
}, |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
}, |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
transform_attribute_sub => fun ($throw, @args) { |
601
|
|
|
|
|
|
|
$throw->("Expected 2 arguments, got " . @args) |
602
|
|
|
|
|
|
|
if @args != 2; |
603
|
|
|
|
|
|
|
my ($attr, $fn) = @args; |
604
|
|
|
|
|
|
|
_is_callable $fn |
605
|
|
|
|
|
|
|
or $throw->("Argument must be a function"); |
606
|
|
|
|
|
|
|
_mk_transform_attr $attr, $fn |
607
|
|
|
|
|
|
|
}, |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
transform_attribute_var => fun ($throw, @args) { |
610
|
|
|
|
|
|
|
$throw->("Expected 2 arguments, got " . @args) |
611
|
|
|
|
|
|
|
if @args != 2; |
612
|
|
|
|
|
|
|
my ($attr, $var) = @args; |
613
|
|
|
|
|
|
|
$var = _varify $throw, $var; |
614
|
|
|
|
|
|
|
+{ |
615
|
|
|
|
|
|
|
%_nop, |
616
|
|
|
|
|
|
|
attrset => { |
617
|
|
|
|
|
|
|
type => AT_AS_MODIFY_ATTRS, |
618
|
|
|
|
|
|
|
content => { |
619
|
|
|
|
|
|
|
$attr => { |
620
|
|
|
|
|
|
|
type => AT_A_MODIFY_ATTR, |
621
|
|
|
|
|
|
|
param => { type => AT_P_TRANSFORM, static => \&_id, dynamic => [$var] }, |
622
|
|
|
|
|
|
|
}, |
623
|
|
|
|
|
|
|
}, |
624
|
|
|
|
|
|
|
}, |
625
|
|
|
|
|
|
|
} |
626
|
|
|
|
|
|
|
}, |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
add_attribute_word => fun ($throw, @args) { |
629
|
|
|
|
|
|
|
$throw->("Expected 2 or more arguments, not " . @args) |
630
|
|
|
|
|
|
|
if @args < 2; |
631
|
|
|
|
|
|
|
_attr_add_word $throw, @args |
632
|
|
|
|
|
|
|
}, |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
remove_attribute_word => fun ($throw, @args) { |
635
|
|
|
|
|
|
|
$throw->("Expected 2 or more arguments, not " . @args) |
636
|
|
|
|
|
|
|
if @args < 2; |
637
|
|
|
|
|
|
|
_attr_remove_word $throw, @args |
638
|
|
|
|
|
|
|
}, |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
add_class => fun ($throw, @args) { |
641
|
|
|
|
|
|
|
$throw->("Expected 1 or more arguments, not " . @args) |
642
|
|
|
|
|
|
|
if @args < 1; |
643
|
|
|
|
|
|
|
_attr_add_word $throw, 'class', @args |
644
|
|
|
|
|
|
|
}, |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
remove_class => fun ($throw, @args) { |
647
|
|
|
|
|
|
|
$throw->("Expected 1 or more arguments, not " . @args) |
648
|
|
|
|
|
|
|
if @args < 1; |
649
|
|
|
|
|
|
|
_attr_remove_word $throw, 'class', @args |
650
|
|
|
|
|
|
|
}, |
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
repeat_outer => fun ($throw, @args) { |
653
|
|
|
|
|
|
|
$throw->("Expected 1 or more arguments, not " . @args) |
654
|
|
|
|
|
|
|
if @args < 1; |
655
|
|
|
|
|
|
|
my $var = _varify $throw, shift @args; |
656
|
|
|
|
|
|
|
my @inplace; |
657
|
|
|
|
|
|
|
if (@args && ref($args[0]) eq 'REF' && ref(${$args[0]}) eq 'ARRAY') { |
658
|
|
|
|
|
|
|
my $actions = ${shift @args}; |
659
|
|
|
|
|
|
|
@inplace = map _parse_action(fun ($err) { $throw->("Root action: $err") }, $_), ref($actions->[0]) ? @$actions : $actions; |
660
|
|
|
|
|
|
|
} |
661
|
|
|
|
|
|
|
my @rules; |
662
|
|
|
|
|
|
|
for my $proto (@args) { |
663
|
|
|
|
|
|
|
my ($selector, $actions) = _parse_rule($proto); |
664
|
|
|
|
|
|
|
push @rules, [$selector, @$actions] |
665
|
|
|
|
|
|
|
if @$actions; |
666
|
|
|
|
|
|
|
} |
667
|
|
|
|
|
|
|
+{ type => AT_REPEAT_OUTER, var => $var, inplace => \@inplace, nested => \%_nop, rules => \@rules } |
668
|
|
|
|
|
|
|
}, |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
repeat_inner => fun ($throw, @args) { |
671
|
|
|
|
|
|
|
$throw->("Expected 1 or more arguments, not " . @args) |
672
|
|
|
|
|
|
|
if @args < 1; |
673
|
|
|
|
|
|
|
my $var = _varify $throw, shift @args; |
674
|
|
|
|
|
|
|
my @rules; |
675
|
|
|
|
|
|
|
for my $proto (@args) { |
676
|
|
|
|
|
|
|
my ($selector, $actions) = _parse_rule($proto, custom_action => { |
677
|
|
|
|
|
|
|
separator => fun ($throw, @args) { |
678
|
|
|
|
|
|
|
$throw->("Expected 0 arguments, got " . @args) |
679
|
|
|
|
|
|
|
if @args != 0; |
680
|
|
|
|
|
|
|
+{ type => AT_REMOVE_IF, else => undef, cond => [[undef, \'iter0']] } |
681
|
|
|
|
|
|
|
}, |
682
|
|
|
|
|
|
|
}); |
683
|
|
|
|
|
|
|
push @rules, [$selector, @$actions] |
684
|
|
|
|
|
|
|
if @$actions; |
685
|
|
|
|
|
|
|
} |
686
|
|
|
|
|
|
|
+{ %_nop, repeat => [{ var => $var, rules => \@rules }] } |
687
|
|
|
|
|
|
|
}, |
688
|
|
|
|
|
|
|
); |
689
|
|
|
|
|
|
|
|
690
|
259
|
50
|
|
259
|
|
660
|
fun _parse_action($throw, $action_proto, $custom_action = {}) { |
|
259
|
50
|
|
|
|
530
|
|
|
259
|
100
|
|
|
|
696
|
|
|
259
|
|
|
|
|
357
|
|
691
|
259
|
50
|
|
|
|
652
|
ref($action_proto) eq 'ARRAY' |
692
|
|
|
|
|
|
|
or $throw->("Not an ARRAY reference: '$action_proto'"); |
693
|
259
|
50
|
|
|
|
722
|
@$action_proto |
694
|
|
|
|
|
|
|
or $throw->("Action cannot be empty"); |
695
|
259
|
|
|
|
|
612
|
my ($type, @args) = @$action_proto; |
696
|
259
|
0
|
66
|
|
|
1246
|
my $action_fn = $custom_action->{$type} // $actions{$type} // $throw->("Unknown action type '$type'" . ($type eq 'seperator' && $custom_action->{separator} ? " (did you mean 'separator'?)" : "")); |
|
|
|
0
|
|
|
|
|
|
|
|
33
|
|
|
|
|
697
|
259
|
0
|
|
0
|
|
1292
|
$action_fn->(fun ($err) { $throw->("'$type': $err"); }, @args) |
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
698
|
|
|
|
|
|
|
} |
699
|
|
|
|
|
|
|
|
700
|
256
|
50
|
66
|
256
|
|
502
|
fun _parse_rule($proto, :$custom_action = {}) { |
|
256
|
50
|
|
|
|
643
|
|
|
256
|
100
|
|
|
|
484
|
|
|
256
|
50
|
|
|
|
670
|
|
|
256
|
|
|
|
|
612
|
|
|
256
|
|
|
|
|
355
|
|
701
|
256
|
|
|
|
|
604
|
my ($sel_str, @action_protos) = @$proto; |
702
|
256
|
|
|
|
|
547
|
my $selector = _parse_selector $sel_str; |
703
|
256
|
0
|
|
0
|
|
1606
|
my @actions = map _parse_action(fun ($err) { croak "Invalid action for '$sel_str': $err" }, $_, $custom_action), @action_protos; |
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
704
|
256
|
|
|
|
|
1067
|
$selector, \@actions |
705
|
|
|
|
|
|
|
} |
706
|
|
|
|
|
|
|
|
707
|
253
|
50
|
|
253
|
1
|
1151
|
method add_rules(@rules) { |
|
253
|
|
|
|
|
387
|
|
|
253
|
|
|
|
|
438
|
|
|
253
|
|
|
|
|
340
|
|
708
|
253
|
|
|
|
|
513
|
my $ruleset = $self->{ruleset}; |
709
|
253
|
|
|
|
|
509
|
for my $rule (@rules) { |
710
|
249
|
|
|
|
|
507
|
my ($selector, $actions) = _parse_rule $rule; |
711
|
249
|
50
|
|
|
|
1075
|
$ruleset->add_rule($selector, @$actions) |
712
|
|
|
|
|
|
|
if @$actions; |
713
|
|
|
|
|
|
|
} |
714
|
|
|
|
|
|
|
} |
715
|
|
|
|
|
|
|
|
716
|
276
|
50
|
|
276
|
1
|
26123
|
method apply_to_html($name, $html) { |
|
276
|
50
|
|
|
|
608
|
|
|
276
|
|
|
|
|
432
|
|
|
276
|
|
|
|
|
536
|
|
|
276
|
|
|
|
|
374
|
|
717
|
276
|
|
|
|
|
891
|
HTML::Blitz::Template->new(_codegen => $self->{ruleset}->compile($name, $html)) |
718
|
|
|
|
|
|
|
} |
719
|
|
|
|
|
|
|
|
720
|
10
|
50
|
|
10
|
1
|
6568
|
method apply_to_file($file) { |
|
10
|
50
|
|
|
|
24
|
|
|
10
|
|
|
|
|
17
|
|
|
10
|
|
|
|
|
16
|
|
|
10
|
|
|
|
|
43
|
|
721
|
10
|
|
|
|
|
14
|
my $html = do { |
722
|
10
|
50
|
|
|
|
447
|
open my $fh, '<:encoding(UTF-8)', $file |
723
|
|
|
|
|
|
|
or croak "Can't open $file: $!"; |
724
|
10
|
|
|
|
|
1962
|
local $/; |
725
|
10
|
|
|
|
|
409
|
readline $fh |
726
|
|
|
|
|
|
|
}; |
727
|
10
|
|
|
|
|
401
|
$self->apply_to_html($file, $html) |
728
|
|
|
|
|
|
|
} |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
1 |
731
|
|
|
|
|
|
|
__END__ |