Development Guide

April 23, 2026 · View on GitHub

This guide covers setting up your development environment, building the library, running tests, and contributing code to the AdGuard Filters Compiler.

Prerequisites

Required Tools

ToolVersionNotes
Node.js22Use nvm to manage versions
pnpm10.7Package manager
GitLatestVersion control

Note: Development is tested on macOS and Linux. Windows users should use WSL or a virtual machine.

Getting Started

1. Clone the Repository

# GitHub
git clone https://github.com/AdguardTeam/FiltersCompiler.git
# or internal Bitbucket mirror — use the canonical URL for your environment
cd FiltersCompiler

2. Install Dependencies

pnpm install

3. Build the Library

pnpm build

Build output goes to dist/ (ESM: dist/index.js, CJS: dist/index.cjs). Rollup also copies JSON schemas and trust-level files into dist/.

4. Run Tests

pnpm test

5. Run Linter

pnpm lint

Development Workflow

Available Commands

CommandDescription
pnpm installInstall dependencies
pnpm buildBuild the library (Rollup → dist/)
pnpm testRun all tests (Vitest)
pnpm lintRun ESLint and TypeScript type checker
pnpm lint:codeRun ESLint
pnpm lint:typesRun TypeScript type checker (tsc --noEmit)
pnpm build-schemasRegenerate JSON schemas from tasks/build-schemas/
pnpm build-txtGenerate dist/build.txt with version info
pnpm incrementBump patch version in package.json
pnpm tgzPack release tarball (filters-compiler.tgz)

TypeScript

New source files should be written in TypeScript. The project uses TypeScript in strict mode for new .ts files while leaving existing .js files unchanged.

Key Commands

CommandDescription
pnpm lint:codeESLint — automatically uses the TypeScript parser for .ts files
pnpm lint:typesRun the TypeScript type checker (tsc --noEmit)
pnpm buildRollup — transpiles .ts files via @rollup/plugin-typescript

Adding a New TypeScript Module

  1. Create your .ts file under src/ (e.g., src/main/utils/my-feature.ts)
  2. Import it from existing code — both .js → .ts and .ts → .js imports work
  3. When importing a .js module from .ts, the import resolves to any via the ambient declaration in src/types/global.d.ts. For better type coverage, write a .d.ts shim alongside the .js file.
  4. Run pnpm lint && pnpm test && pnpm build

Writing Tests in TypeScript

Create test files as test/*.test.ts. Vitest discovers both .test.js and .test.ts files automatically.

Policy

  • New files: Write in TypeScript
  • Existing files: Leave as JavaScript until explicitly migrated
  • allowJs / checkJs: Disabled — existing JS is not type-checked
  • strict mode: Enabled for all .ts files
  • Naming collisions: Do not create foo.ts alongside foo.js in the same directory — rename or migrate instead

Before Committing

Run these checks before every commit:

# 1. Lint (includes type-checking)
pnpm lint

# 2. Run tests
pnpm test

Both must pass with no errors. Husky pre-commit hook runs pnpm lint && pnpm test automatically.

Branching Strategy

  1. Create a feature branch from master
  2. Make your changes
  3. Ensure pnpm lint and pnpm test pass
  4. Submit a pull request to master

Spec-Driven Development (SDD)

Changes that affect src/ should be guided by a lightweight spec authored before implementation begins.

Spec Lifecycle

  1. Draft — create a new spec in specs/.current/ (this directory is local-only; its contents are gitignored).
  2. Review — share the spec for review (e.g., attach to the PR description or a JIRA ticket).

Spec Structure

A spec directory contains at minimum:

FilePurpose
spec.mdProblem statement, proposed solution, and acceptance criteria

Additional files (diagrams, example filter snippets, etc.) may be added as needed.

Mapping Specs to Tests

  • Each acceptance criterion in the spec should correspond to at least one test case in test/.
  • Reference the spec path in the test description or a comment so reviewers can trace coverage back to the spec.
  • If full test coverage is deferred, note it as "future work" in the spec.

Quick Reference

specs/
├── .current/          # WIP — local only, gitignored contents
│   └── .gitkeep
├── add-platform-x/    # Finalized and committed
│   └── spec.md
└── ...

Common Tasks

Updating JSON Schemas

Schemas in schemas/ are generated — never edit them directly. Edit the generation scripts in tasks/build-schemas/ instead:

pnpm build-schemas

Important: Legacy schemas in schemas/mac/ and schemas/mac_v2/ must not be changed.

Updating Scriptlets and Redirects

To add support for new scriptlets and redirects, update @adguard/tsurlfilter (which bundles updated @adguard/scriptlets):

pnpm add @adguard/tsurlfilter@latest

For fixing scriptlets converting or validation specifically, update @adguard/scriptlets directly:

pnpm add @adguard/scriptlets@latest

Building a Release

# 1. Bump the patch version
pnpm increment

# 2. Build the library
pnpm build

# 3. Generate build info
pnpm build-txt

# 4. Pack the tarball
pnpm tgz

This produces filters-compiler.tgz ready for publishing.

Testing

Running Tests

# Run all tests once
pnpm test

Test Configuration

  • Framework: Vitest with node environment
  • Config: vitest.config.js
  • Test files: test/*.test.{js,ts}

Test Resources

Test fixtures are in test/resources/:

  • Filter files and platform configs used as test inputs
  • Expected output files for comparison
  • Some resources are gitignored (generated during test runs)

Troubleshooting

Node.js Version Issues

Problem: Build or tests fail with unexpected errors.

Solution: Ensure you are using Node.js 22:

node --version  # Should be v22.x.x

If using nvm:

nvm install 22
nvm use 22

Schema Validation Errors After Manual Edit

Problem: Tests fail after directly editing files in schemas/.

Solution: Never edit schemas manually. Revert your changes and use the generation scripts:

git checkout schemas/
# Edit tasks/build-schemas/ instead, then:
pnpm build-schemas

pnpm Not Found

Problem: pnpm: command not found

Solution: Install pnpm globally:

npm install -g pnpm
# or
corepack enable
corepack prepare pnpm@latest --activate

Additional Resources