@pyreon/lint 0.11.4 → 0.11.6

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.
Files changed (86) hide show
  1. package/README.md +91 -91
  2. package/lib/analysis/cli.js.html +5406 -0
  3. package/lib/analysis/index.js.html +1 -1
  4. package/lib/cli.js +3290 -0
  5. package/lib/cli.js.map +1 -0
  6. package/lib/index.js +220 -29
  7. package/lib/index.js.map +1 -1
  8. package/lib/types/index.d.ts +30 -5
  9. package/lib/types/index.d.ts.map +1 -1
  10. package/package.json +19 -19
  11. package/src/cache.ts +1 -1
  12. package/src/cli.ts +39 -28
  13. package/src/config/ignore.ts +23 -23
  14. package/src/config/loader.ts +8 -8
  15. package/src/config/presets.ts +11 -11
  16. package/src/index.ts +14 -12
  17. package/src/lint.ts +19 -25
  18. package/src/lsp/index.ts +225 -0
  19. package/src/reporter.ts +17 -17
  20. package/src/rules/accessibility/dialog-a11y.ts +10 -10
  21. package/src/rules/accessibility/overlay-a11y.ts +11 -11
  22. package/src/rules/accessibility/toast-a11y.ts +11 -11
  23. package/src/rules/architecture/dev-guard-warnings.ts +19 -19
  24. package/src/rules/architecture/no-circular-import.ts +16 -16
  25. package/src/rules/architecture/no-cross-layer-import.ts +35 -35
  26. package/src/rules/architecture/no-deep-import.ts +7 -7
  27. package/src/rules/architecture/no-error-without-prefix.ts +20 -20
  28. package/src/rules/form/no-submit-without-validation.ts +13 -13
  29. package/src/rules/form/no-unregistered-field.ts +12 -12
  30. package/src/rules/form/prefer-field-array.ts +11 -11
  31. package/src/rules/hooks/no-raw-addeventlistener.ts +9 -9
  32. package/src/rules/hooks/no-raw-localstorage.ts +11 -11
  33. package/src/rules/hooks/no-raw-setinterval.ts +11 -11
  34. package/src/rules/index.ts +60 -57
  35. package/src/rules/jsx/no-and-conditional.ts +8 -8
  36. package/src/rules/jsx/no-children-access.ts +12 -12
  37. package/src/rules/jsx/no-classname.ts +10 -10
  38. package/src/rules/jsx/no-htmlfor.ts +10 -10
  39. package/src/rules/jsx/no-index-as-by.ts +17 -17
  40. package/src/rules/jsx/no-map-in-jsx.ts +9 -9
  41. package/src/rules/jsx/no-missing-for-by.ts +9 -9
  42. package/src/rules/jsx/no-onchange.ts +12 -12
  43. package/src/rules/jsx/no-props-destructure.ts +11 -11
  44. package/src/rules/jsx/no-ternary-conditional.ts +8 -8
  45. package/src/rules/jsx/use-by-not-key.ts +12 -12
  46. package/src/rules/lifecycle/no-dom-in-setup.ts +18 -18
  47. package/src/rules/lifecycle/no-effect-in-mount.ts +11 -11
  48. package/src/rules/lifecycle/no-missing-cleanup.ts +19 -19
  49. package/src/rules/lifecycle/no-mount-in-effect.ts +11 -11
  50. package/src/rules/performance/no-eager-import.ts +7 -7
  51. package/src/rules/performance/no-effect-in-for.ts +10 -10
  52. package/src/rules/performance/no-large-for-without-by.ts +9 -9
  53. package/src/rules/performance/prefer-show-over-display.ts +16 -16
  54. package/src/rules/reactivity/no-bare-signal-in-jsx.ts +10 -10
  55. package/src/rules/reactivity/no-context-destructure.ts +45 -0
  56. package/src/rules/reactivity/no-effect-assignment.ts +16 -16
  57. package/src/rules/reactivity/no-nested-effect.ts +10 -10
  58. package/src/rules/reactivity/no-peek-in-tracked.ts +10 -10
  59. package/src/rules/reactivity/no-signal-in-loop.ts +13 -13
  60. package/src/rules/reactivity/no-signal-leak.ts +9 -9
  61. package/src/rules/reactivity/no-unbatched-updates.ts +12 -12
  62. package/src/rules/reactivity/prefer-computed.ts +13 -13
  63. package/src/rules/router/index.ts +4 -4
  64. package/src/rules/router/no-href-navigation.ts +14 -14
  65. package/src/rules/router/no-imperative-navigate-in-render.ts +19 -19
  66. package/src/rules/router/no-missing-fallback.ts +16 -16
  67. package/src/rules/router/prefer-use-is-active.ts +11 -11
  68. package/src/rules/ssr/no-mismatch-risk.ts +11 -11
  69. package/src/rules/ssr/no-window-in-ssr.ts +22 -22
  70. package/src/rules/ssr/prefer-request-context.ts +14 -14
  71. package/src/rules/store/no-duplicate-store-id.ts +9 -9
  72. package/src/rules/store/no-mutate-store-state.ts +11 -11
  73. package/src/rules/store/no-store-outside-provider.ts +15 -15
  74. package/src/rules/styling/no-dynamic-styled.ts +13 -13
  75. package/src/rules/styling/no-inline-style-object.ts +10 -10
  76. package/src/rules/styling/no-theme-outside-provider.ts +11 -11
  77. package/src/rules/styling/prefer-cx.ts +12 -12
  78. package/src/runner.ts +13 -14
  79. package/src/tests/lsp.test.ts +88 -0
  80. package/src/tests/runner.test.ts +325 -325
  81. package/src/types.ts +15 -15
  82. package/src/utils/ast.ts +50 -50
  83. package/src/utils/imports.ts +53 -53
  84. package/src/utils/index.ts +12 -3
  85. package/src/utils/source.ts +2 -2
  86. package/src/watcher.ts +19 -25
