LibJS: Escape line terminators in regex source

This commit is contained in:
aplefull 2025-10-17 14:57:07 +02:00 committed by Tim Flynn
parent 7ce4abe330
commit cd4ac4f30f
2 changed files with 59 additions and 2 deletions

View File

@ -275,12 +275,30 @@ String RegExpObject::escape_regexp_pattern() const
// FIXME: Check the 'u' and 'v' flags and escape accordingly
StringBuilder builder;
auto escaped = false;
auto in_character_class = false;
for (auto code_point : m_pattern) {
if (escaped) {
escaped = false;
builder.append_code_point('\\');
builder.append_code_point(code_point);
switch (code_point) {
case '\n':
builder.append_code_point('n');
break;
case '\r':
builder.append_code_point('r');
break;
case LINE_SEPARATOR:
builder.append("u2028"sv);
break;
case PARAGRAPH_SEPARATOR:
builder.append("u2029"sv);
break;
default:
builder.append_code_point(code_point);
break;
}
continue;
}
@ -289,9 +307,18 @@ String RegExpObject::escape_regexp_pattern() const
continue;
}
if (code_point == '[') {
in_character_class = true;
} else if (code_point == ']') {
in_character_class = false;
}
switch (code_point) {
case '/':
builder.append("\\/"sv);
if (in_character_class)
builder.append_code_point('/');
else
builder.append("\\/"sv);
break;
case '\n':
builder.append("\\n"sv);

View File

@ -5,3 +5,33 @@ test("basic functionality", () => {
expect(/\n/.source).toBe("\\n");
expect(/foo\/bar/.source).toBe("foo\\/bar");
});
test("escaped characters", () => {
const tests = [
{ regex: /\\n/, source: "\\\\n" },
{ regex: /\\\n/, source: "\\\\\\n" },
{ regex: /\\\\n/, source: "\\\\\\\\n" },
{ regex: /\\r/, source: "\\\\r" },
{ regex: /\\\r/, source: "\\\\\\r" },
{ regex: /\\\\r/, source: "\\\\\\\\r" },
{ regex: /\\u2028/, source: "\\\\u2028" },
{ regex: /\\\u2028/, source: "\\\\\\u2028" },
{ regex: /\\\\u2028/, source: "\\\\\\\\u2028" },
{ regex: /\\u2029/, source: "\\\\u2029" },
{ regex: /\\\u2029/, source: "\\\\\\u2029" },
{ regex: /\\\\u2029/, source: "\\\\\\\\u2029" },
{ regex: /\//, source: "\\/" },
{ regex: /\\\//, source: "\\\\\\/" },
{ regex: /[/]/, source: "[/]" },
{ regex: /[\/]/, source: "[\\/]" },
{ regex: /[\\/]/, source: "[\\\\/]" },
{ regex: /[\\\/]/, source: "[\\\\\\/]" },
{ regex: /\[\/\]/, source: "\\[\\/\\]" },
{ regex: /\[\/\]/, source: "\\[\\/\\]" },
{ regex: /\[\\\/\]/, source: "\\[\\\\\\/\\]" },
];
for (const test of tests) {
expect(test.regex.source).toBe(test.source);
}
});