eslint-plugin-what 0.10.0 → 0.11.0
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 +2 -2
- package/package.json +1 -1
- package/src/index.js +33 -1
- package/src/rules/no-uncalled-signals.js +6 -4
- package/src/rules/signal-call-in-jsx.js +12 -10
package/README.md
CHANGED
|
@@ -36,12 +36,12 @@ export default [
|
|
|
36
36
|
Catches the #1 mistake for new developers: using a signal reference instead of calling it. Signals are functions -- you must call them to read the value.
|
|
37
37
|
|
|
38
38
|
```jsx
|
|
39
|
-
// Bad --
|
|
39
|
+
// Bad -- conditionals are always truthy; bare JSX reads rely on compiler auto-wrapping
|
|
40
40
|
<span>{count}</span>
|
|
41
41
|
{isLoading && <Spinner />}
|
|
42
42
|
<span>{swr.data}</span>
|
|
43
43
|
|
|
44
|
-
// Good
|
|
44
|
+
// Good -- explicit reads work everywhere, compiler or not
|
|
45
45
|
<span>{count()}</span>
|
|
46
46
|
{isLoading() && <Spinner />}
|
|
47
47
|
<span>{swr.data()}</span>
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* export default [what.configs.recommended];
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import { createRequire } from 'node:module';
|
|
13
|
+
|
|
12
14
|
import noSignalInEffectDeps from './rules/no-signal-in-effect-deps.js';
|
|
13
15
|
import reactiveJsxChildren from './rules/reactive-jsx-children.js';
|
|
14
16
|
import noSignalWriteInRender from './rules/no-signal-write-in-render.js';
|
|
@@ -19,10 +21,14 @@ import noHInUserCode from './rules/no-h-in-user-code.js';
|
|
|
19
21
|
import signalCallInJsx from './rules/signal-call-in-jsx.js';
|
|
20
22
|
import noSetInComputed from './rules/no-set-in-computed.js';
|
|
21
23
|
|
|
24
|
+
// Read the real version from package.json so plugin meta never goes stale.
|
|
25
|
+
const require = createRequire(import.meta.url);
|
|
26
|
+
const pkg = require('../package.json');
|
|
27
|
+
|
|
22
28
|
const plugin = {
|
|
23
29
|
meta: {
|
|
24
30
|
name: 'eslint-plugin-what',
|
|
25
|
-
version:
|
|
31
|
+
version: pkg.version,
|
|
26
32
|
},
|
|
27
33
|
|
|
28
34
|
rules: {
|
|
@@ -41,8 +47,28 @@ const plugin = {
|
|
|
41
47
|
};
|
|
42
48
|
|
|
43
49
|
// Flat config presets (ESLint 9+)
|
|
50
|
+
//
|
|
51
|
+
// Each preset is a COMPLETE standalone flat config entry: it carries its own
|
|
52
|
+
// `files` glob and JSX-enabled language options, so
|
|
53
|
+
// `export default [what.configs.recommended]` works with stock ESLint —
|
|
54
|
+
// no extra parser setup required for .js/.jsx. (.ts/.tsx files match the glob
|
|
55
|
+
// too, but TypeScript syntax additionally needs a TS parser config layered on
|
|
56
|
+
// top, e.g. typescript-eslint.)
|
|
57
|
+
|
|
58
|
+
const baseLanguageOptions = {
|
|
59
|
+
ecmaVersion: 'latest',
|
|
60
|
+
sourceType: 'module',
|
|
61
|
+
parserOptions: {
|
|
62
|
+
ecmaFeatures: { jsx: true },
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const FILES = ['**/*.{js,jsx,ts,tsx}'];
|
|
44
67
|
|
|
45
68
|
plugin.configs.recommended = {
|
|
69
|
+
name: 'what/recommended',
|
|
70
|
+
files: FILES,
|
|
71
|
+
languageOptions: baseLanguageOptions,
|
|
46
72
|
plugins: { what: plugin },
|
|
47
73
|
rules: {
|
|
48
74
|
'what/no-signal-in-effect-deps': 'warn',
|
|
@@ -59,6 +85,9 @@ plugin.configs.recommended = {
|
|
|
59
85
|
|
|
60
86
|
// Stricter config — all rules as errors + prefer-set
|
|
61
87
|
plugin.configs.strict = {
|
|
88
|
+
name: 'what/strict',
|
|
89
|
+
files: FILES,
|
|
90
|
+
languageOptions: baseLanguageOptions,
|
|
62
91
|
plugins: { what: plugin },
|
|
63
92
|
rules: {
|
|
64
93
|
'what/no-signal-in-effect-deps': 'error',
|
|
@@ -75,6 +104,9 @@ plugin.configs.strict = {
|
|
|
75
104
|
|
|
76
105
|
// Config for projects using the What compiler (disables rules the compiler handles)
|
|
77
106
|
plugin.configs.compiler = {
|
|
107
|
+
name: 'what/compiler',
|
|
108
|
+
files: FILES,
|
|
109
|
+
languageOptions: baseLanguageOptions,
|
|
78
110
|
plugins: { what: plugin },
|
|
79
111
|
rules: {
|
|
80
112
|
'what/no-signal-in-effect-deps': 'warn',
|
|
@@ -6,14 +6,16 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Signals are functions — you must call them to read the value.
|
|
8
8
|
* Using a signal without () gives you the function reference, which:
|
|
9
|
-
* - Renders as "[Function]" in JSX
|
|
10
9
|
* - Is always truthy in conditionals
|
|
11
10
|
* - Produces wrong comparisons
|
|
11
|
+
* - Coerces to the function source in template literals
|
|
12
|
+
* - In JSX children it only works because the compiler auto-wraps it —
|
|
13
|
+
* explicit () reads don't depend on that
|
|
12
14
|
*
|
|
13
|
-
* Bad: <span>{count}</span> → renders "[Function]"
|
|
14
15
|
* Bad: {isLoading && <Spinner />} → always truthy
|
|
15
|
-
* Bad: {
|
|
16
|
-
* Bad:
|
|
16
|
+
* Bad: `Total: ${count}` → function source, not the value
|
|
17
|
+
* Bad: <span>{count}</span> → implicit (relies on compiler auto-wrap)
|
|
18
|
+
* Bad: {swr.data} → implicit (relies on compiler auto-wrap)
|
|
17
19
|
*
|
|
18
20
|
* Good: <span>{count()}</span>
|
|
19
21
|
* Good: {isLoading() && <Spinner />}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Rule: what/signal-call-in-jsx
|
|
3
3
|
*
|
|
4
|
-
* Warn when a signal is used in JSX
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Warn when a signal is used in JSX as a bare reference instead of being
|
|
5
|
+
* called. The What compiler auto-wraps bare signals ({count} works when the
|
|
6
|
+
* code is compiled), but explicit reads ({count()}) are clearer, lint-safe,
|
|
7
|
+
* and don't depend on compiler magic — e.g. they keep working in plain
|
|
8
|
+
* h()/runtime-only code paths.
|
|
7
9
|
*
|
|
8
10
|
* This rule specifically targets JSX expression containers, complementing
|
|
9
11
|
* the broader no-uncalled-signals rule with JSX-specific messaging.
|
|
10
12
|
*
|
|
11
|
-
*
|
|
12
|
-
* Bad:
|
|
13
|
+
* Implicit: <span>{count}</span> — relies on compiler auto-wrapping
|
|
14
|
+
* Bad: <p>{isLoading && <Spinner />}</p> — signal fn is always truthy
|
|
13
15
|
*
|
|
14
|
-
*
|
|
15
|
-
* Good:
|
|
16
|
+
* Explicit: <span>{count()}</span>
|
|
17
|
+
* Good: <p>{isLoading() && <Spinner />}</p>
|
|
16
18
|
*/
|
|
17
19
|
|
|
18
20
|
import { createSignalTracker, SIGNAL_METHODS } from '../utils/signal-tracking.js';
|
|
@@ -26,11 +28,11 @@ export default {
|
|
|
26
28
|
},
|
|
27
29
|
messages: {
|
|
28
30
|
signalNotCalledInJsx:
|
|
29
|
-
'"{{name}}" is a signal used in JSX
|
|
30
|
-
'
|
|
31
|
+
'"{{name}}" is a signal used in JSX as a bare reference. ' +
|
|
32
|
+
'Prefer {{{name}}()} for an explicit read — bare signals rely on the compiler auto-wrapping them.',
|
|
31
33
|
signalNotCalledInJsxLogical:
|
|
32
34
|
'"{{name}}" is a signal used in a JSX conditional without calling it. ' +
|
|
33
|
-
'
|
|
35
|
+
'A signal function is always truthy — use {{{name}}() && ...} instead.',
|
|
34
36
|
},
|
|
35
37
|
schema: [],
|
|
36
38
|
},
|