Skip to content

Commit

Permalink
feat: build stylesheet with supported extended selectors
Browse files Browse the repository at this point in the history
  • Loading branch information
seia-soto committed Nov 13, 2024
1 parent c1d7176 commit 105ff98
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 1 deletion.
26 changes: 26 additions & 0 deletions packages/adblocker-extended-selectors/src/extended.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

import { tokenize, RECURSIVE_PSEUDO_CLASSES } from './parse.js';
import { Atoms } from './types.js';

export const EXTENDED_PSEUDO_CLASSES = new Set([
// '-abp-contains',
Expand Down Expand Up @@ -137,3 +138,28 @@ export function classifySelector(selector: string): SelectorType {

return SelectorType.Normal;
}

export function getExtendedPseudoClasses(selector: string): Set<string> {
const extendedSelectors = new Set<string>();

if (selector.indexOf(':') === -1) {
return extendedSelectors;
}

const tokens: Atoms = [...tokenize(selector)];

while (tokens.length !== 0) {
const token = tokens.shift()!;

if (token.type === 'pseudo-class') {
if (EXTENDED_PSEUDO_CLASSES.has(token.name) === true) {
extendedSelectors.add(token.name);
}
if (token.argument !== undefined && RECURSIVE_PSEUDO_CLASSES.has(token.name) === true) {
tokens.push(...tokenize(token.argument));
}
}
}

return extendedSelectors;
}
1 change: 1 addition & 0 deletions packages/adblocker-extended-selectors/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ export {
PSEUDO_ELEMENTS,
SelectorType,
classifySelector,
getExtendedPseudoClasses,
} from './extended.js';
13 changes: 12 additions & 1 deletion packages/adblocker/src/engine/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,8 @@ export default class FilterEngine extends EventEmitter<EngineEventHandlers> {
getRulesFromDOM = true,
getRulesFromHostname = true,

// Other information
experimentalPseudoClasses = ['has'],
hidingStyle,
callerContext,
}: {
Expand All @@ -1007,6 +1009,9 @@ export default class FilterEngine extends EventEmitter<EngineEventHandlers> {
getRulesFromDOM?: boolean;
getRulesFromHostname?: boolean;

// If set, outputs a separate css block with specified experimental selectors.
// This argument has a higher priority than `getExtendedRules`.
experimentalPseudoClasses?: string[] | undefined;
hidingStyle?: string | undefined;
callerContext?: any | undefined;
}): IMessageFromBackground {
Expand Down Expand Up @@ -1122,7 +1127,13 @@ export default class FilterEngine extends EventEmitter<EngineEventHandlers> {
applied = true;
}
} else if (filter.isExtended()) {
if (getExtendedRules === true) {
if (
experimentalPseudoClasses.length !== 0 &&
filter.hasUnsupportedExtendedPseudoClass(experimentalPseudoClasses) === false
) {
styleFilters.push(filter);
applied = true;
} else if (getExtendedRules === true) {
extendedFilters.push(filter);
applied = true;
}
Expand Down
17 changes: 17 additions & 0 deletions packages/adblocker/src/filters/cosmetic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
classifySelector,
SelectorType,
parse as parseCssSelector,
getExtendedPseudoClasses,
} from '@ghostery/adblocker-extended-selectors';

import { Domains } from '../engine/domains.js';
Expand Down Expand Up @@ -425,6 +426,7 @@ export default class CosmeticFilter implements IFilter {

private id: number | undefined;
private scriptletDetails: { name: string; args: string[] } | undefined;
private extendedPseudoClasses: Set<string> | undefined;

constructor({
mask,
Expand All @@ -447,6 +449,7 @@ export default class CosmeticFilter implements IFilter {
this.id = undefined;
this.rawLine = rawLine;
this.scriptletDetails = undefined;
this.extendedPseudoClasses = undefined;
}

public isCosmeticFilter(): this is CosmeticFilter {
Expand Down Expand Up @@ -868,6 +871,20 @@ export default class CosmeticFilter implements IFilter {
return getBit(this.mask, COSMETICS_MASK.extended);
}

public hasUnsupportedExtendedPseudoClass(withPseudoClasses: string[]): boolean {
if (this.extendedPseudoClasses === undefined) {
this.extendedPseudoClasses = getExtendedPseudoClasses(this.getSelector());
}

for (const pseudoClass of withPseudoClasses) {
if (!this.extendedPseudoClasses.has(pseudoClass)) {
return true;
}
}

return false;
}

public isRemove(): boolean {
return getBit(this.mask, COSMETICS_MASK.remove);
}
Expand Down

0 comments on commit 105ff98

Please sign in to comment.