From 9f365014238e06633e9b10eb6aae95a77bd49bee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20T=C3=B3ta?= Date: Thu, 9 Jul 2026 09:59:13 +0000 Subject: [PATCH] AG-55945 Add development and agent reference documentation Squashed commit of the following: commit 930d5e72f6610dbb6e84807c56bc9e48aded2b3b Author: scripthunter7 Date: Thu Jul 9 11:02:29 2026 +0200 Add contributing guide with references to development and agent documentation commit 9b2fcc596dcc0982b862ff98bb944922c87dcec7 Author: scripthunter7 Date: Thu Jul 9 06:31:11 2026 +0200 Improve documentation by removing redundant Table of Contents entries across AGENTS.md and DEVELOPMENT.md files in all directories. commit ab51c7c4c9a0d978113b9c52f98721e489245250 Author: scripthunter7 Date: Thu Jul 9 06:28:59 2026 +0200 Remove Build And Test Commands section from AGENTS.md files across client, server, shared, syntaxes, and tools directories for improved documentation clarity. commit da0df48ea1dcf851d62b736dc70abad7bb7a7487 Author: scripthunter7 Date: Wed Jul 1 17:42:31 2026 +0200 Refactor dependency flow diagrams to use Mermaid syntax for improved clarity in AGENTS.md files commit b87e190aa9a51899e43063717d67b84d576a3f41 Author: scripthunter7 Date: Tue Jun 30 18:32:32 2026 +0200 Fix markdownlint, rename contributing guide commit 3267984c22f4ff222d36d363f9975b86c2c936e5 Author: scripthunter7 Date: Tue Jun 30 18:02:14 2026 +0200 Add development and agent reference documentation --- AGENTS.md | 341 ++++++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 241 +------------------------ DEVELOPMENT.md | 279 +++++++++++++++++++++++++++++ README.md | 6 +- client/.markdownlint.json | 3 + client/AGENTS.md | 189 ++++++++++++++++++++ client/DEVELOPMENT.md | 120 +++++++++++++ server/.markdownlint.json | 3 + server/AGENTS.md | 249 ++++++++++++++++++++++++++ server/DEVELOPMENT.md | 143 +++++++++++++++ shared/.markdownlint.json | 3 + shared/AGENTS.md | 160 +++++++++++++++++ shared/DEVELOPMENT.md | 115 ++++++++++++ syntaxes/.markdownlint.json | 3 + syntaxes/AGENTS.md | 184 +++++++++++++++++++ syntaxes/DEVELOPMENT.md | 131 ++++++++++++++ tools/AGENTS.md | 159 +++++++++++++++++ tools/DEVELOPMENT.md | 97 ++++++++++ 18 files changed, 2190 insertions(+), 236 deletions(-) create mode 100644 AGENTS.md create mode 100644 DEVELOPMENT.md create mode 100644 client/.markdownlint.json create mode 100644 client/AGENTS.md create mode 100644 client/DEVELOPMENT.md create mode 100644 server/.markdownlint.json create mode 100644 server/AGENTS.md create mode 100644 server/DEVELOPMENT.md create mode 100644 shared/.markdownlint.json create mode 100644 shared/AGENTS.md create mode 100644 shared/DEVELOPMENT.md create mode 100644 syntaxes/.markdownlint.json create mode 100644 syntaxes/AGENTS.md create mode 100644 syntaxes/DEVELOPMENT.md create mode 100644 tools/AGENTS.md create mode 100644 tools/DEVELOPMENT.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..4476ad1 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,341 @@ + +# AGENTS.md + +Working reference for AI coding agents (and human contributors) operating in the +VSCode Adblock Syntax monorepo. It describes the conventions to follow, where +program modules live, and how to verify your work. + +For environment setup (installing Node, pnpm, recommended extensions, running +the extension in debug mode) see [DEVELOPMENT.md](DEVELOPMENT.md) and +[README.md](README.md). This file does not duplicate setup steps. + + +## Table of Contents + +- [Project Overview](#project-overview) +- [Technical Context](#technical-context) +- [Project Structure](#project-structure) +- [Build And Test Commands](#build-and-test-commands) +- [Contribution Instructions](#contribution-instructions) +- [Code Guidelines](#code-guidelines) + - [System Design](#system-design) + - [Architecture](#architecture) + - [Code Quality](#code-quality) + - [Testing](#testing) + - [Dependency Management](#dependency-management) + - [Configuration \& Documentation](#configuration--documentation) + - [Markdown Formatting](#markdown-formatting) + - [Other](#other) +- [Package Agents](#package-agents) + +## Project Overview + +VSCode Adblock Syntax is a Visual Studio Code extension that adds language +support for ad blocking filter lists (AdGuard, uBlock Origin, AdBlock, and +Adblock Plus syntax). It is a development tool for authoring filter lists, not an +ad blocker. + +The extension provides: + +- Syntax highlighting via a TextMate grammar. +- Real-time linting, auto-fixing, and platform compatibility checks powered by + [AGLint](https://github.com/AdguardTeam/AGLint), integrated through the + Language Server Protocol (LSP). +- Quick fixes and code actions (apply fix, apply suggestion, disable rule). +- Auto-discovery of AGLint installed locally or globally in the workspace. + +It is published to the VSCode Marketplace and Open VSX as `adguard.adblock`. + +## Technical Context + +- **Language/Version**: TypeScript `~5.9` targeting `ESNext`, `module: ESNext`, + `moduleResolution: bundler`, `strict` mode. +- **Runtime**: Node.js (`>=20`; development uses Node v22). The extension host + is VSCode `^1.74.0`. +- **Primary Dependencies**: `vscode-languageclient` / `vscode-languageserver` + (LSP), `@adguard/aglint` and `@adguard/agtree` (linting and AST), + `vscode-textmate` + `vscode-oniguruma` (grammar testing), `valibot` + (validation), `fast-glob`, `semver`, `resolve`, `preferred-pm`. +- **Storage**: None. State is in-memory per LSP server process; the only + persisted artifacts are build outputs and the packaged `.vsix`. +- **Testing**: [Vitest](https://vitest.dev) in every package. +- **Build**: [Rspack](https://rspack.dev) (client, server, shared) and `tsx` + scripts (syntaxes, tools). +- **Linting**: ESLint (airbnb-base + airbnb-typescript, JSDoc, import, + boundaries) and markdownlint. +- **Target Platform**: VSCode desktop (extension host on Node.js). Virtual and + untrusted workspaces are supported with syntax highlighting only. +- **Project Type**: monorepo (pnpm workspaces) of five packages. +- **Performance Goals**: N/A (no formal targets). Linting is debounced (100 ms) + and results are optionally cached in memory. +- **Constraints**: AGLint linting requires the Node.js filesystem API, so it is + unavailable in virtual workspaces. +- **Scale/Scope**: Single-developer-machine tool; published to public extension + registries. + +## Project Structure + +```text +. +├── package.json # Root manifest: extension metadata, contributes, scripts +├── pnpm-workspace.yaml # Workspace members + dependency version catalog +├── language-configuration.json # VSCode language config (brackets, comments) +├── tsconfig.base.json # Shared TypeScript compiler options +├── .eslintrc.cjs # Root ESLint config (rules + boundaries) +├── .markdownlint.json # Markdown lint rules +├── AGENTS.md # This file (root agent reference) +├── README.md # User-facing documentation +├── DEVELOPMENT.md # Environment setup + development guide +├── client/ # VSCode extension entry (LSP client) — see client/AGENTS.md +├── server/ # LSP language server (AGLint integration) — see server/AGENTS.md +├── shared/ # Shared types/utilities for client + server — see shared/AGENTS.md +├── syntaxes/ # TextMate grammar source, compiler, tests — see syntaxes/AGENTS.md +├── tools/ # Repo build/utility scripts — see tools/AGENTS.md +├── test/static/ # Static fixtures (sample rules, aglint test workspace) +├── icons/ # Extension icons +└── bamboo-specs/ # CI/CD pipeline configuration +``` + +Each package has its own `AGENTS.md` with package-specific structure and +guidelines (see [Package Agents](#package-agents)). + +## Build And Test Commands + +Run from the repository root unless noted. The package manager is pnpm v10. + +- **Build all**: `pnpm build` (recursive, production mode with minification). +- **Test all**: `pnpm test` (recursive Vitest, single run). +- **Type-check all**: `pnpm test:compile` (recursive `tsc --noEmit`). +- **Lint all**: `pnpm lint` (recursive ESLint + markdownlint). +- **Lint code only**: `pnpm lint:code` (ESLint with cache). +- **Lint Markdown only**: `pnpm lint:md` (markdownlint). +- **Clean**: `pnpm clean` (removes generated files / `node_modules`). +- **Package extension**: `pnpm package` (produces `out/vscode-adblock.vsix`); + `pnpm package:pre` for a pre-release build. + +Per-package commands use workspace filters, e.g.: + +- `pnpm --filter @vscode-adblock-syntax/server build` +- `pnpm --filter @vscode-adblock-syntax/syntaxes test` + +There is no separate format command — formatting is enforced through ESLint +(`lint:code`) and markdownlint (`lint:md`). + +## Contribution Instructions + +After completing a task, you MUST do the following: + +- Verify your changes with the linter and type checker. Use: + - `pnpm test:compile` to check for TypeScript type errors. + - `pnpm lint:code` to run ESLint (add `--fix` to auto-fix). + - `pnpm lint:md` to lint Markdown files. + - `pnpm lint` to run all linters recursively. +- Update or add unit tests for any code you changed. +- Run `pnpm test` and ensure all tests pass before considering the task done. +- When you change the project structure (add, remove, move modules), update the + Project Structure section in the relevant `AGENTS.md` (this file and/or the + package one) so it stays accurate. +- If a prompt essentially asks you to refactor or improve existing code, phrase + the lesson as a code guideline and add it to the Code Guidelines section of + the relevant `AGENTS.md`. +- After finishing, verify that the code you wrote follows the Code Guidelines in + this file and in the affected package's `AGENTS.md`. +- Even when the task only changes documentation (a plan, this file, any Markdown + file), still run `pnpm lint:md` to verify Markdown formatting. + +## Code Guidelines + +### System Design + +This repository ships a VSCode extension. Design for the extension runtime: + +- The extension runs in a sandboxed host with limited APIs. Request only the + capabilities you need; the extension declares limited support for virtual and + untrusted workspaces and must degrade to syntax highlighting only when the + Node.js filesystem is unavailable. +- Keep the bundle lightweight — every added dependency slows extension + activation. Heavy dependencies (AGLint) are loaded lazily by the server. +- Separate concerns across extension contexts: the **client** holds all VSCode + API access and extension activation logic; the **server** runs in a separate + Node.js process and holds AGLint and linting logic; **shared** holds types + used by both. Do not put business logic in the client; delegate to the server + over LSP. +- Communicate between client and server exclusively via the Language Server + Protocol (requests, notifications). Never share mutable state directly between + the two processes. +- Handle lifecycle correctly. A language client/server pair is created per + outermost workspace folder and disposed when the folder is removed; clean up + watchers and clients on deactivation. +- React to workspace and document events asynchronously; never block the + extension host. + +### Architecture + +The codebase should follow these universal design principles: + +- **Separation of Concerns** — each package and module handles one aspect + (client = VSCode integration, server = linting, shared = common types, + syntaxes = grammar, tools = build scripts). +- **Single Responsibility Principle** — every file/function has one reason to + change. +- **Dependency Direction** — dependencies point downward: `client` and `server` + depend on `shared`; `shared` depends on neither. No upward imports. +- **Explicit Boundaries** — packages interact through published entry points + (`shared` exports from its `index.ts`; client/server talk only over LSP). The + `eslint-plugin-boundaries` config forbids `client` and `server` from importing + each other's internals. +- **Data Flow Clarity** — document events flow client → server → AGLint → + diagnostics → client in a predictable path. +- **Minimize Coupling, Maximize Cohesion** — AGLint is decoupled from VSCode via + a filesystem adapter in the server. +- **Make Invalid States Impossible** — use TypeScript types and `valibot` + schemas at boundaries (LSP messages, settings) to reject invalid input. +- **Observability Built-in** — use the LSP connection console / VSCode output + channel for logging with consistent prefixes; the status bar surfaces AGLint + state to the user. +- **Keep It Boring** — prefer standard LSP and VSCode patterns over novel + abstractions. + +Layered architecture across the monorepo: + +| Layer | Responsibility | Examples | +| --- | --- | --- | +| Extension client | VSCode API, activation, LSP client lifecycle | [client/src/extension.ts](client/src/extension.ts) | +| Shared contracts | Types/enums used by client and server | [shared/src/index.ts](shared/src/index.ts) | +| Language server | LSP handlers, linting orchestration, AGLint integration | [server/src/server.ts](server/src/server.ts) | +| Grammar | TextMate grammar source + compiler | [syntaxes/scripts/build.ts](syntaxes/scripts/build.ts) | +| Build tooling | Repo-wide build/clean scripts | [tools/build-txt.ts](tools/build-txt.ts) | + +Dependency flow: + +```mermaid +flowchart LR + client["client (VSCode API, LSP client)"] --> shared["shared (types/enums)"] + server["server (LSP server)"] --> shared + server -.->|"loads at runtime"| aglint["@adguard/aglint (external)"] +``` + +`syntaxes` and `tools` are standalone — no cross-package dependencies. + +`client` and `server` run as separate processes and communicate only over LSP; +neither imports the other. + +### Code Quality + +- **Documentation**: JSDoc is required by ESLint (`jsdoc/require-jsdoc`, + `jsdoc/require-description`) on functions, classes, methods, and class + properties. Descriptions must be complete sentences; `@param` and `@returns` + descriptions are required (types come from TypeScript, not JSDoc). +- **Static analysis gates**: ESLint (airbnb-base + airbnb-typescript), the + TypeScript compiler (`test:compile`), and markdownlint must all pass. +- **Linter/formatter config**: Do not weaken or disable lint rules to make code + pass. Change the shared `.eslintrc.cjs` / `.markdownlint.json` only with + explicit justification. +- **Formatting**: 4-space indentation; max line length 120 (`max-len`). Imports + are grouped (builtin, external, parent, sibling) and alphabetized; members + within an import are sorted. +- **Type imports**: Use inline type imports/exports + (`import { type Foo }`) — enforced by + `@typescript-eslint/consistent-type-imports`. +- **Error handling**: Throw specific errors from low-level helpers; catch at + handler/orchestration boundaries, log, and degrade gracefully (the server + never crashes on an AGLint failure). Use the shared error helpers + (`getErrorMessage`, `getErrorStack`) to read `unknown` errors safely. +- **Naming**: `camelCase` for variables/functions (verb-prefixed for actions), + `PascalCase` for types/classes, `UPPER_SNAKE_CASE` for constants, `kebab-case` + for file names. + +### Testing + +- **Framework**: Vitest. Tests live under each package's `test/` (or `tests/` + for client) directory and mirror the `src/` structure. +- **Naming**: test files are named `*.test.ts`. +- **Mocking**: mock external boundaries — the VSCode API (client mocks under + `client/tests/__mocks__/vscode.ts`), the LSP connection and server context + (server `test/helpers/mocks.ts`). Do not mock pure utility functions; test + them directly. +- **Verification**: all tests must pass (`pnpm test`) before a change is + considered complete. Update tests for any changed code. +- **Grammar tests**: the `syntaxes` package tokenizes sample rules with the real + TextMate grammar and asserts token scopes; see + [syntaxes/AGENTS.md](syntaxes/AGENTS.md). + +### Dependency Management + +- **Pin dependency versions explicitly.** Versions are centralized in the + `catalog` of [pnpm-workspace.yaml](pnpm-workspace.yaml); packages reference + them with `catalog:`. Prefer exact versions over ranges that allow untested + upgrades. +- **Prefer vanilla solutions.** Use the Node.js standard library and built-in + APIs when they solve the problem; only add a dependency when it provides + clear value. +- **Reputable sources only.** Add dependencies from well-established, actively + maintained projects (judged by adoption, activity, and maintainers). +- **Avoid unpopular libraries.** Do not add niche or obscure packages. +- **Minimize dependency count.** Each dependency increases attack surface, + bundle size, and maintenance burden — justify every addition. +- **Use the latest stable version.** Check the registry for the current stable + release rather than copying version numbers from memory. The workspace + enforces a 7-day `minimumReleaseAge` (excluding `@adguard/*`) to avoid + freshly published, unvetted releases. + +**Known exclusions** (to be fixed): most catalog entries use caret ranges +(`^x.y.z`) rather than exact pins; tighten these toward exact versions when +practical. + +### Configuration & Documentation + +- **Runtime configuration**: user settings are declared in the root + [package.json](package.json) `contributes.configuration` + (`adblock.enableAglint`, `adblock.enableInMemoryAglintCache`) and read by the + server via LSP configuration. AGLint itself is configured by `.aglintrc.*` + files in the user's workspace. +- **No secrets**: this is a local developer tool — do not introduce secrets, + tokens, or hardcoded absolute paths. +- **Documentation sync**: when you change build commands, project structure, the + settings schema, or the client/server protocol, update the affected + `AGENTS.md`, and update [README.md](README.md) / [DEVELOPMENT.md](DEVELOPMENT.md) + when user-facing behavior or the development workflow changes. + +### Markdown Formatting + +All Markdown files MUST follow these rules (aligned with +[.markdownlint.json](.markdownlint.json)): + +- **Line length**: keep lines at most 120 characters (the project's + markdownlint limit). Lines inside fenced code blocks are exempt. +- **Unordered lists**: use dashes (`-`); indent nested items by 4 spaces. +- **Continuation lines**: align wrapped list-item text with the first character + of the item text, not the marker. +- **Emphasis**: use asterisks (`*italic*`, `**bold**`); do NOT use underscores. +- **Headings**: duplicate heading names are allowed only among sibling headings. +- **Inline HTML**: avoid raw HTML; the only allowed elements are ``, + `
`, ``, ``, `
`, `
`, and `

