ESLint rule playground
Test custom ESLint rules in the browser
Paste a compact rule, define valid and invalid fixtures, then run a RuleTester-like check without sending code to a backend.
- Runtime
- Dedicated browser worker
- Compatibility
- RuleTester-like adapter
- TypeScript
- TypeScript syntax adapter
Checks messageId matching on Identifier nodes with one valid and one invalid JavaScript fixture.
Fixture JSON
Run result
Choose a preset or edit the rule and fixtures, then run the tester.
Fixture workflow
Use one valid case, one invalid case and then expand toward TypeScript syntax, options and autofix boundaries.
Worker safety model
The tool blocks network and storage APIs, caps input size and terminates long runs; it is still for short synthetic examples, not untrusted packages.
TypeScript scope
The MVP parses TypeScript syntax with a TypeScript compiler syntax adapter. Type-aware projectService checks belong in repository CI or a server-side sandbox.
ESLint Rule Tester Playground | Playground Forge
Test lint rule behavior before it reaches a repository
Test small JavaScript and TypeScript ESLint rules in a private browser worker with RuleTester-like fixtures, messageId checks and simple autofix output.
Test lint rule behavior before it reaches a repository
ESLint Rule Tester Playground gives rule authors a small, private surface for checking whether a custom rule reports the right node, message and fix on representative snippets. Paste a CommonJS rule module, define a compact fixture array and run the cases in a dedicated browser worker. The page is built for the review moment before a rule enters shared tooling: does the selector fire on the intended syntax, does messageId resolve to the right copy, do valid examples stay quiet, and does a simple autofix produce the expected output? The route deliberately avoids backend execution and persistent storage so short code samples remain local to the browser session.
What the MVP checks
The MVP implements a controlled RuleTester-like adapter rather than pretending to be a full Node.js ESLint runtime. Each fixture has a name, code, valid flag, optional filename, options, expected errors and optional output. The adapter parses JavaScript or TypeScript syntax with a TypeScript compiler syntax adapter, walks the ESTree-shaped AST by listener key, exposes context.report, context.options, context.getSourceCode().getText and a small fixer API for replaceText, remove, insertTextBefore and insertTextAfter. Expected errors can be a number or an array matching messageId, message fragments and AST node type. This is enough to validate early rule shape, test examples for docs and compare simple autofixes without asking the public route to load arbitrary plugins, tsconfig projects or repository files.
How to interpret the result
A green run means the current snippet set matches the rule behavior declared in the fixtures. It does not mean the rule is production-ready for every parser option, monorepo package or framework AST shape. Start with one valid case and one invalid case, then add a TypeScript-specific fixture if the rule touches type annotations, TSTypeReference, imports, enums or generics. Read failures as contract feedback: a mismatch in messageId usually points to meta.messages or report configuration; a node type mismatch usually means the selector is too broad or too narrow; an output mismatch means the fixer range or replacement text should be simplified before rollout. The playground blocks network and storage APIs in the worker, caps input size and terminates long runs, but it is still an execution surface for short synthetic rules, not a security sandbox for untrusted packages. Keep examples small, avoid confidential source and move the final rule into a repository test suite with the real ESLint RuleTester before shipping. The publisher content on this route is intentionally deeper than a widget: it explains parser boundaries, fixture design, autofix risks, timeout behavior and why type-aware projectService checks are outside the client-side MVP. A practical review should also cover rule ergonomics. Check whether the rule copy tells a developer what to change, whether the invalid example is close to real code, and whether the autofix would be safe in a large pull request. A good lint rule should reduce repeated review comments, not create new ambiguity. For that reason the playground keeps output visible case by case: passed valid examples prove the rule is not too noisy, failed invalid examples show whether the selector found the intended syntax, and output comparison makes fixer risk visible before the rule is promoted to a shared preset. The TypeScript parser mode is useful for syntax-level policy such as imports, type aliases, generic references, enum usage and unsafe naming patterns. It is not a replacement for parserServices, type checker queries or project references. If a rule needs symbol resolution, semantic type information, module graph awareness or tsconfig-specific behavior, the safe next step is a repository-local test suite. This boundary is important for trust: the public route can demonstrate rule shape and fixture design, while CI remains responsible for full dependency context, official RuleTester parity and framework-specific edge cases. Use the three presets as decision templates. The identifier example is for message contracts and selector noise. The ReadonlyArray example is for TypeScript AST vocabulary without semantic type services. The debugger example is for option handling, schema language and conservative fixes. When a team proposes a new lint rule, map it to one of those patterns first, then add only the smallest additional fixture needed to prove the behavior. That habit keeps rule discussions concrete and prevents a public playground from turning into an undocumented lint framework.
A practical lint rule workflow
Start with one behavior the rule should enforce, then write the smallest valid fixture that should stay quiet and the smallest invalid fixture that should report. Add messageId only after the selector is stable, and add output only when the fix is conservative enough to review in a large repository. This keeps the playground useful for rule design instead of turning it into an accidental lint framework. A good pull request note can copy three facts from the page: the valid case that proves the rule is not noisy, the invalid case that proves the selector finds the intended syntax, and the limitation that still requires repository RuleTester coverage. That evidence makes the rollout discussion concrete for platform teams and avoids vague claims such as the rule works everywhere.