@projectplaceholders/eslint-config
v0.1.0
Published
Lint rules that hold a codebase's shape while an agent edits it.
Readme
@projectplaceholders/eslint-config
Lint rules that hold a codebase's shape while an agent edits it.
Presets
| Import | For |
|---|---|
| @projectplaceholders/eslint-config/base | Any TypeScript package. Type-aware. |
| @projectplaceholders/eslint-config/node | CLIs, services, tooling. |
| @projectplaceholders/eslint-config/react-library | React component libraries. |
| @projectplaceholders/eslint-config/next | Next.js apps. Includes the architecture rules. |
| @projectplaceholders/eslint-config/architecture | The architecture rules on their own. |
// eslint.config.js
import { config } from "@projectplaceholders/eslint-config/next"
export default configEverything is an error, nothing is a warning
An agent scrolls past a warning. A non-zero exit code is a wall it has to deal with — it reads the message and fixes itself. That difference is the entire mechanism, so this config ships no warnings at all.
Type-aware by default
Without type information, ESLint cannot see a floating promise or an any flowing through
a call chain — which is most of what an agent gets wrong. base turns on projectService,
so every preset lints against real types.
The architecture rules
src/shared/** may depend on nothing but itself
src/features/<f>/domain/** pure: src/shared and its own domain, no I/O
src/features/<f>/application/** + its own application, + other features' index.ts
src/features/<f>/infrastructure/** + its own infrastructure
src/features/<f>/ui/** like application, plus its own ui
src/features/<f>/index.ts the feature's only public entry point
src/app/** src/shared and feature entry pointsTwo consequences are the point of the whole thing:
applicationmay not importinfrastructure. A use case cannot reach for a database or an HTTP client itself, so it stays testable without one.- A feature is reachable only through its
index.ts.features/billing/infrastructure/stripecannot be imported from anywhere else — that is the deep-import ban.
Inside src/features/*/domain/**, any and non-null assertions are also errors. Domain is
the layer every other layer trusts; an any there launders an unchecked value into code
that believes it was checked.
Every violation message names the layers involved and states what to do instead, because the reader is usually an agent deciding its next edit:
'application' may not import 'infrastructure'. Allowed: domain -> src/shared and its own
feature's domain only ... If you need something from another feature, export it from that
feature's index.ts; if the logic belongs to neither feature, move it to src/shared.Tests
pnpm testtest/fixtures is a small project holding nine files that follow the architecture and seven
that each break exactly one rule. The suite asserts silence on the first group and the right
rule id on the second — a config that enforces nothing passes neither half.
