@pyreon/lint 0.12.9 → 0.12.11
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/lib/analysis/cli.js.html +1 -1
- package/lib/analysis/index.js.html +1 -1
- package/lib/cli.js +133 -1
- package/lib/cli.js.map +1 -1
- package/lib/index.js +133 -1
- package/lib/index.js.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/config/presets.ts +4 -0
- package/src/rules/architecture/no-process-dev-gate.ts +183 -0
- package/src/rules/index.ts +4 -1
- package/src/tests/runner.test.ts +273 -4
package/lib/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":[],"sources":["../src/cache.ts","../src/config/ignore.ts","../src/config/loader.ts","../src/utils/imports.ts","../src/utils/ast.ts","../src/rules/accessibility/dialog-a11y.ts","../src/rules/accessibility/overlay-a11y.ts","../src/rules/accessibility/toast-a11y.ts","../src/rules/architecture/dev-guard-warnings.ts","../src/rules/architecture/no-circular-import.ts","../src/rules/architecture/no-cross-layer-import.ts","../src/rules/architecture/no-deep-import.ts","../src/rules/architecture/no-error-without-prefix.ts","../src/rules/form/no-submit-without-validation.ts","../src/rules/form/no-unregistered-field.ts","../src/rules/form/prefer-field-array.ts","../src/rules/hooks/no-raw-addeventlistener.ts","../src/rules/hooks/no-raw-localstorage.ts","../src/rules/hooks/no-raw-setinterval.ts","../src/rules/jsx/no-and-conditional.ts","../src/rules/jsx/no-children-access.ts","../src/rules/jsx/no-classname.ts","../src/rules/jsx/no-htmlfor.ts","../src/rules/jsx/no-index-as-by.ts","../src/rules/jsx/no-map-in-jsx.ts","../src/rules/jsx/no-missing-for-by.ts","../src/rules/jsx/no-onchange.ts","../src/rules/jsx/no-props-destructure.ts","../src/rules/jsx/no-ternary-conditional.ts","../src/rules/jsx/use-by-not-key.ts","../src/rules/lifecycle/no-dom-in-setup.ts","../src/rules/lifecycle/no-effect-in-mount.ts","../src/rules/lifecycle/no-missing-cleanup.ts","../src/rules/lifecycle/no-mount-in-effect.ts","../src/rules/performance/no-eager-import.ts","../src/rules/performance/no-effect-in-for.ts","../src/rules/performance/no-large-for-without-by.ts","../src/rules/performance/prefer-show-over-display.ts","../src/rules/reactivity/no-bare-signal-in-jsx.ts","../src/rules/reactivity/no-context-destructure.ts","../src/rules/reactivity/no-effect-assignment.ts","../src/rules/reactivity/no-nested-effect.ts","../src/rules/reactivity/no-peek-in-tracked.ts","../src/rules/reactivity/no-signal-in-loop.ts","../src/rules/reactivity/no-signal-in-props.ts","../src/rules/reactivity/no-signal-leak.ts","../src/rules/reactivity/no-unbatched-updates.ts","../src/rules/reactivity/prefer-computed.ts","../src/rules/router/no-href-navigation.ts","../src/rules/router/no-imperative-navigate-in-render.ts","../src/rules/router/no-missing-fallback.ts","../src/rules/router/prefer-use-is-active.ts","../src/rules/ssr/no-mismatch-risk.ts","../src/rules/ssr/no-window-in-ssr.ts","../src/rules/ssr/prefer-request-context.ts","../src/rules/store/no-duplicate-store-id.ts","../src/rules/store/no-mutate-store-state.ts","../src/rules/store/no-store-outside-provider.ts","../src/rules/styling/no-dynamic-styled.ts","../src/rules/styling/no-inline-style-object.ts","../src/rules/styling/no-theme-outside-provider.ts","../src/rules/styling/prefer-cx.ts","../src/rules/index.ts","../src/config/presets.ts","../src/utils/source.ts","../src/utils/index.ts","../src/runner.ts","../src/lint.ts","../src/lsp/index.ts","../src/reporter.ts","../src/watcher.ts","../src/cli.ts"],"sourcesContent":["import type { LineIndex } from './utils/source'\n\n/**\n * Simple in-memory cache for parsed ASTs keyed by file content hash.\n *\n * Uses FNV-1a hash of source text as cache key for fast lookups\n * during repeat runs (e.g., watch mode).\n *\n * @example\n * ```ts\n * import { AstCache } from \"@pyreon/lint\"\n *\n * const cache = new AstCache()\n * const cached = cache.get(sourceText)\n * if (!cached) {\n * const parsed = parse(sourceText)\n * cache.set(sourceText, parsed)\n * }\n * ```\n */\nexport class AstCache {\n private cache = new Map<string, { program: any; lineIndex: LineIndex }>()\n\n get(sourceText: string): { program: any; lineIndex: LineIndex } | undefined {\n const key = fnv1aHash(sourceText)\n return this.cache.get(key)\n }\n\n set(sourceText: string, value: { program: any; lineIndex: LineIndex }): void {\n const key = fnv1aHash(sourceText)\n this.cache.set(key, value)\n }\n\n clear(): void {\n this.cache.clear()\n }\n\n get size(): number {\n return this.cache.size\n }\n}\n\n/** FNV-1a hash — fast, non-cryptographic, low collision rate. */\nfunction fnv1aHash(str: string): string {\n let hash = 0x811c9dc5 // FNV offset basis\n for (let i = 0; i < str.length; i++) {\n hash ^= str.charCodeAt(i)\n hash = (hash * 0x01000193) | 0 // FNV prime, keep 32-bit\n }\n return (hash >>> 0).toString(36)\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join, relative, resolve } from 'node:path'\n\n/**\n * Create a filter function that returns true if a file path should be ignored.\n *\n * Loads patterns from `.pyreonlintignore` and `.gitignore` in the given directory.\n *\n * @example\n * ```ts\n * import { createIgnoreFilter } from \"@pyreon/lint\"\n *\n * const isIgnored = createIgnoreFilter(process.cwd())\n * if (!isIgnored(\"src/app.tsx\")) lintFile(...)\n * ```\n */\nexport function createIgnoreFilter(\n cwd: string,\n extraIgnore?: string | undefined,\n): (filePath: string) => boolean {\n const patterns: string[] = []\n const resolvedCwd = resolve(cwd)\n\n // Load .pyreonlintignore\n loadPatternsFromFile(join(resolvedCwd, '.pyreonlintignore'), patterns)\n\n // Load .gitignore\n loadPatternsFromFile(join(resolvedCwd, '.gitignore'), patterns)\n\n // Load extra ignore file if provided\n if (extraIgnore) {\n loadPatternsFromFile(resolve(extraIgnore), patterns)\n }\n\n // Compile patterns into matchers\n const matchers = patterns.map((p) => compileMatcher(p))\n\n return (filePath: string): boolean => {\n const rel = relative(resolvedCwd, resolve(filePath))\n // Normalize to forward slashes\n const normalized = rel.replace(/\\\\/g, '/')\n\n for (const matcher of matchers) {\n if (matcher(normalized)) return true\n }\n return false\n }\n}\n\nfunction loadPatternsFromFile(filePath: string, patterns: string[]): void {\n if (!existsSync(filePath)) return\n try {\n const content = readFileSync(filePath, 'utf-8')\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n // Skip empty lines and comments\n if (!trimmed || trimmed.startsWith('#')) continue\n patterns.push(trimmed)\n }\n } catch {\n // Ignore read errors\n }\n}\n\n/**\n * Compile a gitignore-style pattern into a matcher function.\n * Supports: `*` (any non-slash chars), `**` (any path segment), `?` (single char),\n * leading `/` (root-anchored), trailing `/` (directory only).\n */\nfunction compileMatcher(pattern: string): (path: string) => boolean {\n let p = pattern\n let anchored = false\n\n // Negated patterns (not supported — just skip them)\n if (p.startsWith('!')) {\n return () => false\n }\n\n // Leading slash means anchored to root\n if (p.startsWith('/')) {\n anchored = true\n p = p.slice(1)\n }\n\n // Trailing slash means only match directories (we treat all paths as files, so strip it\n // and match as a prefix)\n let dirOnly = false\n if (p.endsWith('/')) {\n dirOnly = true\n p = p.slice(0, -1)\n }\n\n const regex = globToRegex(p)\n\n return (path: string): boolean => {\n if (dirOnly) {\n // Match as prefix: the pattern should match a directory portion\n if (anchored) {\n return regex.test(path) || path.startsWith(`${p}/`) || path === p\n }\n // Unanchored directory pattern — match anywhere in path\n return regex.test(path) || path.includes(`/${p}/`) || path.startsWith(`${p}/`) || path === p\n }\n\n if (anchored) {\n return regex.test(path)\n }\n\n // Unanchored pattern — try matching the full path, or just the basename\n if (regex.test(path)) return true\n\n // Also try matching against just the filename\n const lastSlash = path.lastIndexOf('/')\n if (lastSlash !== -1) {\n const basename = path.slice(lastSlash + 1)\n return regex.test(basename)\n }\n\n return false\n }\n}\n\nconst GLOB_CHAR_MAP: Record<string, string> = {\n '?': '[^/]',\n '.': '\\\\.',\n '/': '/',\n}\n\nfunction handleStar(glob: string, pos: number): { pattern: string; advance: number } {\n if (glob[pos + 1] === '*') {\n if (glob[pos + 2] === '/') return { pattern: '(?:.*/)?', advance: 3 }\n return { pattern: '.*', advance: 2 }\n }\n return { pattern: '[^/]*', advance: 1 }\n}\n\nfunction globToRegex(glob: string): RegExp {\n let result = '^'\n let i = 0\n\n while (i < glob.length) {\n const ch = glob[i] as string\n if (ch === '*') {\n const star = handleStar(glob, i)\n result += star.pattern\n i += star.advance\n } else {\n result += GLOB_CHAR_MAP[ch] ?? escapeRegex(ch)\n i++\n }\n }\n\n result += '$'\n return new RegExp(result)\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[\\\\^$+{}[\\]|()]/g, '\\\\$&')\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { dirname, join, resolve } from 'node:path'\nimport type { LintConfigFile } from '../types'\n\nconst CONFIG_FILENAMES = ['.pyreonlintrc.json', '.pyreonlintrc', 'pyreonlint.config.json']\n\n/**\n * Load a lint config file from the given directory or its parents.\n *\n * Search order:\n * 1. `.pyreonlintrc.json`\n * 2. `.pyreonlintrc`\n * 3. `pyreonlint.config.json`\n * 4. `package.json` `\"pyreonlint\"` field\n *\n * @example\n * ```ts\n * import { loadConfig } from \"@pyreon/lint\"\n *\n * const config = loadConfig(process.cwd())\n * if (config) console.log(config.preset)\n * ```\n */\nexport function loadConfig(cwd: string): LintConfigFile | null {\n let dir = resolve(cwd)\n const root = dirname(dir)\n\n while (true) {\n const found = searchDirectory(dir)\n if (found !== null) return found\n\n const parent = dirname(dir)\n if (parent === dir || parent === root) break\n dir = parent\n }\n\n return null\n}\n\nfunction searchDirectory(dir: string): LintConfigFile | null {\n for (const filename of CONFIG_FILENAMES) {\n const content = tryReadJson(join(dir, filename))\n if (content !== null) return content\n }\n return extractPkgConfig(join(dir, 'package.json'))\n}\n\nfunction extractPkgConfig(pkgPath: string): LintConfigFile | null {\n const pkg = tryReadJson(pkgPath)\n if (pkg === null || typeof pkg !== 'object' || !('pyreonlint' in pkg)) return null\n const field = (pkg as Record<string, unknown>).pyreonlint\n if (field && typeof field === 'object') return field as LintConfigFile\n return null\n}\n\n/**\n * Load a config file from a specific path.\n */\nexport function loadConfigFromPath(filePath: string): LintConfigFile | null {\n return tryReadJson(resolve(filePath))\n}\n\nfunction tryReadJson(filePath: string): any | null {\n if (!existsSync(filePath)) return null\n try {\n const raw = readFileSync(filePath, 'utf-8').trim()\n if (!raw) return null\n return JSON.parse(raw)\n } catch {\n return null\n }\n}\n","import type { ImportInfo } from '../types'\n\nexport type { ImportInfo }\n\n// ── Constants ───────────────────────────────────────────────────────────────\n\nexport const PYREON_PREFIX = '@pyreon/'\n\nexport const REACTIVITY_APIS = new Set([\n 'signal',\n 'computed',\n 'effect',\n 'batch',\n 'onCleanup',\n 'createSelector',\n 'createStore',\n 'untrack',\n])\n\nexport const LIFECYCLE_APIS = new Set(['onMount', 'onUnmount'])\n\nexport const CONTEXT_APIS = new Set(['createContext', 'provide', 'pushContext', 'popContext'])\n\nexport const JSX_COMPONENTS = new Set([\n 'For',\n 'Show',\n 'Switch',\n 'Match',\n 'Dynamic',\n 'ErrorBoundary',\n 'Suspense',\n 'Portal',\n])\n\nexport const HEAVY_PACKAGES = new Set([\n '@pyreon/charts',\n '@pyreon/code',\n '@pyreon/document',\n '@pyreon/flow',\n])\n\nexport const BROWSER_GLOBALS = new Set([\n 'window',\n 'document',\n 'navigator',\n 'location',\n 'history',\n 'localStorage',\n 'sessionStorage',\n 'indexedDB',\n 'fetch',\n 'XMLHttpRequest',\n 'WebSocket',\n 'requestAnimationFrame',\n 'cancelAnimationFrame',\n 'IntersectionObserver',\n 'MutationObserver',\n 'ResizeObserver',\n 'matchMedia',\n 'getComputedStyle',\n 'addEventListener',\n 'removeEventListener',\n])\n\n// ── Functions ───────────────────────────────────────────────────────────────\n\nexport function isPyreonImport(source: string): boolean {\n return source.startsWith(PYREON_PREFIX)\n}\n\nexport function isPyreonPackage(source: string): boolean {\n return source.startsWith(PYREON_PREFIX)\n}\n\nexport function extractImportInfo(node: any): ImportInfo | null {\n if (node.type !== 'ImportDeclaration') return null\n\n const source = node.source?.value as string\n if (!source) return null\n\n const specifiers: ImportInfo['specifiers'] = []\n let isDefault = false\n let isNamespace = false\n\n for (const spec of node.specifiers ?? []) {\n if (spec.type === 'ImportDefaultSpecifier') {\n isDefault = true\n specifiers.push({ imported: 'default', local: spec.local?.name ?? '' })\n } else if (spec.type === 'ImportNamespaceSpecifier') {\n isNamespace = true\n specifiers.push({ imported: '*', local: spec.local?.name ?? '' })\n } else if (spec.type === 'ImportSpecifier') {\n const imported =\n spec.imported?.type === 'Identifier' ? spec.imported.name : (spec.imported?.value ?? '')\n specifiers.push({ imported, local: spec.local?.name ?? '' })\n }\n }\n\n return { source, specifiers, isDefault, isNamespace }\n}\n\nexport function importsName(imports: ImportInfo[], name: string, fromPackage?: string): boolean {\n return imports.some(\n (imp) =>\n (!fromPackage || imp.source === fromPackage) &&\n imp.specifiers.some((s) => s.imported === name),\n )\n}\n\nexport function getLocalName(\n imports: ImportInfo[],\n name: string,\n fromPackage?: string,\n): string | null {\n for (const imp of imports) {\n if (fromPackage && imp.source !== fromPackage) continue\n for (const s of imp.specifiers) {\n if (s.imported === name) return s.local\n }\n }\n return null\n}\n","import type { Span } from '../types'\nimport { BROWSER_GLOBALS } from './imports'\n\n/** Check if a node is a call expression to a specific function name. */\nexport function isCallTo(node: any, name: string): boolean {\n return (\n node.type === 'CallExpression' &&\n node.callee?.type === 'Identifier' &&\n node.callee.name === name\n )\n}\n\n/** Check if a node is a call expression to any of the given function names. */\nexport function isCallToAny(node: any, names: Set<string>): boolean {\n return (\n node.type === 'CallExpression' &&\n node.callee?.type === 'Identifier' &&\n names.has(node.callee.name)\n )\n}\n\n/** Check if a node is a member call like `obj.method()`. */\nexport function isMemberCallTo(node: any, objectName: string, methodName: string): boolean {\n return (\n node.type === 'CallExpression' &&\n node.callee?.type === 'MemberExpression' &&\n node.callee.object?.type === 'Identifier' &&\n node.callee.object.name === objectName &&\n node.callee.property?.type === 'Identifier' &&\n node.callee.property.name === methodName\n )\n}\n\n/** Check if a node is a JSX element (opening or self-closing). */\nexport function isJSXElement(node: any): boolean {\n return node.type === 'JSXElement' || node.type === 'JSXFragment'\n}\n\n/** Get the tag name of a JSX element. */\nexport function getJSXTagName(node: any): string | null {\n if (node.type === 'JSXElement') {\n const opening = node.openingElement\n if (!opening) return null\n const name = opening.name\n if (name?.type === 'JSXIdentifier') return name.name\n if (name?.type === 'JSXMemberExpression') {\n return `${name.object?.name ?? ''}.${name.property?.name ?? ''}`\n }\n }\n return null\n}\n\n/** Get a JSX attribute by name from an opening element. */\nexport function getJSXAttribute(openingElement: any, attrName: string): any | null {\n const attrs = openingElement.attributes ?? []\n for (const attr of attrs) {\n if (\n attr.type === 'JSXAttribute' &&\n attr.name?.type === 'JSXIdentifier' &&\n attr.name.name === attrName\n ) {\n return attr\n }\n }\n return null\n}\n\n/** Check if a JSX opening element has an attribute. */\nexport function hasJSXAttribute(openingElement: any, attrName: string): boolean {\n return getJSXAttribute(openingElement, attrName) !== null\n}\n\n/** Check if a node is inside a function (arrow or regular). */\nexport function isInsideFunction(ancestors: any[]): boolean {\n return ancestors.some(\n (a) =>\n a.type === 'FunctionDeclaration' ||\n a.type === 'FunctionExpression' ||\n a.type === 'ArrowFunctionExpression',\n )\n}\n\n/** Check if a node is inside JSX. */\nexport function isInsideJSX(ancestors: any[]): boolean {\n return ancestors.some((a) => a.type === 'JSXElement' || a.type === 'JSXFragment')\n}\n\n/** Check if a node is an array .map() call. */\nexport function isArrayMapCall(node: any): boolean {\n return (\n node.type === 'CallExpression' &&\n node.callee?.type === 'MemberExpression' &&\n node.callee.property?.type === 'Identifier' &&\n node.callee.property.name === 'map'\n )\n}\n\n/** Check if a node is a function expression or arrow function. */\nexport function isFunction(node: any): boolean {\n return (\n node.type === 'FunctionDeclaration' ||\n node.type === 'FunctionExpression' ||\n node.type === 'ArrowFunctionExpression'\n )\n}\n\n/** Check if a node is a destructuring pattern. */\nexport function isDestructuring(node: any): boolean {\n return node.type === 'ObjectPattern' || node.type === 'ArrayPattern'\n}\n\n/** Check if a node is a ternary with JSX in either branch. */\nexport function isTernaryWithJSX(node: any): boolean {\n if (node.type !== 'ConditionalExpression') return false\n return containsJSX(node.consequent) || containsJSX(node.alternate)\n}\n\n/** Check if a node contains JSX anywhere. */\nfunction containsJSX(node: any): boolean {\n if (!node) return false\n if (node.type === 'JSXElement' || node.type === 'JSXFragment') return true\n if (node.type === 'ParenthesizedExpression') return containsJSX(node.expression)\n return false\n}\n\n/** Check if a JSX element has JSX children. */\nexport function hasJSXChild(node: any): boolean {\n if (node.type !== 'JSXElement') return false\n return (node.children ?? []).some((c: any) => c.type === 'JSXElement' || c.type === 'JSXFragment')\n}\n\n/** Check if a node is a logical AND with JSX. */\nexport function isLogicalAndWithJSX(node: any): boolean {\n if (node.type !== 'LogicalExpression' || node.operator !== '&&') return false\n return containsJSX(node.right)\n}\n\n/** Check if a node is a .peek() call. */\nexport function isPeekCall(node: any): boolean {\n return (\n node.type === 'CallExpression' &&\n node.callee?.type === 'MemberExpression' &&\n node.callee.property?.type === 'Identifier' &&\n node.callee.property.name === 'peek'\n )\n}\n\n/** Check if a node is a .set() call. */\nexport function isSetCall(node: any): boolean {\n return (\n node.type === 'CallExpression' &&\n node.callee?.type === 'MemberExpression' &&\n node.callee.property?.type === 'Identifier' &&\n node.callee.property.name === 'set'\n )\n}\n\n/** Check if a node references a browser global. */\nexport function isBrowserGlobal(node: any): boolean {\n return node.type === 'Identifier' && BROWSER_GLOBALS.has(node.name)\n}\n\n/** Get the span (byte offsets) of a node. */\nexport function getSpan(node: any): Span {\n return { start: node.start as number, end: node.end as number }\n}\n\n/** Check if a node is inside a `if (__DEV__)` guard. */\nexport function isInsideDevGuard(ancestors: any[]): boolean {\n return ancestors.some(\n (a) => a.type === 'IfStatement' && a.test?.type === 'Identifier' && a.test.name === '__DEV__',\n )\n}\n\n/** Check if a node is inside an onMount callback. */\nexport function isInsideOnMount(ancestors: any[]): boolean {\n return ancestors.some(\n (a) =>\n a.type === 'CallExpression' && a.callee?.type === 'Identifier' && a.callee.name === 'onMount',\n )\n}\n\n/** Check if a node is inside a typeof guard (e.g., `typeof window !== \"undefined\"`). */\nexport function isInsideTypeofGuard(ancestors: any[]): boolean {\n return ancestors.some(\n (a) =>\n a.type === 'IfStatement' &&\n a.test?.type === 'BinaryExpression' &&\n a.test.left?.type === 'UnaryExpression' &&\n a.test.left.operator === 'typeof',\n )\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, hasJSXAttribute } from '../../utils/ast'\n\nexport const dialogA11y: Rule = {\n meta: {\n id: 'pyreon/dialog-a11y',\n category: 'accessibility',\n description: 'Warn when <dialog> is missing aria-label or aria-labelledby.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const name = node.name\n if (!name || name.type !== 'JSXIdentifier' || name.name !== 'dialog') return\n\n const hasLabel = hasJSXAttribute(node, 'aria-label')\n const hasLabelledBy = hasJSXAttribute(node, 'aria-labelledby')\n\n if (!hasLabel && !hasLabelledBy) {\n context.report({\n message:\n '`<dialog>` missing `aria-label` or `aria-labelledby` — provide an accessible label for screen readers.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, hasJSXAttribute } from '../../utils/ast'\n\nexport const overlayA11y: Rule = {\n meta: {\n id: 'pyreon/overlay-a11y',\n category: 'accessibility',\n description: 'Warn when <Overlay> is missing role, aria-label, or aria-labelledby.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const name = node.name\n if (!name || name.type !== 'JSXIdentifier' || name.name !== 'Overlay') return\n\n const hasRole = hasJSXAttribute(node, 'role')\n const hasLabel = hasJSXAttribute(node, 'aria-label')\n const hasLabelledBy = hasJSXAttribute(node, 'aria-labelledby')\n\n if (!hasRole && !hasLabel && !hasLabelledBy) {\n context.report({\n message:\n '`<Overlay>` missing `role`, `aria-label`, or `aria-labelledby` — provide accessibility attributes for screen readers.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, hasJSXAttribute } from '../../utils/ast'\n\nexport const toastA11y: Rule = {\n meta: {\n id: 'pyreon/toast-a11y',\n category: 'accessibility',\n description: 'Warn when toast-like components are missing role or aria-live attributes.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const name = node.name\n if (!name || name.type !== 'JSXIdentifier') return\n\n const tagName: string = name.name\n // Skip non-PascalCase and the Toaster container itself\n if (tagName === 'Toaster') return\n const firstChar = tagName[0]\n if (!firstChar || firstChar !== firstChar.toUpperCase()) return\n if (!tagName.toLowerCase().includes('toast')) return\n\n const hasRole = hasJSXAttribute(node, 'role')\n const hasAriaLive = hasJSXAttribute(node, 'aria-live')\n\n if (!hasRole && !hasAriaLive) {\n context.report({\n message: `Toast component \\`<${tagName}>\\` missing \\`role\\` or \\`aria-live\\` — add \\`role=\"alert\"\\` and \\`aria-live=\"polite\"\\` for screen reader accessibility.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const devGuardWarnings: Rule = {\n meta: {\n id: 'pyreon/dev-guard-warnings',\n category: 'architecture',\n description: 'Require console.warn/error calls to be wrapped in `if (__DEV__)` guards.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n const filePath = context.getFilePath()\n // Skip test and example files\n if (\n filePath.includes('/tests/') ||\n filePath.includes('/test/') ||\n filePath.includes('/examples/') ||\n filePath.includes('.test.') ||\n filePath.includes('.spec.')\n ) {\n return {}\n }\n\n let devGuardDepth = 0\n const callbacks: VisitorCallbacks = {\n IfStatement(node: any) {\n if (node.test?.type === 'Identifier' && node.test.name === '__DEV__') {\n devGuardDepth++\n }\n },\n 'IfStatement:exit'(node: any) {\n if (node.test?.type === 'Identifier' && node.test.name === '__DEV__') {\n devGuardDepth--\n }\n },\n CallExpression(node: any) {\n if (devGuardDepth > 0) return\n\n const callee = node.callee\n if (\n callee?.type === 'MemberExpression' &&\n callee.object?.type === 'Identifier' &&\n callee.object.name === 'console' &&\n callee.property?.type === 'Identifier' &&\n (callee.property.name === 'warn' || callee.property.name === 'error')\n ) {\n context.report({\n message: `\\`console.${callee.property.name}()\\` without \\`__DEV__\\` guard — dev warnings must be tree-shakeable in production. Wrap in \\`if (__DEV__) { ... }\\`.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\nimport { isPyreonImport } from '../../utils/imports'\n\nconst LAYER_ORDER: Record<string, number> = {\n '@pyreon/reactivity': 0,\n '@pyreon/core': 1,\n '@pyreon/compiler': 1,\n '@pyreon/runtime-dom': 2,\n '@pyreon/runtime-server': 2,\n '@pyreon/router': 3,\n '@pyreon/head': 4,\n '@pyreon/server': 5,\n}\n\nfunction getLayer(source: string): number | null {\n return LAYER_ORDER[source] ?? null\n}\n\nfunction getFileLayer(filePath: string): number | null {\n for (const [pkg, layer] of Object.entries(LAYER_ORDER)) {\n const pkgName = pkg.replace('@pyreon/', '')\n if (filePath.includes(`/packages/core/${pkgName}/`)) return layer\n }\n return null\n}\n\nexport const noCircularImport: Rule = {\n meta: {\n id: 'pyreon/no-circular-import',\n category: 'architecture',\n description: 'Enforce package layer order to prevent circular imports between core packages.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n const filePath = context.getFilePath()\n const fileLayer = getFileLayer(filePath)\n if (fileLayer === null) return {}\n\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const source = node.source?.value as string\n if (!source || !isPyreonImport(source)) return\n\n const importLayer = getLayer(source)\n if (importLayer === null) return\n\n if (importLayer >= fileLayer) {\n context.report({\n message: `Importing \\`${source}\\` (layer ${importLayer}) from layer ${fileLayer} — this violates the package layer order and may cause circular imports.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\nimport { isPyreonImport } from '../../utils/imports'\n\ntype PackageCategory = 'core' | 'fundamentals' | 'tools' | 'ui-system'\n\nconst CORE_PACKAGES = new Set([\n '@pyreon/reactivity',\n '@pyreon/core',\n '@pyreon/compiler',\n '@pyreon/runtime-dom',\n '@pyreon/runtime-server',\n '@pyreon/router',\n '@pyreon/head',\n '@pyreon/server',\n])\n\nconst UI_PACKAGES = new Set([\n '@pyreon/ui-core',\n '@pyreon/styler',\n '@pyreon/unistyle',\n '@pyreon/elements',\n '@pyreon/attrs',\n '@pyreon/rocketstyle',\n '@pyreon/coolgrid',\n '@pyreon/kinetic',\n '@pyreon/kinetic-presets',\n '@pyreon/connector-document',\n '@pyreon/document-primitives',\n])\n\nfunction getImportCategory(source: string): PackageCategory | null {\n if (CORE_PACKAGES.has(source)) return 'core'\n if (UI_PACKAGES.has(source)) return 'ui-system'\n return null\n}\n\nfunction getFileCategory(filePath: string): PackageCategory | null {\n if (filePath.includes('/packages/core/')) return 'core'\n if (filePath.includes('/packages/ui-system/')) return 'ui-system'\n if (filePath.includes('/packages/fundamentals/')) return 'fundamentals'\n if (filePath.includes('/packages/tools/')) return 'tools'\n return null\n}\n\nexport const noCrossLayerImport: Rule = {\n meta: {\n id: 'pyreon/no-cross-layer-import',\n category: 'architecture',\n description: 'Prevent core packages from importing ui-system packages.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n const filePath = context.getFilePath()\n const fileCategory = getFileCategory(filePath)\n if (fileCategory !== 'core') return {}\n\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const source = node.source?.value as string\n if (!source || !isPyreonImport(source)) return\n\n const importCategory = getImportCategory(source)\n if (importCategory === 'ui-system') {\n context.report({\n message: `Core package importing ui-system package \\`${source}\\` — core packages must not depend on ui-system.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\nimport { isPyreonImport } from '../../utils/imports'\n\nconst DEEP_IMPORT_PATTERN = /@pyreon\\/[^/]+\\/(src|dist|lib)\\//\n\nexport const noDeepImport: Rule = {\n meta: {\n id: 'pyreon/no-deep-import',\n category: 'architecture',\n description:\n 'Disallow importing from @pyreon/*/src/, /dist/, or /lib/ — use public exports instead.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const source = node.source?.value as string\n if (!source || !isPyreonImport(source)) return\n\n if (DEEP_IMPORT_PATTERN.test(source)) {\n context.report({\n message: `Deep import \\`${source}\\` — import from the package's public exports instead.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const noErrorWithoutPrefix: Rule = {\n meta: {\n id: 'pyreon/no-error-without-prefix',\n category: 'architecture',\n description: 'Require error messages to be prefixed with [Pyreon].',\n severity: 'warn',\n fixable: true,\n },\n create(context) {\n const filePath = context.getFilePath()\n // Skip test files\n if (\n filePath.includes('/tests/') ||\n filePath.includes('/test/') ||\n filePath.includes('.test.') ||\n filePath.includes('.spec.')\n ) {\n return {}\n }\n\n const callbacks: VisitorCallbacks = {\n ThrowStatement(node: any) {\n const arg = node.argument\n if (!arg || arg.type !== 'NewExpression') return\n const callee = arg.callee\n if (!callee || callee.type !== 'Identifier' || callee.name !== 'Error') return\n\n const args = arg.arguments\n if (!args || args.length === 0) return\n\n const firstArg = args[0]\n if (!firstArg) return\n\n if (firstArg.type === 'Literal' || firstArg.type === 'StringLiteral') {\n const value = firstArg.value as string\n if (typeof value === 'string' && !value.startsWith('[Pyreon]')) {\n const argSpan = getSpan(firstArg)\n // Fix: add [Pyreon] prefix\n const quote = context.getSourceText()[argSpan.start]\n const fixedValue = `${quote}[Pyreon] ${value}${quote}`\n context.report({\n message:\n 'Error message missing `[Pyreon]` prefix — all framework errors should be prefixed for identification.',\n span: getSpan(node),\n fix: { span: argSpan, replacement: fixedValue },\n })\n }\n }\n\n if (firstArg.type === 'TemplateLiteral') {\n const quasis = firstArg.quasis\n if (quasis && quasis.length > 0) {\n const first = quasis[0]\n const raw = first.value?.raw ?? first.value?.cooked ?? ''\n if (!raw.startsWith('[Pyreon]')) {\n const argSpan = getSpan(firstArg)\n const source = context.getSourceText().slice(argSpan.start, argSpan.end)\n const fixed = source.replace(/^`/, '`[Pyreon] ')\n context.report({\n message:\n 'Error message missing `[Pyreon]` prefix — all framework errors should be prefixed for identification.',\n span: getSpan(node),\n fix: { span: argSpan, replacement: fixed },\n })\n }\n }\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noSubmitWithoutValidation: Rule = {\n meta: {\n id: 'pyreon/no-submit-without-validation',\n category: 'form',\n description: 'Warn when useForm() has onSubmit but no validators or schema.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (!isCallTo(node, 'useForm')) return\n const args = node.arguments\n if (!args || args.length === 0) return\n\n const options = args[0]\n if (!options || options.type !== 'ObjectExpression') return\n\n let hasOnSubmit = false\n let hasValidation = false\n\n for (const prop of options.properties ?? []) {\n if (prop.type !== 'Property') continue\n const key = prop.key\n if (!key) continue\n const name = key.type === 'Identifier' ? key.name : null\n if (name === 'onSubmit') hasOnSubmit = true\n if (name === 'validators' || name === 'schema') hasValidation = true\n }\n\n if (hasOnSubmit && !hasValidation) {\n context.report({\n message:\n '`useForm()` has `onSubmit` without `validators` or `schema` — consider adding validation for data integrity.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noUnregisteredField: Rule = {\n meta: {\n id: 'pyreon/no-unregistered-field',\n category: 'form',\n description: 'Warn when useField() is called without a corresponding register() call.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const fieldDecls = new Map<string, { span: { start: number; end: number } }>()\n const registeredNames = new Set<string>()\n\n const callbacks: VisitorCallbacks = {\n VariableDeclarator(node: any) {\n const init = node.init\n if (!init || !isCallTo(init, 'useField')) return\n const id = node.id\n if (!id || id.type !== 'Identifier') return\n fieldDecls.set(id.name, { span: getSpan(node) })\n },\n CallExpression(node: any) {\n const callee = node.callee\n if (!callee || callee.type !== 'MemberExpression') return\n if (callee.property?.type !== 'Identifier' || callee.property.name !== 'register') return\n if (callee.object?.type === 'Identifier') {\n registeredNames.add(callee.object.name)\n }\n },\n 'Program:exit'() {\n for (const [name, { span }] of fieldDecls) {\n if (!registeredNames.has(name)) {\n context.report({\n message: `\\`useField()\\` result \\`${name}\\` is never registered — call \\`${name}.register()\\` to connect it to the form.`,\n span,\n })\n }\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\nimport { extractImportInfo } from '../../utils/imports'\n\nexport const preferFieldArray: Rule = {\n meta: {\n id: 'pyreon/prefer-field-array',\n category: 'form',\n description: 'Suggest useFieldArray() instead of signal([]) in files that import @pyreon/form.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n let importsForm = false\n\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const info = extractImportInfo(node)\n if (info && info.source === '@pyreon/form') {\n importsForm = true\n }\n },\n CallExpression(node: any) {\n if (!importsForm) return\n if (!isCallTo(node, 'signal')) return\n\n const args = node.arguments\n if (!args || args.length === 0) return\n const firstArg = args[0]\n if (firstArg?.type === 'ArrayExpression') {\n context.report({\n message:\n '`signal([])` in a form file — consider using `useFieldArray()` for dynamic array fields with stable keys.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const noRawAddEventListener: Rule = {\n meta: {\n id: 'pyreon/no-raw-addeventlistener',\n category: 'hooks',\n description: 'Suggest useEventListener() instead of raw .addEventListener() calls.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n const callee = node.callee\n if (!callee || callee.type !== 'MemberExpression') return\n if (callee.property?.type !== 'Identifier' || callee.property.name !== 'addEventListener')\n return\n context.report({\n message:\n 'Raw `.addEventListener()` — consider using `useEventListener()` from `@pyreon/hooks` for auto-cleanup on unmount.',\n span: getSpan(node),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nconst STORAGE_OBJECTS = new Set(['localStorage', 'sessionStorage'])\nconst STORAGE_METHODS = new Set(['getItem', 'setItem', 'removeItem'])\n\nexport const noRawLocalStorage: Rule = {\n meta: {\n id: 'pyreon/no-raw-localstorage',\n category: 'hooks',\n description: 'Suggest useStorage() instead of raw localStorage/sessionStorage access.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n const callee = node.callee\n if (!callee || callee.type !== 'MemberExpression') return\n if (\n callee.object?.type === 'Identifier' &&\n STORAGE_OBJECTS.has(callee.object.name) &&\n callee.property?.type === 'Identifier' &&\n STORAGE_METHODS.has(callee.property.name)\n ) {\n context.report({\n message: `Raw \\`${callee.object.name}.${callee.property.name}()\\` — consider using \\`useStorage()\\` from \\`@pyreon/storage\\` for reactive, cross-tab synced storage.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nconst TIMER_FNS = new Set(['setInterval', 'setTimeout'])\n\nexport const noRawSetInterval: Rule = {\n meta: {\n id: 'pyreon/no-raw-setinterval',\n category: 'hooks',\n description: 'Suggest wrapping setInterval/setTimeout in onMount for automatic cleanup.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n let mountDepth = 0\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (isCallTo(node, 'onMount')) {\n mountDepth++\n }\n\n if (mountDepth > 0) return\n\n const callee = node.callee\n if (!callee || callee.type !== 'Identifier') return\n if (TIMER_FNS.has(callee.name)) {\n context.report({\n message: `\\`${callee.name}()\\` outside \\`onMount\\` — wrap in \\`onMount(() => { ... return () => clear... })\\` for automatic cleanup.`,\n span: getSpan(node),\n })\n }\n },\n 'CallExpression:exit'(node: any) {\n if (isCallTo(node, 'onMount')) {\n mountDepth--\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isLogicalAndWithJSX } from '../../utils/ast'\n\nexport const noAndConditional: Rule = {\n meta: {\n id: 'pyreon/no-and-conditional',\n category: 'jsx',\n description: 'Prefer <Show> over `&&` with JSX in expression containers.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let jsxExpressionDepth = 0\n const callbacks: VisitorCallbacks = {\n JSXExpressionContainer() {\n jsxExpressionDepth++\n },\n 'JSXExpressionContainer:exit'() {\n jsxExpressionDepth--\n },\n LogicalExpression(node: any) {\n if (jsxExpressionDepth === 0) return\n if (!isLogicalAndWithJSX(node)) return\n context.report({\n message: '`&&` with JSX — use `<Show>` for conditional rendering.',\n span: getSpan(node),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\nimport { extractImportInfo, type ImportInfo } from '../../utils/imports'\n\nexport const noChildrenAccess: Rule = {\n meta: {\n id: 'pyreon/no-children-access',\n category: 'jsx',\n description: 'Inform about direct props.children access in renderer files.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n const imports: ImportInfo[] = []\n let isRendererFile = false\n\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const info = extractImportInfo(node)\n if (info) {\n imports.push(info)\n if (info.source === '@pyreon/runtime-server' || info.source === '@pyreon/runtime-dom') {\n isRendererFile = true\n }\n }\n },\n MemberExpression(node: any) {\n if (!isRendererFile) return\n if (\n node.object?.type === 'Identifier' &&\n node.property?.type === 'Identifier' &&\n node.property.name === 'children'\n ) {\n context.report({\n message:\n 'Direct `props.children` access in a renderer file — children are already merged via `mergeChildrenIntoProps`.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const noClassName: Rule = {\n meta: {\n id: 'pyreon/no-classname',\n category: 'jsx',\n description: 'Use `class` instead of `className` — Pyreon uses standard HTML attributes.',\n severity: 'error',\n fixable: true,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXAttribute(node: any) {\n if (node.name?.type !== 'JSXIdentifier') return\n if (node.name.name !== 'className') return\n const nameSpan = getSpan(node.name)\n context.report({\n message: 'Use `class` instead of `className` — Pyreon uses standard HTML attributes.',\n span: getSpan(node),\n fix: { span: nameSpan, replacement: 'class' },\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const noHtmlFor: Rule = {\n meta: {\n id: 'pyreon/no-htmlfor',\n category: 'jsx',\n description: 'Use `for` instead of `htmlFor` — Pyreon uses standard HTML attributes.',\n severity: 'error',\n fixable: true,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXAttribute(node: any) {\n if (node.name?.type !== 'JSXIdentifier') return\n if (node.name.name !== 'htmlFor') return\n const nameSpan = getSpan(node.name)\n context.report({\n message: 'Use `for` instead of `htmlFor` — Pyreon uses standard HTML attributes.',\n span: getSpan(node),\n fix: { span: nameSpan, replacement: 'for' },\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getJSXAttribute, getSpan } from '../../utils/ast'\n\nexport const noIndexAsBy: Rule = {\n meta: {\n id: 'pyreon/no-index-as-by',\n category: 'jsx',\n description: 'Disallow using index as `by` prop on <For> — use a unique key instead.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const name = node.name\n if (!name || name.type !== 'JSXIdentifier' || name.name !== 'For') return\n\n const byAttr = getJSXAttribute(node, 'by')\n if (!byAttr) return\n\n const value = byAttr.value\n if (!value || value.type !== 'JSXExpressionContainer') return\n\n const expr = value.expression\n if (!expr) return\n\n // Detect: by={(_, i) => i} or by={(item, index) => index}\n if (expr.type === 'ArrowFunctionExpression' || expr.type === 'FunctionExpression') {\n const params = expr.params\n if (!params || params.length < 2) return\n\n const secondParam = params[1]\n if (!secondParam || secondParam.type !== 'Identifier') return\n\n const indexName = secondParam.name\n const body = expr.body\n\n // Arrow expression body: (_, i) => i\n if (body?.type === 'Identifier' && body.name === indexName) {\n context.report({\n message:\n 'Using index as `by` prop on `<For>` — use a unique key from the data instead.',\n span: getSpan(byAttr),\n })\n }\n\n // Block body: (_, i) => { return i }\n if (body?.type === 'BlockStatement') {\n const stmts = body.body\n if (stmts?.length === 1) {\n const stmt = stmts[0]\n if (\n stmt.type === 'ReturnStatement' &&\n stmt.argument?.type === 'Identifier' &&\n stmt.argument.name === indexName\n ) {\n context.report({\n message:\n 'Using index as `by` prop on `<For>` — use a unique key from the data instead.',\n span: getSpan(byAttr),\n })\n }\n }\n }\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isArrayMapCall } from '../../utils/ast'\n\nexport const noMapInJsx: Rule = {\n meta: {\n id: 'pyreon/no-map-in-jsx',\n category: 'jsx',\n description: 'Prefer <For> over .map() inside JSX for reactive list rendering.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let jsxDepth = 0\n const callbacks: VisitorCallbacks = {\n JSXElement() {\n jsxDepth++\n },\n 'JSXElement:exit'() {\n jsxDepth--\n },\n JSXFragment() {\n jsxDepth++\n },\n 'JSXFragment:exit'() {\n jsxDepth--\n },\n CallExpression(node: any) {\n if (jsxDepth === 0) return\n if (!isArrayMapCall(node)) return\n // Check callback contains JSX\n const args = node.arguments\n if (!args || args.length === 0) return\n const callback = args[0]\n if (!callback) return\n context.report({\n message: '`.map()` in JSX — use `<For>` for reactive list rendering instead.',\n span: getSpan(node),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, hasJSXAttribute } from '../../utils/ast'\n\nexport const noMissingForBy: Rule = {\n meta: {\n id: 'pyreon/no-missing-for-by',\n category: 'jsx',\n description: 'Warn when <For> is used without a `by` prop.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const name = node.name\n if (!name || name.type !== 'JSXIdentifier' || name.name !== 'For') return\n if (hasJSXAttribute(node, 'by')) return\n context.report({\n message:\n '`<For>` without `by` prop — provide a key function for efficient reconciliation.',\n span: getSpan(node),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nconst INPUT_TAGS = new Set(['input', 'textarea', 'select'])\n\nexport const noOnChange: Rule = {\n meta: {\n id: 'pyreon/no-onchange',\n category: 'jsx',\n description:\n 'Prefer `onInput` over `onChange` on input elements for keypress-by-keypress updates.',\n severity: 'warn',\n fixable: true,\n },\n create(context) {\n let currentTag: string | null = null\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const name = node.name\n if (name?.type === 'JSXIdentifier' && INPUT_TAGS.has(name.name)) {\n currentTag = name.name\n } else {\n currentTag = null\n }\n\n if (!currentTag) return\n const attrs = node.attributes ?? []\n for (const attr of attrs) {\n if (\n attr.type === 'JSXAttribute' &&\n attr.name?.type === 'JSXIdentifier' &&\n attr.name.name === 'onChange'\n ) {\n const nameSpan = getSpan(attr.name)\n context.report({\n message: `Use \\`onInput\\` instead of \\`onChange\\` on \\`<${currentTag}>\\` for keypress-by-keypress updates.`,\n span: getSpan(attr),\n fix: { span: nameSpan, replacement: 'onInput' },\n })\n }\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isDestructuring } from '../../utils/ast'\n\nfunction containsJSXReturn(node: any): boolean {\n if (!node) return false\n if (node.type === 'JSXElement' || node.type === 'JSXFragment') return true\n if (node.type === 'ParenthesizedExpression') return containsJSXReturn(node.expression)\n\n if (node.type === 'BlockStatement') {\n for (const stmt of node.body ?? []) {\n if (stmt.type === 'ReturnStatement' && containsJSXReturn(stmt.argument)) {\n return true\n }\n }\n }\n return false\n}\n\n/**\n * Extract destructured property names from an ObjectPattern.\n * Returns names for the fix suggestion.\n */\nfunction getDestructuredNames(pattern: any): string[] {\n if (pattern.type !== 'ObjectPattern') return []\n const names: string[] = []\n for (const prop of pattern.properties ?? []) {\n if (prop.type === 'ObjectProperty' && prop.key?.type === 'Identifier') {\n names.push(prop.key.name)\n }\n }\n return names\n}\n\nexport const noPropsDestructure: Rule = {\n meta: {\n id: 'pyreon/no-props-destructure',\n category: 'jsx',\n description:\n 'Disallow destructuring props in component functions — breaks reactive prop tracking. Use props.x or splitProps().',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n let functionDepth = 0\n\n const callbacks: VisitorCallbacks = {\n ArrowFunctionExpression(node: any) {\n functionDepth++\n checkFunction(node, context, functionDepth)\n },\n 'ArrowFunctionExpression:exit'() {\n functionDepth--\n },\n FunctionDeclaration(node: any) {\n functionDepth++\n checkFunction(node, context, functionDepth)\n },\n 'FunctionDeclaration:exit'() {\n functionDepth--\n },\n FunctionExpression(node: any) {\n functionDepth++\n checkFunction(node, context, functionDepth)\n },\n 'FunctionExpression:exit'() {\n functionDepth--\n },\n }\n return callbacks\n },\n}\n\nfunction checkFunction(node: any, context: any, depth: number) {\n const params = node.params\n if (!params || params.length === 0) return\n\n const firstParam = params[0]\n if (!isDestructuring(firstParam)) return\n\n // Skip HOC inner functions (depth > 1)\n if (depth > 1) return\n\n // Skip functions passed as arguments to HOC factories\n // e.g. createLink(({ href, ...rest }) => <a {...rest} />)\n const parent = node.parent\n if (parent?.type === 'CallExpression' && parent.arguments?.includes(node)) return\n\n const body = node.body\n if (!body) return\n\n if (containsJSXReturn(body)) {\n const names = getDestructuredNames(firstParam)\n const hasRest = (firstParam.properties ?? []).some((p: any) => p.type === 'RestElement')\n\n let suggestion = 'Use `props.x` pattern for reactive prop access.'\n if (names.length > 0) {\n const propsAccess = names.map((n) => `props.${n}`).join(', ')\n suggestion = `Use \\`props\\` parameter and access as ${propsAccess}.`\n if (hasRest) {\n suggestion += ` For rest props, use \\`splitProps(props, [${names.map((n) => `'${n}'`).join(', ')}])\\`.`\n }\n }\n\n context.report({\n message:\n `Destructured props in component function — breaks reactive prop tracking. ${suggestion}`,\n span: getSpan(firstParam),\n })\n }\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isTernaryWithJSX } from '../../utils/ast'\n\nexport const noTernaryConditional: Rule = {\n meta: {\n id: 'pyreon/no-ternary-conditional',\n category: 'jsx',\n description: 'Prefer <Show> over ternary expressions with JSX branches.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let jsxExpressionDepth = 0\n const callbacks: VisitorCallbacks = {\n JSXExpressionContainer() {\n jsxExpressionDepth++\n },\n 'JSXExpressionContainer:exit'() {\n jsxExpressionDepth--\n },\n ConditionalExpression(node: any) {\n if (jsxExpressionDepth === 0) return\n if (!isTernaryWithJSX(node)) return\n context.report({\n message: 'Ternary with JSX — use `<Show>` for more efficient conditional rendering.',\n span: getSpan(node),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getJSXAttribute, getSpan, hasJSXAttribute } from '../../utils/ast'\n\nexport const useByNotKey: Rule = {\n meta: {\n id: 'pyreon/use-by-not-key',\n category: 'jsx',\n description:\n 'Use `by` prop on <For> instead of `key` — JSX reserves `key` for VNode reconciliation.',\n severity: 'error',\n fixable: true,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const tagName = node.name?.type === 'JSXIdentifier' ? node.name.name : null\n if (tagName !== 'For') return\n const keyAttr = getJSXAttribute(node, 'key')\n if (!keyAttr) return\n if (hasJSXAttribute(node, 'by')) return // already has by\n\n const attrSpan = getSpan(keyAttr.name)\n context.report({\n message:\n 'Use `by` prop on `<For>` instead of `key` — JSX reserves `key` for VNode reconciliation.',\n span: getSpan(keyAttr),\n fix: { span: attrSpan, replacement: 'by' },\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nconst DOM_METHODS = new Set([\n 'querySelector',\n 'querySelectorAll',\n 'getElementById',\n 'getElementsByClassName',\n 'getElementsByTagName',\n])\n\nexport const noDomInSetup: Rule = {\n meta: {\n id: 'pyreon/no-dom-in-setup',\n category: 'lifecycle',\n description: 'Warn when DOM query methods are used outside onMount or effect.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let safeDepth = 0 // inside onMount or effect\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (isCallTo(node, 'onMount') || isCallTo(node, 'effect')) {\n safeDepth++\n }\n\n if (safeDepth > 0) return\n\n // Check for document.querySelector() etc.\n const callee = node.callee\n if (\n callee?.type === 'MemberExpression' &&\n callee.object?.type === 'Identifier' &&\n callee.object.name === 'document' &&\n callee.property?.type === 'Identifier' &&\n DOM_METHODS.has(callee.property.name)\n ) {\n context.report({\n message: `\\`document.${callee.property.name}()\\` outside \\`onMount\\`/\\`effect\\` — DOM is not available during SSR or setup phase.`,\n span: getSpan(node),\n })\n }\n },\n 'CallExpression:exit'(node: any) {\n if (isCallTo(node, 'onMount') || isCallTo(node, 'effect')) {\n safeDepth--\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noEffectInMount: Rule = {\n meta: {\n id: 'pyreon/no-effect-in-mount',\n category: 'lifecycle',\n description:\n 'Inform when effect() is created inside onMount — effects are typically created at setup time.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n let mountDepth = 0\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (isCallTo(node, 'onMount')) {\n mountDepth++\n }\n if (mountDepth > 0 && isCallTo(node, 'effect')) {\n context.report({\n message:\n '`effect()` inside `onMount` — effects are typically created at component setup time, not inside lifecycle hooks.',\n span: getSpan(node),\n })\n }\n },\n 'CallExpression:exit'(node: any) {\n if (isCallTo(node, 'onMount')) {\n mountDepth--\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nconst NEEDS_CLEANUP = new Set(['setInterval', 'addEventListener'])\n\nexport const noMissingCleanup: Rule = {\n meta: {\n id: 'pyreon/no-missing-cleanup',\n category: 'lifecycle',\n description:\n 'Warn when onMount uses setInterval/addEventListener without returning a cleanup function.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (!isCallTo(node, 'onMount')) return\n const args = node.arguments\n if (!args || args.length === 0) return\n\n const fn = args[0]\n if (!fn) return\n if (fn.type !== 'ArrowFunctionExpression' && fn.type !== 'FunctionExpression') return\n\n const body = fn.body\n if (!body) return\n\n // Only check block bodies\n if (body.type !== 'BlockStatement') return\n\n let hasCleanupTarget = false\n let hasReturn = false\n\n function walk(n: any) {\n if (!n) return\n if (n.type === 'CallExpression') {\n const callee = n.callee\n if (callee?.type === 'Identifier' && NEEDS_CLEANUP.has(callee.name)) {\n hasCleanupTarget = true\n }\n if (\n callee?.type === 'MemberExpression' &&\n callee.property?.type === 'Identifier' &&\n NEEDS_CLEANUP.has(callee.property.name)\n ) {\n hasCleanupTarget = true\n }\n }\n if (n.type === 'ReturnStatement' && n.argument) {\n hasReturn = true\n }\n for (const key of Object.keys(n)) {\n const child = n[key]\n if (child && typeof child === 'object') {\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item.type === 'string') walk(item)\n }\n } else if (typeof child.type === 'string') {\n walk(child)\n }\n }\n }\n }\n\n walk(body)\n\n if (hasCleanupTarget && !hasReturn) {\n context.report({\n message:\n '`onMount` uses `setInterval`/`addEventListener` without returning a cleanup function — this will cause a memory leak.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noMountInEffect: Rule = {\n meta: {\n id: 'pyreon/no-mount-in-effect',\n category: 'lifecycle',\n description: 'Warn when onMount is called inside effect().',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let effectDepth = 0\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (isCallTo(node, 'effect')) {\n effectDepth++\n }\n if (effectDepth > 0 && isCallTo(node, 'onMount')) {\n context.report({\n message:\n '`onMount` inside `effect()` — `onMount` runs once on mount, not on every effect re-run.',\n span: getSpan(node),\n })\n }\n },\n 'CallExpression:exit'(node: any) {\n if (isCallTo(node, 'effect')) {\n effectDepth--\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\nimport { HEAVY_PACKAGES } from '../../utils/imports'\n\nexport const noEagerImport: Rule = {\n meta: {\n id: 'pyreon/no-eager-import',\n category: 'performance',\n description: 'Suggest lazy-loading heavy Pyreon packages (charts, code, document, flow).',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const source = node.source?.value as string\n if (!source) return\n if (HEAVY_PACKAGES.has(source)) {\n context.report({\n message: `Static import of \\`${source}\\` — consider using \\`lazy()\\` or dynamic \\`import()\\` to reduce initial bundle size.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noEffectInFor: Rule = {\n meta: {\n id: 'pyreon/no-effect-in-for',\n category: 'performance',\n description:\n 'Warn when effect() is created inside <For> — creates effects per item on every reconciliation.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let forJsxDepth = 0\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const name = node.name\n if (name?.type === 'JSXIdentifier' && name.name === 'For') {\n forJsxDepth++\n }\n },\n JSXClosingElement(node: any) {\n const name = node.name\n if (name?.type === 'JSXIdentifier' && name.name === 'For') {\n forJsxDepth--\n }\n },\n CallExpression(node: any) {\n if (forJsxDepth === 0) return\n if (isCallTo(node, 'effect')) {\n context.report({\n message:\n '`effect()` inside `<For>` — this creates a new effect for every item on each reconciliation. Lift the effect outside.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, hasJSXAttribute } from '../../utils/ast'\n\nexport const noLargeForWithoutBy: Rule = {\n meta: {\n id: 'pyreon/no-large-for-without-by',\n category: 'performance',\n description:\n 'Error when <For> is used without a `by` prop — critical for reconciliation performance.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const name = node.name\n if (!name || name.type !== 'JSXIdentifier' || name.name !== 'For') return\n if (hasJSXAttribute(node, 'by')) return\n context.report({\n message:\n '`<For>` without `by` prop — provide a key function for efficient reconciliation.',\n span: getSpan(node),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const preferShowOverDisplay: Rule = {\n meta: {\n id: 'pyreon/prefer-show-over-display',\n category: 'performance',\n description: 'Suggest <Show> over conditional `display` style property in JSX.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXAttribute(node: any) {\n if (node.name?.type !== 'JSXIdentifier' || node.name.name !== 'style') return\n const value = node.value\n if (!value || value.type !== 'JSXExpressionContainer') return\n const expr = value.expression\n if (!expr || expr.type !== 'ObjectExpression') return\n\n for (const prop of expr.properties ?? []) {\n if (prop.type !== 'Property') continue\n const key = prop.key\n if (!key) continue\n const propName =\n key.type === 'Identifier' ? key.name : key.type === 'Literal' ? key.value : null\n if (propName === 'display') {\n // Check if the value is conditional\n const val = prop.value\n if (\n val?.type === 'ConditionalExpression' ||\n val?.type === 'LogicalExpression' ||\n val?.type === 'CallExpression'\n ) {\n context.report({\n message:\n 'Conditional `display` style — consider using `<Show>` for conditional rendering instead of toggling CSS display.',\n span: getSpan(prop),\n })\n }\n }\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nconst SKIP_PREFIXES = /^(use|get|is|has|[A-Z])/\n\nexport const noBareSignalInJsx: Rule = {\n meta: {\n id: 'pyreon/no-bare-signal-in-jsx',\n category: 'reactivity',\n description:\n 'Disallow bare signal calls in JSX text positions. Wrap in `() =>` for reactivity.',\n severity: 'error',\n fixable: true,\n },\n create(context) {\n let jsxDepth = 0\n const callbacks: VisitorCallbacks = {\n JSXElement() {\n jsxDepth++\n },\n 'JSXElement:exit'() {\n jsxDepth--\n },\n JSXFragment() {\n jsxDepth++\n },\n 'JSXFragment:exit'() {\n jsxDepth--\n },\n JSXExpressionContainer(node: any) {\n if (jsxDepth === 0) return\n const expr = node.expression\n if (!expr || expr.type !== 'CallExpression') return\n const callee = expr.callee\n if (!callee || callee.type !== 'Identifier') return\n\n const name: string = callee.name\n if (SKIP_PREFIXES.test(name)) return\n\n const span = getSpan(node)\n const source = context.getSourceText()\n const original = source.slice(span.start, span.end)\n // {count()} → {() => count()}\n const inner = original.slice(1, -1) // strip { }\n const fixed = `{() => ${inner}}`\n\n context.report({\n message: `Bare signal call \\`${name}()\\` in JSX text — wrap in \\`() => ${name}()\\` for fine-grained reactivity.`,\n span,\n fix: { span, replacement: fixed },\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\n/**\n * Detects destructuring the return value of useContext().\n *\n * `const { mode } = useContext(ctx)` loses reactivity when the context\n * provides getter properties. The value is captured once at setup time.\n *\n * Correct: `const ctx = useContext(Ctx)` then read `ctx.mode` lazily.\n */\nexport const noContextDestructure: Rule = {\n meta: {\n id: 'pyreon/no-context-destructure',\n category: 'reactivity',\n description:\n 'Disallow destructuring useContext() — it breaks reactivity when context provides getters.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n VariableDeclarator(node: any) {\n // Match: const { x } = useContext(...)\n const id = node.id\n const init = node.init\n if (!id || !init) return\n if (id.type !== 'ObjectPattern') return\n if (\n init.type !== 'CallExpression' ||\n init.callee?.type !== 'Identifier' ||\n init.callee.name !== 'useContext'\n )\n return\n\n context.report({\n message:\n 'Destructuring useContext() captures values once — reactive getters lose reactivity. Keep the object reference: `const ctx = useContext(Ctx)` and access `ctx.mode` lazily.',\n span: getSpan(id),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nfunction isUpdateCall(node: any): boolean {\n return (\n node.type === 'CallExpression' &&\n node.callee?.type === 'MemberExpression' &&\n node.callee.property?.type === 'Identifier' &&\n node.callee.property.name === 'update'\n )\n}\n\nexport const noEffectAssignment: Rule = {\n meta: {\n id: 'pyreon/no-effect-assignment',\n category: 'reactivity',\n description: 'Warn when an effect only contains a single .update() call.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (!isCallTo(node, 'effect')) return\n const args = node.arguments\n if (!args || args.length === 0) return\n\n const fn = args[0]\n if (!fn) return\n\n let body: any = null\n if (fn.type === 'ArrowFunctionExpression' || fn.type === 'FunctionExpression') {\n body = fn.body\n }\n if (!body) return\n\n // Arrow with expression body\n if (isUpdateCall(body)) {\n context.report({\n message:\n 'Effect contains a single `.update()` — consider using `computed()` for derived values.',\n span: getSpan(node),\n })\n return\n }\n\n // Block body with single statement\n if (body.type === 'BlockStatement') {\n const stmts = body.body\n if (stmts && stmts.length === 1) {\n const stmt = stmts[0]\n if (stmt.type === 'ExpressionStatement' && isUpdateCall(stmt.expression)) {\n context.report({\n message:\n 'Effect contains a single `.update()` — consider using `computed()` for derived values.',\n span: getSpan(node),\n })\n }\n }\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noNestedEffect: Rule = {\n meta: {\n id: 'pyreon/no-nested-effect',\n category: 'reactivity',\n description: 'Warn against nesting effect() inside another effect().',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let effectDepth = 0\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (!isCallTo(node, 'effect')) return\n if (effectDepth > 0) {\n context.report({\n message: 'Nested `effect()` — consider using `computed()` for derived values instead.',\n span: getSpan(node),\n })\n }\n effectDepth++\n },\n 'CallExpression:exit'(node: any) {\n if (isCallTo(node, 'effect')) {\n effectDepth--\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo, isPeekCall } from '../../utils/ast'\n\nexport const noPeekInTracked: Rule = {\n meta: {\n id: 'pyreon/no-peek-in-tracked',\n category: 'reactivity',\n description: 'Disallow .peek() inside effect() or computed() — it bypasses tracking.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n let trackedDepth = 0\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (isCallTo(node, 'effect') || isCallTo(node, 'computed')) {\n trackedDepth++\n }\n if (trackedDepth > 0 && isPeekCall(node)) {\n context.report({\n message:\n '`.peek()` inside a tracked scope (effect/computed) bypasses dependency tracking — use a normal signal read instead.',\n span: getSpan(node),\n })\n }\n },\n 'CallExpression:exit'(node: any) {\n if (isCallTo(node, 'effect') || isCallTo(node, 'computed')) {\n trackedDepth--\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const noSignalInLoop: Rule = {\n meta: {\n id: 'pyreon/no-signal-in-loop',\n category: 'reactivity',\n description: 'Disallow creating signals or computeds inside loops.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n let loopDepth = 0\n const callbacks: VisitorCallbacks = {\n ForStatement() {\n loopDepth++\n },\n 'ForStatement:exit'() {\n loopDepth--\n },\n ForInStatement() {\n loopDepth++\n },\n 'ForInStatement:exit'() {\n loopDepth--\n },\n ForOfStatement() {\n loopDepth++\n },\n 'ForOfStatement:exit'() {\n loopDepth--\n },\n WhileStatement() {\n loopDepth++\n },\n 'WhileStatement:exit'() {\n loopDepth--\n },\n DoWhileStatement() {\n loopDepth++\n },\n 'DoWhileStatement:exit'() {\n loopDepth--\n },\n CallExpression(node: any) {\n if (loopDepth === 0) return\n const callee = node.callee\n if (!callee || callee.type !== 'Identifier') return\n if (callee.name === 'signal' || callee.name === 'computed') {\n context.report({\n message: `\\`${callee.name}()\\` inside a loop — signals should be created once at component setup, not on every iteration.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nfunction isComponentTag(name: string): boolean {\n return name.length > 0 && name[0] === name[0]?.toUpperCase() && name[0] !== name[0]?.toLowerCase()\n}\n\n/**\n * Warn when a known signal/computed is called in a component prop position.\n * Component props are evaluated once at mount — signal reads are NOT reactive\n * unless the compiler wraps them with _rp(). The compiler handles this\n * automatically, but this rule catches manual h() calls and educates developers.\n */\nexport const noSignalInProps: Rule = {\n meta: {\n id: 'pyreon/no-signal-in-props',\n category: 'reactivity',\n description:\n 'Signal call in component prop — value captured once unless compiler wraps it. Use props.x pattern for reactivity.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXExpressionContainer(node: any) {\n const expr = node.expression\n if (!expr || expr.type !== 'CallExpression') return\n const callee = expr.callee\n if (!callee || callee.type !== 'Identifier') return\n\n const source = context.getSourceText()\n const start = node.start as number\n\n let i = start - 1\n while (i >= 0 && source[i] !== '<' && source[i] !== '>') i--\n if (i < 0 || source[i] !== '<') return\n\n const tagStart = i + 1\n let tagEnd = tagStart\n while (tagEnd < source.length && /[\\w.]/.test(source[tagEnd] ?? '')) tagEnd++\n const tagName = source.slice(tagStart, tagEnd)\n\n if (!tagName || !isComponentTag(tagName)) return\n\n context.report({\n message: `Signal call in <${tagName}> prop — use props.x pattern inside the component for reactive access.`,\n span: getSpan(expr),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noSignalLeak: Rule = {\n meta: {\n id: 'pyreon/no-signal-leak',\n category: 'reactivity',\n description: 'Warn about unused signal declarations (potential leaks).',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const signalDecls = new Map<\n string,\n { span: { start: number; end: number }; declStart: number; declEnd: number }\n >()\n const identifierOccurrences = new Map<string, Array<{ start: number; end: number }>>()\n\n const callbacks: VisitorCallbacks = {\n VariableDeclarator(node: any) {\n const init = node.init\n if (!init || !isCallTo(init, 'signal')) return\n const id = node.id\n if (!id || id.type !== 'Identifier') return\n signalDecls.set(id.name, {\n span: getSpan(node),\n declStart: id.start as number,\n declEnd: id.end as number,\n })\n },\n Identifier(node: any) {\n const name: string = node.name\n const existing = identifierOccurrences.get(name)\n if (existing) {\n existing.push({ start: node.start as number, end: node.end as number })\n } else {\n identifierOccurrences.set(name, [\n { start: node.start as number, end: node.end as number },\n ])\n }\n },\n 'Program:exit'() {\n for (const [name, { span, declStart, declEnd }] of signalDecls) {\n const occurrences = identifierOccurrences.get(name) ?? []\n // Filter out the declaration identifier itself\n const usages = occurrences.filter((o) => o.start !== declStart || o.end !== declEnd)\n if (usages.length === 0) {\n context.report({\n message: `Signal \\`${name}\\` is declared but never used — this may be a signal leak.`,\n span,\n })\n }\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo, isSetCall } from '../../utils/ast'\n\ninterface ScopeInfo {\n setCalls: Array<{ span: { start: number; end: number } }>\n hasBatch: boolean\n insideBatch: boolean\n node: any\n}\n\nexport const noUnbatchedUpdates: Rule = {\n meta: {\n id: 'pyreon/no-unbatched-updates',\n category: 'reactivity',\n description: 'Warn when 3+ .set() calls occur in the same function without batch().',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const scopeStack: ScopeInfo[] = []\n let batchDepth = 0\n\n function enterScope(node: any) {\n scopeStack.push({ setCalls: [], hasBatch: false, insideBatch: batchDepth > 0, node })\n }\n\n function exitScope() {\n const scope = scopeStack.pop()\n if (!scope) return\n if (!scope.hasBatch && !scope.insideBatch && scope.setCalls.length >= 3) {\n context.report({\n message: `${scope.setCalls.length} signal \\`.set()\\` calls without \\`batch()\\` — wrap in \\`batch(() => { ... })\\` to avoid unnecessary re-renders.`,\n span: getSpan(scope.node),\n })\n }\n }\n\n const callbacks: VisitorCallbacks = {\n FunctionDeclaration(node: any) {\n enterScope(node)\n },\n 'FunctionDeclaration:exit'() {\n exitScope()\n },\n FunctionExpression(node: any) {\n enterScope(node)\n },\n 'FunctionExpression:exit'() {\n exitScope()\n },\n ArrowFunctionExpression(node: any) {\n enterScope(node)\n },\n 'ArrowFunctionExpression:exit'() {\n exitScope()\n },\n CallExpression(node: any) {\n const currentScope = scopeStack.length > 0 ? scopeStack[scopeStack.length - 1] : undefined\n if (isCallTo(node, 'batch')) {\n batchDepth++\n if (currentScope) {\n currentScope.hasBatch = true\n }\n }\n if (currentScope && isSetCall(node)) {\n currentScope.setCalls.push({ span: getSpan(node) })\n }\n },\n 'CallExpression:exit'(node: any) {\n if (isCallTo(node, 'batch')) {\n batchDepth--\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo, isSetCall } from '../../utils/ast'\n\nexport const preferComputed: Rule = {\n meta: {\n id: 'pyreon/prefer-computed',\n category: 'reactivity',\n description: 'Suggest computed() when an effect only contains a single .set() call.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (!isCallTo(node, 'effect')) return\n const args = node.arguments\n if (!args || args.length === 0) return\n\n const fn = args[0]\n if (!fn) return\n\n let body: any = null\n if (fn.type === 'ArrowFunctionExpression' || fn.type === 'FunctionExpression') {\n body = fn.body\n }\n if (!body) return\n\n // Arrow with expression body: effect(() => x.set(y))\n if (body.type === 'CallExpression' && isSetCall(body)) {\n context.report({\n message:\n 'Effect contains a single `.set()` — consider using `computed()` instead for derived values.',\n span: getSpan(node),\n })\n return\n }\n\n // Block body with single statement: effect(() => { x.set(y) })\n if (body.type === 'BlockStatement') {\n const stmts = body.body\n if (stmts && stmts.length === 1) {\n const stmt = stmts[0]\n if (stmt.type === 'ExpressionStatement' && isSetCall(stmt.expression)) {\n context.report({\n message:\n 'Effect contains a single `.set()` — consider using `computed()` instead for derived values.',\n span: getSpan(node),\n })\n }\n }\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getJSXAttribute, getSpan } from '../../utils/ast'\nimport { extractImportInfo } from '../../utils/imports'\n\nconst EXTERNAL_PREFIXES = ['http://', 'https://', 'mailto:', 'tel:']\n\nexport const noHrefNavigation: Rule = {\n meta: {\n id: 'pyreon/no-href-navigation',\n category: 'router',\n description:\n 'Warn when `<a href>` is used in files that import @pyreon/router — use `<Link>` instead.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let importsRouter = false\n\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const info = extractImportInfo(node)\n if (info && info.source === '@pyreon/router') {\n importsRouter = true\n }\n },\n JSXOpeningElement(node: any) {\n if (!importsRouter) return\n const name = node.name\n if (!name || name.type !== 'JSXIdentifier' || name.name !== 'a') return\n\n const hrefAttr = getJSXAttribute(node, 'href')\n if (!hrefAttr) return\n\n // Get the href value\n const value = hrefAttr.value\n if (value?.type === 'Literal' && typeof value.value === 'string') {\n const href: string = value.value\n // Skip external URLs and anchor links\n if (href.startsWith('#') || EXTERNAL_PREFIXES.some((p) => href.startsWith(p))) return\n }\n\n context.report({\n message:\n '`<a href>` in a router file — use `<Link>` or `<RouterLink>` for client-side navigation.',\n span: getSpan(node),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo, isMemberCallTo } from '../../utils/ast'\n\nexport const noImperativeNavigateInRender: Rule = {\n meta: {\n id: 'pyreon/no-imperative-navigate-in-render',\n category: 'router',\n description:\n 'Error when navigate() or router.push() is called at the top level of a component — causes infinite render loops.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n // Track depth of component functions and safe callback wrappers\n // We detect components via VariableDeclarator with PascalCase name + ArrowFunctionExpression init,\n // or FunctionDeclaration with PascalCase name.\n // \"Safe\" = onMount/effect/onUnmount callbacks or JSX event handlers.\n let componentBodyDepth = 0\n let safeDepth = 0\n\n const callbacks: VisitorCallbacks = {\n FunctionDeclaration(node: any) {\n const name: string = node.id?.name ?? ''\n if (/^[A-Z]/.test(name)) {\n componentBodyDepth++\n }\n },\n 'FunctionDeclaration:exit'(node: any) {\n const name: string = node.id?.name ?? ''\n if (/^[A-Z]/.test(name)) {\n componentBodyDepth--\n }\n },\n // For arrow functions, we use VariableDeclarator to detect component assignment\n VariableDeclarator(node: any) {\n const name: string = node.id?.name ?? ''\n if (/^[A-Z]/.test(name) && node.init?.type === 'ArrowFunctionExpression') {\n componentBodyDepth++\n }\n },\n 'VariableDeclarator:exit'(node: any) {\n const name: string = node.id?.name ?? ''\n if (/^[A-Z]/.test(name) && node.init?.type === 'ArrowFunctionExpression') {\n componentBodyDepth--\n }\n },\n // Track safe callback boundaries: onMount(() => ...), effect(() => ...), etc.\n CallExpression(node: any) {\n if (componentBodyDepth <= 0) return\n\n // Check if this is a safe wrapper entering\n if (isSafeWrapperCall(node)) {\n safeDepth++\n }\n\n // Only report if we're in a component body and NOT inside a safe callback\n if (safeDepth > 0) return\n\n if (isCallTo(node, 'navigate') || isMemberCallTo(node, 'router', 'push')) {\n context.report({\n message:\n 'Imperative navigation at the top level of a component — this runs on every render and causes infinite loops. Move inside `onMount`, `effect`, or an event handler.',\n span: getSpan(node),\n })\n }\n },\n 'CallExpression:exit'(node: any) {\n if (componentBodyDepth <= 0) return\n if (isSafeWrapperCall(node)) {\n safeDepth--\n }\n },\n }\n return callbacks\n },\n}\n\nfunction isSafeWrapperCall(node: any): boolean {\n const callee = node.callee\n if (!callee || callee.type !== 'Identifier') return false\n const name: string = callee.name\n return name === 'onMount' || name === 'effect' || name === 'onUnmount'\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\nimport { extractImportInfo } from '../../utils/imports'\n\nfunction isCatchAllPath(value: string): boolean {\n return value === '*' || value.endsWith('*')\n}\n\nfunction getPathValue(prop: any): string | null {\n const key = prop.key\n if (!key) return null\n const keyName = key.type === 'Identifier' ? key.name : null\n if (keyName !== 'path') return null\n const val = prop.value\n if (val?.type === 'Literal' && typeof val.value === 'string') {\n return val.value\n }\n return null\n}\n\nfunction hasPathProperty(obj: any): boolean {\n if (!obj || obj.type !== 'ObjectExpression') return false\n for (const prop of obj.properties ?? []) {\n if (prop.type !== 'Property') continue\n if (getPathValue(prop) !== null) return true\n }\n return false\n}\n\nfunction hasCatchAllRoute(elements: any[]): boolean {\n for (const elem of elements) {\n if (!elem || elem.type !== 'ObjectExpression') continue\n for (const prop of elem.properties ?? []) {\n if (prop.type !== 'Property') continue\n const pathVal = getPathValue(prop)\n if (pathVal !== null && isCatchAllPath(pathVal)) return true\n }\n }\n return false\n}\n\nexport const noMissingFallback: Rule = {\n meta: {\n id: 'pyreon/no-missing-fallback',\n category: 'router',\n description:\n 'Warn when route config has no catch-all route (`path: \"*\"` or `path: \"/:rest*\"`).',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let importsRouter = false\n let routeArraySpan: { start: number; end: number } | null = null\n let foundCatchAll = false\n\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const info = extractImportInfo(node)\n if (info && info.source === '@pyreon/router') {\n importsRouter = true\n }\n },\n ArrayExpression(node: any) {\n if (!importsRouter) return\n const elements = node.elements ?? []\n const isRouteArray = elements.some((e: any) => hasPathProperty(e))\n if (!isRouteArray) return\n\n if (!routeArraySpan) {\n routeArraySpan = getSpan(node)\n }\n if (hasCatchAllRoute(elements)) {\n foundCatchAll = true\n }\n },\n 'Program:exit'() {\n if (!importsRouter || !routeArraySpan || foundCatchAll) return\n context.report({\n message:\n 'Route config has no catch-all route — add a `{ path: \"*\", component: NotFound }` for unmatched URLs.',\n span: routeArraySpan,\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const preferUseIsActive: Rule = {\n meta: {\n id: 'pyreon/prefer-use-is-active',\n category: 'router',\n description:\n 'Suggest useIsActive() instead of `location.pathname === \"/foo\"` or `route.path === \"/foo\"` patterns.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n BinaryExpression(node: any) {\n if (node.operator !== '===' && node.operator !== '==') return\n\n // Check both sides for location.pathname or route.path\n if (isPathComparison(node.left) || isPathComparison(node.right)) {\n context.report({\n message:\n 'Manual path comparison — use `useIsActive()` for reactive route matching with segment-aware prefix matching.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n\nfunction isPathComparison(node: any): boolean {\n if (!node || node.type !== 'MemberExpression') return false\n const obj = node.object\n const prop = node.property\n if (!obj || !prop || prop.type !== 'Identifier') return false\n\n // location.pathname\n if (obj.type === 'Identifier' && obj.name === 'location' && prop.name === 'pathname') return true\n\n // route.path\n if (obj.type === 'Identifier' && obj.name === 'route' && prop.name === 'path') return true\n\n return false\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isMemberCallTo } from '../../utils/ast'\n\nexport const noMismatchRisk: Rule = {\n meta: {\n id: 'pyreon/no-mismatch-risk',\n category: 'ssr',\n description:\n 'Warn about non-deterministic calls (Date.now, Math.random, crypto.randomUUID) in JSX context that cause hydration mismatches.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let jsxDepth = 0\n const callbacks: VisitorCallbacks = {\n JSXElement() {\n jsxDepth++\n },\n 'JSXElement:exit'() {\n jsxDepth--\n },\n JSXFragment() {\n jsxDepth++\n },\n 'JSXFragment:exit'() {\n jsxDepth--\n },\n CallExpression(node: any) {\n if (jsxDepth === 0) return\n\n if (\n isMemberCallTo(node, 'Date', 'now') ||\n isMemberCallTo(node, 'Math', 'random') ||\n isMemberCallTo(node, 'crypto', 'randomUUID')\n ) {\n const callee = node.callee\n const name = `${callee.object.name}.${callee.property.name}`\n context.report({\n message: `\\`${name}()\\` in JSX context — this produces different values on server and client, causing hydration mismatches.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\nimport { BROWSER_GLOBALS } from '../../utils/imports'\n\nexport const noWindowInSsr: Rule = {\n meta: {\n id: 'pyreon/no-window-in-ssr',\n category: 'ssr',\n description: 'Disallow browser globals outside onMount/effect/typeof guards — they break SSR.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n let safeDepth = 0\n let typeofGuardDepth = 0\n\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (isCallTo(node, 'onMount') || isCallTo(node, 'effect')) {\n safeDepth++\n }\n },\n 'CallExpression:exit'(node: any) {\n if (isCallTo(node, 'onMount') || isCallTo(node, 'effect')) {\n safeDepth--\n }\n },\n IfStatement(node: any) {\n // typeof window !== \"undefined\"\n const test = node.test\n if (\n test?.type === 'BinaryExpression' &&\n test.left?.type === 'UnaryExpression' &&\n test.left.operator === 'typeof'\n ) {\n typeofGuardDepth++\n }\n },\n 'IfStatement:exit'(node: any) {\n const test = node.test\n if (\n test?.type === 'BinaryExpression' &&\n test.left?.type === 'UnaryExpression' &&\n test.left.operator === 'typeof'\n ) {\n typeofGuardDepth--\n }\n },\n Identifier(node: any, parent: any) {\n if (safeDepth > 0 || typeofGuardDepth > 0) return\n if (!BROWSER_GLOBALS.has(node.name)) return\n\n // Skip typeof expressions: typeof window\n if (parent?.type === 'UnaryExpression' && parent.operator === 'typeof') return\n\n // Skip import specifiers\n if (\n parent?.type === 'ImportSpecifier' ||\n parent?.type === 'ImportDefaultSpecifier' ||\n parent?.type === 'ImportNamespaceSpecifier'\n )\n return\n\n // Skip property access on member expressions (only flag when used as the object)\n if (parent?.type === 'MemberExpression' && parent.property === node && !parent.computed)\n return\n\n context.report({\n message: `Browser global \\`${node.name}\\` used outside \\`onMount\\`/\\`effect\\`/typeof guard — this will fail during SSR. Wrap in \\`onMount(() => { ... })\\`.`,\n span: getSpan(node),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const preferRequestContext: Rule = {\n meta: {\n id: 'pyreon/prefer-request-context',\n category: 'ssr',\n description:\n 'Warn about module-level signal()/createStore() in server files — use request context instead.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const filePath = context.getFilePath()\n const isServerFile =\n filePath.includes('server') ||\n filePath.includes('.server.') ||\n filePath.endsWith('server.ts') ||\n filePath.endsWith('server.tsx')\n\n if (!isServerFile) return {}\n\n let functionDepth = 0\n const callbacks: VisitorCallbacks = {\n FunctionDeclaration() {\n functionDepth++\n },\n 'FunctionDeclaration:exit'() {\n functionDepth--\n },\n FunctionExpression() {\n functionDepth++\n },\n 'FunctionExpression:exit'() {\n functionDepth--\n },\n ArrowFunctionExpression() {\n functionDepth++\n },\n 'ArrowFunctionExpression:exit'() {\n functionDepth--\n },\n CallExpression(node: any) {\n if (functionDepth > 0) return // only flag module-level calls\n if (isCallTo(node, 'signal') || isCallTo(node, 'createStore')) {\n const name = node.callee.name\n context.report({\n message: `Module-level \\`${name}()\\` in a server file — this state is shared across all requests. Use \\`runWithRequestContext()\\` for per-request isolation.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noDuplicateStoreId: Rule = {\n meta: {\n id: 'pyreon/no-duplicate-store-id',\n category: 'store',\n description: 'Disallow duplicate defineStore() IDs in the same file.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n const storeIds = new Map<string, { start: number; end: number }>()\n\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (!isCallTo(node, 'defineStore')) return\n const args = node.arguments\n if (!args || args.length === 0) return\n\n const firstArg = args[0]\n if (!firstArg) return\n\n let id: string | null = null\n if (firstArg.type === 'Literal' || firstArg.type === 'StringLiteral') {\n id = firstArg.value as string\n }\n\n if (typeof id !== 'string') return\n\n if (storeIds.has(id)) {\n context.report({\n message: `Duplicate store ID \\`\"${id}\"\\` — each \\`defineStore()\\` must have a unique ID.`,\n span: getSpan(node),\n })\n } else {\n storeIds.set(id, getSpan(node))\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const noMutateStoreState: Rule = {\n meta: {\n id: 'pyreon/no-mutate-store-state',\n category: 'store',\n description: 'Warn when directly calling .set() on store signals — use store actions instead.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n const callee = node.callee\n if (!callee || callee.type !== 'MemberExpression') return\n if (callee.property?.type !== 'Identifier' || callee.property.name !== 'set') return\n\n // Check for store.signal.set() pattern — member.member.set()\n const obj = callee.object\n if (!obj || obj.type !== 'MemberExpression') return\n const outerObj = obj.object\n if (!outerObj || outerObj.type !== 'Identifier') return\n\n const name: string = outerObj.name\n // Heuristic: if the outer object name contains \"store\" (case-insensitive)\n if (name.toLowerCase().includes('store')) {\n context.report({\n message: `Direct \\`.set()\\` on store state \\`${name}\\` — use store actions to mutate state for better traceability.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\nimport { extractImportInfo } from '../../utils/imports'\n\nexport const noStoreOutsideProvider: Rule = {\n meta: {\n id: 'pyreon/no-store-outside-provider',\n category: 'store',\n description: 'Warn when store hooks are used in SSR files without a provider import.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const filePath = context.getFilePath()\n const isServerFile =\n filePath.includes('server') ||\n filePath.includes('.server.') ||\n filePath.endsWith('server.ts') ||\n filePath.endsWith('server.tsx')\n\n if (!isServerFile) return {}\n\n let hasProviderImport = false\n const storeHookCalls: Array<{ name: string; span: { start: number; end: number } }> = []\n\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const info = extractImportInfo(node)\n if (!info) return\n if (\n info.specifiers.some(\n (s) =>\n s.imported === 'setStoreRegistryProvider' || s.imported === 'runWithRequestContext',\n )\n ) {\n hasProviderImport = true\n }\n },\n CallExpression(node: any) {\n const callee = node.callee\n if (!callee || callee.type !== 'Identifier') return\n const name: string = callee.name\n if (name.endsWith('Store') && name.startsWith('use')) {\n storeHookCalls.push({ name, span: getSpan(node) })\n }\n },\n 'Program:exit'() {\n if (hasProviderImport) return\n for (const call of storeHookCalls) {\n context.report({\n message: `\\`${call.name}()\\` in a server file without a store registry provider — use \\`runWithRequestContext()\\` or \\`setStoreRegistryProvider()\\` for SSR isolation.`,\n span: call.span,\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noDynamicStyled: Rule = {\n meta: {\n id: 'pyreon/no-dynamic-styled',\n category: 'styling',\n description:\n 'Warn when styled() is called inside a function — it creates new CSS on every render.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let functionDepth = 0\n const callbacks: VisitorCallbacks = {\n FunctionDeclaration() {\n functionDepth++\n },\n 'FunctionDeclaration:exit'() {\n functionDepth--\n },\n FunctionExpression() {\n functionDepth++\n },\n 'FunctionExpression:exit'() {\n functionDepth--\n },\n ArrowFunctionExpression() {\n functionDepth++\n },\n 'ArrowFunctionExpression:exit'() {\n functionDepth--\n },\n CallExpression(node: any) {\n if (functionDepth === 0) return\n if (isCallTo(node, 'styled')) {\n context.report({\n message:\n '`styled()` inside a function — this creates new CSS rules on every render. Move `styled()` to module scope.',\n span: getSpan(node),\n })\n }\n },\n TaggedTemplateExpression(node: any) {\n if (functionDepth === 0) return\n const tag = node.tag\n if (!tag) return\n // styled('div')`...` — tag is a CallExpression of styled\n if (tag.type === 'CallExpression' && isCallTo(tag, 'styled')) {\n context.report({\n message:\n '`styled()` tagged template inside a function — this creates new CSS rules on every render. Move to module scope.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const noInlineStyleObject: Rule = {\n meta: {\n id: 'pyreon/no-inline-style-object',\n category: 'styling',\n description: 'Warn against inline style objects in JSX — prefer styled() or css``.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXAttribute(node: any) {\n if (node.name?.type !== 'JSXIdentifier' || node.name.name !== 'style') return\n const value = node.value\n if (!value || value.type !== 'JSXExpressionContainer') return\n const expr = value.expression\n if (expr?.type === 'ObjectExpression') {\n context.report({\n message:\n 'Inline style object in JSX — consider using `styled()` or `css\\\\`...\\\\`` for better performance and caching.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\nimport { extractImportInfo } from '../../utils/imports'\n\nexport const noThemeOutsideProvider: Rule = {\n meta: {\n id: 'pyreon/no-theme-outside-provider',\n category: 'styling',\n description: 'Warn when useTheme() is used without PyreonUI or ThemeProvider in the same file.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let hasProviderImport = false\n const themeCalls: Array<{ span: { start: number; end: number } }> = []\n\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const info = extractImportInfo(node)\n if (!info) return\n if (\n info.specifiers.some((s) => s.imported === 'PyreonUI' || s.imported === 'ThemeProvider')\n ) {\n hasProviderImport = true\n }\n },\n CallExpression(node: any) {\n if (isCallTo(node, 'useTheme')) {\n themeCalls.push({ span: getSpan(node) })\n }\n },\n 'Program:exit'() {\n if (hasProviderImport) return\n for (const call of themeCalls) {\n context.report({\n message:\n '`useTheme()` without a `PyreonUI` or `ThemeProvider` import — the theme context may not be available.',\n span: call.span,\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const preferCx: Rule = {\n meta: {\n id: 'pyreon/prefer-cx',\n category: 'styling',\n description:\n 'Suggest cx() for class composition instead of string concatenation or template literals.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXAttribute(node: any) {\n if (node.name?.type !== 'JSXIdentifier' || node.name.name !== 'class') return\n const value = node.value\n if (!value || value.type !== 'JSXExpressionContainer') return\n const expr = value.expression\n if (!expr) return\n\n // String concatenation: \"foo \" + bar\n if (expr.type === 'BinaryExpression' && expr.operator === '+') {\n context.report({\n message:\n 'String concatenation in `class` attribute — use `cx()` for cleaner class composition.',\n span: getSpan(expr),\n })\n return\n }\n\n // Template literal: `foo ${bar}`\n if (expr.type === 'TemplateLiteral' && expr.expressions?.length > 0) {\n context.report({\n message:\n 'Template literal in `class` attribute — use `cx()` for cleaner class composition.',\n span: getSpan(expr),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule } from '../types'\nimport { dialogA11y } from './accessibility/dialog-a11y'\nimport { overlayA11y } from './accessibility/overlay-a11y'\n// Accessibility\nimport { toastA11y } from './accessibility/toast-a11y'\nimport { devGuardWarnings } from './architecture/dev-guard-warnings'\n// Architecture\nimport { noCircularImport } from './architecture/no-circular-import'\nimport { noCrossLayerImport } from './architecture/no-cross-layer-import'\nimport { noDeepImport } from './architecture/no-deep-import'\nimport { noErrorWithoutPrefix } from './architecture/no-error-without-prefix'\nimport { noSubmitWithoutValidation } from './form/no-submit-without-validation'\n// Form\nimport { noUnregisteredField } from './form/no-unregistered-field'\nimport { preferFieldArray } from './form/prefer-field-array'\n// Hooks\nimport { noRawAddEventListener } from './hooks/no-raw-addeventlistener'\nimport { noRawLocalStorage } from './hooks/no-raw-localstorage'\nimport { noRawSetInterval } from './hooks/no-raw-setinterval'\nimport { noAndConditional } from './jsx/no-and-conditional'\nimport { noChildrenAccess } from './jsx/no-children-access'\nimport { noClassName } from './jsx/no-classname'\nimport { noHtmlFor } from './jsx/no-htmlfor'\nimport { noIndexAsBy } from './jsx/no-index-as-by'\n// JSX\nimport { noMapInJsx } from './jsx/no-map-in-jsx'\nimport { noMissingForBy } from './jsx/no-missing-for-by'\nimport { noOnChange } from './jsx/no-onchange'\nimport { noPropsDestructure } from './jsx/no-props-destructure'\nimport { noTernaryConditional } from './jsx/no-ternary-conditional'\nimport { useByNotKey } from './jsx/use-by-not-key'\nimport { noDomInSetup } from './lifecycle/no-dom-in-setup'\nimport { noEffectInMount } from './lifecycle/no-effect-in-mount'\n// Lifecycle\nimport { noMissingCleanup } from './lifecycle/no-missing-cleanup'\nimport { noMountInEffect } from './lifecycle/no-mount-in-effect'\nimport { noEagerImport } from './performance/no-eager-import'\nimport { noEffectInFor } from './performance/no-effect-in-for'\n// Performance\nimport { noLargeForWithoutBy } from './performance/no-large-for-without-by'\nimport { preferShowOverDisplay } from './performance/prefer-show-over-display'\n// Reactivity\nimport { noBareSignalInJsx } from './reactivity/no-bare-signal-in-jsx'\nimport { noContextDestructure } from './reactivity/no-context-destructure'\nimport { noEffectAssignment } from './reactivity/no-effect-assignment'\nimport { noNestedEffect } from './reactivity/no-nested-effect'\nimport { noPeekInTracked } from './reactivity/no-peek-in-tracked'\nimport { noSignalInLoop } from './reactivity/no-signal-in-loop'\nimport { noSignalInProps } from './reactivity/no-signal-in-props'\nimport { noSignalLeak } from './reactivity/no-signal-leak'\nimport { noUnbatchedUpdates } from './reactivity/no-unbatched-updates'\nimport { preferComputed } from './reactivity/prefer-computed'\n// Router\nimport { noHrefNavigation } from './router/no-href-navigation'\nimport { noImperativeNavigateInRender } from './router/no-imperative-navigate-in-render'\nimport { noMissingFallback } from './router/no-missing-fallback'\nimport { preferUseIsActive } from './router/prefer-use-is-active'\nimport { noMismatchRisk } from './ssr/no-mismatch-risk'\n// SSR\nimport { noWindowInSsr } from './ssr/no-window-in-ssr'\nimport { preferRequestContext } from './ssr/prefer-request-context'\nimport { noDuplicateStoreId } from './store/no-duplicate-store-id'\nimport { noMutateStoreState } from './store/no-mutate-store-state'\n// Store\nimport { noStoreOutsideProvider } from './store/no-store-outside-provider'\nimport { noDynamicStyled } from './styling/no-dynamic-styled'\n// Styling\nimport { noInlineStyleObject } from './styling/no-inline-style-object'\nimport { noThemeOutsideProvider } from './styling/no-theme-outside-provider'\nimport { preferCx } from './styling/prefer-cx'\n\nexport const allRules: Rule[] = [\n // Reactivity (10)\n noBareSignalInJsx,\n noContextDestructure,\n noSignalInLoop,\n noSignalInProps,\n noNestedEffect,\n noPeekInTracked,\n noUnbatchedUpdates,\n preferComputed,\n noEffectAssignment,\n noSignalLeak,\n // JSX (11)\n noMapInJsx,\n useByNotKey,\n noClassName,\n noHtmlFor,\n noOnChange,\n noTernaryConditional,\n noAndConditional,\n noIndexAsBy,\n noMissingForBy,\n noPropsDestructure,\n noChildrenAccess,\n // Lifecycle (4)\n noMissingCleanup,\n noMountInEffect,\n noEffectInMount,\n noDomInSetup,\n // Performance (4)\n noLargeForWithoutBy,\n noEffectInFor,\n noEagerImport,\n preferShowOverDisplay,\n // SSR (3)\n noWindowInSsr,\n noMismatchRisk,\n preferRequestContext,\n // Architecture (5)\n noCircularImport,\n noDeepImport,\n noCrossLayerImport,\n devGuardWarnings,\n noErrorWithoutPrefix,\n // Store (3)\n noStoreOutsideProvider,\n noMutateStoreState,\n noDuplicateStoreId,\n // Form (3)\n noUnregisteredField,\n noSubmitWithoutValidation,\n preferFieldArray,\n // Styling (4)\n noInlineStyleObject,\n noDynamicStyled,\n preferCx,\n noThemeOutsideProvider,\n // Hooks (3)\n noRawAddEventListener,\n noRawSetInterval,\n noRawLocalStorage,\n // Accessibility (3)\n toastA11y,\n dialogA11y,\n overlayA11y,\n // Router (4)\n noHrefNavigation,\n noImperativeNavigateInRender,\n noMissingFallback,\n preferUseIsActive,\n]\n\n// Re-export all rules individually\nexport {\n devGuardWarnings,\n dialogA11y,\n noAndConditional,\n // Reactivity\n noBareSignalInJsx,\n noContextDestructure,\n noChildrenAccess,\n // Architecture\n noCircularImport,\n noClassName,\n noCrossLayerImport,\n noDeepImport,\n noDomInSetup,\n noDuplicateStoreId,\n noDynamicStyled,\n noEagerImport,\n noEffectAssignment,\n noEffectInFor,\n noEffectInMount,\n noErrorWithoutPrefix,\n noHrefNavigation,\n noHtmlFor,\n noImperativeNavigateInRender,\n noIndexAsBy,\n // Styling\n noInlineStyleObject,\n // Performance\n noLargeForWithoutBy,\n // JSX\n noMapInJsx,\n noMismatchRisk,\n // Lifecycle\n noMissingCleanup,\n noMissingFallback,\n noMissingForBy,\n noMountInEffect,\n noMutateStoreState,\n noNestedEffect,\n noOnChange,\n noPeekInTracked,\n noPropsDestructure,\n // Hooks\n noRawAddEventListener,\n noRawLocalStorage,\n noRawSetInterval,\n noSignalInLoop,\n noSignalInProps,\n noSignalLeak,\n // Store\n noStoreOutsideProvider,\n noSubmitWithoutValidation,\n noTernaryConditional,\n noThemeOutsideProvider,\n noUnbatchedUpdates,\n // Form\n noUnregisteredField,\n // SSR\n noWindowInSsr,\n overlayA11y,\n preferComputed,\n preferCx,\n preferFieldArray,\n preferRequestContext,\n preferShowOverDisplay,\n preferUseIsActive,\n // Accessibility\n toastA11y,\n useByNotKey,\n}\n","import { allRules } from '../rules/index'\nimport type { LintConfig, PresetName, Severity } from '../types'\n\n/** Build a config where every rule uses its default severity. */\nfunction buildRecommended(): LintConfig {\n const rules: Record<string, Severity> = {}\n for (const rule of allRules) {\n rules[rule.meta.id] = rule.meta.severity\n }\n return { rules }\n}\n\n/** Build a config where every warn is promoted to error. */\nfunction buildStrict(): LintConfig {\n const base = buildRecommended()\n const rules: Record<string, Severity> = {}\n for (const [id, sev] of Object.entries(base.rules)) {\n rules[id] = sev === 'warn' ? 'error' : sev\n }\n return { rules }\n}\n\n/** Build app config — recommended but disable library-only rules. */\nfunction buildApp(): LintConfig {\n const base = buildRecommended()\n return {\n rules: {\n ...base.rules,\n 'pyreon/dev-guard-warnings': 'off',\n 'pyreon/no-error-without-prefix': 'off',\n 'pyreon/no-circular-import': 'off',\n 'pyreon/no-cross-layer-import': 'off',\n },\n }\n}\n\n/** Build lib config — strict + all architecture rules as error. */\nfunction buildLib(): LintConfig {\n const base = buildStrict()\n return {\n rules: {\n ...base.rules,\n 'pyreon/no-circular-import': 'error',\n 'pyreon/no-cross-layer-import': 'error',\n 'pyreon/dev-guard-warnings': 'error',\n 'pyreon/no-error-without-prefix': 'error',\n },\n }\n}\n\nconst presetBuilders: Record<PresetName, () => LintConfig> = {\n recommended: buildRecommended,\n strict: buildStrict,\n app: buildApp,\n lib: buildLib,\n}\n\nexport function getPreset(name: PresetName): LintConfig {\n return presetBuilders[name]()\n}\n\nexport { buildApp, buildLib, buildRecommended, buildStrict }\n","import type { SourceLocation } from '../types'\n\n/**\n * Fast offset→line/column conversion using binary search over precomputed line starts.\n */\nexport class LineIndex {\n private lineStarts: number[]\n\n constructor(sourceText: string) {\n this.lineStarts = [0]\n for (let i = 0; i < sourceText.length; i++) {\n if (sourceText[i] === '\\n') {\n this.lineStarts.push(i + 1)\n }\n }\n }\n\n /** Convert a byte offset to a 1-based line and 0-based column. */\n locate(offset: number): SourceLocation {\n let lo = 0\n let hi = this.lineStarts.length - 1\n\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1\n if ((this.lineStarts[mid] as number) <= offset) {\n lo = mid + 1\n } else {\n hi = mid - 1\n }\n }\n\n const line = lo // 1-based (lo points one past the found index)\n const column = offset - (this.lineStarts[line - 1] as number)\n return { line, column }\n }\n}\n","export {\n getJSXAttribute,\n getJSXTagName,\n getSpan,\n hasJSXAttribute,\n hasJSXChild,\n isArrayMapCall,\n isBrowserGlobal,\n isCallTo,\n isCallToAny,\n isDestructuring,\n isFunction,\n isInsideDevGuard,\n isInsideFunction,\n isInsideJSX,\n isInsideOnMount,\n isInsideTypeofGuard,\n isJSXElement,\n isLogicalAndWithJSX,\n isMemberCallTo,\n isPeekCall,\n isSetCall,\n isTernaryWithJSX,\n} from './ast'\nexport {\n BROWSER_GLOBALS,\n CONTEXT_APIS,\n extractImportInfo,\n getLocalName,\n HEAVY_PACKAGES,\n importsName,\n isPyreonImport,\n isPyreonPackage,\n JSX_COMPONENTS,\n LIFECYCLE_APIS,\n PYREON_PREFIX,\n REACTIVITY_APIS,\n} from './imports'\nexport { LineIndex } from './source'\n\n/** Supported JS/TS file extensions for linting. */\nexport const JS_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mts', '.mjs'])\n\n/** Check if a file path has a supported JS/TS extension. */\nexport function hasJsExtension(filePath: string): boolean {\n const ext = filePath.slice(filePath.lastIndexOf('.'))\n return JS_EXTENSIONS.has(ext)\n}\n","import { parseSync, Visitor } from 'oxc-parser'\nimport type { AstCache } from './cache'\nimport type {\n Diagnostic,\n LintConfig,\n LintFileResult,\n Rule,\n RuleContext,\n Severity,\n VisitorCallbacks,\n} from './types'\nimport { JS_EXTENSIONS } from './utils/index'\nimport { LineIndex } from './utils/source'\n\nfunction getExtension(filePath: string): string {\n const lastDot = filePath.lastIndexOf('.')\n return lastDot === -1 ? '' : filePath.slice(lastDot)\n}\n\ntype OxcLang = 'jsx' | 'tsx' | 'ts' | 'js' | 'dts'\n\nfunction getLang(ext: string): OxcLang {\n if (ext === '.tsx' || ext === '.jsx') return 'tsx'\n if (ext === '.ts' || ext === '.mts') return 'ts'\n return 'js'\n}\n\nfunction createRuleContext(\n rule: Rule,\n severity: Severity,\n diagnostics: Diagnostic[],\n lineIndex: LineIndex,\n sourceText: string,\n filePath: string,\n): RuleContext {\n return {\n report(partial) {\n diagnostics.push({\n ruleId: rule.meta.id,\n severity,\n message: partial.message,\n span: partial.span,\n loc: lineIndex.locate(partial.span.start),\n fix: partial.fix,\n })\n },\n getSourceText() {\n return sourceText\n },\n getFilePath() {\n return filePath\n },\n }\n}\n\nfunction mergeCallbacks(allCallbacks: VisitorCallbacks[]): Record<string, (node: any) => void> {\n const callbacksByKey: Record<string, Array<(node: any) => void>> = {}\n\n for (const callbacks of allCallbacks) {\n for (const [key, fn] of Object.entries(callbacks)) {\n const existing = callbacksByKey[key]\n if (existing) {\n existing.push(fn as (node: any) => void)\n } else {\n callbacksByKey[key] = [fn as (node: any) => void]\n }\n }\n }\n\n const merged: Record<string, (node: any) => void> = {}\n for (const [key, fns] of Object.entries(callbacksByKey)) {\n const first = fns[0]\n if (fns.length === 1 && first) {\n merged[key] = first\n } else {\n merged[key] = (node: any) => {\n for (const fn of fns) fn(node)\n }\n }\n }\n return merged\n}\n\n/**\n * Lint a single file and return diagnostics.\n *\n * @example\n * ```ts\n * const result = lintFile(\"app.tsx\", source, allRules, getPreset(\"recommended\"))\n * for (const d of result.diagnostics) console.log(d.message)\n * ```\n */\nexport function lintFile(\n filePath: string,\n sourceText: string,\n rules: Rule[],\n config: LintConfig,\n cache?: AstCache | undefined,\n): LintFileResult {\n const ext = getExtension(filePath)\n if (!JS_EXTENSIONS.has(ext)) {\n return { filePath, diagnostics: [] }\n }\n\n // Try cache first\n let lineIndex: LineIndex\n let program: any\n const cached = cache?.get(sourceText)\n if (cached) {\n lineIndex = cached.lineIndex\n program = cached.program\n } else {\n lineIndex = new LineIndex(sourceText)\n try {\n const result = parseSync(filePath, sourceText, {\n sourceType: 'module',\n lang: getLang(ext),\n })\n program = result.program\n } catch {\n return { filePath, diagnostics: [] }\n }\n cache?.set(sourceText, { program, lineIndex })\n }\n\n const diagnostics: Diagnostic[] = []\n\n // Filter to enabled rules and create visitor callbacks\n const allCallbacks: VisitorCallbacks[] = []\n for (const rule of rules) {\n const severity = config.rules[rule.meta.id]\n if (severity === undefined || severity === 'off') continue\n const ctx = createRuleContext(rule, severity, diagnostics, lineIndex, sourceText, filePath)\n allCallbacks.push(rule.create(ctx))\n }\n\n // Walk the AST\n const visitor = new Visitor(mergeCallbacks(allCallbacks))\n visitor.visit(program)\n\n // Filter suppressed diagnostics:\n // // pyreon-lint-ignore — suppress all on next line\n // // pyreon-lint-ignore rule-name — suppress specific rule on next line\n const lines = sourceText.split('\\n')\n const filtered = diagnostics.filter((d) => {\n const prevLineIdx = d.loc.line - 2\n if (prevLineIdx < 0) return true\n const prevLine = lines[prevLineIdx]?.trim()\n if (!prevLine?.startsWith('// pyreon-lint-ignore')) return true\n const rest = prevLine.slice('// pyreon-lint-ignore'.length).trim()\n return rest.length > 0 && rest !== d.ruleId\n })\n\n filtered.sort((a, b) => a.span.start - b.span.start)\n return { filePath, diagnostics: filtered }\n}\n\n/**\n * Apply all auto-fixes to a source text.\n * Fixes are applied in reverse order to maintain correct offsets.\n */\nexport function applyFixes(sourceText: string, diagnostics: Diagnostic[]): string {\n const fixable = diagnostics.filter((d) => d.fix !== undefined)\n if (fixable.length === 0) return sourceText\n\n // Sort by start position descending (apply from end to start)\n const sorted = [...fixable].sort((a, b) => {\n const aFix = a.fix\n const bFix = b.fix\n if (!aFix || !bFix) return 0\n return bFix.span.start - aFix.span.start\n })\n\n let result = sourceText\n for (const diag of sorted) {\n const fix = diag.fix\n if (!fix) continue\n result = result.slice(0, fix.span.start) + fix.replacement + result.slice(fix.span.end)\n }\n\n return result\n}\n","import { readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'\nimport { join, resolve } from 'node:path'\nimport { AstCache } from './cache'\nimport { createIgnoreFilter } from './config/ignore'\nimport { loadConfig, loadConfigFromPath } from './config/loader'\nimport { getPreset } from './config/presets'\nimport { allRules } from './rules/index'\nimport { applyFixes, lintFile } from './runner'\nimport type { LintConfig, LintFileResult, LintOptions, LintResult, RuleMeta } from './types'\nimport { hasJsExtension } from './utils/index'\n\nfunction isHiddenOrVendor(entry: string): boolean {\n return entry.startsWith('.') || entry === 'node_modules' || entry === 'lib' || entry === 'dist'\n}\n\nfunction matchesPatterns(\n filePath: string,\n include?: string[] | undefined,\n exclude?: string[] | undefined,\n): boolean {\n if (exclude) {\n for (const pattern of exclude) {\n if (filePath.includes(pattern)) return false\n }\n }\n if (include && include.length > 0) {\n for (const pattern of include) {\n if (filePath.includes(pattern)) return true\n }\n return false\n }\n return true\n}\n\nfunction walkDirectory(\n dir: string,\n files: string[],\n isIgnored: (filePath: string) => boolean,\n include?: string[] | undefined,\n exclude?: string[] | undefined,\n): void {\n let entries: string[]\n try {\n entries = readdirSync(dir)\n } catch {\n return\n }\n for (const entry of entries) {\n if (isHiddenOrVendor(entry)) continue\n const full = join(dir, entry)\n if (isIgnored(full)) continue\n processEntry(full, files, isIgnored, include, exclude)\n }\n}\n\nfunction processEntry(\n full: string,\n files: string[],\n isIgnored: (filePath: string) => boolean,\n include?: string[] | undefined,\n exclude?: string[] | undefined,\n): void {\n let stat: ReturnType<typeof statSync>\n try {\n stat = statSync(full)\n } catch {\n return\n }\n if (stat.isDirectory()) {\n walkDirectory(full, files, isIgnored, include, exclude)\n } else if (stat.isFile() && hasJsExtension(full) && matchesPatterns(full, include, exclude)) {\n files.push(full)\n }\n}\n\nfunction collectFiles(\n dir: string,\n isIgnored: (filePath: string) => boolean,\n include?: string[] | undefined,\n exclude?: string[] | undefined,\n): string[] {\n const files: string[] = []\n walkDirectory(dir, files, isIgnored, include, exclude)\n return files\n}\n\nfunction buildConfig(options: LintOptions): {\n config: LintConfig\n include: string[] | undefined\n exclude: string[] | undefined\n isIgnored: (filePath: string) => boolean\n} {\n const cwd = resolve('.')\n const fileConfig = options.config ? loadConfigFromPath(options.config) : loadConfig(cwd)\n\n const presetName = options.preset ?? fileConfig?.preset ?? 'recommended'\n const config = getPreset(presetName)\n\n // Merge config file rule overrides\n if (fileConfig?.rules) {\n for (const [id, severity] of Object.entries(fileConfig.rules)) {\n config.rules[id] = severity\n }\n }\n\n // CLI rule overrides (highest priority)\n if (options.ruleOverrides) {\n for (const [id, severity] of Object.entries(options.ruleOverrides)) {\n config.rules[id] = severity\n }\n }\n\n return {\n config,\n include: fileConfig?.include,\n exclude: fileConfig?.exclude,\n isIgnored: createIgnoreFilter(cwd, options.ignore),\n }\n}\n\nfunction gatherFiles(\n paths: string[],\n isIgnored: (filePath: string) => boolean,\n include?: string[] | undefined,\n exclude?: string[] | undefined,\n): string[] {\n const files: string[] = []\n for (const p of paths) {\n const resolved = resolve(p)\n let stat: ReturnType<typeof statSync>\n try {\n stat = statSync(resolved)\n } catch {\n continue\n }\n if (stat.isDirectory()) {\n files.push(...collectFiles(resolved, isIgnored, include, exclude))\n } else if (stat.isFile() && !isIgnored(resolved)) {\n files.push(resolved)\n }\n }\n return files\n}\n\nfunction applyFixesToFile(fileResult: LintFileResult, source: string): void {\n const fixable = fileResult.diagnostics.filter((d) => d.fix)\n if (fixable.length === 0) return\n const fixed = applyFixes(source, fileResult.diagnostics)\n writeFileSync(fileResult.filePath, fixed, 'utf-8')\n fileResult.fixedSource = fixed\n fileResult.diagnostics = fileResult.diagnostics.filter((d) => !d.fix)\n}\n\nfunction countDiagnostics(fileResult: LintFileResult, results: LintResult): void {\n for (const d of fileResult.diagnostics) {\n if (d.severity === 'error') results.totalErrors++\n else if (d.severity === 'warn') results.totalWarnings++\n else if (d.severity === 'info') results.totalInfos++\n }\n}\n\n/**\n * Lint files and return results.\n *\n * @example\n * ```ts\n * import { lint } from \"@pyreon/lint\"\n *\n * const result = lint({ paths: [\"src/\"], preset: \"recommended\" })\n * console.log(result.totalErrors) // 0\n * ```\n */\nexport function lint(options: LintOptions): LintResult {\n const { config, include, exclude, isIgnored } = buildConfig(options)\n const cache = new AstCache()\n const files = gatherFiles(options.paths, isIgnored, include, exclude)\n\n const results: LintResult = {\n files: [],\n totalErrors: 0,\n totalWarnings: 0,\n totalInfos: 0,\n }\n\n for (const filePath of files) {\n let source: string\n try {\n source = readFileSync(filePath, 'utf-8')\n } catch {\n continue\n }\n const fileResult = lintFile(filePath, source, allRules, config, cache)\n if (options.fix) {\n applyFixesToFile(fileResult, source)\n }\n if (options.quiet) {\n fileResult.diagnostics = fileResult.diagnostics.filter((d) => d.severity === 'error')\n }\n countDiagnostics(fileResult, results)\n results.files.push(fileResult)\n }\n\n return results\n}\n\n/**\n * List all available rules with their metadata.\n *\n * @example\n * ```ts\n * import { listRules } from \"@pyreon/lint\"\n *\n * for (const rule of listRules()) {\n * console.log(`${rule.id} (${rule.severity}): ${rule.description}`)\n * }\n * ```\n */\nexport function listRules(): RuleMeta[] {\n return allRules.map((r) => r.meta)\n}\n","/**\n * Minimal LSP server for @pyreon/lint.\n *\n * Provides real-time Pyreon-specific diagnostics in editors that support\n * the Language Server Protocol (VS Code, Neovim, etc.).\n *\n * Usage: pyreon-lint --lsp\n *\n * The server communicates via JSON-RPC over stdin/stdout following the\n * LSP specification (https://microsoft.github.io/language-server-protocol/).\n *\n * Supported capabilities:\n * - textDocument/didOpen — lint on open\n * - textDocument/didSave — lint on save\n * - textDocument/didChange — lint on change (debounced)\n *\n * @module\n */\n\nimport { AstCache } from '../cache'\nimport { getPreset } from '../config/presets'\nimport { allRules } from '../rules/index'\nimport { lintFile } from '../runner'\nimport type { Diagnostic, LintConfig } from '../types'\n\nconst cache = new AstCache()\nconst config: LintConfig = getPreset('recommended')\n\n// ─── JSON-RPC message types ────────────────────────────────────────────────\n\ninterface JsonRpcMessage {\n jsonrpc: '2.0'\n id?: number | string | undefined\n method?: string | undefined\n params?: any\n result?: any\n}\n\n// ─── LSP Diagnostic conversion ─────────────────────────────────────────────\n\ninterface LspDiagnostic {\n range: { start: { line: number; character: number }; end: { line: number; character: number } }\n severity: number\n source: string\n message: string\n code: string\n}\n\nfunction toLspDiagnostics(diagnostics: Diagnostic[]): LspDiagnostic[] {\n return diagnostics.map((d) => ({\n range: {\n start: { line: d.loc.line - 1, character: d.loc.column - 1 },\n end: { line: d.loc.line - 1, character: d.loc.column - 1 + (d.span.end - d.span.start) },\n },\n severity: d.severity === 'error' ? 1 : d.severity === 'warn' ? 2 : 3,\n source: 'pyreon-lint',\n message: d.message,\n code: d.ruleId,\n }))\n}\n\n// ─── Lint a document ───────────────────────────────────────────────────────\n\nfunction lintDocument(uri: string, text: string): LspDiagnostic[] {\n try {\n const filePath = uri.replace('file://', '')\n const result = lintFile(filePath, text, allRules, config, cache)\n return toLspDiagnostics(result.diagnostics)\n } catch {\n // Parse errors, unsupported file types — return empty diagnostics\n return []\n }\n}\n\n// ─── Debounce ──────────────────────────────────────────────────────────────\n\nconst DEBOUNCE_MS = 150\nconst debounceTimers = new Map<string, ReturnType<typeof setTimeout>>()\n\nfunction debounceLint(uri: string, text: string): void {\n const existing = debounceTimers.get(uri)\n if (existing) clearTimeout(existing)\n debounceTimers.set(\n uri,\n setTimeout(() => {\n debounceTimers.delete(uri)\n const diagnostics = lintDocument(uri, text)\n sendNotification('textDocument/publishDiagnostics', { uri, diagnostics })\n }, DEBOUNCE_MS),\n )\n}\n\n// ─── Message handling ──────────────────────────────────────────────────────\n\nconst openDocuments = new Map<string, string>()\n\nfunction handleMessage(msg: JsonRpcMessage): JsonRpcMessage | null {\n if (msg.method === 'initialize') {\n return {\n jsonrpc: '2.0',\n id: msg.id,\n result: {\n capabilities: {\n textDocumentSync: 1, // Full sync\n diagnosticProvider: { interFileDependencies: false, workspaceDiagnostics: false },\n },\n serverInfo: { name: 'pyreon-lint', version: '0.11.5' },\n },\n }\n }\n\n if (msg.method === 'initialized') {\n return null // no response needed\n }\n\n if (msg.method === 'textDocument/didOpen') {\n const { uri, text } = msg.params.textDocument\n openDocuments.set(uri, text)\n const diagnostics = lintDocument(uri, text)\n sendNotification('textDocument/publishDiagnostics', { uri, diagnostics })\n return null\n }\n\n if (msg.method === 'textDocument/didChange') {\n const uri = msg.params.textDocument.uri\n const text = msg.params.contentChanges[0]?.text\n if (text != null) {\n openDocuments.set(uri, text)\n // Debounce: wait 150ms after last keystroke before linting\n debounceLint(uri, text)\n }\n return null\n }\n\n if (msg.method === 'textDocument/didSave') {\n const uri = msg.params.textDocument.uri\n const text = openDocuments.get(uri)\n if (text) {\n const diagnostics = lintDocument(uri, text)\n sendNotification('textDocument/publishDiagnostics', { uri, diagnostics })\n }\n return null\n }\n\n if (msg.method === 'textDocument/didClose') {\n const uri = msg.params.textDocument.uri\n openDocuments.delete(uri)\n sendNotification('textDocument/publishDiagnostics', { uri, diagnostics: [] })\n return null\n }\n\n if (msg.method === 'shutdown') {\n return { jsonrpc: '2.0', id: msg.id, result: null }\n }\n\n if (msg.method === 'exit') {\n process.exit(0)\n }\n\n // Unknown method\n if (msg.id != null) {\n return {\n jsonrpc: '2.0',\n id: msg.id,\n result: null,\n }\n }\n\n return null\n}\n\n// ─── JSON-RPC transport (stdin/stdout) ─────────────────────────────────────\n\nfunction sendMessage(msg: JsonRpcMessage) {\n const body = JSON.stringify(msg)\n const header = `Content-Length: ${Buffer.byteLength(body)}\\r\\n\\r\\n`\n process.stdout.write(header + body)\n}\n\nfunction sendNotification(method: string, params: any) {\n sendMessage({ jsonrpc: '2.0', method, params })\n}\n\n/**\n * Start the LSP server. Reads JSON-RPC messages from stdin,\n * processes them, and writes responses to stdout.\n */\nexport function startLspServer(): void {\n let buffer = ''\n\n process.stdin.setEncoding('utf-8')\n process.stdin.on('data', (chunk: string) => {\n buffer += chunk\n\n // Parse Content-Length header + body\n while (true) {\n const headerEnd = buffer.indexOf('\\r\\n\\r\\n')\n if (headerEnd === -1) break\n\n const header = buffer.slice(0, headerEnd)\n const match = header.match(/Content-Length:\\s*(\\d+)/i)\n if (!match) {\n buffer = buffer.slice(headerEnd + 4)\n continue\n }\n\n const contentLength = Number.parseInt(match[1]!, 10)\n const bodyStart = headerEnd + 4\n if (buffer.length < bodyStart + contentLength) break\n\n const body = buffer.slice(bodyStart, bodyStart + contentLength)\n buffer = buffer.slice(bodyStart + contentLength)\n\n try {\n const msg = JSON.parse(body) as JsonRpcMessage\n const response = handleMessage(msg)\n if (response) sendMessage(response)\n } catch {\n // malformed JSON — ignore\n }\n }\n })\n\n process.stderr.write('[pyreon-lint] LSP server started\\n')\n}\n","import type { LintResult, Severity } from './types'\n\n// ANSI colors\nconst BOLD = '\\x1b[1m'\nconst RED = '\\x1b[31m'\nconst YELLOW = '\\x1b[33m'\nconst BLUE = '\\x1b[34m'\nconst DIM = '\\x1b[2m'\nconst RESET = '\\x1b[0m'\n\nconst SEVERITY_SYMBOL: Record<Severity, string> = {\n error: `${RED}\\u2716${RESET}`,\n warn: `${YELLOW}\\u26A0${RESET}`,\n info: `${BLUE}\\u2139${RESET}`,\n off: '',\n}\n\nconst SEVERITY_LABEL: Record<Severity, string> = {\n error: `${RED}error${RESET}`,\n warn: `${YELLOW}warning${RESET}`,\n info: `${BLUE}info${RESET}`,\n off: '',\n}\n\n/**\n * Format results as human-readable colored text.\n */\nexport function formatText(result: LintResult): string {\n const lines: string[] = []\n\n for (const file of result.files) {\n if (file.diagnostics.length === 0) continue\n\n lines.push('')\n lines.push(`${BOLD}${file.filePath}${RESET}`)\n\n for (const d of file.diagnostics) {\n const loc = `${DIM}${d.loc.line}:${d.loc.column}${RESET}`\n const severity = SEVERITY_LABEL[d.severity]\n const ruleId = `${DIM}${d.ruleId}${RESET}`\n lines.push(` ${loc} ${severity} ${d.message} ${ruleId}`)\n }\n }\n\n const total = result.totalErrors + result.totalWarnings + result.totalInfos\n if (total > 0) {\n lines.push('')\n const parts: string[] = []\n if (result.totalErrors > 0)\n parts.push(`${RED}${result.totalErrors} error${result.totalErrors === 1 ? '' : 's'}${RESET}`)\n if (result.totalWarnings > 0)\n parts.push(\n `${YELLOW}${result.totalWarnings} warning${result.totalWarnings === 1 ? '' : 's'}${RESET}`,\n )\n if (result.totalInfos > 0) parts.push(`${BLUE}${result.totalInfos} info${RESET}`)\n lines.push(`${SEVERITY_SYMBOL.error} ${parts.join(', ')}`)\n lines.push('')\n }\n\n return lines.join('\\n')\n}\n\n/**\n * Format results as JSON.\n */\nexport function formatJSON(result: LintResult): string {\n return JSON.stringify(result, null, 2)\n}\n\n/**\n * Format results as compact single-line-per-diagnostic output.\n */\nexport function formatCompact(result: LintResult): string {\n const lines: string[] = []\n\n for (const file of result.files) {\n for (const d of file.diagnostics) {\n lines.push(\n `${file.filePath}:${d.loc.line}:${d.loc.column}: ${d.severity} [${d.ruleId}] ${d.message}`,\n )\n }\n }\n\n return lines.join('\\n')\n}\n","import { readFileSync, watch } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { AstCache } from './cache'\nimport { createIgnoreFilter } from './config/ignore'\nimport { getPreset } from './config/presets'\nimport { formatCompact, formatJSON, formatText } from './reporter'\nimport { allRules } from './rules/index'\nimport { lintFile } from './runner'\nimport type { LintConfig, LintOptions, LintResult, Severity } from './types'\nimport { hasJsExtension } from './utils/index'\n\nfunction formatOutput(result: LintResult, format: string): string {\n if (format === 'json') return formatJSON(result)\n if (format === 'compact') return formatCompact(result)\n return formatText(result)\n}\n\n/**\n * Watch directories and re-lint changed files.\n *\n * Uses `fs.watch` (recursive) with 100ms debounce.\n * Caches ASTs for unchanged files.\n *\n * @example\n * ```ts\n * import { watchAndLint } from \"@pyreon/lint\"\n *\n * watchAndLint({ paths: [\"src/\"], preset: \"recommended\", format: \"text\" })\n * ```\n */\nexport function watchAndLint(options: LintOptions & { format: string }): void {\n const cache = new AstCache()\n const preset = options.preset ?? 'recommended'\n const config = getPreset(preset)\n\n applyOverrides(config, options.ruleOverrides)\n\n const cwd = resolve('.')\n const isIgnored = createIgnoreFilter(cwd, options.ignore)\n\n // Debounce map: filePath -> timeout\n const pending = new Map<string, ReturnType<typeof setTimeout>>()\n\n // oxlint-disable-next-line no-console\n console.log(`\\x1b[2m[pyreon-lint] Watching for changes...\\x1b[0m\\n`)\n\n for (const p of options.paths) {\n const dir = resolve(p)\n try {\n watch(dir, { recursive: true }, (_event, filename) => {\n if (!filename) return\n const filePath = resolve(dir, filename)\n\n if (!hasJsExtension(filePath) || isIgnored(filePath)) return\n\n // Debounce: clear existing timeout for this file\n const existing = pending.get(filePath)\n if (existing) clearTimeout(existing)\n\n pending.set(\n filePath,\n setTimeout(() => {\n pending.delete(filePath)\n relintFile(filePath, config, cache, options.format)\n }, 100),\n )\n })\n } catch {\n console.error(`[pyreon-lint] Could not watch: ${dir}`)\n }\n }\n}\n\nfunction applyOverrides(\n config: LintConfig,\n overrides?: Record<string, Severity> | undefined,\n): void {\n if (!overrides) return\n for (const [id, severity] of Object.entries(overrides)) {\n config.rules[id] = severity\n }\n}\n\nfunction relintFile(filePath: string, config: LintConfig, cache: AstCache, format: string): void {\n let source: string\n try {\n source = readFileSync(filePath, 'utf-8')\n } catch {\n return\n }\n\n const fileResult = lintFile(filePath, source, allRules, config, cache)\n\n if (fileResult.diagnostics.length === 0) return\n\n const result: LintResult = {\n files: [fileResult],\n totalErrors: 0,\n totalWarnings: 0,\n totalInfos: 0,\n }\n\n for (const d of fileResult.diagnostics) {\n if (d.severity === 'error') result.totalErrors++\n else if (d.severity === 'warn') result.totalWarnings++\n else if (d.severity === 'info') result.totalInfos++\n }\n\n // Clear screen and print\n process.stdout.write('\\x1b[2J\\x1b[H')\n console.log(formatOutput(result, format))\n}\n","#!/usr/bin/env node\nimport { lint, listRules } from './lint'\nimport { startLspServer } from './lsp/index'\nimport { formatCompact, formatJSON, formatText } from './reporter'\nimport type { PresetName, Severity } from './types'\nimport { watchAndLint } from './watcher'\n\n// Read version from package.json at build time; fallback for dev\nconst VERSION = '0.11.4'\n\nfunction printUsage() {\n console.log(`\n pyreon-lint [options] [path...]\n\n Options:\n --preset <name> Preset: recommended (default), strict, app, lib\n --fix Auto-fix fixable issues\n --format <fmt> Output: text (default), json, compact\n --quiet Only show errors\n --list List all available rules\n --rule <id>=<sev> Override rule severity\n --config <path> Config file path\n --ignore <path> Ignore file path\n --watch Watch mode — re-lint on file changes\n --lsp Start LSP server (stdin/stdout JSON-RPC)\n --help, -h Show this help\n --version, -v Show version\n`)\n}\n\nfunction printList() {\n const rules = listRules()\n const maxId = Math.max(...rules.map((r) => r.id.length))\n const maxCat = Math.max(...rules.map((r) => r.category.length))\n\n for (const rule of rules) {\n const fixLabel = rule.fixable ? ' [fixable]' : ''\n const id = rule.id.padEnd(maxId)\n const cat = rule.category.padEnd(maxCat)\n const sev = rule.severity.padEnd(5)\n console.log(` ${id} ${cat} ${sev} ${rule.description}${fixLabel}`)\n }\n\n console.log(`\\n ${rules.length} rules total`)\n}\n\ninterface CliArgs {\n preset: PresetName\n fix: boolean\n format: 'text' | 'json' | 'compact'\n quiet: boolean\n showList: boolean\n showHelp: boolean\n showVersion: boolean\n watchMode: boolean\n lspMode: boolean\n configPath: string | undefined\n ignorePath: string | undefined\n ruleOverrides: Record<string, Severity>\n paths: string[]\n}\n\nconst BOOLEAN_FLAGS: Record<string, keyof CliArgs> = {\n '--help': 'showHelp',\n '-h': 'showHelp',\n '--version': 'showVersion',\n '-v': 'showVersion',\n '--list': 'showList',\n '--fix': 'fix',\n '--quiet': 'quiet',\n '--watch': 'watchMode',\n '--lsp': 'lspMode',\n}\n\nfunction parseArgs(argv: string[]): CliArgs {\n const result: CliArgs = {\n preset: 'recommended',\n fix: false,\n format: 'text',\n quiet: false,\n showList: false,\n showHelp: false,\n showVersion: false,\n watchMode: false,\n lspMode: false,\n configPath: undefined,\n ignorePath: undefined,\n ruleOverrides: {},\n paths: [],\n }\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i] as string\n const boolKey = BOOLEAN_FLAGS[arg]\n\n if (boolKey) {\n ;(result as unknown as Record<string, unknown>)[boolKey] = true\n continue\n }\n\n const consumed = parseValueFlag(arg, argv[i + 1], result)\n i += consumed\n }\n\n return result\n}\n\n/** Returns number of extra args consumed (0 or 1). */\nfunction parseValueFlag(arg: string, nextArg: string | undefined, result: CliArgs): number {\n if (arg === '--preset') {\n result.preset = (nextArg ?? 'recommended') as PresetName\n return 1\n }\n if (arg === '--format') {\n result.format = (nextArg ?? 'text') as 'text' | 'json' | 'compact'\n return 1\n }\n if (arg === '--config') {\n result.configPath = nextArg\n return 1\n }\n if (arg === '--ignore') {\n result.ignorePath = nextArg\n return 1\n }\n if (arg === '--rule') {\n parseRuleOverride(nextArg, result.ruleOverrides)\n return 1\n }\n if (arg) {\n result.paths.push(arg)\n }\n return 0\n}\n\nfunction parseRuleOverride(val: string | undefined, overrides: Record<string, Severity>): void {\n if (!val) return\n const eqIdx = val.lastIndexOf('=')\n if (eqIdx === -1) return\n const ruleId = val.slice(0, eqIdx)\n const severity = val.slice(eqIdx + 1) as Severity\n overrides[ruleId] = severity\n}\n\nfunction main() {\n const args = parseArgs(process.argv.slice(2))\n\n if (args.showHelp) {\n printUsage()\n process.exit(0)\n }\n\n if (args.showVersion) {\n console.log(`pyreon-lint v${VERSION}`)\n process.exit(0)\n }\n\n if (args.showList) {\n printList()\n process.exit(0)\n }\n\n if (args.lspMode) {\n startLspServer()\n return\n }\n\n if (args.paths.length === 0) {\n args.paths.push('.')\n }\n\n if (args.watchMode) {\n watchAndLint({\n paths: args.paths,\n preset: args.preset,\n fix: args.fix,\n quiet: args.quiet,\n ruleOverrides: args.ruleOverrides,\n config: args.configPath,\n ignore: args.ignorePath,\n format: args.format,\n })\n return\n }\n\n const result = lint({\n paths: args.paths,\n preset: args.preset,\n fix: args.fix,\n quiet: args.quiet,\n ruleOverrides: args.ruleOverrides,\n config: args.configPath,\n ignore: args.ignorePath,\n })\n\n if (args.format === 'json') {\n console.log(formatJSON(result))\n } else if (args.format === 'compact') {\n console.log(formatCompact(result))\n } else {\n const output = formatText(result)\n if (output) console.log(output)\n }\n\n if (result.totalErrors > 0) {\n process.exit(1)\n }\n}\n\nmain()\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.js","names":[],"sources":["../src/cache.ts","../src/config/ignore.ts","../src/config/loader.ts","../src/utils/imports.ts","../src/utils/ast.ts","../src/rules/accessibility/dialog-a11y.ts","../src/rules/accessibility/overlay-a11y.ts","../src/rules/accessibility/toast-a11y.ts","../src/rules/architecture/dev-guard-warnings.ts","../src/rules/architecture/no-circular-import.ts","../src/rules/architecture/no-cross-layer-import.ts","../src/rules/architecture/no-deep-import.ts","../src/rules/architecture/no-error-without-prefix.ts","../src/rules/architecture/no-process-dev-gate.ts","../src/rules/form/no-submit-without-validation.ts","../src/rules/form/no-unregistered-field.ts","../src/rules/form/prefer-field-array.ts","../src/rules/hooks/no-raw-addeventlistener.ts","../src/rules/hooks/no-raw-localstorage.ts","../src/rules/hooks/no-raw-setinterval.ts","../src/rules/jsx/no-and-conditional.ts","../src/rules/jsx/no-children-access.ts","../src/rules/jsx/no-classname.ts","../src/rules/jsx/no-htmlfor.ts","../src/rules/jsx/no-index-as-by.ts","../src/rules/jsx/no-map-in-jsx.ts","../src/rules/jsx/no-missing-for-by.ts","../src/rules/jsx/no-onchange.ts","../src/rules/jsx/no-props-destructure.ts","../src/rules/jsx/no-ternary-conditional.ts","../src/rules/jsx/use-by-not-key.ts","../src/rules/lifecycle/no-dom-in-setup.ts","../src/rules/lifecycle/no-effect-in-mount.ts","../src/rules/lifecycle/no-missing-cleanup.ts","../src/rules/lifecycle/no-mount-in-effect.ts","../src/rules/performance/no-eager-import.ts","../src/rules/performance/no-effect-in-for.ts","../src/rules/performance/no-large-for-without-by.ts","../src/rules/performance/prefer-show-over-display.ts","../src/rules/reactivity/no-bare-signal-in-jsx.ts","../src/rules/reactivity/no-context-destructure.ts","../src/rules/reactivity/no-effect-assignment.ts","../src/rules/reactivity/no-nested-effect.ts","../src/rules/reactivity/no-peek-in-tracked.ts","../src/rules/reactivity/no-signal-in-loop.ts","../src/rules/reactivity/no-signal-in-props.ts","../src/rules/reactivity/no-signal-leak.ts","../src/rules/reactivity/no-unbatched-updates.ts","../src/rules/reactivity/prefer-computed.ts","../src/rules/router/no-href-navigation.ts","../src/rules/router/no-imperative-navigate-in-render.ts","../src/rules/router/no-missing-fallback.ts","../src/rules/router/prefer-use-is-active.ts","../src/rules/ssr/no-mismatch-risk.ts","../src/rules/ssr/no-window-in-ssr.ts","../src/rules/ssr/prefer-request-context.ts","../src/rules/store/no-duplicate-store-id.ts","../src/rules/store/no-mutate-store-state.ts","../src/rules/store/no-store-outside-provider.ts","../src/rules/styling/no-dynamic-styled.ts","../src/rules/styling/no-inline-style-object.ts","../src/rules/styling/no-theme-outside-provider.ts","../src/rules/styling/prefer-cx.ts","../src/rules/index.ts","../src/config/presets.ts","../src/utils/source.ts","../src/utils/index.ts","../src/runner.ts","../src/lint.ts","../src/lsp/index.ts","../src/reporter.ts","../src/watcher.ts","../src/cli.ts"],"sourcesContent":["import type { LineIndex } from './utils/source'\n\n/**\n * Simple in-memory cache for parsed ASTs keyed by file content hash.\n *\n * Uses FNV-1a hash of source text as cache key for fast lookups\n * during repeat runs (e.g., watch mode).\n *\n * @example\n * ```ts\n * import { AstCache } from \"@pyreon/lint\"\n *\n * const cache = new AstCache()\n * const cached = cache.get(sourceText)\n * if (!cached) {\n * const parsed = parse(sourceText)\n * cache.set(sourceText, parsed)\n * }\n * ```\n */\nexport class AstCache {\n private cache = new Map<string, { program: any; lineIndex: LineIndex }>()\n\n get(sourceText: string): { program: any; lineIndex: LineIndex } | undefined {\n const key = fnv1aHash(sourceText)\n return this.cache.get(key)\n }\n\n set(sourceText: string, value: { program: any; lineIndex: LineIndex }): void {\n const key = fnv1aHash(sourceText)\n this.cache.set(key, value)\n }\n\n clear(): void {\n this.cache.clear()\n }\n\n get size(): number {\n return this.cache.size\n }\n}\n\n/** FNV-1a hash — fast, non-cryptographic, low collision rate. */\nfunction fnv1aHash(str: string): string {\n let hash = 0x811c9dc5 // FNV offset basis\n for (let i = 0; i < str.length; i++) {\n hash ^= str.charCodeAt(i)\n hash = (hash * 0x01000193) | 0 // FNV prime, keep 32-bit\n }\n return (hash >>> 0).toString(36)\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join, relative, resolve } from 'node:path'\n\n/**\n * Create a filter function that returns true if a file path should be ignored.\n *\n * Loads patterns from `.pyreonlintignore` and `.gitignore` in the given directory.\n *\n * @example\n * ```ts\n * import { createIgnoreFilter } from \"@pyreon/lint\"\n *\n * const isIgnored = createIgnoreFilter(process.cwd())\n * if (!isIgnored(\"src/app.tsx\")) lintFile(...)\n * ```\n */\nexport function createIgnoreFilter(\n cwd: string,\n extraIgnore?: string | undefined,\n): (filePath: string) => boolean {\n const patterns: string[] = []\n const resolvedCwd = resolve(cwd)\n\n // Load .pyreonlintignore\n loadPatternsFromFile(join(resolvedCwd, '.pyreonlintignore'), patterns)\n\n // Load .gitignore\n loadPatternsFromFile(join(resolvedCwd, '.gitignore'), patterns)\n\n // Load extra ignore file if provided\n if (extraIgnore) {\n loadPatternsFromFile(resolve(extraIgnore), patterns)\n }\n\n // Compile patterns into matchers\n const matchers = patterns.map((p) => compileMatcher(p))\n\n return (filePath: string): boolean => {\n const rel = relative(resolvedCwd, resolve(filePath))\n // Normalize to forward slashes\n const normalized = rel.replace(/\\\\/g, '/')\n\n for (const matcher of matchers) {\n if (matcher(normalized)) return true\n }\n return false\n }\n}\n\nfunction loadPatternsFromFile(filePath: string, patterns: string[]): void {\n if (!existsSync(filePath)) return\n try {\n const content = readFileSync(filePath, 'utf-8')\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n // Skip empty lines and comments\n if (!trimmed || trimmed.startsWith('#')) continue\n patterns.push(trimmed)\n }\n } catch {\n // Ignore read errors\n }\n}\n\n/**\n * Compile a gitignore-style pattern into a matcher function.\n * Supports: `*` (any non-slash chars), `**` (any path segment), `?` (single char),\n * leading `/` (root-anchored), trailing `/` (directory only).\n */\nfunction compileMatcher(pattern: string): (path: string) => boolean {\n let p = pattern\n let anchored = false\n\n // Negated patterns (not supported — just skip them)\n if (p.startsWith('!')) {\n return () => false\n }\n\n // Leading slash means anchored to root\n if (p.startsWith('/')) {\n anchored = true\n p = p.slice(1)\n }\n\n // Trailing slash means only match directories (we treat all paths as files, so strip it\n // and match as a prefix)\n let dirOnly = false\n if (p.endsWith('/')) {\n dirOnly = true\n p = p.slice(0, -1)\n }\n\n const regex = globToRegex(p)\n\n return (path: string): boolean => {\n if (dirOnly) {\n // Match as prefix: the pattern should match a directory portion\n if (anchored) {\n return regex.test(path) || path.startsWith(`${p}/`) || path === p\n }\n // Unanchored directory pattern — match anywhere in path\n return regex.test(path) || path.includes(`/${p}/`) || path.startsWith(`${p}/`) || path === p\n }\n\n if (anchored) {\n return regex.test(path)\n }\n\n // Unanchored pattern — try matching the full path, or just the basename\n if (regex.test(path)) return true\n\n // Also try matching against just the filename\n const lastSlash = path.lastIndexOf('/')\n if (lastSlash !== -1) {\n const basename = path.slice(lastSlash + 1)\n return regex.test(basename)\n }\n\n return false\n }\n}\n\nconst GLOB_CHAR_MAP: Record<string, string> = {\n '?': '[^/]',\n '.': '\\\\.',\n '/': '/',\n}\n\nfunction handleStar(glob: string, pos: number): { pattern: string; advance: number } {\n if (glob[pos + 1] === '*') {\n if (glob[pos + 2] === '/') return { pattern: '(?:.*/)?', advance: 3 }\n return { pattern: '.*', advance: 2 }\n }\n return { pattern: '[^/]*', advance: 1 }\n}\n\nfunction globToRegex(glob: string): RegExp {\n let result = '^'\n let i = 0\n\n while (i < glob.length) {\n const ch = glob[i] as string\n if (ch === '*') {\n const star = handleStar(glob, i)\n result += star.pattern\n i += star.advance\n } else {\n result += GLOB_CHAR_MAP[ch] ?? escapeRegex(ch)\n i++\n }\n }\n\n result += '$'\n return new RegExp(result)\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[\\\\^$+{}[\\]|()]/g, '\\\\$&')\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { dirname, join, resolve } from 'node:path'\nimport type { LintConfigFile } from '../types'\n\nconst CONFIG_FILENAMES = ['.pyreonlintrc.json', '.pyreonlintrc', 'pyreonlint.config.json']\n\n/**\n * Load a lint config file from the given directory or its parents.\n *\n * Search order:\n * 1. `.pyreonlintrc.json`\n * 2. `.pyreonlintrc`\n * 3. `pyreonlint.config.json`\n * 4. `package.json` `\"pyreonlint\"` field\n *\n * @example\n * ```ts\n * import { loadConfig } from \"@pyreon/lint\"\n *\n * const config = loadConfig(process.cwd())\n * if (config) console.log(config.preset)\n * ```\n */\nexport function loadConfig(cwd: string): LintConfigFile | null {\n let dir = resolve(cwd)\n const root = dirname(dir)\n\n while (true) {\n const found = searchDirectory(dir)\n if (found !== null) return found\n\n const parent = dirname(dir)\n if (parent === dir || parent === root) break\n dir = parent\n }\n\n return null\n}\n\nfunction searchDirectory(dir: string): LintConfigFile | null {\n for (const filename of CONFIG_FILENAMES) {\n const content = tryReadJson(join(dir, filename))\n if (content !== null) return content\n }\n return extractPkgConfig(join(dir, 'package.json'))\n}\n\nfunction extractPkgConfig(pkgPath: string): LintConfigFile | null {\n const pkg = tryReadJson(pkgPath)\n if (pkg === null || typeof pkg !== 'object' || !('pyreonlint' in pkg)) return null\n const field = (pkg as Record<string, unknown>).pyreonlint\n if (field && typeof field === 'object') return field as LintConfigFile\n return null\n}\n\n/**\n * Load a config file from a specific path.\n */\nexport function loadConfigFromPath(filePath: string): LintConfigFile | null {\n return tryReadJson(resolve(filePath))\n}\n\nfunction tryReadJson(filePath: string): any | null {\n if (!existsSync(filePath)) return null\n try {\n const raw = readFileSync(filePath, 'utf-8').trim()\n if (!raw) return null\n return JSON.parse(raw)\n } catch {\n return null\n }\n}\n","import type { ImportInfo } from '../types'\n\nexport type { ImportInfo }\n\n// ── Constants ───────────────────────────────────────────────────────────────\n\nexport const PYREON_PREFIX = '@pyreon/'\n\nexport const REACTIVITY_APIS = new Set([\n 'signal',\n 'computed',\n 'effect',\n 'batch',\n 'onCleanup',\n 'createSelector',\n 'createStore',\n 'untrack',\n])\n\nexport const LIFECYCLE_APIS = new Set(['onMount', 'onUnmount'])\n\nexport const CONTEXT_APIS = new Set(['createContext', 'provide', 'pushContext', 'popContext'])\n\nexport const JSX_COMPONENTS = new Set([\n 'For',\n 'Show',\n 'Switch',\n 'Match',\n 'Dynamic',\n 'ErrorBoundary',\n 'Suspense',\n 'Portal',\n])\n\nexport const HEAVY_PACKAGES = new Set([\n '@pyreon/charts',\n '@pyreon/code',\n '@pyreon/document',\n '@pyreon/flow',\n])\n\nexport const BROWSER_GLOBALS = new Set([\n 'window',\n 'document',\n 'navigator',\n 'location',\n 'history',\n 'localStorage',\n 'sessionStorage',\n 'indexedDB',\n 'fetch',\n 'XMLHttpRequest',\n 'WebSocket',\n 'requestAnimationFrame',\n 'cancelAnimationFrame',\n 'IntersectionObserver',\n 'MutationObserver',\n 'ResizeObserver',\n 'matchMedia',\n 'getComputedStyle',\n 'addEventListener',\n 'removeEventListener',\n])\n\n// ── Functions ───────────────────────────────────────────────────────────────\n\nexport function isPyreonImport(source: string): boolean {\n return source.startsWith(PYREON_PREFIX)\n}\n\nexport function isPyreonPackage(source: string): boolean {\n return source.startsWith(PYREON_PREFIX)\n}\n\nexport function extractImportInfo(node: any): ImportInfo | null {\n if (node.type !== 'ImportDeclaration') return null\n\n const source = node.source?.value as string\n if (!source) return null\n\n const specifiers: ImportInfo['specifiers'] = []\n let isDefault = false\n let isNamespace = false\n\n for (const spec of node.specifiers ?? []) {\n if (spec.type === 'ImportDefaultSpecifier') {\n isDefault = true\n specifiers.push({ imported: 'default', local: spec.local?.name ?? '' })\n } else if (spec.type === 'ImportNamespaceSpecifier') {\n isNamespace = true\n specifiers.push({ imported: '*', local: spec.local?.name ?? '' })\n } else if (spec.type === 'ImportSpecifier') {\n const imported =\n spec.imported?.type === 'Identifier' ? spec.imported.name : (spec.imported?.value ?? '')\n specifiers.push({ imported, local: spec.local?.name ?? '' })\n }\n }\n\n return { source, specifiers, isDefault, isNamespace }\n}\n\nexport function importsName(imports: ImportInfo[], name: string, fromPackage?: string): boolean {\n return imports.some(\n (imp) =>\n (!fromPackage || imp.source === fromPackage) &&\n imp.specifiers.some((s) => s.imported === name),\n )\n}\n\nexport function getLocalName(\n imports: ImportInfo[],\n name: string,\n fromPackage?: string,\n): string | null {\n for (const imp of imports) {\n if (fromPackage && imp.source !== fromPackage) continue\n for (const s of imp.specifiers) {\n if (s.imported === name) return s.local\n }\n }\n return null\n}\n","import type { Span } from '../types'\nimport { BROWSER_GLOBALS } from './imports'\n\n/** Check if a node is a call expression to a specific function name. */\nexport function isCallTo(node: any, name: string): boolean {\n return (\n node.type === 'CallExpression' &&\n node.callee?.type === 'Identifier' &&\n node.callee.name === name\n )\n}\n\n/** Check if a node is a call expression to any of the given function names. */\nexport function isCallToAny(node: any, names: Set<string>): boolean {\n return (\n node.type === 'CallExpression' &&\n node.callee?.type === 'Identifier' &&\n names.has(node.callee.name)\n )\n}\n\n/** Check if a node is a member call like `obj.method()`. */\nexport function isMemberCallTo(node: any, objectName: string, methodName: string): boolean {\n return (\n node.type === 'CallExpression' &&\n node.callee?.type === 'MemberExpression' &&\n node.callee.object?.type === 'Identifier' &&\n node.callee.object.name === objectName &&\n node.callee.property?.type === 'Identifier' &&\n node.callee.property.name === methodName\n )\n}\n\n/** Check if a node is a JSX element (opening or self-closing). */\nexport function isJSXElement(node: any): boolean {\n return node.type === 'JSXElement' || node.type === 'JSXFragment'\n}\n\n/** Get the tag name of a JSX element. */\nexport function getJSXTagName(node: any): string | null {\n if (node.type === 'JSXElement') {\n const opening = node.openingElement\n if (!opening) return null\n const name = opening.name\n if (name?.type === 'JSXIdentifier') return name.name\n if (name?.type === 'JSXMemberExpression') {\n return `${name.object?.name ?? ''}.${name.property?.name ?? ''}`\n }\n }\n return null\n}\n\n/** Get a JSX attribute by name from an opening element. */\nexport function getJSXAttribute(openingElement: any, attrName: string): any | null {\n const attrs = openingElement.attributes ?? []\n for (const attr of attrs) {\n if (\n attr.type === 'JSXAttribute' &&\n attr.name?.type === 'JSXIdentifier' &&\n attr.name.name === attrName\n ) {\n return attr\n }\n }\n return null\n}\n\n/** Check if a JSX opening element has an attribute. */\nexport function hasJSXAttribute(openingElement: any, attrName: string): boolean {\n return getJSXAttribute(openingElement, attrName) !== null\n}\n\n/** Check if a node is inside a function (arrow or regular). */\nexport function isInsideFunction(ancestors: any[]): boolean {\n return ancestors.some(\n (a) =>\n a.type === 'FunctionDeclaration' ||\n a.type === 'FunctionExpression' ||\n a.type === 'ArrowFunctionExpression',\n )\n}\n\n/** Check if a node is inside JSX. */\nexport function isInsideJSX(ancestors: any[]): boolean {\n return ancestors.some((a) => a.type === 'JSXElement' || a.type === 'JSXFragment')\n}\n\n/** Check if a node is an array .map() call. */\nexport function isArrayMapCall(node: any): boolean {\n return (\n node.type === 'CallExpression' &&\n node.callee?.type === 'MemberExpression' &&\n node.callee.property?.type === 'Identifier' &&\n node.callee.property.name === 'map'\n )\n}\n\n/** Check if a node is a function expression or arrow function. */\nexport function isFunction(node: any): boolean {\n return (\n node.type === 'FunctionDeclaration' ||\n node.type === 'FunctionExpression' ||\n node.type === 'ArrowFunctionExpression'\n )\n}\n\n/** Check if a node is a destructuring pattern. */\nexport function isDestructuring(node: any): boolean {\n return node.type === 'ObjectPattern' || node.type === 'ArrayPattern'\n}\n\n/** Check if a node is a ternary with JSX in either branch. */\nexport function isTernaryWithJSX(node: any): boolean {\n if (node.type !== 'ConditionalExpression') return false\n return containsJSX(node.consequent) || containsJSX(node.alternate)\n}\n\n/** Check if a node contains JSX anywhere. */\nfunction containsJSX(node: any): boolean {\n if (!node) return false\n if (node.type === 'JSXElement' || node.type === 'JSXFragment') return true\n if (node.type === 'ParenthesizedExpression') return containsJSX(node.expression)\n return false\n}\n\n/** Check if a JSX element has JSX children. */\nexport function hasJSXChild(node: any): boolean {\n if (node.type !== 'JSXElement') return false\n return (node.children ?? []).some((c: any) => c.type === 'JSXElement' || c.type === 'JSXFragment')\n}\n\n/** Check if a node is a logical AND with JSX. */\nexport function isLogicalAndWithJSX(node: any): boolean {\n if (node.type !== 'LogicalExpression' || node.operator !== '&&') return false\n return containsJSX(node.right)\n}\n\n/** Check if a node is a .peek() call. */\nexport function isPeekCall(node: any): boolean {\n return (\n node.type === 'CallExpression' &&\n node.callee?.type === 'MemberExpression' &&\n node.callee.property?.type === 'Identifier' &&\n node.callee.property.name === 'peek'\n )\n}\n\n/** Check if a node is a .set() call. */\nexport function isSetCall(node: any): boolean {\n return (\n node.type === 'CallExpression' &&\n node.callee?.type === 'MemberExpression' &&\n node.callee.property?.type === 'Identifier' &&\n node.callee.property.name === 'set'\n )\n}\n\n/** Check if a node references a browser global. */\nexport function isBrowserGlobal(node: any): boolean {\n return node.type === 'Identifier' && BROWSER_GLOBALS.has(node.name)\n}\n\n/** Get the span (byte offsets) of a node. */\nexport function getSpan(node: any): Span {\n return { start: node.start as number, end: node.end as number }\n}\n\n/** Check if a node is inside a `if (__DEV__)` guard. */\nexport function isInsideDevGuard(ancestors: any[]): boolean {\n return ancestors.some(\n (a) => a.type === 'IfStatement' && a.test?.type === 'Identifier' && a.test.name === '__DEV__',\n )\n}\n\n/** Check if a node is inside an onMount callback. */\nexport function isInsideOnMount(ancestors: any[]): boolean {\n return ancestors.some(\n (a) =>\n a.type === 'CallExpression' && a.callee?.type === 'Identifier' && a.callee.name === 'onMount',\n )\n}\n\n/** Check if a node is inside a typeof guard (e.g., `typeof window !== \"undefined\"`). */\nexport function isInsideTypeofGuard(ancestors: any[]): boolean {\n return ancestors.some(\n (a) =>\n a.type === 'IfStatement' &&\n a.test?.type === 'BinaryExpression' &&\n a.test.left?.type === 'UnaryExpression' &&\n a.test.left.operator === 'typeof',\n )\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, hasJSXAttribute } from '../../utils/ast'\n\nexport const dialogA11y: Rule = {\n meta: {\n id: 'pyreon/dialog-a11y',\n category: 'accessibility',\n description: 'Warn when <dialog> is missing aria-label or aria-labelledby.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const name = node.name\n if (!name || name.type !== 'JSXIdentifier' || name.name !== 'dialog') return\n\n const hasLabel = hasJSXAttribute(node, 'aria-label')\n const hasLabelledBy = hasJSXAttribute(node, 'aria-labelledby')\n\n if (!hasLabel && !hasLabelledBy) {\n context.report({\n message:\n '`<dialog>` missing `aria-label` or `aria-labelledby` — provide an accessible label for screen readers.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, hasJSXAttribute } from '../../utils/ast'\n\nexport const overlayA11y: Rule = {\n meta: {\n id: 'pyreon/overlay-a11y',\n category: 'accessibility',\n description: 'Warn when <Overlay> is missing role, aria-label, or aria-labelledby.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const name = node.name\n if (!name || name.type !== 'JSXIdentifier' || name.name !== 'Overlay') return\n\n const hasRole = hasJSXAttribute(node, 'role')\n const hasLabel = hasJSXAttribute(node, 'aria-label')\n const hasLabelledBy = hasJSXAttribute(node, 'aria-labelledby')\n\n if (!hasRole && !hasLabel && !hasLabelledBy) {\n context.report({\n message:\n '`<Overlay>` missing `role`, `aria-label`, or `aria-labelledby` — provide accessibility attributes for screen readers.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, hasJSXAttribute } from '../../utils/ast'\n\nexport const toastA11y: Rule = {\n meta: {\n id: 'pyreon/toast-a11y',\n category: 'accessibility',\n description: 'Warn when toast-like components are missing role or aria-live attributes.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const name = node.name\n if (!name || name.type !== 'JSXIdentifier') return\n\n const tagName: string = name.name\n // Skip non-PascalCase and the Toaster container itself\n if (tagName === 'Toaster') return\n const firstChar = tagName[0]\n if (!firstChar || firstChar !== firstChar.toUpperCase()) return\n if (!tagName.toLowerCase().includes('toast')) return\n\n const hasRole = hasJSXAttribute(node, 'role')\n const hasAriaLive = hasJSXAttribute(node, 'aria-live')\n\n if (!hasRole && !hasAriaLive) {\n context.report({\n message: `Toast component \\`<${tagName}>\\` missing \\`role\\` or \\`aria-live\\` — add \\`role=\"alert\"\\` and \\`aria-live=\"polite\"\\` for screen reader accessibility.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const devGuardWarnings: Rule = {\n meta: {\n id: 'pyreon/dev-guard-warnings',\n category: 'architecture',\n description: 'Require console.warn/error calls to be wrapped in `if (__DEV__)` guards.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n const filePath = context.getFilePath()\n // Skip test and example files\n if (\n filePath.includes('/tests/') ||\n filePath.includes('/test/') ||\n filePath.includes('/examples/') ||\n filePath.includes('.test.') ||\n filePath.includes('.spec.')\n ) {\n return {}\n }\n\n let devGuardDepth = 0\n const callbacks: VisitorCallbacks = {\n IfStatement(node: any) {\n if (node.test?.type === 'Identifier' && node.test.name === '__DEV__') {\n devGuardDepth++\n }\n },\n 'IfStatement:exit'(node: any) {\n if (node.test?.type === 'Identifier' && node.test.name === '__DEV__') {\n devGuardDepth--\n }\n },\n CallExpression(node: any) {\n if (devGuardDepth > 0) return\n\n const callee = node.callee\n if (\n callee?.type === 'MemberExpression' &&\n callee.object?.type === 'Identifier' &&\n callee.object.name === 'console' &&\n callee.property?.type === 'Identifier' &&\n (callee.property.name === 'warn' || callee.property.name === 'error')\n ) {\n context.report({\n message: `\\`console.${callee.property.name}()\\` without \\`__DEV__\\` guard — dev warnings must be tree-shakeable in production. Wrap in \\`if (__DEV__) { ... }\\`.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\nimport { isPyreonImport } from '../../utils/imports'\n\nconst LAYER_ORDER: Record<string, number> = {\n '@pyreon/reactivity': 0,\n '@pyreon/core': 1,\n '@pyreon/compiler': 1,\n '@pyreon/runtime-dom': 2,\n '@pyreon/runtime-server': 2,\n '@pyreon/router': 3,\n '@pyreon/head': 4,\n '@pyreon/server': 5,\n}\n\nfunction getLayer(source: string): number | null {\n return LAYER_ORDER[source] ?? null\n}\n\nfunction getFileLayer(filePath: string): number | null {\n for (const [pkg, layer] of Object.entries(LAYER_ORDER)) {\n const pkgName = pkg.replace('@pyreon/', '')\n if (filePath.includes(`/packages/core/${pkgName}/`)) return layer\n }\n return null\n}\n\nexport const noCircularImport: Rule = {\n meta: {\n id: 'pyreon/no-circular-import',\n category: 'architecture',\n description: 'Enforce package layer order to prevent circular imports between core packages.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n const filePath = context.getFilePath()\n const fileLayer = getFileLayer(filePath)\n if (fileLayer === null) return {}\n\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const source = node.source?.value as string\n if (!source || !isPyreonImport(source)) return\n\n const importLayer = getLayer(source)\n if (importLayer === null) return\n\n if (importLayer >= fileLayer) {\n context.report({\n message: `Importing \\`${source}\\` (layer ${importLayer}) from layer ${fileLayer} — this violates the package layer order and may cause circular imports.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\nimport { isPyreonImport } from '../../utils/imports'\n\ntype PackageCategory = 'core' | 'fundamentals' | 'tools' | 'ui-system'\n\nconst CORE_PACKAGES = new Set([\n '@pyreon/reactivity',\n '@pyreon/core',\n '@pyreon/compiler',\n '@pyreon/runtime-dom',\n '@pyreon/runtime-server',\n '@pyreon/router',\n '@pyreon/head',\n '@pyreon/server',\n])\n\nconst UI_PACKAGES = new Set([\n '@pyreon/ui-core',\n '@pyreon/styler',\n '@pyreon/unistyle',\n '@pyreon/elements',\n '@pyreon/attrs',\n '@pyreon/rocketstyle',\n '@pyreon/coolgrid',\n '@pyreon/kinetic',\n '@pyreon/kinetic-presets',\n '@pyreon/connector-document',\n '@pyreon/document-primitives',\n])\n\nfunction getImportCategory(source: string): PackageCategory | null {\n if (CORE_PACKAGES.has(source)) return 'core'\n if (UI_PACKAGES.has(source)) return 'ui-system'\n return null\n}\n\nfunction getFileCategory(filePath: string): PackageCategory | null {\n if (filePath.includes('/packages/core/')) return 'core'\n if (filePath.includes('/packages/ui-system/')) return 'ui-system'\n if (filePath.includes('/packages/fundamentals/')) return 'fundamentals'\n if (filePath.includes('/packages/tools/')) return 'tools'\n return null\n}\n\nexport const noCrossLayerImport: Rule = {\n meta: {\n id: 'pyreon/no-cross-layer-import',\n category: 'architecture',\n description: 'Prevent core packages from importing ui-system packages.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n const filePath = context.getFilePath()\n const fileCategory = getFileCategory(filePath)\n if (fileCategory !== 'core') return {}\n\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const source = node.source?.value as string\n if (!source || !isPyreonImport(source)) return\n\n const importCategory = getImportCategory(source)\n if (importCategory === 'ui-system') {\n context.report({\n message: `Core package importing ui-system package \\`${source}\\` — core packages must not depend on ui-system.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\nimport { isPyreonImport } from '../../utils/imports'\n\nconst DEEP_IMPORT_PATTERN = /@pyreon\\/[^/]+\\/(src|dist|lib)\\//\n\nexport const noDeepImport: Rule = {\n meta: {\n id: 'pyreon/no-deep-import',\n category: 'architecture',\n description:\n 'Disallow importing from @pyreon/*/src/, /dist/, or /lib/ — use public exports instead.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const source = node.source?.value as string\n if (!source || !isPyreonImport(source)) return\n\n if (DEEP_IMPORT_PATTERN.test(source)) {\n context.report({\n message: `Deep import \\`${source}\\` — import from the package's public exports instead.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const noErrorWithoutPrefix: Rule = {\n meta: {\n id: 'pyreon/no-error-without-prefix',\n category: 'architecture',\n description: 'Require error messages to be prefixed with [Pyreon].',\n severity: 'warn',\n fixable: true,\n },\n create(context) {\n const filePath = context.getFilePath()\n // Skip test files\n if (\n filePath.includes('/tests/') ||\n filePath.includes('/test/') ||\n filePath.includes('.test.') ||\n filePath.includes('.spec.')\n ) {\n return {}\n }\n\n const callbacks: VisitorCallbacks = {\n ThrowStatement(node: any) {\n const arg = node.argument\n if (!arg || arg.type !== 'NewExpression') return\n const callee = arg.callee\n if (!callee || callee.type !== 'Identifier' || callee.name !== 'Error') return\n\n const args = arg.arguments\n if (!args || args.length === 0) return\n\n const firstArg = args[0]\n if (!firstArg) return\n\n if (firstArg.type === 'Literal' || firstArg.type === 'StringLiteral') {\n const value = firstArg.value as string\n if (typeof value === 'string' && !value.startsWith('[Pyreon]')) {\n const argSpan = getSpan(firstArg)\n // Fix: add [Pyreon] prefix\n const quote = context.getSourceText()[argSpan.start]\n const fixedValue = `${quote}[Pyreon] ${value}${quote}`\n context.report({\n message:\n 'Error message missing `[Pyreon]` prefix — all framework errors should be prefixed for identification.',\n span: getSpan(node),\n fix: { span: argSpan, replacement: fixedValue },\n })\n }\n }\n\n if (firstArg.type === 'TemplateLiteral') {\n const quasis = firstArg.quasis\n if (quasis && quasis.length > 0) {\n const first = quasis[0]\n const raw = first.value?.raw ?? first.value?.cooked ?? ''\n if (!raw.startsWith('[Pyreon]')) {\n const argSpan = getSpan(firstArg)\n const source = context.getSourceText().slice(argSpan.start, argSpan.end)\n const fixed = source.replace(/^`/, '`[Pyreon] ')\n context.report({\n message:\n 'Error message missing `[Pyreon]` prefix — all framework errors should be prefixed for identification.',\n span: getSpan(node),\n fix: { span: argSpan, replacement: fixed },\n })\n }\n }\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\n/**\n * `pyreon/no-process-dev-gate` — flag the broken `typeof process` dev-mode gate\n * pattern that is dead code in real Vite browser bundles.\n *\n * The pattern this rule catches:\n *\n * ```ts\n * const __DEV__ = typeof process !== 'undefined' && process.env.NODE_ENV !== 'production'\n * ```\n *\n * This works in vitest (Node, `process` is defined) but is **silently dead\n * code in real Vite browser bundles** because Vite does not polyfill\n * `process` for the client. Every dev warning gated on this constant never\n * fires for real users in dev mode.\n *\n * The fix is to use `import.meta.env.DEV`, which Vite/Rolldown literal-replace\n * at build time:\n *\n * ```ts\n * // No const needed — read directly at the use site so the bundler can fold:\n * if (!import.meta.env?.DEV) return\n * ```\n *\n * Vitest sets `import.meta.env.DEV === true` automatically (because it is\n * Vite-based), so existing tests continue to pass.\n *\n * Reference implementation: `packages/fundamentals/flow/src/layout.ts:warnIgnoredOptions`.\n *\n * **Auto-fix**: replaces the assignment with `import.meta.env?.DEV === true`.\n * Does NOT delete the const declaration — that has to happen by hand because\n * the variable name and downstream usages may need updating in callers.\n *\n * **Server-package exception**: server-only files run in Node where `process`\n * is always defined, so the pattern is correct there. The rule skips files\n * matching `packages/zero/`, `packages/core/server/`, `packages/core/runtime-server/`,\n * `packages/tools/vite-plugin/`, and any file containing `/server/` in its\n * path. Add new server packages to `SERVER_PACKAGE_PATTERNS` below.\n */\n/**\n * File-path patterns for server-only packages. Substring match against the\n * file path passed to the rule. Patterns intentionally do NOT start with `/`\n * so they match both absolute paths (`/Users/.../packages/zero/...`) and\n * relative paths (`packages/zero/...`) — different lint runners pass paths\n * differently.\n */\nconst SERVER_PACKAGE_PATTERNS = [\n 'packages/zero/',\n 'packages/core/server/',\n 'packages/core/runtime-server/',\n 'packages/tools/vite-plugin/',\n 'packages/tools/cli/',\n 'packages/tools/lint/',\n 'packages/tools/mcp/',\n 'packages/tools/storybook/',\n 'packages/tools/typescript/',\n 'scripts/',\n]\n\nfunction isServerOnlyFile(filePath: string): boolean {\n return SERVER_PACKAGE_PATTERNS.some((pat) => filePath.includes(pat))\n}\n\nexport const noProcessDevGate: Rule = {\n meta: {\n id: 'pyreon/no-process-dev-gate',\n category: 'architecture',\n description:\n 'Forbid `typeof process !== \"undefined\" && process.env.NODE_ENV !== \"production\"` as a dev-mode gate. Use `import.meta.env.DEV` instead — `typeof process` is dead code in real Vite browser bundles because Vite does not polyfill `process` for the client.',\n severity: 'error',\n fixable: true,\n },\n create(context) {\n const filePath = context.getFilePath()\n\n // Skip test files — vitest has `process`, the gate works there, and\n // tests are not shipped to users.\n if (\n filePath.includes('/tests/') ||\n filePath.includes('/test/') ||\n filePath.includes('/__tests__/') ||\n filePath.includes('.test.') ||\n filePath.includes('.spec.')\n ) {\n return {}\n }\n\n // Skip server-only packages — they run in Node where `process` is\n // always defined, so the pattern is correct there.\n if (isServerOnlyFile(filePath)) {\n return {}\n }\n\n /**\n * Match the broken pattern at the AST level. We're looking for any\n * `LogicalExpression` whose two sides are:\n *\n * 1. `typeof process !== 'undefined'` (a UnaryExpression on the LHS\n * of a BinaryExpression with operator `!==`)\n * 2. `process.env.NODE_ENV !== 'production'` (a MemberExpression on\n * the LHS of a BinaryExpression with operator `!==`)\n *\n * The order can be either way (process check first or NODE_ENV check\n * first), and the operator can be `&&` or `||` (we only flag `&&`\n * because `||` doesn't make sense as a dev gate).\n */\n function isTypeofProcessCheck(node: any): boolean {\n // typeof process !== 'undefined'\n if (node?.type !== 'BinaryExpression') return false\n if (node.operator !== '!==' && node.operator !== '!=') return false\n const left = node.left\n const right = node.right\n if (left?.type !== 'UnaryExpression' || left.operator !== 'typeof') return false\n if (left.argument?.type !== 'Identifier' || left.argument.name !== 'process') return false\n if (\n (right?.type === 'Literal' || right?.type === 'StringLiteral') &&\n right.value === 'undefined'\n ) {\n return true\n }\n return false\n }\n\n function isNodeEnvCheck(node: any): boolean {\n // process.env.NODE_ENV !== 'production'\n if (node?.type !== 'BinaryExpression') return false\n if (node.operator !== '!==' && node.operator !== '!=') return false\n const left = node.left\n const right = node.right\n if (left?.type !== 'MemberExpression') return false\n if (left.object?.type !== 'MemberExpression') return false\n if (left.object.object?.type !== 'Identifier' || left.object.object.name !== 'process') {\n return false\n }\n if (left.object.property?.type !== 'Identifier' || left.object.property.name !== 'env') {\n return false\n }\n if (left.property?.type !== 'Identifier' || left.property.name !== 'NODE_ENV') return false\n if (\n (right?.type === 'Literal' || right?.type === 'StringLiteral') &&\n right.value === 'production'\n ) {\n return true\n }\n return false\n }\n\n function isBrokenDevGate(node: any): boolean {\n if (node?.type !== 'LogicalExpression') return false\n if (node.operator !== '&&') return false\n // Order can be (typeof process) && (NODE_ENV) OR vice versa\n return (\n (isTypeofProcessCheck(node.left) && isNodeEnvCheck(node.right)) ||\n (isNodeEnvCheck(node.left) && isTypeofProcessCheck(node.right))\n )\n }\n\n const callbacks: VisitorCallbacks = {\n LogicalExpression(node: any) {\n if (!isBrokenDevGate(node)) return\n\n const span = getSpan(node)\n // Auto-fix: replace the entire `typeof process ... && process.env.NODE_ENV ...`\n // expression with `import.meta.env?.DEV === true`. We use optional\n // chaining + strict equality so the expression is `false` (not\n // `undefined`) when `import.meta.env` is missing — preserving the\n // boolean shape callers expect.\n const replacement = 'import.meta.env?.DEV === true'\n\n context.report({\n message:\n '`typeof process !== \"undefined\" && process.env.NODE_ENV !== \"production\"` is dead code in real Vite browser bundles — Vite does not polyfill `process`, so this guard is `false` and any wrapped dev warnings never fire for real users. Use `import.meta.env.DEV` instead, which Vite literal-replaces at build time and tree-shakes correctly in prod. Reference implementation: `packages/fundamentals/flow/src/layout.ts:warnIgnoredOptions`.',\n span,\n fix: { span, replacement },\n })\n },\n }\n\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noSubmitWithoutValidation: Rule = {\n meta: {\n id: 'pyreon/no-submit-without-validation',\n category: 'form',\n description: 'Warn when useForm() has onSubmit but no validators or schema.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (!isCallTo(node, 'useForm')) return\n const args = node.arguments\n if (!args || args.length === 0) return\n\n const options = args[0]\n if (!options || options.type !== 'ObjectExpression') return\n\n let hasOnSubmit = false\n let hasValidation = false\n\n for (const prop of options.properties ?? []) {\n if (prop.type !== 'Property') continue\n const key = prop.key\n if (!key) continue\n const name = key.type === 'Identifier' ? key.name : null\n if (name === 'onSubmit') hasOnSubmit = true\n if (name === 'validators' || name === 'schema') hasValidation = true\n }\n\n if (hasOnSubmit && !hasValidation) {\n context.report({\n message:\n '`useForm()` has `onSubmit` without `validators` or `schema` — consider adding validation for data integrity.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noUnregisteredField: Rule = {\n meta: {\n id: 'pyreon/no-unregistered-field',\n category: 'form',\n description: 'Warn when useField() is called without a corresponding register() call.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const fieldDecls = new Map<string, { span: { start: number; end: number } }>()\n const registeredNames = new Set<string>()\n\n const callbacks: VisitorCallbacks = {\n VariableDeclarator(node: any) {\n const init = node.init\n if (!init || !isCallTo(init, 'useField')) return\n const id = node.id\n if (!id || id.type !== 'Identifier') return\n fieldDecls.set(id.name, { span: getSpan(node) })\n },\n CallExpression(node: any) {\n const callee = node.callee\n if (!callee || callee.type !== 'MemberExpression') return\n if (callee.property?.type !== 'Identifier' || callee.property.name !== 'register') return\n if (callee.object?.type === 'Identifier') {\n registeredNames.add(callee.object.name)\n }\n },\n 'Program:exit'() {\n for (const [name, { span }] of fieldDecls) {\n if (!registeredNames.has(name)) {\n context.report({\n message: `\\`useField()\\` result \\`${name}\\` is never registered — call \\`${name}.register()\\` to connect it to the form.`,\n span,\n })\n }\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\nimport { extractImportInfo } from '../../utils/imports'\n\nexport const preferFieldArray: Rule = {\n meta: {\n id: 'pyreon/prefer-field-array',\n category: 'form',\n description: 'Suggest useFieldArray() instead of signal([]) in files that import @pyreon/form.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n let importsForm = false\n\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const info = extractImportInfo(node)\n if (info && info.source === '@pyreon/form') {\n importsForm = true\n }\n },\n CallExpression(node: any) {\n if (!importsForm) return\n if (!isCallTo(node, 'signal')) return\n\n const args = node.arguments\n if (!args || args.length === 0) return\n const firstArg = args[0]\n if (firstArg?.type === 'ArrayExpression') {\n context.report({\n message:\n '`signal([])` in a form file — consider using `useFieldArray()` for dynamic array fields with stable keys.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const noRawAddEventListener: Rule = {\n meta: {\n id: 'pyreon/no-raw-addeventlistener',\n category: 'hooks',\n description: 'Suggest useEventListener() instead of raw .addEventListener() calls.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n const callee = node.callee\n if (!callee || callee.type !== 'MemberExpression') return\n if (callee.property?.type !== 'Identifier' || callee.property.name !== 'addEventListener')\n return\n context.report({\n message:\n 'Raw `.addEventListener()` — consider using `useEventListener()` from `@pyreon/hooks` for auto-cleanup on unmount.',\n span: getSpan(node),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nconst STORAGE_OBJECTS = new Set(['localStorage', 'sessionStorage'])\nconst STORAGE_METHODS = new Set(['getItem', 'setItem', 'removeItem'])\n\nexport const noRawLocalStorage: Rule = {\n meta: {\n id: 'pyreon/no-raw-localstorage',\n category: 'hooks',\n description: 'Suggest useStorage() instead of raw localStorage/sessionStorage access.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n const callee = node.callee\n if (!callee || callee.type !== 'MemberExpression') return\n if (\n callee.object?.type === 'Identifier' &&\n STORAGE_OBJECTS.has(callee.object.name) &&\n callee.property?.type === 'Identifier' &&\n STORAGE_METHODS.has(callee.property.name)\n ) {\n context.report({\n message: `Raw \\`${callee.object.name}.${callee.property.name}()\\` — consider using \\`useStorage()\\` from \\`@pyreon/storage\\` for reactive, cross-tab synced storage.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nconst TIMER_FNS = new Set(['setInterval', 'setTimeout'])\n\nexport const noRawSetInterval: Rule = {\n meta: {\n id: 'pyreon/no-raw-setinterval',\n category: 'hooks',\n description: 'Suggest wrapping setInterval/setTimeout in onMount for automatic cleanup.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n let mountDepth = 0\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (isCallTo(node, 'onMount')) {\n mountDepth++\n }\n\n if (mountDepth > 0) return\n\n const callee = node.callee\n if (!callee || callee.type !== 'Identifier') return\n if (TIMER_FNS.has(callee.name)) {\n context.report({\n message: `\\`${callee.name}()\\` outside \\`onMount\\` — wrap in \\`onMount(() => { ... return () => clear... })\\` for automatic cleanup.`,\n span: getSpan(node),\n })\n }\n },\n 'CallExpression:exit'(node: any) {\n if (isCallTo(node, 'onMount')) {\n mountDepth--\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isLogicalAndWithJSX } from '../../utils/ast'\n\nexport const noAndConditional: Rule = {\n meta: {\n id: 'pyreon/no-and-conditional',\n category: 'jsx',\n description: 'Prefer <Show> over `&&` with JSX in expression containers.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let jsxExpressionDepth = 0\n const callbacks: VisitorCallbacks = {\n JSXExpressionContainer() {\n jsxExpressionDepth++\n },\n 'JSXExpressionContainer:exit'() {\n jsxExpressionDepth--\n },\n LogicalExpression(node: any) {\n if (jsxExpressionDepth === 0) return\n if (!isLogicalAndWithJSX(node)) return\n context.report({\n message: '`&&` with JSX — use `<Show>` for conditional rendering.',\n span: getSpan(node),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\nimport { extractImportInfo, type ImportInfo } from '../../utils/imports'\n\nexport const noChildrenAccess: Rule = {\n meta: {\n id: 'pyreon/no-children-access',\n category: 'jsx',\n description: 'Inform about direct props.children access in renderer files.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n const imports: ImportInfo[] = []\n let isRendererFile = false\n\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const info = extractImportInfo(node)\n if (info) {\n imports.push(info)\n if (info.source === '@pyreon/runtime-server' || info.source === '@pyreon/runtime-dom') {\n isRendererFile = true\n }\n }\n },\n MemberExpression(node: any) {\n if (!isRendererFile) return\n if (\n node.object?.type === 'Identifier' &&\n node.property?.type === 'Identifier' &&\n node.property.name === 'children'\n ) {\n context.report({\n message:\n 'Direct `props.children` access in a renderer file — children are already merged via `mergeChildrenIntoProps`.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const noClassName: Rule = {\n meta: {\n id: 'pyreon/no-classname',\n category: 'jsx',\n description: 'Use `class` instead of `className` — Pyreon uses standard HTML attributes.',\n severity: 'error',\n fixable: true,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXAttribute(node: any) {\n if (node.name?.type !== 'JSXIdentifier') return\n if (node.name.name !== 'className') return\n const nameSpan = getSpan(node.name)\n context.report({\n message: 'Use `class` instead of `className` — Pyreon uses standard HTML attributes.',\n span: getSpan(node),\n fix: { span: nameSpan, replacement: 'class' },\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const noHtmlFor: Rule = {\n meta: {\n id: 'pyreon/no-htmlfor',\n category: 'jsx',\n description: 'Use `for` instead of `htmlFor` — Pyreon uses standard HTML attributes.',\n severity: 'error',\n fixable: true,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXAttribute(node: any) {\n if (node.name?.type !== 'JSXIdentifier') return\n if (node.name.name !== 'htmlFor') return\n const nameSpan = getSpan(node.name)\n context.report({\n message: 'Use `for` instead of `htmlFor` — Pyreon uses standard HTML attributes.',\n span: getSpan(node),\n fix: { span: nameSpan, replacement: 'for' },\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getJSXAttribute, getSpan } from '../../utils/ast'\n\nexport const noIndexAsBy: Rule = {\n meta: {\n id: 'pyreon/no-index-as-by',\n category: 'jsx',\n description: 'Disallow using index as `by` prop on <For> — use a unique key instead.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const name = node.name\n if (!name || name.type !== 'JSXIdentifier' || name.name !== 'For') return\n\n const byAttr = getJSXAttribute(node, 'by')\n if (!byAttr) return\n\n const value = byAttr.value\n if (!value || value.type !== 'JSXExpressionContainer') return\n\n const expr = value.expression\n if (!expr) return\n\n // Detect: by={(_, i) => i} or by={(item, index) => index}\n if (expr.type === 'ArrowFunctionExpression' || expr.type === 'FunctionExpression') {\n const params = expr.params\n if (!params || params.length < 2) return\n\n const secondParam = params[1]\n if (!secondParam || secondParam.type !== 'Identifier') return\n\n const indexName = secondParam.name\n const body = expr.body\n\n // Arrow expression body: (_, i) => i\n if (body?.type === 'Identifier' && body.name === indexName) {\n context.report({\n message:\n 'Using index as `by` prop on `<For>` — use a unique key from the data instead.',\n span: getSpan(byAttr),\n })\n }\n\n // Block body: (_, i) => { return i }\n if (body?.type === 'BlockStatement') {\n const stmts = body.body\n if (stmts?.length === 1) {\n const stmt = stmts[0]\n if (\n stmt.type === 'ReturnStatement' &&\n stmt.argument?.type === 'Identifier' &&\n stmt.argument.name === indexName\n ) {\n context.report({\n message:\n 'Using index as `by` prop on `<For>` — use a unique key from the data instead.',\n span: getSpan(byAttr),\n })\n }\n }\n }\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isArrayMapCall } from '../../utils/ast'\n\nexport const noMapInJsx: Rule = {\n meta: {\n id: 'pyreon/no-map-in-jsx',\n category: 'jsx',\n description: 'Prefer <For> over .map() inside JSX for reactive list rendering.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let jsxDepth = 0\n const callbacks: VisitorCallbacks = {\n JSXElement() {\n jsxDepth++\n },\n 'JSXElement:exit'() {\n jsxDepth--\n },\n JSXFragment() {\n jsxDepth++\n },\n 'JSXFragment:exit'() {\n jsxDepth--\n },\n CallExpression(node: any) {\n if (jsxDepth === 0) return\n if (!isArrayMapCall(node)) return\n // Check callback contains JSX\n const args = node.arguments\n if (!args || args.length === 0) return\n const callback = args[0]\n if (!callback) return\n context.report({\n message: '`.map()` in JSX — use `<For>` for reactive list rendering instead.',\n span: getSpan(node),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, hasJSXAttribute } from '../../utils/ast'\n\nexport const noMissingForBy: Rule = {\n meta: {\n id: 'pyreon/no-missing-for-by',\n category: 'jsx',\n description: 'Warn when <For> is used without a `by` prop.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const name = node.name\n if (!name || name.type !== 'JSXIdentifier' || name.name !== 'For') return\n if (hasJSXAttribute(node, 'by')) return\n context.report({\n message:\n '`<For>` without `by` prop — provide a key function for efficient reconciliation.',\n span: getSpan(node),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nconst INPUT_TAGS = new Set(['input', 'textarea', 'select'])\n\nexport const noOnChange: Rule = {\n meta: {\n id: 'pyreon/no-onchange',\n category: 'jsx',\n description:\n 'Prefer `onInput` over `onChange` on input elements for keypress-by-keypress updates.',\n severity: 'warn',\n fixable: true,\n },\n create(context) {\n let currentTag: string | null = null\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const name = node.name\n if (name?.type === 'JSXIdentifier' && INPUT_TAGS.has(name.name)) {\n currentTag = name.name\n } else {\n currentTag = null\n }\n\n if (!currentTag) return\n const attrs = node.attributes ?? []\n for (const attr of attrs) {\n if (\n attr.type === 'JSXAttribute' &&\n attr.name?.type === 'JSXIdentifier' &&\n attr.name.name === 'onChange'\n ) {\n const nameSpan = getSpan(attr.name)\n context.report({\n message: `Use \\`onInput\\` instead of \\`onChange\\` on \\`<${currentTag}>\\` for keypress-by-keypress updates.`,\n span: getSpan(attr),\n fix: { span: nameSpan, replacement: 'onInput' },\n })\n }\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isDestructuring } from '../../utils/ast'\n\nfunction containsJSXReturn(node: any): boolean {\n if (!node) return false\n if (node.type === 'JSXElement' || node.type === 'JSXFragment') return true\n if (node.type === 'ParenthesizedExpression') return containsJSXReturn(node.expression)\n\n if (node.type === 'BlockStatement') {\n for (const stmt of node.body ?? []) {\n if (stmt.type === 'ReturnStatement' && containsJSXReturn(stmt.argument)) {\n return true\n }\n }\n }\n return false\n}\n\n/**\n * Extract destructured property names from an ObjectPattern.\n * Returns names for the fix suggestion.\n */\nfunction getDestructuredNames(pattern: any): string[] {\n if (pattern.type !== 'ObjectPattern') return []\n const names: string[] = []\n for (const prop of pattern.properties ?? []) {\n if (prop.type === 'ObjectProperty' && prop.key?.type === 'Identifier') {\n names.push(prop.key.name)\n }\n }\n return names\n}\n\nexport const noPropsDestructure: Rule = {\n meta: {\n id: 'pyreon/no-props-destructure',\n category: 'jsx',\n description:\n 'Disallow destructuring props in component functions — breaks reactive prop tracking. Use props.x or splitProps().',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n let functionDepth = 0\n\n const callbacks: VisitorCallbacks = {\n ArrowFunctionExpression(node: any) {\n functionDepth++\n checkFunction(node, context, functionDepth)\n },\n 'ArrowFunctionExpression:exit'() {\n functionDepth--\n },\n FunctionDeclaration(node: any) {\n functionDepth++\n checkFunction(node, context, functionDepth)\n },\n 'FunctionDeclaration:exit'() {\n functionDepth--\n },\n FunctionExpression(node: any) {\n functionDepth++\n checkFunction(node, context, functionDepth)\n },\n 'FunctionExpression:exit'() {\n functionDepth--\n },\n }\n return callbacks\n },\n}\n\nfunction checkFunction(node: any, context: any, depth: number) {\n const params = node.params\n if (!params || params.length === 0) return\n\n const firstParam = params[0]\n if (!isDestructuring(firstParam)) return\n\n // Skip HOC inner functions (depth > 1)\n if (depth > 1) return\n\n // Skip functions passed as arguments to HOC factories\n // e.g. createLink(({ href, ...rest }) => <a {...rest} />)\n const parent = node.parent\n if (parent?.type === 'CallExpression' && parent.arguments?.includes(node)) return\n\n const body = node.body\n if (!body) return\n\n if (containsJSXReturn(body)) {\n const names = getDestructuredNames(firstParam)\n const hasRest = (firstParam.properties ?? []).some((p: any) => p.type === 'RestElement')\n\n let suggestion = 'Use `props.x` pattern for reactive prop access.'\n if (names.length > 0) {\n const propsAccess = names.map((n) => `props.${n}`).join(', ')\n suggestion = `Use \\`props\\` parameter and access as ${propsAccess}.`\n if (hasRest) {\n suggestion += ` For rest props, use \\`splitProps(props, [${names.map((n) => `'${n}'`).join(', ')}])\\`.`\n }\n }\n\n context.report({\n message:\n `Destructured props in component function — breaks reactive prop tracking. ${suggestion}`,\n span: getSpan(firstParam),\n })\n }\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isTernaryWithJSX } from '../../utils/ast'\n\nexport const noTernaryConditional: Rule = {\n meta: {\n id: 'pyreon/no-ternary-conditional',\n category: 'jsx',\n description: 'Prefer <Show> over ternary expressions with JSX branches.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let jsxExpressionDepth = 0\n const callbacks: VisitorCallbacks = {\n JSXExpressionContainer() {\n jsxExpressionDepth++\n },\n 'JSXExpressionContainer:exit'() {\n jsxExpressionDepth--\n },\n ConditionalExpression(node: any) {\n if (jsxExpressionDepth === 0) return\n if (!isTernaryWithJSX(node)) return\n context.report({\n message: 'Ternary with JSX — use `<Show>` for more efficient conditional rendering.',\n span: getSpan(node),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getJSXAttribute, getSpan, hasJSXAttribute } from '../../utils/ast'\n\nexport const useByNotKey: Rule = {\n meta: {\n id: 'pyreon/use-by-not-key',\n category: 'jsx',\n description:\n 'Use `by` prop on <For> instead of `key` — JSX reserves `key` for VNode reconciliation.',\n severity: 'error',\n fixable: true,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const tagName = node.name?.type === 'JSXIdentifier' ? node.name.name : null\n if (tagName !== 'For') return\n const keyAttr = getJSXAttribute(node, 'key')\n if (!keyAttr) return\n if (hasJSXAttribute(node, 'by')) return // already has by\n\n const attrSpan = getSpan(keyAttr.name)\n context.report({\n message:\n 'Use `by` prop on `<For>` instead of `key` — JSX reserves `key` for VNode reconciliation.',\n span: getSpan(keyAttr),\n fix: { span: attrSpan, replacement: 'by' },\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nconst DOM_METHODS = new Set([\n 'querySelector',\n 'querySelectorAll',\n 'getElementById',\n 'getElementsByClassName',\n 'getElementsByTagName',\n])\n\nexport const noDomInSetup: Rule = {\n meta: {\n id: 'pyreon/no-dom-in-setup',\n category: 'lifecycle',\n description: 'Warn when DOM query methods are used outside onMount or effect.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let safeDepth = 0 // inside onMount or effect\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (isCallTo(node, 'onMount') || isCallTo(node, 'effect')) {\n safeDepth++\n }\n\n if (safeDepth > 0) return\n\n // Check for document.querySelector() etc.\n const callee = node.callee\n if (\n callee?.type === 'MemberExpression' &&\n callee.object?.type === 'Identifier' &&\n callee.object.name === 'document' &&\n callee.property?.type === 'Identifier' &&\n DOM_METHODS.has(callee.property.name)\n ) {\n context.report({\n message: `\\`document.${callee.property.name}()\\` outside \\`onMount\\`/\\`effect\\` — DOM is not available during SSR or setup phase.`,\n span: getSpan(node),\n })\n }\n },\n 'CallExpression:exit'(node: any) {\n if (isCallTo(node, 'onMount') || isCallTo(node, 'effect')) {\n safeDepth--\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noEffectInMount: Rule = {\n meta: {\n id: 'pyreon/no-effect-in-mount',\n category: 'lifecycle',\n description:\n 'Inform when effect() is created inside onMount — effects are typically created at setup time.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n let mountDepth = 0\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (isCallTo(node, 'onMount')) {\n mountDepth++\n }\n if (mountDepth > 0 && isCallTo(node, 'effect')) {\n context.report({\n message:\n '`effect()` inside `onMount` — effects are typically created at component setup time, not inside lifecycle hooks.',\n span: getSpan(node),\n })\n }\n },\n 'CallExpression:exit'(node: any) {\n if (isCallTo(node, 'onMount')) {\n mountDepth--\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nconst NEEDS_CLEANUP = new Set(['setInterval', 'addEventListener'])\n\nexport const noMissingCleanup: Rule = {\n meta: {\n id: 'pyreon/no-missing-cleanup',\n category: 'lifecycle',\n description:\n 'Warn when onMount uses setInterval/addEventListener without returning a cleanup function.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (!isCallTo(node, 'onMount')) return\n const args = node.arguments\n if (!args || args.length === 0) return\n\n const fn = args[0]\n if (!fn) return\n if (fn.type !== 'ArrowFunctionExpression' && fn.type !== 'FunctionExpression') return\n\n const body = fn.body\n if (!body) return\n\n // Only check block bodies\n if (body.type !== 'BlockStatement') return\n\n let hasCleanupTarget = false\n let hasReturn = false\n\n function walk(n: any) {\n if (!n) return\n if (n.type === 'CallExpression') {\n const callee = n.callee\n if (callee?.type === 'Identifier' && NEEDS_CLEANUP.has(callee.name)) {\n hasCleanupTarget = true\n }\n if (\n callee?.type === 'MemberExpression' &&\n callee.property?.type === 'Identifier' &&\n NEEDS_CLEANUP.has(callee.property.name)\n ) {\n hasCleanupTarget = true\n }\n }\n if (n.type === 'ReturnStatement' && n.argument) {\n hasReturn = true\n }\n for (const key of Object.keys(n)) {\n const child = n[key]\n if (child && typeof child === 'object') {\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item.type === 'string') walk(item)\n }\n } else if (typeof child.type === 'string') {\n walk(child)\n }\n }\n }\n }\n\n walk(body)\n\n if (hasCleanupTarget && !hasReturn) {\n context.report({\n message:\n '`onMount` uses `setInterval`/`addEventListener` without returning a cleanup function — this will cause a memory leak.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noMountInEffect: Rule = {\n meta: {\n id: 'pyreon/no-mount-in-effect',\n category: 'lifecycle',\n description: 'Warn when onMount is called inside effect().',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let effectDepth = 0\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (isCallTo(node, 'effect')) {\n effectDepth++\n }\n if (effectDepth > 0 && isCallTo(node, 'onMount')) {\n context.report({\n message:\n '`onMount` inside `effect()` — `onMount` runs once on mount, not on every effect re-run.',\n span: getSpan(node),\n })\n }\n },\n 'CallExpression:exit'(node: any) {\n if (isCallTo(node, 'effect')) {\n effectDepth--\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\nimport { HEAVY_PACKAGES } from '../../utils/imports'\n\nexport const noEagerImport: Rule = {\n meta: {\n id: 'pyreon/no-eager-import',\n category: 'performance',\n description: 'Suggest lazy-loading heavy Pyreon packages (charts, code, document, flow).',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const source = node.source?.value as string\n if (!source) return\n if (HEAVY_PACKAGES.has(source)) {\n context.report({\n message: `Static import of \\`${source}\\` — consider using \\`lazy()\\` or dynamic \\`import()\\` to reduce initial bundle size.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noEffectInFor: Rule = {\n meta: {\n id: 'pyreon/no-effect-in-for',\n category: 'performance',\n description:\n 'Warn when effect() is created inside <For> — creates effects per item on every reconciliation.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let forJsxDepth = 0\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const name = node.name\n if (name?.type === 'JSXIdentifier' && name.name === 'For') {\n forJsxDepth++\n }\n },\n JSXClosingElement(node: any) {\n const name = node.name\n if (name?.type === 'JSXIdentifier' && name.name === 'For') {\n forJsxDepth--\n }\n },\n CallExpression(node: any) {\n if (forJsxDepth === 0) return\n if (isCallTo(node, 'effect')) {\n context.report({\n message:\n '`effect()` inside `<For>` — this creates a new effect for every item on each reconciliation. Lift the effect outside.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, hasJSXAttribute } from '../../utils/ast'\n\nexport const noLargeForWithoutBy: Rule = {\n meta: {\n id: 'pyreon/no-large-for-without-by',\n category: 'performance',\n description:\n 'Error when <For> is used without a `by` prop — critical for reconciliation performance.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXOpeningElement(node: any) {\n const name = node.name\n if (!name || name.type !== 'JSXIdentifier' || name.name !== 'For') return\n if (hasJSXAttribute(node, 'by')) return\n context.report({\n message:\n '`<For>` without `by` prop — provide a key function for efficient reconciliation.',\n span: getSpan(node),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const preferShowOverDisplay: Rule = {\n meta: {\n id: 'pyreon/prefer-show-over-display',\n category: 'performance',\n description: 'Suggest <Show> over conditional `display` style property in JSX.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXAttribute(node: any) {\n if (node.name?.type !== 'JSXIdentifier' || node.name.name !== 'style') return\n const value = node.value\n if (!value || value.type !== 'JSXExpressionContainer') return\n const expr = value.expression\n if (!expr || expr.type !== 'ObjectExpression') return\n\n for (const prop of expr.properties ?? []) {\n if (prop.type !== 'Property') continue\n const key = prop.key\n if (!key) continue\n const propName =\n key.type === 'Identifier' ? key.name : key.type === 'Literal' ? key.value : null\n if (propName === 'display') {\n // Check if the value is conditional\n const val = prop.value\n if (\n val?.type === 'ConditionalExpression' ||\n val?.type === 'LogicalExpression' ||\n val?.type === 'CallExpression'\n ) {\n context.report({\n message:\n 'Conditional `display` style — consider using `<Show>` for conditional rendering instead of toggling CSS display.',\n span: getSpan(prop),\n })\n }\n }\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nconst SKIP_PREFIXES = /^(use|get|is|has|[A-Z])/\n\nexport const noBareSignalInJsx: Rule = {\n meta: {\n id: 'pyreon/no-bare-signal-in-jsx',\n category: 'reactivity',\n description:\n 'Disallow bare signal calls in JSX text positions. Wrap in `() =>` for reactivity.',\n severity: 'error',\n fixable: true,\n },\n create(context) {\n let jsxDepth = 0\n const callbacks: VisitorCallbacks = {\n JSXElement() {\n jsxDepth++\n },\n 'JSXElement:exit'() {\n jsxDepth--\n },\n JSXFragment() {\n jsxDepth++\n },\n 'JSXFragment:exit'() {\n jsxDepth--\n },\n JSXExpressionContainer(node: any) {\n if (jsxDepth === 0) return\n const expr = node.expression\n if (!expr || expr.type !== 'CallExpression') return\n const callee = expr.callee\n if (!callee || callee.type !== 'Identifier') return\n\n const name: string = callee.name\n if (SKIP_PREFIXES.test(name)) return\n\n const span = getSpan(node)\n const source = context.getSourceText()\n const original = source.slice(span.start, span.end)\n // {count()} → {() => count()}\n const inner = original.slice(1, -1) // strip { }\n const fixed = `{() => ${inner}}`\n\n context.report({\n message: `Bare signal call \\`${name}()\\` in JSX text — wrap in \\`() => ${name}()\\` for fine-grained reactivity.`,\n span,\n fix: { span, replacement: fixed },\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\n/**\n * Detects destructuring the return value of useContext().\n *\n * `const { mode } = useContext(ctx)` loses reactivity when the context\n * provides getter properties. The value is captured once at setup time.\n *\n * Correct: `const ctx = useContext(Ctx)` then read `ctx.mode` lazily.\n */\nexport const noContextDestructure: Rule = {\n meta: {\n id: 'pyreon/no-context-destructure',\n category: 'reactivity',\n description:\n 'Disallow destructuring useContext() — it breaks reactivity when context provides getters.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n VariableDeclarator(node: any) {\n // Match: const { x } = useContext(...)\n const id = node.id\n const init = node.init\n if (!id || !init) return\n if (id.type !== 'ObjectPattern') return\n if (\n init.type !== 'CallExpression' ||\n init.callee?.type !== 'Identifier' ||\n init.callee.name !== 'useContext'\n )\n return\n\n context.report({\n message:\n 'Destructuring useContext() captures values once — reactive getters lose reactivity. Keep the object reference: `const ctx = useContext(Ctx)` and access `ctx.mode` lazily.',\n span: getSpan(id),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nfunction isUpdateCall(node: any): boolean {\n return (\n node.type === 'CallExpression' &&\n node.callee?.type === 'MemberExpression' &&\n node.callee.property?.type === 'Identifier' &&\n node.callee.property.name === 'update'\n )\n}\n\nexport const noEffectAssignment: Rule = {\n meta: {\n id: 'pyreon/no-effect-assignment',\n category: 'reactivity',\n description: 'Warn when an effect only contains a single .update() call.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (!isCallTo(node, 'effect')) return\n const args = node.arguments\n if (!args || args.length === 0) return\n\n const fn = args[0]\n if (!fn) return\n\n let body: any = null\n if (fn.type === 'ArrowFunctionExpression' || fn.type === 'FunctionExpression') {\n body = fn.body\n }\n if (!body) return\n\n // Arrow with expression body\n if (isUpdateCall(body)) {\n context.report({\n message:\n 'Effect contains a single `.update()` — consider using `computed()` for derived values.',\n span: getSpan(node),\n })\n return\n }\n\n // Block body with single statement\n if (body.type === 'BlockStatement') {\n const stmts = body.body\n if (stmts && stmts.length === 1) {\n const stmt = stmts[0]\n if (stmt.type === 'ExpressionStatement' && isUpdateCall(stmt.expression)) {\n context.report({\n message:\n 'Effect contains a single `.update()` — consider using `computed()` for derived values.',\n span: getSpan(node),\n })\n }\n }\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noNestedEffect: Rule = {\n meta: {\n id: 'pyreon/no-nested-effect',\n category: 'reactivity',\n description: 'Warn against nesting effect() inside another effect().',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let effectDepth = 0\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (!isCallTo(node, 'effect')) return\n if (effectDepth > 0) {\n context.report({\n message: 'Nested `effect()` — consider using `computed()` for derived values instead.',\n span: getSpan(node),\n })\n }\n effectDepth++\n },\n 'CallExpression:exit'(node: any) {\n if (isCallTo(node, 'effect')) {\n effectDepth--\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo, isPeekCall } from '../../utils/ast'\n\nexport const noPeekInTracked: Rule = {\n meta: {\n id: 'pyreon/no-peek-in-tracked',\n category: 'reactivity',\n description: 'Disallow .peek() inside effect() or computed() — it bypasses tracking.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n let trackedDepth = 0\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (isCallTo(node, 'effect') || isCallTo(node, 'computed')) {\n trackedDepth++\n }\n if (trackedDepth > 0 && isPeekCall(node)) {\n context.report({\n message:\n '`.peek()` inside a tracked scope (effect/computed) bypasses dependency tracking — use a normal signal read instead.',\n span: getSpan(node),\n })\n }\n },\n 'CallExpression:exit'(node: any) {\n if (isCallTo(node, 'effect') || isCallTo(node, 'computed')) {\n trackedDepth--\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const noSignalInLoop: Rule = {\n meta: {\n id: 'pyreon/no-signal-in-loop',\n category: 'reactivity',\n description: 'Disallow creating signals or computeds inside loops.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n let loopDepth = 0\n const callbacks: VisitorCallbacks = {\n ForStatement() {\n loopDepth++\n },\n 'ForStatement:exit'() {\n loopDepth--\n },\n ForInStatement() {\n loopDepth++\n },\n 'ForInStatement:exit'() {\n loopDepth--\n },\n ForOfStatement() {\n loopDepth++\n },\n 'ForOfStatement:exit'() {\n loopDepth--\n },\n WhileStatement() {\n loopDepth++\n },\n 'WhileStatement:exit'() {\n loopDepth--\n },\n DoWhileStatement() {\n loopDepth++\n },\n 'DoWhileStatement:exit'() {\n loopDepth--\n },\n CallExpression(node: any) {\n if (loopDepth === 0) return\n const callee = node.callee\n if (!callee || callee.type !== 'Identifier') return\n if (callee.name === 'signal' || callee.name === 'computed') {\n context.report({\n message: `\\`${callee.name}()\\` inside a loop — signals should be created once at component setup, not on every iteration.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nfunction isComponentTag(name: string): boolean {\n return name.length > 0 && name[0] === name[0]?.toUpperCase() && name[0] !== name[0]?.toLowerCase()\n}\n\n/**\n * Warn when a known signal/computed is called in a component prop position.\n * Component props are evaluated once at mount — signal reads are NOT reactive\n * unless the compiler wraps them with _rp(). The compiler handles this\n * automatically, but this rule catches manual h() calls and educates developers.\n */\nexport const noSignalInProps: Rule = {\n meta: {\n id: 'pyreon/no-signal-in-props',\n category: 'reactivity',\n description:\n 'Signal call in component prop — value captured once unless compiler wraps it. Use props.x pattern for reactivity.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXExpressionContainer(node: any) {\n const expr = node.expression\n if (!expr || expr.type !== 'CallExpression') return\n const callee = expr.callee\n if (!callee || callee.type !== 'Identifier') return\n\n const source = context.getSourceText()\n const start = node.start as number\n\n let i = start - 1\n while (i >= 0 && source[i] !== '<' && source[i] !== '>') i--\n if (i < 0 || source[i] !== '<') return\n\n const tagStart = i + 1\n let tagEnd = tagStart\n while (tagEnd < source.length && /[\\w.]/.test(source[tagEnd] ?? '')) tagEnd++\n const tagName = source.slice(tagStart, tagEnd)\n\n if (!tagName || !isComponentTag(tagName)) return\n\n context.report({\n message: `Signal call in <${tagName}> prop — use props.x pattern inside the component for reactive access.`,\n span: getSpan(expr),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noSignalLeak: Rule = {\n meta: {\n id: 'pyreon/no-signal-leak',\n category: 'reactivity',\n description: 'Warn about unused signal declarations (potential leaks).',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const signalDecls = new Map<\n string,\n { span: { start: number; end: number }; declStart: number; declEnd: number }\n >()\n const identifierOccurrences = new Map<string, Array<{ start: number; end: number }>>()\n\n const callbacks: VisitorCallbacks = {\n VariableDeclarator(node: any) {\n const init = node.init\n if (!init || !isCallTo(init, 'signal')) return\n const id = node.id\n if (!id || id.type !== 'Identifier') return\n signalDecls.set(id.name, {\n span: getSpan(node),\n declStart: id.start as number,\n declEnd: id.end as number,\n })\n },\n Identifier(node: any) {\n const name: string = node.name\n const existing = identifierOccurrences.get(name)\n if (existing) {\n existing.push({ start: node.start as number, end: node.end as number })\n } else {\n identifierOccurrences.set(name, [\n { start: node.start as number, end: node.end as number },\n ])\n }\n },\n 'Program:exit'() {\n for (const [name, { span, declStart, declEnd }] of signalDecls) {\n const occurrences = identifierOccurrences.get(name) ?? []\n // Filter out the declaration identifier itself\n const usages = occurrences.filter((o) => o.start !== declStart || o.end !== declEnd)\n if (usages.length === 0) {\n context.report({\n message: `Signal \\`${name}\\` is declared but never used — this may be a signal leak.`,\n span,\n })\n }\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo, isSetCall } from '../../utils/ast'\n\ninterface ScopeInfo {\n setCalls: Array<{ span: { start: number; end: number } }>\n hasBatch: boolean\n insideBatch: boolean\n node: any\n}\n\nexport const noUnbatchedUpdates: Rule = {\n meta: {\n id: 'pyreon/no-unbatched-updates',\n category: 'reactivity',\n description: 'Warn when 3+ .set() calls occur in the same function without batch().',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const scopeStack: ScopeInfo[] = []\n let batchDepth = 0\n\n function enterScope(node: any) {\n scopeStack.push({ setCalls: [], hasBatch: false, insideBatch: batchDepth > 0, node })\n }\n\n function exitScope() {\n const scope = scopeStack.pop()\n if (!scope) return\n if (!scope.hasBatch && !scope.insideBatch && scope.setCalls.length >= 3) {\n context.report({\n message: `${scope.setCalls.length} signal \\`.set()\\` calls without \\`batch()\\` — wrap in \\`batch(() => { ... })\\` to avoid unnecessary re-renders.`,\n span: getSpan(scope.node),\n })\n }\n }\n\n const callbacks: VisitorCallbacks = {\n FunctionDeclaration(node: any) {\n enterScope(node)\n },\n 'FunctionDeclaration:exit'() {\n exitScope()\n },\n FunctionExpression(node: any) {\n enterScope(node)\n },\n 'FunctionExpression:exit'() {\n exitScope()\n },\n ArrowFunctionExpression(node: any) {\n enterScope(node)\n },\n 'ArrowFunctionExpression:exit'() {\n exitScope()\n },\n CallExpression(node: any) {\n const currentScope = scopeStack.length > 0 ? scopeStack[scopeStack.length - 1] : undefined\n if (isCallTo(node, 'batch')) {\n batchDepth++\n if (currentScope) {\n currentScope.hasBatch = true\n }\n }\n if (currentScope && isSetCall(node)) {\n currentScope.setCalls.push({ span: getSpan(node) })\n }\n },\n 'CallExpression:exit'(node: any) {\n if (isCallTo(node, 'batch')) {\n batchDepth--\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo, isSetCall } from '../../utils/ast'\n\nexport const preferComputed: Rule = {\n meta: {\n id: 'pyreon/prefer-computed',\n category: 'reactivity',\n description: 'Suggest computed() when an effect only contains a single .set() call.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (!isCallTo(node, 'effect')) return\n const args = node.arguments\n if (!args || args.length === 0) return\n\n const fn = args[0]\n if (!fn) return\n\n let body: any = null\n if (fn.type === 'ArrowFunctionExpression' || fn.type === 'FunctionExpression') {\n body = fn.body\n }\n if (!body) return\n\n // Arrow with expression body: effect(() => x.set(y))\n if (body.type === 'CallExpression' && isSetCall(body)) {\n context.report({\n message:\n 'Effect contains a single `.set()` — consider using `computed()` instead for derived values.',\n span: getSpan(node),\n })\n return\n }\n\n // Block body with single statement: effect(() => { x.set(y) })\n if (body.type === 'BlockStatement') {\n const stmts = body.body\n if (stmts && stmts.length === 1) {\n const stmt = stmts[0]\n if (stmt.type === 'ExpressionStatement' && isSetCall(stmt.expression)) {\n context.report({\n message:\n 'Effect contains a single `.set()` — consider using `computed()` instead for derived values.',\n span: getSpan(node),\n })\n }\n }\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getJSXAttribute, getSpan } from '../../utils/ast'\nimport { extractImportInfo } from '../../utils/imports'\n\nconst EXTERNAL_PREFIXES = ['http://', 'https://', 'mailto:', 'tel:']\n\nexport const noHrefNavigation: Rule = {\n meta: {\n id: 'pyreon/no-href-navigation',\n category: 'router',\n description:\n 'Warn when `<a href>` is used in files that import @pyreon/router — use `<Link>` instead.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let importsRouter = false\n\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const info = extractImportInfo(node)\n if (info && info.source === '@pyreon/router') {\n importsRouter = true\n }\n },\n JSXOpeningElement(node: any) {\n if (!importsRouter) return\n const name = node.name\n if (!name || name.type !== 'JSXIdentifier' || name.name !== 'a') return\n\n const hrefAttr = getJSXAttribute(node, 'href')\n if (!hrefAttr) return\n\n // Get the href value\n const value = hrefAttr.value\n if (value?.type === 'Literal' && typeof value.value === 'string') {\n const href: string = value.value\n // Skip external URLs and anchor links\n if (href.startsWith('#') || EXTERNAL_PREFIXES.some((p) => href.startsWith(p))) return\n }\n\n context.report({\n message:\n '`<a href>` in a router file — use `<Link>` or `<RouterLink>` for client-side navigation.',\n span: getSpan(node),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo, isMemberCallTo } from '../../utils/ast'\n\nexport const noImperativeNavigateInRender: Rule = {\n meta: {\n id: 'pyreon/no-imperative-navigate-in-render',\n category: 'router',\n description:\n 'Error when navigate() or router.push() is called at the top level of a component — causes infinite render loops.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n // Track depth of component functions and safe callback wrappers\n // We detect components via VariableDeclarator with PascalCase name + ArrowFunctionExpression init,\n // or FunctionDeclaration with PascalCase name.\n // \"Safe\" = onMount/effect/onUnmount callbacks or JSX event handlers.\n let componentBodyDepth = 0\n let safeDepth = 0\n\n const callbacks: VisitorCallbacks = {\n FunctionDeclaration(node: any) {\n const name: string = node.id?.name ?? ''\n if (/^[A-Z]/.test(name)) {\n componentBodyDepth++\n }\n },\n 'FunctionDeclaration:exit'(node: any) {\n const name: string = node.id?.name ?? ''\n if (/^[A-Z]/.test(name)) {\n componentBodyDepth--\n }\n },\n // For arrow functions, we use VariableDeclarator to detect component assignment\n VariableDeclarator(node: any) {\n const name: string = node.id?.name ?? ''\n if (/^[A-Z]/.test(name) && node.init?.type === 'ArrowFunctionExpression') {\n componentBodyDepth++\n }\n },\n 'VariableDeclarator:exit'(node: any) {\n const name: string = node.id?.name ?? ''\n if (/^[A-Z]/.test(name) && node.init?.type === 'ArrowFunctionExpression') {\n componentBodyDepth--\n }\n },\n // Track safe callback boundaries: onMount(() => ...), effect(() => ...), etc.\n CallExpression(node: any) {\n if (componentBodyDepth <= 0) return\n\n // Check if this is a safe wrapper entering\n if (isSafeWrapperCall(node)) {\n safeDepth++\n }\n\n // Only report if we're in a component body and NOT inside a safe callback\n if (safeDepth > 0) return\n\n if (isCallTo(node, 'navigate') || isMemberCallTo(node, 'router', 'push')) {\n context.report({\n message:\n 'Imperative navigation at the top level of a component — this runs on every render and causes infinite loops. Move inside `onMount`, `effect`, or an event handler.',\n span: getSpan(node),\n })\n }\n },\n 'CallExpression:exit'(node: any) {\n if (componentBodyDepth <= 0) return\n if (isSafeWrapperCall(node)) {\n safeDepth--\n }\n },\n }\n return callbacks\n },\n}\n\nfunction isSafeWrapperCall(node: any): boolean {\n const callee = node.callee\n if (!callee || callee.type !== 'Identifier') return false\n const name: string = callee.name\n return name === 'onMount' || name === 'effect' || name === 'onUnmount'\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\nimport { extractImportInfo } from '../../utils/imports'\n\nfunction isCatchAllPath(value: string): boolean {\n return value === '*' || value.endsWith('*')\n}\n\nfunction getPathValue(prop: any): string | null {\n const key = prop.key\n if (!key) return null\n const keyName = key.type === 'Identifier' ? key.name : null\n if (keyName !== 'path') return null\n const val = prop.value\n if (val?.type === 'Literal' && typeof val.value === 'string') {\n return val.value\n }\n return null\n}\n\nfunction hasPathProperty(obj: any): boolean {\n if (!obj || obj.type !== 'ObjectExpression') return false\n for (const prop of obj.properties ?? []) {\n if (prop.type !== 'Property') continue\n if (getPathValue(prop) !== null) return true\n }\n return false\n}\n\nfunction hasCatchAllRoute(elements: any[]): boolean {\n for (const elem of elements) {\n if (!elem || elem.type !== 'ObjectExpression') continue\n for (const prop of elem.properties ?? []) {\n if (prop.type !== 'Property') continue\n const pathVal = getPathValue(prop)\n if (pathVal !== null && isCatchAllPath(pathVal)) return true\n }\n }\n return false\n}\n\nexport const noMissingFallback: Rule = {\n meta: {\n id: 'pyreon/no-missing-fallback',\n category: 'router',\n description:\n 'Warn when route config has no catch-all route (`path: \"*\"` or `path: \"/:rest*\"`).',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let importsRouter = false\n let routeArraySpan: { start: number; end: number } | null = null\n let foundCatchAll = false\n\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const info = extractImportInfo(node)\n if (info && info.source === '@pyreon/router') {\n importsRouter = true\n }\n },\n ArrayExpression(node: any) {\n if (!importsRouter) return\n const elements = node.elements ?? []\n const isRouteArray = elements.some((e: any) => hasPathProperty(e))\n if (!isRouteArray) return\n\n if (!routeArraySpan) {\n routeArraySpan = getSpan(node)\n }\n if (hasCatchAllRoute(elements)) {\n foundCatchAll = true\n }\n },\n 'Program:exit'() {\n if (!importsRouter || !routeArraySpan || foundCatchAll) return\n context.report({\n message:\n 'Route config has no catch-all route — add a `{ path: \"*\", component: NotFound }` for unmatched URLs.',\n span: routeArraySpan,\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const preferUseIsActive: Rule = {\n meta: {\n id: 'pyreon/prefer-use-is-active',\n category: 'router',\n description:\n 'Suggest useIsActive() instead of `location.pathname === \"/foo\"` or `route.path === \"/foo\"` patterns.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n BinaryExpression(node: any) {\n if (node.operator !== '===' && node.operator !== '==') return\n\n // Check both sides for location.pathname or route.path\n if (isPathComparison(node.left) || isPathComparison(node.right)) {\n context.report({\n message:\n 'Manual path comparison — use `useIsActive()` for reactive route matching with segment-aware prefix matching.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n\nfunction isPathComparison(node: any): boolean {\n if (!node || node.type !== 'MemberExpression') return false\n const obj = node.object\n const prop = node.property\n if (!obj || !prop || prop.type !== 'Identifier') return false\n\n // location.pathname\n if (obj.type === 'Identifier' && obj.name === 'location' && prop.name === 'pathname') return true\n\n // route.path\n if (obj.type === 'Identifier' && obj.name === 'route' && prop.name === 'path') return true\n\n return false\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isMemberCallTo } from '../../utils/ast'\n\nexport const noMismatchRisk: Rule = {\n meta: {\n id: 'pyreon/no-mismatch-risk',\n category: 'ssr',\n description:\n 'Warn about non-deterministic calls (Date.now, Math.random, crypto.randomUUID) in JSX context that cause hydration mismatches.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let jsxDepth = 0\n const callbacks: VisitorCallbacks = {\n JSXElement() {\n jsxDepth++\n },\n 'JSXElement:exit'() {\n jsxDepth--\n },\n JSXFragment() {\n jsxDepth++\n },\n 'JSXFragment:exit'() {\n jsxDepth--\n },\n CallExpression(node: any) {\n if (jsxDepth === 0) return\n\n if (\n isMemberCallTo(node, 'Date', 'now') ||\n isMemberCallTo(node, 'Math', 'random') ||\n isMemberCallTo(node, 'crypto', 'randomUUID')\n ) {\n const callee = node.callee\n const name = `${callee.object.name}.${callee.property.name}`\n context.report({\n message: `\\`${name}()\\` in JSX context — this produces different values on server and client, causing hydration mismatches.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\nimport { BROWSER_GLOBALS } from '../../utils/imports'\n\nexport const noWindowInSsr: Rule = {\n meta: {\n id: 'pyreon/no-window-in-ssr',\n category: 'ssr',\n description: 'Disallow browser globals outside onMount/effect/typeof guards — they break SSR.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n let safeDepth = 0\n let typeofGuardDepth = 0\n\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (isCallTo(node, 'onMount') || isCallTo(node, 'effect')) {\n safeDepth++\n }\n },\n 'CallExpression:exit'(node: any) {\n if (isCallTo(node, 'onMount') || isCallTo(node, 'effect')) {\n safeDepth--\n }\n },\n IfStatement(node: any) {\n // typeof window !== \"undefined\"\n const test = node.test\n if (\n test?.type === 'BinaryExpression' &&\n test.left?.type === 'UnaryExpression' &&\n test.left.operator === 'typeof'\n ) {\n typeofGuardDepth++\n }\n },\n 'IfStatement:exit'(node: any) {\n const test = node.test\n if (\n test?.type === 'BinaryExpression' &&\n test.left?.type === 'UnaryExpression' &&\n test.left.operator === 'typeof'\n ) {\n typeofGuardDepth--\n }\n },\n Identifier(node: any, parent: any) {\n if (safeDepth > 0 || typeofGuardDepth > 0) return\n if (!BROWSER_GLOBALS.has(node.name)) return\n\n // Skip typeof expressions: typeof window\n if (parent?.type === 'UnaryExpression' && parent.operator === 'typeof') return\n\n // Skip import specifiers\n if (\n parent?.type === 'ImportSpecifier' ||\n parent?.type === 'ImportDefaultSpecifier' ||\n parent?.type === 'ImportNamespaceSpecifier'\n )\n return\n\n // Skip property access on member expressions (only flag when used as the object)\n if (parent?.type === 'MemberExpression' && parent.property === node && !parent.computed)\n return\n\n context.report({\n message: `Browser global \\`${node.name}\\` used outside \\`onMount\\`/\\`effect\\`/typeof guard — this will fail during SSR. Wrap in \\`onMount(() => { ... })\\`.`,\n span: getSpan(node),\n })\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const preferRequestContext: Rule = {\n meta: {\n id: 'pyreon/prefer-request-context',\n category: 'ssr',\n description:\n 'Warn about module-level signal()/createStore() in server files — use request context instead.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const filePath = context.getFilePath()\n const isServerFile =\n filePath.includes('server') ||\n filePath.includes('.server.') ||\n filePath.endsWith('server.ts') ||\n filePath.endsWith('server.tsx')\n\n if (!isServerFile) return {}\n\n let functionDepth = 0\n const callbacks: VisitorCallbacks = {\n FunctionDeclaration() {\n functionDepth++\n },\n 'FunctionDeclaration:exit'() {\n functionDepth--\n },\n FunctionExpression() {\n functionDepth++\n },\n 'FunctionExpression:exit'() {\n functionDepth--\n },\n ArrowFunctionExpression() {\n functionDepth++\n },\n 'ArrowFunctionExpression:exit'() {\n functionDepth--\n },\n CallExpression(node: any) {\n if (functionDepth > 0) return // only flag module-level calls\n if (isCallTo(node, 'signal') || isCallTo(node, 'createStore')) {\n const name = node.callee.name\n context.report({\n message: `Module-level \\`${name}()\\` in a server file — this state is shared across all requests. Use \\`runWithRequestContext()\\` for per-request isolation.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noDuplicateStoreId: Rule = {\n meta: {\n id: 'pyreon/no-duplicate-store-id',\n category: 'store',\n description: 'Disallow duplicate defineStore() IDs in the same file.',\n severity: 'error',\n fixable: false,\n },\n create(context) {\n const storeIds = new Map<string, { start: number; end: number }>()\n\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n if (!isCallTo(node, 'defineStore')) return\n const args = node.arguments\n if (!args || args.length === 0) return\n\n const firstArg = args[0]\n if (!firstArg) return\n\n let id: string | null = null\n if (firstArg.type === 'Literal' || firstArg.type === 'StringLiteral') {\n id = firstArg.value as string\n }\n\n if (typeof id !== 'string') return\n\n if (storeIds.has(id)) {\n context.report({\n message: `Duplicate store ID \\`\"${id}\"\\` — each \\`defineStore()\\` must have a unique ID.`,\n span: getSpan(node),\n })\n } else {\n storeIds.set(id, getSpan(node))\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const noMutateStoreState: Rule = {\n meta: {\n id: 'pyreon/no-mutate-store-state',\n category: 'store',\n description: 'Warn when directly calling .set() on store signals — use store actions instead.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n CallExpression(node: any) {\n const callee = node.callee\n if (!callee || callee.type !== 'MemberExpression') return\n if (callee.property?.type !== 'Identifier' || callee.property.name !== 'set') return\n\n // Check for store.signal.set() pattern — member.member.set()\n const obj = callee.object\n if (!obj || obj.type !== 'MemberExpression') return\n const outerObj = obj.object\n if (!outerObj || outerObj.type !== 'Identifier') return\n\n const name: string = outerObj.name\n // Heuristic: if the outer object name contains \"store\" (case-insensitive)\n if (name.toLowerCase().includes('store')) {\n context.report({\n message: `Direct \\`.set()\\` on store state \\`${name}\\` — use store actions to mutate state for better traceability.`,\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\nimport { extractImportInfo } from '../../utils/imports'\n\nexport const noStoreOutsideProvider: Rule = {\n meta: {\n id: 'pyreon/no-store-outside-provider',\n category: 'store',\n description: 'Warn when store hooks are used in SSR files without a provider import.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const filePath = context.getFilePath()\n const isServerFile =\n filePath.includes('server') ||\n filePath.includes('.server.') ||\n filePath.endsWith('server.ts') ||\n filePath.endsWith('server.tsx')\n\n if (!isServerFile) return {}\n\n let hasProviderImport = false\n const storeHookCalls: Array<{ name: string; span: { start: number; end: number } }> = []\n\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const info = extractImportInfo(node)\n if (!info) return\n if (\n info.specifiers.some(\n (s) =>\n s.imported === 'setStoreRegistryProvider' || s.imported === 'runWithRequestContext',\n )\n ) {\n hasProviderImport = true\n }\n },\n CallExpression(node: any) {\n const callee = node.callee\n if (!callee || callee.type !== 'Identifier') return\n const name: string = callee.name\n if (name.endsWith('Store') && name.startsWith('use')) {\n storeHookCalls.push({ name, span: getSpan(node) })\n }\n },\n 'Program:exit'() {\n if (hasProviderImport) return\n for (const call of storeHookCalls) {\n context.report({\n message: `\\`${call.name}()\\` in a server file without a store registry provider — use \\`runWithRequestContext()\\` or \\`setStoreRegistryProvider()\\` for SSR isolation.`,\n span: call.span,\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\n\nexport const noDynamicStyled: Rule = {\n meta: {\n id: 'pyreon/no-dynamic-styled',\n category: 'styling',\n description:\n 'Warn when styled() is called inside a function — it creates new CSS on every render.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let functionDepth = 0\n const callbacks: VisitorCallbacks = {\n FunctionDeclaration() {\n functionDepth++\n },\n 'FunctionDeclaration:exit'() {\n functionDepth--\n },\n FunctionExpression() {\n functionDepth++\n },\n 'FunctionExpression:exit'() {\n functionDepth--\n },\n ArrowFunctionExpression() {\n functionDepth++\n },\n 'ArrowFunctionExpression:exit'() {\n functionDepth--\n },\n CallExpression(node: any) {\n if (functionDepth === 0) return\n if (isCallTo(node, 'styled')) {\n context.report({\n message:\n '`styled()` inside a function — this creates new CSS rules on every render. Move `styled()` to module scope.',\n span: getSpan(node),\n })\n }\n },\n TaggedTemplateExpression(node: any) {\n if (functionDepth === 0) return\n const tag = node.tag\n if (!tag) return\n // styled('div')`...` — tag is a CallExpression of styled\n if (tag.type === 'CallExpression' && isCallTo(tag, 'styled')) {\n context.report({\n message:\n '`styled()` tagged template inside a function — this creates new CSS rules on every render. Move to module scope.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const noInlineStyleObject: Rule = {\n meta: {\n id: 'pyreon/no-inline-style-object',\n category: 'styling',\n description: 'Warn against inline style objects in JSX — prefer styled() or css``.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXAttribute(node: any) {\n if (node.name?.type !== 'JSXIdentifier' || node.name.name !== 'style') return\n const value = node.value\n if (!value || value.type !== 'JSXExpressionContainer') return\n const expr = value.expression\n if (expr?.type === 'ObjectExpression') {\n context.report({\n message:\n 'Inline style object in JSX — consider using `styled()` or `css\\\\`...\\\\`` for better performance and caching.',\n span: getSpan(node),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan, isCallTo } from '../../utils/ast'\nimport { extractImportInfo } from '../../utils/imports'\n\nexport const noThemeOutsideProvider: Rule = {\n meta: {\n id: 'pyreon/no-theme-outside-provider',\n category: 'styling',\n description: 'Warn when useTheme() is used without PyreonUI or ThemeProvider in the same file.',\n severity: 'warn',\n fixable: false,\n },\n create(context) {\n let hasProviderImport = false\n const themeCalls: Array<{ span: { start: number; end: number } }> = []\n\n const callbacks: VisitorCallbacks = {\n ImportDeclaration(node: any) {\n const info = extractImportInfo(node)\n if (!info) return\n if (\n info.specifiers.some((s) => s.imported === 'PyreonUI' || s.imported === 'ThemeProvider')\n ) {\n hasProviderImport = true\n }\n },\n CallExpression(node: any) {\n if (isCallTo(node, 'useTheme')) {\n themeCalls.push({ span: getSpan(node) })\n }\n },\n 'Program:exit'() {\n if (hasProviderImport) return\n for (const call of themeCalls) {\n context.report({\n message:\n '`useTheme()` without a `PyreonUI` or `ThemeProvider` import — the theme context may not be available.',\n span: call.span,\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule, VisitorCallbacks } from '../../types'\nimport { getSpan } from '../../utils/ast'\n\nexport const preferCx: Rule = {\n meta: {\n id: 'pyreon/prefer-cx',\n category: 'styling',\n description:\n 'Suggest cx() for class composition instead of string concatenation or template literals.',\n severity: 'info',\n fixable: false,\n },\n create(context) {\n const callbacks: VisitorCallbacks = {\n JSXAttribute(node: any) {\n if (node.name?.type !== 'JSXIdentifier' || node.name.name !== 'class') return\n const value = node.value\n if (!value || value.type !== 'JSXExpressionContainer') return\n const expr = value.expression\n if (!expr) return\n\n // String concatenation: \"foo \" + bar\n if (expr.type === 'BinaryExpression' && expr.operator === '+') {\n context.report({\n message:\n 'String concatenation in `class` attribute — use `cx()` for cleaner class composition.',\n span: getSpan(expr),\n })\n return\n }\n\n // Template literal: `foo ${bar}`\n if (expr.type === 'TemplateLiteral' && expr.expressions?.length > 0) {\n context.report({\n message:\n 'Template literal in `class` attribute — use `cx()` for cleaner class composition.',\n span: getSpan(expr),\n })\n }\n },\n }\n return callbacks\n },\n}\n","import type { Rule } from '../types'\nimport { dialogA11y } from './accessibility/dialog-a11y'\nimport { overlayA11y } from './accessibility/overlay-a11y'\n// Accessibility\nimport { toastA11y } from './accessibility/toast-a11y'\nimport { devGuardWarnings } from './architecture/dev-guard-warnings'\n// Architecture\nimport { noCircularImport } from './architecture/no-circular-import'\nimport { noCrossLayerImport } from './architecture/no-cross-layer-import'\nimport { noDeepImport } from './architecture/no-deep-import'\nimport { noErrorWithoutPrefix } from './architecture/no-error-without-prefix'\nimport { noProcessDevGate } from './architecture/no-process-dev-gate'\nimport { noSubmitWithoutValidation } from './form/no-submit-without-validation'\n// Form\nimport { noUnregisteredField } from './form/no-unregistered-field'\nimport { preferFieldArray } from './form/prefer-field-array'\n// Hooks\nimport { noRawAddEventListener } from './hooks/no-raw-addeventlistener'\nimport { noRawLocalStorage } from './hooks/no-raw-localstorage'\nimport { noRawSetInterval } from './hooks/no-raw-setinterval'\nimport { noAndConditional } from './jsx/no-and-conditional'\nimport { noChildrenAccess } from './jsx/no-children-access'\nimport { noClassName } from './jsx/no-classname'\nimport { noHtmlFor } from './jsx/no-htmlfor'\nimport { noIndexAsBy } from './jsx/no-index-as-by'\n// JSX\nimport { noMapInJsx } from './jsx/no-map-in-jsx'\nimport { noMissingForBy } from './jsx/no-missing-for-by'\nimport { noOnChange } from './jsx/no-onchange'\nimport { noPropsDestructure } from './jsx/no-props-destructure'\nimport { noTernaryConditional } from './jsx/no-ternary-conditional'\nimport { useByNotKey } from './jsx/use-by-not-key'\nimport { noDomInSetup } from './lifecycle/no-dom-in-setup'\nimport { noEffectInMount } from './lifecycle/no-effect-in-mount'\n// Lifecycle\nimport { noMissingCleanup } from './lifecycle/no-missing-cleanup'\nimport { noMountInEffect } from './lifecycle/no-mount-in-effect'\nimport { noEagerImport } from './performance/no-eager-import'\nimport { noEffectInFor } from './performance/no-effect-in-for'\n// Performance\nimport { noLargeForWithoutBy } from './performance/no-large-for-without-by'\nimport { preferShowOverDisplay } from './performance/prefer-show-over-display'\n// Reactivity\nimport { noBareSignalInJsx } from './reactivity/no-bare-signal-in-jsx'\nimport { noContextDestructure } from './reactivity/no-context-destructure'\nimport { noEffectAssignment } from './reactivity/no-effect-assignment'\nimport { noNestedEffect } from './reactivity/no-nested-effect'\nimport { noPeekInTracked } from './reactivity/no-peek-in-tracked'\nimport { noSignalInLoop } from './reactivity/no-signal-in-loop'\nimport { noSignalInProps } from './reactivity/no-signal-in-props'\nimport { noSignalLeak } from './reactivity/no-signal-leak'\nimport { noUnbatchedUpdates } from './reactivity/no-unbatched-updates'\nimport { preferComputed } from './reactivity/prefer-computed'\n// Router\nimport { noHrefNavigation } from './router/no-href-navigation'\nimport { noImperativeNavigateInRender } from './router/no-imperative-navigate-in-render'\nimport { noMissingFallback } from './router/no-missing-fallback'\nimport { preferUseIsActive } from './router/prefer-use-is-active'\nimport { noMismatchRisk } from './ssr/no-mismatch-risk'\n// SSR\nimport { noWindowInSsr } from './ssr/no-window-in-ssr'\nimport { preferRequestContext } from './ssr/prefer-request-context'\nimport { noDuplicateStoreId } from './store/no-duplicate-store-id'\nimport { noMutateStoreState } from './store/no-mutate-store-state'\n// Store\nimport { noStoreOutsideProvider } from './store/no-store-outside-provider'\nimport { noDynamicStyled } from './styling/no-dynamic-styled'\n// Styling\nimport { noInlineStyleObject } from './styling/no-inline-style-object'\nimport { noThemeOutsideProvider } from './styling/no-theme-outside-provider'\nimport { preferCx } from './styling/prefer-cx'\n\nexport const allRules: Rule[] = [\n // Reactivity (10)\n noBareSignalInJsx,\n noContextDestructure,\n noSignalInLoop,\n noSignalInProps,\n noNestedEffect,\n noPeekInTracked,\n noUnbatchedUpdates,\n preferComputed,\n noEffectAssignment,\n noSignalLeak,\n // JSX (11)\n noMapInJsx,\n useByNotKey,\n noClassName,\n noHtmlFor,\n noOnChange,\n noTernaryConditional,\n noAndConditional,\n noIndexAsBy,\n noMissingForBy,\n noPropsDestructure,\n noChildrenAccess,\n // Lifecycle (4)\n noMissingCleanup,\n noMountInEffect,\n noEffectInMount,\n noDomInSetup,\n // Performance (4)\n noLargeForWithoutBy,\n noEffectInFor,\n noEagerImport,\n preferShowOverDisplay,\n // SSR (3)\n noWindowInSsr,\n noMismatchRisk,\n preferRequestContext,\n // Architecture (6)\n noCircularImport,\n noDeepImport,\n noCrossLayerImport,\n devGuardWarnings,\n noErrorWithoutPrefix,\n noProcessDevGate,\n // Store (3)\n noStoreOutsideProvider,\n noMutateStoreState,\n noDuplicateStoreId,\n // Form (3)\n noUnregisteredField,\n noSubmitWithoutValidation,\n preferFieldArray,\n // Styling (4)\n noInlineStyleObject,\n noDynamicStyled,\n preferCx,\n noThemeOutsideProvider,\n // Hooks (3)\n noRawAddEventListener,\n noRawSetInterval,\n noRawLocalStorage,\n // Accessibility (3)\n toastA11y,\n dialogA11y,\n overlayA11y,\n // Router (4)\n noHrefNavigation,\n noImperativeNavigateInRender,\n noMissingFallback,\n preferUseIsActive,\n]\n\n// Re-export all rules individually\nexport {\n devGuardWarnings,\n dialogA11y,\n noAndConditional,\n // Reactivity\n noBareSignalInJsx,\n noContextDestructure,\n noChildrenAccess,\n // Architecture\n noCircularImport,\n noClassName,\n noCrossLayerImport,\n noDeepImport,\n noDomInSetup,\n noDuplicateStoreId,\n noDynamicStyled,\n noEagerImport,\n noEffectAssignment,\n noEffectInFor,\n noEffectInMount,\n noErrorWithoutPrefix,\n noHrefNavigation,\n noHtmlFor,\n noImperativeNavigateInRender,\n noIndexAsBy,\n // Styling\n noInlineStyleObject,\n // Performance\n noLargeForWithoutBy,\n // JSX\n noMapInJsx,\n noMismatchRisk,\n // Lifecycle\n noMissingCleanup,\n noMissingFallback,\n noMissingForBy,\n noMountInEffect,\n noMutateStoreState,\n noNestedEffect,\n noOnChange,\n noPeekInTracked,\n noProcessDevGate,\n noPropsDestructure,\n // Hooks\n noRawAddEventListener,\n noRawLocalStorage,\n noRawSetInterval,\n noSignalInLoop,\n noSignalInProps,\n noSignalLeak,\n // Store\n noStoreOutsideProvider,\n noSubmitWithoutValidation,\n noTernaryConditional,\n noThemeOutsideProvider,\n noUnbatchedUpdates,\n // Form\n noUnregisteredField,\n // SSR\n noWindowInSsr,\n overlayA11y,\n preferComputed,\n preferCx,\n preferFieldArray,\n preferRequestContext,\n preferShowOverDisplay,\n preferUseIsActive,\n // Accessibility\n toastA11y,\n useByNotKey,\n}\n","import { allRules } from '../rules/index'\nimport type { LintConfig, PresetName, Severity } from '../types'\n\n/** Build a config where every rule uses its default severity. */\nfunction buildRecommended(): LintConfig {\n const rules: Record<string, Severity> = {}\n for (const rule of allRules) {\n rules[rule.meta.id] = rule.meta.severity\n }\n return { rules }\n}\n\n/** Build a config where every warn is promoted to error. */\nfunction buildStrict(): LintConfig {\n const base = buildRecommended()\n const rules: Record<string, Severity> = {}\n for (const [id, sev] of Object.entries(base.rules)) {\n rules[id] = sev === 'warn' ? 'error' : sev\n }\n return { rules }\n}\n\n/** Build app config — recommended but disable library-only rules. */\nfunction buildApp(): LintConfig {\n const base = buildRecommended()\n return {\n rules: {\n ...base.rules,\n 'pyreon/dev-guard-warnings': 'off',\n 'pyreon/no-error-without-prefix': 'off',\n 'pyreon/no-circular-import': 'off',\n 'pyreon/no-cross-layer-import': 'off',\n // `no-process-dev-gate` stays ON in `app` preset because the bug\n // hits user-facing browser code regardless of whether it's a lib\n // or an app.\n },\n }\n}\n\n/** Build lib config — strict + all architecture rules as error. */\nfunction buildLib(): LintConfig {\n const base = buildStrict()\n return {\n rules: {\n ...base.rules,\n 'pyreon/no-circular-import': 'error',\n 'pyreon/no-cross-layer-import': 'error',\n 'pyreon/dev-guard-warnings': 'error',\n 'pyreon/no-error-without-prefix': 'error',\n 'pyreon/no-process-dev-gate': 'error',\n },\n }\n}\n\nconst presetBuilders: Record<PresetName, () => LintConfig> = {\n recommended: buildRecommended,\n strict: buildStrict,\n app: buildApp,\n lib: buildLib,\n}\n\nexport function getPreset(name: PresetName): LintConfig {\n return presetBuilders[name]()\n}\n\nexport { buildApp, buildLib, buildRecommended, buildStrict }\n","import type { SourceLocation } from '../types'\n\n/**\n * Fast offset→line/column conversion using binary search over precomputed line starts.\n */\nexport class LineIndex {\n private lineStarts: number[]\n\n constructor(sourceText: string) {\n this.lineStarts = [0]\n for (let i = 0; i < sourceText.length; i++) {\n if (sourceText[i] === '\\n') {\n this.lineStarts.push(i + 1)\n }\n }\n }\n\n /** Convert a byte offset to a 1-based line and 0-based column. */\n locate(offset: number): SourceLocation {\n let lo = 0\n let hi = this.lineStarts.length - 1\n\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1\n if ((this.lineStarts[mid] as number) <= offset) {\n lo = mid + 1\n } else {\n hi = mid - 1\n }\n }\n\n const line = lo // 1-based (lo points one past the found index)\n const column = offset - (this.lineStarts[line - 1] as number)\n return { line, column }\n }\n}\n","export {\n getJSXAttribute,\n getJSXTagName,\n getSpan,\n hasJSXAttribute,\n hasJSXChild,\n isArrayMapCall,\n isBrowserGlobal,\n isCallTo,\n isCallToAny,\n isDestructuring,\n isFunction,\n isInsideDevGuard,\n isInsideFunction,\n isInsideJSX,\n isInsideOnMount,\n isInsideTypeofGuard,\n isJSXElement,\n isLogicalAndWithJSX,\n isMemberCallTo,\n isPeekCall,\n isSetCall,\n isTernaryWithJSX,\n} from './ast'\nexport {\n BROWSER_GLOBALS,\n CONTEXT_APIS,\n extractImportInfo,\n getLocalName,\n HEAVY_PACKAGES,\n importsName,\n isPyreonImport,\n isPyreonPackage,\n JSX_COMPONENTS,\n LIFECYCLE_APIS,\n PYREON_PREFIX,\n REACTIVITY_APIS,\n} from './imports'\nexport { LineIndex } from './source'\n\n/** Supported JS/TS file extensions for linting. */\nexport const JS_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mts', '.mjs'])\n\n/** Check if a file path has a supported JS/TS extension. */\nexport function hasJsExtension(filePath: string): boolean {\n const ext = filePath.slice(filePath.lastIndexOf('.'))\n return JS_EXTENSIONS.has(ext)\n}\n","import { parseSync, Visitor } from 'oxc-parser'\nimport type { AstCache } from './cache'\nimport type {\n Diagnostic,\n LintConfig,\n LintFileResult,\n Rule,\n RuleContext,\n Severity,\n VisitorCallbacks,\n} from './types'\nimport { JS_EXTENSIONS } from './utils/index'\nimport { LineIndex } from './utils/source'\n\nfunction getExtension(filePath: string): string {\n const lastDot = filePath.lastIndexOf('.')\n return lastDot === -1 ? '' : filePath.slice(lastDot)\n}\n\ntype OxcLang = 'jsx' | 'tsx' | 'ts' | 'js' | 'dts'\n\nfunction getLang(ext: string): OxcLang {\n if (ext === '.tsx' || ext === '.jsx') return 'tsx'\n if (ext === '.ts' || ext === '.mts') return 'ts'\n return 'js'\n}\n\nfunction createRuleContext(\n rule: Rule,\n severity: Severity,\n diagnostics: Diagnostic[],\n lineIndex: LineIndex,\n sourceText: string,\n filePath: string,\n): RuleContext {\n return {\n report(partial) {\n diagnostics.push({\n ruleId: rule.meta.id,\n severity,\n message: partial.message,\n span: partial.span,\n loc: lineIndex.locate(partial.span.start),\n fix: partial.fix,\n })\n },\n getSourceText() {\n return sourceText\n },\n getFilePath() {\n return filePath\n },\n }\n}\n\nfunction mergeCallbacks(allCallbacks: VisitorCallbacks[]): Record<string, (node: any) => void> {\n const callbacksByKey: Record<string, Array<(node: any) => void>> = {}\n\n for (const callbacks of allCallbacks) {\n for (const [key, fn] of Object.entries(callbacks)) {\n const existing = callbacksByKey[key]\n if (existing) {\n existing.push(fn as (node: any) => void)\n } else {\n callbacksByKey[key] = [fn as (node: any) => void]\n }\n }\n }\n\n const merged: Record<string, (node: any) => void> = {}\n for (const [key, fns] of Object.entries(callbacksByKey)) {\n const first = fns[0]\n if (fns.length === 1 && first) {\n merged[key] = first\n } else {\n merged[key] = (node: any) => {\n for (const fn of fns) fn(node)\n }\n }\n }\n return merged\n}\n\n/**\n * Lint a single file and return diagnostics.\n *\n * @example\n * ```ts\n * const result = lintFile(\"app.tsx\", source, allRules, getPreset(\"recommended\"))\n * for (const d of result.diagnostics) console.log(d.message)\n * ```\n */\nexport function lintFile(\n filePath: string,\n sourceText: string,\n rules: Rule[],\n config: LintConfig,\n cache?: AstCache | undefined,\n): LintFileResult {\n const ext = getExtension(filePath)\n if (!JS_EXTENSIONS.has(ext)) {\n return { filePath, diagnostics: [] }\n }\n\n // Try cache first\n let lineIndex: LineIndex\n let program: any\n const cached = cache?.get(sourceText)\n if (cached) {\n lineIndex = cached.lineIndex\n program = cached.program\n } else {\n lineIndex = new LineIndex(sourceText)\n try {\n const result = parseSync(filePath, sourceText, {\n sourceType: 'module',\n lang: getLang(ext),\n })\n program = result.program\n } catch {\n return { filePath, diagnostics: [] }\n }\n cache?.set(sourceText, { program, lineIndex })\n }\n\n const diagnostics: Diagnostic[] = []\n\n // Filter to enabled rules and create visitor callbacks\n const allCallbacks: VisitorCallbacks[] = []\n for (const rule of rules) {\n const severity = config.rules[rule.meta.id]\n if (severity === undefined || severity === 'off') continue\n const ctx = createRuleContext(rule, severity, diagnostics, lineIndex, sourceText, filePath)\n allCallbacks.push(rule.create(ctx))\n }\n\n // Walk the AST\n const visitor = new Visitor(mergeCallbacks(allCallbacks))\n visitor.visit(program)\n\n // Filter suppressed diagnostics:\n // // pyreon-lint-ignore — suppress all on next line\n // // pyreon-lint-ignore rule-name — suppress specific rule on next line\n const lines = sourceText.split('\\n')\n const filtered = diagnostics.filter((d) => {\n const prevLineIdx = d.loc.line - 2\n if (prevLineIdx < 0) return true\n const prevLine = lines[prevLineIdx]?.trim()\n if (!prevLine?.startsWith('// pyreon-lint-ignore')) return true\n const rest = prevLine.slice('// pyreon-lint-ignore'.length).trim()\n return rest.length > 0 && rest !== d.ruleId\n })\n\n filtered.sort((a, b) => a.span.start - b.span.start)\n return { filePath, diagnostics: filtered }\n}\n\n/**\n * Apply all auto-fixes to a source text.\n * Fixes are applied in reverse order to maintain correct offsets.\n */\nexport function applyFixes(sourceText: string, diagnostics: Diagnostic[]): string {\n const fixable = diagnostics.filter((d) => d.fix !== undefined)\n if (fixable.length === 0) return sourceText\n\n // Sort by start position descending (apply from end to start)\n const sorted = [...fixable].sort((a, b) => {\n const aFix = a.fix\n const bFix = b.fix\n if (!aFix || !bFix) return 0\n return bFix.span.start - aFix.span.start\n })\n\n let result = sourceText\n for (const diag of sorted) {\n const fix = diag.fix\n if (!fix) continue\n result = result.slice(0, fix.span.start) + fix.replacement + result.slice(fix.span.end)\n }\n\n return result\n}\n","import { readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'\nimport { join, resolve } from 'node:path'\nimport { AstCache } from './cache'\nimport { createIgnoreFilter } from './config/ignore'\nimport { loadConfig, loadConfigFromPath } from './config/loader'\nimport { getPreset } from './config/presets'\nimport { allRules } from './rules/index'\nimport { applyFixes, lintFile } from './runner'\nimport type { LintConfig, LintFileResult, LintOptions, LintResult, RuleMeta } from './types'\nimport { hasJsExtension } from './utils/index'\n\nfunction isHiddenOrVendor(entry: string): boolean {\n return entry.startsWith('.') || entry === 'node_modules' || entry === 'lib' || entry === 'dist'\n}\n\nfunction matchesPatterns(\n filePath: string,\n include?: string[] | undefined,\n exclude?: string[] | undefined,\n): boolean {\n if (exclude) {\n for (const pattern of exclude) {\n if (filePath.includes(pattern)) return false\n }\n }\n if (include && include.length > 0) {\n for (const pattern of include) {\n if (filePath.includes(pattern)) return true\n }\n return false\n }\n return true\n}\n\nfunction walkDirectory(\n dir: string,\n files: string[],\n isIgnored: (filePath: string) => boolean,\n include?: string[] | undefined,\n exclude?: string[] | undefined,\n): void {\n let entries: string[]\n try {\n entries = readdirSync(dir)\n } catch {\n return\n }\n for (const entry of entries) {\n if (isHiddenOrVendor(entry)) continue\n const full = join(dir, entry)\n if (isIgnored(full)) continue\n processEntry(full, files, isIgnored, include, exclude)\n }\n}\n\nfunction processEntry(\n full: string,\n files: string[],\n isIgnored: (filePath: string) => boolean,\n include?: string[] | undefined,\n exclude?: string[] | undefined,\n): void {\n let stat: ReturnType<typeof statSync>\n try {\n stat = statSync(full)\n } catch {\n return\n }\n if (stat.isDirectory()) {\n walkDirectory(full, files, isIgnored, include, exclude)\n } else if (stat.isFile() && hasJsExtension(full) && matchesPatterns(full, include, exclude)) {\n files.push(full)\n }\n}\n\nfunction collectFiles(\n dir: string,\n isIgnored: (filePath: string) => boolean,\n include?: string[] | undefined,\n exclude?: string[] | undefined,\n): string[] {\n const files: string[] = []\n walkDirectory(dir, files, isIgnored, include, exclude)\n return files\n}\n\nfunction buildConfig(options: LintOptions): {\n config: LintConfig\n include: string[] | undefined\n exclude: string[] | undefined\n isIgnored: (filePath: string) => boolean\n} {\n const cwd = resolve('.')\n const fileConfig = options.config ? loadConfigFromPath(options.config) : loadConfig(cwd)\n\n const presetName = options.preset ?? fileConfig?.preset ?? 'recommended'\n const config = getPreset(presetName)\n\n // Merge config file rule overrides\n if (fileConfig?.rules) {\n for (const [id, severity] of Object.entries(fileConfig.rules)) {\n config.rules[id] = severity\n }\n }\n\n // CLI rule overrides (highest priority)\n if (options.ruleOverrides) {\n for (const [id, severity] of Object.entries(options.ruleOverrides)) {\n config.rules[id] = severity\n }\n }\n\n return {\n config,\n include: fileConfig?.include,\n exclude: fileConfig?.exclude,\n isIgnored: createIgnoreFilter(cwd, options.ignore),\n }\n}\n\nfunction gatherFiles(\n paths: string[],\n isIgnored: (filePath: string) => boolean,\n include?: string[] | undefined,\n exclude?: string[] | undefined,\n): string[] {\n const files: string[] = []\n for (const p of paths) {\n const resolved = resolve(p)\n let stat: ReturnType<typeof statSync>\n try {\n stat = statSync(resolved)\n } catch {\n continue\n }\n if (stat.isDirectory()) {\n files.push(...collectFiles(resolved, isIgnored, include, exclude))\n } else if (stat.isFile() && !isIgnored(resolved)) {\n files.push(resolved)\n }\n }\n return files\n}\n\nfunction applyFixesToFile(fileResult: LintFileResult, source: string): void {\n const fixable = fileResult.diagnostics.filter((d) => d.fix)\n if (fixable.length === 0) return\n const fixed = applyFixes(source, fileResult.diagnostics)\n writeFileSync(fileResult.filePath, fixed, 'utf-8')\n fileResult.fixedSource = fixed\n fileResult.diagnostics = fileResult.diagnostics.filter((d) => !d.fix)\n}\n\nfunction countDiagnostics(fileResult: LintFileResult, results: LintResult): void {\n for (const d of fileResult.diagnostics) {\n if (d.severity === 'error') results.totalErrors++\n else if (d.severity === 'warn') results.totalWarnings++\n else if (d.severity === 'info') results.totalInfos++\n }\n}\n\n/**\n * Lint files and return results.\n *\n * @example\n * ```ts\n * import { lint } from \"@pyreon/lint\"\n *\n * const result = lint({ paths: [\"src/\"], preset: \"recommended\" })\n * console.log(result.totalErrors) // 0\n * ```\n */\nexport function lint(options: LintOptions): LintResult {\n const { config, include, exclude, isIgnored } = buildConfig(options)\n const cache = new AstCache()\n const files = gatherFiles(options.paths, isIgnored, include, exclude)\n\n const results: LintResult = {\n files: [],\n totalErrors: 0,\n totalWarnings: 0,\n totalInfos: 0,\n }\n\n for (const filePath of files) {\n let source: string\n try {\n source = readFileSync(filePath, 'utf-8')\n } catch {\n continue\n }\n const fileResult = lintFile(filePath, source, allRules, config, cache)\n if (options.fix) {\n applyFixesToFile(fileResult, source)\n }\n if (options.quiet) {\n fileResult.diagnostics = fileResult.diagnostics.filter((d) => d.severity === 'error')\n }\n countDiagnostics(fileResult, results)\n results.files.push(fileResult)\n }\n\n return results\n}\n\n/**\n * List all available rules with their metadata.\n *\n * @example\n * ```ts\n * import { listRules } from \"@pyreon/lint\"\n *\n * for (const rule of listRules()) {\n * console.log(`${rule.id} (${rule.severity}): ${rule.description}`)\n * }\n * ```\n */\nexport function listRules(): RuleMeta[] {\n return allRules.map((r) => r.meta)\n}\n","/**\n * Minimal LSP server for @pyreon/lint.\n *\n * Provides real-time Pyreon-specific diagnostics in editors that support\n * the Language Server Protocol (VS Code, Neovim, etc.).\n *\n * Usage: pyreon-lint --lsp\n *\n * The server communicates via JSON-RPC over stdin/stdout following the\n * LSP specification (https://microsoft.github.io/language-server-protocol/).\n *\n * Supported capabilities:\n * - textDocument/didOpen — lint on open\n * - textDocument/didSave — lint on save\n * - textDocument/didChange — lint on change (debounced)\n *\n * @module\n */\n\nimport { AstCache } from '../cache'\nimport { getPreset } from '../config/presets'\nimport { allRules } from '../rules/index'\nimport { lintFile } from '../runner'\nimport type { Diagnostic, LintConfig } from '../types'\n\nconst cache = new AstCache()\nconst config: LintConfig = getPreset('recommended')\n\n// ─── JSON-RPC message types ────────────────────────────────────────────────\n\ninterface JsonRpcMessage {\n jsonrpc: '2.0'\n id?: number | string | undefined\n method?: string | undefined\n params?: any\n result?: any\n}\n\n// ─── LSP Diagnostic conversion ─────────────────────────────────────────────\n\ninterface LspDiagnostic {\n range: { start: { line: number; character: number }; end: { line: number; character: number } }\n severity: number\n source: string\n message: string\n code: string\n}\n\nfunction toLspDiagnostics(diagnostics: Diagnostic[]): LspDiagnostic[] {\n return diagnostics.map((d) => ({\n range: {\n start: { line: d.loc.line - 1, character: d.loc.column - 1 },\n end: { line: d.loc.line - 1, character: d.loc.column - 1 + (d.span.end - d.span.start) },\n },\n severity: d.severity === 'error' ? 1 : d.severity === 'warn' ? 2 : 3,\n source: 'pyreon-lint',\n message: d.message,\n code: d.ruleId,\n }))\n}\n\n// ─── Lint a document ───────────────────────────────────────────────────────\n\nfunction lintDocument(uri: string, text: string): LspDiagnostic[] {\n try {\n const filePath = uri.replace('file://', '')\n const result = lintFile(filePath, text, allRules, config, cache)\n return toLspDiagnostics(result.diagnostics)\n } catch {\n // Parse errors, unsupported file types — return empty diagnostics\n return []\n }\n}\n\n// ─── Debounce ──────────────────────────────────────────────────────────────\n\nconst DEBOUNCE_MS = 150\nconst debounceTimers = new Map<string, ReturnType<typeof setTimeout>>()\n\nfunction debounceLint(uri: string, text: string): void {\n const existing = debounceTimers.get(uri)\n if (existing) clearTimeout(existing)\n debounceTimers.set(\n uri,\n setTimeout(() => {\n debounceTimers.delete(uri)\n const diagnostics = lintDocument(uri, text)\n sendNotification('textDocument/publishDiagnostics', { uri, diagnostics })\n }, DEBOUNCE_MS),\n )\n}\n\n// ─── Message handling ──────────────────────────────────────────────────────\n\nconst openDocuments = new Map<string, string>()\n\nfunction handleMessage(msg: JsonRpcMessage): JsonRpcMessage | null {\n if (msg.method === 'initialize') {\n return {\n jsonrpc: '2.0',\n id: msg.id,\n result: {\n capabilities: {\n textDocumentSync: 1, // Full sync\n diagnosticProvider: { interFileDependencies: false, workspaceDiagnostics: false },\n },\n serverInfo: { name: 'pyreon-lint', version: '0.11.5' },\n },\n }\n }\n\n if (msg.method === 'initialized') {\n return null // no response needed\n }\n\n if (msg.method === 'textDocument/didOpen') {\n const { uri, text } = msg.params.textDocument\n openDocuments.set(uri, text)\n const diagnostics = lintDocument(uri, text)\n sendNotification('textDocument/publishDiagnostics', { uri, diagnostics })\n return null\n }\n\n if (msg.method === 'textDocument/didChange') {\n const uri = msg.params.textDocument.uri\n const text = msg.params.contentChanges[0]?.text\n if (text != null) {\n openDocuments.set(uri, text)\n // Debounce: wait 150ms after last keystroke before linting\n debounceLint(uri, text)\n }\n return null\n }\n\n if (msg.method === 'textDocument/didSave') {\n const uri = msg.params.textDocument.uri\n const text = openDocuments.get(uri)\n if (text) {\n const diagnostics = lintDocument(uri, text)\n sendNotification('textDocument/publishDiagnostics', { uri, diagnostics })\n }\n return null\n }\n\n if (msg.method === 'textDocument/didClose') {\n const uri = msg.params.textDocument.uri\n openDocuments.delete(uri)\n sendNotification('textDocument/publishDiagnostics', { uri, diagnostics: [] })\n return null\n }\n\n if (msg.method === 'shutdown') {\n return { jsonrpc: '2.0', id: msg.id, result: null }\n }\n\n if (msg.method === 'exit') {\n process.exit(0)\n }\n\n // Unknown method\n if (msg.id != null) {\n return {\n jsonrpc: '2.0',\n id: msg.id,\n result: null,\n }\n }\n\n return null\n}\n\n// ─── JSON-RPC transport (stdin/stdout) ─────────────────────────────────────\n\nfunction sendMessage(msg: JsonRpcMessage) {\n const body = JSON.stringify(msg)\n const header = `Content-Length: ${Buffer.byteLength(body)}\\r\\n\\r\\n`\n process.stdout.write(header + body)\n}\n\nfunction sendNotification(method: string, params: any) {\n sendMessage({ jsonrpc: '2.0', method, params })\n}\n\n/**\n * Start the LSP server. Reads JSON-RPC messages from stdin,\n * processes them, and writes responses to stdout.\n */\nexport function startLspServer(): void {\n let buffer = ''\n\n process.stdin.setEncoding('utf-8')\n process.stdin.on('data', (chunk: string) => {\n buffer += chunk\n\n // Parse Content-Length header + body\n while (true) {\n const headerEnd = buffer.indexOf('\\r\\n\\r\\n')\n if (headerEnd === -1) break\n\n const header = buffer.slice(0, headerEnd)\n const match = header.match(/Content-Length:\\s*(\\d+)/i)\n if (!match) {\n buffer = buffer.slice(headerEnd + 4)\n continue\n }\n\n const contentLength = Number.parseInt(match[1]!, 10)\n const bodyStart = headerEnd + 4\n if (buffer.length < bodyStart + contentLength) break\n\n const body = buffer.slice(bodyStart, bodyStart + contentLength)\n buffer = buffer.slice(bodyStart + contentLength)\n\n try {\n const msg = JSON.parse(body) as JsonRpcMessage\n const response = handleMessage(msg)\n if (response) sendMessage(response)\n } catch {\n // malformed JSON — ignore\n }\n }\n })\n\n process.stderr.write('[pyreon-lint] LSP server started\\n')\n}\n","import type { LintResult, Severity } from './types'\n\n// ANSI colors\nconst BOLD = '\\x1b[1m'\nconst RED = '\\x1b[31m'\nconst YELLOW = '\\x1b[33m'\nconst BLUE = '\\x1b[34m'\nconst DIM = '\\x1b[2m'\nconst RESET = '\\x1b[0m'\n\nconst SEVERITY_SYMBOL: Record<Severity, string> = {\n error: `${RED}\\u2716${RESET}`,\n warn: `${YELLOW}\\u26A0${RESET}`,\n info: `${BLUE}\\u2139${RESET}`,\n off: '',\n}\n\nconst SEVERITY_LABEL: Record<Severity, string> = {\n error: `${RED}error${RESET}`,\n warn: `${YELLOW}warning${RESET}`,\n info: `${BLUE}info${RESET}`,\n off: '',\n}\n\n/**\n * Format results as human-readable colored text.\n */\nexport function formatText(result: LintResult): string {\n const lines: string[] = []\n\n for (const file of result.files) {\n if (file.diagnostics.length === 0) continue\n\n lines.push('')\n lines.push(`${BOLD}${file.filePath}${RESET}`)\n\n for (const d of file.diagnostics) {\n const loc = `${DIM}${d.loc.line}:${d.loc.column}${RESET}`\n const severity = SEVERITY_LABEL[d.severity]\n const ruleId = `${DIM}${d.ruleId}${RESET}`\n lines.push(` ${loc} ${severity} ${d.message} ${ruleId}`)\n }\n }\n\n const total = result.totalErrors + result.totalWarnings + result.totalInfos\n if (total > 0) {\n lines.push('')\n const parts: string[] = []\n if (result.totalErrors > 0)\n parts.push(`${RED}${result.totalErrors} error${result.totalErrors === 1 ? '' : 's'}${RESET}`)\n if (result.totalWarnings > 0)\n parts.push(\n `${YELLOW}${result.totalWarnings} warning${result.totalWarnings === 1 ? '' : 's'}${RESET}`,\n )\n if (result.totalInfos > 0) parts.push(`${BLUE}${result.totalInfos} info${RESET}`)\n lines.push(`${SEVERITY_SYMBOL.error} ${parts.join(', ')}`)\n lines.push('')\n }\n\n return lines.join('\\n')\n}\n\n/**\n * Format results as JSON.\n */\nexport function formatJSON(result: LintResult): string {\n return JSON.stringify(result, null, 2)\n}\n\n/**\n * Format results as compact single-line-per-diagnostic output.\n */\nexport function formatCompact(result: LintResult): string {\n const lines: string[] = []\n\n for (const file of result.files) {\n for (const d of file.diagnostics) {\n lines.push(\n `${file.filePath}:${d.loc.line}:${d.loc.column}: ${d.severity} [${d.ruleId}] ${d.message}`,\n )\n }\n }\n\n return lines.join('\\n')\n}\n","import { readFileSync, watch } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { AstCache } from './cache'\nimport { createIgnoreFilter } from './config/ignore'\nimport { getPreset } from './config/presets'\nimport { formatCompact, formatJSON, formatText } from './reporter'\nimport { allRules } from './rules/index'\nimport { lintFile } from './runner'\nimport type { LintConfig, LintOptions, LintResult, Severity } from './types'\nimport { hasJsExtension } from './utils/index'\n\nfunction formatOutput(result: LintResult, format: string): string {\n if (format === 'json') return formatJSON(result)\n if (format === 'compact') return formatCompact(result)\n return formatText(result)\n}\n\n/**\n * Watch directories and re-lint changed files.\n *\n * Uses `fs.watch` (recursive) with 100ms debounce.\n * Caches ASTs for unchanged files.\n *\n * @example\n * ```ts\n * import { watchAndLint } from \"@pyreon/lint\"\n *\n * watchAndLint({ paths: [\"src/\"], preset: \"recommended\", format: \"text\" })\n * ```\n */\nexport function watchAndLint(options: LintOptions & { format: string }): void {\n const cache = new AstCache()\n const preset = options.preset ?? 'recommended'\n const config = getPreset(preset)\n\n applyOverrides(config, options.ruleOverrides)\n\n const cwd = resolve('.')\n const isIgnored = createIgnoreFilter(cwd, options.ignore)\n\n // Debounce map: filePath -> timeout\n const pending = new Map<string, ReturnType<typeof setTimeout>>()\n\n // oxlint-disable-next-line no-console\n console.log(`\\x1b[2m[pyreon-lint] Watching for changes...\\x1b[0m\\n`)\n\n for (const p of options.paths) {\n const dir = resolve(p)\n try {\n watch(dir, { recursive: true }, (_event, filename) => {\n if (!filename) return\n const filePath = resolve(dir, filename)\n\n if (!hasJsExtension(filePath) || isIgnored(filePath)) return\n\n // Debounce: clear existing timeout for this file\n const existing = pending.get(filePath)\n if (existing) clearTimeout(existing)\n\n pending.set(\n filePath,\n setTimeout(() => {\n pending.delete(filePath)\n relintFile(filePath, config, cache, options.format)\n }, 100),\n )\n })\n } catch {\n console.error(`[pyreon-lint] Could not watch: ${dir}`)\n }\n }\n}\n\nfunction applyOverrides(\n config: LintConfig,\n overrides?: Record<string, Severity> | undefined,\n): void {\n if (!overrides) return\n for (const [id, severity] of Object.entries(overrides)) {\n config.rules[id] = severity\n }\n}\n\nfunction relintFile(filePath: string, config: LintConfig, cache: AstCache, format: string): void {\n let source: string\n try {\n source = readFileSync(filePath, 'utf-8')\n } catch {\n return\n }\n\n const fileResult = lintFile(filePath, source, allRules, config, cache)\n\n if (fileResult.diagnostics.length === 0) return\n\n const result: LintResult = {\n files: [fileResult],\n totalErrors: 0,\n totalWarnings: 0,\n totalInfos: 0,\n }\n\n for (const d of fileResult.diagnostics) {\n if (d.severity === 'error') result.totalErrors++\n else if (d.severity === 'warn') result.totalWarnings++\n else if (d.severity === 'info') result.totalInfos++\n }\n\n // Clear screen and print\n process.stdout.write('\\x1b[2J\\x1b[H')\n console.log(formatOutput(result, format))\n}\n","#!/usr/bin/env node\nimport { lint, listRules } from './lint'\nimport { startLspServer } from './lsp/index'\nimport { formatCompact, formatJSON, formatText } from './reporter'\nimport type { PresetName, Severity } from './types'\nimport { watchAndLint } from './watcher'\n\n// Read version from package.json at build time; fallback for dev\nconst VERSION = '0.11.4'\n\nfunction printUsage() {\n console.log(`\n pyreon-lint [options] [path...]\n\n Options:\n --preset <name> Preset: recommended (default), strict, app, lib\n --fix Auto-fix fixable issues\n --format <fmt> Output: text (default), json, compact\n --quiet Only show errors\n --list List all available rules\n --rule <id>=<sev> Override rule severity\n --config <path> Config file path\n --ignore <path> Ignore file path\n --watch Watch mode — re-lint on file changes\n --lsp Start LSP server (stdin/stdout JSON-RPC)\n --help, -h Show this help\n --version, -v Show version\n`)\n}\n\nfunction printList() {\n const rules = listRules()\n const maxId = Math.max(...rules.map((r) => r.id.length))\n const maxCat = Math.max(...rules.map((r) => r.category.length))\n\n for (const rule of rules) {\n const fixLabel = rule.fixable ? ' [fixable]' : ''\n const id = rule.id.padEnd(maxId)\n const cat = rule.category.padEnd(maxCat)\n const sev = rule.severity.padEnd(5)\n console.log(` ${id} ${cat} ${sev} ${rule.description}${fixLabel}`)\n }\n\n console.log(`\\n ${rules.length} rules total`)\n}\n\ninterface CliArgs {\n preset: PresetName\n fix: boolean\n format: 'text' | 'json' | 'compact'\n quiet: boolean\n showList: boolean\n showHelp: boolean\n showVersion: boolean\n watchMode: boolean\n lspMode: boolean\n configPath: string | undefined\n ignorePath: string | undefined\n ruleOverrides: Record<string, Severity>\n paths: string[]\n}\n\nconst BOOLEAN_FLAGS: Record<string, keyof CliArgs> = {\n '--help': 'showHelp',\n '-h': 'showHelp',\n '--version': 'showVersion',\n '-v': 'showVersion',\n '--list': 'showList',\n '--fix': 'fix',\n '--quiet': 'quiet',\n '--watch': 'watchMode',\n '--lsp': 'lspMode',\n}\n\nfunction parseArgs(argv: string[]): CliArgs {\n const result: CliArgs = {\n preset: 'recommended',\n fix: false,\n format: 'text',\n quiet: false,\n showList: false,\n showHelp: false,\n showVersion: false,\n watchMode: false,\n lspMode: false,\n configPath: undefined,\n ignorePath: undefined,\n ruleOverrides: {},\n paths: [],\n }\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i] as string\n const boolKey = BOOLEAN_FLAGS[arg]\n\n if (boolKey) {\n ;(result as unknown as Record<string, unknown>)[boolKey] = true\n continue\n }\n\n const consumed = parseValueFlag(arg, argv[i + 1], result)\n i += consumed\n }\n\n return result\n}\n\n/** Returns number of extra args consumed (0 or 1). */\nfunction parseValueFlag(arg: string, nextArg: string | undefined, result: CliArgs): number {\n if (arg === '--preset') {\n result.preset = (nextArg ?? 'recommended') as PresetName\n return 1\n }\n if (arg === '--format') {\n result.format = (nextArg ?? 'text') as 'text' | 'json' | 'compact'\n return 1\n }\n if (arg === '--config') {\n result.configPath = nextArg\n return 1\n }\n if (arg === '--ignore') {\n result.ignorePath = nextArg\n return 1\n }\n if (arg === '--rule') {\n parseRuleOverride(nextArg, result.ruleOverrides)\n return 1\n }\n if (arg) {\n result.paths.push(arg)\n }\n return 0\n}\n\nfunction parseRuleOverride(val: string | undefined, overrides: Record<string, Severity>): void {\n if (!val) return\n const eqIdx = val.lastIndexOf('=')\n if (eqIdx === -1) return\n const ruleId = val.slice(0, eqIdx)\n const severity = val.slice(eqIdx + 1) as Severity\n overrides[ruleId] = severity\n}\n\nfunction main() {\n const args = parseArgs(process.argv.slice(2))\n\n if (args.showHelp) {\n printUsage()\n process.exit(0)\n }\n\n if (args.showVersion) {\n console.log(`pyreon-lint v${VERSION}`)\n process.exit(0)\n }\n\n if (args.showList) {\n printList()\n process.exit(0)\n }\n\n if (args.lspMode) {\n startLspServer()\n return\n }\n\n if (args.paths.length === 0) {\n args.paths.push('.')\n }\n\n if (args.watchMode) {\n watchAndLint({\n paths: args.paths,\n preset: args.preset,\n fix: args.fix,\n quiet: args.quiet,\n ruleOverrides: args.ruleOverrides,\n config: args.configPath,\n ignore: args.ignorePath,\n format: args.format,\n })\n return\n }\n\n const result = lint({\n paths: args.paths,\n preset: args.preset,\n fix: args.fix,\n quiet: args.quiet,\n ruleOverrides: args.ruleOverrides,\n config: args.configPath,\n ignore: args.ignorePath,\n })\n\n if (args.format === 'json') {\n console.log(formatJSON(result))\n } else if (args.format === 'compact') {\n console.log(formatCompact(result))\n } else {\n const output = formatText(result)\n if (output) console.log(output)\n }\n\n if (result.totalErrors > 0) {\n process.exit(1)\n }\n}\n\nmain()\n"],"mappings":"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"}
|