package/README.md CHANGED
@@ -41,12 +41,12 @@ pyreon-lint --list
41
41
  ### Programmatic API
42
42
 
43
43
  ```ts
44
- import { lint, listRules, lintFile, applyFixes } from "@pyreon/lint"
44
+ import { lint, listRules, lintFile, applyFixes } from '@pyreon/lint'
45
45
 
46
46
  // Lint files
47
47
  const result = lint({
48
- paths: ["src/"],
49
- preset: "recommended",
48
+ paths: ['src/'],
49
+ preset: 'recommended',
50
50
  fix: false,
51
51
  quiet: false,
52
52
  })
@@ -59,140 +59,140 @@ for (const rule of listRules()) {
59
59
  }
60
60
 
61
61
  // Lint a single source string
62
- import { getPreset } from "@pyreon/lint"
63
- import { allRules } from "@pyreon/lint/rules"
62
+ import { getPreset } from '@pyreon/lint'
63
+ import { allRules } from '@pyreon/lint/rules'
64
64
 
65
- const fileResult = lintFile("app.tsx", source, allRules, getPreset("recommended"))
65
+ const fileResult = lintFile('app.tsx', source, allRules, getPreset('recommended'))
66
66
  ```
67
67
 
68
68
  ## Rules (51)
69
69
 
70
70
  ### Reactivity (8)
71
71
 
72
- | Rule | Severity | Fixable | Description |
73
- |------|----------|---------|-------------|
74
- | `pyreon/no-bare-signal-in-jsx` | error | Yes | Flags `{count()}` in JSX text — wrap in `() =>` |
75
- | `pyreon/no-signal-in-loop` | error | No | Flags signal()/computed() inside loops |
76
- | `pyreon/no-nested-effect` | warn | No | Flags effect() inside effect() |
77
- | `pyreon/no-peek-in-tracked` | error | No | Flags .peek() inside effect/computed |
78
- | `pyreon/no-unbatched-updates` | warn | No | Flags 3+ .set() calls without batch() |
79
- | `pyreon/prefer-computed` | warn | No | Suggests computed() for effect with single .set() |
80
- | `pyreon/no-effect-assignment` | warn | No | Flags effect with single .update() |
81
- | `pyreon/no-signal-leak` | warn | No | Reports unused signal declarations |
72
+ | Rule | Severity | Fixable | Description |
73
+ | ------------------------------ | -------- | ------- | ------------------------------------------------- |
74
+ | `pyreon/no-bare-signal-in-jsx` | error | Yes | Flags `{count()}` in JSX text — wrap in `() =>` |
75
+ | `pyreon/no-signal-in-loop` | error | No | Flags signal()/computed() inside loops |
76
+ | `pyreon/no-nested-effect` | warn | No | Flags effect() inside effect() |
77
+ | `pyreon/no-peek-in-tracked` | error | No | Flags .peek() inside effect/computed |
78
+ | `pyreon/no-unbatched-updates` | warn | No | Flags 3+ .set() calls without batch() |
79
+ | `pyreon/prefer-computed` | warn | No | Suggests computed() for effect with single .set() |
80
+ | `pyreon/no-effect-assignment` | warn | No | Flags effect with single .update() |
81
+ | `pyreon/no-signal-leak` | warn | No | Reports unused signal declarations |
82
82
 
