Skip to content

Commit 705db69

Browse files
committed
AG-36072 & AG-35902 Update CSS Tree and integrate AdGuard CSS Tokenizer
Squashed commit of the following: commit aa84b60 Author: scripthunter7 <d.tota@adguard.com> Date: Tue Oct 21 13:50:31 2025 +0300 fix abbreviation for eslint commit 67d7c66 Author: scripthunter7 <d.tota@adguard.com> Date: Tue Oct 21 13:27:33 2025 +0300 replace toMatchObject with toStrictEqual in syntax tests commit 56a0fd4 Author: scripthunter7 <d.tota@adguard.com> Date: Tue Oct 21 13:25:15 2025 +0300 fix link definition commit 76c6c0a Author: scripthunter7 <d.tota@adguard.com> Date: Tue Oct 21 13:12:02 2025 +0300 clarify changelog commit 353d272 Author: scripthunter7 <d.tota@adguard.com> Date: Tue Oct 21 13:03:13 2025 +0300 Update CSS Tree and integrate AdGuard CSS Tokenizer
1 parent 305487a commit 705db69

22 files changed

Lines changed: 2581 additions & 2953 deletions

.eslintrc.cjs

Lines changed: 223 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,243 @@
11
const MAX_LINE_LENGTH = 120;
2-
const TAB_WIDTH = 4;
2+
3+
/**
4+
* ESLint rules.
5+
*
6+
* @see {@link https://eslint.org/docs/v8.x/rules/}
7+
*/
8+
const ESLINT_RULES = {
9+
indent: 'off',
10+
'no-bitwise': 'off',
11+
'no-new': 'off',
12+
'no-continue': 'off',
13+
'arrow-body-style': 'off',
14+
15+
'no-restricted-syntax': ['error', 'LabeledStatement', 'WithStatement'],
16+
'no-constant-condition': ['error', { checkLoops: false }],
17+
'max-len': [
18+
'error',
19+
{
20+
code: MAX_LINE_LENGTH,
21+
comments: MAX_LINE_LENGTH,
22+
tabWidth: 4,
23+
ignoreUrls: true,
24+
ignoreTrailingComments: false,
25+
ignoreComments: false,
26+
/**
27+
* Ignore calls to logger, e.g. logger.error(), because of the long string.
28+
*/
29+
ignorePattern: 'logger\\.',
30+
},
31+
],
32+
// Sort members of import statements, e.g. `import { B, A } from 'module';` -> `import { A, B } from 'module';`
33+
// Note: imports themself are sorted by import/order rule
34+
'sort-imports': ['error', {
35+
ignoreCase: true,
36+
// Avoid conflict with import/order rule
37+
ignoreDeclarationSort: true,
38+
ignoreMemberSort: false,
39+
memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'],
40+
}],
41+
};
42+
43+
/**
44+
* Import plugin rules.
45+
*
46+
* @see {@link https://github.com/import-js/eslint-plugin-import/tree/main/docs/rules}
47+
*/
48+
const IMPORT_PLUGIN_RULES = {
49+
'import/prefer-default-export': 'off',
50+
51+
'import-newlines/enforce': ['error', 3, MAX_LINE_LENGTH],
52+
'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
53+
// Split external and internal imports with an empty line
54+
'import/order': [
55+
'error',
56+
{
57+
groups: [
58+
// Built-in Node.js modules
59+
'builtin',
60+
// External packages
61+
'external',
62+
// Parent modules, e.g. `import { foo } from '../bar';`
63+
'parent',
64+
// Sibling modules, e.g. `import { foo } from './bar';`
65+
'sibling',
66+
// All other imports
67+
],
68+
alphabetize: { order: 'asc', caseInsensitive: true },
69+
'newlines-between': 'always',
70+
},
71+
],
72+
};
73+
74+
/**
75+
* JSDoc plugin rules.
76+
*
77+
* @see {@link https://github.com/gajus/eslint-plugin-jsdoc?tab=readme-ov-file#user-content-eslint-plugin-jsdoc-rules}
78+
*/
79+
const JSDOC_PLUGIN_RULES = {
80+
// Types are described in TypeScript
81+
'jsdoc/require-param-type': 'off',
82+
'jsdoc/no-undefined-types': 'off',
83+
'jsdoc/require-returns-type': 'off',
84+
'jsdoc/require-throws-type': 'off',
85+
86+
'jsdoc/require-param-description': 'error',
87+
'jsdoc/require-property-description': 'error',
88+
'jsdoc/require-returns-description': 'error',
89+
'jsdoc/require-returns': 'error',
90+
'jsdoc/require-param': 'error',
91+
'jsdoc/require-returns-check': 'error',
92+
93+
'jsdoc/check-tag-names': [
94+
'warn',
95+
{
96+
// Define additional tags
97+
// https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-tag-names.md#definedtags
98+
definedTags: ['note'],
99+
},
100+
],
101+
102+
'jsdoc/require-hyphen-before-param-description': ['error', 'never'],
103+
'jsdoc/require-jsdoc': [
104+
'error',
105+
{
106+
contexts: [
107+
'ClassDeclaration',
108+
'ClassProperty',
109+
'PropertyDefinition',
110+
'FunctionDeclaration',
111+
'MethodDefinition',
112+
],
113+
},
114+
],
115+
'jsdoc/require-description': [
116+
'error',
117+
{
118+
contexts: [
119+
'ClassDeclaration',
120+
'ClassProperty',
121+
'PropertyDefinition',
122+
'FunctionDeclaration',
123+
'MethodDefinition',
124+
],
125+
},
126+
],
127+
'jsdoc/require-description-complete-sentence': [
128+
'error',
129+
{
130+
abbreviations: [
131+
'e.g.',
132+
'i.e.',
133+
],
134+
},
135+
],
136+
'jsdoc/multiline-blocks': [
137+
'error',
138+
{
139+
noSingleLineBlocks: true,
140+
singleLineTags: [
141+
'inheritdoc',
142+
],
143+
},
144+
],
145+
'jsdoc/tag-lines': [
146+
'error',
147+
'any',
148+
{
149+
startLines: 1,
150+
},
151+
],
152+
'jsdoc/sort-tags': [
153+
'error',
154+
{
155+
linesBetween: 1,
156+
tagSequence: [
157+
{ tags: ['file'] },
158+
{ tags: ['template'] },
159+
{ tags: ['see'] },
160+
{ tags: ['param'] },
161+
{ tags: ['returns'] },
162+
{ tags: ['throws'] },
163+
{ tags: ['example'] },
164+
],
165+
},
166+
],
167+
};
168+
169+
/**
170+
* N plugin rules.
171+
*
172+
* @see {@link https://github.com/eslint-community/eslint-plugin-n?tab=readme-ov-file#-rules}
173+
*/
174+
const N_PLUGIN_RULES = {
175+
// Import plugin is enough, also, this rule requires extensions in ESM, but we use bundler resolution
176+
'n/no-missing-import': 'off',
177+
// Require using node protocol for node modules, e.g. `node:fs` instead of `fs`.
178+
'n/prefer-node-protocol': 'error',
179+
// Prefer `/promises` API for `fs` and `dns` modules, if the corresponding imports are used.
180+
'n/prefer-promises/fs': 'error',
181+
'n/prefer-promises/dns': 'error',
182+
183+
'n/hashbang': [
184+
'error',
185+
{
186+
// This rule reads the bin property from package.json, and only allows shebangs for that file.
187+
// But since we transform the source files to the dist folder, we need to convert the paths.
188+
convertPath: [
189+
{
190+
include: ['src/**/*.ts'],
191+
replace: ['^src/(.+)\\.ts$', 'dist/$1.js'],
192+
},
193+
],
194+
},
195+
],
196+
};
197+
198+
/**
199+
* Merges multiple rule sets into a single object.
200+
*
201+
* @param ruleSets The rule sets to merge.
202+
*
203+
* @returns The merged rule set.
204+
*/
205+
function mergeRules(...ruleSets) {
206+
const merged = {};
207+
for (const rules of ruleSets) {
208+
for (const [key, value] of Object.entries(rules)) {
209+
if (merged[key]) {
210+
throw new Error(`Duplicate ESLint rule: ${key}`);
211+
}
212+
merged[key] = value;
213+
}
214+
}
215+
return merged;
216+
}
3217