`. +- **Trailing spaces**: do not leave trailing whitespace; use a blank line + instead of two-space line breaks. +- **Bare URLs**: permitted (the project disables MD034). +- **Tables**: align columns with single-space padding; use `| --- |` separators. + +**Rationale**: uniform Markdown formatting improves readability for humans and +for AI agents that consume this documentation as context. + +### Other + +- **Versioning**: the extension uses an odd/even minor scheme — even minor + versions are releases, odd minor versions are pre-releases (see + [DEVELOPMENT.md](DEVELOPMENT.md)). Marketplaces accept only + `major.minor.patch`. +- **Git hooks**: Husky runs linters and tests on commit; do not bypass hooks + with `--no-verify`. + +## Package Agents + +Each package documents its own structure and conventions: + +- [client/AGENTS.md](client/AGENTS.md) — VSCode extension client (LSP client). +- [server/AGENTS.md](server/AGENTS.md) — LSP language server and AGLint + integration. +- [shared/AGENTS.md](shared/AGENTS.md) — shared types and utilities. +- [syntaxes/AGENTS.md](syntaxes/AGENTS.md) — TextMate grammar source, compiler, + and tests. +- [tools/AGENTS.md](tools/AGENTS.md) — repository build and utility scripts. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9d89582..57fbb3d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,239 +1,14 @@ - # Contributing & Development Guide -Thank you for your interest in contributing to the VSCode Adblock Syntax project! This guide aims to provide essential -information about the project and outlines steps to contribute effectively. +Thank you for your interest in contributing to the VSCode Adblock Syntax +project! This guide aims to provide essential information about the project and +outlines steps to contribute effectively. -Contributors to AdGuard projects can receive **various** rewards; please check [this page][contribute] for details. +Contributors to AdGuard projects can receive **various** rewards; please check +[this page][contribute] for details. -Table of Contents: +For detailed setup instructions, build commands, testing, and the full +development workflow, see [DEVELOPMENT.md](DEVELOPMENT.md). For code guidelines +and architecture, see [AGENTS.md](AGENTS.md). -- [Prerequisites](#prerequisites) -- [Initial setup](#initial-setup) -- [Project structure](#project-structure) - - [Main packages](#main-packages) - - [Supporting folders](#supporting-folders) -- [Running the extension in development mode](#running-the-extension-in-development-mode) -- [Creating a production build](#creating-a-production-build) -- [Updating syntax highlighting](#updating-syntax-highlighting) -- [Available commands](#available-commands) - - [Build commands](#build-commands) - - [Package commands](#package-commands) - - [Package-level build commands](#package-level-build-commands) - - [Utility commands](#utility-commands) - - [Linting \& testing commands](#linting--testing-commands) -- [Versioning policy](#versioning-policy) - - [VS Code extension versioning requirements](#vs-code-extension-versioning-requirements) - - [Pre-release versioning strategy](#pre-release-versioning-strategy) -- [Useful links](#useful-links) - -## Prerequisites - -Ensure that the following software is installed on your computer: - -- [Node.js][nodejs]: v22 (you can install multiple versions using [nvm][nvm]) -- [pnpm][pnpm]: v10 -- [VSCode][vscode] -- [Git][git] - -[git]: https://git-scm.com/ -[nodejs]: https://nodejs.org/en/download -[nvm]: https://github.com/nvm-sh/nvm -[pnpm]: https://pnpm.io/installation - -## Initial setup - -After cloning the repository, follow these steps to initialize the project: - -1. Install dependencies by calling `pnpm install`. - This will also install client and server dependencies via `postinstall` scripts. - After installation, it will initialize [Husky Git hooks][husky] through the `prepare` script. -2. Install recommended VSCode extensions (refer to the [`.vscode/extensions.json`][vscode-extensions-file] file). - **These extensions are REQUIRED for the development process.** - -## Project structure - -This project uses a **monorepo structure** with **pnpm workspaces**. Each package is independent with its own -`package.json`, build system, and tests. - -### Main packages - -- [**client**][client-dir]: VSCode extension code which has access to all VS Code Namespace API. - - Built with Rspack - - Contains the extension activation logic and VSCode integration -- [**server**][server-dir]: Language server running in a separate process. - - Built with Rspack with code splitting for large dependencies - - Handles AGLint integration, diagnostics, and language features -- [**shared**][shared-dir]: Shared utilities used by both client and server packages. - - Built with Rspack - - Contains common types and utilities -- [**syntaxes**][syntaxes-dir]: TextMate grammars for syntax highlighting. - - Converts YAML grammar to PList format for VSCode - - Contains grammar tests and utilities - -### Supporting folders - -- [**test**][test-dir]: Static test files and test workspaces. - - [**static/aglint**][test-static-aglint-dir]: AGLint test project workspace. - - [**static/rules**][test-static-rules-dir]: Rules for testing the syntax highlighting visually. -- [**tools**][tools-dir]: Build and utility scripts for the project. -- [**bamboo-specs**][bamboo-specs-dir]: CI/CD pipeline configurations. - -> [!NOTE] -> To learn more about the client-server architecture of VSCode extensions, refer to the [VSCode Language Server -> Extension Guide][vscode-ls-extension-guide]. - -## Running the extension in development mode - -If you've made changes to the extension code and want to test them, follow these steps: - -1. Open the project's **root** folder in VSCode. -1. Select `Run > Start Debugging` menu item in VSCode (or just press the `F5` key). This starts the watch build process - in the background, opening a new VSCode window called "Extension Development Host" where you can test the extension. -1. Watch build does not automatically update the extension in the "Extension Development Host" window. You'll need to - reload the window manually by pressing `Ctrl + R` or selecting `Developer: Reload Window` command in the command - palette (`Ctrl + Shift + P`). - -> [!IMPORTANT] -> When you start the debugging, VSCode starts the watch build commands in separate terminals. To interpret the terminal -> output correctly, VSCode relies on [problem matchers][vscode-problem-matcher-docs], -> otherwise the watch build will not stop when it encounters an error. - -## Creating a production build - -To create a production build of the extension: - -1. Run `pnpm build` command to build packages. -2. Run `pnpm package` command to package the extension into a `.vsix` file. -3. To ensure the build is correct, install the generated `.vsix` file in VSCode. Open the command palette - (`Ctrl + Shift + P`), select "Extensions: Install from VSIX...", and choose the `vscode-adblock.vsix` file. - -## Updating syntax highlighting - -1. Update the TM grammar in the `syntaxes/adblock.yaml-tmlanguage` file. -1. Create/modify example rules in the `test/static/rules` folder. Add link for GitHub issues to rules if related to some - issue. -1. Create/modify unit tests in `syntaxes/test/adblock`. Ensure tests pass by running - `pnpm --filter @vscode-adblock-syntax/syntaxes test`. - -> [!TIP] -> Open the `test/static` folder in the "Extension Development Host" window and you can check the syntax highlighting -> visually. This is useful when you want to check how the highlighting works with specific rules. - -> [!NOTE] -> You can use the [Online test page for TextMate grammars][nova-light-show] to test the TM grammars. - -## Available commands - -During development, you can use the following commands (listed in `package.json`). - -### Build commands - -- `pnpm build` - Build all packages recursively with minification enabled. - -### Package commands - -- `pnpm package` - Package the extension into a `.vsix` file in the `out` directory. -- `pnpm package:pre` - Package the extension with the `--pre-release` flag for prerelease builds. - -### Package-level build commands - -Each package can be built independently using pnpm workspace filters: - -- `pnpm --filter @vscode-adblock-syntax/shared build` - Build the shared package with Rspack. -- `pnpm --filter @vscode-adblock-syntax/client build` - Build the client package with Rspack. -- `pnpm --filter @vscode-adblock-syntax/server build` - Build the server package with Rspack (includes code splitting). -- `pnpm --filter @vscode-adblock-syntax/syntaxes build` - Build the syntaxes package (converts grammar to PList format). - -> [!NOTE] -> Rspack builds are configured via `rspack.config.ts` files in each package. Production mode is enabled via -> `NODE_ENV=production` environment variable, which is set automatically by the root `pnpm build` command. - -### Utility commands - -- `pnpm clean` - Removes all generated files using the clean utility script. -- `pnpm increment` - Increment the patch version number in the `package.json` file. Typically used by CI. - -### Linting & testing commands - -- `pnpm lint` - Run all linters recursively across all packages. -- `pnpm lint:code` - Lint the code with [ESLint][eslint]. -- `pnpm lint:md` - Lint the markdown files with [markdownlint][markdownlint]. -- `pnpm test` - Run tests recursively across all packages with [Vitest][vitest]. -- `pnpm test:compile` - Type-check all packages without emitting files. - -You can also run linting and tests for individual packages: - -- `pnpm --filter @vscode-adblock-syntax/shared lint` / `test` -- `pnpm --filter @vscode-adblock-syntax/client lint` / `test` -- `pnpm --filter @vscode-adblock-syntax/server lint` / `test` -- `pnpm --filter @vscode-adblock-syntax/syntaxes lint` / `test` - -> [!NOTE] -> Watch builds are handled automatically by VSCode tasks when you start debugging (see -> [`.vscode/tasks.json`][vscode-tasks-file] file). Each package (shared, client, server, syntaxes) has its own watch -> task that rebuilds on file changes. - -> [!NOTE] -> Linting and testing commands are called automatically by Husky Git hooks and CI. You can run them manually if needed. - -## Versioning policy - -This project follows [Semantic Versioning (SemVer)][semver] with specific requirements for VS Code extensions. -See [VS Code pre-release extensions documentation][vscode-prerelease] for more details. - -### VS Code extension versioning requirements - -> [!IMPORTANT] -> VS Code Marketplace and Open VSX **only support `major.minor.patch` format**. Pre-release tags like `1.0.0-alpha` or -> `1.0.0-beta` are **NOT supported** and will be rejected by the stores. - -### Pre-release versioning strategy - -To support pre-release versions while maintaining compatibility, we use an **odd/even minor version scheme**: - -- **Release versions**: `major.EVEN.patch` → e.g., `2.0.0`, `2.0.1`, `2.2.0` -- **Pre-release versions**: `major.ODD.patch` → e.g., `2.1.0`, `2.1.1`, `2.3.0` - -**Version progression example:** - -```text -2.0.0 → 2.1.0 (start pre-release) → 2.1.1 (pre-release update) → 2.2.0 (promote to release) -``` - -> [!WARNING] -> VS Code auto-updates to the highest version. Always ensure pre-release versions are higher than release versions to -> prevent downgrading pre-release users. - -## Useful links - -Explore the following links for more information on development: - -- [TMLanguage](https://code.visualstudio.com/api/language-extensions/syntax-highlight-guide) -- [VSCode API](https://code.visualstudio.com/api/references/vscode-api) -- [VSCode Language Server Extension Guide](https://code.visualstudio.com/api/language-extensions/language-server-extension-guide) -- [VSCode Extension Samples](https://github.com/microsoft/vscode-extension-samples) -- [Online test page for TextMate grammars][nova-light-show] - -[bamboo-specs-dir]: ./bamboo-specs -[client-dir]: ./client [contribute]: https://adguard.com/contribute.html -[eslint]: https://eslint.org/ -[husky]: https://typicode.github.io/husky -[markdownlint]: https://github.com/DavidAnson/markdownlint -[nova-light-show]: https://novalightshow.netlify.app/ -[semver]: https://semver.org/ -[server-dir]: ./server -[shared-dir]: ./shared -[syntaxes-dir]: ./syntaxes -[test-dir]: ./test -[test-static-aglint-dir]: ./test/static/aglint -[test-static-rules-dir]: ./test/static/rules -[tools-dir]: ./tools -[vitest]: https://vitest.dev/ -[vscode-extensions-file]: ./.vscode/extensions.json -[vscode-ls-extension-guide]: https://code.visualstudio.com/api/language-extensions/language-server-extension-guide -[vscode-prerelease]: https://code.visualstudio.com/api/working-with-extensions/publishing-extension#prerelease-extensions -[vscode-problem-matcher-docs]: https://code.visualstudio.com/docs/editor/tasks#_processing-task-output-with-problem-matchers -[vscode-tasks-file]: ./.vscode/tasks.json -[vscode]: https://code.visualstudio.com/ diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md new file mode 100644 index 0000000..ab190c3 --- /dev/null +++ b/DEVELOPMENT.md @@ -0,0 +1,279 @@ + +# Development Guide + +A comprehensive guide for developers working on the VSCode Adblock Syntax +extension: how to set up the environment, run the project locally, test, build, +and contribute code. + +This is the repo-wide guide. Each package has its own focused guide: + +- [client/DEVELOPMENT.md](client/DEVELOPMENT.md) — VSCode extension client (LSP client). +- [server/DEVELOPMENT.md](server/DEVELOPMENT.md) — LSP language server (AGLint integration). +- [shared/DEVELOPMENT.md](shared/DEVELOPMENT.md) — shared types and utilities. +- [syntaxes/DEVELOPMENT.md](syntaxes/DEVELOPMENT.md) — TextMate grammar and tests. +- [tools/DEVELOPMENT.md](tools/DEVELOPMENT.md) — repository build/utility scripts. + +For code guidelines and architecture, see [AGENTS.md](AGENTS.md). For the +user-facing manual, see [README.md](README.md). + + +## Table of Contents + +- [Prerequisites](#prerequisites) +- [Getting Started](#getting-started) + - [Clone and install](#clone-and-install) + - [Recommended VSCode extensions](#recommended-vscode-extensions) + - [Project structure](#project-structure) +- [Development Workflow](#development-workflow) + - [Running the extension in development mode](#running-the-extension-in-development-mode) + - [Code style and linting](#code-style-and-linting) + - [Testing](#testing) + - [Type checking](#type-checking) + - [Building for production](#building-for-production) + - [Branching and pull requests](#branching-and-pull-requests) +- [Common Tasks](#common-tasks) + - [Available commands](#available-commands) + - [Updating syntax highlighting](#updating-syntax-highlighting) + - [Packaging the extension](#packaging-the-extension) + - [Working in a single package](#working-in-a-single-package) + - [Versioning](#versioning) +- [Troubleshooting](#troubleshooting) +- [Additional Resources](#additional-resources) + +## Prerequisites + +Install the following before you start: + +- [Node.js](https://nodejs.org/en/download): v22 (the engines field requires + `>=20`; development uses Node v22). Use [nvm](https://github.com/nvm-sh/nvm) + to manage multiple versions. +- [pnpm](https://pnpm.io/installation): v10 (the repo pins `packageManager` to + pnpm 10). +- [VSCode](https://code.visualstudio.com/): the extension host targets + VSCode `^1.74.0`. +- [Git](https://git-scm.com/). + +## Getting Started + +### Clone and install + +```bash +git clone https://github.com/AdguardTeam/VscodeAdblockSyntax.git +cd VscodeAdblockSyntax +pnpm install +``` + +`pnpm install` installs dependencies for every workspace package and runs the +`prepare` script, which initializes [Husky](https://typicode.github.io/husky) +Git hooks (linting and tests run on commit). + +### Recommended VSCode extensions + +Open the repository root in VSCode and install the recommended extensions when +prompted (defined in [.vscode/extensions.json](.vscode/extensions.json)). They +are **required** for the development workflow: + +- `dbaeumer.vscode-eslint` — ESLint integration. +- `davidanson.vscode-markdownlint` — Markdown linting. +- `vitest.explorer` — run and debug Vitest tests from the editor. +- `editorconfig.editorconfig` — consistent editor settings. + +### Project structure + +This is a [pnpm workspaces](https://pnpm.io/workspaces) monorepo of five +packages plus supporting folders: + +```text +. +├── client/ # VSCode extension entry (LSP client) +├── server/ # LSP language server (AGLint integration) +├── shared/ # Shared types/utilities for client + server +├── syntaxes/ # TextMate grammar source, compiler, tests +├── tools/ # Repo build/utility scripts +├── test/ # Static fixtures (sample rules, AGLint test workspace) +├── icons/ # Extension icons +└── bamboo-specs/ # CI/CD pipeline configuration +``` + +The dependency direction is one-way: `client` and `server` depend on `shared`; +`shared` depends on neither. `client` and `server` run as separate processes and +communicate only over the Language Server Protocol (LSP). See [AGENTS.md](AGENTS.md) +for the full architecture. + +## Development Workflow + +### Running the extension in development mode + +1. Open the repository **root** folder in VSCode. +2. Select `Run > Start Debugging` or press `F5`. This runs the + `Launch Client` configuration in [.vscode/launch.json](.vscode/launch.json), + which starts the watch build tasks + (see [.vscode/tasks.json](.vscode/tasks.json)) and opens a new + "Extension Development Host" window with the + [test/static/aglint](test/static/aglint) workspace loaded. +3. The watch build does **not** auto-reload the extension. After changing code, + reload the host window with `Cmd/Ctrl + R` or run + `Developer: Reload Window` from the command palette. + +> The debug launch relies on VSCode problem matchers to interpret the watch +> build output; if the build errors, the launch stops. + +### Code style and linting + +Formatting and style are enforced by ESLint (airbnb-base + airbnb-typescript, +JSDoc, import, boundaries) and markdownlint. There is no separate format +command. Key rules: 4-space indentation, max line length 120, grouped and +alphabetized imports, inline type imports, required JSDoc. Full rules live in +[AGENTS.md](AGENTS.md#code-quality). + +```bash +pnpm lint # all linters recursively (ESLint + markdownlint) +pnpm lint:code # ESLint only (add -- --fix to auto-fix) +pnpm lint:md # markdownlint only +``` + +### Testing + +Every package uses [Vitest](https://vitest.dev). Run all tests from the root: + +```bash +pnpm test # run all package tests once +``` + +Run tests for a single package with a workspace filter (see +[Working in a single package](#working-in-a-single-package)). Update or add +tests for any code you change before considering a task done. + +### Type checking + +```bash +pnpm test:compile # type-check all packages (tsc --noEmit), no emit +``` + +TypeScript targets `ESNext` with `strict` mode; shared compiler options are in +[tsconfig.base.json](tsconfig.base.json). + +### Building for production + +```bash +pnpm build # build all packages recursively in production mode +``` + +This sets `NODE_ENV=production` and builds the shared, client, and server +bundles with [Rspack](https://rspack.dev) (minified) and compiles the grammar +with `tsx`. + +### Branching and pull requests + +- Branch off the default branch and keep changes focused. +- Husky hooks run linters and tests on commit; do **not** bypass them with + `--no-verify`. +- Before opening a pull request, ensure `pnpm lint`, `pnpm test:compile`, and + `pnpm test` all pass. +- Update the relevant `AGENTS.md` when you change project structure, commands, + or the client/server protocol, and update [README.md](README.md) when + user-facing behavior changes. +- AdGuard contributors can receive rewards; see the + [contribute page](https://adguard.com/contribute.html). + +## Common Tasks + +### Available commands + +Run from the repository root with pnpm v10: + +| Command | Description | +| --- | --- | +| `pnpm build` | Build all packages recursively (production, minified). | +| `pnpm test` | Run all package tests once (Vitest). | +| `pnpm test:compile` | Type-check all packages (`tsc --noEmit`). | +| `pnpm lint` | Run all linters recursively (ESLint + markdownlint). | +| `pnpm lint:code` | Lint code with ESLint (cached). | +| `pnpm lint:md` | Lint Markdown with markdownlint. | +| `pnpm clean` | Remove generated files / `node_modules`. | +| `pnpm package` | Package the extension into `out/vscode-adblock.vsix`. | +| `pnpm package:pre` | Package a pre-release build (`--pre-release`). | +| `pnpm increment` | Increment the patch version (used by CI). | + +### Updating syntax highlighting + +1. Edit the grammar source in + [syntaxes/adblock.yaml-tmlanguage](syntaxes/adblock.yaml-tmlanguage). +2. Add or modify example rules under [test/static/rules](test/static/rules) (link + related GitHub issues in the rule files). +3. Add or update tokenization tests under + [syntaxes/test/adblock](syntaxes/test/adblock) and rebuild the grammar, then + run `pnpm --filter @vscode-adblock-syntax/syntaxes test`. +4. Open the [test/static](test/static) folder in the Extension Development Host + to check highlighting visually. + +See [syntaxes/DEVELOPMENT.md](syntaxes/DEVELOPMENT.md) for full details. + +### Packaging the extension + +```bash +pnpm build # build all packages first +pnpm package # produces out/vscode-adblock.vsix +``` + +To verify a build, install the generated `.vsix` in VSCode: command palette → +`Extensions: Install from VSIX...` → select `out/vscode-adblock.vsix`. + +### Working in a single package + +Use pnpm workspace filters to scope commands to one package, for example: + +```bash +pnpm --filter @vscode-adblock-syntax/server build +pnpm --filter @vscode-adblock-syntax/syntaxes test +pnpm --filter @vscode-adblock-syntax/client exec tsc --noEmit +``` + +Each package guide documents its own commands: +[client](client/DEVELOPMENT.md), [server](server/DEVELOPMENT.md), +[shared](shared/DEVELOPMENT.md), [syntaxes](syntaxes/DEVELOPMENT.md), +[tools](tools/DEVELOPMENT.md). + +### Versioning + +The extension uses an **odd/even minor** scheme: even minor versions are +releases (`2.0.0`, `2.2.0`), odd minor versions are pre-releases (`2.1.0`, +`2.3.0`). VSCode Marketplace and Open VSX accept only `major.minor.patch` — no +`-alpha`/`-beta` suffixes. Always keep pre-release versions higher than the +latest release so VSCode does not downgrade pre-release users. + +## Troubleshooting + +- **Changes not visible in the Extension Development Host**: reload the host + window (`Cmd/Ctrl + R`); the watch build does not auto-reload. +- **Watch build stops on launch**: the `F5` launch halts when the watch build + reports an error via the problem matcher. Fix the reported TypeScript/ESLint + error and relaunch. +- **AGLint linting does not run**: AGLint is resolved from the user's workspace + (local or global), not bundled. Confirm `@adguard/aglint` (>= `4.0.0-beta.1`) + is installed and an `.aglintrc.*` config exists. The + [test/static/aglint](test/static/aglint) workspace is preconfigured. +- **No linting in virtual/untrusted workspaces**: this is expected — AGLint needs + the Node.js filesystem API, so only syntax highlighting is available there. +- **Grammar/tokenization tests fail to load the grammar**: build the grammar + first (`pnpm --filter @vscode-adblock-syntax/syntaxes build`); tests load the + compiled `out/adblock.plist`. +- **Stale build or dependency issues**: run `pnpm clean` then `pnpm install` to + reset generated files and `node_modules`. +- **Husky hook blocks a commit**: fix the reported lint/test failures rather than + bypassing the hook with `--no-verify`. + +## Additional Resources + +- [AGENTS.md](AGENTS.md) — code guidelines and architecture. +- [README.md](README.md) — user-facing documentation. +- Package guides: + [client](client/DEVELOPMENT.md), + [server](server/DEVELOPMENT.md), + [shared](shared/DEVELOPMENT.md), + [syntaxes](syntaxes/DEVELOPMENT.md), + [tools](tools/DEVELOPMENT.md). +- [VSCode Language Server Extension Guide](https://code.visualstudio.com/api/language-extensions/language-server-extension-guide) +- [VSCode Syntax Highlight Guide](https://code.visualstudio.com/api/language-extensions/syntax-highlight-guide) +- [VSCode API reference](https://code.visualstudio.com/api/references/vscode-api) +- [Online test page for TextMate grammars](https://novalightshow.netlify.app/) diff --git a/README.md b/README.md index b0ab004..cdbf56e 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ AdBlock AdBlock・ Adblock Plus Adblock Plus -[Install][marketplace] • [Documentation](#features) • [Report Issue][issues] • [Contributing][contributing] +[Install][marketplace] • [Documentation](#features) • [Report Issue][issues] • [Development Guide][development]

