Imported from AdguardTeam/tsurlfilter (
packages/dnr-rulesets/AGENTS.md). Install upstream withnpx skills add AdguardTeam/tsurlfilter --skill dnr-rulesets. Copyright stays with the author.
AGENTS.md
Project Overview
@adguard/dnr-rulesets is a build-time utility and CLI tool that creates,
loads, and manages prebuilt AdGuard Declarative Net Request (DNR) rulesets for
Chromium MV3 browser extensions. It downloads AdGuard filter lists, converts
them to DNR JSON rulesets via @adguard/dnr-converter's declarative converter,
patches extension manifest.json with ruleset declarations, and provides a
watch mode for local development. It also exposes a programmatic API for
integration into custom build scripts.
Technical Context
- Language/Version: TypeScript (ESNext target, strict mode)
- Primary Dependencies:
@adguard/dnr-converter(declarative converter),@adguard/agtree(filter rule parser),@adguard/logger,commander(CLI),axios(HTTP),zod(schema validation),chokidar(file watching),fs-extra,fast-glob - Build Toolchain: Rollup (with
@rollup/plugin-swc),rollup-plugin-dts(type bundling),tsx(task scripts) - Storage: None (filesystem only — reads/writes JSON rulesets and manifests)
- Testing: Vitest (with 100 % coverage thresholds configured for
test:coverageruns) - Target Platform: Node.js ≥ 22 (CLI tool and build-time library; ESM output for lib, CJS output for CLI binary)
- Project Type: Package inside the
tsurlfilterpnpm monorepo - Constraints: CLI binary is CJS because
@adguard/re2-wasmuses raw__dirname; the WASM file must be copied todist/at build time
Project Structure
packages/dnr-rulesets/
├── src/
│ ├── cli.ts # CLI entry point (commander program)
│ ├── common/ # Shared helpers (local script rules, constants)
│ ├── lib/ # Public library API
│ │ ├── assets/ # AssetsLoader — downloads/copies rulesets
│ │ ├── manifest/ # ManifestPatcher, RulesetsInjector, Watcher
│ │ └── unsafe-rules/ # Unsafe rules exclusion for CWS compliance
│ └── utils/ # Utility entry point (getVersion, etc.)
├── common/ # Build-time constants and helpers (not published)
├── tasks/ # Build/CI scripts (run via tsx)
├── test/ # Tests mirroring src/ structure + smoke tests
├── dist/ # Build output (gitignored)
├── rollup.config.ts # Rollup build config (lib + CLI + types)
├── vitest.config.ts # Vitest config
├── eslint.config.mjs # ESLint flat config
├── tsconfig*.json # TypeScript configs (base, build, types)
└── package.json
Build And Test Commands
pnpm build— full build: clear dist, build assets, build lib + CLIpnpm build:assets— download filters and convert to DNR rulesetspnpm build:lib— bundle library and CLI via Rolluppnpm build:docs— regenerate the "Included filter lists" section in READMEpnpm validate:assets— validate built assetspnpm test— run unit tests via Vitestpnpm test:smoke— run smoke tests (ESM import + exports validation)pnpm test:coverage— run tests with V8 coveragepnpm lint— run both code linting and type checkingpnpm lint:code— run ESLint (eslint --cache .)pnpm lint:types— run TypeScript type checking (tsc)pnpm clear— removedist/androllup.cache/
Contribution Instructions
You MUST follow the following rules for EVERY task that you perform:
-
You MUST verify your changes pass all static analysis checks before completing a task:
pnpm lint:typesto check for TypeScript errorspnpm lint:codeto run ESLint
-
You MUST update or add unit tests for any changed code.
-
You MUST run the test suite to verify your changes do not break existing functionality:
pnpm test. -
When making changes to the project structure, ensure the Project Structure section in
AGENTS.mdis updated and remains valid. -
When the task is finished update
CHANGELOG.mdfile and explain changes in theUnreleasedsection. Add entries to the appropriate subsection (Added,Changed, orFixed) if it already exists; do not create duplicate subsections. -
If the prompt essentially asks you to refactor or improve existing code, check if you can phrase it as a code guideline. If it's possible, add it to the relevant Code Guidelines section in
AGENTS.md. -
After completing the task you MUST verify that the code you've written follows the Code Guidelines in this file.
-
You MUST NOT modify auto-generated sections (e.g. "Included filter lists" in
README.md). Usepnpm build:docsto regenerate them instead. -
When a new filter list is added to
dnr-rulesets, you MUST bump at least the minor version of the package, not just the patch version. Filter list versions are timestamp-based (e.g.4.2.20260617150056), so a patch bump (e.g.4.2.3) would be semver-less than the current stable filter list version. Bumping the minor version (e.g.4.3.0) ensures the package version stays greater than any filter list version. You MUST also updatetasks/validator-data.jsonso thatpnpm validate:assetspasses — see the "Managingvalidator-data.json" section inREADME.mdfor the full procedure.
Code Guidelines
I. Architecture
-
Three entry points. The package exposes three separate entry points bundled by Rollup:
lib(src/lib/index.ts) — public programmatic API (AssetsLoader,ManifestPatcher,RulesetsInjector,excludeUnsafeRules).utils(src/utils/index.ts) — lightweight utility functions (getVersion,getVersionTimestampMs).- CLI (
src/cli.ts) —commander-based CLI binary shipped as CJS.
New public API MUST be exported through the appropriate barrel file. New CLI commands MUST be added in
src/cli.ts.Rationale: Keeps the public surface explicit and allows tree-shaking for consumers who only need a subset.
-
Shared code lives in
src/common/. Code used by bothlibandtasks(or by multiple modules withinlib) SHOULD be placed insrc/common/. Build-time-only constants and helpers live in the top-levelcommon/directory (outsidesrc/).Rationale: Prevents circular dependencies and clarifies which code ships in the published package vs. what is build-only.
-
Tasks are standalone scripts. Files under
tasks/are executed viatsxand MUST NOT be imported bysrc/code. They may import from the top-levelcommon/directory.Rationale: Keeps the published library free of build-time dependencies.
II. Code Quality Standards
-
JSDoc is required on every class, class property, function declaration, and method definition. Descriptions MUST be complete sentences. Use
@param,@returns, and@throwstags as appropriate.Rationale: Enforced by
eslint-plugin-jsdocrules ineslint.config.mjs. -
Max line length is 120 characters. URLs are exempt.
Rationale: Configured in the ESLint
max-lenrule. -
Imports MUST be sorted using
simple-import-sort. Group Node built-ins first, then external packages, then internal paths.Rationale: Enforced by
simple-import-sort/importsESLint rule. -
Use 4-space indentation, single quotes, semicolons, and
1tbsbrace style with arrow parens always present.Rationale: Enforced by
@stylistic/eslint-pluginconfiguration. -
Strict TypeScript options are enabled:
noUnusedLocals,noUnusedParameters,noImplicitReturns,noFallthroughCasesInSwitch. All code MUST compile cleanly underpnpm lint:types.Rationale: Prevents common bugs at compile time.
III. Testing Discipline
-
Test files mirror
src/structure undertest/. For example, tests forsrc/lib/manifest/patcher.tslive intest/lib/manifest/.Rationale: Makes it easy to locate tests for any source file.
-
100 % coverage thresholds are configured in
vitest.config.tsfor branches, functions, lines, and statements. They are checked when runningpnpm test:coverage. New code SHOULD be covered by tests.Rationale: Catches regressions in test coverage before publishing.
-
Smoke tests validate that the published package can be imported as ESM and that all declared exports resolve correctly (via
tsd). Located intest/smoke/.Rationale: Catches packaging regressions before publishing.
IV. Other
-
CLI output is CJS. The CLI binary (
dist/cli.cjs) is built as CommonJS because@adguard/re2-wasmrelies on__dirname. The library output is ESM. Do NOT change the CLI format without verifying WASM loading still works.Rationale: Documented in
rollup.config.tscomments. -
All AdGuard workspace packages are bundled into the CLI. The Rollup CLI config excludes most externals but bundles
@adguard/agtree,@adguard/logger, and@adguard/dnr-converterbecause they are ESM-only and the CLI output is CJS.Rationale: Avoids
import.meta.urlissues in CJS context.