@adguard/ecss-tree

中文文档
2.0.3发布于 2026/06/30MITTypeScriptESM + CJS近 30 天下载 7596

Adblock Extended CSS fork for CSSTree

原始使用文档
文档目录14 节
  1. Table of contents
  2. Installation
  3. Supported Extended CSS elements
  4. Motivation
  5. Advanced validation
  6. Handle problematic cases
  7. Examples
  8. Reporting problems / Requesting features
  9. Contributing
  10. Development
  11. Documentation
  12. License
  13. Acknowledgements
  14. References
CSSTree logo

ECSSTree

NPM version NPM Downloads LICENSE

Adblock Extended CSS supplement for CSSTree. Our primary goal is to change the internal behavior of the CSSTree parser to support Extended CSS (ECSS) language elements, but we don't change the API or the AST structure. Therefore ECSSTree fully backwards compatible with CSSTree, so you can pass our AST to CSSTree functions and vice versa without any problems.

Note: This package is developed in AdGuardSoftwareLimited/ext-ecsstree. The AdguardTeam/ecsstree repository is a public mirror.

[!NOTE] If you are looking for a library that can parse CSS, but you don't know what is Adblock or Extended CSS, you should probably use CSSTree instead of this library :)

Table of contents

Installation

You can install the library using

  • PNPM: pnpm add @adguard/ecss-tree
  • NPM: npm install @adguard/ecss-tree
  • Yarn: yarn add @adguard/ecss-tree

Or you can use it via esm.run: https://esm.run/@adguard/ecss-tree

Supported Extended CSS elements

Currently, the following Extended CSS pseudo classes are supported:

In addition, CSSTree supports the following pseudo classes by default:

Also, CSSTree supports legacy Extended CSS elements by default (attribute selectors): [-ext-name="value"], where name is the name of the Extended CSS element and value is its value. For example, the following selector can be parsed by CSSTree:

[-ext-has="selector list"]

If a pseudo class is unknown to CSSTree, it tries to parse it as a Raw element (if possible - see problematic cases).

The CSSTree library itself is quite flexible and error-tolerant, so it basically manages well the Extended CSS elements that are not (yet) included here.

Motivation

For example, the following selector

div:-abp-has(> section)

will be parsed by the default CSSTree as follows

{
    "type": "Selector",
    "loc": null,
    "children": [
        {
            "type": "PseudoClassSelector",
            "loc": null,
            "name": "-abp-has",
            "children": [
                {
                    "type": "Raw",
                    "loc": null,
                    "value": "> section"
                }
            ]
        }
    ]
}

The problem with this is that the -abp-has parameter is parsed as Raw, not as a Selector, since -abp-has is an unknown pseudo class in CSS / CSSTree.

This is where the ECSSTree library comes into play. It detects that -abp-has expects a selector as a parameter, i.e. it parses the passed parameter as a Selector. This means that the selector above will be parsed as follows:

{
    "type": "Selector",
    "loc": null,
    "children": [
        {
            "type": "PseudoClassSelector",
            "loc": null,
            "name": "-abp-has",
            "children": [
                {
                    "type": "Selector",
                    "loc": null,
                    "children": [
                        {
                            "type": "Combinator",
                            "loc": null,
                            "name": ">"
                        },
                        {
                            "type": "TypeSelector",
                            "loc": null,
                            "name": "section"
                        }
                    ]
                }
            ]
        }
    ]
}

Combinator and similar Nodes are part of CSSTree, this fork simply specifies that the -abp-has parameter should be parsed as a selector. The nodes themselves are part of the CSSTree.

Advanced validation

In addition, this approach enables a more advanced validation. For example, the default CSSTree does not throw an error when parsing the following selector:

div:-abp-has(42)

since it doesn't know what -abp-has is, it simply parses 42 as Raw. ECSSTree parses the parameter as a selector, which will throw an error, since 42 is simply an invalid selector.

Handle problematic cases

The library also handles problematic selectors, such as the following:

