Skip to content

Commit

Permalink
fix: Prevent axe-core crashing on “-“ as a class name (#884)
Browse files Browse the repository at this point in the history
  • Loading branch information
WilcoFiers authored May 17, 2018
1 parent bb96523 commit 9c4d84e
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 37 deletions.
28 changes: 14 additions & 14 deletions lib/core/utils/escape-selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
axe.utils.escapeSelector = function (value) {
'use strict';
/*eslint no-bitwise: 0, eqeqeq: 0, complexity: ["error",27],
max-statements:["error", 23], one-var: 0, -W041: 0 */
max-statements:["error", 25], one-var: 0, -W041: 0 */
var string = String(value);
var length = string.length;
var index = -1;
Expand All @@ -20,33 +20,33 @@ axe.utils.escapeSelector = function (value) {
// Note: there’s no need to special-case astral symbols, surrogate
// pairs, or lone surrogates.

// If the character is NULL (U+0000), then throw an
// `InvalidCharacterError` exception and terminate these steps.
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER
// (U+FFFD).
if (codeUnit == 0x0000) {
throw new Error('INVALID_CHARACTER_ERR');
result += '\uFFFD';
continue;
}

if (
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or
// [\7F-\9F] (U+007F to U+009F), […]
(codeUnit >= 0x0001 && codeUnit <= 0x001F) ||
(codeUnit >= 0x007F && codeUnit <= 0x009F) ||
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
// U+007F, […]
(codeUnit >= 0x0001 && codeUnit <= 0x001F) ||
codeUnit == 0x007F ||
// If the character is the first character and is in the range [0-9]
// (U+0030 to U+0039), […]
(index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
// If the character is the second character and is in the range [0-9]
// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
(index == 1 && codeUnit >= 0x0030 && codeUnit <= 0x0039 && firstCodeUnit == 0x002D)
) {
// http://dev.w3.org/csswg/cssom/#escape-a-character-as-code-point
// https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
result += '\\' + codeUnit.toString(16) + ' ';
continue;
}

// If the character is the second character and is `-` (U+002D) and the
// first character is `-` as well, […]
if (index == 1 && codeUnit == 0x002D && firstCodeUnit == 0x002D) {
// http://dev.w3.org/csswg/cssom/#escape-a-character
// If the character is the first character and is a `-` (U+002D), and
// there is no second character, […]
if (index == 0 && length == 1 && codeUnit == 0x002D) {
result += '\\' + string.charAt(index);
continue;
}
Expand All @@ -69,7 +69,7 @@ axe.utils.escapeSelector = function (value) {
}

// Otherwise, the escaped character.
// http://dev.w3.org/csswg/cssom/#escape-a-character
// https://drafts.csswg.org/cssom/#escape-a-character
result += '\\' + string.charAt(index);

}
Expand Down
57 changes: 34 additions & 23 deletions test/core/utils/escape-selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,37 @@ describe('utils.escapeSelector', function () {
'use strict';
var escapeSelector = axe.utils.escapeSelector;

it('should serialize strings based on CSSOM spec', function () {
it('leaves characters that do not need to escape alone', function () {
assert.equal(escapeSelector('a0b'), 'a0b');
assert.equal(escapeSelector('a1b'), 'a1b');
assert.equal(escapeSelector('a2b'), 'a2b');
assert.equal(escapeSelector('a3b'), 'a3b');
assert.equal(escapeSelector('a4b'), 'a4b');
assert.equal(escapeSelector('a5b'), 'a5b');
assert.equal(escapeSelector('a6b'), 'a6b');
assert.equal(escapeSelector('a7b'), 'a7b');
assert.equal(escapeSelector('a8b'), 'a8b');
assert.equal(escapeSelector('a9b'), 'a9b');
assert.equal(escapeSelector('a0123456789b'), 'a0123456789b');
assert.equal(escapeSelector('abcdefghijklmnopqrstuvwxyz'), 'abcdefghijklmnopqrstuvwxyz');
assert.equal(escapeSelector('ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
});

assert.throws(function () { escapeSelector('\0'); }, Error);
assert.throws(function () { escapeSelector('a\0'); }, Error);
assert.throws(function () { escapeSelector('a\0b'); }, Error);
it('escapes null characters', function () {
assert.equal(escapeSelector('\0'), '\uFFFD');
assert.equal(escapeSelector('a\0'), 'a\uFFFD');
assert.equal(escapeSelector('a\0b'), 'a\uFFFDb');
});

it('stringifies non-string characters', function () {
assert.equal(escapeSelector(), 'undefined');
assert.equal(escapeSelector(true), 'true');
assert.equal(escapeSelector(false), 'false');
assert.equal(escapeSelector(null), 'null');
assert.equal(escapeSelector(''), '');
});

assert.equal(escapeSelector('\x01\x02\x1E\x1F'), '\\1 \\2 \\1e \\1f ');

it('escapes strings starting with a number', function () {
assert.equal(escapeSelector('0a'), '\\30 a');
assert.equal(escapeSelector('1a'), '\\31 a');
assert.equal(escapeSelector('2a'), '\\32 a');
Expand All @@ -27,18 +44,15 @@ describe('utils.escapeSelector', function () {
assert.equal(escapeSelector('7a'), '\\37 a');
assert.equal(escapeSelector('8a'), '\\38 a');
assert.equal(escapeSelector('9a'), '\\39 a');
});

assert.equal(escapeSelector('a0b'), 'a0b');
assert.equal(escapeSelector('a1b'), 'a1b');
assert.equal(escapeSelector('a2b'), 'a2b');
assert.equal(escapeSelector('a3b'), 'a3b');
assert.equal(escapeSelector('a4b'), 'a4b');
assert.equal(escapeSelector('a5b'), 'a5b');
assert.equal(escapeSelector('a6b'), 'a6b');
assert.equal(escapeSelector('a7b'), 'a7b');
assert.equal(escapeSelector('a8b'), 'a8b');
assert.equal(escapeSelector('a9b'), 'a9b');
it('only escapes "-" when before a number, or on its own', function () {
assert.equal(escapeSelector('-123'), '-\\31 23');
assert.equal(escapeSelector('-'), '\\-');
assert.equal(escapeSelector('--a'), '--a');
});

it('escapes characters staring with a negative number', function () {
assert.equal(escapeSelector('-0a'), '-\\30 a');
assert.equal(escapeSelector('-1a'), '-\\31 a');
assert.equal(escapeSelector('-2a'), '-\\32 a');
Expand All @@ -49,23 +63,20 @@ describe('utils.escapeSelector', function () {
assert.equal(escapeSelector('-7a'), '-\\37 a');
assert.equal(escapeSelector('-8a'), '-\\38 a');
assert.equal(escapeSelector('-9a'), '-\\39 a');
});

assert.equal(escapeSelector('--a'), '-\\-a');

assert.equal(escapeSelector('\x80\x2D\x5F\xA9'), '\\80 \x2D\x5F\xA9');
it('escapes hex character codes', function () {
assert.equal(escapeSelector('\x80\x2D\x5F\xA9'), '\x80\x2D\x5F\xA9');
assert.equal(escapeSelector('\xA0\xA1\xA2'), '\xA0\xA1\xA2');
assert.equal(escapeSelector('a0123456789b'), 'a0123456789b');
assert.equal(escapeSelector('abcdefghijklmnopqrstuvwxyz'), 'abcdefghijklmnopqrstuvwxyz');
assert.equal(escapeSelector('ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');

assert.equal(escapeSelector('\x01\x02\x1E\x1F'), '\\1 \\2 \\1e \\1f ');
assert.equal(escapeSelector('\x20\x21\x78\x79'), '\\ \\!xy');

// astral symbol (U+1D306 TETRAGRAM FOR CENTRE)
assert.equal(escapeSelector('\uD834\uDF06'), '\uD834\uDF06');
// lone surrogates
assert.equal(escapeSelector('\uDF06'), '\uDF06');
assert.equal(escapeSelector('\uD834'), '\uD834');

});

});

0 comments on commit 9c4d84e

Please sign in to comment.