Skip to content

Commit

Permalink
feat: Support pseudo elements with data (#762)
Browse files Browse the repository at this point in the history
  • Loading branch information
fb55 committed Mar 31, 2022
1 parent 13ffc5b commit 3be227a
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 42 deletions.
29 changes: 28 additions & 1 deletion src/__fixtures__/tests.ts
Expand Up @@ -411,6 +411,33 @@ export const tests: [
{
type: SelectorType.PseudoElement,
name: "foo",
data: null,
},
],
],
"pseudo-element",
],
[
"::foo()",
[
[
{
type: SelectorType.PseudoElement,
name: "foo",
data: "",
},
],
],
"pseudo-element",
],
[
"::foo(bar())",
[
[
{
type: SelectorType.PseudoElement,
name: "foo",
data: "bar()",
},
],
],
Expand Down Expand Up @@ -485,7 +512,7 @@ export const tests: [
{
type: SelectorType.Pseudo,
name: "contains",
data: "(a((foo\\))))",
data: "(a((foo))))",
},
],
],
Expand Down
67 changes: 38 additions & 29 deletions src/parse.ts
Expand Up @@ -175,6 +175,38 @@ function parseSelector(
}
}

function readValueWithParenthesis(): string {
selectorIndex += 1;
const start = selectorIndex;
let counter = 1;

for (
;
counter > 0 && selectorIndex < selector.length;
selectorIndex++
) {
if (
selector.charCodeAt(selectorIndex) ===
CharCode.LeftParenthesis &&
!isEscaped(selectorIndex)
) {
counter++;
} else if (
selector.charCodeAt(selectorIndex) ===
CharCode.RightParenthesis &&
!isEscaped(selectorIndex)
) {
counter--;
}
}

if (counter) {
throw new Error("Parenthesis not matched");
}

return unescapeCSS(selector.slice(start, selectorIndex - 1));
}

function isEscaped(pos: number): boolean {
let slashCount = 0;

Expand Down Expand Up @@ -434,6 +466,11 @@ function parseSelector(
tokens.push({
type: SelectorType.PseudoElement,
name: getName(2).toLowerCase(),
data:
selector.charCodeAt(selectorIndex) ===
CharCode.LeftParenthesis
? readValueWithParenthesis()
: null,
});
continue;
}
Expand Down Expand Up @@ -470,35 +507,7 @@ function parseSelector(

selectorIndex += 1;
} else {
selectorIndex += 1;
const start = selectorIndex;
let counter = 1;

for (
;
counter > 0 && selectorIndex < selector.length;
selectorIndex++
) {
if (
selector.charCodeAt(selectorIndex) ===
CharCode.LeftParenthesis &&
!isEscaped(selectorIndex)
) {
counter++;
} else if (
selector.charCodeAt(selectorIndex) ===
CharCode.RightParenthesis &&
!isEscaped(selectorIndex)
) {
counter--;
}
}

if (counter) {
throw new Error("Parenthesis not matched");
}

data = selector.slice(start, selectorIndex - 1);
data = readValueWithParenthesis();

if (stripQuotesFromPseudos.has(name)) {
const quot = data.charCodeAt(0);
Expand Down
29 changes: 17 additions & 12 deletions src/stringify.ts
Expand Up @@ -69,20 +69,25 @@ function stringifyToken(
return getNamespacedName(token);

case SelectorType.PseudoElement:
return `::${escapeName(token.name, charsToEscapeInName)}`;
return `::${escapeName(token.name, charsToEscapeInName)}${
token.data === null
? ""
: `(${escapeName(token.data, charsToEscapeInPseudoValue)})`
}`;

case SelectorType.Pseudo:
if (token.data === null)
return `:${escapeName(token.name, charsToEscapeInName)}`;
if (typeof token.data === "string") {
return `:${escapeName(
token.name,
charsToEscapeInName
)}(${escapeName(token.data, charsToEscapeInPseudoValue)})`;
}
return `:${escapeName(token.name, charsToEscapeInName)}(${stringify(
token.data
)})`;
return `:${escapeName(token.name, charsToEscapeInName)}${
token.data === null
? ""
: `(${
typeof token.data === "string"
? escapeName(
token.data,
charsToEscapeInPseudoValue
)
: stringify(token.data)
})`
}`;

case SelectorType.Attribute: {
if (
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Expand Up @@ -56,6 +56,7 @@ export interface PseudoSelector {
export interface PseudoElement {
type: SelectorType.PseudoElement;
name: string;
data: string | null;
}

export interface TagSelector {
Expand Down

0 comments on commit 3be227a

Please sign in to comment.