Skip to content

Commit 38004f2

Browse files
committed
review
1 parent 8453451 commit 38004f2

File tree

7 files changed

+232
-184
lines changed

7 files changed

+232
-184
lines changed

config-presets/all.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
}
2121
],
2222
"no-inconsistent-hint-platforms": "error",
23-
"no-invalid-cosmetic-separator": "error",
23+
"no-invalid-cosmetic-separator": [
24+
"warn"
25+
],
2426
"no-invalid-css-declaration": "error",
2527
"no-invalid-domains": "error",
2628
"no-invalid-hint-params": "error",

config-presets/recommended.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
"no-duplicated-hints": "error",
88
"no-duplicated-modifiers": "error",
99
"no-inconsistent-hint-platforms": "error",
10-
"no-invalid-cosmetic-separator": "error",
10+
"no-invalid-cosmetic-separator": [
11+
"warn"
12+
],
1113
"no-invalid-css-declaration": "error",
1214
"no-invalid-domains": "error",
1315
"no-invalid-hint-params": "error",

src/common/constants.ts

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,3 +218,189 @@ export const SUPPORTED_PREPROCESSOR_DIRECTIVES = new Set([
218218

219219
export const REMOVE_PROPERTY = 'remove';
220220
export const REMOVE_VALUE = 'true';
221+
222+
/**
223+
* Supported Extended CSS pseudo-classes.
224+
*
225+
* These pseudo-classes are not supported by browsers natively, so we need Extended CSS library to support them.
226+
*
227+
* Please keep this list sorted alphabetically.
228+
*/
229+
export const SUPPORTED_EXT_CSS_PSEUDO_CLASSES = new Set([
230+
/**
231+
* Pseudo-classes :is(), and :not() may use native implementation.
232+
*
233+
* @see {@link https://github.com/AdguardTeam/ExtendedCss#extended-css-is}
234+
* @see {@link https://github.com/AdguardTeam/ExtendedCss#extended-css-not}
235+
*/
236+
/**
237+
* :has() should also be conditionally considered as extended and should not be in this list,
238+
* for details check: https://github.com/AdguardTeam/ExtendedCss#extended-css-has,
239+
* but there is a bug with content blocker in safari:
240+
* for details check: https://bugs.webkit.org/show_bug.cgi?id=248868.
241+
*
242+
* TODO: remove 'has' later.
243+
*/
244+
'-abp-contains', // alias for 'contains'
245+
'-abp-has', // alias for 'has'
246+
'contains',
247+
'has', // some browsers support 'has' natively
248+
'has-text', // alias for 'contains'
249+
'if',
250+
'if-not',
251+
'matches-attr',
252+
'matches-css',
253+
'matches-css-after', // deprecated, replaced by 'matches-css'
254+
'matches-css-before', // deprecated, replaced by 'matches-css'
255+
'matches-property',
256+
'nth-ancestor',
257+
'remove',
258+
'upward',
259+
'xpath',
260+
'style',
261+
'matches-media',
262+
]);
263+
264+
// TODO: Use compatibility tables once they support Extended CSS pseudo-classes.
265+
// https://github.com/AdguardTeam/tsurlfilter/issues/175
266+
267+
/**
268+
* Supported Extended CSS pseudo-classes.
269+
*
270+
* These pseudo-classes are not supported by browsers natively, so we need Extended CSS library to support them.
271+
*
272+
* Please keep this list sorted alphabetically.
273+
*/
274+
export const SUPPORTED_ADG_PSEUDO_CLASSES: ReadonlySet<string> = new Set([
275+
/**
276+
* Pseudo-classes :is(), and :not() may use native implementation.
277+
*
278+
* @see {@link https://github.com/AdguardTeam/ExtendedCss#extended-css-is}
279+
* @see {@link https://github.com/AdguardTeam/ExtendedCss#extended-css-not}
280+
*/
281+
/**
282+
* :has() should also be conditionally considered as extended and should not be in this list,
283+
* for details check: https://github.com/AdguardTeam/ExtendedCss#extended-css-has,
284+
* but there is a bug with content blocker in safari:
285+
* for details check: https://bugs.webkit.org/show_bug.cgi?id=248868.
286+
*
287+
* TODO: remove 'has' later.
288+
*/
289+
'-abp-contains', // alias for 'contains'
290+
'-abp-has', // alias for 'has'
291+
'contains',
292+
'has', // some browsers support 'has' natively
293+
'has-text', // alias for 'contains'
294+
'if',
295+
'if-not',
296+
'matches-attr',
297+
'matches-css',
298+
'matches-css-after', // deprecated, replaced by 'matches-css'
299+
'matches-css-before', // deprecated, replaced by 'matches-css'
300+
'matches-property',
301+
'nth-ancestor',
302+
'remove',
303+
'upward',
304+
'xpath',
305+
]);
306+
307+
/**
308+
* Supported ABP Extended CSS pseudo-classes.
309+
*
310+
* These pseudo-classes are not supported by browsers natively, so we need Extended CSS library to support them.
311+
*
312+
* Please keep this list sorted alphabetically.
313+
*
314+
* @see {@link https://help.adblockplus.org/hc/en-us/articles/360062733293-How-to-write-filters#elemhide-emulation}
315+
*/
316+
export const SUPPORTED_ABP_PSEUDO_CLASSES: ReadonlySet<string> = new Set([
317+
'-abp-contains',
318+
'-abp-has',
319+
'-abp-properties',
320+
'xpath',
321+
]);
322+
323+
/**
324+
* Supported uBlock action operators.
325+
*
326+
* @see {@link https://github.com/gorhill/uBlock/wiki/Static-filter-syntax#action-operators}
327+
*/
328+
export const SUPPORTED_UBO_ACTION_OPERATORS = new Set([
329+
'remove',
330+
'remove-attr',
331+
'remove-class',
332+
'style',
333+
]);
334+
335+
/**
336+
* Supported uBlock procedural pseudo-classes.
337+
*
338+
* @see {@link https://github.com/gorhill/uBlock/wiki/Static-filter-syntax#procedural-cosmetic-filters}
339+
* @see {@link https://github.com/gorhill/uBlock/wiki/Static-filter-syntax#action-operators}
340+
*/
341+
export const SUPPORTED_UBO_PSEUDO_CLASSES: ReadonlySet<string> = new Set([
342+
'has',
343+
'has-text',
344+
'matches-attr',
345+
'matches-css',
346+
'matches-css-after',
347+
'matches-css-before',
348+
'matches-media',
349+
'matches-path',
350+
'matches-prop',
351+
'min-text-length',
352+
'not',
353+
'others',
354+
'upward',
355+
'watch-attr',
356+
'xpath',
357+
...SUPPORTED_UBO_ACTION_OPERATORS,
358+
]);
359+
360+
/**
361+
* Supported native CSS pseudo-classes.
362+
*
363+
* These pseudo-classes are supported by browsers natively, so we don't need Extended CSS library to support them.
364+
*
365+
* The problem with pseudo-classes is that any unknown pseudo-class makes browser ignore the whole CSS rule,
366+
* which contains a lot more selectors. So, if CSS selector contains a pseudo-class, we should try to validate it.
367+
* One more problem with pseudo-classes is that they are actively used in uBlock, hence it may mess AG styles.
368+
*
369+
* Please keep this list sorted alphabetically.
370+
*/
371+
export const SUPPORTED_CSS_PSEUDO_CLASSES = new Set([
372+
'active', // https://developer.mozilla.org/en-US/docs/Web/CSS/:active
373+
'checked', // https://developer.mozilla.org/en-US/docs/Web/CSS/:checked
374+
'disabled', // https://developer.mozilla.org/en-US/docs/Web/CSS/:disabled
375+
'empty', // https://developer.mozilla.org/en-US/docs/Web/CSS/:empty
376+
'enabled', // https://developer.mozilla.org/en-US/docs/Web/CSS/:enabled
377+
'first-child', // https://developer.mozilla.org/en-US/docs/Web/CSS/:first-child
378+
'first-of-type', // https://developer.mozilla.org/en-US/docs/Web/CSS/:first-of-type
379+
'focus', // https://developer.mozilla.org/en-US/docs/Web/CSS/:focus
380+
'has', // https://developer.mozilla.org/en-US/docs/Web/CSS/:has
381+
'hover', // https://developer.mozilla.org/en-US/docs/Web/CSS/:hover
382+
'in-range', // https://developer.mozilla.org/en-US/docs/Web/CSS/:in-range
383+
'invalid', // https://developer.mozilla.org/en-US/docs/Web/CSS/:invalid
384+
'is', // https://developer.mozilla.org/en-US/docs/Web/CSS/:is
385+
'lang', // https://developer.mozilla.org/en-US/docs/Web/CSS/:lang
386+
'last-child', // https://developer.mozilla.org/en-US/docs/Web/CSS/:last-child
387+
'last-of-type', // https://developer.mozilla.org/en-US/docs/Web/CSS/:last-of-type
388+
'link', // https://developer.mozilla.org/en-US/docs/Web/CSS/:link
389+
'not', // https://developer.mozilla.org/en-US/docs/Web/CSS/:not
390+
'nth-child', // https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child
391+
'nth-last-child', // https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-last-child
392+
'nth-last-of-type', // https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-last-of-type
393+
'nth-of-type', // https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-of-type
394+
'only-child', // https://developer.mozilla.org/en-US/docs/Web/CSS/:only-child
395+
'only-of-type', // https://developer.mozilla.org/en-US/docs/Web/CSS/:only-of-type
396+
'optional', // https://developer.mozilla.org/en-US/docs/Web/CSS/:optional
397+
'out-of-range', // https://developer.mozilla.org/en-US/docs/Web/CSS/:out-of-range
398+
'read-only', // https://developer.mozilla.org/en-US/docs/Web/CSS/:read-only
399+
'read-write', // https://developer.mozilla.org/en-US/docs/Web/CSS/:read-write
400+
'required', // https://developer.mozilla.org/en-US/docs/Web/CSS/:required
401+
'root', // https://developer.mozilla.org/en-US/docs/Web/CSS/:root
402+
'target', // https://developer.mozilla.org/en-US/docs/Web/CSS/:target
403+
'valid', // https://developer.mozilla.org/en-US/docs/Web/CSS/:valid
404+
'visited', // https://developer.mozilla.org/en-US/docs/Web/CSS/:visited
405+
'where', // https://developer.mozilla.org/en-US/docs/Web/CSS/:where
406+
]);

src/rules/no-invalid-cosmetic-separator.ts

Lines changed: 30 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
AdblockSyntax,
23
CosmeticRuleSeparator,
34
type CssInjectionRule,
45
type CssInjectionRuleBody,
@@ -7,51 +8,14 @@ import {
78
} from '@adguard/agtree';
89
import { type DeclarationPlain, type PseudoClassSelectorPlain } from '@adguard/ecss-tree';
910

10-
import { REMOVE_PROPERTY, REMOVE_VALUE } from '../common/constants';
11+
import {
12+
REMOVE_PROPERTY,
13+
REMOVE_VALUE,
14+
SUPPORTED_EXT_CSS_PSEUDO_CLASSES,
15+
SUPPORTED_UBO_ACTION_OPERATORS,
16+
} from '../common/constants';
1117
import { defineRule, LinterRuleType } from '../linter/rule';
1218

13-
/**
14-
* Supported Extended CSS pseudo-classes.
15-
*
16-
* These pseudo-classes are not supported by browsers natively, so we need Extended CSS library to support them.
17-
*
18-
* Please keep this list sorted alphabetically.
19-
*/
20-
export const SUPPORTED_EXT_CSS_PSEUDO_CLASSES = new Set([
21-
/**
22-
* Pseudo-classes :is(), and :not() may use native implementation.
23-
*
24-
* @see {@link https://github.com/AdguardTeam/ExtendedCss#extended-css-is}
25-
* @see {@link https://github.com/AdguardTeam/ExtendedCss#extended-css-not}
26-
*/
27-
/**
28-
* :has() should also be conditionally considered as extended and should not be in this list,
29-
* for details check: https://github.com/AdguardTeam/ExtendedCss#extended-css-has,
30-
* but there is a bug with content blocker in safari:
31-
* for details check: https://bugs.webkit.org/show_bug.cgi?id=248868.
32-
*
33-
* TODO: remove 'has' later.
34-
*/
35-
'-abp-contains', // alias for 'contains'
36-
'-abp-has', // alias for 'has'
37-
'contains',
38-
'has', // some browsers support 'has' natively
39-
'has-text', // alias for 'contains'
40-
'if',
41-
'if-not',
42-
'matches-attr',
43-
'matches-css',
44-
'matches-css-after', // deprecated, replaced by 'matches-css'
45-
'matches-css-before', // deprecated, replaced by 'matches-css'
46-
'matches-property',
47-
'nth-ancestor',
48-
'remove',
49-
'upward',
50-
'xpath',
51-
'style',
52-
'matches-media',
53-
]);
54-
5519
export default defineRule({
5620
meta: {
5721
type: LinterRuleType.Problem,
@@ -95,19 +59,29 @@ export default defineRule({
9559
version: '4.0.0',
9660
},
9761
create: (context) => {
62+
let syntax: AdblockSyntax | undefined;
9863
let currentRuleSeparator: Value;
9964
let currentRuleException = false;
10065
let hasPseudoClassSelectors = false;
10166
let hasExtendedDeclarations = false;
10267

68+
const isUboPseudoAllowedWithNativeSeparator = (pseudoClassName: string): boolean => {
69+
return pseudoClassName === 'matches-path' || SUPPORTED_UBO_ACTION_OPERATORS.has(pseudoClassName);
70+
};
71+
10372
return {
10473
ElementHidingRule: (node: ElementHidingRule) => {
74+
syntax = node.syntax;
10575
hasPseudoClassSelectors = false;
10676
hasExtendedDeclarations = false;
10777
currentRuleSeparator = node.separator;
10878
currentRuleException = !!node.exception;
10979
},
11080

81+
'ElementHidingRule:exit': () => {
82+
syntax = undefined;
83+
},
84+
11185
'ElementHidingRuleBody:exit': (node: ElementHidingRule) => {
11286
if (!currentRuleSeparator) {
11387
return;
@@ -216,12 +190,17 @@ export default defineRule({
216190
},
217191

218192
CssInjectionRule: (node: CssInjectionRule) => {
193+
syntax = node.syntax;
219194
hasPseudoClassSelectors = false;
220195
hasExtendedDeclarations = false;
221196
currentRuleSeparator = node.separator;
222197
currentRuleException = !!node.exception;
223198
},
224199

200+
'CssInjectionRule:exit': () => {
201+
syntax = undefined;
202+
},
203+
225204
'CssInjectionRuleBody:exit': (node: CssInjectionRuleBody) => {
226205
if (!currentRuleSeparator) {
227206
return;
@@ -292,9 +271,15 @@ export default defineRule({
292271

293272
PseudoClassSelector: (node: PseudoClassSelectorPlain) => {
294273
const { name } = node;
295-
if (SUPPORTED_EXT_CSS_PSEUDO_CLASSES.has(name) && name !== 'has') {
296-
hasPseudoClassSelectors = true;
274+
if (!SUPPORTED_EXT_CSS_PSEUDO_CLASSES.has(name) || name === 'has') {
275+
return;
276+
}
277+
278+
if (syntax === AdblockSyntax.Ubo && isUboPseudoAllowedWithNativeSeparator(name)) {
279+
return;
297280
}
281+
282+
hasPseudoClassSelectors = true;
298283
},
299284

300285
Declaration: (node: DeclarationPlain) => {

0 commit comments

Comments
 (0)