Skip to content

Commit 88b536a

Browse files
authored
allow mixed-case class names (#1347)
* allow mixed-case class names * more tests; cite spec
1 parent a6747a2 commit 88b536a

File tree

2 files changed

+49
-1
lines changed

2 files changed

+49
-1
lines changed

src/style.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,8 +414,9 @@ export function impliedNumber(value, impliedValue) {
414414
if ((value = number(value)) !== impliedValue) return value;
415415
}
416416

417+
// https://www.w3.org/TR/CSS21/grammar.html
417418
const validClassName =
418-
/^-?([_a-z]|[\240-\377]|\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-f])([_a-z0-9-]|[\240-\377]|\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-f])*$/;
419+
/^-?([_a-z]|[\240-\377]|\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-f])([_a-z0-9-]|[\240-\377]|\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-f])*$/i;
419420

420421
export function maybeClassName(name) {
421422
if (name === undefined) return `plot-${Math.random().toString(16).slice(2)}`;

test/style-test.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import assert from "assert";
2+
import {maybeClassName} from "../src/style.js";
3+
4+
it("maybeClassName allows typical class names", () => {
5+
assert.strictEqual(maybeClassName("foo"), "foo");
6+
assert.strictEqual(maybeClassName("foo2"), "foo2");
7+
assert.strictEqual(maybeClassName("foo-bar"), "foo-bar");
8+
assert.strictEqual(maybeClassName("-bar"), "-bar");
9+
});
10+
11+
it("maybeClassName allows escaped class names", () => {
12+
assert.strictEqual(maybeClassName("\\1234"), "\\1234");
13+
assert.strictEqual(maybeClassName("\\64"), "\\64");
14+
assert.strictEqual(maybeClassName("\\ "), "\\ ");
15+
});
16+
17+
it("maybeClassName allows mixed-case class names", () => {
18+
assert.strictEqual(maybeClassName("FOO"), "FOO");
19+
assert.strictEqual(maybeClassName("fooBar"), "fooBar");
20+
});
21+
22+
it("maybeClassName disallows invalid class names", () => {
23+
assert.throws(() => maybeClassName(" "), /invalid class name/);
24+
assert.throws(() => maybeClassName("42"), /invalid class name/);
25+
assert.throws(() => maybeClassName("foo "), /invalid class name/);
26+
assert.throws(() => maybeClassName(" foo"), /invalid class name/);
27+
assert.throws(() => maybeClassName(".foo"), /invalid class name/);
28+
assert.throws(() => maybeClassName("[foo]"), /invalid class name/);
29+
assert.throws(() => maybeClassName("💩"), /invalid class name/);
30+
assert.throws(() => maybeClassName("--hi"), /invalid class name/);
31+
assert.throws(() => maybeClassName("\\"), /invalid class name/);
32+
});
33+
34+
it("maybeClassName coerces to strings", () => {
35+
assert.strictEqual(maybeClassName(["foo"]), "foo");
36+
assert.strictEqual(maybeClassName({toString: () => "foo-bar"}), "foo-bar");
37+
});
38+
39+
it("maybeClassName generates distinct random class names", () => {
40+
const names = new Set();
41+
for (let i = 0; i < 100; ++i) {
42+
const name = maybeClassName();
43+
assert.match(name, /^plot-[0-9a-f]{6,}$/);
44+
assert.strictEqual(names.has(name), false);
45+
names.add(name);
46+
}
47+
});

0 commit comments

Comments
 (0)