@thomaflette/eslint-plugin-solid-2 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -63,7 +63,9 @@ The `flat/recommended` and `flat/recommended-type-checked` names are aliases for
63
63
  | `prefer-show` | Uses `<Show>` for idiomatic reactive JSX conditionals. |
64
64
  | `self-closing-comp` | Keeps empty JSX elements consistently self-closing. |
65
65
 
66
- Every rule has focused documentation in [docs](./docs).
66
+ Every rule has focused documentation in [docs](./docs). The
67
+ [dev-diagnostic coverage matrix](./docs/dev-diagnostic-coverage.md) records which Solid runtime
68
+ diagnostics are covered statically and which remain intentionally runtime-only.
67
69
 
68
70
  ## Design principles
69
71
 
@@ -58,3 +58,8 @@ props are valid code that static analysis cannot prove safe or unsafe.
58
58
  proven from bindings or nominal Solid accessor types, and recognizes JSX, nested closures,
59
59
  reactive callbacks, and `untrack` as safe execution contexts. It does not restore the deleted
60
60
  heuristic's guesses about arbitrary helper calls.
61
+ - Runtime-state mirrors for `PENDING_ASYNC_FORBIDDEN_SCOPE`, `SETTLED_CLEANUP_UNOWNED`, and the
62
+ `NO_OWNER_*` diagnostics were prototyped and rejected. Whether they fire depends on the source's
63
+ pending state or the active owner at execution; an owner-backed scheduler and an already-settled
64
+ async memo are valid counterexamples to static callback/source heuristics. Solid's exact runtime
65
+ diagnostics own these cases.
@@ -0,0 +1,29 @@
1
+ # Solid 2 dev-diagnostic coverage
2
+
3
+ The plugin complements Solid's
4
+ [dev-mode diagnostics](https://github.com/solidjs/solid/blob/next/documentation/solid-2.0/08-dev-diagnostics.md).
5
+ It reports a diagnostic statically only when the source proves the invalid runtime context. Dynamic
6
+ ownership, pending state, disposal state, and scheduler behavior remain with the runtime.
7
+
8
+ | Solid diagnostic | Static coverage | Rule or owner |
9
+ | -------------------------------- | ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- |
10
+ | `REACTIVE_WRITE_IN_OWNED_SCOPE` | Strong, sound subset | `no-owned-scope-writes` |
11
+ | `PENDING_ASYNC_UNTRACKED_READ` | Partial; catches provable untracked reads, regardless of pending state | `no-stale-props-alias`, `no-destructure`, `no-untracked-read-in-effect-apply` |
12
+ | `ASYNC_OUTSIDE_LOADING_BOUNDARY` | Runtime only; loading ancestry and render timing are dynamic | Solid runtime |
13
+ | `CLEANUP_IN_FORBIDDEN_SCOPE` | Strong | `no-leaf-owner-operations` |
14
+ | `SETTLED_CLEANUP_UNOWNED` | Runtime only; ownership at execution determines whether cleanup is honored | Solid runtime |
15
+ | `PRIMITIVE_IN_FORBIDDEN_SCOPE` | Strong for owner-creating primitives; plain value signals/stores follow current runtime behavior | `no-leaf-owner-operations` |
16
+ | Invalid cleanup return | Type-level cases are intentionally delegated | TypeScript and Solid runtime |
17
+ | `flush()` in forbidden scope | Strong | `no-leaf-owner-operations` |
18
+ | Potential infinite loop | Runtime only; depends on executed graph behavior | Solid runtime |
19
+ | `STRICT_READ_UNTRACKED` | Strong, sound subset of binding-proven reads | `no-stale-props-alias`, `no-destructure`, `no-untracked-read-in-effect-apply` |
20
+ | `PENDING_ASYNC_FORBIDDEN_SCOPE` | Runtime only; the source must actually be pending when read | Solid runtime |
21
+ | `NO_OWNER_EFFECT` | Runtime only; the active owner is execution-context state | Solid runtime |
22
+ | `NO_OWNER_CLEANUP` | Runtime only; the active owner is execution-context state | Solid runtime |
23
+ | `NO_OWNER_BOUNDARY` | Runtime only; the active owner is execution-context state | Solid runtime |
24
+ | `RUN_WITH_DISPOSED_OWNER` | Runtime only; disposal is dynamic | Solid runtime |
25
+
26
+ Some plugin rules have no corresponding runtime diagnostic. For example,
27
+ `no-reactive-read-after-await` catches dependency loss that native async continuation semantics make
28
+ indistinguishable from an intentional untracked read at runtime. The control-flow and JSX rules
29
+ likewise protect static structure or style rather than mirroring a dev diagnostic.
@@ -34,11 +34,15 @@ onSettled(() => {
34
34
 
35
35
  ## Good
36
36
 
37
- ```ts
38
- onSettled(() => {
39
- const id = setInterval(tick, 1000);
40
- return () => clearInterval(id);
41
- });
37
+ ```tsx
38
+ function Ticker() {
39
+ onSettled(() => {
40
+ const id = setInterval(tick, 1000);
41
+ return () => clearInterval(id);
42
+ });
43
+
44
+ return <output>{time()}</output>;
45
+ }
42
46
  ```
43
47
 
44
48
  ```ts
@@ -49,17 +53,21 @@ createTrackedEffect(() => {
49
53
  ```
50
54
 
51
55
  ```ts
52
- createEffect(
53
- () => count(),
54
- () => {
55
- queueMicrotask(() => flush());
56
- },
57
- );
56
+ onSettled(() => {
57
+ queueMicrotask(() => {
58
+ setOpen(true);
59
+ flush(); // Commit the update before reading the resulting DOM.
60
+ dialog.focus();
61
+ });
62
+ });
58
63
  ```
59
64
 
60
65
  ## Notes
61
66
 
62
67
  - Only **direct** calls inside the forbidden callback body are checked; nested helper function definitions are allowed.
68
+ - `flush()` is normally unnecessary because Solid flushes updates automatically. Use it only at an
69
+ imperative boundary that must observe the updated DOM synchronously; a microtask scheduled from a
70
+ leaf-owner callback is outside that callback's non-reentrant flush cycle.
63
71
  - Calls are matched by binding (a direct, aliased, or namespace `solid-js` import, or an unresolved
64
72
  global) — a same-named function from another package is not flagged. Type-aware mode also follows
65
73
  re-export chains.
@@ -3,9 +3,9 @@
3
3
  Disallow writing to signals/stores or calling actions inside component bodies and reactive compute
4
4
  scopes.
5
5
 
6
- This matches Solid 2's `SIGNAL_WRITE_IN_OWNED_SCOPE` behavior. In these places, derive values instead of writing state back into the graph.
7
- It also matches beta.17's `ACTION_CALLED_IN_OWNED_SCOPE` error: actions belong at imperative
8
- boundaries such as event handlers.
6
+ This matches Solid 2's `REACTIVE_WRITE_IN_OWNED_SCOPE` behavior. In these places, derive values
7
+ instead of writing state back into the graph. It also matches the runtime's
8
+ `ACTION_CALLED_IN_OWNED_SCOPE` error: actions belong at imperative boundaries such as event handlers.
9
9
 
10
10
  ## Bad
11
11
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thomaflette/eslint-plugin-solid-2",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Sound ESLint rules for Solid 2 reactivity and idiomatic control flow.",
5
5
  "keywords": [
6
6
  "eslint",