From 03d0fe8884041da69f87eb2566ed07b5ae281220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20B=C3=B6hm?= Date: Sun, 31 May 2020 14:03:28 -0700 Subject: [PATCH] Support names starting with arbitrary characters Fixes #18 --- src/__fixtures__/tests.ts | 17 +++++++++++++++++ src/parse.ts | 20 ++++++++++---------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/__fixtures__/tests.ts b/src/__fixtures__/tests.ts index cbdcbfb4..ae8359a5 100644 --- a/src/__fixtures__/tests.ts +++ b/src/__fixtures__/tests.ts @@ -353,6 +353,23 @@ export const tests: [string, Selector[][], string][] = [ "attribute with previously normalized characters", ], + // ID starting with a dot + [ + "#.identifier", + [ + [ + { + type: "attribute", + action: "equals", + name: "id", + value: ".identifier", + ignoreCase: false, + }, + ], + ], + "ID starting with a dot", + ], + //pseudo selectors [ ":foo", diff --git a/src/parse.ts b/src/parse.ts index 8a6bcf1b..a7b2f3bc 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -67,10 +67,10 @@ export type TraversalType = | "parent" | "sibling"; -const reName = /^(?:\\([\da-f]{1,6}\s?|(\s)|.)|[\w\-\u00b0-\uFFFF])+/, - reEscape = /\\([\da-f]{1,6}\s?|(\s)|.)/gi, - //modified version of https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L87 - reAttr = /^\s*((?:\\.|[\w\u00b0-\uFFFF-])+)\s*(?:(\S?)=\s*(?:(['"])([^]*?)\3|(#?(?:\\.|[\w\u00b0-\uFFFF-])*)|)|)\s*(i)?\]/; +const reName = /^[^\\]?(?:\\(?:[\da-f]{1,6}\s?|.)|[\w\-\u00b0-\uFFFF])+/; +const reEscape = /\\([\da-f]{1,6}\s?|.)/gi; +//modified version of https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L87 +const reAttr = /^\s*((?:\\.|[\w\u00b0-\uFFFF-])+)\s*(?:(\S?)=\s*(?:(['"])([^]*?)\3|(#?(?:\\.|[\w\u00b0-\uFFFF-])*)|)|)\s*(i)?\]/; const actionTypes: { [key: string]: AttributeAction } = { undefined: "exists", @@ -127,7 +127,7 @@ function isWhitespace(c: string) { function parse(selector: string, options?: Options): Selector[][] { const subselects: Selector[][] = []; - selector = parseSelector(subselects, selector + "", options); + selector = parseSelector(subselects, `${selector}`, options); if (selector !== "") { throw new Error(`Unmatched selector: ${selector}`); @@ -232,7 +232,7 @@ function parseSelector( tokens.push({ type: "attribute", - name: name, + name, action: actionTypes[data[2]], value: unescapeCSS(data[4] || data[5] || ""), ignoreCase: !!data[6], @@ -278,8 +278,8 @@ function parseSelector( selector = selector.substr(1); } else { - let pos = 1, - counter = 1; + let pos = 1; + let counter = 1; for (; counter > 0 && pos < selector.length; pos++) { if (selector.charAt(pos) === "(" && !isEscaped(pos)) @@ -310,7 +310,7 @@ function parseSelector( } } - tokens.push({ type: "pseudo", name: name, data: data }); + tokens.push({ type: "pseudo", name, data }); } else if (reName.test(selector)) { let name = getName(); @@ -323,7 +323,7 @@ function parseSelector( name = name.toLowerCase(); } - tokens.push({ type: "tag", name: name }); + tokens.push({ type: "tag", name }); } else { if ( tokens.length &&