agentleFS
purupurupupurupurupu/css-noop-checker/CLAUDE.md

css-noop-checker

CLAUDE.md24 starsChanged 8 months agoMITView on GitHub

css-noop-checker is a Chrome DevTools extension (Manifest V3) that detects "no-op" CSS properties on the selected element. Built with React 19, TypeScript 5.9, and Vite 7. Package manager is pnpm (not npm/yarn). Runtime: Node.js 24, pnpm 10 (managed via .mise.toml). Chrome DevTools extension with two entry points (multi-page Vite build): Pure-function rules with zero Chrome API dependency — fully testable. Each rule file is named after its rule ID (e.g. container-no-gap.ts → rule ID container-no-gap). Key infrastructure files: Rule IDs…

  • Commits and pushes

The file

Show its rules and text

We split this CLAUDE.md into the rules it gives an agent

25 rules. About 0 are common, 9 are distinctive, and 16 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈9

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 16

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  • could be automatic: a setting could enforce it
  1. Very specific:

    When adding a new rule, pick a descriptive target and qualifier — avoid numbered IDs like D-1 or C-2.

    line 59
  2. Very specific:

    Create src/rules/<rule-id>.ts — implement RuleDescriptor, call registerRule(), export the check function.

    line 63
  3. Very specific:

    Add side-effect import in src/rules/engine.ts (keep alphabetical order)

    line 64
  4. Very specific:

    Add DEFAULT_COMPUTED_STYLES entries in src/rules/__tests__/helpers/make-element.ts for any new requiredProperties (the validation test will …

    line 65
  5. Very specific:

    Add unit tests in src/rules/__tests__/<rule-id>.test.ts

    line 66
  6. Very specific:

    Add "should warn" and "should NOT warn" test cases to examples/test.html (keep alphabetical order by rule ID)

    line 67
  7. Distinctive:

    Update the Detected Patterns table in README.md

    line 68
  8. Very specific:

    Add docs/rules/<rule-id>.md — explain why the property combination is a no-op, with examples (see existing docs for the template)

    line 69
  9. Very specific:

    Run pnpm test and pnpm test:e2e to verify

    line 70
  10. Distinctive:

    Do not assume a property is a full no-op just because one aspect is ignored.

    line 79
  11. Distinctive:

    Prefer avoiding false positives over maximizing warning count.

    line 81
  12. Distinctive:

    If you intentionally keep a false negative or a known limitation, say so in the rule comment with the specific trade-off.

    line 82
  13. Distinctive:

    Update the rule logic.

    line 90
  14. Distinctive:

    Update unit tests that encoded the old assumption.

    line 91
  15. Very specific:

    Update examples/test.html and EXPECTED_CASE_COUNT if cases were added or removed.

    line 92
  16. Very specific:

    Run both pnpm test and pnpm test:e2e.

    line 93
  17. Distinctive:

    Avoid absolute language such as "this rule is correct" unless it has been validated in Chromium and the remaining limitations are …

    line 95
  18. Very specific:

    When modifying any of these behaviors, update both build-scan-script.ts and extract-element-data.ts.

    line 150
  19. Very specific:

    Use import type for type-only imports (verbatimModuleSyntax is enabled)

    line 173
  20. Distinctive:

    Write messages in English

    line 183
  21. Distinctive:

    Add a body after a blank line when extra context is needed

    line 184
  22. Very specific:

    Run pnpm fmt before committing to apply formatting

    line 185
  23. Very specific:

    Run pnpm build or pnpm lint before committing to verify nothing is broken

    line 186
  24. Very specific:

    Update version in both package.json (root) and mcp-server/package.json — keep them in sync

    line 194
  25. Very specific:

    Follow semver: 0.Y.Z during pre-1.0 development

    line 207

≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
CLAUDE.md

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

css-noop-checker is a Chrome DevTools extension (Manifest V3) that detects "no-op" CSS properties on the selected element. Built with React 19, TypeScript 5.9, and Vite 7.

Commands

  • pnpm dev — Watch-mode build (vite build --watch)
  • pnpm build — Type-check with tsc -b then bundle with Vite
  • pnpm lint — Lint with Oxlint
  • pnpm fmt — Format with Oxfmt
  • pnpm fmt:check — Check formatting without writing
  • pnpm test — Run tests with Vitest
  • pnpm test:watch — Run tests in watch mode
  • pnpm test:e2e — Run Playwright browser integration tests
  • pnpm test:e2e:ui — Run Playwright tests with interactive UI

Package manager is pnpm (not npm/yarn). Runtime: Node.js 24, pnpm 10 (managed via .mise.toml).

Tech Stack

  • Build: Vite 7 + SWC via @vitejs/plugin-react-swc
  • Framework: React 19 (react-jsx transform)
  • Language: TypeScript 5.9 (strict, verbatimModuleSyntax, erasableSyntaxOnly)
  • Linting: Oxlint (.oxlintrc.json) — plugins: typescript, react
  • Formatting: Oxfmt (.oxfmtrc.jsonc) — singleQuote, trailingComma all, printWidth 100
  • Testing: Vitest 4 (vitest.config.ts, separate from vite.config.ts), Playwright (playwright.config.ts) for browser integration tests

Architecture

Chrome DevTools extension with two entry points (multi-page Vite build):

  • devtools.html → src/devtools.ts — Creates "CSS Noop" sidebar pane in Elements tab
  • sidebar.html → src/sidebar/main.tsx — React app rendered inside the sidebar pane

Rules Engine (src/rules/)

Pure-function rules with zero Chrome API dependency — fully testable. Each rule file is named after its rule ID (e.g. container-no-gap.ts → rule ID container-no-gap).

Key infrastructure files:

  • types.ts — ElementData, Warning, Rule, RuleContext, RuleId
  • context.ts — createRuleContext() normalizes computed styles; helper predicates
  • stacking-context.ts — isStackingContext() detects CSS stacking context triggers
  • engine.ts — analyzeElement() creates context then runs all registered rules
  • registry.ts — rule registration via side-effect imports in engine.ts

Rule ID Naming Convention

Rule IDs follow Stylelint's thing-no-qualifier pattern — the de facto standard in CSS lint tooling. This makes rule purposes immediately obvious without looking up documentation.

  • Format: <target>-no-<what-is-disallowed>
  • target — the element/context being checked (e.g. inline, container)
  • no-<qualifier> — the property or behavior that has no effect in that context

When adding a new rule, pick a descriptive target and qualifier — avoid numbered IDs like D-1 or C-2.

New Rule Checklist

  1. Create src/rules/<rule-id>.ts — implement RuleDescriptor, call registerRule(), export the check function. Use createWarning() factory via a scoped warn helper for all warnings.
  2. Add side-effect import in src/rules/engine.ts (keep alphabetical order)
  3. Add DEFAULT_COMPUTED_STYLES entries in src/rules/__tests__/helpers/make-element.ts for any new requiredProperties (the validation test will fail if missed). If the rule uses requiredInlineProperties, ensure unit tests pass appropriate inline style overrides via makeElement's third parameter.
  4. Add unit tests in src/rules/__tests__/<rule-id>.test.ts
  5. Add "should warn" and "should NOT warn" test cases to examples/test.html (keep alphabetical order by rule ID)
  6. Update the Detected Patterns table in README.md
  7. Add docs/rules/<rule-id>.md — explain why the property combination is a no-op, with examples (see existing docs for the template)
  8. Run pnpm test and pnpm test:e2e to verify

Rule Correctness Expectations

This project should be treated as Chromium-behavior-driven, not purely spec-driven.

  • The extension analyzes styles from Chrome DevTools, so the most important question is: does this declaration actually have an effect in current Chromium?
  • Unit tests are necessary but not sufficient. They often encode assumptions; those assumptions can be wrong.
  • For any non-trivial rule change, add or update a real browser case in examples/test.html and verify it with Playwright.
  • Do not assume a property is a full no-op just because one aspect is ignored. Shorthands and composite features can be partially effective.
    • Example pattern: place-items can still matter if either the align-items half or the justify-items half is effective in Chromium.
  • Prefer avoiding false positives over maximizing warning count. If behavior is conditional, context-sensitive, or unclear in Chromium, bias toward silence and document the limitation.
  • If you intentionally keep a false negative or a known limitation, say so in the rule comment with the specific trade-off.

When Auditing or Fixing Existing Rules

Use this order:

  1. Reproduce the case in real Chromium with a minimal layout.
  2. Confirm whether the declaration is fully ineffective, partially effective, or effective.
  3. Update the rule logic.
  4. Update unit tests that encoded the old assumption.
  5. Update examples/test.html and EXPECTED_CASE_COUNT if cases were added or removed.
  6. Run both pnpm test and pnpm test:e2e.

Avoid absolute language such as "this rule is correct" unless it has been validated in Chromium and the remaining limitations are explicitly called out.

test.html Test Case Format

Each test case in examples/test.html must include data-target and data-rule attributes for Playwright integration tests:

<!-- "should warn" case -->
<div class="case expect-warn" data-rule="<rule-id>">
  <div class="label label-warn"><rule-id> warn: description</div>
  <TARGET_ELEMENT data-target style="...">...</TARGET_ELEMENT>
</div>

<!-- "should NOT warn" case -->
<div class="case expect-ok" data-rule="<rule-id>">
  <div class="label label-ok"><rule-id> ok: description</div>
  <TARGET_ELEMENT data-target style="...">...</TARGET_ELEMENT>
</div>
  • data-rule — the rule ID being tested (e.g. inline-no-dimensions). Use data-rule="none" for cases that should produce zero warnings from any rule
  • data-target — boolean attribute on the element to inspect (must be exactly one per .case)
  • For cases where the target is a nested child (e.g. flex/grid items), place data-target on the actual inspectable element, not the wrapper
  • Ordering — rule sections in test.html must be sorted alphabetically by rule ID (e.g. block-no-vertical-align before container-no-align). The "No issues" section stays at the end. This matches the Scan Page display order.

MCP Server (mcp-server/)

Standalone MCP server that reuses the rules engine and e2e extraction helpers to analyze live pages via Playwright. Separate package.json managed as a pnpm workspace.

  • src/index.ts — MCP tool handlers (list_rules, analyze_element, scan_page)
  • src/url-validation.ts — SSRF-safe URL validation (scheme + private IP checks)

Element Extraction: Dual Implementation

Element extraction (getting computed styles from in-page elements) exists in two parallel implementations due to different API constraints:

Extension sidebarE2E helpers / MCP server
Filessrc/sidebar/hooks/build-eval-script.ts, build-scan-script.tse2e/helpers/extract-element-data.ts
APIchrome.devtools.inspectedWindow.eval() — requires string-serialized JSPlaywright page.evaluate() — accepts functions directly
Used byChrome extension UIPlaywright e2e tests, MCP server

Adding a new rule does NOT require changes to either extraction implementation — both dynamically query registry.ts for required CSS properties.

However, changes to extraction behavior itself require updating both implementations. The two implementations currently have known divergences:

Both implementations share SKIP_TAGS and other constants from src/rules/scan-constants.ts. The remaining divergences:

BehaviorExtension sidebarE2E / MCP server
display: noneFilters out (cs.display === 'none')Does not filter
Query scopedocument.body.querySelectorAll('*')document.querySelectorAll('*')
Selector formatCSS.escape() + max 3 classesnth-of-type + all classes
Scan capChunked pagination (offset/limit)Single pass, 5 000 element cap

When modifying any of these behaviors, update both build-scan-script.ts and extract-element-data.ts.

Browser Integration Tests (e2e/)

Playwright-based tests that verify rules against real browser getComputedStyle():

  • helpers/extract-element-data.ts — registry-driven computed style extraction (mirrors extension eval script)
  • integration/rules-against-real-styles.test.ts — opens test.html, extracts real styles, runs analyzeElement(), asserts against data-rule / expect-warn / expect-ok

New rules are automatically covered when test cases are added to test.html with proper data-target and data-rule attributes. No changes to the integration test code are needed.

Sidebar UI (src/sidebar/)

React app rendered in the DevTools sidebar pane. See src/sidebar/components/ and src/sidebar/hooks/ for the full list.

Build Constraints

  • base: '' in vite.config.ts — relative paths required for extension
  • modulePreload: false — MV3 CSP blocks <link rel="modulepreload">. Do not remove.

Code Style

  • ESM modules ("type": "module")
  • Use import type for type-only imports (verbatimModuleSyntax is enabled)
  • No barrel exports — do not create index.ts re-export files. Import directly from the source module.
  • Format with Oxfmt before committing

Commit Rules

  • Make small, meaningful commits (1 commit = 1 logical change)
  • Focus on "why" in commit messages, not "what" changed
  • Format: <type>: <why-focused message>
    • type: feat, fix, refactor, chore, docs, test
  • Write messages in English
  • Add a body after a blank line when extra context is needed
  • Run pnpm fmt before committing to apply formatting
  • Run pnpm build or pnpm lint before committing to verify nothing is broken

Release Rules

Releases are triggered by pushing a v* tag. The GitHub Actions workflow (.github/workflows/release.yml) automatically runs CI, creates a GitHub Release with the extension zip, and publishes the MCP server to npm via OIDC trusted publisher.

Version bump procedure

  1. Update version in both package.json (root) and mcp-server/package.json — keep them in sync
  2. Commit: chore: bump version to X.Y.Z
  3. Merge to main via PR
  4. Tag and push:
    git checkout main && git pull
    git tag vX.Y.Z
    git push --tags
  5. Workflow runs automatically — verify at GitHub Actions

Versioning

  • Follow semver: 0.Y.Z during pre-1.0 development
  • Root package and MCP server share the same version

PR Rules

  • Title and body must be written in English
  • Title: short (under 70 chars), format <type>: <concise description>
  • Body structure:
    • ## Summary — bullet points describing what and why
    • ## Test plan — checklist of verification steps
  • Include a table or list for any non-obvious design decisions
  • Link to related issues if applicable

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.