@continuum-js/eslint-plugin
v0.3.0
Published
ESLint rules for Continuum — catch impure combinator callbacks, frozen sample() in JSX, missing retain() and onChange-on-blur before they bite
Readme
@continuum-js/eslint-plugin
ESLint rules for Continuum: catch the common mistakes before they run.
npm i -D @continuum-js/eslint-plugin// eslint.config.js (flat config)
import continuum from "@continuum-js/eslint-plugin";
export default [
// …your other configs
continuum.configs.recommended,
];Rules
| Rule | Default | Catches |
| ----------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| no-impure-combinators | error | fetch/localStorage/document/alert/timers/setters/dispatch/Date.now/Math.random inside accum/accumE (and legacy snapshot/lift2/lift3) callbacks — combinator functions must be pure |
| no-sample-in-jsx | error | {count.sample()} in JSX — renders once and freezes; bind the wire itself (handlers are fine) |
| state-needs-scope | error | module-level state (hold/accum/accumE/perform) outside root() — state lives as long as its scope, and at module level there is none, so it throws at runtime |
| prefer-oninput | warn | onChange on text fields — the native change event fires on blur; use onInput or bindInput (checkbox/radio/file/select are fine) |
Scope, honestly
Purity is undecidable statically, so these are heuristics tuned against
false positives: map/filter callbacks are deliberately not flagged
(they collide with Array.prototype). The runtime purity guard in
@continuum-js/frp covers that half dynamically — firing a source inside
any pure combinator throws a teaching error.
