@luckystack/core 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/eslint/internal/hasPackage.ts","../../src/eslint/rules/no-arbitrary-tailwind-color.ts","../../src/eslint/rules/no-direct-prisma-import-in-components.ts","../../src/eslint/rules/no-raw-fetch-in-src.ts","../../src/eslint/rules/no-raw-try-catch.ts","../../src/eslint/rules/no-unsafe-api-wrappers.ts","../../src/eslint/rules/no-unsafe-sync-wrappers.ts","../../src/eslint/rules/prefer-luckystack-confirm.ts","../../src/eslint/rules/prefer-luckystack-dropdown.ts","../../src/eslint/rules/prefer-luckystack-notify.ts","../../src/eslint/index.ts"],"sourcesContent":["//? Peer-dep presence probe used to gate package-dependent eslint rules.\r\n//? Resolves against `process.cwd()` so the CONSUMER's node_modules drives\r\n//? activation, not this package's own resolution graph.\r\n//?\r\n//? Implementation: tries `require.resolve` first (works for CJS-compatible\r\n//? packages), falls back to an fs-based `node_modules/<name>/package.json`\r\n//? check for pure-ESM packages whose `exports` map omits the `require`\r\n//? condition (which is the case for the @luckystack/* packages themselves).\r\n\r\nimport { existsSync } from 'node:fs';\r\nimport { createRequire } from 'node:module';\r\nimport path from 'node:path';\r\n\r\nconst localRequire = createRequire(import.meta.url);\r\n\r\nconst checkOnDisk = (name: string): boolean => {\r\n const segments = name.startsWith('@')\r\n ? name.split('/').slice(0, 2)\r\n : [name.split('/')[0] ?? name];\r\n return existsSync(path.join(process.cwd(), 'node_modules', ...segments, 'package.json'));\r\n};\r\n\r\nexport const hasPackage = (name: string): boolean => {\r\n try {\r\n localRequire.resolve(name, { paths: [process.cwd()] });\r\n return true;\r\n } catch {\r\n return checkOnDisk(name);\r\n }\r\n};\r\n","//? Rule: warn on arbitrary Tailwind color values (`text-[#fff]`,\r\n//? `bg-[#abc123]`, `border-[#000]`) inside className strings. The framework\r\n//? mandates colors from `src/index.css` `@theme` block (rule 14). Arbitrary\r\n//? colors break dark-mode auto-switching.\r\n\r\n//? Double-cast disabled file-wide: this rule operates on AST nodes that span\r\n//? two type universes (eslint's `Rule.Node` vs the JSX-extended shape from\r\n//? eslint-plugin-react). Bridging them needs `as unknown as`; runtime\r\n//? guards happen via explicit `.type === 'JSXIdentifier'` checks above each\r\n//? cast.\r\n/* eslint-disable no-restricted-syntax */\r\n\r\nimport type { Rule } from 'eslint';\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\nconst ARBITRARY_COLOR_PATTERN = /\\b(?:text|bg|border|ring|fill|stroke|from|to|via|outline|decoration|accent|caret|placeholder|divide)-\\[#[0-9a-fA-F]{3,8}\\]/;\r\n\r\n//? JSX AST nodes (JSXAttribute, JSXExpressionContainer, …) are not part of\r\n//? eslint's stock estree AST. eslint-plugin-react extends the visitor map at\r\n//? runtime, but the stock `Rule.RuleListener` type does not know about them,\r\n//? so we describe the shapes we read inline. The actual eslint runtime gives\r\n//? us the right object; this is purely a TS-side annotation.\r\ntype ClassNameValueShape =\r\n | { type: 'Literal'; value: unknown }\r\n | { type: 'JSXExpressionContainer'; expression: ExpressionShape }\r\n | { type: string };\r\n\r\ntype ExpressionShape =\r\n | { type: 'Literal'; value: unknown }\r\n | { type: 'TemplateLiteral'; quasis: readonly { value: { cooked?: string; raw: string } }[] }\r\n | { type: string };\r\n\r\ninterface JsxAttributeShape {\r\n name: { type: string; name?: string };\r\n value?: ClassNameValueShape | null;\r\n}\r\n\r\nconst reportIfArbitrary = (\r\n context: Rule.RuleContext,\r\n node: Rule.Node,\r\n value: string,\r\n): void => {\r\n if (ARBITRARY_COLOR_PATTERN.test(value)) {\r\n context.report({ node, messageId: 'useThemeToken' });\r\n }\r\n};\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'suggestion',\r\n docs: {\r\n description: 'Disallow arbitrary Tailwind color values (`text-[#…]`, `bg-[#…]`, …). Use tokens from `src/index.css` `@theme` block.',\r\n },\r\n messages: {\r\n useThemeToken:\r\n 'Do not use arbitrary Tailwind color values like `text-[#…]`. Use a token from `src/index.css` `@theme` block (e.g. `bg-primary`, `text-title`, `border-divider`). Arbitrary colors break dark-mode auto-switching.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n const listener: Rule.RuleListener = {\r\n JSXAttribute(rawNode: unknown): void {\r\n const node = rawNode as JsxAttributeShape & Rule.Node;\r\n if (node.name.type !== 'JSXIdentifier' || node.name.name !== 'className') return;\r\n const value = node.value;\r\n if (!value) return;\r\n if (value.type === 'Literal' && typeof (value as { value?: unknown }).value === 'string') {\r\n reportIfArbitrary(context, value as unknown as Rule.Node, (value as { value: string }).value);\r\n return;\r\n }\r\n if (value.type === 'JSXExpressionContainer') {\r\n const expression = (value as { expression: ExpressionShape }).expression;\r\n if (expression.type === 'TemplateLiteral') {\r\n const quasis = (expression as { quasis: readonly { value: { cooked?: string; raw: string } }[] }).quasis;\r\n for (const quasi of quasis) {\r\n reportIfArbitrary(\r\n context,\r\n quasi as unknown as Rule.Node,\r\n quasi.value.cooked ?? quasi.value.raw,\r\n );\r\n }\r\n } else if (expression.type === 'Literal' && typeof (expression as { value?: unknown }).value === 'string') {\r\n reportIfArbitrary(\r\n context,\r\n expression as unknown as Rule.Node,\r\n (expression as { value: string }).value,\r\n );\r\n }\r\n }\r\n },\r\n };\r\n return listener;\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: warn on `import … from '@prisma/client'` outside of allowed\n//? boundaries. Convention: app code re-exports Prisma model types through\n//? `src/_types/<ModelName>.ts` so swapping providers / extending types\n//? stays centralised. Direct imports leak Prisma details into UI code.\n//?\n//? Allowed paths: `src/_types/**`, `server/**`, and any file ending in\n//? `Adapter.ts` (legitimate adapter implementations).\n\nimport type { EslintRule } from '../internal/ruleTypes.js';\n\nconst isAllowedPath = (filename: string): boolean => {\n const normalised = filename.replaceAll('\\\\', '/');\n if (normalised.includes('/src/_types/')) return true;\n if (normalised.includes('/server/')) return true;\n if (normalised.endsWith('Adapter.ts') || normalised.endsWith('Adapter.tsx')) return true;\n if (normalised.includes('/packages/')) return true;\n //? Project-root config files (the LuckyStack `config.ts` convention) and\n //? any `*.config.ts` are framework boundaries — Prisma types there are\n //? expected and not a \"leaking into component code\" concern.\n if (normalised.endsWith('/config.ts') || normalised.endsWith('.config.ts')) return true;\n if (normalised.includes('/prisma/')) return true;\n return false;\n};\n\nconst rule: EslintRule = {\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Re-export Prisma model types through `src/_types/<Model>.ts` rather than importing `@prisma/client` directly in components.',\n },\n messages: {\n reExportThroughTypes:\n 'Do not import from `@prisma/client` here. Re-export the type through `src/_types/<ModelName>.ts` and import that instead — keeps Prisma details out of component code.',\n },\n schema: [],\n },\n create(context) {\n if (isAllowedPath(context.filename)) return {};\n return {\n ImportDeclaration(node) {\n if (node.source.value === '@prisma/client') {\n context.report({ node, messageId: 'reExportThroughTypes' });\n }\n },\n };\n },\n};\n\nexport default rule;\n","//? Rule: forbid direct `fetch(...)` calls to framework `/api/*` or\r\n//? `/sync/*` routes. The framework provides typed transport helpers\r\n//? `apiRequest` (for `_api/` routes) and `syncRequest` (for `_sync/`\r\n//? routes) which preserve route/version generics + auth/CSRF/validation.\r\n//?\r\n//? The rule is deliberately narrow:\r\n//? - Fires when the URL is a literal / template containing `/api/` or\r\n//? `/sync/` (framework route patterns).\r\n//? - Skips URLs whose PATH STARTS with `/auth/` — the framework's auth\r\n//? endpoints (`/auth/api/credentials`, OAuth callbacks) are HTTP-only\r\n//? and intentionally use raw fetch (cookies, headers, redirects). The\r\n//? start-of-path check (not `.includes`) means a consumer's typed\r\n//? route under an `auth/` page folder (URL `/api/auth/...`) still\r\n//? fires correctly.\r\n//? - Skips external URLs (starts with `http://`, `https://`, `//`) —\r\n//? consumers fetching third-party APIs are fine.\r\n//? - Skips dynamic URLs (variable, function call, etc.) — be permissive\r\n//? rather than flag-by-default; consumers can opt in via comments.\r\n//?\r\n//? Gated by hasPackage('@luckystack/api') OR hasPackage('@luckystack/core')\r\n//? at the config-composition layer.\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\ninterface AstNodeShape {\r\n type?: string;\r\n value?: unknown;\r\n quasis?: { value?: { raw?: string; cooked?: string } }[];\r\n}\r\n\r\nconst extractStaticUrlText = (urlNode: unknown): string | null => {\r\n if (!urlNode || typeof urlNode !== 'object') return null;\r\n const n = urlNode as AstNodeShape;\r\n if (n.type === 'Literal' && typeof n.value === 'string') return n.value;\r\n if (n.type === 'TemplateLiteral' && Array.isArray(n.quasis)) {\r\n return n.quasis.map((q) => q.value?.cooked ?? q.value?.raw ?? '').join('|');\r\n }\r\n return null;\r\n};\r\n\r\nconst targetsFrameworkRoute = (urlNode: unknown): boolean => {\r\n const text = extractStaticUrlText(urlNode);\r\n if (text === null) return false;\r\n if (/^(https?:)?\\/\\//.test(text)) return false;\r\n //? Skip only when the path STARTS with `/auth/` (framework's special\r\n //? endpoints). The leading `|` accounts for `extractStaticUrlText`'s\r\n //? template-literal join when the first quasi is empty, e.g.\r\n //? `${backendUrl}/auth/api/credentials` joins to `|/auth/api/credentials`.\r\n if (/^(?:\\|)?\\/auth\\//.test(text)) return false;\r\n return /(?:^|[^A-Za-z])\\/(?:api|sync)\\//.test(text);\r\n};\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'problem',\r\n docs: {\r\n description: 'Disallow raw `fetch(...)` to framework `/api/*` and `/sync/*` routes. Use `apiRequest` / `syncRequest` instead.',\r\n },\r\n messages: {\r\n useApiRequest:\r\n 'Do not call `fetch` directly for framework `/api/*` routes. Use `apiRequest({ name, version, data })` for typed inference, or `httpFetch(...)` from `@luckystack/core` if you need a raw same-origin request.',\r\n useSyncRequest:\r\n 'Do not call `fetch` directly for framework `/sync/*` routes. Use `syncRequest({ name, version, data, receiver })` instead.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n return {\r\n CallExpression(node) {\r\n const callee = node.callee;\r\n const isFetchCall =\r\n (callee.type === 'Identifier' && callee.name === 'fetch') ||\r\n (callee.type === 'MemberExpression' &&\r\n callee.object.type === 'Identifier' &&\r\n callee.object.name === 'window' &&\r\n callee.property.type === 'Identifier' &&\r\n callee.property.name === 'fetch');\r\n if (!isFetchCall) return;\r\n const url = node.arguments[0];\r\n if (!targetsFrameworkRoute(url)) return;\r\n const text = extractStaticUrlText(url) ?? '';\r\n const messageId = text.includes('/sync/') ? 'useSyncRequest' : 'useApiRequest';\r\n context.report({ node, messageId });\r\n },\r\n };\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: forbid raw `try { … } catch` inside src/server/shared code.\n//? The framework provides `tryCatch` from @luckystack/core (and the API/sync\n//? handler `functions.tryCatch` injection) that handles Sentry capture +\n//? normalised tuple returns. Raw try/catch bypasses that.\n\nimport type { EslintRule } from '../internal/ruleTypes.js';\n\nconst rule: EslintRule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Disallow raw `try { … } catch` blocks — use the framework `tryCatch` helper instead.',\n },\n messages: {\n useTryCatch:\n 'Do not use raw try/catch. Import `tryCatch` from `@luckystack/core` (client) or `server/functions/tryCatch` (server), or use the injected `functions.tryCatch` in API / sync handlers.',\n },\n schema: [],\n },\n create(context) {\n return {\n TryStatement(node) {\n //? Only fire when an actual catch clause is present. `try { } finally { }`\n //? is a different construct (cleanup, not error handling) and the\n //? `tryCatch` helper is not a substitute.\n if (node.handler) {\n context.report({ node, messageId: 'useTryCatch' });\n }\n },\n };\n },\n};\n\nexport default rule;\n","//? Rule: forbid local wrappers around `apiRequest` whose parameter types\r\n//? erase the route/version generics. The framework's type system relies on\r\n//? literal `name`/`version` strings to infer `serverOutput` / `clientOutput`.\r\n//? A wrapper like:\r\n//?\r\n//? const unsafeApi = (name: string, version: string, data: unknown) =>\r\n//? apiRequest({ name: name as any, ... });\r\n//?\r\n//? destroys that inference. Always call `apiRequest` directly with route\r\n//? literals, or write a wrapper that preserves the generics.\r\n//?\r\n//? Gated by hasPackage('@luckystack/api') at the config-composition layer.\r\n\r\n//? Double-cast + any-spread disabled file-wide: bridges `Rule.Node` to specific\r\n//? AST shapes; the spread iterates over `Object.entries(node)` whose values are\r\n//? typed as `any` because eslint's AST shape varies by node kind.\r\n/* eslint-disable no-restricted-syntax, @typescript-eslint/no-unsafe-argument */\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\nconst SUSPECT_PARAM_NAMES = new Set(['name', 'version', 'route', 'apiName']);\r\n\r\n//? AST keys that point to parents or non-AST metadata. Including them in\r\n//? a recursive descent causes infinite loops because eslint adds `parent`\r\n//? pointers during traversal.\r\nconst SKIP_KEYS = new Set(['parent', 'loc', 'range', 'tokens', 'comments']);\r\n\r\nconst containsApiRequestCall = (body: unknown): boolean => {\r\n if (!body || typeof body !== 'object') return false;\r\n const visited = new WeakSet<object>();\r\n const stack: unknown[] = [body];\r\n while (stack.length > 0) {\r\n const node = stack.pop() as Record<string, unknown> | null;\r\n if (!node || typeof node !== 'object') continue;\r\n if (visited.has(node)) continue;\r\n visited.add(node);\r\n const callee = (node as { type?: string; callee?: { type?: string; name?: string } }).callee;\r\n if (\r\n (node as { type?: string }).type === 'CallExpression' &&\r\n callee?.type === 'Identifier' &&\r\n (callee.name === 'apiRequest' || callee.name === 'syncRequest')\r\n ) {\r\n return true;\r\n }\r\n for (const [key, value] of Object.entries(node)) {\r\n if (SKIP_KEYS.has(key)) continue;\r\n if (Array.isArray(value)) stack.push(...value);\r\n else if (value && typeof value === 'object') stack.push(value);\r\n }\r\n }\r\n return false;\r\n};\r\n\r\nconst isSuspectFunction = (node: {\r\n params?: { type?: string; name?: string; typeAnnotation?: { typeAnnotation?: { type?: string } } }[];\r\n body?: unknown;\r\n}): boolean => {\r\n if (!node.params || node.params.length === 0) return false;\r\n const hasSuspectStringParam = node.params.some((p) => {\r\n if (p.type !== 'Identifier' || !p.name) return false;\r\n if (!SUSPECT_PARAM_NAMES.has(p.name)) return false;\r\n const annotation = p.typeAnnotation?.typeAnnotation?.type;\r\n return annotation === 'TSStringKeyword';\r\n });\r\n if (!hasSuspectStringParam) return false;\r\n return containsApiRequestCall(node.body);\r\n};\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'problem',\r\n docs: {\r\n description: 'Disallow local wrappers around `apiRequest` / `syncRequest` whose `name`/`version` params are typed as plain `string` — this erases the generic route/version inference.',\r\n },\r\n messages: {\r\n unsafeWrapper:\r\n 'This wrapper around `apiRequest` / `syncRequest` accepts `{{paramName}}: string` and erases the route/version generic inference. Call the framework helper directly with literal route names, or type the parameter as a literal union (e.g. `name: \\'examples/getUserData\\'`).',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n return {\r\n FunctionDeclaration(node) {\r\n if (isSuspectFunction(node)) {\r\n const suspect = (node.params as { name?: string }[]).find((p) => p.name && SUSPECT_PARAM_NAMES.has(p.name));\r\n context.report({ node, messageId: 'unsafeWrapper', data: { paramName: suspect?.name ?? 'name' } });\r\n }\r\n },\r\n ArrowFunctionExpression(node) {\r\n if (isSuspectFunction(node)) {\r\n const suspect = (node.params as { name?: string }[]).find((p) => p.name && SUSPECT_PARAM_NAMES.has(p.name));\r\n context.report({ node, messageId: 'unsafeWrapper', data: { paramName: suspect?.name ?? 'name' } });\r\n }\r\n },\r\n };\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: same shape as no-unsafe-api-wrappers, but targeting wrappers\r\n//? around `syncRequest` and `upsertSyncEventCallback`. Gated by\r\n//? hasPackage('@luckystack/sync') at the config-composition layer.\r\n//?\r\n//? Note: the api-wrappers rule already covers the `syncRequest` call site;\r\n//? this rule additionally catches `upsertSyncEventCallback` wrappers and\r\n//? exists as a distinct identity so the sync-only rule can be disabled\r\n//? independently when a consumer uses api but not sync.\r\n\r\n//? Double-cast + any-spread disabled file-wide: bridges `Rule.Node` to specific\r\n//? AST shapes; the spread iterates over `Object.entries(node)` whose values are\r\n//? typed as `any` because eslint's AST shape varies by node kind.\r\n/* eslint-disable no-restricted-syntax, @typescript-eslint/no-unsafe-argument */\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\nconst SUSPECT_PARAM_NAMES = new Set(['name', 'version', 'route', 'syncName']);\r\nconst SUSPECT_CALLEES = new Set(['syncRequest', 'upsertSyncEventCallback']);\r\n\r\n//? AST keys that point to parents or non-AST metadata. Skipped to avoid\r\n//? infinite loops when eslint adds `parent` pointers during traversal.\r\nconst SKIP_KEYS = new Set(['parent', 'loc', 'range', 'tokens', 'comments']);\r\n\r\nconst containsSuspectCall = (body: unknown): boolean => {\r\n if (!body || typeof body !== 'object') return false;\r\n const visited = new WeakSet<object>();\r\n const stack: unknown[] = [body];\r\n while (stack.length > 0) {\r\n const node = stack.pop() as Record<string, unknown> | null;\r\n if (!node || typeof node !== 'object') continue;\r\n if (visited.has(node)) continue;\r\n visited.add(node);\r\n const callee = (node as { type?: string; callee?: { type?: string; name?: string } }).callee;\r\n if (\r\n (node as { type?: string }).type === 'CallExpression' &&\r\n callee?.type === 'Identifier' &&\r\n SUSPECT_CALLEES.has(callee.name ?? '')\r\n ) {\r\n return true;\r\n }\r\n for (const [key, value] of Object.entries(node)) {\r\n if (SKIP_KEYS.has(key)) continue;\r\n if (Array.isArray(value)) stack.push(...value);\r\n else if (value && typeof value === 'object') stack.push(value);\r\n }\r\n }\r\n return false;\r\n};\r\n\r\nconst isSuspect = (node: {\r\n params?: { type?: string; name?: string; typeAnnotation?: { typeAnnotation?: { type?: string } } }[];\r\n body?: unknown;\r\n}): boolean => {\r\n if (!node.params || node.params.length === 0) return false;\r\n const hasSuspectStringParam = node.params.some((p) => {\r\n if (p.type !== 'Identifier' || !p.name) return false;\r\n if (!SUSPECT_PARAM_NAMES.has(p.name)) return false;\r\n return p.typeAnnotation?.typeAnnotation?.type === 'TSStringKeyword';\r\n });\r\n if (!hasSuspectStringParam) return false;\r\n return containsSuspectCall(node.body);\r\n};\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'problem',\r\n docs: {\r\n description: 'Disallow local wrappers around `syncRequest` / `upsertSyncEventCallback` whose `name`/`version` params are typed as plain `string`.',\r\n },\r\n messages: {\r\n unsafeSyncWrapper:\r\n 'This wrapper around `syncRequest` / `upsertSyncEventCallback` accepts a `string` route param and erases the generic event-payload inference. Call the framework helper directly with literal route names.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n return {\r\n FunctionDeclaration(node) {\r\n if (isSuspect(node)) {\r\n context.report({ node, messageId: 'unsafeSyncWrapper' });\r\n }\r\n },\r\n ArrowFunctionExpression(node) {\r\n if (isSuspect(node)) {\r\n context.report({ node, messageId: 'unsafeSyncWrapper' });\r\n }\r\n },\r\n };\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: warn on `confirm(...)` / `window.confirm(...)` calls. The framework\n//? provides `menuHandler.confirm({ title, content, input? })` from\n//? `src/_functions/menuHandler.ts` which renders a styled, theme-aware,\n//? Promise-returning confirm dialog and respects keyboard / accessibility.\n\nimport type { EslintRule } from '../internal/ruleTypes.js';\n\nconst rule: EslintRule = {\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Prefer `menuHandler.confirm({ title, content })` over the native `confirm()` dialog.',\n },\n messages: {\n useMenuHandlerConfirm:\n 'Use `menuHandler.confirm({ title, content })` from `src/_functions/menuHandler.ts` instead of native `confirm()`. Returns a `Promise<boolean>` with proper theming.',\n },\n schema: [],\n },\n create(context) {\n return {\n CallExpression(node) {\n const callee = node.callee;\n if (callee.type === 'Identifier' && callee.name === 'confirm') {\n context.report({ node, messageId: 'useMenuHandlerConfirm' });\n return;\n }\n if (\n callee.type === 'MemberExpression' &&\n callee.object.type === 'Identifier' &&\n callee.object.name === 'window' &&\n callee.property.type === 'Identifier' &&\n callee.property.name === 'confirm'\n ) {\n context.report({ node, messageId: 'useMenuHandlerConfirm' });\n }\n },\n };\n },\n};\n\nexport default rule;\n","//? Rule: warn when a JSX `<select>` element is used. The framework ships\r\n//? `Dropdown` (src/_components/Dropdown.tsx) with search, keyboard nav,\r\n//? sizing variants, and consistent dark/light styling. Native `<select>`\r\n//? skips all of that.\r\n\r\nimport type { Rule } from 'eslint';\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\n//? JSX AST nodes are extended at runtime by eslint-plugin-react, but\r\n//? eslint's stock `Rule.RuleListener` type does not know about them. We\r\n//? describe the shapes we read inline.\r\ninterface JsxOpeningElementShape {\r\n name: { type: string; name?: string };\r\n}\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'suggestion',\r\n docs: {\r\n description: 'Prefer the framework `Dropdown` component over native `<select>` elements.',\r\n },\r\n messages: {\r\n useDropdown:\r\n 'Use `Dropdown` from `src/_components/Dropdown.tsx` (or `MultiSelectDropdown` for multi-select) instead of native `<select>`. The framework component handles keyboard nav, search, sizing, and dark/light theme.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n const listener: Rule.RuleListener = {\r\n JSXOpeningElement(rawNode: unknown): void {\r\n const node = rawNode as JsxOpeningElementShape & Rule.Node;\r\n if (node.name.type === 'JSXIdentifier' && node.name.name === 'select') {\r\n context.report({ node, messageId: 'useDropdown' });\r\n }\r\n },\r\n };\r\n return listener;\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: warn on `alert(...)` / `window.alert(...)`. The framework's\n//? `notify` helper (from @luckystack/core) renders themed toast\n//? notifications via the registered notifier (default sonner).\n\nimport type { EslintRule } from '../internal/ruleTypes.js';\n\nconst rule: EslintRule = {\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Prefer `notify()` over the native `alert()` dialog.',\n },\n messages: {\n useNotify:\n 'Use `notify({ type, message })` from `@luckystack/core` instead of native `alert()`. Renders a themed toast via the registered notifier.',\n },\n schema: [],\n },\n create(context) {\n return {\n CallExpression(node) {\n const callee = node.callee;\n if (callee.type === 'Identifier' && callee.name === 'alert') {\n context.report({ node, messageId: 'useNotify' });\n return;\n }\n if (\n callee.type === 'MemberExpression' &&\n callee.object.type === 'Identifier' &&\n callee.object.name === 'window' &&\n callee.property.type === 'Identifier' &&\n callee.property.name === 'alert'\n ) {\n context.report({ node, messageId: 'useNotify' });\n }\n },\n };\n },\n};\n\nexport default rule;\n","//? Public entry for `@luckystack/core/eslint`. Composes the LuckyStack\r\n//? flat-config tier that the scaffolded `eslint.luckystack.config.js`\r\n//? consumes. Rules that target an optional `@luckystack/*` peer package\r\n//? are gated via `hasPackage(...)` so absent peers cause silent rule\r\n//? skips (NOT noisy \"rule not found\" errors).\r\n//?\r\n//? Override surface: consumers can spread this default export and append\r\n//? their own config blocks, or replace individual rule severities by\r\n//? re-stating them with `'off' | 'warn' | 'error'`.\r\n\r\nimport type { Linter } from 'eslint';\r\n\r\nimport { hasPackage } from './internal/hasPackage.js';\r\nimport type { EslintRule } from './internal/ruleTypes.js';\r\n\r\nimport noArbitraryTailwindColor from './rules/no-arbitrary-tailwind-color.js';\r\nimport noDirectPrismaImportInComponents from './rules/no-direct-prisma-import-in-components.js';\r\nimport noRawFetchInSrc from './rules/no-raw-fetch-in-src.js';\r\nimport noRawTryCatch from './rules/no-raw-try-catch.js';\r\nimport noUnsafeApiWrappers from './rules/no-unsafe-api-wrappers.js';\r\nimport noUnsafeSyncWrappers from './rules/no-unsafe-sync-wrappers.js';\r\nimport preferLuckystackConfirm from './rules/prefer-luckystack-confirm.js';\r\nimport preferLuckystackDropdown from './rules/prefer-luckystack-dropdown.js';\r\nimport preferLuckystackNotify from './rules/prefer-luckystack-notify.js';\r\n\r\nconst allRules: Record<string, EslintRule> = {\r\n 'no-raw-try-catch': noRawTryCatch,\r\n 'no-raw-fetch-in-src': noRawFetchInSrc,\r\n 'no-unsafe-api-wrappers': noUnsafeApiWrappers,\r\n 'no-unsafe-sync-wrappers': noUnsafeSyncWrappers,\r\n 'prefer-luckystack-dropdown': preferLuckystackDropdown,\r\n 'prefer-luckystack-confirm': preferLuckystackConfirm,\r\n 'prefer-luckystack-notify': preferLuckystackNotify,\r\n 'no-direct-prisma-import-in-components': noDirectPrismaImportInComponents,\r\n 'no-arbitrary-tailwind-color': noArbitraryTailwindColor,\r\n};\r\n\r\nconst hasApi = hasPackage('@luckystack/api');\r\nconst hasCore = hasPackage('@luckystack/core');\r\nconst hasSync = hasPackage('@luckystack/sync');\r\n\r\nconst ruleSeverities: Record<string, Linter.RuleSeverity> = {\r\n // Always-on errors.\r\n 'luckystack/no-raw-try-catch': 'error',\r\n\r\n // Package-gated errors. Disabled when the relevant peer is absent so\r\n // a consumer using only @luckystack/core sees no \"use apiRequest\" noise.\r\n 'luckystack/no-raw-fetch-in-src': hasApi || hasCore ? 'error' : 'off',\r\n 'luckystack/no-unsafe-api-wrappers': hasApi ? 'error' : 'off',\r\n 'luckystack/no-unsafe-sync-wrappers': hasSync ? 'error' : 'off',\r\n\r\n // Warnings — enabled by default per framework owner's preference.\r\n 'luckystack/prefer-luckystack-dropdown': 'warn',\r\n 'luckystack/prefer-luckystack-confirm': 'warn',\r\n 'luckystack/prefer-luckystack-notify': 'warn',\r\n 'luckystack/no-direct-prisma-import-in-components': 'warn',\r\n 'luckystack/no-arbitrary-tailwind-color': 'warn',\r\n};\r\n\r\nconst luckystackConfig: Linter.Config[] = [\r\n {\r\n files: ['**/*.{ts,tsx,js,jsx,mjs,cjs}'],\r\n plugins: {\r\n luckystack: { rules: allRules },\r\n },\r\n rules: ruleSeverities,\r\n },\r\n];\r\n\r\nexport default luckystackConfig;\r\n\r\n//? Named exports for advanced consumers who want to assemble their own\r\n//? config or selectively re-enable individual rules.\r\nexport { allRules as rules };\r\n\r\n\r\nexport {hasPackage} from './internal/hasPackage.js';"],"mappings":"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","names":["rule","rule","rule","rule","SUSPECT_PARAM_NAMES","SKIP_KEYS","rule","rule","rule","rule"]}
1
+ {"version":3,"sources":["../../src/eslint/internal/hasPackage.ts","../../src/eslint/rules/no-arbitrary-tailwind-color.ts","../../src/eslint/rules/no-direct-prisma-import-in-components.ts","../../src/eslint/rules/no-raw-fetch-in-src.ts","../../src/eslint/rules/no-raw-try-catch.ts","../../src/eslint/rules/no-unsafe-api-wrappers.ts","../../src/eslint/rules/no-unsafe-sync-wrappers.ts","../../src/eslint/rules/prefer-luckystack-confirm.ts","../../src/eslint/rules/prefer-luckystack-dropdown.ts","../../src/eslint/rules/prefer-luckystack-notify.ts","../../src/eslint/index.ts"],"sourcesContent":["//? Peer-dep presence probe used to gate package-dependent eslint rules.\r\n//? Resolves against `process.cwd()` so the CONSUMER's node_modules drives\r\n//? activation, not this package's own resolution graph.\r\n//?\r\n//? Implementation: tries `require.resolve` first (works for CJS-compatible\r\n//? packages), falls back to an fs-based `node_modules/<name>/package.json`\r\n//? check for pure-ESM packages whose `exports` map omits the `require`\r\n//? condition (which is the case for the @luckystack/* packages themselves).\r\n\r\nimport { existsSync } from 'node:fs';\r\nimport { createRequire } from 'node:module';\r\nimport path from 'node:path';\r\n\r\nconst localRequire = createRequire(import.meta.url);\r\n\r\nconst checkOnDisk = (name: string): boolean => {\r\n const segments = name.startsWith('@')\r\n ? name.split('/').slice(0, 2)\r\n : [name.split('/')[0] ?? name];\r\n return existsSync(path.join(process.cwd(), 'node_modules', ...segments, 'package.json'));\r\n};\r\n\r\nexport const hasPackage = (name: string): boolean => {\r\n try {\r\n localRequire.resolve(name, { paths: [process.cwd()] });\r\n return true;\r\n } catch {\r\n return checkOnDisk(name);\r\n }\r\n};\r\n","//? Rule: warn on arbitrary Tailwind color values (`text-[#fff]`,\r\n//? `bg-[#abc123]`, `border-[#000]`) inside className strings. The framework\r\n//? mandates colors from `src/index.css` `@theme` block (rule 14). Arbitrary\r\n//? colors break dark-mode auto-switching.\r\n\r\n//? Double-cast disabled file-wide: this rule operates on AST nodes that span\r\n//? two type universes (eslint's `Rule.Node` vs the JSX-extended shape from\r\n//? eslint-plugin-react). Bridging them needs `as unknown as`; runtime\r\n//? guards happen via explicit `.type === 'JSXIdentifier'` checks above each\r\n//? cast.\r\n/* eslint-disable no-restricted-syntax */\r\n\r\nimport type { Rule } from 'eslint';\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\nconst ARBITRARY_COLOR_PATTERN = /\\b(?:text|bg|border|ring|fill|stroke|from|to|via|outline|decoration|accent|caret|placeholder|divide)-\\[#[0-9a-fA-F]{3,8}\\]/;\r\n\r\n//? JSX AST nodes (JSXAttribute, JSXExpressionContainer, …) are not part of\r\n//? eslint's stock estree AST. eslint-plugin-react extends the visitor map at\r\n//? runtime, but the stock `Rule.RuleListener` type does not know about them,\r\n//? so we describe the shapes we read inline. The actual eslint runtime gives\r\n//? us the right object; this is purely a TS-side annotation.\r\ntype ClassNameValueShape =\r\n | { type: 'Literal'; value: unknown }\r\n | { type: 'JSXExpressionContainer'; expression: ExpressionShape }\r\n | { type: string };\r\n\r\ntype ExpressionShape =\r\n | { type: 'Literal'; value: unknown }\r\n | { type: 'TemplateLiteral'; quasis: readonly { value: { cooked?: string; raw: string } }[] }\r\n | { type: string };\r\n\r\ninterface JsxAttributeShape {\r\n name: { type: string; name?: string };\r\n value?: ClassNameValueShape | null;\r\n}\r\n\r\nconst reportIfArbitrary = (\r\n context: Rule.RuleContext,\r\n node: Rule.Node,\r\n value: string,\r\n): void => {\r\n if (ARBITRARY_COLOR_PATTERN.test(value)) {\r\n context.report({ node, messageId: 'useThemeToken' });\r\n }\r\n};\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'suggestion',\r\n docs: {\r\n description: 'Disallow arbitrary Tailwind color values (`text-[#…]`, `bg-[#…]`, …). Use tokens from `src/index.css` `@theme` block.',\r\n },\r\n messages: {\r\n useThemeToken:\r\n 'Do not use arbitrary Tailwind color values like `text-[#…]`. Use a token from `src/index.css` `@theme` block (e.g. `bg-primary`, `text-title`, `border-divider`). Arbitrary colors break dark-mode auto-switching.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n const listener: Rule.RuleListener = {\r\n JSXAttribute(rawNode: unknown): void {\r\n const node = rawNode as JsxAttributeShape & Rule.Node;\r\n if (node.name.type !== 'JSXIdentifier' || node.name.name !== 'className') return;\r\n const value = node.value;\r\n if (!value) return;\r\n if (value.type === 'Literal' && typeof (value as { value?: unknown }).value === 'string') {\r\n reportIfArbitrary(context, value as unknown as Rule.Node, (value as { value: string }).value);\r\n return;\r\n }\r\n if (value.type === 'JSXExpressionContainer') {\r\n const expression = (value as { expression: ExpressionShape }).expression;\r\n if (expression.type === 'TemplateLiteral') {\r\n const quasis = (expression as { quasis: readonly { value: { cooked?: string; raw: string } }[] }).quasis;\r\n for (const quasi of quasis) {\r\n reportIfArbitrary(\r\n context,\r\n quasi as unknown as Rule.Node,\r\n quasi.value.cooked ?? quasi.value.raw,\r\n );\r\n }\r\n } else if (expression.type === 'Literal' && typeof (expression as { value?: unknown }).value === 'string') {\r\n reportIfArbitrary(\r\n context,\r\n expression as unknown as Rule.Node,\r\n (expression as { value: string }).value,\r\n );\r\n }\r\n }\r\n },\r\n };\r\n return listener;\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: warn on `import … from '@prisma/client'` outside of allowed\r\n//? boundaries. Convention: app code re-exports Prisma model types through\r\n//? `src/_types/<ModelName>.ts` so swapping providers / extending types\r\n//? stays centralised. Direct imports leak Prisma details into UI code.\r\n//?\r\n//? Allowed paths: `src/_types/**`, `server/**`, and any file ending in\r\n//? `Adapter.ts` (legitimate adapter implementations).\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\nconst isAllowedPath = (filename: string): boolean => {\r\n const normalised = filename.replaceAll('\\\\', '/');\r\n if (normalised.includes('/src/_types/')) return true;\r\n if (normalised.includes('/server/')) return true;\r\n if (normalised.endsWith('Adapter.ts') || normalised.endsWith('Adapter.tsx')) return true;\r\n if (normalised.includes('/packages/')) return true;\r\n //? Project-root config files (the LuckyStack `config.ts` convention) and\r\n //? any `*.config.ts` are framework boundaries — Prisma types there are\r\n //? expected and not a \"leaking into component code\" concern.\r\n if (normalised.endsWith('/config.ts') || normalised.endsWith('.config.ts')) return true;\r\n if (normalised.includes('/prisma/')) return true;\r\n return false;\r\n};\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'suggestion',\r\n docs: {\r\n description: 'Re-export Prisma model types through `src/_types/<Model>.ts` rather than importing `@prisma/client` directly in components.',\r\n },\r\n messages: {\r\n reExportThroughTypes:\r\n 'Do not import from `@prisma/client` here. Re-export the type through `src/_types/<ModelName>.ts` and import that instead — keeps Prisma details out of component code.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n if (isAllowedPath(context.filename)) return {};\r\n return {\r\n ImportDeclaration(node) {\r\n if (node.source.value === '@prisma/client') {\r\n context.report({ node, messageId: 'reExportThroughTypes' });\r\n }\r\n },\r\n };\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: forbid direct `fetch(...)` calls to framework `/api/*` or\r\n//? `/sync/*` routes. The framework provides typed transport helpers\r\n//? `apiRequest` (for `_api/` routes) and `syncRequest` (for `_sync/`\r\n//? routes) which preserve route/version generics + auth/CSRF/validation.\r\n//?\r\n//? The rule is deliberately narrow:\r\n//? - Fires when the URL is a literal / template containing `/api/` or\r\n//? `/sync/` (framework route patterns).\r\n//? - Skips URLs whose PATH STARTS with `/auth/` — the framework's auth\r\n//? endpoints (`/auth/api/credentials`, OAuth callbacks) are HTTP-only\r\n//? and intentionally use raw fetch (cookies, headers, redirects). The\r\n//? start-of-path check (not `.includes`) means a consumer's typed\r\n//? route under an `auth/` page folder (URL `/api/auth/...`) still\r\n//? fires correctly.\r\n//? - Skips external URLs (starts with `http://`, `https://`, `//`) —\r\n//? consumers fetching third-party APIs are fine.\r\n//? - Skips dynamic URLs (variable, function call, etc.) — be permissive\r\n//? rather than flag-by-default; consumers can opt in via comments.\r\n//?\r\n//? Gated by hasPackage('@luckystack/api') OR hasPackage('@luckystack/core')\r\n//? at the config-composition layer.\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\ninterface AstNodeShape {\r\n type?: string;\r\n value?: unknown;\r\n quasis?: { value?: { raw?: string; cooked?: string } }[];\r\n}\r\n\r\nconst extractStaticUrlText = (urlNode: unknown): string | null => {\r\n if (!urlNode || typeof urlNode !== 'object') return null;\r\n const n = urlNode as AstNodeShape;\r\n if (n.type === 'Literal' && typeof n.value === 'string') return n.value;\r\n if (n.type === 'TemplateLiteral' && Array.isArray(n.quasis)) {\r\n return n.quasis.map((q) => q.value?.cooked ?? q.value?.raw ?? '').join('|');\r\n }\r\n return null;\r\n};\r\n\r\nconst targetsFrameworkRoute = (urlNode: unknown): boolean => {\r\n const text = extractStaticUrlText(urlNode);\r\n if (text === null) return false;\r\n if (/^(https?:)?\\/\\//.test(text)) return false;\r\n //? Skip only when the path STARTS with `/auth/` (framework's special\r\n //? endpoints). The leading `|` accounts for `extractStaticUrlText`'s\r\n //? template-literal join when the first quasi is empty, e.g.\r\n //? `${backendUrl}/auth/api/credentials` joins to `|/auth/api/credentials`.\r\n if (/^(?:\\|)?\\/auth\\//.test(text)) return false;\r\n return /(?:^|[^A-Za-z])\\/(?:api|sync)\\//.test(text);\r\n};\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'problem',\r\n docs: {\r\n description: 'Disallow raw `fetch(...)` to framework `/api/*` and `/sync/*` routes. Use `apiRequest` / `syncRequest` instead.',\r\n },\r\n messages: {\r\n useApiRequest:\r\n 'Do not call `fetch` directly for framework `/api/*` routes. Use `apiRequest({ name, version, data })` for typed inference, or `httpFetch(...)` from `@luckystack/core` if you need a raw same-origin request.',\r\n useSyncRequest:\r\n 'Do not call `fetch` directly for framework `/sync/*` routes. Use `syncRequest({ name, version, data, receiver })` instead.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n return {\r\n CallExpression(node) {\r\n const callee = node.callee;\r\n const isFetchCall =\r\n (callee.type === 'Identifier' && callee.name === 'fetch') ||\r\n (callee.type === 'MemberExpression' &&\r\n callee.object.type === 'Identifier' &&\r\n callee.object.name === 'window' &&\r\n callee.property.type === 'Identifier' &&\r\n callee.property.name === 'fetch');\r\n if (!isFetchCall) return;\r\n const url = node.arguments[0];\r\n if (!targetsFrameworkRoute(url)) return;\r\n const text = extractStaticUrlText(url) ?? '';\r\n const messageId = text.includes('/sync/') ? 'useSyncRequest' : 'useApiRequest';\r\n context.report({ node, messageId });\r\n },\r\n };\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: forbid raw `try { … } catch` inside src/server/shared code.\r\n//? The framework provides `tryCatch` from @luckystack/core (and the API/sync\r\n//? handler `functions.tryCatch` injection) that handles Sentry capture +\r\n//? normalised tuple returns. Raw try/catch bypasses that.\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'problem',\r\n docs: {\r\n description: 'Disallow raw `try { … } catch` blocks — use the framework `tryCatch` helper instead.',\r\n },\r\n messages: {\r\n useTryCatch:\r\n 'Do not use raw try/catch. Import `tryCatch` from `@luckystack/core` (client) or `server/functions/tryCatch` (server), or use the injected `functions.tryCatch` in API / sync handlers.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n return {\r\n TryStatement(node) {\r\n //? Only fire when an actual catch clause is present. `try { } finally { }`\r\n //? is a different construct (cleanup, not error handling) and the\r\n //? `tryCatch` helper is not a substitute.\r\n if (node.handler) {\r\n context.report({ node, messageId: 'useTryCatch' });\r\n }\r\n },\r\n };\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: forbid local wrappers around `apiRequest` whose parameter types\r\n//? erase the route/version generics. The framework's type system relies on\r\n//? literal `name`/`version` strings to infer `serverOutput` / `clientOutput`.\r\n//? A wrapper like:\r\n//?\r\n//? const unsafeApi = (name: string, version: string, data: unknown) =>\r\n//? apiRequest({ name: name as any, ... });\r\n//?\r\n//? destroys that inference. Always call `apiRequest` directly with route\r\n//? literals, or write a wrapper that preserves the generics.\r\n//?\r\n//? Gated by hasPackage('@luckystack/api') at the config-composition layer.\r\n\r\n//? Double-cast + any-spread disabled file-wide: bridges `Rule.Node` to specific\r\n//? AST shapes; the spread iterates over `Object.entries(node)` whose values are\r\n//? typed as `any` because eslint's AST shape varies by node kind.\r\n/* eslint-disable no-restricted-syntax, @typescript-eslint/no-unsafe-argument */\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\nconst SUSPECT_PARAM_NAMES = new Set(['name', 'version', 'route', 'apiName']);\r\n\r\n//? AST keys that point to parents or non-AST metadata. Including them in\r\n//? a recursive descent causes infinite loops because eslint adds `parent`\r\n//? pointers during traversal.\r\nconst SKIP_KEYS = new Set(['parent', 'loc', 'range', 'tokens', 'comments']);\r\n\r\nconst containsApiRequestCall = (body: unknown): boolean => {\r\n if (!body || typeof body !== 'object') return false;\r\n const visited = new WeakSet<object>();\r\n const stack: unknown[] = [body];\r\n while (stack.length > 0) {\r\n const node = stack.pop() as Record<string, unknown> | null;\r\n if (!node || typeof node !== 'object') continue;\r\n if (visited.has(node)) continue;\r\n visited.add(node);\r\n const callee = (node as { type?: string; callee?: { type?: string; name?: string } }).callee;\r\n if (\r\n (node as { type?: string }).type === 'CallExpression' &&\r\n callee?.type === 'Identifier' &&\r\n (callee.name === 'apiRequest' || callee.name === 'syncRequest')\r\n ) {\r\n return true;\r\n }\r\n for (const [key, value] of Object.entries(node)) {\r\n if (SKIP_KEYS.has(key)) continue;\r\n if (Array.isArray(value)) stack.push(...value);\r\n else if (value && typeof value === 'object') stack.push(value);\r\n }\r\n }\r\n return false;\r\n};\r\n\r\nconst isSuspectFunction = (node: {\r\n params?: { type?: string; name?: string; typeAnnotation?: { typeAnnotation?: { type?: string } } }[];\r\n body?: unknown;\r\n}): boolean => {\r\n if (!node.params || node.params.length === 0) return false;\r\n const hasSuspectStringParam = node.params.some((p) => {\r\n if (p.type !== 'Identifier' || !p.name) return false;\r\n if (!SUSPECT_PARAM_NAMES.has(p.name)) return false;\r\n const annotation = p.typeAnnotation?.typeAnnotation?.type;\r\n return annotation === 'TSStringKeyword';\r\n });\r\n if (!hasSuspectStringParam) return false;\r\n return containsApiRequestCall(node.body);\r\n};\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'problem',\r\n docs: {\r\n description: 'Disallow local wrappers around `apiRequest` / `syncRequest` whose `name`/`version` params are typed as plain `string` — this erases the generic route/version inference.',\r\n },\r\n messages: {\r\n unsafeWrapper:\r\n 'This wrapper around `apiRequest` / `syncRequest` accepts `{{paramName}}: string` and erases the route/version generic inference. Call the framework helper directly with literal route names, or type the parameter as a literal union (e.g. `name: \\'examples/getUserData\\'`).',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n return {\r\n FunctionDeclaration(node) {\r\n if (isSuspectFunction(node)) {\r\n const suspect = (node.params as { name?: string }[]).find((p) => p.name && SUSPECT_PARAM_NAMES.has(p.name));\r\n context.report({ node, messageId: 'unsafeWrapper', data: { paramName: suspect?.name ?? 'name' } });\r\n }\r\n },\r\n ArrowFunctionExpression(node) {\r\n if (isSuspectFunction(node)) {\r\n const suspect = (node.params as { name?: string }[]).find((p) => p.name && SUSPECT_PARAM_NAMES.has(p.name));\r\n context.report({ node, messageId: 'unsafeWrapper', data: { paramName: suspect?.name ?? 'name' } });\r\n }\r\n },\r\n };\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: same shape as no-unsafe-api-wrappers, but targeting wrappers\r\n//? around `syncRequest` and `upsertSyncEventCallback`. Gated by\r\n//? hasPackage('@luckystack/sync') at the config-composition layer.\r\n//?\r\n//? Note: the api-wrappers rule already covers the `syncRequest` call site;\r\n//? this rule additionally catches `upsertSyncEventCallback` wrappers and\r\n//? exists as a distinct identity so the sync-only rule can be disabled\r\n//? independently when a consumer uses api but not sync.\r\n\r\n//? Double-cast + any-spread disabled file-wide: bridges `Rule.Node` to specific\r\n//? AST shapes; the spread iterates over `Object.entries(node)` whose values are\r\n//? typed as `any` because eslint's AST shape varies by node kind.\r\n/* eslint-disable no-restricted-syntax, @typescript-eslint/no-unsafe-argument */\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\nconst SUSPECT_PARAM_NAMES = new Set(['name', 'version', 'route', 'syncName']);\r\nconst SUSPECT_CALLEES = new Set(['syncRequest', 'upsertSyncEventCallback']);\r\n\r\n//? AST keys that point to parents or non-AST metadata. Skipped to avoid\r\n//? infinite loops when eslint adds `parent` pointers during traversal.\r\nconst SKIP_KEYS = new Set(['parent', 'loc', 'range', 'tokens', 'comments']);\r\n\r\nconst containsSuspectCall = (body: unknown): boolean => {\r\n if (!body || typeof body !== 'object') return false;\r\n const visited = new WeakSet<object>();\r\n const stack: unknown[] = [body];\r\n while (stack.length > 0) {\r\n const node = stack.pop() as Record<string, unknown> | null;\r\n if (!node || typeof node !== 'object') continue;\r\n if (visited.has(node)) continue;\r\n visited.add(node);\r\n const callee = (node as { type?: string; callee?: { type?: string; name?: string } }).callee;\r\n if (\r\n (node as { type?: string }).type === 'CallExpression' &&\r\n callee?.type === 'Identifier' &&\r\n SUSPECT_CALLEES.has(callee.name ?? '')\r\n ) {\r\n return true;\r\n }\r\n for (const [key, value] of Object.entries(node)) {\r\n if (SKIP_KEYS.has(key)) continue;\r\n if (Array.isArray(value)) stack.push(...value);\r\n else if (value && typeof value === 'object') stack.push(value);\r\n }\r\n }\r\n return false;\r\n};\r\n\r\nconst isSuspect = (node: {\r\n params?: { type?: string; name?: string; typeAnnotation?: { typeAnnotation?: { type?: string } } }[];\r\n body?: unknown;\r\n}): boolean => {\r\n if (!node.params || node.params.length === 0) return false;\r\n const hasSuspectStringParam = node.params.some((p) => {\r\n if (p.type !== 'Identifier' || !p.name) return false;\r\n if (!SUSPECT_PARAM_NAMES.has(p.name)) return false;\r\n return p.typeAnnotation?.typeAnnotation?.type === 'TSStringKeyword';\r\n });\r\n if (!hasSuspectStringParam) return false;\r\n return containsSuspectCall(node.body);\r\n};\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'problem',\r\n docs: {\r\n description: 'Disallow local wrappers around `syncRequest` / `upsertSyncEventCallback` whose `name`/`version` params are typed as plain `string`.',\r\n },\r\n messages: {\r\n unsafeSyncWrapper:\r\n 'This wrapper around `syncRequest` / `upsertSyncEventCallback` accepts a `string` route param and erases the generic event-payload inference. Call the framework helper directly with literal route names.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n return {\r\n FunctionDeclaration(node) {\r\n if (isSuspect(node)) {\r\n context.report({ node, messageId: 'unsafeSyncWrapper' });\r\n }\r\n },\r\n ArrowFunctionExpression(node) {\r\n if (isSuspect(node)) {\r\n context.report({ node, messageId: 'unsafeSyncWrapper' });\r\n }\r\n },\r\n };\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: warn on `confirm(...)` / `window.confirm(...)` calls. The framework\r\n//? provides `menuHandler.confirm({ title, content, input? })` from\r\n//? `src/_functions/menuHandler.ts` which renders a styled, theme-aware,\r\n//? Promise-returning confirm dialog and respects keyboard / accessibility.\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'suggestion',\r\n docs: {\r\n description: 'Prefer `menuHandler.confirm({ title, content })` over the native `confirm()` dialog.',\r\n },\r\n messages: {\r\n useMenuHandlerConfirm:\r\n 'Use `menuHandler.confirm({ title, content })` from `src/_functions/menuHandler.ts` instead of native `confirm()`. Returns a `Promise<boolean>` with proper theming.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n return {\r\n CallExpression(node) {\r\n const callee = node.callee;\r\n if (callee.type === 'Identifier' && callee.name === 'confirm') {\r\n context.report({ node, messageId: 'useMenuHandlerConfirm' });\r\n return;\r\n }\r\n if (\r\n callee.type === 'MemberExpression' &&\r\n callee.object.type === 'Identifier' &&\r\n callee.object.name === 'window' &&\r\n callee.property.type === 'Identifier' &&\r\n callee.property.name === 'confirm'\r\n ) {\r\n context.report({ node, messageId: 'useMenuHandlerConfirm' });\r\n }\r\n },\r\n };\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: warn when a JSX `<select>` element is used. The framework ships\r\n//? `Dropdown` (src/_components/Dropdown.tsx) with search, keyboard nav,\r\n//? sizing variants, and consistent dark/light styling. Native `<select>`\r\n//? skips all of that.\r\n\r\nimport type { Rule } from 'eslint';\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\n//? JSX AST nodes are extended at runtime by eslint-plugin-react, but\r\n//? eslint's stock `Rule.RuleListener` type does not know about them. We\r\n//? describe the shapes we read inline.\r\ninterface JsxOpeningElementShape {\r\n name: { type: string; name?: string };\r\n}\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'suggestion',\r\n docs: {\r\n description: 'Prefer the framework `Dropdown` component over native `<select>` elements.',\r\n },\r\n messages: {\r\n useDropdown:\r\n 'Use `Dropdown` from `src/_components/Dropdown.tsx` (or `MultiSelectDropdown` for multi-select) instead of native `<select>`. The framework component handles keyboard nav, search, sizing, and dark/light theme.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n const listener: Rule.RuleListener = {\r\n JSXOpeningElement(rawNode: unknown): void {\r\n const node = rawNode as JsxOpeningElementShape & Rule.Node;\r\n if (node.name.type === 'JSXIdentifier' && node.name.name === 'select') {\r\n context.report({ node, messageId: 'useDropdown' });\r\n }\r\n },\r\n };\r\n return listener;\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Rule: warn on `alert(...)` / `window.alert(...)`. The framework's\r\n//? `notify` helper (from @luckystack/core) renders themed toast\r\n//? notifications via the registered notifier (default sonner).\r\n\r\nimport type { EslintRule } from '../internal/ruleTypes.js';\r\n\r\nconst rule: EslintRule = {\r\n meta: {\r\n type: 'suggestion',\r\n docs: {\r\n description: 'Prefer `notify()` over the native `alert()` dialog.',\r\n },\r\n messages: {\r\n useNotify:\r\n 'Use `notify({ type, message })` from `@luckystack/core` instead of native `alert()`. Renders a themed toast via the registered notifier.',\r\n },\r\n schema: [],\r\n },\r\n create(context) {\r\n return {\r\n CallExpression(node) {\r\n const callee = node.callee;\r\n if (callee.type === 'Identifier' && callee.name === 'alert') {\r\n context.report({ node, messageId: 'useNotify' });\r\n return;\r\n }\r\n if (\r\n callee.type === 'MemberExpression' &&\r\n callee.object.type === 'Identifier' &&\r\n callee.object.name === 'window' &&\r\n callee.property.type === 'Identifier' &&\r\n callee.property.name === 'alert'\r\n ) {\r\n context.report({ node, messageId: 'useNotify' });\r\n }\r\n },\r\n };\r\n },\r\n};\r\n\r\nexport default rule;\r\n","//? Public entry for `@luckystack/core/eslint`. Composes the LuckyStack\r\n//? flat-config tier that the scaffolded `eslint.luckystack.config.js`\r\n//? consumes. Rules that target an optional `@luckystack/*` peer package\r\n//? are gated via `hasPackage(...)` so absent peers cause silent rule\r\n//? skips (NOT noisy \"rule not found\" errors).\r\n//?\r\n//? Override surface: consumers can spread this default export and append\r\n//? their own config blocks, or replace individual rule severities by\r\n//? re-stating them with `'off' | 'warn' | 'error'`.\r\n\r\nimport type { Linter } from 'eslint';\r\n\r\nimport { hasPackage } from './internal/hasPackage.js';\r\nimport type { EslintRule } from './internal/ruleTypes.js';\r\n\r\nimport noArbitraryTailwindColor from './rules/no-arbitrary-tailwind-color.js';\r\nimport noDirectPrismaImportInComponents from './rules/no-direct-prisma-import-in-components.js';\r\nimport noRawFetchInSrc from './rules/no-raw-fetch-in-src.js';\r\nimport noRawTryCatch from './rules/no-raw-try-catch.js';\r\nimport noUnsafeApiWrappers from './rules/no-unsafe-api-wrappers.js';\r\nimport noUnsafeSyncWrappers from './rules/no-unsafe-sync-wrappers.js';\r\nimport preferLuckystackConfirm from './rules/prefer-luckystack-confirm.js';\r\nimport preferLuckystackDropdown from './rules/prefer-luckystack-dropdown.js';\r\nimport preferLuckystackNotify from './rules/prefer-luckystack-notify.js';\r\n\r\nconst allRules: Record<string, EslintRule> = {\r\n 'no-raw-try-catch': noRawTryCatch,\r\n 'no-raw-fetch-in-src': noRawFetchInSrc,\r\n 'no-unsafe-api-wrappers': noUnsafeApiWrappers,\r\n 'no-unsafe-sync-wrappers': noUnsafeSyncWrappers,\r\n 'prefer-luckystack-dropdown': preferLuckystackDropdown,\r\n 'prefer-luckystack-confirm': preferLuckystackConfirm,\r\n 'prefer-luckystack-notify': preferLuckystackNotify,\r\n 'no-direct-prisma-import-in-components': noDirectPrismaImportInComponents,\r\n 'no-arbitrary-tailwind-color': noArbitraryTailwindColor,\r\n};\r\n\r\nconst hasApi = hasPackage('@luckystack/api');\r\nconst hasCore = hasPackage('@luckystack/core');\r\nconst hasSync = hasPackage('@luckystack/sync');\r\n\r\nconst ruleSeverities: Record<string, Linter.RuleSeverity> = {\r\n // Always-on errors.\r\n 'luckystack/no-raw-try-catch': 'error',\r\n\r\n // Package-gated errors. Disabled when the relevant peer is absent so\r\n // a consumer using only @luckystack/core sees no \"use apiRequest\" noise.\r\n 'luckystack/no-raw-fetch-in-src': hasApi || hasCore ? 'error' : 'off',\r\n 'luckystack/no-unsafe-api-wrappers': hasApi ? 'error' : 'off',\r\n 'luckystack/no-unsafe-sync-wrappers': hasSync ? 'error' : 'off',\r\n\r\n // Warnings — enabled by default per framework owner's preference.\r\n 'luckystack/prefer-luckystack-dropdown': 'warn',\r\n 'luckystack/prefer-luckystack-confirm': 'warn',\r\n 'luckystack/prefer-luckystack-notify': 'warn',\r\n 'luckystack/no-direct-prisma-import-in-components': 'warn',\r\n 'luckystack/no-arbitrary-tailwind-color': 'warn',\r\n};\r\n\r\nconst luckystackConfig: Linter.Config[] = [\r\n {\r\n files: ['**/*.{ts,tsx,js,jsx,mjs,cjs}'],\r\n plugins: {\r\n luckystack: { rules: allRules },\r\n },\r\n rules: ruleSeverities,\r\n },\r\n];\r\n\r\nexport default luckystackConfig;\r\n\r\n//? Named exports for advanced consumers who want to assemble their own\r\n//? config or selectively re-enable individual rules.\r\nexport { allRules as rules };\r\n\r\n\r\nexport {hasPackage} from './internal/hasPackage.js';"],"mappings":"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","names":["rule","rule","rule","rule","SUSPECT_PARAM_NAMES","SKIP_KEYS","rule","rule","rule","rule"]}