Skip to content

Commit cc9f379

Browse files
committed
GH#6; fix handling of regex character classes, and / detection.
Inside of a regex, an unescaped `/` may be present inside of a character class definition.
1 parent d39895d commit cc9f379

3 files changed

Lines changed: 44 additions & 6 deletions

File tree

Changes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ Revision history for Perl extension JavaScript::Minifier::XS.
77
- optimize whitespace collapsing
88
- GH#3 / RT#108682; fix whitespace reduction at end of preserved line
99
comment. Thanks to Dan Goodliffe
10+
- GH#6; fix unescaped slash in character set, inside of a regex, with thanks
11+
to @faf
1012

1113
0.13 2020-12-30 21:46:29-08:00 America/Vancouver
1214
- POD cleanups; spelling, SYNOPSIS

XS.xs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ void _JsExtractLiteral(JsDoc* doc, Node* node) {
298298
const char* buf = doc->buffer;
299299
size_t offset = doc->offset;
300300
char delimiter = buf[offset];
301+
bool in_char_class = 0;
301302
/* skip start of literal */
302303
offset ++;
303304
/* search for end of literal */
@@ -306,12 +307,24 @@ void _JsExtractLiteral(JsDoc* doc, Node* node) {
306307
/* escaped character; skip */
307308
offset ++;
308309
}
309-
else if (buf[offset] == delimiter) {
310-
const char* start = buf + doc->offset;
311-
size_t length = offset - doc->offset + 1;
312-
JsSetNodeContents(node, start, length);
313-
node->type = NODE_LITERAL;
314-
return;
310+
else {
311+
/* if in a regex, track if we're in a character class */
312+
if (delimiter == '/') {
313+
if ((buf[offset] == '[') && !in_char_class) {
314+
in_char_class = 1;
315+
}
316+
if ((buf[offset] == ']') && in_char_class) {
317+
in_char_class = 0;
318+
}
319+
}
320+
/* if we have found the end of the literal, store it */
321+
if ((buf[offset] == delimiter) && !in_char_class) {
322+
const char* start = buf + doc->offset;
323+
size_t length = offset - doc->offset + 1;
324+
JsSetNodeContents(node, start, length);
325+
node->type = NODE_LITERAL;
326+
return;
327+
}
315328
}
316329
/* move onto next character */
317330
offset ++;

t/minify.t

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,29 @@ subtest 'regexp escaped "/" is not a comment' => sub {
236236
is $got, $expect;
237237
};
238238

239+
###############################################################################
240+
# GH#6; regexps can contain an unescaped slash inside a character set
241+
subtest 'regexp with unescaped slash in character set' => sub {
242+
my $given = q|var a = ""; var re = /[/"]/i; console.log(re.test(a));|;
243+
my $expect = q|var a="";var re=/[/"]/i;console.log(re.test(a));|;
244+
my $got = minify($given);
245+
is $got, $expect;
246+
};
247+
248+
subtest 'regexp with escaped slash in character set' => sub {
249+
my $given = q|var a = ""; var re = /[\/"]/i; console.log(re.test(a));|;
250+
my $expect = q|var a="";var re=/[\/"]/i;console.log(re.test(a));|;
251+
my $got = minify($given);
252+
is $got, $expect;
253+
};
254+
255+
subtest 'regexp with not really a character set' => sub {
256+
my $given = q|var a = ""; var re = /\[/i; console.log(re.test(a));|;
257+
my $expect = q|var a="";var re=/\[/i;console.log(re.test(a));|;
258+
my $got = minify($given);
259+
is $got, $expect;
260+
};
261+
239262
###############################################################################
240263
# should be able to return a regex from a function
241264
subtest 'return regex from function' => sub {

0 commit comments

Comments
 (0)