83
83
  ### JSX (11)
84
84
 
85
- | Rule | Severity | Fixable | Description |
86
- |------|----------|---------|-------------|
87
- | `pyreon/no-map-in-jsx` | warn | No | Prefer `<For>` over .map() in JSX |
88
- | `pyreon/use-by-not-key` | error | Yes | Use `by` not `key` on `<For>` |
89
- | `pyreon/no-classname` | error | Yes | Use `class` not `className` |
90
- | `pyreon/no-htmlfor` | error | Yes | Use `for` not `htmlFor` |
91
- | `pyreon/no-onchange` | warn | Yes | Prefer `onInput` over `onChange` on inputs |
92
- | `pyreon/no-ternary-conditional` | warn | No | Prefer `<Show>` over ternary with JSX |
93
- | `pyreon/no-and-conditional` | warn | No | Prefer `<Show>` over `&&` with JSX |
94
- | `pyreon/no-index-as-by` | warn | No | Don't use index as `by` prop |
95
- | `pyreon/no-missing-for-by` | warn | No | `<For>` should have `by` prop |
96
- | `pyreon/no-props-destructure` | error | No | Don't destructure component props |
97
- | `pyreon/no-children-access` | info | No | Direct props.children access in renderers |
85
+ | Rule | Severity | Fixable | Description |
86
+ | ------------------------------- | -------- | ------- | ------------------------------------------ |
87
+ | `pyreon/no-map-in-jsx` | warn | No | Prefer `<For>` over .map() in JSX |
88
+ | `pyreon/use-by-not-key` | error | Yes | Use `by` not `key` on `<For>` |
89
+ | `pyreon/no-classname` | error | Yes | Use `class` not `className` |
90
+ | `pyreon/no-htmlfor` | error | Yes | Use `for` not `htmlFor` |
91
+ | `pyreon/no-onchange` | warn | Yes | Prefer `onInput` over `onChange` on inputs |
92
+ | `pyreon/no-ternary-conditional` | warn | No | Prefer `<Show>` over ternary with JSX |
93
+ | `pyreon/no-and-conditional` | warn | No | Prefer `<Show>` over `&&` with JSX |
94
+ | `pyreon/no-index-as-by` | warn | No | Don't use index as `by` prop |
95
+ | `pyreon/no-missing-for-by` | warn | No | `<For>` should have `by` prop |
96
+ | `pyreon/no-props-destructure` | error | No | Don't destructure component props |
97
+ | `pyreon/no-children-access` | info | No | Direct props.children access in renderers |
98
98
 
99
99
  ### Lifecycle (4)
100
100
 
101
- | Rule | Severity | Fixable | Description |
102
- |------|----------|---------|-------------|
103
- | `pyreon/no-missing-cleanup` | warn | No | onMount with timers needs cleanup return |
104
- | `pyreon/no-mount-in-effect` | warn | No | Don't call onMount inside effect |
105
- | `pyreon/no-effect-in-mount` | info | No | effect() inside onMount is unusual |
106
- | `pyreon/no-dom-in-setup` | warn | No | DOM queries outside onMount/effect |
101
+ | Rule | Severity | Fixable | Description |
102
+ | --------------------------- | -------- | ------- | ---------------------------------------- |
103
+ | `pyreon/no-missing-cleanup` | warn | No | onMount with timers needs cleanup return |
104
+ | `pyreon/no-mount-in-effect` | warn | No | Don't call onMount inside effect |
105
+ | `pyreon/no-effect-in-mount` | info | No | effect() inside onMount is unusual |
106
+ | `pyreon/no-dom-in-setup` | warn | No | DOM queries outside onMount/effect |
107
107
 
108
108
  ### Performance (4)
109
109
 