4218
module.exports = {
5219
root: true,
6-
env: { jest: true },
7220
parserOptions: {
8221
ecmaVersion: 'latest',
9222
},
10223
plugins: [
11224
'import',
12225
'import-newlines',
226+
'n',
13227
],
14228
extends: [
15-
'eslint:recommended',
16229
'airbnb-base',
17230
'plugin:jsdoc/recommended',
231+
'plugin:n/recommended',
18232
],
19233
ignorePatterns: [
20234
'dist',
21235
'coverage',
22-
'examples',
23236
],
24-
rules: {
25-
'max-len': [
26-
'error',
27-
{
28-
code: MAX_LINE_LENGTH,
29-
comments: MAX_LINE_LENGTH,
30-
tabWidth: TAB_WIDTH,
31-
ignoreUrls: true,
32-
ignoreTrailingComments: false,
33-
ignoreComments: false,
34-
},
35-
],
36-
indent: [
37-
'error',
38-
TAB_WIDTH,
39-
{
40-
SwitchCase: 1,
41-
},
42-
],
43-
44-
'arrow-body-style': 'off',
45-
'no-await-in-loop': 'off',
46-
'no-continue': 'off',
47-
'no-new': 'off',
48-
'no-restricted-syntax': ['error', 'LabeledStatement', 'WithStatement'],
49-
50-
'import/prefer-default-export': 'off',
51-
'import-newlines/enforce': ['error', { items: 3, 'max-len': MAX_LINE_LENGTH }],
52-
// Split external and internal imports with an empty line
53-
'import/order': [
54-
'error',
55-
{
56-
groups: [
57-
['builtin', 'external'],
58-
],
59-
'newlines-between': 'always',
60-
},
61-
],
62-
63-
'jsdoc/multiline-blocks': ['error', { noSingleLineBlocks: true }],
64-
'jsdoc/require-param-type': 'off',
65-
'jsdoc/require-returns-type': 'off',
66-
'jsdoc/tag-lines': [
67-
'warn',
68-
'any',
69-
{
70-
startLines: 1,
71-
},
72-
],
73-
'jsdoc/check-tag-names': [
74-
'warn',
75-
{
76-
// Define additional tags
77-
// https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-tag-names.md#definedtags
78-
definedTags: ['note'],
79-
},
80-
],
81-
},
237+
rules: mergeRules(
238+
ESLINT_RULES,
239+
IMPORT_PLUGIN_RULES,
240+
JSDOC_PLUGIN_RULES,
241+
N_PLUGIN_RULES,
242+
),
82243
};

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,22 @@ The format is based on [Keep a Changelog][keepachangelog], and this project adhe
88
[keepachangelog]: https://keepachangelog.com/en/1.0.0/
99
[semver]: https://semver.org/spec/v2.0.0.html
1010

11+
## [2.0.0] - 2025-10-21
12+
13+
### Changed
14+
15+
- `css-tree` to `@eslint/css-tree` (a `css-tree` fork made by ESLint Team) [#16].
16+
This also updates CSS Tree from `v2` to `v3`, which introduces breaking changes.
17+
For more details see their changelog.
18+
19+
### Added
20+
21+
- `@adguard/css-tokenizer` as tokenizer dependency [#15].
22+
23+
[#15]: https://github.com/AdguardTeam/ecsstree/issues/15
24+
[#16]: https://github.com/AdguardTeam/ecsstree/issues/16
25+
[2.0.0]: https://github.com/AdguardTeam/ecsstree/compare/v1.1.0...v2.0.0
26+
1127
## [1.1.0] - 2024-09-10
1228

1329
### Fixed

ecsstree.d.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1 @@
1-
import { Lexer } from "css-tree";
2-
3-
// Export default types
4-
export * from "css-tree";
5-
6-
// Extend types
7-
declare const lexer: Lexer;
8-
9-
export { lexer };
1+
export * from "@eslint/css-tree";

jest.config.js

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)