@pyreon/lint 0.11.5 → 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 +1 -1
  3. package/lib/analysis/index.js.html +1 -1
  4. package/lib/cli.js +214 -1
  5. package/lib/cli.js.map +1 -1
  6. package/lib/index.js +207 -1
  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 +15 -15
  11. package/src/cache.ts +1 -1
  12. package/src/cli.ts +38 -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 -19
  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 -13
  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 +5 -5
  85. package/src/utils/source.ts +2 -2
  86. package/src/watcher.ts +19 -19
package/src/types.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // ── Severity & Diagnostics ──────────────────────────────────────────────────
2
2
 
3
- export type Severity = "error" | "warn" | "info" | "off"
3
+ export type Severity = 'error' | 'warn' | 'info' | 'off'
4
4
 
5
5
  export interface SourceLocation {
6
6
  line: number
@@ -29,18 +29,18 @@ export interface Diagnostic {
29
29
  // ── Rule Metadata ───────────────────────────────────────────────────────────
30
30
 
31
31
  export type RuleCategory =
32
- | "reactivity"
33
- | "jsx"
34
- | "lifecycle"
35
- | "performance"
36
- | "ssr"
37
- | "architecture"
38
- | "store"
39
- | "form"
40
- | "styling"
41
- | "hooks"
42
- | "accessibility"
43
- | "router"
32
+ | 'reactivity'
33
+ | 'jsx'
34
+ | 'lifecycle'
35
+ | 'performance'
36
+ | 'ssr'
37
+ | 'architecture'
38
+ | 'store'
39
+ | 'form'
40
+ | 'styling'
41
+ | 'hooks'
42
+ | 'accessibility'
43
+ | 'router'
44
44
 
45
45
  export interface RuleMeta {
46
46
  id: string
@@ -53,7 +53,7 @@ export interface RuleMeta {
53
53
  // ── Rule Context & Visitor ──────────────────────────────────────────────────
54
54
 
55
55
  export interface RuleContext {
56
- report(diagnostic: Omit<Diagnostic, "ruleId" | "severity" | "loc">): void
56
+ report(diagnostic: Omit<Diagnostic, 'ruleId' | 'severity' | 'loc'>): void
57
57
  getSourceText(): string
58
58
  getFilePath(): string
59
59
  }
@@ -86,7 +86,7 @@ export interface LintConfigFile {
86
86
  exclude?: string[] | undefined
87
87
  }
88
88
 
89
- export type PresetName = "recommended" | "strict" | "app" | "lib"
89
+ export type PresetName = 'recommended' | 'strict' | 'app' | 'lib'
90
90
 
91
91
  // ── Results ─────────────────────────────────────────────────────────────────
92
92
 
package/src/utils/ast.ts CHANGED
@@ -1,11 +1,11 @@
1
- import type { Span } from "../types"
2
- import { BROWSER_GLOBALS } from "./imports"
1
+ import type { Span } from '../types'
2
+ import { BROWSER_GLOBALS } from './imports'
3
3
 
4
4
  /** Check if a node is a call expression to a specific function name. */
5
5
  export function isCallTo(node: any, name: string): boolean {
6
6
  return (
7
- node.type === "CallExpression" &&
8
- node.callee?.type === "Identifier" &&
7
+ node.type === 'CallExpression' &&
8
+ node.callee?.type === 'Identifier' &&
9
9
  node.callee.name === name
10
10
  )
11
11
  }
@@ -13,8 +13,8 @@ export function isCallTo(node: any, name: string): boolean {
13
13
  /** Check if a node is a call expression to any of the given function names. */
14
14
  export function isCallToAny(node: any, names: Set<string>): boolean {
15
15
  return (
16
- node.type === "CallExpression" &&
17
- node.callee?.type === "Identifier" &&
16
+ node.type === 'CallExpression' &&
17
+ node.callee?.type === 'Identifier' &&
18
18
  names.has(node.callee.name)
19
19
  )
20
20
  }
@@ -22,29 +22,29 @@ export function isCallToAny(node: any, names: Set<string>): boolean {
22
22
  /** Check if a node is a member call like `obj.method()`. */
23
23
  export function isMemberCallTo(node: any, objectName: string, methodName: string): boolean {
24
24
  return (
25
- node.type === "CallExpression" &&
26
- node.callee?.type === "MemberExpression" &&
27
- node.callee.object?.type === "Identifier" &&
25
+ node.type === 'CallExpression' &&
26
+ node.callee?.type === 'MemberExpression' &&
27
+ node.callee.object?.type === 'Identifier' &&
28
28
  node.callee.object.name === objectName &&
29
- node.callee.property?.type === "Identifier" &&
29
+ node.callee.property?.type === 'Identifier' &&
30
30
  node.callee.property.name === methodName
31
31
  )
32
32
  }
33
33
 
34
34
  /** Check if a node is a JSX element (opening or self-closing). */
35
35
  export function isJSXElement(node: any): boolean {
36
- return node.type === "JSXElement" || node.type === "JSXFragment"
36
+ return node.type === 'JSXElement' || node.type === 'JSXFragment'
37
37
  }
38
38
 
39
39
  /** Get the tag name of a JSX element. */
40
40
  export function getJSXTagName(node: any): string | null {
41
- if (node.type === "JSXElement") {
41
+ if (node.type === 'JSXElement') {
42
42
  const opening = node.openingElement
43
43
  if (!opening) return null
44
44
  const name = opening.name
45
- if (name?.type === "JSXIdentifier") return name.name
46
- if (name?.type === "JSXMemberExpression") {
47
- return `${name.object?.name ?? ""}.${name.property?.name ?? ""}`
45
+ if (name?.type === 'JSXIdentifier') return name.name
46
+ if (name?.type === 'JSXMemberExpression') {
47
+ return `${name.object?.name ?? ''}.${name.property?.name ?? ''}`
48
48
  }
49
49
  }
50
50
  return null
@@ -55,8 +55,8 @@ export function getJSXAttribute(openingElement: any, attrName: string): any | nu
55
55
  const attrs = openingElement.attributes ?? []
56
56
  for (const attr of attrs) {
57
57
  if (
58
- attr.type === "JSXAttribute" &&
59
- attr.name?.type === "JSXIdentifier" &&
58
+ attr.type === 'JSXAttribute' &&
59
+ attr.name?.type === 'JSXIdentifier' &&
60
60
  attr.name.name === attrName
61
61
  ) {
62
62
  return attr
@@ -74,90 +74,90 @@ export function hasJSXAttribute(openingElement: any, attrName: string): boolean
74
74
  export function isInsideFunction(ancestors: any[]): boolean {
75
75
  return ancestors.some(
76
76
  (a) =>
77
- a.type === "FunctionDeclaration" ||
78
- a.type === "FunctionExpression" ||
79
- a.type === "ArrowFunctionExpression",
77
+ a.type === 'FunctionDeclaration' ||
78
+ a.type === 'FunctionExpression' ||
79
+ a.type === 'ArrowFunctionExpression',
80
80
  )
81
81
  }
82
82
 
83
83
  /** Check if a node is inside JSX. */
84
84
  export function isInsideJSX(ancestors: any[]): boolean {
85
- return ancestors.some((a) => a.type === "JSXElement" || a.type === "JSXFragment")
85
+ return ancestors.some((a) => a.type === 'JSXElement' || a.type === 'JSXFragment')
86
86
  }
87
87
 
88
88
  /** Check if a node is an array .map() call. */
89
89
  export function isArrayMapCall(node: any): boolean {
90
90
  return (
91
- node.type === "CallExpression" &&
92
- node.callee?.type === "MemberExpression" &&
93
- node.callee.property?.type === "Identifier" &&
94
- node.callee.property.name === "map"
91
+ node.type === 'CallExpression' &&
92
+ node.callee?.type === 'MemberExpression' &&
93
+ node.callee.property?.type === 'Identifier' &&
94
+ node.callee.property.name === 'map'
95
95
  )
96
96
  }
97
97
 
98
98
  /** Check if a node is a function expression or arrow function. */
99
99
  export function isFunction(node: any): boolean {
100
100
  return (
101
- node.type === "FunctionDeclaration" ||
102
- node.type === "FunctionExpression" ||
103
- node.type === "ArrowFunctionExpression"
101
+ node.type === 'FunctionDeclaration' ||
102
+ node.type === 'FunctionExpression' ||
103
+ node.type === 'ArrowFunctionExpression'
104
104
  )
105
105
  }
106
106
 
107
107
  /** Check if a node is a destructuring pattern. */
108
108
  export function isDestructuring(node: any): boolean {
109
- return node.type === "ObjectPattern" || node.type === "ArrayPattern"
109
+ return node.type === 'ObjectPattern' || node.type === 'ArrayPattern'
110
110
  }
111
111
 
112
112
  /** Check if a node is a ternary with JSX in either branch. */
113
113
  export function isTernaryWithJSX(node: any): boolean {
114
- if (node.type !== "ConditionalExpression") return false
114
+ if (node.type !== 'ConditionalExpression') return false
115
115
  return containsJSX(node.consequent) || containsJSX(node.alternate)
116
116
  }
117
117
 
118
118
  /** Check if a node contains JSX anywhere. */
119
119
  function containsJSX(node: any): boolean {
120
120
  if (!node) return false
121
- if (node.type === "JSXElement" || node.type === "JSXFragment") return true
122
- if (node.type === "ParenthesizedExpression") return containsJSX(node.expression)
121
+ if (node.type === 'JSXElement' || node.type === 'JSXFragment') return true
122
+ if (node.type === 'ParenthesizedExpression') return containsJSX(node.expression)
123
123
  return false
124
124
  }
125
125
 
126
126
  /** Check if a JSX element has JSX children. */
127
127
  export function hasJSXChild(node: any): boolean {
128
- if (node.type !== "JSXElement") return false
129
- return (node.children ?? []).some((c: any) => c.type === "JSXElement" || c.type === "JSXFragment")
128
+ if (node.type !== 'JSXElement') return false
129
+ return (node.children ?? []).some((c: any) => c.type === 'JSXElement' || c.type === 'JSXFragment')
130
130
  }
131
131
 
132
132
  /** Check if a node is a logical AND with JSX. */
133
133
  export function isLogicalAndWithJSX(node: any): boolean {
134
- if (node.type !== "LogicalExpression" || node.operator !== "&&") return false
134
+ if (node.type !== 'LogicalExpression' || node.operator !== '&&') return false
135
135
  return containsJSX(node.right)
136
136
  }
137
137
 
138
138
  /** Check if a node is a .peek() call. */
139
139
  export function isPeekCall(node: any): boolean {
140
140
  return (
141
- node.type === "CallExpression" &&
142
- node.callee?.type === "MemberExpression" &&
143
- node.callee.property?.type === "Identifier" &&
144
- node.callee.property.name === "peek"
141
+ node.type === 'CallExpression' &&
142
+ node.callee?.type === 'MemberExpression' &&
143
+ node.callee.property?.type === 'Identifier' &&
144
+ node.callee.property.name === 'peek'
145
145
  )
146
146
  }
147
147
 
148
148
  /** Check if a node is a .set() call. */
149
149
  export function isSetCall(node: any): boolean {
150
150
  return (
151
- node.type === "CallExpression" &&
152
- node.callee?.type === "MemberExpression" &&
153
- node.callee.property?.type === "Identifier" &&
154
- node.callee.property.name === "set"
151
+ node.type === 'CallExpression' &&
152
+ node.callee?.type === 'MemberExpression' &&
153
+ node.callee.property?.type === 'Identifier' &&
154
+ node.callee.property.name === 'set'
155
155
  )
156
156
  }
157
157
 
158
158
  /** Check if a node references a browser global. */
159
159
  export function isBrowserGlobal(node: any): boolean {
160
- return node.type === "Identifier" && BROWSER_GLOBALS.has(node.name)
160
+ return node.type === 'Identifier' && BROWSER_GLOBALS.has(node.name)
161
161
  }
162
162
 
163
163
  /** Get the span (byte offsets) of a node. */
@@ -168,7 +168,7 @@ export function getSpan(node: any): Span {
168
168
  /** Check if a node is inside a `if (__DEV__)` guard. */
169
169
  export function isInsideDevGuard(ancestors: any[]): boolean {
170
170
  return ancestors.some(
171
- (a) => a.type === "IfStatement" && a.test?.type === "Identifier" && a.test.name === "__DEV__",
171
+ (a) => a.type === 'IfStatement' && a.test?.type === 'Identifier' && a.test.name === '__DEV__',
172
172
  )
173
173
  }
174
174
 
@@ -176,7 +176,7 @@ export function isInsideDevGuard(ancestors: any[]): boolean {
176
176
  export function isInsideOnMount(ancestors: any[]): boolean {
177
177
  return ancestors.some(
178
178
  (a) =>
179
- a.type === "CallExpression" && a.callee?.type === "Identifier" && a.callee.name === "onMount",
179
+ a.type === 'CallExpression' && a.callee?.type === 'Identifier' && a.callee.name === 'onMount',
180
180
  )
181
181
  }
182
182
 
@@ -184,9 +184,9 @@ export function isInsideOnMount(ancestors: any[]): boolean {
184
184
  export function isInsideTypeofGuard(ancestors: any[]): boolean {
185
185
  return ancestors.some(
186
186
  (a) =>
187
- a.type === "IfStatement" &&
188
- a.test?.type === "BinaryExpression" &&
189
- a.test.left?.type === "UnaryExpression" &&
190
- a.test.left.operator === "typeof",
187
+ a.type === 'IfStatement' &&
188
+ a.test?.type === 'BinaryExpression' &&
189
+ a.test.left?.type === 'UnaryExpression' &&
190
+ a.test.left.operator === 'typeof',
191
191
  )
192
192
  }
@@ -1,65 +1,65 @@
1
- import type { ImportInfo } from "../types"
1
+ import type { ImportInfo } from '../types'
2
2
 
3
3
  export type { ImportInfo }
4
4
 
5
5
  // ── Constants ───────────────────────────────────────────────────────────────
6
6
 
7
- export const PYREON_PREFIX = "@pyreon/"
7
+ export const PYREON_PREFIX = '@pyreon/'
8
8
 
9
9
  export const REACTIVITY_APIS = new Set([
10
- "signal",
11
- "computed",
12
- "effect",
13
- "batch",
14
- "onCleanup",
15
- "createSelector",
16
- "createStore",
17
- "untrack",
10
+ 'signal',
11
+ 'computed',
12
+ 'effect',
13
+ 'batch',
14
+ 'onCleanup',
15
+ 'createSelector',
16
+ 'createStore',
17
+ 'untrack',
18
18
  ])
19
19
 
20
- export const LIFECYCLE_APIS = new Set(["onMount", "onUnmount"])
20
+ export const LIFECYCLE_APIS = new Set(['onMount', 'onUnmount'])
21
21
 
22
- export const CONTEXT_APIS = new Set(["createContext", "provide", "pushContext", "popContext"])
22
+ export const CONTEXT_APIS = new Set(['createContext', 'provide', 'pushContext', 'popContext'])
23
23
 
24
24
  export const JSX_COMPONENTS = new Set([
25
- "For",
26
- "Show",
27
- "Switch",
28
- "Match",
29
- "Dynamic",
30
- "ErrorBoundary",
31
- "Suspense",
32
- "Portal",
25
+ 'For',
26
+ 'Show',
27
+ 'Switch',
28
+ 'Match',
29
+ 'Dynamic',
30
+ 'ErrorBoundary',
31
+ 'Suspense',
32
+ 'Portal',
33
33
  ])
34
34
 
35
35
  export const HEAVY_PACKAGES = new Set([
36
- "@pyreon/charts",
37
- "@pyreon/code",
38
- "@pyreon/document",
39
- "@pyreon/flow",
36
+ '@pyreon/charts',
37
+ '@pyreon/code',
38
+ '@pyreon/document',
39
+ '@pyreon/flow',
40
40
  ])
41
41
 
42
42
  export const BROWSER_GLOBALS = new Set([
43
- "window",
44
- "document",
45
- "navigator",
46
- "location",
47
- "history",
48
- "localStorage",
49
- "sessionStorage",
50
- "indexedDB",
51
- "fetch",
52
- "XMLHttpRequest",
53
- "WebSocket",
54
- "requestAnimationFrame",
55
- "cancelAnimationFrame",
56
- "IntersectionObserver",
57
- "MutationObserver",
58
- "ResizeObserver",
59
- "matchMedia",
60
- "getComputedStyle",
61
- "addEventListener",
62
- "removeEventListener",
43
+ 'window',
44
+ 'document',
45
+ 'navigator',
46
+ 'location',
47
+ 'history',
48
+ 'localStorage',
49
+ 'sessionStorage',
50
+ 'indexedDB',
51
+ 'fetch',
52
+ 'XMLHttpRequest',
53
+ 'WebSocket',
54
+ 'requestAnimationFrame',
55
+ 'cancelAnimationFrame',
56
+ 'IntersectionObserver',
57
+ 'MutationObserver',
58
+ 'ResizeObserver',
59
+ 'matchMedia',
60
+ 'getComputedStyle',
61
+ 'addEventListener',
62
+ 'removeEventListener',
63
63
  ])
64
64
 
65
65
  // ── Functions ───────────────────────────────────────────────────────────────
@@ -73,26 +73,26 @@ export function isPyreonPackage(source: string): boolean {
73
73
  }
74
74
 
75
75
  export function extractImportInfo(node: any): ImportInfo | null {
76
- if (node.type !== "ImportDeclaration") return null
76
+ if (node.type !== 'ImportDeclaration') return null
77
77
 
78
78
  const source = node.source?.value as string
79
79
  if (!source) return null
80
80
 
81
- const specifiers: ImportInfo["specifiers"] = []
81
+ const specifiers: ImportInfo['specifiers'] = []
82
82
  let isDefault = false
83
83
  let isNamespace = false
84
84
 
85
85
  for (const spec of node.specifiers ?? []) {
86
- if (spec.type === "ImportDefaultSpecifier") {
86
+ if (spec.type === 'ImportDefaultSpecifier') {
87
87
  isDefault = true
88
- specifiers.push({ imported: "default", local: spec.local?.name ?? "" })
89
- } else if (spec.type === "ImportNamespaceSpecifier") {
88
+ specifiers.push({ imported: 'default', local: spec.local?.name ?? '' })
89
+ } else if (spec.type === 'ImportNamespaceSpecifier') {
90
90
  isNamespace = true
91
- specifiers.push({ imported: "*", local: spec.local?.name ?? "" })
92
- } else if (spec.type === "ImportSpecifier") {
91
+ specifiers.push({ imported: '*', local: spec.local?.name ?? '' })
92
+ } else if (spec.type === 'ImportSpecifier') {
93
93
  const imported =
94
- spec.imported?.type === "Identifier" ? spec.imported.name : (spec.imported?.value ?? "")
95
- specifiers.push({ imported, local: spec.local?.name ?? "" })
94
+ spec.imported?.type === 'Identifier' ? spec.imported.name : (spec.imported?.value ?? '')
95
+ specifiers.push({ imported, local: spec.local?.name ?? '' })
96
96
  }
97
97
  }
98
98
 
@@ -21,7 +21,7 @@ export {
21
21
  isPeekCall,
22
22
  isSetCall,
23
23
  isTernaryWithJSX,
24
- } from "./ast"
24
+ } from './ast'
25
25
  export {
26
26
  BROWSER_GLOBALS,
27
27
  CONTEXT_APIS,
@@ -35,14 +35,14 @@ export {
35
35
  LIFECYCLE_APIS,
36
36
  PYREON_PREFIX,
37
37
  REACTIVITY_APIS,
38
- } from "./imports"
39
- export { LineIndex } from "./source"
38
+ } from './imports'
39
+ export { LineIndex } from './source'
40
40
 
41
41
  /** Supported JS/TS file extensions for linting. */
42
- export const JS_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".mts", ".mjs"])
42
+ export const JS_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mts', '.mjs'])
43
43
 
44
44
  /** Check if a file path has a supported JS/TS extension. */
45
45
  export function hasJsExtension(filePath: string): boolean {
46
- const ext = filePath.slice(filePath.lastIndexOf("."))
46
+ const ext = filePath.slice(filePath.lastIndexOf('.'))
47
47
  return JS_EXTENSIONS.has(ext)
48
48
  }
@@ -1,4 +1,4 @@
1
- import type { SourceLocation } from "../types"
1
+ import type { SourceLocation } from '../types'
2
2
 
3
3
  /**
4
4
  * Fast offset→line/column conversion using binary search over precomputed line starts.
@@ -9,7 +9,7 @@ export class LineIndex {
9
9
  constructor(sourceText: string) {
10
10
  this.lineStarts = [0]
11
11
  for (let i = 0; i < sourceText.length; i++) {
12
- if (sourceText[i] === "\n") {
12
+ if (sourceText[i] === '\n') {
13
13
  this.lineStarts.push(i + 1)
14
14
  }
15
15
  }
package/src/watcher.ts CHANGED
@@ -1,17 +1,17 @@
1
- import { readFileSync, watch } from "node:fs"
2
- import { resolve } from "node:path"
3
- import { AstCache } from "./cache"
4
- import { createIgnoreFilter } from "./config/ignore"
5
- import { getPreset } from "./config/presets"
6
- import { formatCompact, formatJSON, formatText } from "./reporter"
7
- import { allRules } from "./rules/index"
8
- import { lintFile } from "./runner"
9
- import type { LintConfig, LintOptions, LintResult, Severity } from "./types"
10
- import { hasJsExtension } from "./utils/index"
1
+ import { readFileSync, watch } from 'node:fs'
2
+ import { resolve } from 'node:path'
3
+ import { AstCache } from './cache'
4
+ import { createIgnoreFilter } from './config/ignore'
5
+ import { getPreset } from './config/presets'
6
+ import { formatCompact, formatJSON, formatText } from './reporter'
7
+ import { allRules } from './rules/index'
8
+ import { lintFile } from './runner'
9
+ import type { LintConfig, LintOptions, LintResult, Severity } from './types'
10
+ import { hasJsExtension } from './utils/index'
11
11
 
12
12
  function formatOutput(result: LintResult, format: string): string {
13
- if (format === "json") return formatJSON(result)
14
- if (format === "compact") return formatCompact(result)
13
+ if (format === 'json') return formatJSON(result)
14
+ if (format === 'compact') return formatCompact(result)
15
15
  return formatText(result)
16
16
  }
17
17
 
@@ -30,12 +30,12 @@ function formatOutput(result: LintResult, format: string): string {
30
30
  */
31
31
  export function watchAndLint(options: LintOptions & { format: string }): void {
32
32
  const cache = new AstCache()
33
- const preset = options.preset ?? "recommended"
33
+ const preset = options.preset ?? 'recommended'
34
34
  const config = getPreset(preset)
35
35
 
36
36
  applyOverrides(config, options.ruleOverrides)
37
37
 
38
- const cwd = resolve(".")
38
+ const cwd = resolve('.')
39
39
  const isIgnored = createIgnoreFilter(cwd, options.ignore)
40
40
 
41
41
  // Debounce map: filePath -> timeout
@@ -84,7 +84,7 @@ function applyOverrides(
84
84
  function relintFile(filePath: string, config: LintConfig, cache: AstCache, format: string): void {
85
85
  let source: string
86
86
  try {
87
- source = readFileSync(filePath, "utf-8")
87
+ source = readFileSync(filePath, 'utf-8')
88
88
  } catch {
89
89
  return
90
90
  }
@@ -101,12 +101,12 @@ function relintFile(filePath: string, config: LintConfig, cache: AstCache, forma
101
101
  }
102
102
 
103
103
  for (const d of fileResult.diagnostics) {
104
- if (d.severity === "error") result.totalErrors++
105
- else if (d.severity === "warn") result.totalWarnings++
106
- else if (d.severity === "info") result.totalInfos++
104
+ if (d.severity === 'error') result.totalErrors++
105
+ else if (d.severity === 'warn') result.totalWarnings++
106
+ else if (d.severity === 'info') result.totalInfos++
107
107
  }
108
108
 
109
109
  // Clear screen and print
110
- process.stdout.write("\x1b[2J\x1b[H")
110
+ process.stdout.write('\x1b[2J\x1b[H')
111
111
  console.log(formatOutput(result, format))
112
112
  }