Repository navigation
Releases: solidjs-community/eslint-plugin-solid
Release list
v0.18.1
Bug-fix patch release. Thanks @thedanchez for the detailed reports (#233, #234, #235), @brenelz for #230, and @milomg for #228.
solid/reactivity
dynamic()sources from@solidjs/webare now tracked scopes, likecreateMemo— async sources included (#230 by @brenelz; fixes item 1 of #235).- Optional callback properties wrapped in a conditional or logical expression (
{ onDrag: props.onDrag ? (e) => props.onDrag(e) : undefined }) now classify like the unconditional property form instead of reportingbadUnnamedDerivedSignal(#235 item 2). .then()/.catch()/.finally()callbacks are treated as called functions, like timer callbacks and code afterawait(#235 item 3).
solid/no-unused-signal
- Function-form derived primitives (
createSignal(fn),createStore(fn, seed)) are no longer reported as "never written" — they change through their source function (#234). - The export exemption now applies only to the exported declaration itself, so signals inside
export function Component() {}are checked again;export const [a, setA] = createSignal(0)stays exempt (#234).
Types
- Public exports are now assignable to ESLint's
defineConfig()fromeslint/config: the plugin's rules are declared with a loose structural type at the export boundary (mirroring typescript-eslint's workaround for typescript-eslint#11543), and configs validate against ESLint's ownLinter.Config. Runtime unchanged; a type-level test now guards this in CI (#233).
eslint-solid-standalone
v0.18.0
Four new correctness rules (from #219, thanks @brenelz), a revived community rule (#145, thanks @SarguelUnda), extensions to existing rules, and a batch of reactivity false-positive fixes. Verified against the official Solid 2.0 templates (zero findings).
New rules (enabled in v2/v2-strict)
solid/no-write-in-pure-computation(error) — setter calls increateMemocallbacks, the compute half ofcreateEffect(compute, effect), and component bodies, all pure owned scopes that throw on writes in Solid 2.0 dev. HonorsownedWrite: true;onSettled/createTrackedEffect/handlers/effect halves exempt by function boundary. Closes #79.solid/no-store-mutation-outside-setter(error) — mutating a store's read proxy is silently ignored by core (no error, no update); lint is the only guardrail today.solid/no-unused-signal(warn) — never-written or never-readcreateSignal/createStore/createOptimistictuples, which unused-variable rules can't see.solid/no-boolean-enumerated-attribute(error) — booleans on enumerated attributes (draggable,spellcheck,contenteditable,translate, tristatearia-*) produce a different state than the string tokens; literals autofix. Closes #144/#145.
Reactivity false-positive fixes
untrack(async () => ...)no longer reports an async tracked scope (#188)this.state = stateis a reference escape, not a snapshot (#184)makePersisted(createSignal(...))-style wrappers analyze as pass-through (#190)
New setting
settings.solid.moduleSourcesregisters custom renderers/re-export wrappers as Solid primitive sources (#183)
Full details in the changelog.
v0.17.1
Bug fixes only. Thanks to @jynxio and @brenelz for the reports and PRs.
Fixes
solid/reactivityregression from 0.16.1 (#223). ThestaleCapturecheck flagged captures read inside synchronous array-method callbacks (items.filter((item) => item.includes(q))) withincreateMemo/createEffectbodies. A function passed as a call argument doesn't escape through areturnbelow it — only the call's result does — so these callbacks run during the computation, where the capture is fresh. IIFEs are exempt for the same reason.solid/importstype mappings for Solid 2.0 (#220, #221, #222). TheJSXnamespace only exists in@solidjs/webin 2.0; the rule was autofixing correct imports into a module that doesn't export it.ValidComponent/ComponentPropsare now accepted from bothsolid-js(DOM-independent) and@solidjs/web(DOM-aware) since the two packages export genuinely different types. The fixer also no longer produces a duplicatetypemodifier (import type { type JSX }) when moving inline type specifiers.renderToStringAsyncis a removed API, not a misplaced one. It no longer exists in Solid 2.0 (renderToStringawaits async content). Dropped from the v2 imports map — which was autofixing imports into a dead end — and added tosolid/removed-apiwith migration guidance.solid/removed-apinow also scans@solidjs/webimports, so a mechanically source-rewritten import of a removed API is still reported.
Also verified fixed and closed: #193 (signals passed as create* arguments stopped warning with the 0.16.1 accessor-passing work).
v0.17.0
Server functions are core in Solid 2.0, so the plugin now lints them. Four new rules cover the "use server" directive's silent failure modes — all enabled as errors in the v2 and v2-strict configs, and verified against the official Solid 2.0 templates (zero findings) and under Oxlint.
New Rules
solid/valid-use-server. The compiler only honors"use server"in specific positions and silently ignores it everywhere else — often shipping database access or secrets to the client without any error. Flags directives that aren't in the directive prologue (after other statements, inside plain blocks), template-literal "directives", and directives in positions the compiler never extracts (object methods, getters/setters, class methods). For module-level directive files, also flags non-function exports (which fail at server boot) and calls to client declaration wrappers (GET,live,withMetafrom@solidjs/web;query,action,liveQueryfrom@solidjs/router), whose client-side behavior is silently compiled out in such files. AclientWrappersoption adds project-specific wrapper names, with*wildcard and/regex/support.solid/require-async-server-function. On the client every server function call resolves a Promise, but during SSR the function is called in-process and returns synchronously — so a non-async server function observes two different return types, and TypeScript only sees one of them. Covers function-level directives and all exports of module-level directive files (includingexport { name }specifiers). Autofixes by insertingasync.solid/no-invalid-server-capture. An editor-time mirror of the compiler's closure-capture validation: server functions cannot capture variables from intermediate scopes (component state, enclosing function parameters), because the extracted function is hoisted to module level on the server and becomes a network proxy on the client. The compiler already rejects this at build time; the rule reports the same captures as you type. Module top-level bindings, imports, globals, own params/locals, named-function-expression self-references, and TS type-only references are all allowed.solid/no-browser-globals-in-server-function. Flags unambiguous browser-only globals (window,document,localStorage, etc.) inside server functions, which only run on the server. The list is deliberately conservative — server runtimes providefetch,crypto,URL, and evennavigator, so those never warn — and shadowing bindings andtypeof windowguards are ignored. In module-level directive files, the whole module is checked.
Internal
customReactiveFunctions-style pattern matching (exact names,*wildcards,/regex/strings) was extracted into a sharedcreateNameMatcherutility, now used by bothsolid/reactivityandsolid/valid-use-server.
Full Changelog: v0.16.1...v0.17.0
v0.16.1
A precision pass over solid/reactivity, driven by the longest-standing false-positive reports in the tracker. Every fix landed with a regression test reproducing the original issue, and the Solid 2.0 templates still lint clean.
Fixes
- Context provider
valuegets a real explanation (#209). Passing a reactive expression to a provider'svalueprop previously produced the generic "should be used within JSX" message — nonsense for something that is in JSX. It now reports a dedicated message explaining that providers readvalueonce, untracked, when created (true in both Solid 1.x and 2.0), and to pass the signal, memo, or store itself. Detection also now covers the Solid 2.0 form, where the context object is used directly as the provider (<MyContext value={...}>), by resolving JSX names tocreateContext()calls. createResourceargument shapes (#199, #195).createResource(fetcher, options)no longer treats the fetcher as a tracked scope (so async fetchers with an options object stop reportingnoAsyncTrackedScope), and increateResource(source, fetcher)the fetcher is now correctly treated as an untracked called function that may be async and read current values. The source remains a synchronous tracked scope.- Destructuring props inside a tracked scope (#191).
const { item } = propsinsidecreateMemo/createEffectre-runs on updates and no longer warns. Destructuring at component setup level still does. window.setTimeoutand friends (#194). Timer and scheduling callbacks prefixed withwindow.,globalThis., orself.now get the same called-function treatment as the bare globals.mergeProps/mergefunction arguments are tracked scopes (#179). Both wrap function sources increateMemo, so reactive reads inside them no longer warn.- Memos passed to functions are as safe as signals (#182). Passing a
createMemoaccessor to acreate*/use*/custom reactive function no longer warns, matching the existing allowance for signals. - Directly-returned
create*calls (#52).return createMemo(...)(or as an arrow body) no longer reportsshouldAssign— the result is handed to the caller, like a custom primitive. - Functions passed to calls inside tracked scopes (#197). An inline function passed to an unknown call inside an effect (
doSomething(() => props.toggle)) no longer warns, matching the existing behavior for named functions: synchronous calls still run tracked, and later calls poll current values.
Features
- Patterns in
customReactiveFunctions(#176). Entries now support*wildcards ("watch*") and regexes written as"/pattern/"strings, in addition to exact names.
v0.16.0
The complete Solid 2.0 lint surface: version-aware rules, new v2 / v2-strict configs, and a
full set of 2.0-specific rules, all vetted against the official Solid 2.0 templates (which lint
clean with zero errors and zero warnings under the v2 config).
Features
settings.solid.version. Rules can now read the targeted Solid major version from ESLint
settings (settings: { solid: { version: 2 } }). Unset means the permissive dual-version
behavior from 0.15. The new configs preset it; any custom config can opt in with one line.- New
v2config (eslint-plugin-solid/configs/v2, alsosolid.configs.v2): what the
official Solid 2.0 templates ship. Sets the version setting, switches existing rules to strict
2.0 semantics, and enables the new 2.0 rules — errors are reserved for near-certain bugs,
heuristics stay warnings. - New
v2-strictconfig (eslint-plugin-solid/configs/v2-strict): everything inv2plus
the plugin's strongest opinions (see below). - New rule
solid/removed-api(error inv2): flags removed/renamed 1.x APIs with
autofixes where mechanical (onMount→onSettled,batch→flush,mergeProps→merge,
unwrap→snapshot,equalFn→isEqual,getListener→getObserver,
classList={{...}}→class={{...}},"solid-js/web"→"@solidjs/web",
"solid-js/store"→"solid-js") and prescriptive migration messages otherwise
(createResource,on,Suspense→Loading,Index→<For keyed={false}>,produce, etc.).
Lists verified against the Solid 2.0 RC source. - New rule
solid/no-single-arg-create-effect(error inv2): Solid 2.0 requires the split
createEffect(compute, effect)form. The single-argument 1.x form produces no TS compile error
on a bare statement call and only throws at runtime in dev mode; this rule is the build-time
hard stop for the most commonly reproduced AI mistake. - New rule
solid/no-accessor-as-prop(error inv2):<div title={count} />silently
renders a stringified function. Fires on any expression that statically resolves to a function
in a value-typed DOM attribute, with a message that states the fix (count→count()).
Event handlers,ref,children, namespaced attributes, components, and custom elements are
exempt. - New rule
solid/prefer-structured-class(warning inv2, error inv2-strict): nudges
manually-built class strings (concatenation with conditionals, conditional template literals,
.join(" ")) toward the structured array/objectClassValueforms that Solid 2.0 accepts
natively. Static strings and plain interpolation are untouched. - New rule
solid/no-module-scope-reactive-primitive(error inv2-strictonly): reactive
state at module scope is shared across SSR requests.createRoot-wrapped module state is the
deliberate escape hatch and is not flagged. - New rule
solid/prefer-onSettled-for-side-effects(warning inv2-strictonly): flags
side-effectful setup (timers, global listeners, observers) in component bodies, where it also
runs during SSR; suggestsonSettled. Never flagsonCleanupitself. - New rule
solid/no-restated-default-options(error inv2-strictonly, autofixable):
removes restated defaults like<For keyed={true}>and<Show keyed={false}>. - Version-2 behavior in existing rules (active when
settings.solid.versionis 2):solid/no-unknown-namespacesinverts its premise: namespaces are no longer reserved in 2.0,
so any colon-name is a legal literal attribute — but the formerly-special prefixesuse:,
attr:,bool:,on:, andoncapture:are flagged as near-certain 1.x migration bugs with
per-prefix guidance.prop:remains the only special namespace.solid/event-handlersgraduates from style to correctness: only camelCaseonClickis an
event handler in 2.0; a lowercaseonclickwith a function value is a listener that will
never fire (autofixed to camelCase for known DOM events). Lowercase names with static string
values are legitimate literal attributes and are no longer flagged.onDoubleClick(which
lowercases to a nonexistent DOM event) is autofixed toonDblClick.solid/importsrequires the 2.0 export locations: store exports from core"solid-js", web
exports from"@solidjs/web". The legacysolid-js/store/solid-js/websubpaths are
solid/removed-api's territory, avoiding double reports.solid/jsx-no-undefauto-imports the 2.0 control-flow components (For,Repeat,Show,
Switch,Match,Errored,Loading,Reveal);Indexis no longer suggested.solid/reactivitydelegates its uncalled-signal-in-DOM-attribute case to
solid/no-accessor-as-propso a node never gets two reports.solid/no-react-depsself-gates off (a dependency array in the second argument is already a
type and runtime error in 2.0).
- Template vetting. A fixture test runs the
v2config over sources copied from the official
Solid 2.0 templates in CI, andtest/lint-templates.mjssweeps a localsolidjs/templates
checkout. All elevensolid-v2/*templates lint clean.
v0.15.0
The revival release: Solid 2.0 support and a modernized toolchain.
Breaking Changes
- ESLint v9 and v10 only. The
eslintpeer dependency range is now^9.0.0 || ^10.0.0. Support for ESLint v6–v8 has been dropped. - Flat config only. The legacy eslintrc-style
plugin:solid/recommendedandplugin:solid/typescriptconfigs have been removed, matching ESLint v10's removal of the eslintrc system. Useeslint-plugin-solid/configs/recommended/eslint-plugin-solid/configs/typescript, or the configs on the root export (solid.configs.recommended/solid.configs.typescript). Theconfigs["flat/recommended"]andconfigs["flat/typescript"]names from 0.14.x still work as aliases. - Node.js 22+ required. The
engines.nodefield is now>=22.0.0(Node 20 reached end-of-life in April 2026).
Features
- Solid 2.0 API support in
solid/reactivity. The rule now recognizes, alongside the 1.x APIs:createProjection,createOptimistic,createOptimisticStore,merge,omit,isPending,latest,resolve,deep,repeat,flush,action,onSettled,createTrackedEffect,createErrorBoundary,createLoadingBoundary,createRevealOrder, function-formcreateSignal(fn)/createStore(fn), split effects (createEffect(compute, effect)), async computations (e.g.createMemo(async () => ...)), and<For>'skeyedprop callback shapes. Imports from@solidjs/signalsare recognized as Solid imports. Callsites whose meaning differs between 1.x and 2.0 are resolved permissively so that neither interpretation warns. - New
readAfterAwaitwarning insolid/reactivity. In async computations (asynccreateMemo, function-form derived primitives), reactive reads placed after the firstawaitoryieldare not tracked—in 1.x they behave like reads in an event handler, and in 2.0 they can observe unpredictable mid-transition state. The rule now reports these reads specifically and suggests reading the value before the computation suspends. solid/importsunderstands Solid 2.0 export locations.createStore,reconcile, and store types imported from coresolid-js(their 2.0 home) are no longer flagged.- Oxlint support. The plugin runs under Oxlint's
jsPluginswithout modification; see the README for setup.
Internal
- Removed the ESLint v6–v8 test matrix; tests run against typescript-eslint, Babel, and espree parsers on ESLint 10.
- Toolchain updated: pnpm 11, typescript-eslint 8.67, vitest 4, TypeScript 5.9; CI tests Node 22/24/26.
- CI publishing switched from a stored npm token to npm Trusted Publishing (OIDC).
- Fixed silently-broken docs generation (auto-generated CASES sections regenerate again).
Full Changelog: v0.14.5...v0.15.0
v0.14.5
What's Changed
- fix: add missing typescript peer deps by @rtritto in #172
- Bump rollup from 3.29.4 to 3.29.5 by @dependabot in #167
- add
boolnamespace to "no-unknown-namespaces" by @titoBouzout in #171 - fix broken link in readme by @titoBouzout in #170
New Contributors
- @rtritto made their first contribution in #172
- @titoBouzout made their first contribution in #171
Full Changelog: v0.14.4...v0.14.5
v0.14.4
What's Changed
- Fix rule documentation URLs. by @joshwilsonvu in #159
- Less strict checking of event handler attribute names by @pedro00dk in #164
- Fix rule table links. by @joshwilsonvu in #165
- components-return-once: Support declarations after final return. by @joshwilsonvu in #166
New Contributors
- @pedro00dk made their first contribution in #164
Full Changelog: v0.14.3...v0.14.4
v0.14.3
What's Changed
- Restructure to turbo monorepo by @joshwilsonvu in #150
- Add GH Action for bumping package versions. by @joshwilsonvu in #153
- Update Regex that ignores untracked Scopes by @N0tExisting in #152
New Contributors
- @N0tExisting made their first contribution in #152
Full Changelog: v0.14.2...v0.14.3