@pyreon/lint 0.12.0 → 0.12.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index2.d.ts","names":[],"sources":["../../../src/types.ts","../../../src/utils/source.ts","../../../src/cache.ts","../../../src/config/ignore.ts","../../../src/config/loader.ts","../../../src/config/presets.ts","../../../src/lint.ts","../../../src/reporter.ts","../../../src/lsp/index.ts","../../../src/rules/index.ts","../../../src/runner.ts","../../../src/utils/imports.ts","../../../src/watcher.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index2.d.ts","names":[],"sources":["../../../src/types.ts","../../../src/utils/source.ts","../../../src/cache.ts","../../../src/config/ignore.ts","../../../src/config/loader.ts","../../../src/config/presets.ts","../../../src/lint.ts","../../../src/reporter.ts","../../../src/lsp/index.ts","../../../src/rules/index.ts","../../../src/runner.ts","../../../src/utils/imports.ts","../../../src/watcher.ts"],"mappings":";KAEY,QAAA;AAAA,UAEK,cAAA;EACf,IAAA;EACA,MAAA;AAAA;AAAA,UAGe,IAAA;EACf,KAAA;EACA,GAAA;AAAA;AAAA,UAGe,GAAA;EACf,IAAA,EAAM,IAAA;EACN,WAAA;AAAA;AAAA,UAGe,UAAA;EACf,MAAA;EACA,QAAA,EAAU,QAAA;EACV,OAAA;EACA,IAAA,EAAM,IAAA;EACN,GAAA,EAAK,cAAA;EACL,GAAA,GAAM,GAAA;AAAA;AAAA,KAKI,YAAA;AAAA,UAcK,QAAA;EACf,EAAA;EACA,QAAA,EAAU,YAAA;EACV,WAAA;EACA,QAAA,EAAU,QAAA;EACV,OAAA;AAAA;AAAA,UAKe,WAAA;EACf,MAAA,CAAO,UAAA,EAAY,IAAA,CAAK,UAAA;EACxB,aAAA;EACA,WAAA;AAAA;AAAA,KAGU,eAAA,IAAmB,IAAA,OAAW,MAAA;AAAA,UAEzB,gBAAA;EAAA,CACd,QAAA,WAAmB,eAAA;AAAA;AAAA,UAKL,IAAA;EACf,IAAA,EAAM,QAAA;EACN,MAAA,CAAO,OAAA,EAAS,WAAA,GAAc,gBAAA;AAAA;AAAA,UAKf,UAAA;EACf,KAAA,EAAO,MAAA,SAAe,QAAA;EACtB,OAAA;EACA,OAAA;AAAA;AAAA,UAGe,cAAA;EACf,MAAA,GAAS,UAAA;EACT,KAAA,GAAQ,MAAA,SAAe,QAAA;EACvB,OAAA;EACA,OAAA;AAAA;AAAA,KAGU,UAAA;AAAA,UAIK,cAAA;EACf,QAAA;EACA,WAAA,EAAa,UAAA;EACb,WAAA;AAAA;AAAA,UAGe,UAAA;EACf,KAAA,EAAO,cAAA;EACP,WAAA;EACA,aAAA;EACA,UAAA;AAAA;AAAA,UAKe,WAAA;EACf,KAAA;EACA,MAAA,GAAS,UAAA;EACT,GAAA;EACA,KAAA;EACA,aAAA,GAAgB,MAAA,SAAe,QAAA;EAC/B,MAAA;EACA,MAAA;AAAA;AAAA,UAKe,UAAA;EACf,MAAA;EACA,UAAA,EAAY,KAAA;IAAQ,QAAA;IAAkB,KAAA;EAAA;EACtC,SAAA;EACA,WAAA;AAAA;;;AAzHF;;;AAAA,cCGa,SAAA;EAAA,QACH,UAAA;cAEI,UAAA;EDJiB;ECc7B,MAAA,CAAO,MAAA,WAAiB,cAAA;AAAA;;;ADhB1B;;;;;AAEA;;;;;AAKA;;;;;AAKA;;;AAZA,cEkBa,QAAA;EAAA,QACH,KAAA;EAER,GAAA,CAAI,UAAA;IAAuB,OAAA;IAAc,SAAA,EAAW,SAAA;EAAA;EAKpD,GAAA,CAAI,UAAA,UAAoB,KAAA;IAAS,OAAA;IAAc,SAAA,EAAW,SAAA;EAAA;EAK1D,KAAA,CAAA;EAAA,IAII,IAAA,CAAA;AAAA;;;;AFnCN;;;;;AAEA;;;;;AAKA;;iBGOgB,kBAAA,CACd,GAAA,UACA,WAAA,yBACE,QAAA;;;AHjBJ;;;;;AAEA;;;;;AAKA;;;;;AAKA;;AAZA,iBIqBgB,UAAA,CAAW,GAAA,WAAc,cAAA;;;;iBAmCzB,kBAAA,CAAmB,QAAA,WAAmB,cAAA;;;iBCDtC,SAAA,CAAU,IAAA,EAAM,UAAA,GAAa,UAAA;;;ALvD7C;;;;;AAEA;;;;;AAKA;AAPA,iBM0KgB,IAAA,CAAK,OAAA,EAAS,WAAA,GAAc,UAAA;;;;AN9J5C;;;;;;;;;iBM2MgB,SAAA,CAAA,GAAa,QAAA;;;ANvN7B;;;AAAA,iBOyBgB,UAAA,CAAW,MAAA,EAAQ,UAAA;;APvBnC;;iBO6DgB,UAAA,CAAW,MAAA,EAAQ,UAAA;;;APxDnC;iBO+DgB,aAAA,CAAc,MAAA,EAAQ,UAAA;;;;APtEtC;;;;;AAEA;;;;;AAKA;;;;;AAKA;;;;;;iBQ6KgB,cAAA,CAAA;;;cCpHH,QAAA,EAAU,IAAA;;;;;;;ATnEvB;;;;;iBUwFgB,QAAA,CACd,QAAA,UACA,UAAA,UACA,KAAA,EAAO,IAAA,IACP,MAAA,EAAQ,UAAA,EACR,KAAA,GAAQ,QAAA,eACP,cAAA;;;;;iBA+Da,UAAA,CAAW,UAAA,UAAoB,WAAA,EAAa,UAAA;;;iBC/F5C,cAAA,CAAe,MAAA;AAAA,iBAIf,eAAA,CAAgB,MAAA;AAAA,iBAIhB,iBAAA,CAAkB,IAAA,QAAY,UAAA;AAAA,iBA2B9B,WAAA,CAAY,OAAA,EAAS,UAAA,IAAc,IAAA,UAAc,WAAA;AAAA,iBAQjD,YAAA,CACd,OAAA,EAAS,UAAA,IACT,IAAA,UACA,WAAA;;;AX9GF;;;;;AAEA;;;;;AAKA;;;AAPA,iBY4BgB,YAAA,CAAa,OAAA,EAAS,WAAA;EAAgB,MAAA;AAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyreon/lint",
3
- "version": "0.12.0",
3
+ "version": "0.12.2",
4
4
  "description": "Pyreon-specific linter — 56 rules for signals, JSX, SSR, performance, router, and architecture",