110
- | Rule | Severity | Fixable | Description |
111
- |------|----------|---------|-------------|
112
- | `pyreon/no-large-for-without-by` | error | No | `<For>` must have `by` for reconciliation |
113
- | `pyreon/no-effect-in-for` | warn | No | Don't create effects inside `<For>` |
114
- | `pyreon/no-eager-import` | info | No | Lazy-load heavy packages |
115
- | `pyreon/prefer-show-over-display` | info | No | Use `<Show>` instead of CSS display toggle |
110
+ | Rule | Severity | Fixable | Description |
111
+ | --------------------------------- | -------- | ------- | ------------------------------------------ |
112
+ | `pyreon/no-large-for-without-by` | error | No | `<For>` must have `by` for reconciliation |
113
+ | `pyreon/no-effect-in-for` | warn | No | Don't create effects inside `<For>` |
114
+ | `pyreon/no-eager-import` | info | No | Lazy-load heavy packages |
115
+ | `pyreon/prefer-show-over-display` | info | No | Use `<Show>` instead of CSS display toggle |
116
116
 
117
117
  ### SSR (3)
118
118
 
119
- | Rule | Severity | Fixable | Description |
120
- |------|----------|---------|-------------|
121
- | `pyreon/no-window-in-ssr` | error | No | Browser globals outside safe scopes |
122
- | `pyreon/no-mismatch-risk` | warn | No | Non-deterministic calls in JSX |
123
- | `pyreon/prefer-request-context` | warn | No | Module-level state in server files |
119
+ | Rule | Severity | Fixable | Description |
120
+ | ------------------------------- | -------- | ------- | ----------------------------------- |
121
+ | `pyreon/no-window-in-ssr` | error | No | Browser globals outside safe scopes |
122
+ | `pyreon/no-mismatch-risk` | warn | No | Non-deterministic calls in JSX |
123
+ | `pyreon/prefer-request-context` | warn | No | Module-level state in server files |
124
124
 
125
125
  ### Architecture (5)
126
126
 
127
- | Rule | Severity | Fixable | Description |
128
- |------|----------|---------|-------------|
129
- | `pyreon/no-circular-import` | error | No | Enforce package layer order |
130
- | `pyreon/no-deep-import` | warn | No | No @pyreon/*/src/ imports |
131
- | `pyreon/no-cross-layer-import` | error | No | Core can't import ui-system |
132
- | `pyreon/dev-guard-warnings` | error | No | console.warn/error needs `__DEV__` |
133
- | `pyreon/no-error-without-prefix` | warn | Yes | Errors need [Pyreon] prefix |
127
+ | Rule | Severity | Fixable | Description |
128
+ | -------------------------------- | -------- | ------- | ---------------------------------- |
129
+ | `pyreon/no-circular-import` | error | No | Enforce package layer order |
130
+ | `pyreon/no-deep-import` | warn | No | No @pyreon/\*/src/ imports |
131
+ | `pyreon/no-cross-layer-import` | error | No | Core can't import ui-system |
132
+ | `pyreon/dev-guard-warnings` | error | No | console.warn/error needs `__DEV__` |
133
+ | `pyreon/no-error-without-prefix` | warn | Yes | Errors need [Pyreon] prefix |
134
134
 
135
135
  ### Store (3)
136
136
 
137
- | Rule | Severity | Fixable | Description |
138
- |------|----------|---------|-------------|
139
- | `pyreon/no-store-outside-provider` | warn | No | Store hooks need provider in SSR |
140
- | `pyreon/no-mutate-store-state` | warn | No | Use actions, not direct .set() |
141
- | `pyreon/no-duplicate-store-id` | error | No | Unique defineStore() IDs |
137
+ | Rule | Severity | Fixable | Description |
138
+ | ---------------------------------- | -------- | ------- | -------------------------------- |
139
+ | `pyreon/no-store-outside-provider` | warn | No | Store hooks need provider in SSR |
140
+ | `pyreon/no-mutate-store-state` | warn | No | Use actions, not direct .set() |
141
+ | `pyreon/no-duplicate-store-id` | error | No | Unique defineStore() IDs |
142
142
 
143
143
  ### Form (3)
144
144
 
145
- | Rule | Severity | Fixable | Description |
146
- |------|----------|---------|-------------|
147
- | `pyreon/no-unregistered-field` | warn | No | useField() without register() |
148
- | `pyreon/no-submit-without-validation` | warn | No | useForm onSubmit without validators |
149
- | `pyreon/prefer-field-array` | info | No | signal([]) in form files |
145
+ | Rule | Severity | Fixable | Description |
146
+ | ------------------------------------- | -------- | ------- | ----------------------------------- |
147
+ | `pyreon/no-unregistered-field` | warn | No | useField() without register() |
148
+ | `pyreon/no-submit-without-validation` | warn | No | useForm onSubmit without validators |
149
+ | `pyreon/prefer-field-array` | info | No | signal([]) in form files |
150
150
 