div:contains(aaa'bbb)

This selector doesn't fully meet with CSS standards, so even if CSSTree is flexible, it will not be able to parse it properly, because it will tokenize it as follows:

Token typeStart indexEnd indexSource part
ident-token03div
colon-token34:
function-token413contains(
ident-token1316aaa
string-token1621'bbb)

At quote mark (') tokenizer will think that a string is starting, and it tokenizes the rest of the input as a string. This is the normal behavior for the tokenizer, but it is wrong for us, since the parser will fail with an ")" is expected error, as it doesn't found the closing parenthesis, since it thinks that the string is still open.

ECSSTree will handle this case by a special re-tokenization algorithm during the parsing process, when parser reaches this problematic point. This way, ECSSTree's parser will be able to parse this selector properly. It is also true for xpath.

Note: ECSSTree parses :contains and :xpath parameters as Raw. The main goal of this library is changing the internal behavior of the CSSTree's parser to make it able to parse the Extended CSS selectors properly, not to change the AST itself. The AST should be the same as in CSSTree, so that the library can be used as a drop-in replacement for CSSTree. Parsing :xpath expressions or regular expressions in detail would be a huge task, and requires new AST nodes, which would be a breaking change. But it always parses the correct raw expression for you, so you can parse/validate these expressions yourself if you want. There are many libraries for this, such as xpath or regexpp. See example codes for more details.

Examples

Here are a very simple example to show how to use ECSSTree:

import { parse, generate, toPlainObject, fromPlainObject } from "@adguard/ecss-tree";
import { inspect } from "util";

// Some inputs to test
const inputs = [
    // Valid selectors
    `div:-abp-has(> .some-class > a[href^="https://example.com"])`,
    `body:style(padding-top: 0 !important;):matches-media((min-width: 500px) and (max-width: 1000px))`,
    `section:upward(2):contains(aaa'bbb):xpath(//*[contains(text(),"()(cc")])`,

    // Missing closing bracket at the end
    `div:-abp-has(> .some-class > a[href^="https://example.com"]`,
];

// Iterate over inputs
for (const input of inputs) {
    try {
        // Parse raw input to AST. This will throw an error if the input is not valid.
        // Don't forget to set context to 'selector', because CSSTree will try to parse
        // 'stylesheet' by default.
        const ast = parse(input, { context: "selector" });

        // By default, AST uses a doubly linked list. To convert it to plain object, you can
        // use toPlainObject() function.
        // If you want to convert AST back to doubly linked list version, you can use
        // fromPlainObject() function.
        const astPlain = toPlainObject(ast);
        const astAgain = fromPlainObject(astPlain);

        // Print AST to console
        console.log(inspect(astPlain, { colors: true, depth: null }));

        // You can also generate string from AST (don't use plain object here)
        console.log(generate(astAgain));
    } catch (e) {
        // Mark invalid selector
        console.log(`Invalid selector: ${input}`);

        // Show CSSTree's formatted error message
        console.log(e.formattedMessage);
    }
}

The API is the same as in CSSTree, so you can use the CSSTree documentation as a reference.

You can find more examples in the examples folder.

Reporting problems / Requesting features

If you find a bug or want to request a new feature, please please open an issue on GitHub. Please provide a detailed description of the problem or the feature you want to request, and if possible, a code example that demonstrates the problem or the feature.

Contributing

You can contribute to the project by opening a pull request. People who contribute to AdGuard projects can receive various rewards, see this page for details.

Development

Prerequisites

Make sure you have the following tools installed:

  1. Node.js (latest LTS version is recommended)
  2. pnpm

Commands

During development, you can use the following commands (listed in package.json):

  • pnpm lint - lint the code with ESLint
  • pnpm test - run tests with Jest (you can also run a specific test with pnpm test <test-name>)
  • pnpm build - build the library to the dist folder by using Rollup

Documentation

License

This library is licensed under the MIT license. See the LICENSE file for more info.

Acknowledgements

In this section, we would like to thank the following people for their work:

  • Roman Dvornov (lahmatiy) for creating and maintaining the CSSTree library

References

Here are some useful links to learn more about Extended CSS selectors:

版本与发布记录

@adguard/ecss-tree 共发布 10 个版本,首次发布于 2023/02/22;过去 12 个月发布了 3 个版本。

版本发布日期距今
2.0.3latest2026/06/304 个月前
2.0.22026/06/204 个月前
2.0.12025/11/2111 个月前
2.0.02025/10/211 年前
1.1.02024/09/112 年前
1.0.82023/02/283 年前

关于 @adguard/ecss-tree 的常见问题

@adguard/ecss-tree 是什么?

Adblock Extended CSS fork for CSSTree

如何安装 @adguard/ecss-tree?

在项目目录运行 npm install @adguard/ecss-tree,或使用 pnpm add / yarn add / bun add。

@adguard/ecss-tree 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@adguard/ecss-tree 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@adguard/ecss-tree 可以商用吗?

@adguard/ecss-tree 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@adguard/ecss-tree 的下载量有多少?

根据 npm 官方下载统计,@adguard/ecss-tree 在 2026/10/05 – 2026/11/03 这 30 天内被下载 7,596 次,日均约 253 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@adguard/ecss-tree 还在维护吗?

最新版本 2.0.3 发布于 2026/06/30(4 个月前);至今共发布 10 个版本,其中过去 12 个月发布了 3 个;首次发布于 2023/02/22。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。