eslint-plugin-what 0.10.0 → 0.11.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
@@ -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 -- renders "[Function]", conditionals always truthy
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-what",
3
- "version": "0.10.0",
3
+ "version": "0.11.1",
4
4
  "description": "ESLint rules for What Framework — catch signal bugs, enforce patterns",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
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: '0.6.0',
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: {swr.data} renders "[Function]"
16
- * Bad: `Total: ${count}` "[Function]"
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 without calling it.
5
- * Signals are functions using them without () in JSX renders "[Function]"
6
- * instead of the signal's value.
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
- * Bad: <span>{count}</span> — renders "[Function]"
12
- * Bad: <p>{isLoading && <Spinner />}</p> — always truthy
13
+ * Implicit: <span>{count}</span> — relies on compiler auto-wrapping
14
+ * Bad: <p>{isLoading && <Spinner />}</p> — signal fn is always truthy
13
15
  *
14
- * Good: <span>{count()}</span>
15
- * Good: <p>{isLoading() && <Spinner />}</p>
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 without calling it. ' +
30
- 'Use {{{name}}()} to read the value, or the JSX will render "[Function]".',
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
- 'Signals are always truthy — use {{{name}}() && ...} instead.',
35
+ 'A signal function is always truthy — use {{{name}}() && ...} instead.',
34
36
  },
35
37
  schema: [],
36
38
  },