151
151
  ### Styling (4)
152
152
 
153
- | Rule | Severity | Fixable | Description |
154
- |------|----------|---------|-------------|
155
- | `pyreon/no-inline-style-object` | warn | No | Inline style objects in JSX |
156
- | `pyreon/no-dynamic-styled` | warn | No | styled() inside functions |
157
- | `pyreon/prefer-cx` | info | No | Use cx() for class composition |
158
- | `pyreon/no-theme-outside-provider` | warn | No | useTheme() without provider |
153
+ | Rule | Severity | Fixable | Description |
154
+ | ---------------------------------- | -------- | ------- | ------------------------------ |
155
+ | `pyreon/no-inline-style-object` | warn | No | Inline style objects in JSX |
156
+ | `pyreon/no-dynamic-styled` | warn | No | styled() inside functions |
157
+ | `pyreon/prefer-cx` | info | No | Use cx() for class composition |
158
+ | `pyreon/no-theme-outside-provider` | warn | No | useTheme() without provider |
159
159
 
160
160
  ### Hooks (3)
161
161
 
162
- | Rule | Severity | Fixable | Description |
163
- |------|----------|---------|-------------|
164
- | `pyreon/no-raw-addeventlistener` | info | No | Use useEventListener() |
165
- | `pyreon/no-raw-setinterval` | info | No | Wrap timers in onMount |
166
- | `pyreon/no-raw-localstorage` | info | No | Use useStorage() |
162
+ | Rule | Severity | Fixable | Description |
163
+ | -------------------------------- | -------- | ------- | ---------------------- |
164
+ | `pyreon/no-raw-addeventlistener` | info | No | Use useEventListener() |
165
+ | `pyreon/no-raw-setinterval` | info | No | Wrap timers in onMount |
166
+ | `pyreon/no-raw-localstorage` | info | No | Use useStorage() |
167
167
 
168
168
  ### Accessibility (3)
169
169
 
170
- | Rule | Severity | Fixable | Description |
171
- |------|----------|---------|-------------|
172
- | `pyreon/toast-a11y` | warn | No | Toast components need role/aria-live |
173
- | `pyreon/dialog-a11y` | warn | No | `<dialog>` needs aria-label |
174
- | `pyreon/overlay-a11y` | warn | No | `<Overlay>` needs role/aria-label |
170
+ | Rule | Severity | Fixable | Description |
171
+ | --------------------- | -------- | ------- | ------------------------------------ |
172
+ | `pyreon/toast-a11y` | warn | No | Toast components need role/aria-live |
173
+ | `pyreon/dialog-a11y` | warn | No | `<dialog>` needs aria-label |
174
+ | `pyreon/overlay-a11y` | warn | No | `<Overlay>` needs role/aria-label |
175
175
 
176
176
  ## Presets
177
177
 
178
- | Preset | Description |
179
- |--------|-------------|
180
- | `recommended` | All rules at default severity |
181
- | `strict` | All warnings promoted to errors |
182
- | `app` | Recommended minus library-only rules |
183
- | `lib` | Strict plus architecture checks |
178
+ | Preset | Description |
179
+ | ------------- | ------------------------------------ |
180
+ | `recommended` | All rules at default severity |
181
+ | `strict` | All warnings promoted to errors |
182
+ | `app` | Recommended minus library-only rules |
183
+ | `lib` | Strict plus architecture checks |
184
184
 
185
185
  ## Custom Rules
186
186
 
187
187
  ```ts
188
- import type { Rule } from "@pyreon/lint"
188
+ import type { Rule } from '@pyreon/lint'
189
189
 
190
190
  const myRule: Rule = {
191
191
  meta: {
192
- id: "custom/my-rule",
193
- category: "reactivity",
194
- description: "My custom rule",
195
- severity: "warn",
192
+ id: 'custom/my-rule',
193
+ category: 'reactivity',
194
+ description: 'My custom rule',
195
+ severity: 'warn',
196
196
  fixable: false,
197
197
  },
198
198
  create(context) {
@@ -200,7 +200,7 @@ const myRule: Rule = {
200
200
  CallExpression(node, parent) {
201
201
  // Your rule logic
202
202
  context.report({
203
- message: "Something is wrong",
203
+ message: 'Something is wrong',
204
204
  span: { start: node.start, end: node.end },
205
205
  })
206
206
  },