@adguard/agtree 3.4.3 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ast-utils/clone.js +2 -2
- package/dist/ast-utils/modifiers.js +2 -2
- package/dist/ast-utils/network-rules.js +2 -2
- package/dist/ast-utils/scriptlets.js +2 -2
- package/dist/common/abp-snippet-injection-body-common.js +2 -2
- package/dist/common/agent-common.js +2 -2
- package/dist/common/ubo-html-filtering-body-common.js +40 -0
- package/dist/common/ubo-selector-common.js +2 -2
- package/dist/compatibility-tables/base.js +2 -2
- package/dist/compatibility-tables/compatibility-table-data.js +2 -2
- package/dist/compatibility-tables/modifiers.js +2 -2
- package/dist/compatibility-tables/platforms.js +2 -2
- package/dist/compatibility-tables/redirects.js +2 -2
- package/dist/compatibility-tables/schemas/base.js +2 -2
- package/dist/compatibility-tables/schemas/modifier.js +2 -2
- package/dist/compatibility-tables/schemas/platform.js +2 -2
- package/dist/compatibility-tables/schemas/redirect.js +2 -2
- package/dist/compatibility-tables/schemas/resource-type.js +2 -2
- package/dist/compatibility-tables/schemas/scriptlet.js +2 -2
- package/dist/compatibility-tables/scriptlets.js +2 -2
- package/dist/compatibility-tables/utils/platform-helpers.js +2 -2
- package/dist/compatibility-tables/utils/resource-type-helpers.js +2 -2
- package/dist/compatibility-tables/utils/zod-camelcase.js +2 -2
- package/dist/converter/base-interfaces/base-converter.js +2 -2
- package/dist/converter/base-interfaces/conversion-result.js +2 -2
- package/dist/converter/base-interfaces/rule-converter-base.js +2 -2
- package/dist/converter/comment/index.js +2 -2
- package/dist/converter/cosmetic/css.js +2 -2
- package/dist/converter/cosmetic/element-hiding.js +2 -2
- package/dist/converter/cosmetic/header-removal.js +24 -42
- package/dist/converter/cosmetic/html.js +580 -438
- package/dist/converter/cosmetic/index.js +3 -2
- package/dist/converter/cosmetic/rule-modifiers/adg.js +2 -2
- package/dist/converter/cosmetic/rule-modifiers/ubo.js +2 -2
- package/dist/converter/cosmetic/scriptlet.js +2 -2
- package/dist/converter/css/index.js +3 -2
- package/dist/converter/data/css.js +32 -54
- package/dist/converter/filter-list.js +2 -2
- package/dist/converter/index.js +2 -2
- package/dist/converter/misc/network-rule-modifier.js +2 -2
- package/dist/converter/network/index.js +2 -2
- package/dist/converter/raw-filter-list.js +2 -2
- package/dist/converter/raw-rule.js +6 -3
- package/dist/converter/rule.js +2 -2
- package/dist/errors/adblock-syntax-error.js +2 -2
- package/dist/errors/binary-schema-mismatch-error.js +2 -2
- package/dist/errors/not-implemented-error.js +2 -2
- package/dist/errors/rule-conversion-error.js +2 -2
- package/dist/generator/base-generator.js +2 -2
- package/dist/generator/comment/agent-comment-generator.js +2 -2
- package/dist/generator/comment/agent-generator.js +2 -2
- package/dist/generator/comment/comment-rule-generator.js +2 -2
- package/dist/generator/comment/config-comment-generator.js +2 -2
- package/dist/generator/comment/hint-comment-generator.js +2 -2
- package/dist/generator/comment/hint-generator.js +2 -2
- package/dist/generator/comment/metadata-comment-generator.js +2 -2
- package/dist/generator/comment/pre-processor-comment-generator.js +2 -2
- package/dist/generator/comment/simple-comment-generator.js +2 -2
- package/dist/generator/cosmetic/cosmetic-rule-body-generator.js +21 -6
- package/dist/generator/cosmetic/cosmetic-rule-generator.js +2 -2
- package/dist/generator/cosmetic/cosmetic-rule-pattern-generator.js +2 -2
- package/dist/generator/cosmetic/html-filtering-body/adg-html-filtering-body-generator.js +38 -0
- package/dist/generator/cosmetic/html-filtering-body/html-filtering-body-generator.js +32 -0
- package/dist/generator/cosmetic/html-filtering-body/ubo-html-filtering-body-generator.js +65 -0
- package/dist/generator/cosmetic/{body → scriptlet-body}/abp-snippet-injection-body-generator.js +2 -2
- package/dist/generator/cosmetic/{body → scriptlet-body}/adg-scriptlet-injection-body-generator.js +2 -2
- package/dist/generator/cosmetic/{body → scriptlet-body}/ubo-scriptlet-injection-body-generator.js +2 -2
- package/dist/generator/cosmetic/selector/attribute-selector-generator.js +42 -0
- package/dist/generator/cosmetic/selector/class-selector-generator.js +26 -0
- package/dist/generator/cosmetic/selector/complex-selector-generator.js +71 -0
- package/dist/generator/cosmetic/selector/id-selector-generator.js +26 -0
- package/dist/generator/cosmetic/selector/pseudo-class-selector-generator.js +35 -0
- package/dist/generator/cosmetic/selector/selector-combinator-generator.js +30 -0
- package/dist/generator/cosmetic/selector/selector-list-generator.js +41 -0
- package/dist/generator/cosmetic/selector/type-selector-generator.js +25 -0
- package/dist/generator/css/adg-css-injection-generator.js +5 -6
- package/dist/generator/filterlist-generator.js +2 -2
- package/dist/generator/index.js +2 -2
- package/dist/generator/misc/domain-list-generator.js +2 -2
- package/dist/generator/misc/list-items-generator.js +2 -2
- package/dist/generator/misc/logical-expression-generator.js +2 -2
- package/dist/generator/misc/modifier-generator.js +2 -2
- package/dist/generator/misc/modifier-list-generator.js +2 -2
- package/dist/generator/misc/parameter-list-generator.js +2 -2
- package/dist/generator/misc/value-generator.js +2 -2
- package/dist/generator/network/host-rule-generator.js +2 -2
- package/dist/generator/network/network-rule-generator.js +2 -2
- package/dist/generator/rule-generator.js +2 -2
- package/dist/index.js +4 -14
- package/dist/nodes/index.js +2 -2
- package/dist/package.json.js +3 -3
- package/dist/parser/base-parser.js +2 -2
- package/dist/parser/comment/agent-comment-parser.js +2 -2
- package/dist/parser/comment/agent-parser.js +2 -2
- package/dist/parser/comment/comment-parser.js +2 -2
- package/dist/parser/comment/config-comment-parser.js +2 -2
- package/dist/parser/comment/hint-comment-parser.js +2 -2
- package/dist/parser/comment/hint-parser.js +2 -2
- package/dist/parser/comment/metadata-comment-parser.js +2 -2
- package/dist/parser/comment/preprocessor-parser.js +2 -2
- package/dist/parser/comment/simple-comment-parser.js +2 -2
- package/dist/parser/cosmetic/cosmetic-rule-parser.js +10 -21
- package/dist/parser/cosmetic/html-filtering-body/adg-html-filtering-body-parser.js +49 -0
- package/dist/parser/cosmetic/html-filtering-body/html-filtering-body-parser.js +70 -0
- package/dist/parser/cosmetic/html-filtering-body/ubo-html-filtering-body-parser.js +180 -0
- package/dist/parser/cosmetic/{body → scriptlet-body}/abp-snippet-injection-body-parser.js +2 -2
- package/dist/parser/cosmetic/{body → scriptlet-body}/adg-scriptlet-injection-body-parser.js +2 -2
- package/dist/parser/cosmetic/{body → scriptlet-body}/ubo-scriptlet-injection-body-parser.js +2 -2
- package/dist/parser/cosmetic/selector/handlers/attribute-selector-handler.js +206 -0
- package/dist/parser/cosmetic/selector/handlers/class-selector-handler.js +48 -0
- package/dist/parser/cosmetic/selector/handlers/complex-selector-handler.js +67 -0
- package/dist/parser/cosmetic/selector/handlers/compound-selector-handler.js +97 -0
- package/dist/parser/cosmetic/selector/handlers/id-selector-handler.js +42 -0
- package/dist/parser/cosmetic/selector/handlers/pseudo-class-selector-handler.js +128 -0
- package/dist/parser/cosmetic/selector/handlers/type-selector-handler.js +58 -0
- package/dist/parser/cosmetic/selector/selector-list-parser.js +164 -0
- package/dist/parser/css/adg-css-injection-parser.js +4 -5
- package/dist/parser/css/balancing.js +2 -2
- package/dist/parser/css/constants.js +2 -2
- package/dist/parser/css/css-token-stream.js +41 -4
- package/dist/parser/css/ubo-selector-parser.js +2 -2
- package/dist/parser/filterlist-parser.js +2 -2
- package/dist/parser/index.js +2 -2
- package/dist/parser/misc/app-list-parser.js +2 -2
- package/dist/parser/misc/domain-list-parser.js +2 -2
- package/dist/parser/misc/list-items-parser.js +2 -2
- package/dist/parser/misc/logical-expression-parser.js +2 -2
- package/dist/parser/misc/method-list-parser.js +2 -2
- package/dist/parser/misc/modifier-list.js +2 -2
- package/dist/parser/misc/modifier-parser.js +2 -2
- package/dist/parser/misc/parameter-list-parser.js +2 -2
- package/dist/parser/misc/stealth-option-list-parser.js +2 -2
- package/dist/parser/misc/ubo-parameter-list-parser.js +2 -2
- package/dist/parser/misc/value-parser.js +2 -2
- package/dist/parser/network/host-rule-parser.js +2 -2
- package/dist/parser/network/network-rule-parser.js +2 -2
- package/dist/parser/options.js +3 -2
- package/dist/parser/rule-parser.js +2 -2
- package/dist/types/common/ubo-html-filtering-body-common.d.ts +12 -0
- package/dist/types/compatibility-tables/compatibility-table-data.d.ts +3 -3
- package/dist/types/compatibility-tables/schemas/redirect.d.ts +1 -1
- package/dist/types/compatibility-tables/schemas/scriptlet.d.ts +2 -2
- package/dist/types/converter/cosmetic/html.d.ts +167 -42
- package/dist/types/converter/data/css.d.ts +18 -6
- package/dist/types/generator/cosmetic/html-filtering-body/adg-html-filtering-body-generator.d.ts +17 -0
- package/dist/types/generator/cosmetic/html-filtering-body/html-filtering-body-generator.d.ts +17 -0
- package/dist/types/generator/cosmetic/html-filtering-body/ubo-html-filtering-body-generator.d.ts +30 -0
- package/dist/types/generator/cosmetic/selector/attribute-selector-generator.d.ts +15 -0
- package/dist/types/generator/cosmetic/selector/class-selector-generator.d.ts +15 -0
- package/dist/types/generator/cosmetic/selector/complex-selector-generator.d.ts +17 -0
- package/dist/types/generator/cosmetic/selector/id-selector-generator.d.ts +15 -0
- package/dist/types/generator/cosmetic/selector/pseudo-class-selector-generator.d.ts +15 -0
- package/dist/types/generator/cosmetic/selector/selector-combinator-generator.d.ts +15 -0
- package/dist/types/generator/cosmetic/selector/selector-list-generator.d.ts +17 -0
- package/dist/types/generator/cosmetic/selector/type-selector-generator.d.ts +15 -0
- package/dist/types/generator/css/adg-css-injection-generator.d.ts +1 -1
- package/dist/types/index.d.ts +3 -13
- package/dist/types/nodes/index.d.ts +159 -3
- package/dist/types/parser/cosmetic/html-filtering-body/adg-html-filtering-body-parser.d.ts +35 -0
- package/dist/types/parser/cosmetic/html-filtering-body/html-filtering-body-parser.d.ts +39 -0
- package/dist/types/parser/cosmetic/html-filtering-body/ubo-html-filtering-body-parser.d.ts +63 -0
- package/dist/types/parser/cosmetic/selector/context.d.ts +42 -0
- package/dist/types/parser/cosmetic/selector/handlers/attribute-selector-handler.d.ts +35 -0
- package/dist/types/parser/cosmetic/selector/handlers/class-selector-handler.d.ts +15 -0
- package/dist/types/parser/cosmetic/selector/handlers/complex-selector-handler.d.ts +20 -0
- package/dist/types/parser/cosmetic/selector/handlers/compound-selector-handler.d.ts +25 -0
- package/dist/types/parser/cosmetic/selector/handlers/id-selector-handler.d.ts +15 -0
- package/dist/types/parser/cosmetic/selector/handlers/pseudo-class-selector-handler.d.ts +15 -0
- package/dist/types/parser/cosmetic/selector/handlers/type-selector-handler.d.ts +15 -0
- package/dist/types/parser/cosmetic/selector/selector-list-parser.d.ts +38 -0
- package/dist/types/parser/css/adg-css-injection-parser.d.ts +0 -2
- package/dist/types/parser/css/css-token-stream.d.ts +18 -0
- package/dist/types/parser/network/network-rule-parser.d.ts +1 -1
- package/dist/types/parser/options.d.ts +5 -0
- package/dist/types/utils/constants.d.ts +1 -0
- package/dist/types/utils/index.d.ts +0 -6
- package/dist/types/utils/quotes.d.ts +44 -0
- package/dist/types/utils/regexp.d.ts +24 -0
- package/dist/utils/adblockers.js +2 -2
- package/dist/utils/bit-count.js +2 -2
- package/dist/utils/categorizer.js +2 -2
- package/dist/utils/clone.js +2 -2
- package/dist/utils/constants.js +6 -9
- package/dist/utils/cosmetic-rule-separator.js +2 -2
- package/dist/utils/deep-freeze.js +2 -2
- package/dist/utils/domain.js +2 -2
- package/dist/utils/error.js +2 -2
- package/dist/utils/index.js +2 -8
- package/dist/utils/logical-expression.js +2 -2
- package/dist/utils/multi-value-map.js +2 -2
- package/dist/utils/noop-modifier.js +2 -2
- package/dist/utils/position-provider.js +2 -2
- package/dist/utils/quotes.js +163 -10
- package/dist/utils/regexp.js +31 -2
- package/dist/utils/string.js +2 -2
- package/dist/utils/type-guards.js +3 -13
- package/dist/validator/constants.js +2 -2
- package/dist/validator/helpers.js +2 -2
- package/dist/validator/index.js +2 -2
- package/dist/validator/value.js +2 -2
- package/dist/version.js +2 -2
- package/package.json +6 -14
- package/dist/deserializer/base-deserializer.js +0 -29
- package/dist/deserializer/comment/agent-comment-deserializer.js +0 -79
- package/dist/deserializer/comment/agent-deserializer.js +0 -65
- package/dist/deserializer/comment/comment-rule-deserializer.js +0 -54
- package/dist/deserializer/comment/config-comment-deserializer.js +0 -111
- package/dist/deserializer/comment/hint-comment-deserializer.js +0 -72
- package/dist/deserializer/comment/hint-deserializer.js +0 -85
- package/dist/deserializer/comment/metadata-comment-deserializer.js +0 -69
- package/dist/deserializer/comment/pre-processor-comment-deserializer.js +0 -112
- package/dist/deserializer/comment/simple-comment-deserializer.js +0 -65
- package/dist/deserializer/cosmetic/cosmetic-rule-deserializer.js +0 -131
- package/dist/deserializer/cosmetic/css-injection-body-deserializer.js +0 -56
- package/dist/deserializer/cosmetic/element-hiding-body-deserializer.js +0 -48
- package/dist/deserializer/cosmetic/scriptlet-body/abp-snippet-injection-body-deserializer.js +0 -39
- package/dist/deserializer/cosmetic/scriptlet-body/adg-scriptlet-injection-body-deserializer.js +0 -40
- package/dist/deserializer/cosmetic/scriptlet-body/scriptlet-body-deserializer.js +0 -54
- package/dist/deserializer/cosmetic/scriptlet-body/ubo-scriptlet-injection-body-deserializer.js +0 -38
- package/dist/deserializer/empty-rule-deserializer.js +0 -48
- package/dist/deserializer/filterlist-deserializer.js +0 -85
- package/dist/deserializer/index.js +0 -8
- package/dist/deserializer/invalid-rule-deserializer.js +0 -50
- package/dist/deserializer/invalid-rule-error-node-deserializer.js +0 -50
- package/dist/deserializer/misc/domain-list-deserializer.js +0 -64
- package/dist/deserializer/misc/list-item-deserializer.js +0 -69
- package/dist/deserializer/misc/list-items-deserializer.js +0 -30
- package/dist/deserializer/misc/logical-expression-deserializer.js +0 -196
- package/dist/deserializer/misc/modifier-deserializer.js +0 -87
- package/dist/deserializer/misc/modifier-list-deserializer.js +0 -61
- package/dist/deserializer/misc/parameter-list-deserializer.js +0 -64
- package/dist/deserializer/misc/value-deserializer.js +0 -50
- package/dist/deserializer/network/host-rule-deserializer.js +0 -67
- package/dist/deserializer/network/hostname-list-deserializer.js +0 -56
- package/dist/deserializer/network/network-rule-deserializer.js +0 -65
- package/dist/deserializer/rule-deserializer.js +0 -65
- package/dist/deserializer/syntax-deserialization-map.js +0 -21
- package/dist/marshalling-utils/comment/agent-comment-common.js +0 -21
- package/dist/marshalling-utils/comment/agent-common.js +0 -40
- package/dist/marshalling-utils/comment/config-comment-common.js +0 -54
- package/dist/marshalling-utils/comment/hint-comment-common.js +0 -22
- package/dist/marshalling-utils/comment/hint-common.js +0 -56
- package/dist/marshalling-utils/comment/metadata-comment-common.js +0 -41
- package/dist/marshalling-utils/comment/pre-processor-comment-common.js +0 -59
- package/dist/marshalling-utils/comment/simple-comment-common.js +0 -22
- package/dist/marshalling-utils/cosmetic/body/abp-snippet-injection-body-common.js +0 -61
- package/dist/marshalling-utils/cosmetic/body/adg-scriptlet-injection-body-common.js +0 -66
- package/dist/marshalling-utils/cosmetic/body/css-injection-body-common.js +0 -24
- package/dist/marshalling-utils/cosmetic/body/element-hiding-body-common.js +0 -21
- package/dist/marshalling-utils/cosmetic/body/ubo-scriptlet-injection-body-common.js +0 -114
- package/dist/marshalling-utils/cosmetic/cosmetic-rule-common.js +0 -46
- package/dist/marshalling-utils/empty-rule-common.js +0 -20
- package/dist/marshalling-utils/filter-list-common.js +0 -21
- package/dist/marshalling-utils/invalid-rule-common.js +0 -21
- package/dist/marshalling-utils/invalid-rule-error-node-common.js +0 -22
- package/dist/marshalling-utils/misc/binary-type-common.js +0 -54
- package/dist/marshalling-utils/misc/domain-list-common.js +0 -36
- package/dist/marshalling-utils/misc/host-rule-common.js +0 -24
- package/dist/marshalling-utils/misc/hostname-list-common.js +0 -21
- package/dist/marshalling-utils/misc/list-item-common.js +0 -22
- package/dist/marshalling-utils/misc/logical-expression-common.js +0 -83
- package/dist/marshalling-utils/misc/modifier-common.js +0 -231
- package/dist/marshalling-utils/misc/modifier-list-common.js +0 -21
- package/dist/marshalling-utils/misc/parameter-list-common.js +0 -21
- package/dist/marshalling-utils/misc/value-common.js +0 -22
- package/dist/marshalling-utils/network/network-rule-common.js +0 -24
- package/dist/marshalling-utils/syntax-serialization-map.js +0 -30
- package/dist/serializer/base-serializer.js +0 -29
- package/dist/serializer/comment/agent-comment-serializer.js +0 -74
- package/dist/serializer/comment/agent-serializer.js +0 -59
- package/dist/serializer/comment/comment-rule-serializer.js +0 -105
- package/dist/serializer/comment/config-comment-serializer.js +0 -82
- package/dist/serializer/comment/hint-comment-serializer.js +0 -65
- package/dist/serializer/comment/hint-serializer.js +0 -54
- package/dist/serializer/comment/metadata-comment-serializer.js +0 -73
- package/dist/serializer/comment/pre-processor-comment-serializer.js +0 -71
- package/dist/serializer/comment/simple-comment-serializer.js +0 -52
- package/dist/serializer/cosmetic/body/abp-snippet-injection-body-serializer.js +0 -36
- package/dist/serializer/cosmetic/body/adg-scriptlet-injection-body-serializer.js +0 -36
- package/dist/serializer/cosmetic/body/scriptlet-body-serializer.js +0 -50
- package/dist/serializer/cosmetic/body/ubo-scriptlet-injection-body-serializer.js +0 -36
- package/dist/serializer/cosmetic/cosmetic-rule-serializer.js +0 -120
- package/dist/serializer/cosmetic/css-injection-body-serializer.js +0 -51
- package/dist/serializer/cosmetic/element-hiding-body-serializer.js +0 -40
- package/dist/serializer/empty-rule-serializer.js +0 -37
- package/dist/serializer/filterlist-serializer.js +0 -45
- package/dist/serializer/index.js +0 -7
- package/dist/serializer/invalid-rule-error-node-serializer.js +0 -41
- package/dist/serializer/invalid-rule-serializer.js +0 -40
- package/dist/serializer/misc/domain-list-serializer.js +0 -64
- package/dist/serializer/misc/list-item-serializer.js +0 -58
- package/dist/serializer/misc/list-items-serializer.js +0 -29
- package/dist/serializer/misc/logical-expression-serializer.js +0 -136
- package/dist/serializer/misc/modifier-list-serializer.js +0 -58
- package/dist/serializer/misc/modifier-serializer.js +0 -49
- package/dist/serializer/misc/parameter-list-serializer.js +0 -52
- package/dist/serializer/misc/value-serializer.js +0 -50
- package/dist/serializer/network/host-rule-serializer.js +0 -70
- package/dist/serializer/network/hostname-list-serializer.js +0 -53
- package/dist/serializer/network/network-rule-serializer.js +0 -54
- package/dist/serializer/rule-serializer.js +0 -61
- package/dist/types/deserializer/base-deserializer.d.ts +0 -15
- package/dist/types/deserializer/comment/agent-comment-deserializer.d.ts +0 -34
- package/dist/types/deserializer/comment/agent-deserializer.d.ts +0 -25
- package/dist/types/deserializer/comment/comment-rule-deserializer.d.ts +0 -16
- package/dist/types/deserializer/comment/config-comment-deserializer.d.ts +0 -27
- package/dist/types/deserializer/comment/hint-comment-deserializer.d.ts +0 -24
- package/dist/types/deserializer/comment/hint-deserializer.d.ts +0 -26
- package/dist/types/deserializer/comment/metadata-comment-deserializer.d.ts +0 -26
- package/dist/types/deserializer/comment/pre-processor-comment-deserializer.d.ts +0 -29
- package/dist/types/deserializer/comment/simple-comment-deserializer.d.ts +0 -26
- package/dist/types/deserializer/cosmetic/cosmetic-rule-deserializer.d.ts +0 -18
- package/dist/types/deserializer/cosmetic/css-injection-body-deserializer.d.ts +0 -15
- package/dist/types/deserializer/cosmetic/element-hiding-body-deserializer.d.ts +0 -16
- package/dist/types/deserializer/cosmetic/scriptlet-body/abp-snippet-injection-body-deserializer.d.ts +0 -17
- package/dist/types/deserializer/cosmetic/scriptlet-body/adg-scriptlet-injection-body-deserializer.d.ts +0 -18
- package/dist/types/deserializer/cosmetic/scriptlet-body/scriptlet-body-deserializer.d.ts +0 -19
- package/dist/types/deserializer/cosmetic/scriptlet-body/ubo-scriptlet-injection-body-deserializer.d.ts +0 -17
- package/dist/types/deserializer/empty-rule-deserializer.d.ts +0 -16
- package/dist/types/deserializer/filterlist-deserializer.d.ts +0 -34
- package/dist/types/deserializer/index.d.ts +0 -2
- package/dist/types/deserializer/invalid-rule-deserializer.d.ts +0 -16
- package/dist/types/deserializer/invalid-rule-error-node-deserializer.d.ts +0 -16
- package/dist/types/deserializer/misc/domain-list-deserializer.d.ts +0 -15
- package/dist/types/deserializer/misc/list-item-deserializer.d.ts +0 -19
- package/dist/types/deserializer/misc/list-items-deserializer.d.ts +0 -16
- package/dist/types/deserializer/misc/logical-expression-deserializer.d.ts +0 -55
- package/dist/types/deserializer/misc/modifier-deserializer.d.ts +0 -18
- package/dist/types/deserializer/misc/modifier-list-deserializer.d.ts +0 -20
- package/dist/types/deserializer/misc/parameter-list-deserializer.d.ts +0 -18
- package/dist/types/deserializer/misc/value-deserializer.d.ts +0 -17
- package/dist/types/deserializer/network/host-rule-deserializer.d.ts +0 -18
- package/dist/types/deserializer/network/hostname-list-deserializer.d.ts +0 -15
- package/dist/types/deserializer/network/network-rule-deserializer.d.ts +0 -18
- package/dist/types/deserializer/rule-deserializer.d.ts +0 -17
- package/dist/types/deserializer/syntax-deserialization-map.d.ts +0 -2
- package/dist/types/marshalling-utils/comment/agent-comment-common.d.ts +0 -14
- package/dist/types/marshalling-utils/comment/agent-common.d.ts +0 -20
- package/dist/types/marshalling-utils/comment/config-comment-common.d.ts +0 -42
- package/dist/types/marshalling-utils/comment/hint-comment-common.d.ts +0 -15
- package/dist/types/marshalling-utils/comment/hint-common.d.ts +0 -33
- package/dist/types/marshalling-utils/comment/metadata-comment-common.d.ts +0 -21
- package/dist/types/marshalling-utils/comment/pre-processor-comment-common.d.ts +0 -37
- package/dist/types/marshalling-utils/comment/simple-comment-common.d.ts +0 -15
- package/dist/types/marshalling-utils/cosmetic/body/abp-snippet-injection-body-common.d.ts +0 -23
- package/dist/types/marshalling-utils/cosmetic/body/adg-scriptlet-injection-body-common.d.ts +0 -9
- package/dist/types/marshalling-utils/cosmetic/body/css-injection-body-common.d.ts +0 -17
- package/dist/types/marshalling-utils/cosmetic/body/element-hiding-body-common.d.ts +0 -14
- package/dist/types/marshalling-utils/cosmetic/body/ubo-scriptlet-injection-body-common.d.ts +0 -9
- package/dist/types/marshalling-utils/cosmetic/cosmetic-rule-common.d.ts +0 -28
- package/dist/types/marshalling-utils/empty-rule-common.d.ts +0 -13
- package/dist/types/marshalling-utils/filter-list-common.d.ts +0 -14
- package/dist/types/marshalling-utils/invalid-rule-common.d.ts +0 -14
- package/dist/types/marshalling-utils/invalid-rule-error-node-common.d.ts +0 -15
- package/dist/types/marshalling-utils/misc/binary-type-common.d.ts +0 -57
- package/dist/types/marshalling-utils/misc/domain-list-common.d.ts +0 -24
- package/dist/types/marshalling-utils/misc/host-rule-common.d.ts +0 -18
- package/dist/types/marshalling-utils/misc/hostname-list-common.d.ts +0 -14
- package/dist/types/marshalling-utils/misc/list-item-common.d.ts +0 -15
- package/dist/types/marshalling-utils/misc/logical-expression-common.d.ts +0 -47
- package/dist/types/marshalling-utils/misc/modifier-common.d.ts +0 -41
- package/dist/types/marshalling-utils/misc/modifier-list-common.d.ts +0 -14
- package/dist/types/marshalling-utils/misc/parameter-list-common.d.ts +0 -14
- package/dist/types/marshalling-utils/misc/value-common.d.ts +0 -15
- package/dist/types/marshalling-utils/network/network-rule-common.d.ts +0 -18
- package/dist/types/marshalling-utils/syntax-serialization-map.d.ts +0 -2
- package/dist/types/serializer/base-serializer.d.ts +0 -15
- package/dist/types/serializer/comment/agent-comment-serializer.d.ts +0 -34
- package/dist/types/serializer/comment/agent-serializer.d.ts +0 -15
- package/dist/types/serializer/comment/comment-rule-serializer.d.ts +0 -68
- package/dist/types/serializer/comment/config-comment-serializer.d.ts +0 -25
- package/dist/types/serializer/comment/hint-comment-serializer.d.ts +0 -23
- package/dist/types/serializer/comment/hint-serializer.d.ts +0 -24
- package/dist/types/serializer/comment/metadata-comment-serializer.d.ts +0 -25
- package/dist/types/serializer/comment/pre-processor-comment-serializer.d.ts +0 -28
- package/dist/types/serializer/comment/simple-comment-serializer.d.ts +0 -24
- package/dist/types/serializer/cosmetic/body/abp-snippet-injection-body-serializer.d.ts +0 -25
- package/dist/types/serializer/cosmetic/body/adg-scriptlet-injection-body-serializer.d.ts +0 -25
- package/dist/types/serializer/cosmetic/body/scriptlet-body-serializer.d.ts +0 -17
- package/dist/types/serializer/cosmetic/body/ubo-scriptlet-injection-body-serializer.d.ts +0 -25
- package/dist/types/serializer/cosmetic/cosmetic-rule-serializer.d.ts +0 -19
- package/dist/types/serializer/cosmetic/css-injection-body-serializer.d.ts +0 -15
- package/dist/types/serializer/cosmetic/element-hiding-body-serializer.d.ts +0 -15
- package/dist/types/serializer/empty-rule-serializer.d.ts +0 -15
- package/dist/types/serializer/filterlist-serializer.d.ts +0 -15
- package/dist/types/serializer/index.d.ts +0 -1
- package/dist/types/serializer/invalid-rule-error-node-serializer.d.ts +0 -15
- package/dist/types/serializer/invalid-rule-serializer.d.ts +0 -15
- package/dist/types/serializer/misc/domain-list-serializer.d.ts +0 -21
- package/dist/types/serializer/misc/list-item-serializer.d.ts +0 -16
- package/dist/types/serializer/misc/list-items-serializer.d.ts +0 -15
- package/dist/types/serializer/misc/logical-expression-serializer.d.ts +0 -52
- package/dist/types/serializer/misc/modifier-list-serializer.d.ts +0 -20
- package/dist/types/serializer/misc/modifier-serializer.d.ts +0 -18
- package/dist/types/serializer/misc/parameter-list-serializer.d.ts +0 -17
- package/dist/types/serializer/misc/value-serializer.d.ts +0 -17
- package/dist/types/serializer/network/host-rule-serializer.d.ts +0 -30
- package/dist/types/serializer/network/hostname-list-serializer.d.ts +0 -15
- package/dist/types/serializer/network/network-rule-serializer.d.ts +0 -18
- package/dist/types/serializer/rule-serializer.d.ts +0 -17
- package/dist/types/utils/binary-schema-version.d.ts +0 -9
- package/dist/types/utils/byte-buffer.d.ts +0 -54
- package/dist/types/utils/input-byte-buffer.d.ts +0 -146
- package/dist/types/utils/is-chromium.d.ts +0 -7
- package/dist/types/utils/output-byte-buffer.d.ts +0 -132
- package/dist/types/utils/storage-interface.d.ts +0 -23
- package/dist/types/utils/text-decoder-polyfill.d.ts +0 -14
- package/dist/types/utils/text-encoder-polyfill.d.ts +0 -18
- package/dist/utils/binary-schema-version.js +0 -17
- package/dist/utils/byte-buffer.js +0 -91
- package/dist/utils/input-byte-buffer.js +0 -266
- package/dist/utils/is-chromium.js +0 -20
- package/dist/utils/output-byte-buffer.js +0 -231
- package/dist/utils/text-decoder-polyfill.js +0 -107
- package/dist/utils/text-encoder-polyfill.js +0 -78
- /package/dist/types/generator/cosmetic/{body → scriptlet-body}/abp-snippet-injection-body-generator.d.ts +0 -0
- /package/dist/types/generator/cosmetic/{body → scriptlet-body}/adg-scriptlet-injection-body-generator.d.ts +0 -0
- /package/dist/types/generator/cosmetic/{body → scriptlet-body}/ubo-scriptlet-injection-body-generator.d.ts +0 -0
- /package/dist/types/parser/cosmetic/{body → scriptlet-body}/abp-snippet-injection-body-parser.d.ts +0 -0
- /package/dist/types/parser/cosmetic/{body → scriptlet-body}/adg-scriptlet-injection-body-parser.d.ts +0 -0
- /package/dist/types/parser/cosmetic/{body → scriptlet-body}/ubo-scriptlet-injection-body-parser.d.ts +0 -0
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* AGTree
|
|
3
|
-
* (c)
|
|
2
|
+
* AGTree v4.0.1 (build date: Thu, 19 Feb 2026 05:13:05 GMT)
|
|
3
|
+
* (c) 2026 Adguard Software Ltd.
|
|
4
4
|
* Released under the MIT license
|
|
5
5
|
* https://github.com/AdguardTeam/tsurlfilter/tree/master/packages/agtree#readme
|
|
6
6
|
*/
|
|
7
|
-
import { getFormattedTokenName, TokenType } from '@adguard/css-tokenizer';
|
|
8
7
|
import { sprintf } from 'sprintf-js';
|
|
9
8
|
import { CosmeticRuleSeparator, CosmeticRuleType, RuleCategory } from '../../nodes/index.js';
|
|
10
9
|
import { AdblockSyntax } from '../../utils/adblockers.js';
|
|
11
10
|
import { RuleConversionError } from '../../errors/rule-conversion-error.js';
|
|
12
11
|
import { RuleConverterBase } from '../base-interfaces/rule-converter-base.js';
|
|
13
|
-
import { RegExpUtils } from '../../utils/regexp.js';
|
|
14
12
|
import { createNodeConversionResult } from '../base-interfaces/conversion-result.js';
|
|
15
13
|
import { cloneDomainListNode } from '../../ast-utils/clone.js';
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import '
|
|
20
|
-
import {
|
|
21
|
-
import '
|
|
22
|
-
import '../../parser/css/balancing.js';
|
|
14
|
+
import { EMPTY, EQUALS } from '../../utils/constants.js';
|
|
15
|
+
import { RegExpUtils } from '../../utils/regexp.js';
|
|
16
|
+
import { AdgHtmlFilteringBodyParser } from '../../parser/cosmetic/html-filtering-body/adg-html-filtering-body-parser.js';
|
|
17
|
+
import { UboHtmlFilteringBodyParser } from '../../parser/cosmetic/html-filtering-body/ubo-html-filtering-body-parser.js';
|
|
18
|
+
import { AdgHtmlFilteringBodyGenerator } from '../../generator/cosmetic/html-filtering-body/adg-html-filtering-body-generator.js';
|
|
19
|
+
import { UboHtmlFilteringBodyGenerator } from '../../generator/cosmetic/html-filtering-body/ubo-html-filtering-body-generator.js';
|
|
23
20
|
|
|
24
21
|
/**
|
|
25
22
|
* @file HTML filtering rule converter
|
|
@@ -35,152 +32,82 @@ import '../../parser/css/balancing.js';
|
|
|
35
32
|
*/
|
|
36
33
|
const ADG_HTML_DEFAULT_MAX_LENGTH = 8192;
|
|
37
34
|
const ADG_HTML_CONVERSION_MAX_LENGTH = ADG_HTML_DEFAULT_MAX_LENGTH * 32;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Supported special pseudo-classes from uBlock.
|
|
37
|
+
*
|
|
38
|
+
* Note: If new pseudo-classes are added here, ensure to update
|
|
39
|
+
* the set and logic in the converter methods accordingly.
|
|
40
|
+
*/
|
|
41
|
+
const UboPseudoClasses = {
|
|
41
42
|
HasText: 'has-text',
|
|
42
43
|
MinTextLength: 'min-text-length',
|
|
43
44
|
};
|
|
44
45
|
/**
|
|
45
|
-
*
|
|
46
|
+
* Supported special attribute selectors from AdGuard.
|
|
46
47
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* @returns pseudo-class string, including pseudo-class name, value and delimiters.
|
|
48
|
+
* Note: If new pseudo-classes are added here, ensure to update
|
|
49
|
+
* the set and logic in the converter methods accordingly.
|
|
50
50
|
*/
|
|
51
|
-
const
|
|
52
|
-
return `${CSS_PSEUDO_MARKER}${pseudo}${CSS_PSEUDO_OPEN}${value}${CSS_PSEUDO_CLOSE}`;
|
|
53
|
-
};
|
|
54
|
-
const AttributeSelectors = {
|
|
51
|
+
const AdgAttributeSelectors = {
|
|
55
52
|
MaxLength: 'max-length',
|
|
56
53
|
MinLength: 'min-length',
|
|
57
|
-
TagContent: 'tag-content'
|
|
58
|
-
|
|
59
|
-
PseudoClasses.Contains,
|
|
60
|
-
PseudoClasses.HasText,
|
|
61
|
-
PseudoClasses.MinTextLength,
|
|
62
|
-
]);
|
|
63
|
-
const ERROR_MESSAGES = {
|
|
64
|
-
ABP_NOT_SUPPORTED: 'Invalid rule, ABP does not support HTML filtering rules',
|
|
65
|
-
TAG_SHOULD_BE_FIRST_CHILD: "Unexpected token '%s' with value '%s', tag selector should be the first child",
|
|
66
|
-
INVALID_ATTRIBUTE_NAME: "Attribute name should be an identifier, but got '%s' with value '%s'",
|
|
67
|
-
// eslint-disable-next-line max-len
|
|
68
|
-
INVALID_ATTRIBUTE_VALUE: `Expected '${getFormattedTokenName(TokenType.Ident)}' or '${getFormattedTokenName(TokenType.String)}' as attribute value, but got '%s' with value '%s`,
|
|
69
|
-
VALUE_FOR_ATTR_SHOULD_BE_INT: "Value for '%s' attribute should be an integer, but got '%s'",
|
|
70
|
-
INVALID_PSEUDO_CLASS: "Unsupported pseudo class '%s'",
|
|
71
|
-
VALUE_FOR_PSEUDO_CLASS_SHOULD_BE_INT: "Value for '%s' pseudo class should be an integer, but got '%s'",
|
|
72
|
-
// eslint-disable-next-line max-len
|
|
73
|
-
REGEXP_NOT_SUPPORTED: "Cannot convert RegExp parameter '%s' from '%s' pseudo class, because converting RegExp patterns are not supported yet",
|
|
74
|
-
ATTRIBUTE_SELECTOR_REQUIRES_VALUE: "Attribute selector '%s' requires a value",
|
|
75
|
-
VALUE_SHOULD_BE_SPECIFIED: 'Value should be specified if operator is specified',
|
|
76
|
-
VALUE_SHOULD_BE_POSITIVE: 'Value should be positive',
|
|
77
|
-
UNEXPECTED_TOKEN_WITH_VALUE: "Unexpected token '%s' with value '%s'",
|
|
78
|
-
FLAGS_NOT_SUPPORTED: 'Flags are not supported for attribute selectors',
|
|
54
|
+
TagContent: 'tag-content',
|
|
55
|
+
Wildcard: 'wildcard',
|
|
79
56
|
};
|
|
80
57
|
/**
|
|
81
|
-
*
|
|
58
|
+
* Supported special pseudo-classes from AdGuard.
|
|
82
59
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* @note In the legacy syntax, `""` is used to escape double quotes, but it cannot be used in the standard CSS syntax,
|
|
86
|
-
* so we use conversion functions to handle this.
|
|
87
|
-
* @see {@link https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#tag-content}
|
|
60
|
+
* Note: If new pseudo-classes are added here, ensure to update
|
|
61
|
+
* the set and logic in the converter methods accordingly.
|
|
88
62
|
*/
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
for (let i = 0; i < selector.length; i += 1) {
|
|
93
|
-
if (!withinString && selector[i] === DOUBLE_QUOTE_MARKER) {
|
|
94
|
-
withinString = true;
|
|
95
|
-
buffer.push(selector[i]);
|
|
96
|
-
}
|
|
97
|
-
else if (withinString && selector[i] === DOUBLE_QUOTE_MARKER && selector[i + 1] === DOUBLE_QUOTE_MARKER) {
|
|
98
|
-
buffer.push(ESCAPE_CHARACTER);
|
|
99
|
-
buffer.push(DOUBLE_QUOTE_MARKER);
|
|
100
|
-
i += 1;
|
|
101
|
-
}
|
|
102
|
-
else if (withinString && selector[i] === DOUBLE_QUOTE_MARKER && selector[i + 1] !== DOUBLE_QUOTE_MARKER) {
|
|
103
|
-
buffer.push(DOUBLE_QUOTE_MARKER);
|
|
104
|
-
withinString = false;
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
buffer.push(selector[i]);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return buffer.join(EMPTY);
|
|
111
|
-
}
|
|
63
|
+
const AdgPseudoClasses = {
|
|
64
|
+
Contains: 'contains',
|
|
65
|
+
};
|
|
112
66
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* @param value The string value to parse
|
|
116
|
-
* @param attrName The attribute name for error messages
|
|
117
|
-
* @returns Parsed number
|
|
118
|
-
* @throws A {@link RuleConversionError} if parsing fails
|
|
67
|
+
* Set of {@link UboPseudoClasses}.
|
|
119
68
|
*/
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
throw new RuleConversionError(sprintf(ERROR_MESSAGES.VALUE_FOR_ATTR_SHOULD_BE_INT, attrName, value));
|
|
125
|
-
}
|
|
126
|
-
if (parsed < 0) {
|
|
127
|
-
throw new RuleConversionError(sprintf(ERROR_MESSAGES.VALUE_SHOULD_BE_POSITIVE, attrName, value));
|
|
128
|
-
}
|
|
129
|
-
return parsed;
|
|
130
|
-
}
|
|
69
|
+
const SUPPORTED_UBO_PSEUDO_CLASSES = new Set([
|
|
70
|
+
UboPseudoClasses.HasText,
|
|
71
|
+
UboPseudoClasses.MinTextLength,
|
|
72
|
+
]);
|
|
131
73
|
/**
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* @param selector CSS selector string
|
|
135
|
-
* @returns Unescaped CSS selector
|
|
136
|
-
* @note In the legacy syntax, `""` is used to escape double quotes, but it cannot be used in the standard CSS syntax,
|
|
137
|
-
* so we use conversion functions to handle this.
|
|
138
|
-
* @see {@link https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#tag-content}
|
|
74
|
+
* Set of {@link AdgAttributeSelectors}.
|
|
139
75
|
*/
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
buffer.push(selector[i]);
|
|
147
|
-
}
|
|
148
|
-
else if (withinString && selector[i] === ESCAPE_CHARACTER && selector[i + 1] === DOUBLE_QUOTE_MARKER) {
|
|
149
|
-
buffer.push(DOUBLE_QUOTE_MARKER);
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
buffer.push(selector[i]);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
return buffer.join(EMPTY);
|
|
156
|
-
}
|
|
76
|
+
const SUPPORTED_ADG_ATTRIBUTE_SELECTORS = new Set([
|
|
77
|
+
AdgAttributeSelectors.MaxLength,
|
|
78
|
+
AdgAttributeSelectors.MinLength,
|
|
79
|
+
AdgAttributeSelectors.TagContent,
|
|
80
|
+
AdgAttributeSelectors.Wildcard,
|
|
81
|
+
]);
|
|
157
82
|
/**
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* @param attr Attribute name
|
|
161
|
-
* @param op Operator (optional)
|
|
162
|
-
* @param value Attribute value (optional)
|
|
163
|
-
* @param flags Attribute flags (optional)
|
|
164
|
-
* @returns Rendered attribute selector string
|
|
83
|
+
* Set of {@link AdgPseudoClasses}.
|
|
165
84
|
*/
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
85
|
+
const SUPPORTED_ADG_PSEUDO_CLASSES = new Set([
|
|
86
|
+
AdgPseudoClasses.Contains,
|
|
87
|
+
]);
|
|
88
|
+
/**
|
|
89
|
+
* Error messages used in HTML filtering rule conversion.
|
|
90
|
+
*/
|
|
91
|
+
/* eslint-disable max-len */
|
|
92
|
+
const ERROR_MESSAGES = {
|
|
93
|
+
ABP_NOT_SUPPORTED: 'Invalid rule, ABP does not support HTML filtering rules',
|
|
94
|
+
INVALID_RULE: 'Invalid HTML filtering rule: %s',
|
|
95
|
+
MIXED_SYNTAX_ADG_UBO: 'Mixed AdGuard and uBlock syntax',
|
|
96
|
+
EMPTY_SELECTOR_LIST: 'Selector list of HTML filtering rule must not be empty',
|
|
97
|
+
EMPTY_COMPLEX_SELECTOR: 'Complex selector of selector list must not be empty',
|
|
98
|
+
INVALID_SELECTOR_COMBINATOR: "Invalid selector combinator '%s' used between selectors",
|
|
99
|
+
UNKNOWN_SELECTOR_TYPE: "Unknown selector type '%s' found during conversion",
|
|
100
|
+
SPECIAL_ATTRIBUTE_SELECTOR_OPERATOR_INVALID: "Special attribute selector '%s' has invalid operator '%s'",
|
|
101
|
+
SPECIAL_ATTRIBUTE_SELECTOR_FLAG_NOT_SUPPORTED: "Special attribute selector '%s' does not support flags",
|
|
102
|
+
SPECIAL_ATTRIBUTE_SELECTOR_VALUE_REQUIRED: "Special attribute selector '%s' requires a value",
|
|
103
|
+
SPECIAL_ATTRIBUTE_SELECTOR_VALUE_INT: "Value of special attribute selector '%s' must be an integer, got '%s'",
|
|
104
|
+
SPECIAL_ATTRIBUTE_SELECTOR_VALUE_POSITIVE: "Value of special attribute selector '%s' must be a positive integer, got '%s'",
|
|
105
|
+
SPECIAL_ATTRIBUTE_SELECTOR_NOT_SUPPORTED: "Special attribute selector '%s' is not supported in conversion",
|
|
106
|
+
SPECIAL_PSEUDO_CLASS_SELECTOR_ARGUMENT_REQUIRED: "Special pseudo-class selector '%s' requires an argument",
|
|
107
|
+
SPECIAL_PSEUDO_CLASS_SELECTOR_ARGUMENT_INT: "Argument of special pseudo-class selector '%s' must be an integer, got '%s'",
|
|
108
|
+
SPECIAL_PSEUDO_CLASS_SELECTOR_ARGUMENT_POSITIVE: "Argument of special pseudo-class selector '%s' must be a positive integer, got '%s'",
|
|
109
|
+
SPECIAL_PSEUDO_CLASS_SELECTOR_NOT_SUPPORTED: "Special pseudo-class selector '%s' is not supported in conversion",
|
|
110
|
+
};
|
|
184
111
|
/**
|
|
185
112
|
* HTML filtering rule converter class
|
|
186
113
|
*
|
|
@@ -188,344 +115,559 @@ function renderAttrSelector(attr, op, value, flags) {
|
|
|
188
115
|
*/
|
|
189
116
|
class HtmlRuleConverter extends RuleConverterBase {
|
|
190
117
|
/**
|
|
191
|
-
* Converts a HTML rule to AdGuard syntax, if possible.
|
|
192
|
-
* AdGuard rules to AdGuard syntax to validate them.
|
|
118
|
+
* Converts a HTML rule to AdGuard syntax, if possible.
|
|
119
|
+
* Also can be used to convert AdGuard rules to AdGuard syntax to validate them.
|
|
193
120
|
*
|
|
194
|
-
*
|
|
195
|
-
* so the following rule
|
|
196
|
-
* ```
|
|
197
|
-
* example.com##^div[attr1="value1"][attr2="value2"], script:has-text(value)
|
|
198
|
-
* ```
|
|
199
|
-
* will be converted to multiple AdGuard rules:
|
|
200
|
-
* ```
|
|
201
|
-
* example.com$$div[attr1="value1"][attr2="value2"][max-length="262144"]
|
|
202
|
-
* example.com$$script[tag-content="value"][max-length="262144"]
|
|
203
|
-
* ```
|
|
121
|
+
* @param rule Rule node to convert.
|
|
204
122
|
*
|
|
205
|
-
* @param rule Rule node to convert
|
|
206
123
|
* @returns An object which follows the {@link NodeConversionResult} interface. Its `result` property contains
|
|
207
124
|
* the array of converted rule nodes, and its `isConverted` flag indicates whether the original rule was converted.
|
|
208
|
-
* If the rule was not converted, the result array will contain the original node with the same object reference
|
|
209
|
-
*
|
|
125
|
+
* If the rule was not converted, the result array will contain the original node with the same object reference.
|
|
126
|
+
*
|
|
127
|
+
* @throws If the rule is invalid or cannot be converted.
|
|
210
128
|
*/
|
|
211
129
|
static convertToAdg(rule) {
|
|
212
|
-
|
|
130
|
+
let parser;
|
|
131
|
+
let onSpecialAttributeSelector;
|
|
132
|
+
let onSpecialPseudoClassSelector;
|
|
133
|
+
let isConverted = false;
|
|
213
134
|
if (rule.syntax === AdblockSyntax.Adg) {
|
|
135
|
+
parser = AdgHtmlFilteringBodyParser;
|
|
136
|
+
onSpecialAttributeSelector = (name, value) => {
|
|
137
|
+
/**
|
|
138
|
+
* Mark rule as converted in ADG -> ADG conversion only if
|
|
139
|
+
* special attribute selectors are present in the rule body,
|
|
140
|
+
* because they are deprecated and will be removed soon,
|
|
141
|
+
* so we convert them to pseudo-class selectors
|
|
142
|
+
*/
|
|
143
|
+
isConverted = true;
|
|
144
|
+
return HtmlRuleConverter.convertSpecialAttributeSelectorAdgToAdg(name, value);
|
|
145
|
+
};
|
|
146
|
+
onSpecialPseudoClassSelector = HtmlRuleConverter.convertSpecialPseudoClassSelectorAdgToAdg;
|
|
147
|
+
}
|
|
148
|
+
else if (rule.syntax === AdblockSyntax.Ubo) {
|
|
149
|
+
/**
|
|
150
|
+
* Always mark rule as converted in UBO -> ADG conversion.
|
|
151
|
+
*/
|
|
152
|
+
isConverted = true;
|
|
153
|
+
parser = UboHtmlFilteringBodyParser;
|
|
154
|
+
onSpecialAttributeSelector = HtmlRuleConverter.convertSpecialAttributeSelectorUboToAdg;
|
|
155
|
+
onSpecialPseudoClassSelector = HtmlRuleConverter.convertSpecialPseudoClassSelectorUboToAdg;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
throw new RuleConversionError(ERROR_MESSAGES.ABP_NOT_SUPPORTED);
|
|
159
|
+
}
|
|
160
|
+
// Convert body
|
|
161
|
+
const convertedBody = HtmlRuleConverter.convertBody(rule.body, parser, AdgHtmlFilteringBodyGenerator, onSpecialAttributeSelector, onSpecialPseudoClassSelector);
|
|
162
|
+
if (!isConverted) {
|
|
163
|
+
return createNodeConversionResult([rule], false);
|
|
164
|
+
}
|
|
165
|
+
return createNodeConversionResult([{
|
|
166
|
+
category: RuleCategory.Cosmetic,
|
|
167
|
+
type: CosmeticRuleType.HtmlFilteringRule,
|
|
168
|
+
syntax: AdblockSyntax.Adg,
|
|
169
|
+
exception: rule.exception,
|
|
170
|
+
domains: cloneDomainListNode(rule.domains),
|
|
171
|
+
// Convert the separator based on the exception status
|
|
172
|
+
separator: {
|
|
173
|
+
type: 'Value',
|
|
174
|
+
value: rule.exception
|
|
175
|
+
? CosmeticRuleSeparator.AdgHtmlFilteringException
|
|
176
|
+
: CosmeticRuleSeparator.AdgHtmlFiltering,
|
|
177
|
+
},
|
|
178
|
+
body: convertedBody,
|
|
179
|
+
}], true);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Converts a HTML rule to uBlock syntax, if possible.
|
|
183
|
+
* Also can be used to convert uBlock rules to uBlock syntax to validate them.
|
|
184
|
+
*
|
|
185
|
+
* @param rule Rule node to convert.
|
|
186
|
+
*
|
|
187
|
+
* @returns An object which follows the {@link NodeConversionResult} interface. Its `result` property contains
|
|
188
|
+
* the array of converted rule nodes, and its `isConverted` flag indicates whether the original rule was converted.
|
|
189
|
+
* If the rule was not converted, the result array will contain the original node with the same object reference.
|
|
190
|
+
*
|
|
191
|
+
* @throws Error if the rule is invalid or cannot be converted.
|
|
192
|
+
*/
|
|
193
|
+
static convertToUbo(rule) {
|
|
194
|
+
// Ignore uBlock rules
|
|
195
|
+
if (rule.syntax === AdblockSyntax.Ubo) {
|
|
214
196
|
return createNodeConversionResult([rule], false);
|
|
215
197
|
}
|
|
216
198
|
if (rule.syntax === AdblockSyntax.Abp) {
|
|
217
199
|
throw new RuleConversionError(ERROR_MESSAGES.ABP_NOT_SUPPORTED);
|
|
218
200
|
}
|
|
219
|
-
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
201
|
+
// Convert body
|
|
202
|
+
const convertedBody = HtmlRuleConverter.convertBody(rule.body, AdgHtmlFilteringBodyParser, UboHtmlFilteringBodyGenerator, HtmlRuleConverter.convertSpecialAttributeSelectorAdgToUbo, HtmlRuleConverter.convertSpecialPseudoClassSelectorAdgToUbo);
|
|
203
|
+
return createNodeConversionResult([{
|
|
204
|
+
category: RuleCategory.Cosmetic,
|
|
205
|
+
type: CosmeticRuleType.HtmlFilteringRule,
|
|
206
|
+
syntax: AdblockSyntax.Ubo,
|
|
207
|
+
exception: rule.exception,
|
|
208
|
+
domains: cloneDomainListNode(rule.domains),
|
|
209
|
+
separator: {
|
|
210
|
+
type: 'Value',
|
|
211
|
+
value: rule.exception
|
|
212
|
+
? CosmeticRuleSeparator.ElementHidingException
|
|
213
|
+
: CosmeticRuleSeparator.ElementHiding,
|
|
214
|
+
},
|
|
215
|
+
body: convertedBody,
|
|
216
|
+
}], true);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Handles special attribute selectors during AdGuard to AdGuard conversion:
|
|
220
|
+
* - `[tag-content="content"]` -> `:contains(content)`
|
|
221
|
+
* direct conversion, no changes to value
|
|
222
|
+
* - `[wildcard="*content*"]` -> `:contains(/*.content*./s)`
|
|
223
|
+
* convert search pattern to regular expression
|
|
224
|
+
* - `[min-length="min"]` -> `:contains(/^(?=.{min,}$).*\/s)`
|
|
225
|
+
* converts to a length-matching regular expression
|
|
226
|
+
* - `[max-length="max"]` -> `:contains(/^(?=.{0,max}$).*\/s)`
|
|
227
|
+
* converts to a length-matching regular expression
|
|
228
|
+
*
|
|
229
|
+
* Note: This attribute selector to pseudo-class selector conversion
|
|
230
|
+
* is needed because AdGuard special attribute selectors are going
|
|
231
|
+
* to be deprecated and removed soon.
|
|
232
|
+
*
|
|
233
|
+
* @param name Name of the special attribute selector.
|
|
234
|
+
* @param value Value of the special attribute selector.
|
|
235
|
+
*
|
|
236
|
+
* @returns A {@link SimpleSelector} to add to the current complex selector.
|
|
237
|
+
*/
|
|
238
|
+
static convertSpecialAttributeSelectorAdgToAdg(name, value) {
|
|
239
|
+
switch (name) {
|
|
240
|
+
// `[tag-content="content"]` -> `:contains(content)`
|
|
241
|
+
// direct conversion, no changes to value
|
|
242
|
+
case AdgAttributeSelectors.TagContent: {
|
|
243
|
+
return HtmlRuleConverter.getPseudoClassSelectorNode(AdgPseudoClasses.Contains, value);
|
|
239
244
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
tempToken = stream.getOrFail();
|
|
259
|
-
// So check if the next non whitespace token is a closing square bracket
|
|
260
|
-
if (tempToken.type === TokenType.CloseSquareBracket) {
|
|
261
|
-
const { end } = tempToken;
|
|
262
|
-
stream.advance();
|
|
263
|
-
// Special case for min-length and max-length attributes
|
|
264
|
-
if (attr === AttributeSelectors.MinLength || attr === AttributeSelectors.MaxLength) {
|
|
265
|
-
throw new RuleConversionError(sprintf(ERROR_MESSAGES.ATTRIBUTE_SELECTOR_REQUIRES_VALUE, attr));
|
|
266
|
-
}
|
|
267
|
-
convertedSelector.push(source.slice(start, end));
|
|
268
|
-
continue;
|
|
269
|
-
}
|
|
270
|
-
// Next token should be a valid attribute selector operator
|
|
271
|
-
// Only '=' operator is supported
|
|
272
|
-
stream.expect(TokenType.Delim, { value: EQUALS });
|
|
273
|
-
// Advance the operator
|
|
274
|
-
stream.advance();
|
|
275
|
-
// Skip optional whitespace after the operator
|
|
276
|
-
stream.skipWhitespace();
|
|
277
|
-
// Parse attribute value
|
|
278
|
-
tempToken = stream.getOrFail();
|
|
279
|
-
// According to the spec, attribute value should be an identifier or a string
|
|
280
|
-
if (tempToken.type !== TokenType.Ident && tempToken.type !== TokenType.String) {
|
|
281
|
-
throw new RuleConversionError(sprintf(ERROR_MESSAGES.INVALID_ATTRIBUTE_VALUE, getFormattedTokenName(tempToken.type), source.slice(tempToken.start, tempToken.end)));
|
|
282
|
-
}
|
|
283
|
-
const value = source.slice(tempToken.start, tempToken.end);
|
|
284
|
-
// Advance the attribute value
|
|
285
|
-
stream.advance();
|
|
286
|
-
// Skip optional whitespace after the attribute value
|
|
287
|
-
stream.skipWhitespace();
|
|
288
|
-
// Attribute selector may have flags - but AdGuard HTML filtering does not support them
|
|
289
|
-
tempToken = stream.getOrFail();
|
|
290
|
-
if (tempToken.type === TokenType.Ident) {
|
|
291
|
-
throw new RuleConversionError(sprintf(ERROR_MESSAGES.FLAGS_NOT_SUPPORTED));
|
|
292
|
-
}
|
|
293
|
-
// Next token should be a closing square bracket
|
|
294
|
-
stream.expect(TokenType.CloseSquareBracket);
|
|
295
|
-
const { end } = stream.getOrFail();
|
|
296
|
-
stream.advance();
|
|
297
|
-
if (attr === AttributeSelectors.MinLength) {
|
|
298
|
-
// Min length attribute
|
|
299
|
-
const parsed = parseInt(value, 10);
|
|
300
|
-
if (Number.isNaN(parsed)) {
|
|
301
|
-
throw new RuleConversionError(sprintf(ERROR_MESSAGES.VALUE_FOR_ATTR_SHOULD_BE_INT, attr, value));
|
|
302
|
-
}
|
|
303
|
-
minLen = parsed;
|
|
304
|
-
}
|
|
305
|
-
else if (attr === AttributeSelectors.MaxLength) {
|
|
306
|
-
// Max length attribute
|
|
307
|
-
const parsed = parseInt(value, 10);
|
|
308
|
-
if (Number.isNaN(parsed)) {
|
|
309
|
-
throw new RuleConversionError(sprintf(ERROR_MESSAGES.VALUE_FOR_ATTR_SHOULD_BE_INT, attr, value));
|
|
310
|
-
}
|
|
311
|
-
maxLen = parsed;
|
|
245
|
+
// `[wildcard="*content*"] -> `:contains(/*.content*./s)`
|
|
246
|
+
// convert search pattern to regular expression
|
|
247
|
+
case AdgAttributeSelectors.Wildcard: {
|
|
248
|
+
return HtmlRuleConverter.getPseudoClassSelectorNode(AdgPseudoClasses.Contains, RegExpUtils.globToRegExp(value));
|
|
249
|
+
}
|
|
250
|
+
// `[min-length="min"]` -> `:contains(/^(?=.{min,}$).*\/s)`
|
|
251
|
+
// `[max-length="max"]` -> `:contains(/^(?=.{0,max}$).*\/s)`
|
|
252
|
+
// converts to a length-matching regular expression
|
|
253
|
+
case AdgAttributeSelectors.MinLength:
|
|
254
|
+
case AdgAttributeSelectors.MaxLength: {
|
|
255
|
+
// Validate length value
|
|
256
|
+
HtmlRuleConverter.assertValidLengthValue(name, value, ERROR_MESSAGES.SPECIAL_ATTRIBUTE_SELECTOR_VALUE_INT, ERROR_MESSAGES.SPECIAL_ATTRIBUTE_SELECTOR_VALUE_POSITIVE);
|
|
257
|
+
// It's safe to cast to number here after validation
|
|
258
|
+
const length = Number(value);
|
|
259
|
+
let min = null;
|
|
260
|
+
let max = null;
|
|
261
|
+
if (name === AdgAttributeSelectors.MinLength) {
|
|
262
|
+
min = length;
|
|
312
263
|
}
|
|
313
264
|
else {
|
|
314
|
-
|
|
265
|
+
max = length;
|
|
315
266
|
}
|
|
267
|
+
return HtmlRuleConverter.getPseudoClassSelectorNode(AdgPseudoClasses.Contains, RegExpUtils.getLengthRegexp(min, max));
|
|
316
268
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
stream.advance();
|
|
321
|
-
// Next token should be a pseudo class name
|
|
322
|
-
stream.expect(TokenType.Function);
|
|
323
|
-
tempToken = stream.getOrFail();
|
|
324
|
-
const fn = source.slice(tempToken.start, tempToken.end - 1); // do not include '('
|
|
325
|
-
// Pseudo class should be supported
|
|
326
|
-
if (!SUPPORTED_UBO_PSEUDO_CLASSES.has(fn)) {
|
|
327
|
-
throw new RuleConversionError(sprintf(ERROR_MESSAGES.INVALID_PSEUDO_CLASS, fn));
|
|
328
|
-
}
|
|
329
|
-
const paramStart = tempToken.end;
|
|
330
|
-
// Find the closing paren
|
|
331
|
-
stream.skipUntilBalanced();
|
|
332
|
-
tempToken = stream.getOrFail();
|
|
333
|
-
const paramEnd = tempToken.end;
|
|
334
|
-
// Get the parameter
|
|
335
|
-
const param = source.slice(paramStart, paramEnd - 1);
|
|
336
|
-
if (fn === PseudoClasses.MinTextLength) {
|
|
337
|
-
// Min text length pseudo class
|
|
338
|
-
// Parameter should be parsed as an integer
|
|
339
|
-
const parsed = parseInt(param, 10);
|
|
340
|
-
if (Number.isNaN(parsed)) {
|
|
341
|
-
throw new RuleConversionError(sprintf(ERROR_MESSAGES.VALUE_FOR_PSEUDO_CLASS_SHOULD_BE_INT, fn, param));
|
|
342
|
-
}
|
|
343
|
-
minLen = parsed;
|
|
344
|
-
}
|
|
345
|
-
else if (fn === PseudoClasses.Contains || fn === PseudoClasses.HasText) {
|
|
346
|
-
// Contains and has-text pseudo classes
|
|
347
|
-
// Check if the argument is a RegExp
|
|
348
|
-
if (RegExpUtils.isRegexPattern(param)) {
|
|
349
|
-
// TODO: Add some support for RegExp patterns later
|
|
350
|
-
// Need to find a way to convert some RegExp patterns to glob patterns
|
|
351
|
-
throw new RuleConversionError(sprintf(ERROR_MESSAGES.REGEXP_NOT_SUPPORTED, param, fn));
|
|
352
|
-
}
|
|
353
|
-
// Escape unescaped double quotes in the parameter
|
|
354
|
-
const paramEscaped = StringUtils.escapeCharacter(param, DOUBLE_QUOTE_MARKER);
|
|
355
|
-
convertedSelector.push(renderAttrSelector(AttributeSelectors.TagContent, EQUALS, paramEscaped));
|
|
356
|
-
}
|
|
357
|
-
stream.advance();
|
|
269
|
+
// This line is unreachable due to exhausted cases, but we keep it to satisfy TS
|
|
270
|
+
default: {
|
|
271
|
+
throw new RuleConversionError(sprintf(ERROR_MESSAGES.SPECIAL_ATTRIBUTE_SELECTOR_NOT_SUPPORTED, name));
|
|
358
272
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Since special pseudo-class selectors do not need conversion
|
|
277
|
+
* in AdGuard to AdGuard conversion, we simply return `true` to keep them as-is.
|
|
278
|
+
*
|
|
279
|
+
* @param name Name of the special pseudo-class selector.
|
|
280
|
+
*
|
|
281
|
+
* @returns `true` to keep the special pseudo-class selector as-is.
|
|
282
|
+
*
|
|
283
|
+
* @throws Rule conversion error for mixed syntax.
|
|
284
|
+
*/
|
|
285
|
+
static convertSpecialPseudoClassSelectorAdgToAdg(name) {
|
|
286
|
+
if (SUPPORTED_UBO_PSEUDO_CLASSES.has(name)) {
|
|
287
|
+
throw new RuleConversionError(sprintf(ERROR_MESSAGES.INVALID_RULE, ERROR_MESSAGES.MIXED_SYNTAX_ADG_UBO));
|
|
288
|
+
}
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Since special attribute selectors only AdGuard-specific,
|
|
293
|
+
* we should never encounter them in uBlock rules.
|
|
294
|
+
*
|
|
295
|
+
* @throws Rule conversion error for mixed syntax.
|
|
296
|
+
*/
|
|
297
|
+
static convertSpecialAttributeSelectorUboToAdg() {
|
|
298
|
+
throw new RuleConversionError(sprintf(ERROR_MESSAGES.INVALID_RULE, ERROR_MESSAGES.MIXED_SYNTAX_ADG_UBO));
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Handles special pseudo-class selectors during uBlock to AdGuard conversion:
|
|
302
|
+
* - `:has-text(text)` -> `:contains(text)`
|
|
303
|
+
* direct conversion, no changes to argument
|
|
304
|
+
* - `:min-text-length(min)` -> `:contains(/^(?=.{min,MAX_CONVERSION_DEFAULT}$).*\/s)`
|
|
305
|
+
* converts to a length-matching regular expression
|
|
306
|
+
*
|
|
307
|
+
* @param name Name of the special pseudo-class selector.
|
|
308
|
+
* @param argument Argument of the special pseudo-class selector.
|
|
309
|
+
*
|
|
310
|
+
* @returns A {@link SimpleSelector} to add to the current complex selector.
|
|
311
|
+
*
|
|
312
|
+
* @throws If AdGuard-specific pseudo-class selector is found in uBlock rule.
|
|
313
|
+
*/
|
|
314
|
+
static convertSpecialPseudoClassSelectorUboToAdg(name, argument) {
|
|
315
|
+
switch (name) {
|
|
316
|
+
// `:has-text(text)` -> `:contains(text)`
|
|
317
|
+
// direct conversion, no changes to argument
|
|
318
|
+
case UboPseudoClasses.HasText: {
|
|
319
|
+
return HtmlRuleConverter.getPseudoClassSelectorNode(AdgPseudoClasses.Contains, argument);
|
|
320
|
+
}
|
|
321
|
+
// `:min-text-length(min)` -> `:contains(/^(?=.{min,MAX_CONVERSION_DEFAULT}$).*\/s)`
|
|
322
|
+
// converts to a length-matching regular expression
|
|
323
|
+
case UboPseudoClasses.MinTextLength: {
|
|
324
|
+
// Validate length value
|
|
325
|
+
HtmlRuleConverter.assertValidLengthValue(name, argument, ERROR_MESSAGES.SPECIAL_PSEUDO_CLASS_SELECTOR_ARGUMENT_INT, ERROR_MESSAGES.SPECIAL_PSEUDO_CLASS_SELECTOR_ARGUMENT_POSITIVE);
|
|
326
|
+
// It's safe to cast to number here after validation
|
|
327
|
+
const minLength = Number(argument);
|
|
328
|
+
return HtmlRuleConverter.getPseudoClassSelectorNode(AdgPseudoClasses.Contains, RegExpUtils.getLengthRegexp(minLength, ADG_HTML_CONVERSION_MAX_LENGTH));
|
|
367
329
|
}
|
|
368
|
-
|
|
369
|
-
|
|
330
|
+
// Throw an error if the AdGuard-specific pseudo-class selector found in uBlock rule
|
|
331
|
+
case AdgPseudoClasses.Contains: {
|
|
332
|
+
throw new RuleConversionError(sprintf(ERROR_MESSAGES.INVALID_RULE, ERROR_MESSAGES.MIXED_SYNTAX_ADG_UBO));
|
|
370
333
|
}
|
|
371
|
-
|
|
372
|
-
|
|
334
|
+
// This line is unreachable due to exhausted cases, but we keep it to satisfy TS
|
|
335
|
+
default: {
|
|
336
|
+
throw new RuleConversionError(sprintf(ERROR_MESSAGES.SPECIAL_PSEUDO_CLASS_SELECTOR_NOT_SUPPORTED, name));
|
|
373
337
|
}
|
|
374
338
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Handles special attribute selectors during AdGuard to uBlock conversion:
|
|
342
|
+
* - `[tag-content="content"]` -> `:has-text(content)`
|
|
343
|
+
* direct conversion, no changes to value
|
|
344
|
+
* - `[wildcard="*content*"]` -> `:has-text(/*.content*./s)`
|
|
345
|
+
* convert search pattern to regular expression
|
|
346
|
+
* - `[min-length="min"]` -> `:min-text-length(min)`
|
|
347
|
+
* direct conversion, no changes to value
|
|
348
|
+
* - `[max-length]` is skipped
|
|
349
|
+
*
|
|
350
|
+
* @param name Name of the special attribute selector.
|
|
351
|
+
* @param value Value of the special attribute selector.
|
|
352
|
+
*
|
|
353
|
+
* @returns A {@link SimpleSelector} to add to the current complex selector, or `false` to skip it.
|
|
354
|
+
*/
|
|
355
|
+
static convertSpecialAttributeSelectorAdgToUbo(name, value) {
|
|
356
|
+
switch (name) {
|
|
357
|
+
// `[tag-content="content"]` -> `:has-text(content)`
|
|
358
|
+
// direct conversion, no changes to value
|
|
359
|
+
case AdgAttributeSelectors.TagContent: {
|
|
360
|
+
return HtmlRuleConverter.getPseudoClassSelectorNode(UboPseudoClasses.HasText, value);
|
|
361
|
+
}
|
|
362
|
+
// `[wildcard="*content*"] -> `:has-text(/*.content*./s)`
|
|
363
|
+
// convert search pattern to regular expression
|
|
364
|
+
case AdgAttributeSelectors.Wildcard: {
|
|
365
|
+
return HtmlRuleConverter.getPseudoClassSelectorNode(UboPseudoClasses.HasText, RegExpUtils.globToRegExp(value));
|
|
366
|
+
}
|
|
367
|
+
// `[min-length="min"]` -> `:min-text-length(min)`
|
|
368
|
+
// direct conversion, no changes to value
|
|
369
|
+
case AdgAttributeSelectors.MinLength: {
|
|
370
|
+
// Validate length value
|
|
371
|
+
HtmlRuleConverter.assertValidLengthValue(name, value, ERROR_MESSAGES.SPECIAL_ATTRIBUTE_SELECTOR_VALUE_INT, ERROR_MESSAGES.SPECIAL_ATTRIBUTE_SELECTOR_VALUE_POSITIVE);
|
|
372
|
+
return HtmlRuleConverter.getPseudoClassSelectorNode(UboPseudoClasses.MinTextLength, value);
|
|
373
|
+
}
|
|
374
|
+
// `[max-length]` is skipped
|
|
375
|
+
case AdgAttributeSelectors.MaxLength: {
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
// This line is unreachable due to exhausted cases, but we keep it to satisfy TS
|
|
379
|
+
default: {
|
|
380
|
+
throw new RuleConversionError(sprintf(ERROR_MESSAGES.SPECIAL_ATTRIBUTE_SELECTOR_NOT_SUPPORTED, name));
|
|
378
381
|
}
|
|
379
|
-
convertedSelector.push(renderAttrSelector(AttributeSelectors.MaxLength, EQUALS, maxLen !== NOT_SPECIFIED ? maxLen.toString() : ADG_HTML_CONVERSION_MAX_LENGTH.toString()));
|
|
380
|
-
convertedSelectorList.push(convertedSelector.join(EMPTY));
|
|
381
382
|
}
|
|
382
|
-
return createNodeConversionResult(
|
|
383
|
-
// Since AdGuard HTML filtering rules do not support multiple selectors, we need to split each selector
|
|
384
|
-
// into a separate rule node.
|
|
385
|
-
convertedSelectorList.map((selector) => ({
|
|
386
|
-
category: RuleCategory.Cosmetic,
|
|
387
|
-
type: CosmeticRuleType.HtmlFilteringRule,
|
|
388
|
-
syntax: AdblockSyntax.Adg,
|
|
389
|
-
exception: rule.exception,
|
|
390
|
-
domains: cloneDomainListNode(rule.domains),
|
|
391
|
-
// Convert the separator based on the exception status
|
|
392
|
-
separator: {
|
|
393
|
-
type: 'Value',
|
|
394
|
-
value: rule.exception
|
|
395
|
-
? CosmeticRuleSeparator.AdgHtmlFilteringException
|
|
396
|
-
: CosmeticRuleSeparator.AdgHtmlFiltering,
|
|
397
|
-
},
|
|
398
|
-
body: {
|
|
399
|
-
type: 'Value',
|
|
400
|
-
value: unescapeDoubleQuotes(selector),
|
|
401
|
-
},
|
|
402
|
-
})), true);
|
|
403
383
|
}
|
|
404
384
|
/**
|
|
405
|
-
*
|
|
385
|
+
* Handles special pseudo-class selectors during AdGuard to uBlock conversion:
|
|
386
|
+
* - `:contains(text)` -> `:has-text(text)`
|
|
387
|
+
* direct conversion, no changes to argument
|
|
406
388
|
*
|
|
407
|
-
* @
|
|
408
|
-
*
|
|
409
|
-
* uBlock's `:min-text-length()` and `:has-text()` pseudo-classes when possible.
|
|
389
|
+
* @param name Name of the special pseudo-class selector.
|
|
390
|
+
* @param argument Argument of the special pseudo-class selector.
|
|
410
391
|
*
|
|
411
|
-
* @
|
|
412
|
-
*
|
|
413
|
-
*
|
|
414
|
-
* If the rule was not converted, the result array will contain the original node with the same object reference
|
|
415
|
-
* @throws Error if the rule is invalid or cannot be converted
|
|
392
|
+
* @returns A {@link SimpleSelector} to add to the current complex selector.
|
|
393
|
+
*
|
|
394
|
+
* @throws If uBlock-specific pseudo-class selector is found in AdGuard rule.
|
|
416
395
|
*/
|
|
417
|
-
static
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
396
|
+
static convertSpecialPseudoClassSelectorAdgToUbo(name, argument) {
|
|
397
|
+
switch (name) {
|
|
398
|
+
// `:contains(text)` -> `:has-text(text)`
|
|
399
|
+
// direct conversion, no changes to argument
|
|
400
|
+
case AdgPseudoClasses.Contains: {
|
|
401
|
+
return HtmlRuleConverter.getPseudoClassSelectorNode(UboPseudoClasses.HasText, argument);
|
|
402
|
+
}
|
|
403
|
+
// Throw an error if the uBlock-specific pseudo-class selector found in AdGuard rule
|
|
404
|
+
case UboPseudoClasses.HasText:
|
|
405
|
+
case UboPseudoClasses.MinTextLength: {
|
|
406
|
+
throw new RuleConversionError(sprintf(ERROR_MESSAGES.INVALID_RULE, ERROR_MESSAGES.MIXED_SYNTAX_ADG_UBO));
|
|
407
|
+
}
|
|
408
|
+
// This line is unreachable due to exhausted cases, but we keep it to satisfy TS
|
|
409
|
+
default: {
|
|
410
|
+
throw new RuleConversionError(sprintf(ERROR_MESSAGES.SPECIAL_PSEUDO_CLASS_SELECTOR_NOT_SUPPORTED, name));
|
|
411
|
+
}
|
|
421
412
|
}
|
|
422
|
-
|
|
423
|
-
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Converts a HTML filtering rule body by handling special simple selectors via callbacks.
|
|
416
|
+
* Special simple selectors are skipped in the converted selector list and should be handled from callee.
|
|
417
|
+
*
|
|
418
|
+
* @param body HTML filtering rule body to convert.
|
|
419
|
+
* @param parser HTML filtering rule body parser used for parsing raw value bodies.
|
|
420
|
+
* @param generator HTML filtering rule body generator used for generating raw value bodies.
|
|
421
|
+
* @param onSpecialAttributeSelector Callback invoked when a special attribute selector is found.
|
|
422
|
+
* @param onSpecialPseudoClassSelector Callback invoked when a special pseudo-class selector is found.
|
|
423
|
+
*
|
|
424
|
+
* @returns Converted selector list without special simple selectors.
|
|
425
|
+
*/
|
|
426
|
+
static convertBody(body, parser, generator, onSpecialAttributeSelector, onSpecialPseudoClassSelector) {
|
|
427
|
+
// Handle case when body is raw value string.
|
|
428
|
+
// If so, parse it first as we need to work with AST nodes.
|
|
429
|
+
let processedBody;
|
|
430
|
+
if (body.type === 'Value') {
|
|
431
|
+
processedBody = parser.parse(body.value, {
|
|
432
|
+
isLocIncluded: false,
|
|
433
|
+
parseHtmlFilteringRuleBodies: true,
|
|
434
|
+
});
|
|
424
435
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
//
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
436
|
+
else {
|
|
437
|
+
processedBody = body;
|
|
438
|
+
}
|
|
439
|
+
const { children: complexSelectors } = processedBody.selectorList;
|
|
440
|
+
// Selector list node must not be empty
|
|
441
|
+
HtmlRuleConverter.assertNotEmpty(complexSelectors, ERROR_MESSAGES.EMPTY_SELECTOR_LIST);
|
|
442
|
+
// Convert each complex selector
|
|
443
|
+
const convertedComplexSelectors = [];
|
|
444
|
+
for (let i = 0; i < complexSelectors.length; i += 1) {
|
|
445
|
+
const { children: selectors } = complexSelectors[i];
|
|
446
|
+
// Complex selector node must not be empty
|
|
447
|
+
HtmlRuleConverter.assertNotEmpty(selectors, ERROR_MESSAGES.EMPTY_COMPLEX_SELECTOR);
|
|
448
|
+
// Convert each selector
|
|
449
|
+
const convertedSelectors = [];
|
|
450
|
+
for (let j = 0; j < selectors.length; j += 1) {
|
|
451
|
+
const selector = selectors[j];
|
|
452
|
+
switch (selector.type) {
|
|
453
|
+
case 'SelectorCombinator': {
|
|
454
|
+
// Throw if selector combinator used incorrectly
|
|
455
|
+
if (
|
|
456
|
+
// If first selector in the complex selector (`> div`)
|
|
457
|
+
j === 0
|
|
458
|
+
// If the previous selector is also a combinator (`div > + span`)
|
|
459
|
+
|| j === selectors.length - 1
|
|
460
|
+
// If the last selector in the complex selector (`div +`)
|
|
461
|
+
|| (j > 0 && selectors[j - 1].type === 'SelectorCombinator')) {
|
|
462
|
+
throw new RuleConversionError(sprintf(ERROR_MESSAGES.INVALID_RULE, sprintf(ERROR_MESSAGES.INVALID_SELECTOR_COMBINATOR, selector.value)));
|
|
463
|
+
}
|
|
464
|
+
break;
|
|
465
|
+
}
|
|
466
|
+
case 'AttributeSelector': {
|
|
467
|
+
// Not a special attribute selector - clone as-is after the switch
|
|
468
|
+
if (!SUPPORTED_ADG_ATTRIBUTE_SELECTORS.has(selector.name.value)) {
|
|
469
|
+
break;
|
|
470
|
+
}
|
|
471
|
+
// Throw an error if value is missing
|
|
472
|
+
if (!('value' in selector) || selector.value.value === EMPTY) {
|
|
473
|
+
throw new RuleConversionError(sprintf(ERROR_MESSAGES.SPECIAL_ATTRIBUTE_SELECTOR_VALUE_REQUIRED, selector.name.value));
|
|
474
|
+
}
|
|
475
|
+
// Throw an error if operator is not '='
|
|
476
|
+
if (selector.operator.value !== EQUALS) {
|
|
477
|
+
throw new RuleConversionError(sprintf(ERROR_MESSAGES.SPECIAL_ATTRIBUTE_SELECTOR_OPERATOR_INVALID, selector.name.value, selector.operator.value));
|
|
478
|
+
}
|
|
479
|
+
// Throw an error if flag is specified
|
|
480
|
+
if (selector.flag) {
|
|
481
|
+
throw new RuleConversionError(sprintf(ERROR_MESSAGES.SPECIAL_ATTRIBUTE_SELECTOR_FLAG_NOT_SUPPORTED, selector.name.value));
|
|
482
|
+
}
|
|
483
|
+
const name = selector.name.value;
|
|
484
|
+
const { value } = selector.value;
|
|
485
|
+
// Invoke callback and:
|
|
486
|
+
// - add returned simple selector if it's not boolean
|
|
487
|
+
// - skip adding if returned value is false
|
|
488
|
+
// - keep original simple selector if returned value is true
|
|
489
|
+
const result = onSpecialAttributeSelector(name, value);
|
|
490
|
+
if (typeof result !== 'boolean') {
|
|
491
|
+
convertedSelectors.push(result);
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
494
|
+
else if (result === false) {
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
break;
|
|
498
|
+
}
|
|
499
|
+
case 'PseudoClassSelector': {
|
|
500
|
+
// Not a special pseudo-class selector - clone as-is after the switch
|
|
501
|
+
if (!SUPPORTED_ADG_PSEUDO_CLASSES.has(selector.name.value)
|
|
502
|
+
&& !SUPPORTED_UBO_PSEUDO_CLASSES.has(selector.name.value)) {
|
|
503
|
+
break;
|
|
504
|
+
}
|
|
505
|
+
// Throw an error if argument is missing
|
|
506
|
+
if (!selector.argument || selector.argument.value === EMPTY) {
|
|
507
|
+
throw new RuleConversionError(sprintf(ERROR_MESSAGES.SPECIAL_PSEUDO_CLASS_SELECTOR_ARGUMENT_REQUIRED, selector.name.value));
|
|
508
|
+
}
|
|
509
|
+
const name = selector.name.value;
|
|
510
|
+
const argument = selector.argument.value;
|
|
511
|
+
// Invoke callback and:
|
|
512
|
+
// - add returned simple selector if it's not boolean
|
|
513
|
+
// - skip adding if returned value is false
|
|
514
|
+
// - keep original simple selector if returned value is true
|
|
515
|
+
const result = onSpecialPseudoClassSelector(name, argument);
|
|
516
|
+
if (typeof result !== 'boolean') {
|
|
517
|
+
convertedSelectors.push(result);
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
else if (result === false) {
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
break;
|
|
488
524
|
}
|
|
489
525
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
526
|
+
// Clone selector if previous conditions are not met
|
|
527
|
+
convertedSelectors.push(HtmlRuleConverter.cloneSelector(selector));
|
|
528
|
+
}
|
|
529
|
+
convertedComplexSelectors.push({
|
|
530
|
+
type: 'ComplexSelector',
|
|
531
|
+
children: convertedSelectors,
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
let convertedBody = {
|
|
535
|
+
type: 'HtmlFilteringRuleBody',
|
|
536
|
+
selectorList: {
|
|
537
|
+
type: 'SelectorList',
|
|
538
|
+
children: convertedComplexSelectors,
|
|
539
|
+
},
|
|
540
|
+
};
|
|
541
|
+
// Convert back to Value if the original body was Value
|
|
542
|
+
if (body.type === 'Value') {
|
|
543
|
+
convertedBody = {
|
|
544
|
+
type: 'Value',
|
|
545
|
+
value: generator.generate(convertedBody),
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
return convertedBody;
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Clones a simple selector or selector combinator node.
|
|
552
|
+
*
|
|
553
|
+
* @param selector Simple selector or selector combinator node to clone.
|
|
554
|
+
*
|
|
555
|
+
* @returns Cloned simple selector or selector combinator node.
|
|
556
|
+
*/
|
|
557
|
+
static cloneSelector(selector) {
|
|
558
|
+
const { type } = selector;
|
|
559
|
+
switch (type) {
|
|
560
|
+
case 'TypeSelector':
|
|
561
|
+
case 'IdSelector':
|
|
562
|
+
case 'ClassSelector':
|
|
563
|
+
return {
|
|
564
|
+
type: selector.type,
|
|
565
|
+
value: selector.value,
|
|
566
|
+
};
|
|
567
|
+
case 'SelectorCombinator':
|
|
568
|
+
return {
|
|
569
|
+
type: selector.type,
|
|
570
|
+
value: selector.value,
|
|
571
|
+
};
|
|
572
|
+
case 'AttributeSelector': {
|
|
573
|
+
const attributeSelectorClone = {
|
|
574
|
+
type: selector.type,
|
|
575
|
+
name: {
|
|
576
|
+
type: selector.name.type,
|
|
577
|
+
value: selector.name.value,
|
|
578
|
+
},
|
|
579
|
+
};
|
|
580
|
+
if ('value' in selector && selector.value) {
|
|
581
|
+
attributeSelectorClone.operator = {
|
|
582
|
+
type: selector.operator.type,
|
|
583
|
+
value: selector.operator.value,
|
|
584
|
+
};
|
|
585
|
+
attributeSelectorClone.value = {
|
|
586
|
+
type: selector.value.type,
|
|
587
|
+
value: selector.value.value,
|
|
588
|
+
};
|
|
589
|
+
if (selector.flag) {
|
|
590
|
+
attributeSelectorClone.flag = {
|
|
591
|
+
type: selector.flag.type,
|
|
592
|
+
value: selector.flag.value,
|
|
593
|
+
};
|
|
594
|
+
}
|
|
497
595
|
}
|
|
596
|
+
return attributeSelectorClone;
|
|
498
597
|
}
|
|
499
|
-
|
|
500
|
-
|
|
598
|
+
case 'PseudoClassSelector': {
|
|
599
|
+
const pseudoClassSelectorClone = {
|
|
600
|
+
type: selector.type,
|
|
601
|
+
name: {
|
|
602
|
+
type: selector.name.type,
|
|
603
|
+
value: selector.name.value,
|
|
604
|
+
},
|
|
605
|
+
};
|
|
606
|
+
if (selector.argument) {
|
|
607
|
+
pseudoClassSelectorClone.argument = {
|
|
608
|
+
type: selector.argument.type,
|
|
609
|
+
value: selector.argument.value,
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
return pseudoClassSelectorClone;
|
|
501
613
|
}
|
|
502
|
-
|
|
503
|
-
throw new RuleConversionError(sprintf(ERROR_MESSAGES.
|
|
614
|
+
default: {
|
|
615
|
+
throw new RuleConversionError(sprintf(ERROR_MESSAGES.INVALID_RULE, sprintf(ERROR_MESSAGES.UNKNOWN_SELECTOR_TYPE, type)));
|
|
504
616
|
}
|
|
505
617
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Creates a CSS pseudo-class selector node.
|
|
621
|
+
*
|
|
622
|
+
* @param name The name of the pseudo-class selector.
|
|
623
|
+
* @param argument Optional argument of the pseudo-class selector.
|
|
624
|
+
*
|
|
625
|
+
* @returns CSS pseudo-class selector node.
|
|
626
|
+
*/
|
|
627
|
+
static getPseudoClassSelectorNode(name, argument) {
|
|
628
|
+
return {
|
|
629
|
+
type: 'PseudoClassSelector',
|
|
630
|
+
name: {
|
|
631
|
+
type: 'Value',
|
|
632
|
+
value: name,
|
|
633
|
+
},
|
|
634
|
+
argument: argument ? {
|
|
635
|
+
type: 'Value',
|
|
636
|
+
value: argument,
|
|
637
|
+
} : undefined,
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Asserts that the given array is not empty.
|
|
642
|
+
*
|
|
643
|
+
* @param array Array to check.
|
|
644
|
+
* @param errorMessage Error message to use if the array is empty.
|
|
645
|
+
*
|
|
646
|
+
* @throws If the array is empty.
|
|
647
|
+
*/
|
|
648
|
+
static assertNotEmpty(array, errorMessage) {
|
|
649
|
+
if (array.length === 0) {
|
|
650
|
+
throw new RuleConversionError(sprintf(ERROR_MESSAGES.INVALID_RULE, errorMessage));
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Asserts that the given special attribute / pseudo-class length value is valid.
|
|
655
|
+
*
|
|
656
|
+
* @param name Name of the attribute or pseudo-class.
|
|
657
|
+
* @param value Value to parse.
|
|
658
|
+
* @param notIntErrorMessage Error message when the value is not an integer.
|
|
659
|
+
* @param notPositiveErrorMessage Error message when the value is not positive.
|
|
660
|
+
*
|
|
661
|
+
* @throws If the value is not a valid number or not positive.
|
|
662
|
+
*/
|
|
663
|
+
static assertValidLengthValue(name, value, notIntErrorMessage, notPositiveErrorMessage) {
|
|
664
|
+
const parsed = Number(value);
|
|
665
|
+
if (Number.isNaN(parsed)) {
|
|
666
|
+
throw new RuleConversionError(sprintf(notIntErrorMessage, name, value));
|
|
667
|
+
}
|
|
668
|
+
if (parsed < 0) {
|
|
669
|
+
throw new RuleConversionError(sprintf(notPositiveErrorMessage, name, value));
|
|
509
670
|
}
|
|
510
|
-
// Combine all selectors
|
|
511
|
-
const uboSelector = `${convertedSelector.join(EMPTY)}`;
|
|
512
|
-
return createNodeConversionResult([{
|
|
513
|
-
category: RuleCategory.Cosmetic,
|
|
514
|
-
type: CosmeticRuleType.HtmlFilteringRule,
|
|
515
|
-
syntax: AdblockSyntax.Ubo,
|
|
516
|
-
exception: rule.exception,
|
|
517
|
-
domains: cloneDomainListNode(rule.domains),
|
|
518
|
-
separator: {
|
|
519
|
-
type: 'Value',
|
|
520
|
-
value: rule.exception
|
|
521
|
-
? `${CosmeticRuleSeparator.ElementHidingException}${UBO_HTML_MASK}`
|
|
522
|
-
: `${CosmeticRuleSeparator.ElementHiding}${UBO_HTML_MASK}`,
|
|
523
|
-
},
|
|
524
|
-
body: {
|
|
525
|
-
type: 'Value',
|
|
526
|
-
value: unescapeDoubleQuotes(uboSelector),
|
|
527
|
-
},
|
|
528
|
-
}], true);
|
|
529
671
|
}
|
|
530
672
|
}
|
|
531
673
|
|