improve correctness of CSS.escape

This commit is contained in:
Karl Seguin
2026-01-31 10:44:56 +08:00
parent 12a566c07e
commit 466cdb4ee7
2 changed files with 22 additions and 10 deletions

View File

@@ -20,8 +20,10 @@
{ {
testing.expectEqual('\\30 abc', CSS.escape('0abc')); testing.expectEqual('\\30 abc', CSS.escape('0abc'));
testing.expectEqual('\\31 23', CSS.escape('123')); testing.expectEqual('\\31 23', CSS.escape('123'));
testing.expectEqual('\\-test', CSS.escape('-test')); testing.expectEqual('\\-', CSS.escape('-'));
testing.expectEqual('\\--test', CSS.escape('--test')); testing.expectEqual('-test', CSS.escape('-test'));
testing.expectEqual('--test', CSS.escape('--test'));
testing.expectEqual('-\\33 ', CSS.escape('-3'));
} }
</script> </script>

View File

@@ -42,15 +42,23 @@ pub fn parseDimension(value: []const u8) ?f64 {
/// https://drafts.csswg.org/cssom/#the-css.escape()-method /// https://drafts.csswg.org/cssom/#the-css.escape()-method
pub fn escape(_: *const CSS, value: []const u8, page: *Page) ![]const u8 { pub fn escape(_: *const CSS, value: []const u8, page: *Page) ![]const u8 {
if (value.len == 0) { if (value.len == 0) {
return error.InvalidCharacterError; return "";
} }
const first = value[0]; const first = value[0];
if (first == '-' and value.len == 1) {
return "\\-";
}
// Count how many characters we need for the output // Count how many characters we need for the output
var out_len: usize = escapeLen(true, first); var out_len: usize = escapeLen(true, first);
for (value[1..]) |c| { for (value[1..], 0..) |c, i| {
out_len += escapeLen(false, c); // Second char (i==0) is a digit and first is '-', needs hex escape
if (i == 0 and first == '-' and c >= '0' and c <= '9') {
out_len += 2 + hexDigitsNeeded(c);
} else {
out_len += escapeLen(false, c);
}
} }
if (out_len == value.len) { if (out_len == value.len) {
@@ -67,8 +75,13 @@ pub fn escape(_: *const CSS, value: []const u8, page: *Page) ![]const u8 {
pos = 1; pos = 1;
} }
for (value[1..]) |c| { for (value[1..], 0..) |c, i| {
if (!needsEscape(false, c)) { // Second char (i==0) is a digit and first is '-', needs hex escape
if (i == 0 and first == '-' and c >= '0' and c <= '9') {
result[pos] = '\\';
const hex_str = std.fmt.bufPrint(result[pos + 1 ..], "{x} ", .{c}) catch unreachable;
pos += 1 + hex_str.len;
} else if (!needsEscape(false, c)) {
result[pos] = c; result[pos] = c;
pos += 1; pos += 1;
} else { } else {
@@ -105,9 +118,6 @@ fn needsEscape(comptime is_first: bool, c: u8) bool {
if (c >= '0' and c <= '9') { if (c >= '0' and c <= '9') {
return true; return true;
} }
if (c == '-') {
return true;
}
} }
// Characters that need escaping // Characters that need escaping