5
5
  "homepage": "https://github.com/pyreon/pyreon/tree/main/packages/lint#readme",
6
6
  "bugs": {
@@ -46,6 +46,7 @@ import { noEffectAssignment } from './reactivity/no-effect-assignment'
46
46
  import { noNestedEffect } from './reactivity/no-nested-effect'
47
47
  import { noPeekInTracked } from './reactivity/no-peek-in-tracked'
48
48
  import { noSignalInLoop } from './reactivity/no-signal-in-loop'
49
+ import { noSignalInProps } from './reactivity/no-signal-in-props'
49
50
  import { noSignalLeak } from './reactivity/no-signal-leak'
50
51
  import { noUnbatchedUpdates } from './reactivity/no-unbatched-updates'
51
52
  import { preferComputed } from './reactivity/prefer-computed'
@@ -69,10 +70,11 @@ import { noThemeOutsideProvider } from './styling/no-theme-outside-provider'
69
70
  import { preferCx } from './styling/prefer-cx'
70
71
 
71
72
  export const allRules: Rule[] = [
72
- // Reactivity (9)
73
+ // Reactivity (10)
73
74
  noBareSignalInJsx,
74
75
  noContextDestructure,
75
76
  noSignalInLoop,
77
+ noSignalInProps,
76
78
  noNestedEffect,
77
79
  noPeekInTracked,
78
80
  noUnbatchedUpdates,
@@ -187,6 +189,7 @@ export {
187
189
  noRawLocalStorage,
188
190
  noRawSetInterval,
189
191
  noSignalInLoop,
192
+ noSignalInProps,
190
193
  noSignalLeak,
191
194
  // Store
192
195
  noStoreOutsideProvider,
@@ -0,0 +1,53 @@
1
+ import type { Rule, VisitorCallbacks } from '../../types'
2
+ import { getSpan } from '../../utils/ast'
3
+
4
+ function isComponentTag(name: string): boolean {
5
+ return name.length > 0 && name[0] === name[0]?.toUpperCase() && name[0] !== name[0]?.toLowerCase()
6
+ }
7
+
8
+ /**
9
+ * Warn when a known signal/computed is called in a component prop position.
10
+ * Component props are evaluated once at mount — signal reads are NOT reactive
11
+ * unless the compiler wraps them with _rp(). The compiler handles this
12
+ * automatically, but this rule catches manual h() calls and educates developers.
13
+ */
14
+ export const noSignalInProps: Rule = {
15
+ meta: {
16
+ id: 'pyreon/no-signal-in-props',
17
+ category: 'reactivity',
18
+ description:
19
+ 'Signal call in component prop — value captured once unless compiler wraps it. Use props.x pattern for reactivity.',
20
+ severity: 'warn',
21
+ fixable: false,
22
+ },
23
+ create(context) {
24
+ const callbacks: VisitorCallbacks = {
25
+ JSXExpressionContainer(node: any) {
26
+ const expr = node.expression
27
+ if (!expr || expr.type !== 'CallExpression') return
28
+ const callee = expr.callee
29
+ if (!callee || callee.type !== 'Identifier') return
30
+
31
+ const source = context.getSourceText()
32
+ const start = node.start as number
33
+
34
+ let i = start - 1
35
+ while (i >= 0 && source[i] !== '<' && source[i] !== '>') i--
36
+ if (i < 0 || source[i] !== '<') return
37
+
38
+ const tagStart = i + 1
39
+ let tagEnd = tagStart
40
+ while (tagEnd < source.length && /[\w.]/.test(source[tagEnd] ?? '')) tagEnd++
41
+ const tagName = source.slice(tagStart, tagEnd)
42
+
43
+ if (!tagName || !isComponentTag(tagName)) return
44
+
45
+ context.report({
46
+ message: `Signal call in <${tagName}> prop — use props.x pattern inside the component for reactive access.`,
47
+ span: getSpan(expr),
48
+ })
49
+ },
50
+ }
51
+ return callbacks
52
+ },
53
+ }
package/src/runner.ts CHANGED
@@ -138,8 +138,21 @@ export function lintFile(
138
138
  const visitor = new Visitor(mergeCallbacks(allCallbacks))
139
139
  visitor.visit(program)
140
140
 
141
- diagnostics.sort((a, b) => a.span.start - b.span.start)
142
- return { filePath, diagnostics }
141
+ // Filter suppressed diagnostics:
142
+ // // pyreon-lint-ignore — suppress all on next line
143
+ // // pyreon-lint-ignore rule-name — suppress specific rule on next line
144
+ const lines = sourceText.split('\n')
145
+ const filtered = diagnostics.filter((d) => {
146
+ const prevLineIdx = d.loc.line - 2
147
+ if (prevLineIdx < 0) return true
148
+ const prevLine = lines[prevLineIdx]?.trim()
149
+ if (!prevLine?.startsWith('// pyreon-lint-ignore')) return true
150
+ const rest = prevLine.slice('// pyreon-lint-ignore'.length).trim()
151
+ return rest.length > 0 && rest !== d.ruleId
152
+ })
153
+
154
+ filtered.sort((a, b) => a.span.start - b.span.start)
155
+ return { filePath, diagnostics: filtered }
143
156
  }
144
157
 
145
158
  /**
@@ -37,7 +37,7 @@ function lintWith(ruleId: string, source: string, filePath?: string) {
37
37
 
38
38
  describe('Rule metadata', () => {
39
39
  it('should have 56 rules', () => {
40
- expect(allRules.length).toBe(56)
40
+ expect(allRules.length).toBe(57)
41
41
  })
42
42
 
43
43
  it('should have unique rule IDs', () => {
@@ -77,7 +77,7 @@ describe('Rule metadata', () => {
77
77
  for (const rule of allRules) {
78
78
  counts[rule.meta.category] = (counts[rule.meta.category] ?? 0) + 1
79
79
  }
80
- expect(counts.reactivity).toBe(9)
80
+ expect(counts.reactivity).toBe(10)
81
81
  expect(counts.jsx).toBe(11)
82
82
  expect(counts.lifecycle).toBe(4)
83
83
  expect(counts.performance).toBe(4)
@@ -1013,7 +1013,7 @@ describe('Ignore filter', () => {
1013
1013
  describe('Presets', () => {
1014
1014
  it('recommended should include all rules', () => {
1015
1015
  const config = getPreset('recommended')
1016
- expect(Object.keys(config.rules).length).toBe(56)
1016
+ expect(Object.keys(config.rules).length).toBe(57)
1017
1017
  })
1018
1018
 
1019
1019
  it('strict should promote all warns to errors', () => {