# Angular Linters

> Workflow for setting up and managing ESLint, Stylelint, Husky, and Commitlint in Angular projects.

- Skill: `famzila/angular-linters` (Agent Skill, multi-file: 9 files)
- Install (CLI): `npx skillmds@latest add famzila/angular-linters`
- Raw SKILL.md: https://api.skillmd.com/api/skills/famzila/angular-linters/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: famzila (https://skillmd.com/u/famzila)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/famzila/angular-linters

---


# Angular Linters & Git Hooks

This skill standardizes code quality and commit message consistency using industry-standard tools.

## Fundamental Principles

- **References as Source of Truth**: The files within the `references/` directory are the absolute source of truth for configuration patterns. Always read the relevant reference file **BEFORE** performing any configuration step or proposing changes.
- **Strict `defineConfig` Standard**: For Angular v19+ and v21+, `defineConfig` from `eslint/config` is the mandatory wrapper for `eslint.config.js`. Do **NOT** replace it with `tseslint.config` or other wrappers, as it is the official default generated by Angular schematics.

## Recommended Workflow

> **IMPORTANT:** Steps 1–8 form a **continuous pipeline**. Execute them sequentially without pausing for user confirmation between steps. Only stop and try to fix if a **MUST pass** check fails.

> **Package Manager Convention:** Throughout this skill, `[pkg-manager]` refers to the package manager confirmed during project setup (pnpm, npm, or yarn). The `[exec]` command maps to `pnpm exec` / `yarn exec` / `npx` respectively. All commands **MUST** use the confirmed manager — never default to a specific one.

**Pre-Condition (MANDATORY):**

> Before starting, run `git status --porcelain`. If the output is **NOT empty**, **STOP**. Tell the user: _"Your working directory has uncommitted changes. Please commit or stash them before running this skill to protect your work."_

**Failure Recovery:**

> If any step fails:
> 1. Run `git diff --name-only` to identify files changed by this skill.
> 2. Revert **ONLY** those files: `git checkout -- <file1> <file2> ...`
> 3. Remove **ONLY** untracked files created by this skill (config files generated by the script), not all untracked files.
> 4. **Do NOT** use `git reset --hard` or `git clean -fd` — these destroy unrelated user work.

### Step 0: Read Project Manifest

1. Read `PROJECT_MANIFEST.json` from the project root.
2. Extract `packageManager`, `style`, `angularMajorVersion`, and `rxjsLinting`.
3. If the file is missing, ask the user for these values before proceeding. Do NOT assume defaults.
4. Use `packageManager` as `[pkg-manager]` throughout this skill.

### Step 1: Preparation & Installation

1.  **Read References**: Read all files in the `references/` directory to understand the project's quality standards.
2.  **Install Tools**: Run `scripts/configure_linters.sh --style [css|scss] --package-manager [pkg-manager] --rxjs [auto|enabled|disabled]` to install all quality tools and perform initial configuration. Pass the project's style format, package manager, and RxJS linting mode so the correct dependencies are installed:

- **CSS**: Installs `stylelint-config-standard`
- **SCSS**: Installs `stylelint-config-standard-scss` (includes SCSS syntax + plugin)

> **IMPORTANT:** Before running the script, **verify the file content** with a quick read to confirm it contains the expected `--style` parsing logic. This prevents stale file versions from running.

> **Note:** The `globals` package is installed as part of this setup.

### Step 2: Verify Installation Output

After running `configure_linters.sh`, verify what it creates:

**Packages:**

- Required devDependencies exist (e.g., `@angular-eslint/*`, `husky`, `lint-staged`, `@commitlint/cli`, etc.)

**Config Files (auto-generated by script):**

- `eslint.config.js` (from `ng add @angular-eslint/schematics`)
- `.prettierignore`
- `.stylelintignore`
- `stylelint.config.mjs` (CSS or SCSS variant based on `--style`)
- `commitlint.config.js`
- `.husky/commit-msg` (commitlint hook)
- `.husky/pre-commit` (lint-staged hook)

> **Note:** `eslint.config.js` is the base Angular config — it will be enhanced with plugins in Step 3. The `package.json` scripts, prettier config, and lint-staged config are added by the Agent in Step 3.

### Step 3: Iterative ESLint Configuration & Verification

This phase adds ESLint plugins incrementally, verifying stability after each addition.

**3.0: Add Development Scripts**

- Add quality scripts to `package.json`. Adjust the glob pattern to match the project's style format (`*.css`, `*.scss`, or `*.{css,scss}`):

  ```json
  {
    "lint": "ng lint",
    "lint:fix": "ng lint --fix",
    "lint:styles": "stylelint \"src/**/*.css\"",
    "lint:styles:fix": "stylelint \"src/**/*.css\" --fix",
    "format": "prettier --check \"src/**/*.{ts,html,css,json,md}\"",
    "format:fix": "prettier --write \"src/**/*.{ts,html,css,json,md}\""
  }
  ```

- **Verify Scripts:** Run `[pkg-manager] run` to list available scripts and confirm they were added.
- **CI Usage:** Use check-only scripts (`lint`, `lint:styles`, `format`) to fail builds on issues.
- **Development:** Use auto-fix scripts (`lint:fix`, `lint:styles:fix`, `format:fix`) to fix issues locally.

**3.1: Verify Base Configuration**

- Run `[pkg-manager] run lint` immediately after installation.
- **MUST pass** before proceeding.
- **Note:** The base configuration from `ng add @angular-eslint/schematics` automatically includes `tsRecommended`, `templateRecommended`, and `templateAccessibility`. Verification involves ensuring these presets are present in `eslint.config.js`.

**3.2: Add Prettier Integration**