@@ -152,7 +152,7 @@ like `[Adblock Plus 2.0]` or `[AdGuard]`. ## 🤝 Contributing -Contributions are welcome! Please read our [Contributing Guide][contributing] for details on how to get started. +Contributions are welcome! Please read our [Development Guide][development] for details on how to get started. ## 📝 License @@ -209,7 +209,7 @@ Made with ❤️ by [AdGuard][adguard] [badge-license]: https://img.shields.io/github/license/AdguardTeam/VscodeAdblockSyntax [badge-openvsx]: https://img.shields.io/open-vsx/v/adguard/adblock?label=Open%20VSX [badge-vscode]: https://img.shields.io/visual-studio-marketplace/v/adguard.adblock?label=VSCode%20Marketplace -[contributing]: CONTRIBUTING.md +[development]: DEVELOPMENT.md [discussions]: https://github.com/AdguardTeam/VscodeAdblockSyntax/discussions [feature-request]: https://github.com/AdguardTeam/VscodeAdblockSyntax/issues/new [issues]: https://github.com/AdguardTeam/VscodeAdblockSyntax/issues diff --git a/client/.markdownlint.json b/client/.markdownlint.json new file mode 100644 index 0000000..393b086 --- /dev/null +++ b/client/.markdownlint.json @@ -0,0 +1,3 @@ +{ + "extends": "../.markdownlint.json" +} diff --git a/client/AGENTS.md b/client/AGENTS.md new file mode 100644 index 0000000..79ed188 --- /dev/null +++ b/client/AGENTS.md @@ -0,0 +1,189 @@ + +# AGENTS.md — client + +Agent reference for the `@vscode-adblock-syntax/client` package: the VSCode +extension entry point and Language Server Protocol (LSP) client. + +This is part of a monorepo. For repo-wide conventions (dependency management, +Markdown formatting, versioning, contribution rules) see the root +[AGENTS.md](../AGENTS.md). For environment setup see +[DEVELOPMENT.md](../DEVELOPMENT.md). + + +## Table of Contents + +- [Project Overview](#project-overview) +- [Technical Context](#technical-context) +- [Project Structure](#project-structure) +- [Contribution Instructions](#contribution-instructions) +- [Code Guidelines](#code-guidelines) + - [System Design](#system-design) + - [Architecture](#architecture) + - [Code Quality](#code-quality) + - [Testing](#testing) + - [Dependency Management](#dependency-management) + - [Configuration \& Documentation](#configuration--documentation) + - [Markdown Formatting](#markdown-formatting) +- [Related Agents](#related-agents) + +## Project Overview + +The client is the VSCode-facing half of the extension. It activates the +extension, spins up one language client (and a separate server process) per +outermost workspace folder, manages their lifecycle, mirrors AGLint status in +the status bar, and forwards document/configuration events to the server over +LSP. It holds **all** direct VSCode API access; linting logic lives in the +[server](../server/AGENTS.md). + +## Technical Context + +- **Language/Version**: TypeScript targeting `ESNext` (see + [tsconfig.base.json](../tsconfig.base.json)), `strict` mode. +- **Runtime**: VSCode extension host (Node.js), VSCode `^1.74.0`. +- **Primary Dependencies**: `vscode-languageclient` (LSP client), + `@vscode-adblock-syntax/shared` (shared types), `valibot` (validation), + `vscode` API (provided by the host). +- **Storage**: None — in-memory maps of clients and per-folder status. +- **Testing**: Vitest, with a mocked `vscode` module. +- **Build**: Rspack, output to `out/` (root `package.json` `main` points to + `./client/out/extension`). +- **Project Type**: monorepo package (VSCode extension entry). + +## Project Structure + +```text +client/ +├── package.json # Package manifest and scripts +├── rspack.config.ts # Bundler config (output to out/) +├── src/ +│ ├── extension.ts # Entry point: activate/deactivate, LSP client lifecycle +│ ├── constants.ts # Client IDs, language ID, file extensions, status bar config +│ ├── workspace-folders.ts # Outermost-folder resolution, file-in-folder checks +│ └── utils/ +│ ├── log-level.ts # Maps VSCode log level → AGLint debug flag +│ └── status-parser.ts # Parses aglint/status notification params +└── tests/ + ├── __mocks__/vscode.ts # Mock VSCode API for tests + ├── workspace-folders.test.ts + └── utils/ # Unit tests mirroring src/utils +``` + +## Contribution Instructions + +After completing a task, you MUST do the following: + +- Verify your changes with the linter and type checker: + - `pnpm --filter @vscode-adblock-syntax/client exec tsc --noEmit` for type + errors. + - `pnpm --filter @vscode-adblock-syntax/client lint:code` (add `--fix` to + auto-fix) for ESLint. + - `pnpm --filter @vscode-adblock-syntax/client lint:md` for Markdown. +- Update or add Vitest unit tests for any changed code. +- Run `pnpm --filter @vscode-adblock-syntax/client test` and ensure all tests + pass. +- When you change this package's structure, update the + [Project Structure](#project-structure) section above. +- If a prompt asks you to refactor or improve code, capture the lesson as a + guideline under [Code Guidelines](#code-guidelines). +- Verify new code follows these Code Guidelines and the root + [AGENTS.md](../AGENTS.md). + +## Code Guidelines + +### System Design + +Design for the VSCode extension host: + +- Keep all VSCode API usage in this package; never duplicate it in the server. +- Communicate with the server only over LSP (requests, notifications, + middleware). Do not share mutable state across the process boundary. +- Create one client/server pair per **outermost** workspace folder (use + `getOuterMostWorkspaceFolder`); a dedicated default client handles untitled + documents. Dispose clients and their stored status when a folder is removed. +- React to events (document open/change/save, active editor change, workspace + folder change, log-level change) asynchronously; never block the extension + host. +- Keep activation fast and the bundle small; defer heavy work to the server + process. + +### Architecture + +The client is a thin VSCode integration layer. Principles: + +- **Separation of Concerns** — `extension.ts` orchestrates lifecycle; + `workspace-folders.ts` handles folder math; `utils/` handles pure + transformations (log level, status parsing). +- **Single Responsibility** — keep pure helpers (status parsing, log-level + mapping) free of VSCode API calls so they stay unit-testable. +- **Dependency Direction** — depend only on `vscode`, `vscode-languageclient`, + and `@vscode-adblock-syntax/shared`; never import from `server`. +- **Explicit Boundaries** — the only channel to the server is LSP; the only + channel to the user is the VSCode API (status bar, output channels). +- **Data Flow Clarity** — document events → middleware filter (file-in-folder) + → server; `aglint/status` notifications → status bar. +- **Make Invalid States Impossible** — validate notification payloads + (`parseStatusParams`) before using them. +- **Observability Built-in** — each client gets a VSCode `LogOutputChannel`, + making it visible under "Developer: Set Log Level". + +Layers: + +| Layer | Responsibility | Example | +| --- | --- | --- | +| Activation/lifecycle | Create, start, dispose clients | [src/extension.ts](src/extension.ts) | +| Workspace logic | Outermost folder, file containment | [src/workspace-folders.ts](src/workspace-folders.ts) | +| Pure utilities | Log level, status parsing | [src/utils/status-parser.ts](src/utils/status-parser.ts) | + +Dependency flow: + +```mermaid +flowchart LR + extension["extension.ts (VSCode API + LSP client)"] --> workspace["workspace-folders.ts (pure)"] + extension --> utils["utils/* (pure)"] + extension --> shared["@vscode-adblock-syntax/shared (FileScheme, types)"] +``` + +### Code Quality + +- Follow the root [Code Quality](../AGENTS.md#code-quality) rules: required + JSDoc, 4-space indent, max line length 120, grouped/alphabetized imports, + inline type imports. +- Keep VSCode API calls out of pure helpers so they can be tested with the + mocked `vscode` module. +- Swallow only expected errors (e.g. notifications sent before the server is + ready) and document why. + +### Testing + +- Vitest tests live in [tests/](tests) and mirror `src/`. +- The VSCode API is mocked in [tests/\_\_mocks\_\_/vscode.ts](tests/__mocks__/vscode.ts); + pure helpers are tested directly. +- Add tests for new folder-resolution logic, status parsing, and log-level + mapping. All tests must pass before completing a task. + +### Dependency Management + +Follow the root [Dependency Management](../AGENTS.md#dependency-management) +rules. Add dependencies via the workspace `catalog`; keep the client bundle +small because its size affects extension activation time. + +### Configuration & Documentation + +- The client reads VSCode settings indirectly: it passes initialization options + (workspace folder, debug flag) to the server, which fetches + `adblock.*` settings. Update [src/constants.ts](src/constants.ts) when IDs, + watched file patterns, or supported extensions change. +- When the client/server protocol or activation behavior changes, update this + file and the root [AGENTS.md](../AGENTS.md). + +### Markdown Formatting + +Follow the root [Markdown Formatting](../AGENTS.md#markdown-formatting) rules +(max line length 120, dash bullets, 4-space nested indent, asterisk emphasis, +limited inline HTML). + +## Related Agents + +- Root: [AGENTS.md](../AGENTS.md) +- Server: [server/AGENTS.md](../server/AGENTS.md) +- Shared: [shared/AGENTS.md](../shared/AGENTS.md) diff --git a/client/DEVELOPMENT.md b/client/DEVELOPMENT.md new file mode 100644 index 0000000..1954fa1 --- /dev/null +++ b/client/DEVELOPMENT.md @@ -0,0 +1,120 @@ + +# Development Guide — client + +Developer guide for the `@vscode-adblock-syntax/client` package: the VSCode +extension entry point and Language Server Protocol (LSP) client. + +This is part of a monorepo. For environment setup, the debug workflow, and +repo-wide commands, start with the root [DEVELOPMENT.md](../DEVELOPMENT.md). For +code guidelines and architecture, see [AGENTS.md](AGENTS.md). + + +## Table of Contents + +- [Overview](#overview) +- [Prerequisites](#prerequisites) +- [Getting Started](#getting-started) +- [Development Workflow](#development-workflow) + - [Build](#build) + - [Test](#test) + - [Lint](#lint) + - [Type check](#type-check) +- [Common Tasks](#common-tasks) +- [Troubleshooting](#troubleshooting) +- [Additional Resources](#additional-resources) + +## Overview + +The client is the VSCode-facing half of the extension. It activates the +extension, creates one language client (and a separate server process) per +outermost workspace folder, manages their lifecycle, mirrors AGLint status in +the status bar, and forwards document/configuration events to the server over +LSP. It holds **all** direct VSCode API access; linting logic lives in the +[server](../server/DEVELOPMENT.md). It is built with Rspack; the root +`package.json` `main` field points to `./client/out/extension`. + +## Prerequisites + +Same as the repo: Node.js v22, pnpm v10, VSCode `^1.74.0`, Git. See the root +[Prerequisites](../DEVELOPMENT.md#prerequisites). Run `pnpm install` once from +the repository root to install dependencies for all packages. + +## Getting Started + +The client cannot be exercised in isolation — run it through the extension debug +host: + +1. Open the repository **root** in VSCode. +2. Press `F5` (Launch Client) to start the watch builds and open the Extension + Development Host. +3. Reload the host window (`Cmd/Ctrl + R`) after changing client code. + +See [Running the extension in development mode](../DEVELOPMENT.md#running-the-extension-in-development-mode). + +## Development Workflow + +Run these from this directory, or from the repo root with the +`--filter @vscode-adblock-syntax/client` flag. + +### Build + +```bash +pnpm --filter @vscode-adblock-syntax/client build # Rspack -> client/out +``` + +The `prebuild` script clears `out/` first. Add `--watch` (or use the VSCode +watch task) for incremental rebuilds during debugging. + +### Test + +```bash +pnpm --filter @vscode-adblock-syntax/client test # Vitest +``` + +Tests live in [tests/](tests) and mirror `src/`. The VSCode API is mocked in +[tests/\_\_mocks\_\_/vscode.ts](tests/__mocks__/vscode.ts); pure helpers +(`workspace-folders`, `log-level`, `status-parser`) are tested directly. + +### Lint + +```bash +pnpm --filter @vscode-adblock-syntax/client lint # ESLint + markdownlint +pnpm --filter @vscode-adblock-syntax/client lint:code # ESLint (add -- --fix) +pnpm --filter @vscode-adblock-syntax/client lint:md # markdownlint +``` + +### Type check + +```bash +pnpm --filter @vscode-adblock-syntax/client exec tsc --noEmit +``` + +## Common Tasks + +- **Add a pure helper**: place it under `src/utils/`, keep it free of VSCode API + calls so it stays unit-testable, and add a matching test under `tests/utils/`. +- **Change client/server messages**: update the LSP wiring in + [src/extension.ts](src/extension.ts) and keep the contract in sync with the + [server](../server/DEVELOPMENT.md); share types via + [shared](../shared/DEVELOPMENT.md), never import from `server`. +- **Change IDs, watched file patterns, or extensions**: update + [src/constants.ts](src/constants.ts). + +## Troubleshooting + +- **Client code changes have no effect**: reload the Extension Development Host + window; the watch build does not auto-reload. +- **`vscode` import errors in tests**: ensure the test uses the mock in + [tests/\_\_mocks\_\_/vscode.ts](tests/__mocks__/vscode.ts) and that pure logic + is not pulling in the real VSCode API. +- **Status bar not updating**: verify the `aglint/status` notification payload + passes `parseStatusParams` validation. + +## Additional Resources + +- Root guide: [DEVELOPMENT.md](../DEVELOPMENT.md) +- Code guidelines: [AGENTS.md](AGENTS.md) +- Related packages: + [server](../server/DEVELOPMENT.md), + [shared](../shared/DEVELOPMENT.md) +- [VSCode Language Server Extension Guide](https://code.visualstudio.com/api/language-extensions/language-server-extension-guide) diff --git a/server/.markdownlint.json b/server/.markdownlint.json new file mode 100644 index 0000000..393b086 --- /dev/null +++ b/server/.markdownlint.json @@ -0,0 +1,3 @@ +{ + "extends": "../.markdownlint.json" +} diff --git a/server/AGENTS.md b/server/AGENTS.md new file mode 100644 index 0000000..76faf14 --- /dev/null +++ b/server/AGENTS.md @@ -0,0 +1,249 @@ + +# AGENTS.md — server + +Agent reference for the `@vscode-adblock-syntax/server` package: the Language +Server Protocol (LSP) server that integrates AGLint to provide diagnostics and +code actions. + +This is part of a monorepo. For repo-wide conventions (dependency management, +Markdown formatting, versioning, contribution rules) see the root +[AGENTS.md](../AGENTS.md). For environment setup see +[DEVELOPMENT.md](../DEVELOPMENT.md). + + +## Table of Contents + +- [Project Overview](#project-overview) +- [Technical Context](#technical-context) +- [Project Structure](#project-structure) +- [Contribution Instructions](#contribution-instructions) +- [Code Guidelines](#code-guidelines) + - [System Design](#system-design) + - [Architecture](#architecture) + - [Code Quality](#code-quality) + - [Testing](#testing) + - [Dependency Management](#dependency-management) + - [Configuration \& Documentation](#configuration--documentation) + - [Markdown Formatting](#markdown-formatting) + - [Other](#other) +- [Related Agents](#related-agents) + +## Project Overview + +The server runs as a separate Node.js process, one per outermost workspace +folder, and speaks LSP to the [client](../client/AGENTS.md). It dynamically +locates and loads AGLint from the user's workspace (local or global install), +lints filter-list documents, converts AGLint problems into VSCode diagnostics, +and offers code actions (apply fix, apply suggestion, disable a rule). All state +is held in memory and the server degrades gracefully if AGLint cannot be loaded. + +## Technical Context + +- **Language/Version**: TypeScript targeting `ESNext`, `strict` mode. +- **Runtime**: Node.js `>=20` (the LSP server process). +- **Primary Dependencies**: `vscode-languageserver`, + `vscode-languageserver-textdocument`, `vscode-uri`, + `@vscode-adblock-syntax/shared`; `fast-glob`, `resolve`, `preferred-pm`, + `semver`, `debounce`, `yaml`. `@adguard/aglint` and `@adguard/agtree` are + type-only/dev dependencies — AGLint is loaded from the user's workspace at + runtime, not bundled. +- **Storage**: None — in-memory `ServerContext`, `AglintContext`, and an LRU + diagnostics cache. +- **Testing**: Vitest (with `@vitest/coverage-v8`). +- **Build**: Rspack with code splitting; output to `out/server.js`. +- **Project Type**: monorepo package (LSP server). + +## Project Structure + +```text +server/ +├── package.json # Manifest and scripts +├── rspack.config.ts # Bundler config (code splitting) +├── src/ +│ ├── server.ts # Entry point: LSP connection, ServerContext, handler wiring +│ ├── settings.ts # ExtensionSettings interface +│ ├── handlers/ # LSP event entry points +│ │ ├── initialization.ts # onInitialize: capabilities, workspace root +│ │ ├── event-handlers.ts # Registers document/config/watch/log-level listeners +│ │ └── configuration.ts # Settings fetch, AGLint context (re)initialization +│ ├── context/ # Centralized state containers +│ │ ├── server-context.ts # All mutable server state (connection, docs, cache, flags) +│ │ └── aglint-context.ts # AGLint module, debugger, fs/path adapters, linter tree +│ ├── linting/ # Linting orchestration and caching +│ │ ├── orchestration.ts # Public APIs: lintFile, refreshLinter, debounce, config +│ │ ├── helpers.ts # shouldLintDocument, performLinting, cache lookup +│ │ ├── diagnostics.ts # AGLint result → VSCode diagnostic conversion +│ │ └── cache.ts # LRU diagnostics cache (version/config-keyed) +│ ├── code-actions/ # Quick fixes and suggestions +│ │ ├── index.ts # Code action request entry/router +│ │ ├── fix-actions.ts # Fix + suggestion code actions +│ │ ├── disable-rule.ts # Disable-rule / disable-next-line actions +│ │ └── utils.ts # Range/offset/fix conversion helpers +│ ├── loaders/aglint.ts # Dynamic AGLint resolution, version check, import +│ ├── adapters/fs.ts # LSPFileSystemAdapter (AGLint fs over LSP docs + disk) +│ ├── common/constants.ts # AGLint package name, repo URL, char constants +│ └── utils/ # Low-level helpers +│ ├── error.ts # getErrorMessage, getErrorStack +│ ├── uri.ts # isFileUri +│ ├── workspace.ts # extractWorkspaceRootUri, root-from-rootUri +│ ├── file-exists.ts # Async existence check +│ ├── module-resolver.ts # resolveModulePath (local/global packages) +│ ├── package-managers.ts # npm/yarn/pnpm/bun global root discovery +│ └── import.ts # Dynamic import wrapper +└── test/ # Vitest tests mirroring src/ (+ helpers/mocks.ts) +``` + +## Contribution Instructions + +After completing a task, you MUST do the following: + +- Verify your changes with the linter and type checker: + - `pnpm --filter @vscode-adblock-syntax/server exec tsc --noEmit` for type + errors. + - `pnpm --filter @vscode-adblock-syntax/server lint:code` (add `--fix`) for + ESLint. + - `pnpm --filter @vscode-adblock-syntax/server lint:md` for Markdown. +- Update or add Vitest unit tests for any changed code. +- Run `pnpm --filter @vscode-adblock-syntax/server test` and ensure all tests + pass. +- When you change this package's structure, update the + [Project Structure](#project-structure) section above. +- If a prompt asks you to refactor or improve code, capture the lesson as a + guideline under [Code Guidelines](#code-guidelines). +- Verify new code follows these Code Guidelines and the root + [AGENTS.md](../AGENTS.md). + +## Code Guidelines + +### System Design + +Design for a long-lived LSP server process: + +- The server is a long-running process (one per outermost workspace folder). + Clean up resources (watchers, debounced timers, AGLint handles) proactively; + do not rely on process exit. +- Handlers are request/notification entry points — keep them thin and delegate + business logic to the linting and code-action layers. Treat handlers like + route controllers: validate input, call a service, return a response. +- Hold all mutable state in `ServerContext` (and AGLint specifics in + `AglintContext`); do not introduce module-level singletons or shared mutable + globals. +- Initialize AGLint lazily and tolerate failure: if AGLint cannot be resolved, + log, notify the client via `aglint/status`, send no diagnostics, and retry + when `package.json` / `node_modules` change. Never crash the server. +- Debounce document linting (100 ms) to avoid thrashing; trigger an immediate + full refresh on configuration changes. +- Decouple AGLint from the LSP runtime through `adapters/fs.ts` — AGLint always + goes through the adapter, which prefers in-memory LSP documents over disk. + +### Architecture + +Universal principles applied here: + +- **Separation of Concerns** — handlers (LSP entry), linting (business logic), + loaders/adapters (integration), utils (infrastructure) are distinct layers. +- **Single Responsibility** — each module owns one job (e.g. `cache.ts` only + caches; `diagnostics.ts` only converts). +- **Dependency Direction** — handlers → linting/code-actions → adapters/loaders + → utils. Lower layers never import higher ones. `ServerContext`/`AglintContext` + flow downward as arguments. +- **Explicit Boundaries** — `linting/orchestration.ts` is the public linting + API; `helpers.ts` and `cache.ts` are internal. `LSPFileSystemAdapter` does not + leak AGLint types upward. +- **Data Flow Clarity** — document change → `shouldLintDocument` → cache lookup + → `performLinting` (AGLint) → `convertLinterResultToDiagnostics` → publish. +- **Minimize Coupling, Maximize Cohesion** — AGLint integration is isolated in + `loaders/`, `adapters/`, and `context/aglint-context.ts`. +- **Make Invalid States Impossible** — validate the AGLint version + (`>= 4.0.0-beta.1`) before use; type LSP payloads and settings. +- **Observability Built-in** — log through the LSP connection console with + prefixes (`[lsp]`, `[aglint]`); surface state to the client through the + `aglint/status` notification. +- **Keep It Boring** — follow standard LSP server patterns. + +Layers (top to bottom): + +| Layer | Responsibility | Examples | +| --- | --- | --- | +| Handlers | LSP lifecycle and event entry points | [src/handlers/event-handlers.ts](src/handlers/event-handlers.ts) | +| Services | Linting orchestration, code actions | [src/linting/orchestration.ts](src/linting/orchestration.ts), [src/code-actions/index.ts](src/code-actions/index.ts) | +| Linting core | Internal lint helpers, diagnostics, cache | [src/linting/helpers.ts](src/linting/helpers.ts), [src/linting/cache.ts](src/linting/cache.ts) | +| Adapters/Loaders | AGLint module loading, filesystem adapter | [src/loaders/aglint.ts](src/loaders/aglint.ts), [src/adapters/fs.ts](src/adapters/fs.ts) | +| Utils | URI, workspace, module resolution, errors | [src/utils/module-resolver.ts](src/utils/module-resolver.ts) | + +Dependency flow: + +```mermaid +flowchart TD + handlers["Handlers (init, event-handlers, config)"] + handlers --> services["Services (linting, code-actions)"] + services --> linting["Linting core (helpers, diagnostics, cache)"] + linting --> adapters["Adapters / Loaders (fs adapter, aglint loader)"] + adapters --> utils["Utils (error, uri, workspace, module-resolution)"] +``` + +`ServerContext` and `AglintContext` are passed downward; no layer depends on a +layer above it. + +### Code Quality + +- Follow the root [Code Quality](../AGENTS.md#code-quality) rules: required + JSDoc, 4-space indent, max line length 120, grouped/alphabetized imports, + inline type imports. +- **AGLint imports**: only `type` imports from `@adguard/aglint` are allowed + (enforced by `@typescript-eslint/no-restricted-imports` in + [.eslintrc.cjs](.eslintrc.cjs)). The runtime AGLint module must be obtained + through `loaders/aglint.ts`, never imported directly. +- **Error handling**: low-level helpers throw; orchestration/handlers catch, + log, and degrade (return `undefined`, publish empty diagnostics). Use + `getErrorMessage` / `getErrorStack` to read `unknown` errors. Use `undefined` + for "not found" and `null` for "parse failed" consistently. +- **Logging**: use connection console with prefixes `[lsp]` and `[aglint]`; + pick the level (`info`/`debug`/`warn`/`error`) by significance. +- **Naming**: verb-prefixed functions (`lintFile`, `ensureAglintContext`), + `PascalCase` types/contexts, `UPPER_SNAKE_CASE` constants + (`LINT_FILE_DEBOUNCE_DELAY`, `CACHE_MAX_ENTRIES`). + +### Testing + +- Vitest tests live in [test/](test) and mirror `src/`. +- Mock LSP boundaries with the factories in + [test/helpers/mocks.ts](test/helpers/mocks.ts) (`createMockConnection`, + `createMockServerContext`). Test pure logic (cache keys, diagnostic + conversion, config-comment parsing) directly without mocks. +- Add tests when changing cache keying, diagnostic conversion, or code-action + generation. All tests must pass before completing a task. + +### Dependency Management + +Follow the root [Dependency Management](../AGENTS.md#dependency-management) +rules. Keep AGLint a type-only/dev dependency — it is resolved from the user's +workspace at runtime via `loaders/aglint.ts`, not bundled into the server. + +### Configuration & Documentation + +- Runtime settings (`adblock.enableAglint`, + `adblock.enableInMemoryAglintCache`) are fetched from the client and typed by + [src/settings.ts](src/settings.ts). AGLint configuration comes from the user's + `.aglintrc.*` files, read through the filesystem adapter. +- When you change the settings schema, the `aglint/status` protocol, or the + AGLint version requirement, update this file, [src/settings.ts](src/settings.ts), + the root [package.json](../package.json) `contributes.configuration`, and the + root [AGENTS.md](../AGENTS.md). + +### Markdown Formatting + +Follow the root [Markdown Formatting](../AGENTS.md#markdown-formatting) rules. + +### Other + +- **Minimum AGLint version**: `4.0.0-beta.1`. Reject and report older versions + rather than attempting to lint with them. +- **Graceful degradation is mandatory**: a missing or broken AGLint install must + never crash the server or block syntax highlighting. + +## Related Agents + +- Root: [AGENTS.md](../AGENTS.md) +- Client: [client/AGENTS.md](../client/AGENTS.md) +- Shared: [shared/AGENTS.md](../shared/AGENTS.md) diff --git a/server/DEVELOPMENT.md b/server/DEVELOPMENT.md new file mode 100644 index 0000000..778be7c --- /dev/null +++ b/server/DEVELOPMENT.md @@ -0,0 +1,143 @@ + +# Development Guide — server + +Developer guide for the `@vscode-adblock-syntax/server` package: the Language +Server Protocol (LSP) server that integrates AGLint to provide diagnostics and +code actions. + +This is part of a monorepo. For environment setup, the debug workflow, and +repo-wide commands, start with the root [DEVELOPMENT.md](../DEVELOPMENT.md). For +code guidelines and architecture, see [AGENTS.md](AGENTS.md). + + +## Table of Contents + +- [Overview](#overview) +- [Prerequisites](#prerequisites) +- [Getting Started](#getting-started) +- [Development Workflow](#development-workflow) + - [Build](#build) + - [Test](#test) + - [Coverage](#coverage) + - [Lint](#lint) + - [Type check](#type-check) +- [Common Tasks](#common-tasks) +- [Troubleshooting](#troubleshooting) +- [Additional Resources](#additional-resources) + +## Overview + +The server runs as a separate Node.js process (one per outermost workspace +folder) and speaks LSP to the [client](../client/DEVELOPMENT.md). It dynamically +locates and loads AGLint from the user's workspace (local or global install), +lints filter-list documents, converts AGLint problems into VSCode diagnostics, +and offers code actions (apply fix, apply suggestion, disable a rule). All state +is in memory and the server degrades gracefully if AGLint cannot be loaded. It +is built with Rspack (with code splitting) to `out/server.js`. + +## Prerequisites + +Node.js v22 (the package requires `node >=20`), pnpm v10, VSCode `^1.74.0`, Git. +See the root [Prerequisites](../DEVELOPMENT.md#prerequisites). Run `pnpm install` +once from the repository root. + +`@adguard/aglint` and `@adguard/agtree` are type-only/dev dependencies — the +runtime AGLint module is resolved from the user's workspace, not bundled. + +## Getting Started + +The server is launched by the client. To debug it end-to-end: + +1. Open the repository **root** in VSCode. +2. Press `F5` (Launch Client). The launch config has + `autoAttachChildProcesses` enabled, so the debugger attaches to the spawned + server process. +3. The Extension Development Host opens the preconfigured + [test/static/aglint](../test/static/aglint) workspace, which has AGLint and an + `.aglintrc` available for linting. + +## Development Workflow + +Run these from this directory, or from the repo root with the +`--filter @vscode-adblock-syntax/server` flag. + +### Build + +```bash +pnpm --filter @vscode-adblock-syntax/server build # Rspack (code splitting) -> server/out +``` + +The `prebuild` script clears `out/` first. Add `--watch` (or use the VSCode +watch task) for incremental rebuilds during debugging. + +### Test + +```bash +pnpm --filter @vscode-adblock-syntax/server test # Vitest +``` + +Tests live in [test/](test) and mirror `src/`. Mock LSP boundaries with the +factories in [test/helpers/mocks.ts](test/helpers/mocks.ts) +(`createMockConnection`, `createMockServerContext`); test pure logic (cache keys, +diagnostic conversion, config-comment parsing) directly. + +### Coverage + +Coverage uses `@vitest/coverage-v8`: + +```bash +pnpm --filter @vscode-adblock-syntax/server test -- --coverage +``` + +### Lint + +```bash +pnpm --filter @vscode-adblock-syntax/server lint # ESLint + markdownlint +pnpm --filter @vscode-adblock-syntax/server lint:code # ESLint (add -- --fix) +pnpm --filter @vscode-adblock-syntax/server lint:md # markdownlint +``` + +### Type check + +```bash +pnpm --filter @vscode-adblock-syntax/server exec tsc --noEmit +``` + +## Common Tasks + +- **Add an LSP handler**: keep handlers thin (validate input, call a service, + return a response). Put handlers under `src/handlers/` and business logic + under `src/linting/` or `src/code-actions/`. +- **Touch AGLint integration**: only `type` imports from `@adguard/aglint` are + allowed (enforced by ESLint). Obtain the runtime module through + [src/loaders/aglint.ts](src/loaders/aglint.ts), never import it directly. +- **Change settings/protocol**: update [src/settings.ts](src/settings.ts), the + root [package.json](../package.json) `contributes.configuration`, and the + relevant `AGENTS.md`. +- **Manage state**: hold mutable state in `ServerContext` / `AglintContext`; do + not add module-level singletons. + +## Troubleshooting + +- **AGLint not found / not linting**: AGLint is resolved from the user's + workspace (local or global). Ensure `@adguard/aglint` (>= `4.0.0-beta.1`) is + installed and an `.aglintrc.*` exists. The server reports status via the + `aglint/status` notification and never crashes on a missing install. +- **Older AGLint version rejected**: the minimum is `4.0.0-beta.1`; upgrade the + workspace AGLint. +- **Server process not hitting breakpoints**: the launch config attaches to child + processes automatically; confirm you launched via `F5` (Launch Client) from + the repo root and that the server watch build succeeded. +- **Diagnostics seem stale**: in-memory caching is keyed by version/config; + toggle `adblock.enableInMemoryAglintCache` or change the document/config to + invalidate. + +## Additional Resources + +- Root guide: [DEVELOPMENT.md](../DEVELOPMENT.md) +- Code guidelines: [AGENTS.md](AGENTS.md) +- Related packages: + [client](../client/DEVELOPMENT.md), + [shared](../shared/DEVELOPMENT.md) +- [AGLint](https://github.com/AdguardTeam/AGLint) +- [VSCode Language Server Extension Guide](https://code.visualstudio.com/api/language-extensions/language-server-extension-guide) diff --git a/shared/.markdownlint.json b/shared/.markdownlint.json new file mode 100644 index 0000000..393b086 --- /dev/null +++ b/shared/.markdownlint.json @@ -0,0 +1,3 @@ +{ + "extends": "../.markdownlint.json" +} diff --git a/shared/AGENTS.md b/shared/AGENTS.md new file mode 100644 index 0000000..4a22693 --- /dev/null +++ b/shared/AGENTS.md @@ -0,0 +1,160 @@ + +# AGENTS.md — shared + +Agent reference for the `@vscode-adblock-syntax/shared` package: types and +utilities shared between the [client](../client/AGENTS.md) and +[server](../server/AGENTS.md). + +This is part of a monorepo. For repo-wide conventions (dependency management, +Markdown formatting, versioning, contribution rules) see the root +[AGENTS.md](../AGENTS.md). For environment setup see +[DEVELOPMENT.md](../DEVELOPMENT.md). + + +## Table of Contents + +- [Project Overview](#project-overview) +- [Technical Context](#technical-context) +- [Project Structure](#project-structure) +- [Contribution Instructions](#contribution-instructions) +- [Code Guidelines](#code-guidelines) + - [System Design](#system-design) + - [Architecture](#architecture) + - [Code Quality](#code-quality) + - [Testing](#testing) + - [Dependency Management](#dependency-management) + - [Configuration \& Documentation](#configuration--documentation) + - [Markdown Formatting](#markdown-formatting) +- [Related Agents](#related-agents) + +## Project Overview + +A small internal library consumed by the client and server packages. It holds +contracts that must stay consistent across the process boundary: shared enums +and types (e.g. document `FileScheme`), and is the intended home for future +shared validation schemas (Valibot) and custom LSP protocol types. It performs +no I/O and has no side effects. + +## Technical Context + +- **Language/Version**: TypeScript targeting `ESNext`, `strict` mode. +- **Runtime**: Consumed by both the VSCode extension host (client) and the + Node.js LSP server; Node `>=20`. +- **Primary Dependencies**: None at runtime (utility code only). +- **Storage**: None. +- **Testing**: Vitest (`test/` currently a placeholder). +- **Build**: Rspack for the bundle plus `tsc --emitDeclarationOnly` for type + declarations; published via `exports` from `out/index.js` / `out/index.d.ts`. +- **Project Type**: monorepo package (internal library). + +## Project Structure + +```text +shared/ +├── package.json # Manifest, exports map, build (rspack + tsc dts) +├── rspack.config.ts # Bundler config +├── src/ +│ ├── index.ts # Public entry point (re-exports the public API) +│ └── file-scheme.ts # FileScheme enum (file, untitled) +└── test/ # Vitest tests (placeholder) +``` + +## Contribution Instructions + +After completing a task, you MUST do the following: + +- Verify your changes with the linter and type checker: + - `pnpm --filter @vscode-adblock-syntax/shared exec tsc --noEmit` for type + errors. + - `pnpm --filter @vscode-adblock-syntax/shared lint:code` (add `--fix`) for + ESLint. + - `pnpm --filter @vscode-adblock-syntax/shared lint:md` for Markdown. +- Update or add Vitest unit tests for any changed code. +- Run `pnpm --filter @vscode-adblock-syntax/shared test` and ensure all tests + pass. +- When you change this package's structure, update the + [Project Structure](#project-structure) section above. +- If a prompt asks you to refactor or improve code, capture the lesson as a + guideline under [Code Guidelines](#code-guidelines). +- Verify new code follows these Code Guidelines and the root + [AGENTS.md](../AGENTS.md). + +## Code Guidelines + +### System Design + +Design as a consumed library: + +- The library is imported by other packages — never access the filesystem, + network, or environment, and keep side effects out of the default code path. +- Export a stable public API only through [src/index.ts](src/index.ts). Anything + not re-exported there is internal. +- Keep the dependency footprint at zero where possible — every dependency here + becomes a transitive dependency of both client and server. Prefer built-in + APIs. +- Do not mutate global state; both consumers are long-running processes. +- Provide complete type definitions (the package ships `.d.ts`) so consumers get + type checking and autocompletion. +- Document every exported function, class, and type with JSDoc. + +### Architecture + +This package is a single, dependency-free utility layer at the bottom of the +monorepo dependency graph. + +- **Separation of Concerns** — one concept per file (e.g. + [src/file-scheme.ts](src/file-scheme.ts)). +- **Single Responsibility** — each export has one reason to change. +- **Dependency Direction** — depends on nothing inside the repo; client and + server depend on it. Never import from `client` or `server`. +- **Explicit Boundaries** — the public surface is exactly what + [src/index.ts](src/index.ts) re-exports. +- **Data Flow Clarity** — pure values and types only; no hidden state. +- **Make Invalid States Impossible** — model shared contracts as precise types + and enums (this is the intended home for shared Valibot schemas). +- **Keep It Boring** — small, obvious, well-typed helpers. + +Dependency flow: + +```mermaid +flowchart LR + client["client"] --> shared["shared (types/enums, no deps)"] + server["server"] --> shared +``` + +### Code Quality + +- Follow the root [Code Quality](../AGENTS.md#code-quality) rules: required + JSDoc, 4-space indent, max line length 120, grouped/alphabetized imports, + inline type imports. +- Re-export the public API only from [src/index.ts](src/index.ts); keep + implementation files focused and free of cross-cutting concerns. + +### Testing + +- Vitest tests live in [test/](test). The directory is currently a placeholder; + add tests as real logic (e.g. validation schemas) is introduced. +- All tests must pass before completing a task. + +### Dependency Management + +Follow the root [Dependency Management](../AGENTS.md#dependency-management) +rules. Because every dependency here is inherited by both client and server, +keep this package dependency-free unless a dependency is clearly justified. + +### Configuration & Documentation + +- This package has no runtime configuration. When you add to the public API, + update the `exports`/types in [package.json](package.json) if needed, the + [Project Structure](#project-structure) section above, and note shared + contracts in the root [AGENTS.md](../AGENTS.md). + +### Markdown Formatting + +Follow the root [Markdown Formatting](../AGENTS.md#markdown-formatting) rules. + +## Related Agents + +- Root: [AGENTS.md](../AGENTS.md) +- Client: [client/AGENTS.md](../client/AGENTS.md) +- Server: [server/AGENTS.md](../server/AGENTS.md) diff --git a/shared/DEVELOPMENT.md b/shared/DEVELOPMENT.md new file mode 100644 index 0000000..e11ae85 --- /dev/null +++ b/shared/DEVELOPMENT.md @@ -0,0 +1,115 @@ + +# Development Guide — shared + +Developer guide for the `@vscode-adblock-syntax/shared` package: types and +utilities shared between the [client](../client/DEVELOPMENT.md) and +[server](../server/DEVELOPMENT.md). + +This is part of a monorepo. For environment setup and repo-wide commands, start +with the root [DEVELOPMENT.md](../DEVELOPMENT.md). For code guidelines and +architecture, see [AGENTS.md](AGENTS.md). + + +## Table of Contents + +- [Overview](#overview) +- [Prerequisites](#prerequisites) +- [Getting Started](#getting-started) +- [Development Workflow](#development-workflow) + - [Build](#build) + - [Test](#test) + - [Lint](#lint) + - [Type check](#type-check) +- [Common Tasks](#common-tasks) +- [Troubleshooting](#troubleshooting) +- [Additional Resources](#additional-resources) + +## Overview + +A small, dependency-free internal library consumed by the client and server. It +holds contracts that must stay consistent across the process boundary (e.g. the +document `FileScheme` enum) and is the intended home for future shared +validation schemas (Valibot) and custom LSP protocol types. It performs no I/O +and has no side effects. It is built with Rspack for the bundle plus +`tsc --emitDeclarationOnly` for type declarations, and exposes its public API +through the `exports` map (`out/index.js` / `out/index.d.ts`). + +## Prerequisites + +Node.js v22 (the package requires `node >=20`), pnpm v10, Git. See the root +[Prerequisites](../DEVELOPMENT.md#prerequisites). Run `pnpm install` once from +the repository root. + +## Getting Started + +`shared` is built before `client` and `server` depend on it. Build it (or rely +on the watch task) when changing its public API so consumers pick up fresh +declarations: + +```bash +pnpm --filter @vscode-adblock-syntax/shared build +``` + +## Development Workflow + +Run these from this directory, or from the repo root with the +`--filter @vscode-adblock-syntax/shared` flag. + +### Build + +```bash +pnpm --filter @vscode-adblock-syntax/shared build # Rspack + postbuild emits .d.ts +``` + +The `prebuild` script clears `out/`; the `postbuild` script runs +`tsc --project tsconfig.build.json --emitDeclarationOnly` to emit type +declarations. + +### Test + +```bash +pnpm --filter @vscode-adblock-syntax/shared test # Vitest +``` + +Tests live in [test/](test) (currently a placeholder); add tests as real logic +such as validation schemas is introduced. + +### Lint + +```bash +pnpm --filter @vscode-adblock-syntax/shared lint # ESLint + markdownlint +pnpm --filter @vscode-adblock-syntax/shared lint:code # ESLint (add -- --fix) +pnpm --filter @vscode-adblock-syntax/shared lint:md # markdownlint +``` + +### Type check + +```bash +pnpm --filter @vscode-adblock-syntax/shared exec tsc --noEmit +``` + +## Common Tasks + +- **Add to the public API**: implement in a focused file under `src/`, then + re-export it from [src/index.ts](src/index.ts) — anything not re-exported + there is internal. Rebuild so `client`/`server` get the new declarations. +- **Keep it dependency-free**: every dependency here becomes a transitive + dependency of both client and server; prefer Node.js built-ins and avoid + side effects. +- **Never import from `client` or `server`**: this package sits at the bottom of + the dependency graph. + +## Troubleshooting + +- **Consumers don't see a new export**: rebuild `shared` so `out/index.d.ts` and + `out/index.js` are regenerated; the watch task handles this during debugging. +- **Type errors after an API change**: run `tsc --noEmit` here and in the + consuming package; update both `client` and `server` to match the new type. + +## Additional Resources + +- Root guide: [DEVELOPMENT.md](../DEVELOPMENT.md) +- Code guidelines: [AGENTS.md](AGENTS.md) +- Related packages: + [client](../client/DEVELOPMENT.md), + [server](../server/DEVELOPMENT.md) diff --git a/syntaxes/.markdownlint.json b/syntaxes/.markdownlint.json new file mode 100644 index 0000000..393b086 --- /dev/null +++ b/syntaxes/.markdownlint.json @@ -0,0 +1,3 @@ +{ + "extends": "../.markdownlint.json" +} diff --git a/syntaxes/AGENTS.md b/syntaxes/AGENTS.md new file mode 100644 index 0000000..25b791a --- /dev/null +++ b/syntaxes/AGENTS.md @@ -0,0 +1,184 @@ + +# AGENTS.md — syntaxes + +Agent reference for the `@vscode-adblock-syntax/syntaxes` package: the TextMate +grammar source for adblock filter syntax, its compiler, and its tokenization +tests. + +This is part of a monorepo. For repo-wide conventions (dependency management, +Markdown formatting, versioning, contribution rules) see the root +[AGENTS.md](../AGENTS.md). For environment setup see +[DEVELOPMENT.md](../DEVELOPMENT.md). + + +## Table of Contents + +- [Project Overview](#project-overview) +- [Technical Context](#technical-context) +- [Project Structure](#project-structure) +- [Contribution Instructions](#contribution-instructions) +- [Code Guidelines](#code-guidelines) + - [System Design](#system-design) + - [Architecture](#architecture) + - [Code Quality](#code-quality) + - [Testing](#testing) + - [Dependency Management](#dependency-management) + - [Configuration \& Documentation](#configuration--documentation) + - [Markdown Formatting](#markdown-formatting) +- [Related Agents](#related-agents) + +## Project Overview + +This package owns the syntax highlighting grammar. The grammar is authored in +YAML ([adblock.yaml-tmlanguage](adblock.yaml-tmlanguage)) and compiled to a +TextMate PList (`out/adblock.plist`) that the root extension contributes to +VSCode (and that GitHub Linguist uses for highlighting). It also provides a +tokenization test harness that loads the real grammar with `vscode-textmate` + +`vscode-oniguruma` and asserts token scopes for sample rules. + +## Technical Context + +- **Language/Version**: TypeScript (build/test scripts) targeting `ESNext`; + grammar authored in YAML. +- **Runtime**: Node.js (build and test only — the compiled grammar runs inside + VSCode/Linguist, not this package). +- **Primary Dependencies**: `vscode-textmate`, `vscode-oniguruma` (tokenization), + `plist`, `yaml` (grammar conversion), `chokidar` (watch), `fast-glob`, + `fs-extra`, `chalk`, `tar`, `valibot`. +- **Storage**: None — reads the YAML grammar, writes a PList artifact to `out/`. +- **Testing**: Vitest with a custom tokenization matcher. +- **Build**: `tsx scripts/build.ts` (YAML → PList; supports `--watch`). +- **Project Type**: monorepo package (grammar source + build/test tooling). + +## Project Structure + +```text +syntaxes/ +├── package.json # Manifest and scripts +├── adblock.yaml-tmlanguage # Source grammar (YAML TextMate) +├── scripts/ +│ └── build.ts # Compiles YAML grammar → out/adblock.plist (--watch supported) +├── utils/ # Grammar + tokenizer helpers +│ ├── grammar-converter.ts # convertYamlToPlist +│ ├── adblock-grammar-loader.ts # Loads compiled grammar for tests +│ ├── get-adblock-tokenizer.ts # Builds a tokenizer via vscode-textmate/oniguruma +│ ├── constants.ts # Scope names, paths +│ ├── error.ts # getErrorMessage +│ └── utils.ts # Misc helpers +├── test/ # Tokenization tests +│ ├── integration.ts # Integration entry (downloads real-world filter lists) +│ ├── adblock/ # Scope assertions by rule category (comments, cosmetic, network) +│ └── setup/custom-matchers/ # expect-tokenization matcher +└── typings/ # Vitest custom matcher type declarations +``` + +## Contribution Instructions + +After completing a task, you MUST do the following: + +- Verify your changes with the linter and type checker: + - `pnpm --filter @vscode-adblock-syntax/syntaxes exec tsc --noEmit` for type + errors. + - `pnpm --filter @vscode-adblock-syntax/syntaxes lint:code` (add `--fix`) for + ESLint. + - `pnpm --filter @vscode-adblock-syntax/syntaxes lint:md` for Markdown. +- When you change the grammar, rebuild it and update or add tokenization tests + under [test/adblock/](test/adblock); add or modify example rules in + [test/static/rules](../test/static/rules) for visual verification. +- Run `pnpm --filter @vscode-adblock-syntax/syntaxes test` and ensure all tests + pass. +- When you change this package's structure, update the + [Project Structure](#project-structure) section above. +- If a prompt asks you to refactor or improve code, capture the lesson as a + guideline under [Code Guidelines](#code-guidelines). +- Verify new code follows these Code Guidelines and the root + [AGENTS.md](../AGENTS.md). + +## Code Guidelines + +### System Design + +Design as a build/library package that produces a consumed artifact: + +- The compiled grammar (`out/adblock.plist`) is the public artifact — keep it + reproducible from the YAML source via `scripts/build.ts`. Never hand-edit the + PList; edit the YAML and rebuild. +- Build and test scripts run and exit. Validate inputs early (the source grammar + must exist and be valid YAML) and fail with a clear, located error message + (e.g. `file:line:col`). +- Keep the grammar self-contained; embedded languages (JavaScript for + scriptlets) are declared via scope mapping, not by importing other grammars. +- Keep tooling dependencies in `devDependencies` — nothing here ships in the + extension bundle except the generated PList. + +### Architecture + +- **Separation of Concerns** — the grammar source (YAML), the converter + (`utils/grammar-converter.ts`), the build entry (`scripts/build.ts`), and the + test tokenizer (`utils/get-adblock-tokenizer.ts`) are distinct. +- **Single Responsibility** — conversion, loading, and tokenization each live in + their own module. +- **Dependency Direction** — `scripts/` and `test/` depend on `utils/`; `utils/` + modules do not depend on scripts or tests. No cross-package imports. +- **Explicit Boundaries** — the build consumes one input (the YAML grammar) and + produces one output (the PList). +- **Data Flow Clarity** — YAML → `convertYamlToPlist` → PList; PList → + `adblock-grammar-loader` → `get-adblock-tokenizer` → scope assertions. +- **Make Invalid States Impossible** — invalid YAML is rejected at build time + with a precise error. +- **Keep It Boring** — standard TextMate grammar patterns and well-known + tokenization libraries. + +Dependency flow: + +```mermaid +flowchart LR + build["scripts/build.ts"] --> converter["utils/grammar-converter.ts"] --> plist["out/adblock.plist"] + tests["test/adblock/*"] --> loader["utils/adblock-grammar-loader.ts"] + loader --> tokenizer["utils/get-adblock-tokenizer.ts"] +``` + +### Code Quality + +- Follow the root [Code Quality](../AGENTS.md#code-quality) rules: required + JSDoc, 4-space indent, max line length 120, grouped/alphabetized imports, + inline type imports. +- Use the local `getErrorMessage` helper to read `unknown` errors; report + grammar errors with file/line/column context. +- Keep regular expressions in the grammar readable and documented; prefer named + captures and clear scope names. + +### Testing + +- Vitest tokenization tests live in [test/adblock/](test/adblock), grouped by + rule category (comments, cosmetic, network). They tokenize sample rules with + the real grammar and assert scopes via the custom `expect-tokenization` + matcher in [test/setup/custom-matchers](test/setup/custom-matchers). +- The grammar must be built before tokenization tests can load it. +- Add or update tests whenever you change a grammar rule. All tests must pass + before completing a task. + +### Dependency Management + +Follow the root [Dependency Management](../AGENTS.md#dependency-management) +rules. All dependencies here are build/test-only (`devDependencies`); do not add +runtime dependencies to this package. + +### Configuration & Documentation + +- The grammar's scope name (`text.adblock`), output path + (`syntaxes/out/adblock.plist`), and embedded-language mapping are wired up in + the root [package.json](../package.json) `contributes.grammars`. Update that + manifest and the root [AGENTS.md](../AGENTS.md) if scope names or output paths + change. +- When updating syntax highlighting, follow the "Updating the grammar" steps in + [DEVELOPMENT.md](DEVELOPMENT.md). + +### Markdown Formatting + +Follow the root [Markdown Formatting](../AGENTS.md#markdown-formatting) rules. + +## Related Agents + +- Root: [AGENTS.md](../AGENTS.md) +- Tools: [tools/AGENTS.md](../tools/AGENTS.md) diff --git a/syntaxes/DEVELOPMENT.md b/syntaxes/DEVELOPMENT.md new file mode 100644 index 0000000..257cf6f --- /dev/null +++ b/syntaxes/DEVELOPMENT.md @@ -0,0 +1,131 @@ + +# Development Guide — syntaxes + +Developer guide for the `@vscode-adblock-syntax/syntaxes` package: the TextMate +grammar source for adblock filter syntax, its compiler, and its tokenization +tests. + +This is part of a monorepo. For environment setup and repo-wide commands, start +with the root [DEVELOPMENT.md](../DEVELOPMENT.md). For code guidelines and +architecture, see [AGENTS.md](AGENTS.md). + + +## Table of Contents + +- [Overview](#overview) +- [Prerequisites](#prerequisites) +- [Getting Started](#getting-started) +- [Development Workflow](#development-workflow) + - [Build](#build) + - [Test](#test) + - [Lint](#lint) + - [Type check](#type-check) +- [Common Tasks](#common-tasks) + - [Updating the grammar](#updating-the-grammar) +- [Troubleshooting](#troubleshooting) +- [Additional Resources](#additional-resources) + +## Overview + +This package owns the syntax-highlighting grammar. The grammar is authored in +YAML ([adblock.yaml-tmlanguage](adblock.yaml-tmlanguage)) and compiled to a +TextMate PList (`out/adblock.plist`) that the root extension contributes to +VSCode (and that GitHub Linguist uses). It also provides a tokenization test +harness that loads the real grammar with `vscode-textmate` + `vscode-oniguruma` +and asserts token scopes for sample rules. All dependencies are build/test-only. + +## Prerequisites + +Node.js v22, pnpm v10, Git. See the root +[Prerequisites](../DEVELOPMENT.md#prerequisites). Run `pnpm install` once from +the repository root. + +## Getting Started + +Build the grammar so the compiled `out/adblock.plist` exists (the tokenization +tests load it): + +```bash +pnpm --filter @vscode-adblock-syntax/syntaxes build +``` + +To preview highlighting visually, open the [test/static](../test/static) folder +in the Extension Development Host (`F5` from the repo root). + +## Development Workflow + +Run these from this directory, or from the repo root with the +`--filter @vscode-adblock-syntax/syntaxes` flag. + +### Build + +```bash +pnpm --filter @vscode-adblock-syntax/syntaxes build # tsx scripts/build.ts (YAML -> PList) +pnpm --filter @vscode-adblock-syntax/syntaxes build -- --watch # incremental rebuilds +``` + +The `prebuild` script clears `out/` first. Never hand-edit the generated PList — +edit the YAML source and rebuild. + +### Test + +```bash +pnpm --filter @vscode-adblock-syntax/syntaxes test # Vitest tokenization tests +``` + +Tokenization tests live in [test/adblock/](test/adblock), grouped by rule +category (comments, cosmetic, network). They tokenize sample rules with the real +grammar and assert scopes via the custom `expect-tokenization` matcher in +[test/setup/custom-matchers](test/setup/custom-matchers). Build the grammar +before running tests. + +### Lint + +```bash +pnpm --filter @vscode-adblock-syntax/syntaxes lint # ESLint + markdownlint +pnpm --filter @vscode-adblock-syntax/syntaxes lint:code # ESLint (add -- --fix) +pnpm --filter @vscode-adblock-syntax/syntaxes lint:md # markdownlint +``` + +### Type check + +```bash +pnpm --filter @vscode-adblock-syntax/syntaxes exec tsc --noEmit +``` + +## Common Tasks + +### Updating the grammar + +1. Edit the grammar in [adblock.yaml-tmlanguage](adblock.yaml-tmlanguage). +2. Add or modify example rules under [test/static/rules](../test/static/rules) + (link related GitHub issues in the rule files). +3. Rebuild the grammar, then add or update tokenization tests under + [test/adblock/](test/adblock) and run the test command above. +4. Open the [test/static](../test/static) folder in the Extension Development + Host to verify highlighting visually. + +You can also experiment with the grammar on the +[online TextMate test page](https://novalightshow.netlify.app/). + +> The grammar's scope name (`text.adblock`), output path +> (`syntaxes/out/adblock.plist`), and embedded-language mapping are wired up in +> the root [package.json](../package.json) `contributes.grammars`. Update that +> manifest if scope names or output paths change. + +## Troubleshooting + +- **Tests fail to load the grammar**: run the build first; tests load the + compiled `out/adblock.plist`. +- **Build fails with a YAML error**: the build validates the source and reports a + located error (e.g. `file:line:col`); fix the YAML at that position. +- **Highlighting looks wrong in the host**: rebuild the grammar and reload the + Extension Development Host window. + +## Additional Resources + +- Root guide: [DEVELOPMENT.md](../DEVELOPMENT.md) +- Code guidelines: [AGENTS.md](AGENTS.md) +- Related package: [tools](../tools/DEVELOPMENT.md) +- [VSCode Syntax Highlight Guide](https://code.visualstudio.com/api/language-extensions/syntax-highlight-guide) +- [Online test page for TextMate grammars](https://novalightshow.netlify.app/) diff --git a/tools/AGENTS.md b/tools/AGENTS.md new file mode 100644 index 0000000..b365b02 --- /dev/null +++ b/tools/AGENTS.md @@ -0,0 +1,159 @@ + +# AGENTS.md — tools + +Agent reference for the `@vscode-adblock-syntax/tools` package: repository-wide +build and utility scripts. + +This is part of a monorepo. For repo-wide conventions (dependency management, +Markdown formatting, versioning, contribution rules) see the root +[AGENTS.md](../AGENTS.md). For environment setup see +[DEVELOPMENT.md](../DEVELOPMENT.md). + + +## Table of Contents + +- [Project Overview](#project-overview) +- [Technical Context](#technical-context) +- [Project Structure](#project-structure) +- [Contribution Instructions](#contribution-instructions) +- [Code Guidelines](#code-guidelines) + - [System Design](#system-design) + - [Architecture](#architecture) + - [Code Quality](#code-quality) + - [Testing](#testing) + - [Dependency Management](#dependency-management) + - [Configuration \& Documentation](#configuration--documentation) + - [Markdown Formatting](#markdown-formatting) +- [Related Agents](#related-agents) + +## Project Overview + +A collection of small, standalone Node.js scripts used by the repo's build and +maintenance workflows. Currently: + +- [build-txt.ts](build-txt.ts) — writes the extension version from the root + `package.json` into `out/build.txt` (used by CI/packaging). +- [clean.ts](clean.ts) — dependency-free cleanup that removes `node_modules` + from every workspace package. + +These scripts are invoked from the repo root (e.g. `pnpm clean`) and run via +`tsx`. The package has no build step of its own. + +## Technical Context + +- **Language/Version**: TypeScript run directly with `tsx`; CommonJS-style + scripts (`__dirname`, `node:` built-ins). +- **Runtime**: Node.js (run-and-exit scripts). +- **Primary Dependencies**: None — the scripts rely on Node.js built-ins + (`node:fs`, `node:path`, `node:child_process`) and the `pnpm` CLI. +- **Storage**: Filesystem only (writes `out/build.txt`, removes `node_modules`). +- **Testing**: None currently (no test runner configured for this package). +- **Build**: None — scripts are executed in place via `tsx`. +- **Project Type**: monorepo package (CLI/utility scripts). + +## Project Structure + +```text +tools/ +├── package.json # Minimal manifest (no build/test scripts) +├── tsconfig.json # TypeScript config for the scripts +├── build-txt.ts # Writes version → out/build.txt +└── clean.ts # Removes node_modules from all workspace packages +``` + +## Contribution Instructions + +After completing a task, you MUST do the following: + +- Verify your changes with the linter and type checker: + - `pnpm test:compile` (from the root) for TypeScript type errors. + - `pnpm lint:code` (from the root, add `--fix`) for ESLint. + - `pnpm lint:md` (from the root) for Markdown. +- Add unit tests if a script grows non-trivial logic worth covering (no test + runner is configured here yet; prefer keeping scripts simple). +- Run `pnpm test` from the root and ensure all tests pass. +- When you add or remove a script, update the + [Project Structure](#project-structure) and + [Project Overview](#project-overview) sections above. +- If a prompt asks you to refactor or improve code, capture the lesson as a + guideline under [Code Guidelines](#code-guidelines). +- Verify new code follows these Code Guidelines and the root + [AGENTS.md](../AGENTS.md). + +## Code Guidelines + +### System Design + +Design as run-and-exit command-line scripts: + +- Each script performs its work and exits — no long-lived state, no daemons. + Exit non-zero on failure (e.g. [clean.ts](clean.ts) calls `process.exit(1)` on + error). +- Use stdout for normal progress output and stderr for diagnostics and errors. +- Fail fast with clear messages: validate required inputs early (e.g. + [build-txt.ts](build-txt.ts) throws if `package.json` has no `version`). +- Keep startup fast and dependencies minimal — prefer Node.js built-ins so + cleanup-style scripts can run even when package `node_modules` are absent. + +### Architecture + +These are independent, single-file scripts with no shared internal layering. + +- **Separation of Concerns** — one script per task (versioning, cleanup). +- **Single Responsibility** — each file does exactly one job. +- **Dependency Direction** — scripts depend only on Node.js built-ins and CLI + tools (`pnpm`); they do not import from other workspace packages. +- **Explicit Boundaries** — interaction with the repo is through the filesystem + and the `pnpm` CLI, not through package imports. +- **Data Flow Clarity** — read input (package.json / `pnpm ls`), perform an + action (write file / remove dirs), exit. +- **Keep It Boring** — plain, dependency-free Node.js scripts. + +Dependency flow: + +```mermaid +flowchart LR + buildTxt["build-txt.ts"] --> fs["node:fs, node:path"] --> output["out/build.txt"] + clean["clean.ts"] --> pnpm["pnpm CLI + node:fs"] --> removes["removes node_modules"] +``` + +### Code Quality + +- Follow the root [Code Quality](../AGENTS.md#code-quality) rules: required + JSDoc, 4-space indent, max line length 120, grouped/alphabetized imports, + inline type imports. +- `console` output is expected in these scripts; where ESLint's `no-console` + applies, disable it locally with an explanatory comment (as the existing + scripts do) rather than globally. +- Handle filesystem and child-process errors explicitly and exit with a + non-zero code on failure. + +### Testing + +- No test runner is configured for this package. Keep scripts simple enough that + manual verification (running the script) is sufficient. If a script grows + complex logic, extract the logic into a testable function before adding a test + setup. + +### Dependency Management + +Follow the root [Dependency Management](../AGENTS.md#dependency-management) +rules. Keep this package dependency-free: prefer Node.js built-ins so that +maintenance scripts (especially cleanup) do not themselves depend on installed +`node_modules`. + +### Configuration & Documentation + +- These scripts read configuration from the repo (root `package.json` version, + `pnpm ls` output); they take no environment variables or config files of their + own. When a script's inputs or outputs change (e.g. the `build.txt` location), + update this file and any CI configuration that consumes the output. + +### Markdown Formatting + +Follow the root [Markdown Formatting](../AGENTS.md#markdown-formatting) rules. + +## Related Agents + +- Root: [AGENTS.md](../AGENTS.md) +- Syntaxes: [syntaxes/AGENTS.md](../syntaxes/AGENTS.md) diff --git a/tools/DEVELOPMENT.md b/tools/DEVELOPMENT.md new file mode 100644 index 0000000..d90bdc7 --- /dev/null +++ b/tools/DEVELOPMENT.md @@ -0,0 +1,97 @@ + +# Development Guide — tools + +Developer guide for the `@vscode-adblock-syntax/tools` package: repository-wide +build and utility scripts. + +This is part of a monorepo. For environment setup and repo-wide commands, start +with the root [DEVELOPMENT.md](../DEVELOPMENT.md). For code guidelines and +architecture, see [AGENTS.md](AGENTS.md). + + +## Table of Contents + +- [Overview](#overview) +- [Prerequisites](#prerequisites) +- [Getting Started](#getting-started) +- [Development Workflow](#development-workflow) + - [Run a script](#run-a-script) + - [Lint](#lint) + - [Type check](#type-check) +- [Common Tasks](#common-tasks) +- [Troubleshooting](#troubleshooting) +- [Additional Resources](#additional-resources) + +## Overview + +A collection of small, standalone, dependency-free Node.js scripts used by the +repo's build and maintenance workflows: + +- [build-txt.ts](build-txt.ts) — writes the extension version from the root + `package.json` into `out/build.txt` (used by CI/packaging). +- [clean.ts](clean.ts) — removes `node_modules` from every workspace package. + +The scripts are run via `tsx` and rely only on Node.js built-ins and the `pnpm` +CLI. This package has no build or test step of its own. + +## Prerequisites + +Node.js v22, pnpm v10, Git. See the root +[Prerequisites](../DEVELOPMENT.md#prerequisites). Run `pnpm install` once from +the repository root. + +## Getting Started + +There is nothing to build here. The scripts are invoked from the repo root, for +example via the root `pnpm clean` command. + +## Development Workflow + +### Run a script + +```bash +pnpm clean # runs tsx tools/clean.ts (removes node_modules) +pnpm exec tsx tools/build-txt.ts # writes version -> out/build.txt +``` + +### Lint + +This package has no per-package lint script; lint it from the repo root: + +```bash +pnpm lint:code # ESLint (add -- --fix) +pnpm lint:md # markdownlint +``` + +### Type check + +Type checking is covered by the root command: + +```bash +pnpm test:compile +``` + +## Common Tasks + +- **Add a script**: create a single-file `*.ts` script that performs its work and + exits non-zero on failure. Prefer Node.js built-ins (`node:fs`, `node:path`, + `node:child_process`) so cleanup-style scripts run even without installed + `node_modules`. Update [AGENTS.md](AGENTS.md) Project Structure/Overview. +- **Grow non-trivial logic**: extract the logic into a testable function before + adding a test setup (no test runner is configured here yet). +- **Change a script's inputs/outputs**: update any CI configuration that consumes + the output (e.g. the `build.txt` location). + +## Troubleshooting + +- **`tsx: command not found`**: run scripts through pnpm (`pnpm exec tsx ...`) or + the root `pnpm clean` so the workspace `tsx` is used; run `pnpm install` first. +- **`clean` fails partway**: it exits non-zero on error; re-run after resolving + the reported filesystem issue. It is safe to run even when some package + `node_modules` are already absent. + +## Additional Resources + +- Root guide: [DEVELOPMENT.md](../DEVELOPMENT.md) +- Code guidelines: [AGENTS.md](AGENTS.md) +- Related package: [syntaxes](../syntaxes/DEVELOPMENT.md)