- Add **both** Prettier packages to `eslint.config.js` as the **last two entries** in the `defineConfig` array:
  1. `eslint-config-prettier` — Disables ESLint formatting rules that conflict with Prettier.
  2. `eslint-plugin-prettier/recommended` — Runs Prettier as an ESLint rule (so `ng lint --fix` formats too).
- Add global ignores and globals configuration (see `references/eslint-config-template.md`).
- **Prettier Config:** Modern Angular CLI may auto-generate a `"prettier"` key in `package.json`. **Do NOT create a `.prettierrc` file.** Instead:
  1. Verify the `"prettier"` key exists in `package.json`.
  2. Verify the Angular HTML parser override is in `package.json` (see `references/prettier.md`).
- Create `.prettierignore` (consult `references/prettier.md`).
- Run `[pkg-manager] run lint`.
- **MUST pass** before proceeding.

**3.3: Add Organizational Plugins**
- Add `eslint-plugin-import-x` and `eslint-plugin-unused-imports` to `eslint.config.js` (consult `references/import-x-and-unused-imports.md`).
- Use the official `defineConfig` pattern: register `importX` as a plugin and use `extends: ['import-x/flat/recommended', 'import-x/flat/typescript']` string references.
- Add `// @ts-expect-error -- known type incompatibility between import-x and ESLint Plugin types` above the `'import-x': importX` line.
- Run `[pkg-manager] run lint`.
- **MUST pass** before proceeding.

**3.4: Add RxJS Plugin (CONDITIONAL)**

1. Read `rxjsLinting` from `PROJECT_MANIFEST.json` (or ask the user if no manifest):
   - `"auto"` (default): Check if `rxjs` is listed in `package.json` dependencies or devDependencies. If present, proceed. If absent, skip.
   - `"enabled"`: Always install and configure the plugin.
   - `"disabled"`: Skip entirely.
2. **If installing:** Add `eslint-plugin-rxjs-x` to `eslint.config.js` using the shared config `rxjsX.configs.recommended` (consult `references/rxjs.md`). Ensure `parserOptions.projectService: true` is set in the TypeScript block for type-aware rules.
   - Run `[pkg-manager] run lint`.
   - If type-checker errors occur, consult references and troubleshoot parser configuration.
   - **MUST pass** before proceeding.
3. **If skipping:** Inform the user: _"RxJS linting is disabled for this project. If you add RxJS later, re-run Step 3.4 or set `rxjsLinting: enabled` in the manifest."_

### Step 4: Stylelint Verification

- **Verify:** `stylelint.config.mjs` and `.stylelintignore` exist (auto-generated by script in Step 1).
- Run `[pkg-manager] run lint:styles` to verify configuration.
- **MUST pass** before proceeding.

### Step 5: Git Hooks Validation

- **Verify:** `.husky/pre-commit` and `.husky/commit-msg` exist (auto-generated by script in Step 1).
- Add a `"lint-staged"` key to `package.json` (consistent with Prettier — both inline):
  ```json
  {
    "lint-staged": {
      "*.ts": ["eslint --fix"],
      "*.html": ["eslint --fix", "prettier --write"],
      "*.css": ["stylelint --fix", "prettier --write"],
      "*.{json,md}": ["prettier --write"]
    }
  }
  ```
  > **Note:** Do NOT create a `.lintstagedrc` file. Keep it inline in `package.json` for consistency.
- **Verify:** `commitlint.config.js`, `.husky/commit-msg`, `.husky/pre-commit`, and `"lint-staged"` key in `package.json` all exist.
- Perform a test commit to verify:
  - Husky pre-commit hook triggers lint-staged.
  - Commitlint validates conventional commit messages.
- **MUST succeed** before proceeding.

### Step 6: Final Verification

- Run `[pkg-manager] run lint` (check-only) to verify all ESLint rules pass.
- Run `[pkg-manager] run lint:styles` to verify all Stylelint rules pass (if applicable).
- Run `[pkg-manager] run format` (check-only) to verify all files are properly formatted.
- All checks **MUST pass** before proceeding.

### Step 7: Validation Testing (REQUIRED)

Confirm all quality rules are actively working by creating intentional violations and verifying detection, auto-fix, and cleanup.

Follow the complete test strategy in `references/validation-testing.md`. It covers:

- **ESLint TypeScript** (unused imports, wrong import order, naming)
- **ESLint HTML/Accessibility** (missing alt text, click without keyup, non-focusable elements)
- **ESLint RxJS-x** (nested subscribe, unsafe takeUntil)
- **Prettier** (formatting violations)
- **Stylelint** (CSS violations)
- **Commitlint** (bad vs good commit messages)
- **Lint-staged** (pre-commit hook execution)

**MUST complete** the validation checklist in `references/validation-testing.md` before proceeding to Step 8.

### Step 8: Cleanup

- Do not leave intermediate files, backups, or temporary artifacts in the user workspace.

## Resources

- **scripts/configure_linters.sh**: Deterministic orchestrator for installation and initial setup.
- **references/**: Configuration examples and troubleshooting guides for each tool.
  - `eslint-config-template.md` — ESLint flat config structural skeleton — defines WHERE each plugin integrates. Read alongside the individual plugin reference files.
  - `rxjs.md` — `eslint-plugin-rxjs-x` shared configs and integration guide.
  - `prettier.md` — Prettier + ESLint integration.
  - `stylelint.md` — Stylelint config for CSS/SCSS Angular projects.
  - `import-x-and-unused-imports.md` — Import organization and unused import detection.
  - `parser-config.md` — TypeScript parser troubleshooting (projectService, tsconfigRootDir).
  - `validation-testing.md` — Complete test patterns for validating all quality tools.

